mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-23 16:00:38 +00:00
Merge remote-tracking branch 'origin/main' into dieri/triggers-queue-mode
This commit is contained in:
@@ -86,4 +86,4 @@ jobs:
|
||||
run: |
|
||||
deno --version && bun -v && go version && python3 --version
|
||||
cd windmill-duckdb-ffi-internal && ./build_dev.sh && cd ..
|
||||
DENO_PATH=$(which deno) BUN_PATH=$(which bun) GO_PATH=$(which go) UV_PATH=$(which uv) cargo test --features enterprise,deno_core,duckdb,license,python,rust,scoped_cache,private --all -- --nocapture
|
||||
DENO_PATH=$(which deno) BUN_PATH=$(which bun) GO_PATH=$(which go) UV_PATH=$(which uv) cargo test --features enterprise,deno_core,duckdb,license,python,rust,scoped_cache,parquet,private --all -- --nocapture
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# Changelog
|
||||
|
||||
## [1.583.1](https://github.com/windmill-labs/windmill/compare/v1.583.0...v1.583.1) (2025-11-21)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **cli:** improve cli local policy generation ([b857d15](https://github.com/windmill-labs/windmill/commit/b857d15352ab422c1d477cd9172856956c2c4b7c))
|
||||
|
||||
## [1.583.0](https://github.com/windmill-labs/windmill/compare/v1.582.2...v1.583.0) (2025-11-21)
|
||||
|
||||
|
||||
|
||||
+5
-5
@@ -46,11 +46,11 @@
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true
|
||||
]
|
||||
|
||||
+3
-1
@@ -59,7 +59,9 @@
|
||||
"failure",
|
||||
"command",
|
||||
"approval",
|
||||
"preprocessor"
|
||||
"preprocessor",
|
||||
"schedule_handler_old",
|
||||
"dynamic_skip"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+27
-27
@@ -15213,7 +15213,7 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windmill"
|
||||
version = "1.583.0"
|
||||
version = "1.583.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"aws-sdk-config",
|
||||
@@ -15275,7 +15275,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-api"
|
||||
version = "1.583.0"
|
||||
version = "1.583.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"argon2",
|
||||
@@ -15396,7 +15396,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-api-client"
|
||||
version = "1.583.0"
|
||||
version = "1.583.1"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"chrono",
|
||||
@@ -15411,7 +15411,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-audit"
|
||||
version = "1.583.0"
|
||||
version = "1.583.1"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"lazy_static",
|
||||
@@ -15425,7 +15425,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-autoscaling"
|
||||
version = "1.583.0"
|
||||
version = "1.583.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"axum",
|
||||
@@ -15444,7 +15444,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-common"
|
||||
version = "1.583.0"
|
||||
version = "1.583.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-recursion",
|
||||
@@ -15533,7 +15533,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-git-sync"
|
||||
version = "1.583.0"
|
||||
version = "1.583.1"
|
||||
dependencies = [
|
||||
"regex",
|
||||
"serde",
|
||||
@@ -15548,7 +15548,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-indexer"
|
||||
version = "1.583.0"
|
||||
version = "1.583.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@@ -15572,7 +15572,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-macros"
|
||||
version = "1.583.0"
|
||||
version = "1.583.1"
|
||||
dependencies = [
|
||||
"itertools 0.14.0",
|
||||
"lazy_static",
|
||||
@@ -15584,7 +15584,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser"
|
||||
version = "1.583.0"
|
||||
version = "1.583.1"
|
||||
dependencies = [
|
||||
"convert_case 0.6.0",
|
||||
"serde",
|
||||
@@ -15593,7 +15593,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-bash"
|
||||
version = "1.583.0"
|
||||
version = "1.583.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"lazy_static",
|
||||
@@ -15605,7 +15605,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-csharp"
|
||||
version = "1.583.0"
|
||||
version = "1.583.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"serde_json",
|
||||
@@ -15617,7 +15617,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-go"
|
||||
version = "1.583.0"
|
||||
version = "1.583.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"gosyn",
|
||||
@@ -15629,7 +15629,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-graphql"
|
||||
version = "1.583.0"
|
||||
version = "1.583.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"lazy_static",
|
||||
@@ -15641,7 +15641,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-java"
|
||||
version = "1.583.0"
|
||||
version = "1.583.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"serde_json",
|
||||
@@ -15653,7 +15653,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-nu"
|
||||
version = "1.583.0"
|
||||
version = "1.583.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"nu-parser",
|
||||
@@ -15664,7 +15664,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-php"
|
||||
version = "1.583.0"
|
||||
version = "1.583.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"itertools 0.14.0",
|
||||
@@ -15675,7 +15675,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-py"
|
||||
version = "1.583.0"
|
||||
version = "1.583.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"itertools 0.14.0",
|
||||
@@ -15687,7 +15687,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-py-imports"
|
||||
version = "1.583.0"
|
||||
version = "1.583.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-recursion",
|
||||
@@ -15710,7 +15710,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-ruby"
|
||||
version = "1.583.0"
|
||||
version = "1.583.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"lazy_static",
|
||||
@@ -15724,7 +15724,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-rust"
|
||||
version = "1.583.0"
|
||||
version = "1.583.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"convert_case 0.6.0",
|
||||
@@ -15741,7 +15741,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-sql"
|
||||
version = "1.583.0"
|
||||
version = "1.583.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"lazy_static",
|
||||
@@ -15755,7 +15755,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-ts"
|
||||
version = "1.583.0"
|
||||
version = "1.583.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"lazy_static",
|
||||
@@ -15773,7 +15773,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-yaml"
|
||||
version = "1.583.0"
|
||||
version = "1.583.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"serde",
|
||||
@@ -15784,7 +15784,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-queue"
|
||||
version = "1.583.0"
|
||||
version = "1.583.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-recursion",
|
||||
@@ -15821,7 +15821,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-sql-datatype-parser-wasm"
|
||||
version = "1.583.0"
|
||||
version = "1.583.1"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-test",
|
||||
@@ -15831,7 +15831,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-worker"
|
||||
version = "1.583.0"
|
||||
version = "1.583.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-once-cell",
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "windmill"
|
||||
version = "1.583.0"
|
||||
version = "1.583.1"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
@@ -33,7 +33,7 @@ members = [
|
||||
exclude = ["./windmill-duckdb-ffi-internal"]
|
||||
|
||||
[workspace.package]
|
||||
version = "1.583.0"
|
||||
version = "1.583.1"
|
||||
authors = ["Ruben Fiszel <ruben@windmill.dev>"]
|
||||
edition = "2021"
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
a01942048c2464317fc0484c0b2414e14aa5f2a4
|
||||
a01942048c2464317fc0484c0b2414e14aa5f2a4
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
openapi: "3.0.3"
|
||||
|
||||
info:
|
||||
version: 1.583.0
|
||||
version: 1.583.1
|
||||
title: Windmill API
|
||||
|
||||
contact:
|
||||
@@ -5180,6 +5180,14 @@ paths:
|
||||
Accepts multiple values as a comma-separated list.
|
||||
schema:
|
||||
type: string
|
||||
- name: without_description
|
||||
in: query
|
||||
description: |
|
||||
(default false)
|
||||
If true, the description field will be omitted from the response.
|
||||
schema:
|
||||
type: boolean
|
||||
|
||||
responses:
|
||||
"200":
|
||||
description: All scripts
|
||||
@@ -6463,6 +6471,13 @@ paths:
|
||||
in: query
|
||||
schema:
|
||||
type: boolean
|
||||
- name: without_description
|
||||
in: query
|
||||
description: |
|
||||
(default false)
|
||||
If true, the description field will be omitted from the response.
|
||||
schema:
|
||||
type: boolean
|
||||
responses:
|
||||
"200":
|
||||
description: All flow
|
||||
@@ -12061,32 +12076,32 @@ paths:
|
||||
schema:
|
||||
type: boolean
|
||||
/w/{workspace}/email_triggers/setenabled/{path}:
|
||||
post:
|
||||
summary: enable/disable email trigger
|
||||
operationId: setEmailTriggerEnabled
|
||||
tags:
|
||||
- email_trigger
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/WorkspaceId"
|
||||
- $ref: "#/components/parameters/Path"
|
||||
requestBody:
|
||||
required: true
|
||||
post:
|
||||
summary: enable/disable email trigger
|
||||
operationId: setEmailTriggerEnabled
|
||||
tags:
|
||||
- email_trigger
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/WorkspaceId"
|
||||
- $ref: "#/components/parameters/Path"
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
enabled:
|
||||
type: boolean
|
||||
required:
|
||||
- enabled
|
||||
responses:
|
||||
"200":
|
||||
description: email trigger enable/disable
|
||||
content:
|
||||
application/json:
|
||||
text/plain:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
enabled:
|
||||
type: boolean
|
||||
required:
|
||||
- enabled
|
||||
responses:
|
||||
"200":
|
||||
description: email trigger enable/disable
|
||||
content:
|
||||
text/plain:
|
||||
schema:
|
||||
type: string
|
||||
type: string
|
||||
|
||||
/groups/list:
|
||||
get:
|
||||
|
||||
@@ -133,7 +133,11 @@ async fn list_flows(
|
||||
"o.workspace_id",
|
||||
"o.path",
|
||||
"summary",
|
||||
"description",
|
||||
if !lq.without_description.unwrap_or(false) {
|
||||
"description"
|
||||
} else {
|
||||
"NULL as description"
|
||||
},
|
||||
"fv.created_by as edited_by",
|
||||
"fv.created_at as edited_at",
|
||||
"archived",
|
||||
|
||||
@@ -228,6 +228,11 @@ async fn list_scripts(
|
||||
"COALESCE(draft.created_at, o.created_at) as created_at",
|
||||
"archived",
|
||||
"extra_perms",
|
||||
if !lq.without_description.unwrap_or(false) {
|
||||
"description"
|
||||
} else {
|
||||
"NULL as description"
|
||||
},
|
||||
"CASE WHEN lock_error_logs IS NOT NULL THEN true ELSE false END as has_deploy_errors",
|
||||
"language",
|
||||
"favorite.path IS NOT NULL as starred",
|
||||
|
||||
@@ -78,7 +78,8 @@ pub struct ListableFlow {
|
||||
pub workspace_id: String,
|
||||
pub path: String,
|
||||
pub summary: String,
|
||||
pub description: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub description: Option<String>,
|
||||
pub edited_by: Option<String>,
|
||||
pub edited_at: Option<chrono::DateTime<chrono::Utc>>,
|
||||
pub archived: bool,
|
||||
@@ -1122,6 +1123,7 @@ where
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct ListFlowQuery {
|
||||
pub without_description: Option<bool>,
|
||||
pub path_start: Option<String>,
|
||||
pub path_exact: Option<String>,
|
||||
pub edited_by: Option<String>,
|
||||
|
||||
@@ -353,6 +353,8 @@ pub struct ListableScript {
|
||||
pub starred: bool,
|
||||
pub tag: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub description: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub has_draft: Option<bool>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub draft_only: Option<bool>,
|
||||
@@ -492,6 +494,7 @@ where
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct ListScriptQuery {
|
||||
pub without_description: Option<bool>,
|
||||
pub path_start: Option<String>,
|
||||
pub path_exact: Option<String>,
|
||||
pub created_by: Option<String>,
|
||||
|
||||
@@ -598,7 +598,10 @@ async fn transform_s3_uris(query: &str) -> Result<String> {
|
||||
// BigQuery extension requires a json file as credentials
|
||||
// The file path is set as an env var by do_duckdb
|
||||
// It is created by transform_attach_db_resource_query (when bigquery is detected)
|
||||
// and deleted by do_duckdb after the query is executed
|
||||
// and deleted by do_duckdb after the query is executed.
|
||||
//
|
||||
// This relies on the fact that DuckDB does not run in native worker, so
|
||||
// a worker will only run a single job at a time.
|
||||
pub struct UseBigQueryCredentialsFile {
|
||||
path: String,
|
||||
}
|
||||
@@ -660,6 +663,8 @@ fn remove_comments(stmt: &str) -> &str {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
// Tests for remove_comments function
|
||||
#[test]
|
||||
fn test_remove_comments_single_line() {
|
||||
let sql = "-- This is a comment\nSELECT * FROM table;";
|
||||
@@ -690,4 +695,377 @@ mod tests {
|
||||
let sql = " -- Comment\n -- Comment2\n -- Comment3\n SELECT\n\n * FROM\n table\n;\n\n -- end comment ";
|
||||
assert_eq!(remove_comments(sql), "SELECT\n\n * FROM\n table\n;");
|
||||
}
|
||||
|
||||
// Tests for parse_attach_db_resource function
|
||||
#[test]
|
||||
fn test_parse_attach_db_resource_postgres_res_prefix() {
|
||||
let query = "ATTACH '$res:u/user/my_postgres' AS mydb (TYPE POSTGRES)";
|
||||
let result = parse_attach_db_resource(query);
|
||||
assert!(result.is_some());
|
||||
let parsed = result.unwrap();
|
||||
assert_eq!(parsed.resource_path, "u/user/my_postgres");
|
||||
assert_eq!(parsed.name, "mydb");
|
||||
assert_eq!(parsed.db_type, "POSTGRES");
|
||||
assert!(parsed.extra_args.is_none() || parsed.extra_args.unwrap().is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_attach_db_resource_res_protocol() {
|
||||
let query = "ATTACH 'res://f/folder/database' AS db (TYPE postgresql)";
|
||||
let result = parse_attach_db_resource(query);
|
||||
assert!(result.is_some());
|
||||
let parsed = result.unwrap();
|
||||
assert_eq!(parsed.resource_path, "f/folder/database");
|
||||
assert_eq!(parsed.name, "db");
|
||||
assert_eq!(parsed.db_type, "postgresql");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_attach_db_resource_mysql() {
|
||||
let query = "ATTACH '$res:u/admin/mysql_prod' AS mysql_db (TYPE mysql)";
|
||||
let result = parse_attach_db_resource(query);
|
||||
assert!(result.is_some());
|
||||
let parsed = result.unwrap();
|
||||
assert_eq!(parsed.resource_path, "u/admin/mysql_prod");
|
||||
assert_eq!(parsed.name, "mysql_db");
|
||||
assert_eq!(parsed.db_type, "mysql");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_attach_db_resource_bigquery() {
|
||||
let query = "ATTACH '$res:u/user/bq_resource' AS bq (TYPE bigquery)";
|
||||
let result = parse_attach_db_resource(query);
|
||||
assert!(result.is_some());
|
||||
let parsed = result.unwrap();
|
||||
assert_eq!(parsed.resource_path, "u/user/bq_resource");
|
||||
assert_eq!(parsed.name, "bq");
|
||||
assert_eq!(parsed.db_type, "bigquery");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_attach_db_resource_with_extra_args() {
|
||||
let query = "ATTACH '$res:u/user/db' AS mydb (TYPE POSTGRES, READ_ONLY)";
|
||||
let result = parse_attach_db_resource(query);
|
||||
assert!(result.is_some());
|
||||
let parsed = result.unwrap();
|
||||
assert_eq!(parsed.resource_path, "u/user/db");
|
||||
assert_eq!(parsed.name, "mydb");
|
||||
assert_eq!(parsed.db_type, "POSTGRES");
|
||||
assert_eq!(parsed.extra_args.unwrap(), ", READ_ONLY");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_attach_db_resource_case_insensitive() {
|
||||
let query = "attach '$res:u/user/db' as mydb (type postgres)";
|
||||
let result = parse_attach_db_resource(query);
|
||||
assert!(result.is_some());
|
||||
let parsed = result.unwrap();
|
||||
assert_eq!(parsed.resource_path, "u/user/db");
|
||||
assert_eq!(parsed.name, "mydb");
|
||||
assert_eq!(parsed.db_type, "postgres");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_attach_db_resource_no_match() {
|
||||
let query = "SELECT * FROM table";
|
||||
let result = parse_attach_db_resource(query);
|
||||
assert!(result.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_attach_db_resource_regular_attach() {
|
||||
// Regular ATTACH without $res: or res:// should not match
|
||||
let query = "ATTACH 'mydb.duckdb' AS mydb (TYPE duckdb)";
|
||||
let result = parse_attach_db_resource(query);
|
||||
assert!(result.is_none());
|
||||
}
|
||||
|
||||
// Tests for format_attach_db_conn_str function
|
||||
#[test]
|
||||
fn test_format_attach_db_conn_str_postgres_full() {
|
||||
let db_resource = json!({
|
||||
"host": "localhost",
|
||||
"port": 5432,
|
||||
"user": "admin",
|
||||
"password": "secret123",
|
||||
"dbname": "mydb",
|
||||
"sslmode": "require"
|
||||
});
|
||||
let result = format_attach_db_conn_str(db_resource, "postgres").unwrap();
|
||||
assert!(result.contains("dbname=mydb"));
|
||||
assert!(result.contains("user=admin"));
|
||||
assert!(result.contains("host=localhost"));
|
||||
assert!(result.contains("password=secret123"));
|
||||
assert!(result.contains("port=5432"));
|
||||
assert!(result.contains("sslmode=require"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_format_attach_db_conn_str_postgres_minimal() {
|
||||
let db_resource = json!({
|
||||
"host": "db.example.com",
|
||||
"dbname": "production"
|
||||
});
|
||||
let result = format_attach_db_conn_str(db_resource, "postgres").unwrap();
|
||||
assert!(result.contains("dbname=production"));
|
||||
assert!(result.contains("host=db.example.com"));
|
||||
// Optional fields should result in empty strings
|
||||
assert!(!result.contains("user="));
|
||||
assert!(!result.contains("password="));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_format_attach_db_conn_str_postgresql_alias() {
|
||||
let db_resource = json!({
|
||||
"host": "localhost",
|
||||
"dbname": "test"
|
||||
});
|
||||
let result = format_attach_db_conn_str(db_resource, "postgresql").unwrap();
|
||||
assert!(result.contains("dbname=test"));
|
||||
assert!(result.contains("host=localhost"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_format_attach_db_conn_str_bigquery() {
|
||||
let db_resource = json!({
|
||||
"project_id": "my-gcp-project"
|
||||
});
|
||||
let result = format_attach_db_conn_str(db_resource, "bigquery").unwrap();
|
||||
assert_eq!(result, "project=my-gcp-project");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_format_attach_db_conn_str_bigquery_missing_project_id() {
|
||||
let db_resource = json!({
|
||||
"other_field": "value"
|
||||
});
|
||||
let result = format_attach_db_conn_str(db_resource, "bigquery");
|
||||
assert!(result.is_err());
|
||||
assert!(result.unwrap_err().to_string().contains("project_id"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_format_attach_db_conn_str_unsupported_type() {
|
||||
let db_resource = json!({});
|
||||
let result = format_attach_db_conn_str(db_resource, "oracle");
|
||||
assert!(result.is_err());
|
||||
assert!(result
|
||||
.unwrap_err()
|
||||
.to_string()
|
||||
.contains("Unsupported db type"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_format_attach_db_conn_str_case_insensitive() {
|
||||
let db_resource = json!({
|
||||
"host": "localhost",
|
||||
"dbname": "test"
|
||||
});
|
||||
let result = format_attach_db_conn_str(db_resource, "POSTGRES").unwrap();
|
||||
assert!(result.contains("dbname=test"));
|
||||
}
|
||||
|
||||
#[cfg(feature = "mysql")]
|
||||
#[test]
|
||||
fn test_format_attach_db_conn_str_mysql_full() {
|
||||
let db_resource = json!({
|
||||
"host": "mysql.example.com",
|
||||
"port": 3306,
|
||||
"user": "root",
|
||||
"password": "mysecret",
|
||||
"database": "app_db",
|
||||
"ssl": true
|
||||
});
|
||||
let result = format_attach_db_conn_str(db_resource, "mysql").unwrap();
|
||||
assert!(result.contains("database=app_db"));
|
||||
assert!(result.contains("host=mysql.example.com"));
|
||||
assert!(result.contains("ssl_mode=required"));
|
||||
assert!(result.contains("password=mysecret"));
|
||||
assert!(result.contains("port=3306"));
|
||||
assert!(result.contains("user=root"));
|
||||
}
|
||||
|
||||
#[cfg(feature = "mysql")]
|
||||
#[test]
|
||||
fn test_format_attach_db_conn_str_mysql_ssl_disabled() {
|
||||
let db_resource = json!({
|
||||
"host": "localhost",
|
||||
"database": "test",
|
||||
"ssl": false
|
||||
});
|
||||
let result = format_attach_db_conn_str(db_resource, "mysql").unwrap();
|
||||
assert!(result.contains("ssl_mode=disabled"));
|
||||
}
|
||||
|
||||
// Tests for get_attach_db_install_str function
|
||||
#[test]
|
||||
fn test_get_attach_db_install_str_postgres() {
|
||||
let result = get_attach_db_install_str("postgres").unwrap();
|
||||
assert_eq!(result, "INSTALL postgres;");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_attach_db_install_str_bigquery() {
|
||||
let result = get_attach_db_install_str("bigquery").unwrap();
|
||||
assert_eq!(result, "INSTALL bigquery FROM community;");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_attach_db_install_str_unsupported() {
|
||||
let result = get_attach_db_install_str("sqlite");
|
||||
assert!(result.is_err());
|
||||
assert!(result
|
||||
.unwrap_err()
|
||||
.to_string()
|
||||
.contains("Unsupported db type"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_attach_db_install_str_case_insensitive() {
|
||||
let result = get_attach_db_install_str("POSTGRES").unwrap();
|
||||
assert_eq!(result, "INSTALL postgres;");
|
||||
}
|
||||
|
||||
#[cfg(feature = "mysql")]
|
||||
#[test]
|
||||
fn test_get_attach_db_install_str_mysql() {
|
||||
let result = get_attach_db_install_str("mysql").unwrap();
|
||||
assert_eq!(result, "INSTALL mysql;");
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "mysql"))]
|
||||
#[test]
|
||||
fn test_get_attach_db_install_str_mysql_disabled() {
|
||||
let result = get_attach_db_install_str("mysql");
|
||||
assert!(result.is_err());
|
||||
assert!(result
|
||||
.unwrap_err()
|
||||
.to_string()
|
||||
.contains("MySQL feature is not enabled"));
|
||||
}
|
||||
|
||||
// Tests for transform_s3_uris function
|
||||
#[tokio::test]
|
||||
async fn test_transform_s3_uris_empty_storage() {
|
||||
let query = "SELECT * FROM read_parquet('s3:///path/to/file.parquet')";
|
||||
let result = transform_s3_uris(query).await.unwrap();
|
||||
assert_eq!(
|
||||
result,
|
||||
"SELECT * FROM read_parquet('s3://_default_/path/to/file.parquet')"
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_transform_s3_uris_with_storage() {
|
||||
// URIs with explicit storage should not be transformed
|
||||
let query = "SELECT * FROM read_parquet('s3://mybucket/path/to/file.parquet')";
|
||||
let result = transform_s3_uris(query).await.unwrap();
|
||||
assert_eq!(result, query);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_transform_s3_uris_multiple_empty() {
|
||||
let query = "SELECT * FROM read_parquet('s3:///file1.parquet') UNION SELECT * FROM read_parquet('s3:///file2.parquet')";
|
||||
let result = transform_s3_uris(query).await.unwrap();
|
||||
assert!(result.contains("s3://_default_/file1.parquet"));
|
||||
assert!(result.contains("s3://_default_/file2.parquet"));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_transform_s3_uris_no_s3() {
|
||||
let query = "SELECT * FROM my_table";
|
||||
let result = transform_s3_uris(query).await.unwrap();
|
||||
assert_eq!(result, query);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_transform_s3_uris_mixed() {
|
||||
let query = "SELECT * FROM read_parquet('s3:///default.parquet'), read_csv('s3://explicit/file.csv')";
|
||||
let result = transform_s3_uris(query).await.unwrap();
|
||||
assert!(result.contains("s3://_default_/default.parquet"));
|
||||
assert!(result.contains("s3://explicit/file.csv"));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_transform_s3_uris_nested_path() {
|
||||
let query = "SELECT * FROM read_parquet('s3:///deep/nested/path/file.parquet')";
|
||||
let result = transform_s3_uris(query).await.unwrap();
|
||||
assert_eq!(
|
||||
result,
|
||||
"SELECT * FROM read_parquet('s3://_default_/deep/nested/path/file.parquet')"
|
||||
);
|
||||
}
|
||||
|
||||
// Tests for Arg struct
|
||||
#[test]
|
||||
fn test_arg_serialization() {
|
||||
let arg = Arg {
|
||||
name: "test_arg".to_string(),
|
||||
arg_type: "string".to_string(),
|
||||
json_value: json!("hello"),
|
||||
};
|
||||
let serialized = serde_json::to_string(&arg).unwrap();
|
||||
assert!(serialized.contains("\"name\":\"test_arg\""));
|
||||
assert!(serialized.contains("\"arg_type\":\"string\""));
|
||||
assert!(serialized.contains("\"json_value\":\"hello\""));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_arg_serialization_number() {
|
||||
let arg = Arg {
|
||||
name: "count".to_string(),
|
||||
arg_type: "integer".to_string(),
|
||||
json_value: json!(42),
|
||||
};
|
||||
let serialized = serde_json::to_string(&arg).unwrap();
|
||||
assert!(serialized.contains("\"json_value\":42"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_arg_serialization_null() {
|
||||
let arg = Arg {
|
||||
name: "optional".to_string(),
|
||||
arg_type: "text".to_string(),
|
||||
json_value: json!(null),
|
||||
};
|
||||
let serialized = serde_json::to_string(&arg).unwrap();
|
||||
assert!(serialized.contains("\"json_value\":null"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_arg_serialization_array() {
|
||||
let arg = Arg {
|
||||
name: "items".to_string(),
|
||||
arg_type: "array".to_string(),
|
||||
json_value: json!([1, 2, 3]),
|
||||
};
|
||||
let serialized = serde_json::to_string(&arg).unwrap();
|
||||
assert!(serialized.contains("\"json_value\":[1,2,3]"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_arg_serialization_object() {
|
||||
let arg = Arg {
|
||||
name: "config".to_string(),
|
||||
arg_type: "object".to_string(),
|
||||
json_value: json!({"key": "value"}),
|
||||
};
|
||||
let serialized = serde_json::to_string(&arg).unwrap();
|
||||
assert!(serialized.contains("\"json_value\":{\"key\":\"value\"}"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_remove_comments_comment_in_string() {
|
||||
let sql = "SELECT '-- not a comment' FROM table;";
|
||||
let result = remove_comments(sql);
|
||||
assert_eq!(result, "SELECT '-- not a comment' FROM table;");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_remove_comments_multiple_dashes() {
|
||||
let sql = "SELECT 5 - - 3;";
|
||||
let result = remove_comments(sql);
|
||||
// This correctly handles the subtraction of negative number
|
||||
assert_eq!(result, sql);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -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.583.0";
|
||||
export const VERSION = "v1.583.1";
|
||||
|
||||
export async function login(email: string, password: string): Promise<string> {
|
||||
return await windmill.UserService.login({
|
||||
|
||||
@@ -45,7 +45,7 @@ export async function pushApp(
|
||||
} catch {
|
||||
//ignore
|
||||
}
|
||||
app.value.policy = undefined;
|
||||
app.policy = undefined;
|
||||
|
||||
if (!localPath.endsWith(SEP)) {
|
||||
localPath += SEP;
|
||||
@@ -78,7 +78,7 @@ export async function pushApp(
|
||||
}
|
||||
|
||||
replaceInlineScripts(localApp.value);
|
||||
await generatingPolicy(localApp.value, remotePath);
|
||||
await generatingPolicy(localApp, remotePath);
|
||||
if (app) {
|
||||
if (isSuperset(localApp, app)) {
|
||||
log.info(colors.green(`App ${remotePath} is up to date`));
|
||||
@@ -110,7 +110,8 @@ export async function pushApp(
|
||||
async function generatingPolicy(app: any, path: string) {
|
||||
log.info(colors.gray(`Generating fresh policy for app ${path}...`));
|
||||
try {
|
||||
app.policy = await windmillUtils.updatePolicy(app, undefined);
|
||||
app.policy = await windmillUtils.updatePolicy(app.value, undefined);
|
||||
app.policy.execution_mode = "publisher";
|
||||
} catch (e) {
|
||||
log.error(colors.red(`Error generating policy for app ${path}: ${e}`));
|
||||
throw e;
|
||||
|
||||
@@ -662,7 +662,6 @@ export async function elementsToMap(
|
||||
const map: { [key: string]: string } = {};
|
||||
const processedBasePaths = new Set<string>();
|
||||
|
||||
|
||||
for await (const entry of readDirRecursiveWithIgnore(ignore, els)) {
|
||||
if (entry.isDirectory || entry.ignored) continue;
|
||||
const path = entry.path;
|
||||
@@ -854,25 +853,6 @@ async function compareDynFSElement(
|
||||
}
|
||||
}
|
||||
return o;
|
||||
} else if (k.endsWith(".app.yaml")) {
|
||||
let o: any;
|
||||
try {
|
||||
o = yamlParseContent(k, v);
|
||||
} catch (error) {
|
||||
log.error(`Failed to parse app YAML content at path: ${k}`);
|
||||
throw error;
|
||||
}
|
||||
const o2 = o["policy"];
|
||||
|
||||
if (typeof o2 == "object") {
|
||||
if (o2["on_behalf_of"] != undefined) {
|
||||
delete o2["on_behalf_of"];
|
||||
}
|
||||
if (o2["on_behalf_of_email"] != undefined) {
|
||||
delete o2["on_behalf_of_email"];
|
||||
}
|
||||
}
|
||||
return o;
|
||||
} else {
|
||||
try {
|
||||
return yamlParseContent(k, v);
|
||||
|
||||
+1
-1
@@ -68,7 +68,7 @@ export {
|
||||
// }
|
||||
// });
|
||||
|
||||
export const VERSION = "1.583.0";
|
||||
export const VERSION = "1.583.1";
|
||||
|
||||
export const WM_FORK_PREFIX = "wm-fork";
|
||||
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "windmill-components",
|
||||
"version": "1.583.0",
|
||||
"version": "1.583.1",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "windmill-components",
|
||||
"version": "1.583.0",
|
||||
"version": "1.583.1",
|
||||
"hasInstallScript": true,
|
||||
"license": "AGPL-3.0",
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "windmill-components",
|
||||
"version": "1.583.0",
|
||||
"version": "1.583.1",
|
||||
"scripts": {
|
||||
"dev": "vite dev",
|
||||
"build": "vite build",
|
||||
|
||||
@@ -57,15 +57,19 @@
|
||||
|
||||
async function loadItems(): Promise<void> {
|
||||
if (itemKind == 'flow') {
|
||||
items = (await FlowService.listFlows({ workspace: $workspaceStore! })).map((flow) => ({
|
||||
items = (
|
||||
await FlowService.listFlows({ workspace: $workspaceStore!, withoutDescription: true })
|
||||
).map((flow) => ({
|
||||
value: flow.path,
|
||||
label: `${flow.path}${flow.summary ? ` | ${truncate(flow.summary, 20)}` : ''}`
|
||||
label: `${flow.path}${flow.summary ? ` | ${truncate(flow.summary, 20)}` : ''}`,
|
||||
withoutDescription: true
|
||||
}))
|
||||
} else if (itemKind == 'script') {
|
||||
items = (
|
||||
await ScriptService.listScripts({
|
||||
workspace: $workspaceStore!,
|
||||
kinds: kinds.join(',')
|
||||
kinds: kinds.join(','),
|
||||
withoutDescription: true
|
||||
})
|
||||
).map((script) => ({
|
||||
value: script.path,
|
||||
|
||||
@@ -196,7 +196,7 @@
|
||||
id: string
|
||||
result_stream?: string
|
||||
}) {
|
||||
setResult(nresult_stream, id)
|
||||
setResult(nresult_stream, id, false)
|
||||
},
|
||||
cancel({ id }: { id: string }) {
|
||||
onCancel?.()
|
||||
@@ -630,7 +630,7 @@
|
||||
result = res
|
||||
}
|
||||
|
||||
async function setResult(res: any, jobId: string | undefined) {
|
||||
async function setResult(res: any, jobId: string | undefined, dispatchSuccess: boolean = true) {
|
||||
dispatch('resultSet', res)
|
||||
const errors = getResultErrors(res)
|
||||
|
||||
@@ -669,7 +669,9 @@
|
||||
recordJob(jobId, result, undefined, transformerResult)
|
||||
delete $errorByComponent[id]
|
||||
|
||||
dispatch('success', result)
|
||||
if (dispatchSuccess) {
|
||||
dispatch('success', result)
|
||||
}
|
||||
// callbacks?.done(res)
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -27,7 +27,8 @@
|
||||
async function loadFlow(): Promise<void> {
|
||||
const loadedFlows = await FlowService.listFlows({
|
||||
workspace: $workspaceStore!,
|
||||
perPage: 300
|
||||
perPage: 300,
|
||||
withoutDescription: true
|
||||
})
|
||||
|
||||
flows = loadedFlows
|
||||
|
||||
+2
-1
@@ -27,7 +27,8 @@
|
||||
async function loadScripts(): Promise<void> {
|
||||
const loadedScripts = await ScriptService.listScripts({
|
||||
workspace: $workspaceStore!,
|
||||
perPage: 300
|
||||
perPage: 300,
|
||||
withoutDescription: true
|
||||
})
|
||||
|
||||
scripts = loadedScripts
|
||||
|
||||
@@ -374,7 +374,7 @@ class WorkspaceScriptsSearch {
|
||||
|
||||
private async init(workspace: string) {
|
||||
this.scripts = await ScriptService.listScripts({
|
||||
workspace
|
||||
workspace,
|
||||
})
|
||||
this.workspace = workspace
|
||||
}
|
||||
|
||||
@@ -6,28 +6,38 @@
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { emptyString } from '$lib/utils'
|
||||
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { createEventDispatcher, untrack } from 'svelte'
|
||||
import { flip } from 'svelte/animate'
|
||||
import { fade } from 'svelte/transition'
|
||||
interface Props {
|
||||
children?: import('svelte').Snippet
|
||||
}
|
||||
|
||||
let { children }: Props = $props()
|
||||
|
||||
// export let failureModule: boolean
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
let items: Flow[] | undefined = undefined
|
||||
let filteredItems: (Flow & { marked?: string })[] | undefined = undefined
|
||||
let filter = ''
|
||||
$: $workspaceStore && loadFlows()
|
||||
let items = $state(undefined) as Flow[] | undefined
|
||||
let filteredItems = $state(undefined) as (Flow & { marked?: string })[] | undefined
|
||||
let filter = $state('')
|
||||
|
||||
let ownerFilter: string | undefined = undefined
|
||||
$: prefilteredItems = ownerFilter ? items?.filter((x) => x.path.startsWith(ownerFilter!)) : items
|
||||
|
||||
$: owners = Array.from(
|
||||
new Set(filteredItems?.map((x) => x.path.split('/').slice(0, 2).join('/')) ?? [])
|
||||
).sort()
|
||||
let ownerFilter: string | undefined = $state(undefined)
|
||||
|
||||
async function loadFlows() {
|
||||
items = await FlowService.listFlows({ workspace: $workspaceStore! })
|
||||
items = await FlowService.listFlows({ workspace: $workspaceStore!, withoutDescription: true })
|
||||
}
|
||||
$effect(() => {
|
||||
$workspaceStore && untrack(() => loadFlows())
|
||||
})
|
||||
let prefilteredItems = $derived(
|
||||
ownerFilter ? items?.filter((x) => x.path.startsWith(ownerFilter!)) : items
|
||||
)
|
||||
let owners = $derived(
|
||||
Array.from(
|
||||
new Set(filteredItems?.map((x) => x.path.split('/').slice(0, 2).join('/')) ?? [])
|
||||
).sort()
|
||||
)
|
||||
</script>
|
||||
|
||||
<SearchItems
|
||||
@@ -39,7 +49,7 @@
|
||||
<div class="flex flex-col min-h-0 p-4">
|
||||
<h3 class="mb-4">Pick a Workspace Flow</h3>
|
||||
<div class="w-full flex mt-1 items-center gap-2 mb-3">
|
||||
<slot />
|
||||
{@render children?.()}
|
||||
|
||||
<input
|
||||
type="text"
|
||||
@@ -78,7 +88,7 @@
|
||||
<li class="flex flex-row w-full">
|
||||
<button
|
||||
class="p-4 gap-1 flex flex-row grow hover:bg-surface-hover bg-surface transition-all text-primary"
|
||||
on:click={() => {
|
||||
onclick={() => {
|
||||
dispatch('pick', { path })
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { Skeleton } from '$lib/components/common'
|
||||
import SearchItems from '$lib/components/SearchItems.svelte'
|
||||
import { FlowService, type Flow } from '$lib/gen'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { emptyString } from '$lib/utils'
|
||||
import BarsStaggered from '$lib/components/icons/BarsStaggered.svelte'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
|
||||
// export let failureModule: boolean
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
let items: Flow[] | undefined = undefined
|
||||
let filteredItems: (Flow & { marked?: string })[] | undefined = undefined
|
||||
export let filter = ''
|
||||
$: $workspaceStore && loadFlows()
|
||||
|
||||
let ownerFilter: string | undefined = undefined
|
||||
$: prefilteredItems = ownerFilter ? items?.filter((x) => x.path.startsWith(ownerFilter!)) : items
|
||||
|
||||
export let owners: string[] = []
|
||||
$: owners = Array.from(
|
||||
new Set(filteredItems?.map((x) => x.path.split('/').slice(0, 2).join('/')) ?? [])
|
||||
).sort()
|
||||
|
||||
async function loadFlows() {
|
||||
items = await FlowService.listFlows({ workspace: $workspaceStore! })
|
||||
}
|
||||
</script>
|
||||
|
||||
<SearchItems
|
||||
{filter}
|
||||
items={prefilteredItems}
|
||||
bind:filteredItems
|
||||
f={(x) => (emptyString(x.summary) ? x.path : x.summary + ' (' + x.path + ')')}
|
||||
/>
|
||||
<div class="flex flex-col min-h-0">
|
||||
{#if filteredItems}
|
||||
{#if filter.length > 0 && filteredItems.length == 0}
|
||||
<div class="text-2xs text-tercary font-extralight text-center py-2 px-3 items-center">
|
||||
No items found.
|
||||
</div>
|
||||
{/if}
|
||||
<ul class="overflow-auto">
|
||||
{#each filteredItems as { path, summary, marked }}
|
||||
<li class="flex flex-row w-full">
|
||||
<button
|
||||
class="px-3 py-2 gap-2 flex flex-row w-full hover:bg-surface-hover bg-surface transition-all items-center rounded-md text-left text-2xs text-primary font-normal"
|
||||
on:click={async () => {
|
||||
dispatch('pickFlow', {
|
||||
path,
|
||||
summary
|
||||
})
|
||||
}}
|
||||
>
|
||||
<BarsStaggered size={14} />
|
||||
<span class="grow truncate">
|
||||
{#if marked}
|
||||
{@html marked}
|
||||
{:else}
|
||||
{!summary || summary.length == 0 ? path : summary}
|
||||
{/if}
|
||||
</span>
|
||||
</button>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
{:else}
|
||||
{#each Array(10).fill(0) as _}
|
||||
<Skeleton layout={[0.5, [1.5]]} />
|
||||
{/each}
|
||||
{/if}
|
||||
</div>
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { createEventDispatcher, untrack } from 'svelte'
|
||||
import { ScriptService } from '$lib/gen'
|
||||
import SearchItems from '$lib/components/SearchItems.svelte'
|
||||
import { Badge, Skeleton } from '$lib/components/common'
|
||||
@@ -11,10 +11,6 @@
|
||||
import NoItemFound from '$lib/components/home/NoItemFound.svelte'
|
||||
import TextInput from '$lib/components/text_input/TextInput.svelte'
|
||||
|
||||
export let kind: 'script' | 'trigger' | 'approval' | 'failure' = 'script'
|
||||
export let isTemplate: boolean | undefined = undefined
|
||||
export let displayLock = false
|
||||
|
||||
type Item = {
|
||||
path: string
|
||||
summary?: string
|
||||
@@ -22,33 +18,54 @@
|
||||
hash?: string
|
||||
}
|
||||
|
||||
let items: Item[] | undefined = undefined
|
||||
let items = $state(undefined) as Item[] | undefined
|
||||
|
||||
let filteredItems: (Item & { marked?: string })[] | undefined = undefined
|
||||
export let filter = ''
|
||||
let filteredItems = $state(undefined) as (Item & { marked?: string })[] | undefined
|
||||
interface Props {
|
||||
kind?: 'script' | 'trigger' | 'approval' | 'failure'
|
||||
isTemplate?: boolean | undefined
|
||||
displayLock?: boolean
|
||||
filter?: string
|
||||
children?: import('svelte').Snippet
|
||||
}
|
||||
|
||||
$: $workspaceStore && kind && loadItems()
|
||||
let {
|
||||
kind = 'script',
|
||||
isTemplate = undefined,
|
||||
displayLock = false,
|
||||
filter = $bindable(''),
|
||||
children
|
||||
}: Props = $props()
|
||||
|
||||
async function loadItems(): Promise<void> {
|
||||
items = await ScriptService.listScripts({
|
||||
workspace: $workspaceStore!,
|
||||
kinds: kind,
|
||||
isTemplate
|
||||
isTemplate,
|
||||
withoutDescription: true
|
||||
})
|
||||
}
|
||||
|
||||
let ownerFilter: string | undefined = undefined
|
||||
$: if ($workspaceStore) {
|
||||
ownerFilter = undefined
|
||||
}
|
||||
$: prefilteredItems = ownerFilter ? items?.filter((x) => x.path.startsWith(ownerFilter!)) : items
|
||||
|
||||
$: owners = Array.from(
|
||||
new Set(filteredItems?.map((x) => x.path.split('/').slice(0, 2).join('/')) ?? [])
|
||||
).sort()
|
||||
let ownerFilter: string | undefined = $state(undefined)
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
let lockHash = false
|
||||
let lockHash = $state(false)
|
||||
$effect(() => {
|
||||
$workspaceStore && kind && untrack(() => loadItems())
|
||||
})
|
||||
$effect(() => {
|
||||
if ($workspaceStore) {
|
||||
ownerFilter = undefined
|
||||
}
|
||||
})
|
||||
let prefilteredItems = $derived(
|
||||
ownerFilter ? items?.filter((x) => x.path.startsWith(ownerFilter!)) : items
|
||||
)
|
||||
let owners = $derived(
|
||||
Array.from(
|
||||
new Set(filteredItems?.map((x) => x.path.split('/').slice(0, 2).join('/')) ?? [])
|
||||
).sort()
|
||||
)
|
||||
</script>
|
||||
|
||||
<SearchItems
|
||||
@@ -59,7 +76,7 @@
|
||||
/>
|
||||
<div class="flex flex-col min-h-0">
|
||||
<div class="w-full flex items-center gap-2 mb-3">
|
||||
<slot />
|
||||
{@render children?.()}
|
||||
|
||||
<TextInput
|
||||
inputProps={{
|
||||
@@ -109,7 +126,7 @@
|
||||
<li class="flex flex-row w-full">
|
||||
<button
|
||||
class="p-4 gap-1 flex flex-row grow hover:bg-surface-hover bg-surface transition-all text-primary"
|
||||
on:click={() => {
|
||||
onclick={() => {
|
||||
dispatch('pick', { path, hash: lockHash ? hash : undefined })
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -13,8 +13,13 @@
|
||||
}) =>
|
||||
workspace && get(userStore)
|
||||
? kind == 'flow'
|
||||
? FlowService.listFlows({ workspace })
|
||||
: ScriptService.listScripts({ workspace, kinds: kind, isTemplate })
|
||||
? FlowService.listFlows({ workspace, withoutDescription: true })
|
||||
: ScriptService.listScripts({
|
||||
workspace,
|
||||
kinds: kind,
|
||||
isTemplate,
|
||||
withoutDescription: true
|
||||
})
|
||||
: undefined,
|
||||
initialWorkspace
|
||||
? {
|
||||
|
||||
@@ -85,7 +85,8 @@
|
||||
workspace: $workspaceStore!,
|
||||
showArchived: archived ? true : undefined,
|
||||
includeWithoutMain: includeWithoutMain ? true : undefined,
|
||||
includeDraftOnly: true
|
||||
includeDraftOnly: true,
|
||||
withoutDescription: true
|
||||
})
|
||||
|
||||
scripts = loadedScripts.map((script: Script) => {
|
||||
@@ -102,7 +103,8 @@
|
||||
await FlowService.listFlows({
|
||||
workspace: $workspaceStore!,
|
||||
showArchived: archived ? true : undefined,
|
||||
includeDraftOnly: true
|
||||
includeDraftOnly: true,
|
||||
withoutDescription: true
|
||||
})
|
||||
).map((x: Flow) => {
|
||||
return {
|
||||
|
||||
@@ -484,10 +484,12 @@
|
||||
|
||||
async function fetchCombinedItems() {
|
||||
const scripts = await ScriptService.listScripts({
|
||||
workspace: $workspaceStore!
|
||||
workspace: $workspaceStore!,
|
||||
withoutDescription: true
|
||||
})
|
||||
const flows = await FlowService.listFlows({
|
||||
workspace: $workspaceStore!
|
||||
workspace: $workspaceStore!,
|
||||
withoutDescription: true
|
||||
})
|
||||
const apps = await AppService.listApps({ workspace: $workspaceStore! })
|
||||
const raw_apps = await RawAppService.listRawApps({ workspace: $workspaceStore! })
|
||||
|
||||
@@ -202,7 +202,8 @@
|
||||
const scripts = await ScriptService.listScripts({
|
||||
starredOnly: favoriteOnly,
|
||||
workspace,
|
||||
pathStart
|
||||
pathStart,
|
||||
withoutDescription: true
|
||||
})
|
||||
return scripts.map((x) => x.path)
|
||||
}
|
||||
@@ -219,7 +220,8 @@
|
||||
const flows = await FlowService.listFlows({
|
||||
starredOnly: favoriteOnly,
|
||||
workspace,
|
||||
pathStart
|
||||
pathStart,
|
||||
withoutDescription: true
|
||||
})
|
||||
return flows.map((x) => x.path)
|
||||
}
|
||||
|
||||
@@ -155,11 +155,13 @@
|
||||
const scripts = await ScriptService.listScripts({
|
||||
workspace: $workspaceStore ?? '',
|
||||
starredOnly: true,
|
||||
includeWithoutMain: true
|
||||
includeWithoutMain: true,
|
||||
withoutDescription: true
|
||||
})
|
||||
const flows = await FlowService.listFlows({
|
||||
workspace: $workspaceStore ?? '',
|
||||
starredOnly: true
|
||||
starredOnly: true,
|
||||
withoutDescription: true
|
||||
})
|
||||
const apps = await AppService.listApps({
|
||||
workspace: $workspaceStore ?? '',
|
||||
|
||||
+2
-2
@@ -4,8 +4,8 @@ verify_ssl = true
|
||||
name = "pypi"
|
||||
|
||||
[packages]
|
||||
wmill = ">=1.583.0"
|
||||
wmill_pg = ">=1.583.0"
|
||||
wmill = ">=1.583.1"
|
||||
wmill_pg = ">=1.583.1"
|
||||
sendgrid = "*"
|
||||
mysql-connector-python = "*"
|
||||
pymongo = "*"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
openapi: "3.0.3"
|
||||
|
||||
info:
|
||||
version: 1.583.0
|
||||
version: 1.583.1
|
||||
title: OpenFlow Spec
|
||||
contact:
|
||||
name: Ruben Fiszel
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
RootModule = 'WindmillClient.psm1'
|
||||
|
||||
# Version number of this module.
|
||||
ModuleVersion = '1.583.0'
|
||||
ModuleVersion = '1.583.1'
|
||||
|
||||
# Supported PSEditions
|
||||
# CompatiblePSEditions = @()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[tool.poetry]
|
||||
name = "wmill"
|
||||
version = "1.583.0"
|
||||
version = "1.583.1"
|
||||
description = "A client library for accessing Windmill server wrapping the Windmill client API"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://windmill.dev"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[tool.poetry]
|
||||
name = "wmill-pg"
|
||||
version = "1.583.0"
|
||||
version = "1.583.1"
|
||||
description = "An extension client for the wmill client library focused on pg"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://windmill.dev"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@windmill/windmill",
|
||||
"version": "1.583.0",
|
||||
"version": "1.583.1",
|
||||
"exports": "./src/index.ts",
|
||||
"publish": {
|
||||
"exclude": ["!src", "./s3Types.ts", "./client.ts"]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "windmill-client",
|
||||
"description": "Windmill SDK client for browsers and Node.js",
|
||||
"version": "1.583.0",
|
||||
"version": "1.583.1",
|
||||
"author": "Ruben Fiszel",
|
||||
"license": "Apache 2.0",
|
||||
"devDependencies": {
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
1.583.0
|
||||
1.583.1
|
||||
|
||||
Reference in New Issue
Block a user