mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-20 16:02:28 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
39f0752525 | ||
|
|
1ee78da4bf | ||
|
|
0a336467d8 |
@@ -1,54 +1,5 @@
|
||||
# Changelog
|
||||
|
||||
## [1.383.0](https://github.com/windmill-labs/windmill/compare/v1.382.2...v1.383.0) (2024-08-22)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add native html select support + fix mobile scroll on app text component ([d604b6f](https://github.com/windmill-labs/windmill/commit/d604b6f2a0e5755c949f302c0490de47a8d662ca))
|
||||
* add wrap_body header to webhooks ([9226d6c](https://github.com/windmill-labs/windmill/commit/9226d6cbc119f6a1b16936ebb855ff4f50c0e122))
|
||||
* improve early stop ([#4257](https://github.com/windmill-labs/windmill/issues/4257)) ([bcde2e6](https://github.com/windmill-labs/windmill/commit/bcde2e62d7846822cfe7f8ef89a9484938829903))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **frontend:** fix large JSON viewer ([#4273](https://github.com/windmill-labs/windmill/issues/4273)) ([b3eabff](https://github.com/windmill-labs/windmill/commit/b3eabffb76e266269b2f5ff471a053fa065da4d0))
|
||||
* **python-client:** only require httpx to be >= 0.24 instead of ^0.24 ([fc12aeb](https://github.com/windmill-labs/windmill/commit/fc12aeb3961b8a1a42a8493e3774815c940b75af))
|
||||
|
||||
## [1.382.2](https://github.com/windmill-labs/windmill/compare/v1.382.1...v1.382.2) (2024-08-20)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **app:** database studio/empty table count reset ([d6d3389](https://github.com/windmill-labs/windmill/commit/d6d33898a765f910f66cd0cfbd70a439ab107528))
|
||||
* **frontend:** Fix initial FlowGraph rendering on Chrome ([#4268](https://github.com/windmill-labs/windmill/issues/4268)) ([84d4e2c](https://github.com/windmill-labs/windmill/commit/84d4e2cb956ab4947b364d64c464fd5cf3c1d16f))
|
||||
* handle more gracefully worker without tags ([7e1f280](https://github.com/windmill-labs/windmill/commit/7e1f28071a7d6f3f34df417ea746fc9b5dca5157))
|
||||
|
||||
## [1.382.1](https://github.com/windmill-labs/windmill/compare/v1.382.0...v1.382.1) (2024-08-20)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **frontend:** Fix flow graph step preview ([#4264](https://github.com/windmill-labs/windmill/issues/4264)) ([0a6832a](https://github.com/windmill-labs/windmill/commit/0a6832aa4561468fb0150f9eb435b7ad857fc841))
|
||||
|
||||
## [1.382.0](https://github.com/windmill-labs/windmill/compare/v1.381.0...v1.382.0) (2024-08-20)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **frontend:** improve versions history by adding a diff viewer with… ([#4261](https://github.com/windmill-labs/windmill/issues/4261)) ([c19df12](https://github.com/windmill-labs/windmill/commit/c19df12292241c20c12e3de5d880c04df9b74324))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add FORCE_WORKER_TAGS & fix workers page when default worker group is missing ([09c6af0](https://github.com/windmill-labs/windmill/commit/09c6af05cd6e0b3b30f771a125b1fa330a938101))
|
||||
* **bun:** disable large transpiling cache ([1a0e32b](https://github.com/windmill-labs/windmill/commit/1a0e32b40b5f1ac5dcfe3639e697affb6e79a558))
|
||||
* **cli:** improve error message of cli ([f3bcadb](https://github.com/windmill-labs/windmill/commit/f3bcadbfb1e42b56996e273800aa0dcb01a6868b))
|
||||
* frontend/package.json & frontend/package-lock.json to reduce vulnerabilities ([#4255](https://github.com/windmill-labs/windmill/issues/4255)) ([7fe0442](https://github.com/windmill-labs/windmill/commit/7fe0442a814ed42b1775386be5f4defdcb5c0a0f))
|
||||
* **frontend:** nit worker limits ([#4258](https://github.com/windmill-labs/windmill/issues/4258)) ([bb92824](https://github.com/windmill-labs/windmill/commit/bb9282427399f305c3e8874204e6478272c43ff8))
|
||||
* improve resource picker handling of objects ([2502377](https://github.com/windmill-labs/windmill/commit/250237793b3c2b1afd5ee122b147301bc487eeeb))
|
||||
* **typescript-client:** runFlowAsync by default assume job doesn't outlive flow ([010e0fd](https://github.com/windmill-labs/windmill/commit/010e0fdc2352d740a72de124cc26eea8fc1915af))
|
||||
|
||||
## [1.381.0](https://github.com/windmill-labs/windmill/compare/v1.380.0...v1.381.0) (2024-08-16)
|
||||
|
||||
|
||||
|
||||
Generated
+178
-298
File diff suppressed because it is too large
Load Diff
+2
-2
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "windmill"
|
||||
version = "1.383.0"
|
||||
version = "1.381.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
@@ -25,7 +25,7 @@ members = [
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
version = "1.383.0"
|
||||
version = "1.381.0"
|
||||
authors = ["Ruben Fiszel <ruben@windmill.dev>"]
|
||||
edition = "2021"
|
||||
|
||||
|
||||
@@ -1113,7 +1113,6 @@ async fn test_deno_flow(db: Pool<Postgres>) {
|
||||
}
|
||||
.into(),
|
||||
stop_after_if: Default::default(),
|
||||
stop_after_all_iters_if: Default::default(),
|
||||
summary: Default::default(),
|
||||
suspend: Default::default(),
|
||||
retry: None,
|
||||
@@ -1153,7 +1152,6 @@ async fn test_deno_flow(db: Pool<Postgres>) {
|
||||
}
|
||||
.into(),
|
||||
stop_after_if: Default::default(),
|
||||
stop_after_all_iters_if: Default::default(),
|
||||
summary: Default::default(),
|
||||
suspend: Default::default(),
|
||||
retry: None,
|
||||
@@ -1168,7 +1166,6 @@ async fn test_deno_flow(db: Pool<Postgres>) {
|
||||
}
|
||||
.into(),
|
||||
stop_after_if: Default::default(),
|
||||
stop_after_all_iters_if: Default::default(),
|
||||
summary: Default::default(),
|
||||
suspend: Default::default(),
|
||||
retry: None,
|
||||
@@ -1273,7 +1270,6 @@ async fn test_deno_flow_same_worker(db: Pool<Postgres>) {
|
||||
concurrency_time_window_s: None,
|
||||
}.into(),
|
||||
stop_after_if: Default::default(),
|
||||
stop_after_all_iters_if: Default::default(),
|
||||
summary: Default::default(),
|
||||
suspend: Default::default(),
|
||||
retry: None,
|
||||
@@ -1323,7 +1319,6 @@ async fn test_deno_flow_same_worker(db: Pool<Postgres>) {
|
||||
concurrency_time_window_s: None,
|
||||
}.into(),
|
||||
stop_after_if: Default::default(),
|
||||
stop_after_all_iters_if: Default::default(),
|
||||
summary: Default::default(),
|
||||
suspend: Default::default(),
|
||||
retry: None,
|
||||
@@ -1359,7 +1354,6 @@ async fn test_deno_flow_same_worker(db: Pool<Postgres>) {
|
||||
concurrency_time_window_s: None,
|
||||
}.into(),
|
||||
stop_after_if: Default::default(),
|
||||
stop_after_all_iters_if: Default::default(),
|
||||
summary: Default::default(),
|
||||
suspend: Default::default(),
|
||||
retry: None,
|
||||
@@ -1375,7 +1369,6 @@ async fn test_deno_flow_same_worker(db: Pool<Postgres>) {
|
||||
],
|
||||
}.into(),
|
||||
stop_after_if: Default::default(),
|
||||
stop_after_all_iters_if: Default::default(),
|
||||
summary: Default::default(),
|
||||
suspend: Default::default(),
|
||||
retry: None,
|
||||
@@ -1418,7 +1411,6 @@ async fn test_deno_flow_same_worker(db: Pool<Postgres>) {
|
||||
concurrency_time_window_s: None,
|
||||
}.into(),
|
||||
stop_after_if: Default::default(),
|
||||
stop_after_all_iters_if: Default::default(),
|
||||
summary: Default::default(),
|
||||
suspend: Default::default(),
|
||||
retry: None,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
openapi: "3.0.3"
|
||||
|
||||
info:
|
||||
version: 1.383.0
|
||||
version: 1.381.0
|
||||
title: Windmill API
|
||||
|
||||
contact:
|
||||
|
||||
+241
-153
@@ -248,78 +248,6 @@ async fn fix_flow_versioning_migration(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
macro_rules! run_windmill_migration {
|
||||
($migration_job_name:expr, $db:expr, $code:block) => {
|
||||
{
|
||||
let migration_job_name = $migration_job_name;
|
||||
let db: &Pool<Postgres> = $db;
|
||||
|
||||
let has_done_migration = sqlx::query_scalar!(
|
||||
"SELECT EXISTS(SELECT name FROM windmill_migrations WHERE name = $1)",
|
||||
migration_job_name
|
||||
)
|
||||
.fetch_one(db)
|
||||
.await?
|
||||
.unwrap_or(false);
|
||||
if !has_done_migration {
|
||||
tracing::info!("Applying {migration_job_name} migration");
|
||||
let mut tx = db.begin().await?;
|
||||
let mut r = false;
|
||||
while !r {
|
||||
r = sqlx::query_scalar!("SELECT pg_try_advisory_lock(4242)")
|
||||
.fetch_one(&mut *tx)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
tracing::error!("Error acquiring {migration_job_name} lock: {e:#}");
|
||||
sqlx::migrate::MigrateError::Execute(e)
|
||||
})?
|
||||
.unwrap_or(false);
|
||||
if !r {
|
||||
tracing::info!("PG {migration_job_name} lock already acquired by another server or worker, retrying in 5s. (look for the advisory lock in pg_lock with granted = true)");
|
||||
tokio::time::sleep(std::time::Duration::from_secs(5)).await;
|
||||
}
|
||||
}
|
||||
tracing::info!("acquired lock for {migration_job_name}");
|
||||
|
||||
let has_done_migration = sqlx::query_scalar!(
|
||||
"SELECT EXISTS(SELECT name FROM windmill_migrations WHERE name = $1)",
|
||||
migration_job_name
|
||||
)
|
||||
.fetch_one(db)
|
||||
.await?
|
||||
.unwrap_or(false);
|
||||
|
||||
if !has_done_migration {
|
||||
|
||||
$code
|
||||
|
||||
sqlx::query!(
|
||||
"INSERT INTO windmill_migrations (name) VALUES ($1) ON CONFLICT DO NOTHING",
|
||||
migration_job_name
|
||||
)
|
||||
.execute(&mut *tx)
|
||||
.await?;
|
||||
tracing::info!("Finished applying {migration_job_name} migration");
|
||||
} else {
|
||||
tracing::info!("migration {migration_job_name} already done");
|
||||
}
|
||||
|
||||
let _ = sqlx::query("SELECT pg_advisory_unlock(4242)")
|
||||
.execute(&mut *tx)
|
||||
.await?;
|
||||
tx.commit().await?;
|
||||
tracing::info!("released lock for {migration_job_name}");
|
||||
|
||||
|
||||
tracing::info!("Finished applying {migration_job_name} migration");
|
||||
} else {
|
||||
tracing::info!("migration {migration_job_name} already done");
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async fn fix_job_completed_index(db: &DB) -> Result<(), Error> {
|
||||
// let has_done_migration = sqlx::query_scalar!(
|
||||
// "SELECT EXISTS(SELECT name FROM windmill_migrations WHERE name = 'fix_job_completed_index')"
|
||||
@@ -362,124 +290,284 @@ async fn fix_job_completed_index(db: &DB) -> Result<(), Error> {
|
||||
// tx.commit().await?;
|
||||
// }
|
||||
|
||||
run_windmill_migration!("fix_job_completed_index_2", &db, {
|
||||
// sqlx::query(
|
||||
// "CREATE INDEX CONCURRENTLY IF NOT EXISTS ix_completed_job_workspace_id_created_at_new_2 ON completed_job (workspace_id, job_kind, success, is_skipped, is_flow_step, created_at DESC)"
|
||||
// ).execute(db).await?;
|
||||
let migration_job_name = "fix_job_completed_index_2";
|
||||
let has_done_migration = sqlx::query_scalar!(
|
||||
"SELECT EXISTS(SELECT name FROM windmill_migrations WHERE name = $1)",
|
||||
migration_job_name
|
||||
)
|
||||
.fetch_one(db)
|
||||
.await?
|
||||
.unwrap_or(false);
|
||||
if !has_done_migration {
|
||||
tracing::info!("Applying {migration_job_name} migration");
|
||||
let mut tx = db.begin().await?;
|
||||
let mut r = false;
|
||||
while !r {
|
||||
r = sqlx::query_scalar!("SELECT pg_try_advisory_lock(4242)")
|
||||
.fetch_one(&mut *tx)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
tracing::error!("Error acquiring {migration_job_name} lock: {e:#}");
|
||||
sqlx::migrate::MigrateError::Execute(e)
|
||||
})?
|
||||
.unwrap_or(false);
|
||||
if !r {
|
||||
tracing::info!("PG {migration_job_name} lock already acquired by another server or worker, retrying in 5s. (look for the advisory lock in pg_lock with granted = true)");
|
||||
tokio::time::sleep(std::time::Duration::from_secs(5)).await;
|
||||
}
|
||||
}
|
||||
|
||||
// sqlx::query(
|
||||
// "CREATE INDEX CONCURRENTLY IF NOT EXISTS ix_completed_job_workspace_id_started_at_new ON completed_job (workspace_id, job_kind, success, is_skipped, is_flow_step, started_at DESC)"
|
||||
// ).execute(db).await?;
|
||||
|
||||
sqlx::query("DROP INDEX CONCURRENTLY IF EXISTS ix_completed_job_workspace_id_created_at")
|
||||
.execute(db)
|
||||
.await?;
|
||||
|
||||
sqlx::query(
|
||||
"DROP INDEX CONCURRENTLY IF EXISTS ix_completed_job_workspace_id_created_at_new",
|
||||
tracing::info!("acquired lock for {migration_job_name}");
|
||||
let has_done_migration = sqlx::query_scalar!(
|
||||
"SELECT EXISTS(SELECT name FROM windmill_migrations WHERE name = $1)",
|
||||
migration_job_name
|
||||
)
|
||||
.execute(db)
|
||||
.await?;
|
||||
});
|
||||
.fetch_one(db)
|
||||
.await?
|
||||
.unwrap_or(false);
|
||||
|
||||
run_windmill_migration!("fix_job_completed_index_3", &db, {
|
||||
sqlx::query("DROP INDEX CONCURRENTLY IF EXISTS index_completed_job_on_schedule_path")
|
||||
if !has_done_migration {
|
||||
// sqlx::query(
|
||||
// "CREATE INDEX CONCURRENTLY IF NOT EXISTS ix_completed_job_workspace_id_created_at_new_2 ON completed_job (workspace_id, job_kind, success, is_skipped, is_flow_step, created_at DESC)"
|
||||
// ).execute(db).await?;
|
||||
|
||||
// sqlx::query(
|
||||
// "CREATE INDEX CONCURRENTLY IF NOT EXISTS ix_completed_job_workspace_id_started_at_new ON completed_job (workspace_id, job_kind, success, is_skipped, is_flow_step, started_at DESC)"
|
||||
// ).execute(db).await?;
|
||||
|
||||
sqlx::query(
|
||||
"DROP INDEX CONCURRENTLY IF EXISTS ix_completed_job_workspace_id_created_at",
|
||||
)
|
||||
.execute(db)
|
||||
.await?;
|
||||
|
||||
sqlx::query("DROP INDEX CONCURRENTLY IF EXISTS concurrency_limit_stats_queue")
|
||||
sqlx::query(
|
||||
"DROP INDEX CONCURRENTLY IF EXISTS ix_completed_job_workspace_id_created_at_new",
|
||||
)
|
||||
.execute(db)
|
||||
.await?;
|
||||
|
||||
sqlx::query("DROP INDEX CONCURRENTLY IF EXISTS root_job_index")
|
||||
sqlx::query!(
|
||||
"INSERT INTO windmill_migrations (name) VALUES ($1) ON CONFLICT DO NOTHING",
|
||||
migration_job_name
|
||||
)
|
||||
.execute(&mut *tx)
|
||||
.await?;
|
||||
tracing::info!("Finished applying {migration_job_name} migration");
|
||||
} else {
|
||||
tracing::info!("migration {migration_job_name} already done");
|
||||
}
|
||||
|
||||
let _ = sqlx::query("SELECT pg_advisory_unlock(4242)")
|
||||
.execute(&mut *tx)
|
||||
.await?;
|
||||
tx.commit().await?;
|
||||
tracing::info!("released lock for {migration_job_name}");
|
||||
}
|
||||
|
||||
let migration_job_name = "fix_job_completed_index_3";
|
||||
let has_done_migration = sqlx::query_scalar!(
|
||||
"SELECT EXISTS(SELECT name FROM windmill_migrations WHERE name = $1)",
|
||||
migration_job_name
|
||||
)
|
||||
.fetch_one(db)
|
||||
.await?
|
||||
.unwrap_or(false);
|
||||
if !has_done_migration {
|
||||
tracing::info!("Applying {migration_job_name} migration");
|
||||
let mut tx = db.begin().await?;
|
||||
let mut r = false;
|
||||
while !r {
|
||||
r = sqlx::query_scalar!("SELECT pg_try_advisory_lock(4242)")
|
||||
.fetch_one(&mut *tx)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
tracing::error!("Error acquiring {migration_job_name} lock: {e:#}");
|
||||
sqlx::migrate::MigrateError::Execute(e)
|
||||
})?
|
||||
.unwrap_or(false);
|
||||
if !r {
|
||||
tracing::info!("PG {migration_job_name} lock already acquired by another server or worker, retrying in 5s. (look for the advisory lock in pg_lock with granted = true)");
|
||||
tokio::time::sleep(std::time::Duration::from_secs(5)).await;
|
||||
}
|
||||
}
|
||||
tracing::info!("acquired lock for {migration_job_name}");
|
||||
|
||||
let has_done_migration = sqlx::query_scalar!(
|
||||
"SELECT EXISTS(SELECT name FROM windmill_migrations WHERE name = $1)",
|
||||
migration_job_name
|
||||
)
|
||||
.fetch_one(db)
|
||||
.await?
|
||||
.unwrap_or(false);
|
||||
|
||||
if !has_done_migration {
|
||||
sqlx::query("DROP INDEX CONCURRENTLY IF EXISTS index_completed_job_on_schedule_path")
|
||||
.execute(db)
|
||||
.await?;
|
||||
|
||||
sqlx::query("DROP INDEX CONCURRENTLY IF EXISTS concurrency_limit_stats_queue")
|
||||
.execute(db)
|
||||
.await?;
|
||||
|
||||
sqlx::query("DROP INDEX CONCURRENTLY IF EXISTS root_job_index")
|
||||
.execute(db)
|
||||
.await?;
|
||||
|
||||
sqlx::query("DROP INDEX CONCURRENTLY IF EXISTS index_completed_on_created")
|
||||
.execute(db)
|
||||
.await?;
|
||||
|
||||
sqlx::query!(
|
||||
"INSERT INTO windmill_migrations (name) VALUES ($1) ON CONFLICT DO NOTHING",
|
||||
migration_job_name
|
||||
)
|
||||
.execute(&mut *tx)
|
||||
.await?;
|
||||
tracing::info!("Finished applying {migration_job_name} migration");
|
||||
} else {
|
||||
tracing::info!("migration {migration_job_name} already done");
|
||||
}
|
||||
|
||||
let _ = sqlx::query("SELECT pg_advisory_unlock(4242)")
|
||||
.execute(&mut *tx)
|
||||
.await?;
|
||||
tx.commit().await?;
|
||||
tracing::info!("released lock for {migration_job_name}");
|
||||
}
|
||||
|
||||
let migration_job_name = "fix_job_completed_index_4";
|
||||
let has_done_migration = sqlx::query_scalar!(
|
||||
"SELECT EXISTS(SELECT name FROM windmill_migrations WHERE name = $1)",
|
||||
migration_job_name
|
||||
)
|
||||
.fetch_one(db)
|
||||
.await?
|
||||
.unwrap_or(false);
|
||||
if !has_done_migration {
|
||||
tracing::info!("Applying {migration_job_name} migration");
|
||||
let mut tx = db.begin().await?;
|
||||
let mut r = false;
|
||||
while !r {
|
||||
r = sqlx::query_scalar!("SELECT pg_try_advisory_lock(4242)")
|
||||
.fetch_one(&mut *tx)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
tracing::error!("Error acquiring {migration_job_name} lock: {e:#}");
|
||||
sqlx::migrate::MigrateError::Execute(e)
|
||||
})?
|
||||
.unwrap_or(false);
|
||||
if !r {
|
||||
tracing::info!("PG {migration_job_name} lock already acquired by another server or worker, retrying in 5s. (look for the advisory lock in pg_lock with granted = true)");
|
||||
tokio::time::sleep(std::time::Duration::from_secs(5)).await;
|
||||
}
|
||||
}
|
||||
tracing::info!("acquired lock for {migration_job_name}");
|
||||
|
||||
let has_done_migration = sqlx::query_scalar!(
|
||||
"SELECT EXISTS(SELECT name FROM windmill_migrations WHERE name = $1)",
|
||||
migration_job_name
|
||||
)
|
||||
.fetch_one(db)
|
||||
.await?
|
||||
.unwrap_or(false);
|
||||
|
||||
if !has_done_migration {
|
||||
let mut i = 1;
|
||||
tracing::info!("step {i} of {migration_job_name} migration");
|
||||
sqlx::query("create index concurrently if not exists ix_completed_job_workspace_id_created_at_new_3 ON completed_job (workspace_id, created_at DESC)")
|
||||
.execute(db)
|
||||
.await?;
|
||||
i += 1;
|
||||
tracing::info!("step {i} of {migration_job_name} migration");
|
||||
|
||||
sqlx::query("create index concurrently if not exists ix_completed_job_workspace_id_created_at_new_8 ON completed_job (workspace_id, created_at DESC) where job_kind in ('deploymentcallback') AND parent_job IS NULL")
|
||||
.execute(db)
|
||||
.await?;
|
||||
i += 1;
|
||||
tracing::info!("step {i} of {migration_job_name} migration");
|
||||
|
||||
sqlx::query("DROP INDEX CONCURRENTLY IF EXISTS index_completed_on_created")
|
||||
sqlx::query("create index concurrently if not exists ix_completed_job_workspace_id_created_at_new_9 ON completed_job (workspace_id, created_at DESC) where job_kind in ('dependencies', 'flowdependencies', 'appdependencies') AND parent_job IS NULL")
|
||||
.execute(db)
|
||||
.await?;
|
||||
});
|
||||
i += 1;
|
||||
tracing::info!("step {i} of {migration_job_name} migration");
|
||||
|
||||
run_windmill_migration!("fix_job_completed_index_4", &db, {
|
||||
let migration_job_name = "fix_job_completed_index_4";
|
||||
let mut i = 1;
|
||||
tracing::info!("step {i} of {migration_job_name} migration");
|
||||
sqlx::query("create index concurrently if not exists ix_completed_job_workspace_id_created_at_new_3 ON completed_job (workspace_id, created_at DESC)")
|
||||
sqlx::query("create index concurrently if not exists ix_completed_job_workspace_id_created_at_new_5 ON completed_job (workspace_id, created_at DESC) where job_kind in ('preview', 'flowpreview') AND parent_job IS NULL")
|
||||
.execute(db)
|
||||
.await?;
|
||||
i += 1;
|
||||
tracing::info!("step {i} of {migration_job_name} migration");
|
||||
i += 1;
|
||||
tracing::info!("step {i} of {migration_job_name} migration");
|
||||
|
||||
sqlx::query("create index concurrently if not exists ix_completed_job_workspace_id_created_at_new_8 ON completed_job (workspace_id, created_at DESC) where job_kind in ('deploymentcallback') AND parent_job IS NULL")
|
||||
.execute(db)
|
||||
.await?;
|
||||
i += 1;
|
||||
tracing::info!("step {i} of {migration_job_name} migration");
|
||||
|
||||
sqlx::query("create index concurrently if not exists ix_completed_job_workspace_id_created_at_new_9 ON completed_job (workspace_id, created_at DESC) where job_kind in ('dependencies', 'flowdependencies', 'appdependencies') AND parent_job IS NULL")
|
||||
.execute(db)
|
||||
.await?;
|
||||
i += 1;
|
||||
tracing::info!("step {i} of {migration_job_name} migration");
|
||||
|
||||
sqlx::query("create index concurrently if not exists ix_completed_job_workspace_id_created_at_new_5 ON completed_job (workspace_id, created_at DESC) where job_kind in ('preview', 'flowpreview') AND parent_job IS NULL")
|
||||
sqlx::query("create index concurrently if not exists ix_completed_job_workspace_id_created_at_new_6 ON completed_job (workspace_id, created_at DESC) where job_kind in ('script', 'flow') AND parent_job IS NULL")
|
||||
.execute(db)
|
||||
.await?;
|
||||
i += 1;
|
||||
tracing::info!("step {i} of {migration_job_name} migration");
|
||||
i += 1;
|
||||
tracing::info!("step {i} of {migration_job_name} migration");
|
||||
|
||||
sqlx::query("create index concurrently if not exists ix_completed_job_workspace_id_created_at_new_6 ON completed_job (workspace_id, created_at DESC) where job_kind in ('script', 'flow') AND parent_job IS NULL")
|
||||
sqlx::query("create index concurrently if not exists ix_completed_job_workspace_id_created_at_new_7 ON completed_job (workspace_id, success, created_at DESC) where job_kind in ('script', 'flow') AND parent_job IS NULL")
|
||||
.execute(db)
|
||||
.await?;
|
||||
i += 1;
|
||||
tracing::info!("step {i} of {migration_job_name} migration");
|
||||
i += 1;
|
||||
tracing::info!("step {i} of {migration_job_name} migration");
|
||||
|
||||
sqlx::query("create index concurrently if not exists ix_completed_job_workspace_id_created_at_new_7 ON completed_job (workspace_id, success, created_at DESC) where job_kind in ('script', 'flow') AND parent_job IS NULL")
|
||||
sqlx::query("create index concurrently if not exists ix_completed_job_workspace_id_started_at_new_2 ON completed_job (workspace_id, started_at DESC)")
|
||||
.execute(db)
|
||||
.await?;
|
||||
i += 1;
|
||||
tracing::info!("step {i} of {migration_job_name} migration");
|
||||
i += 1;
|
||||
tracing::info!("step {i} of {migration_job_name} migration");
|
||||
|
||||
sqlx::query("create index concurrently if not exists ix_completed_job_workspace_id_started_at_new_2 ON completed_job (workspace_id, started_at DESC)")
|
||||
.execute(db)
|
||||
.await?;
|
||||
i += 1;
|
||||
tracing::info!("step {i} of {migration_job_name} migration");
|
||||
|
||||
sqlx::query("create index concurrently if not exists root_job_index_by_path_2 ON completed_job (workspace_id, script_path, created_at desc) WHERE parent_job IS NULL")
|
||||
sqlx::query("create index concurrently if not exists root_job_index_by_path_2 ON completed_job (workspace_id, script_path, created_at desc) WHERE parent_job IS NULL")
|
||||
.execute(db)
|
||||
.await?;
|
||||
|
||||
i += 1;
|
||||
tracing::info!("step {i} of {migration_job_name} migration");
|
||||
i += 1;
|
||||
tracing::info!("step {i} of {migration_job_name} migration");
|
||||
|
||||
sqlx::query("create index concurrently if not exists ix_completed_job_created_at ON completed_job (created_at DESC)")
|
||||
sqlx::query("create index concurrently if not exists ix_completed_job_created_at ON completed_job (created_at DESC)")
|
||||
.execute(db)
|
||||
.await?;
|
||||
|
||||
i += 1;
|
||||
tracing::info!("step {i} of {migration_job_name} migration");
|
||||
i += 1;
|
||||
tracing::info!("step {i} of {migration_job_name} migration");
|
||||
|
||||
sqlx::query(
|
||||
"DROP INDEX CONCURRENTLY IF EXISTS ix_completed_job_workspace_id_created_at_new_2",
|
||||
)
|
||||
.execute(db)
|
||||
.await?;
|
||||
i += 1;
|
||||
tracing::info!("step {i} of {migration_job_name} migration");
|
||||
|
||||
sqlx::query(
|
||||
"DROP INDEX CONCURRENTLY IF EXISTS ix_completed_job_workspace_id_started_at_new",
|
||||
)
|
||||
.execute(db)
|
||||
.await?;
|
||||
i += 1;
|
||||
tracing::info!("step {i} of {migration_job_name} migration");
|
||||
|
||||
sqlx::query("DROP INDEX CONCURRENTLY IF EXISTS root_job_index_by_path")
|
||||
sqlx::query(
|
||||
"DROP INDEX CONCURRENTLY IF EXISTS ix_completed_job_workspace_id_created_at_new_2",
|
||||
)
|
||||
.execute(db)
|
||||
.await?;
|
||||
});
|
||||
i += 1;
|
||||
tracing::info!("step {i} of {migration_job_name} migration");
|
||||
|
||||
sqlx::query(
|
||||
"DROP INDEX CONCURRENTLY IF EXISTS ix_completed_job_workspace_id_started_at_new",
|
||||
)
|
||||
.execute(db)
|
||||
.await?;
|
||||
i += 1;
|
||||
tracing::info!("step {i} of {migration_job_name} migration");
|
||||
|
||||
sqlx::query("DROP INDEX CONCURRENTLY IF EXISTS root_job_index_by_path")
|
||||
.execute(db)
|
||||
.await?;
|
||||
|
||||
sqlx::query!(
|
||||
"INSERT INTO windmill_migrations (name) VALUES ($1) ON CONFLICT DO NOTHING",
|
||||
migration_job_name
|
||||
)
|
||||
.execute(&mut *tx)
|
||||
.await?;
|
||||
tracing::info!("Finished applying {migration_job_name} migration");
|
||||
} else {
|
||||
tracing::info!("migration {migration_job_name} already done");
|
||||
}
|
||||
|
||||
let _ = sqlx::query("SELECT pg_advisory_unlock(4242)")
|
||||
.execute(&mut *tx)
|
||||
.await?;
|
||||
tx.commit().await?;
|
||||
tracing::info!("released lock for {migration_job_name}");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1144,7 +1144,6 @@ mod tests {
|
||||
tag_override: None,
|
||||
}),
|
||||
stop_after_if: None,
|
||||
stop_after_all_iters_if: None,
|
||||
summary: None,
|
||||
suspend: Default::default(),
|
||||
retry: None,
|
||||
@@ -1173,7 +1172,6 @@ mod tests {
|
||||
expr: "foo = 'bar'".to_string(),
|
||||
skip_if_stopped: false,
|
||||
}),
|
||||
stop_after_all_iters_if: None,
|
||||
summary: None,
|
||||
suspend: Default::default(),
|
||||
retry: None,
|
||||
@@ -1200,7 +1198,6 @@ mod tests {
|
||||
expr: "previous.isEmpty()".to_string(),
|
||||
skip_if_stopped: false,
|
||||
}),
|
||||
stop_after_all_iters_if: None,
|
||||
summary: None,
|
||||
suspend: Default::default(),
|
||||
retry: None,
|
||||
@@ -1226,7 +1223,6 @@ mod tests {
|
||||
expr: "previous.isEmpty()".to_string(),
|
||||
skip_if_stopped: false,
|
||||
}),
|
||||
stop_after_all_iters_if: None,
|
||||
summary: None,
|
||||
suspend: Default::default(),
|
||||
retry: None,
|
||||
|
||||
@@ -236,8 +236,6 @@ pub struct FlowModule {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub stop_after_if: Option<StopAfterIf>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub stop_after_all_iters_if: Option<StopAfterIf>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub summary: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub suspend: Option<Suspend>,
|
||||
@@ -582,7 +580,6 @@ pub fn add_virtual_items_if_necessary(modules: &mut Vec<FlowModule>) {
|
||||
id: format!("{}-v", modules[modules.len() - 1].id),
|
||||
value: crate::worker::to_raw_value(&FlowModuleValue::Identity),
|
||||
stop_after_if: None,
|
||||
stop_after_all_iters_if: None,
|
||||
summary: Some("Virtual module needed for suspend/sleep when last module".to_string()),
|
||||
mock: None,
|
||||
retry: None,
|
||||
|
||||
@@ -86,10 +86,6 @@ lazy_static::lazy_static! {
|
||||
}
|
||||
|
||||
pub async fn make_suspended_pull_query(wc: &WorkerConfig) {
|
||||
if wc.worker_tags.len() == 0 {
|
||||
tracing::error!("Empty tags in worker tags, skipping");
|
||||
return;
|
||||
}
|
||||
let query = format!(
|
||||
"UPDATE queue
|
||||
SET running = true
|
||||
@@ -118,10 +114,6 @@ pub async fn make_suspended_pull_query(wc: &WorkerConfig) {
|
||||
pub async fn make_pull_query(wc: &WorkerConfig) {
|
||||
let mut queries = vec![];
|
||||
for tags in wc.priority_tags_sorted.iter() {
|
||||
if tags.tags.len() == 0 {
|
||||
tracing::error!("Empty tags in priority tags, skipping");
|
||||
continue;
|
||||
}
|
||||
let query = format!("UPDATE queue
|
||||
SET running = true
|
||||
, started_at = coalesce(started_at, now())
|
||||
@@ -571,18 +563,6 @@ pub async fn load_worker_config(
|
||||
config.worker_tags = Some(all_tags);
|
||||
}
|
||||
|
||||
if let Some(force_worker_tags) = std::env::var("FORCE_WORKER_TAGS")
|
||||
.ok()
|
||||
.filter(|x| !x.is_empty())
|
||||
.map(|x| x.split(',').map(|x| x.to_string()).collect::<Vec<String>>())
|
||||
{
|
||||
tracing::info!(
|
||||
"Detected FORCE_WORKER_TAGS, forcing worker tags to: {:#?}",
|
||||
force_worker_tags
|
||||
);
|
||||
config.worker_tags = Some(force_worker_tags);
|
||||
}
|
||||
|
||||
// set worker_tags using default if none. If priority tags is set, compute the sorted priority tags as well
|
||||
let worker_tags = config
|
||||
.worker_tags
|
||||
|
||||
@@ -1967,11 +1967,6 @@ async fn pull_single_job_and_mark_as_running_no_concurrency_limit<
|
||||
* or suspend_until <= now() if it has timed out */
|
||||
let query = WORKER_SUSPENDED_PULL_QUERY.read().await;
|
||||
|
||||
if query.is_empty() {
|
||||
tracing::warn!("No suspended pull queries available");
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let r = if suspend_first {
|
||||
// tracing::info!("Pulling job with query: {}", query);
|
||||
sqlx::query_as::<_, QueuedJob>(&query)
|
||||
@@ -1987,11 +1982,6 @@ async fn pull_single_job_and_mark_as_running_no_concurrency_limit<
|
||||
|
||||
let queries = WORKER_PULL_QUERIES.read().await;
|
||||
|
||||
if queries.is_empty() {
|
||||
tracing::warn!("No pull queries available");
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
for query in queries.iter() {
|
||||
// tracing::info!("Pulling job with query: {}", query);
|
||||
let r = sqlx::query_as::<_, QueuedJob>(query)
|
||||
@@ -2598,7 +2588,6 @@ impl DecodeQueries {
|
||||
#[derive(Deserialize)]
|
||||
pub struct RequestQuery {
|
||||
pub raw: Option<bool>,
|
||||
pub wrap_body: Option<bool>,
|
||||
pub include_header: Option<String>,
|
||||
}
|
||||
|
||||
@@ -2633,14 +2622,13 @@ impl PushArgsOwned {
|
||||
async fn from_json(
|
||||
mut extra: HashMap<String, Box<RawValue>>,
|
||||
use_raw: bool,
|
||||
force_wrap_body: bool,
|
||||
str: String,
|
||||
) -> Result<Self, Response> {
|
||||
if use_raw {
|
||||
extra.insert("raw_string".to_string(), to_raw_value(&str));
|
||||
}
|
||||
|
||||
let wrap_body = force_wrap_body || str.len() > 0 && str.chars().next().unwrap() != '{';
|
||||
let wrap_body = str.len() > 0 && str.chars().next().unwrap() != '{';
|
||||
|
||||
if wrap_body {
|
||||
let args = serde_json::from_str::<Option<Box<RawValue>>>(&str)
|
||||
@@ -2745,7 +2733,7 @@ where
|
||||
req: Request<axum::body::Body>,
|
||||
_state: &S,
|
||||
) -> Result<Self, Self::Rejection> {
|
||||
let (content_type, mut extra, use_raw, wrap_body) = {
|
||||
let (content_type, mut extra, use_raw) = {
|
||||
let headers_map = req.headers();
|
||||
let content_type_header = headers_map.get(CONTENT_TYPE);
|
||||
let content_type = content_type_header.and_then(|value| value.to_str().ok());
|
||||
@@ -2757,8 +2745,7 @@ where
|
||||
extra.extend(queries);
|
||||
}
|
||||
let raw = query.raw.as_ref().is_some_and(|x| *x);
|
||||
let wrap_body = query.wrap_body.as_ref().is_some_and(|x| *x);
|
||||
(content_type, extra, raw, wrap_body)
|
||||
(content_type, extra, raw)
|
||||
};
|
||||
|
||||
if content_type.is_none() || content_type.unwrap().starts_with("application/json") {
|
||||
@@ -2768,7 +2755,7 @@ where
|
||||
let str = String::from_utf8(bytes.to_vec())
|
||||
.map_err(|e| Error::BadRequest(format!("invalid utf8: {}", e)).into_response())?;
|
||||
|
||||
PushArgsOwned::from_json(extra, use_raw, wrap_body, str).await
|
||||
PushArgsOwned::from_json(extra, use_raw, str).await
|
||||
} else if content_type
|
||||
.unwrap()
|
||||
.starts_with("application/cloudevents+json")
|
||||
@@ -3349,7 +3336,6 @@ pub async fn push<'c, 'd, R: rsmq_async::RsmqConnection + Send + 'c>(
|
||||
},
|
||||
),
|
||||
stop_after_if: None,
|
||||
stop_after_all_iters_if: None,
|
||||
summary: None,
|
||||
suspend: None,
|
||||
mock: None,
|
||||
|
||||
@@ -571,7 +571,6 @@ pub fn copy_recursively(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let original = entry.path();
|
||||
|
||||
if filetype.is_dir() {
|
||||
@@ -1291,10 +1290,6 @@ pub async fn get_common_bun_proc_envs(base_internal_url: &str) -> HashMap<String
|
||||
String::from("BUN_INSTALL_CACHE_DIR"),
|
||||
BUN_CACHE_DIR.to_string(),
|
||||
),
|
||||
(
|
||||
String::from("BUN_RUNTIME_TRANSPILER_CACHE_PATH"),
|
||||
"0".to_string(),
|
||||
),
|
||||
]);
|
||||
|
||||
if let Some(ref node_path) = NODE_PATH.as_ref() {
|
||||
|
||||
@@ -232,27 +232,22 @@ pub async fn update_flow_status_after_job_completion_internal<
|
||||
// "UPDATE FLOW STATUS 2: {module_index:#?} {module_status:#?} {old_status:#?} "
|
||||
// );
|
||||
|
||||
let (is_loop, skip_loop_failures, parallelism) = if matches!(
|
||||
let (skip_loop_failures, parallelism) = if matches!(
|
||||
module_status,
|
||||
FlowStatusModule::InProgress { iterator: Some(_), .. }
|
||||
) {
|
||||
let (loop_failures, parallelism) =
|
||||
compute_skip_loop_failures_and_parallelism(flow, old_status.step, db).await?;
|
||||
(true, loop_failures.unwrap_or(false), parallelism)
|
||||
(loop_failures.unwrap_or(false), parallelism)
|
||||
} else {
|
||||
(false, false, None)
|
||||
(false, None)
|
||||
};
|
||||
|
||||
let is_branch_all = matches!(
|
||||
module_status,
|
||||
FlowStatusModule::InProgress { branchall: Some(_), .. }
|
||||
);
|
||||
|
||||
// 0 length flows are not failure steps
|
||||
let is_failure_step =
|
||||
old_status.step >= old_status.modules.len() as i32 && old_status.modules.len() > 0;
|
||||
|
||||
let (mut stop_early, mut skip_if_stop_early, continue_on_error) = if let Some(se) =
|
||||
let (mut stop_early, skip_if_stop_early, continue_on_error) = if let Some(se) =
|
||||
stop_early_override
|
||||
{
|
||||
//do not stop early if module is a flow step
|
||||
@@ -285,18 +280,7 @@ pub async fn update_flow_status_after_job_completion_internal<
|
||||
.map_err(|e| Error::InternalErr(format!("retrieval of stop_early_expr from state: {e:#}")))?;
|
||||
|
||||
let stop_early = success
|
||||
&& !is_branch_all
|
||||
&& if let Some(expr) = r.stop_early_expr.clone() {
|
||||
let all_iters = match &module_status {
|
||||
FlowStatusModule::InProgress { flow_jobs: Some(flow_jobs), .. }
|
||||
if expr.contains("all_iters") =>
|
||||
{
|
||||
Some(Arc::new(
|
||||
retrieve_flow_jobs_results(db, w_id, flow_jobs).await?,
|
||||
))
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
compute_bool_from_expr(
|
||||
expr,
|
||||
Marc::new(
|
||||
@@ -306,7 +290,6 @@ pub async fn update_flow_status_after_job_completion_internal<
|
||||
.to_owned(),
|
||||
),
|
||||
result.clone(),
|
||||
all_iters,
|
||||
None,
|
||||
Some(client),
|
||||
None,
|
||||
@@ -752,50 +735,6 @@ pub async fn update_flow_status_after_job_completion_internal<
|
||||
_ => result.clone(),
|
||||
};
|
||||
|
||||
match &new_status {
|
||||
Some(FlowStatusModule::Success { .. }) if is_loop || is_branch_all => {
|
||||
let r_after_all_iters = sqlx::query_as::<_, SkipIfStopped>(
|
||||
"SELECT
|
||||
raw_flow->'modules'->$1::int->'stop_after_all_iters_if'->>'expr' as stop_early_expr,
|
||||
(raw_flow->'modules'->$1::int->'stop_after_all_iters_if'->>'skip_if_stopped')::bool as skip_if_stopped,
|
||||
NULL as continue_on_error,
|
||||
args
|
||||
FROM queue
|
||||
WHERE id = $2"
|
||||
)
|
||||
.bind(old_status.step)
|
||||
.bind(flow)
|
||||
.fetch_one(db)
|
||||
.await
|
||||
.map_err(|e| Error::InternalErr(format!("retrieval of stop_early_expr from state: {e:#}")))?;
|
||||
if let Some(expr) = r_after_all_iters.stop_early_expr {
|
||||
let should_stop = compute_bool_from_expr(
|
||||
expr,
|
||||
Marc::new(
|
||||
r_after_all_iters
|
||||
.args
|
||||
.map(|x| x.0)
|
||||
.unwrap_or_else(|| serde_json::from_str("{}").unwrap())
|
||||
.to_owned(),
|
||||
),
|
||||
nresult.clone(),
|
||||
None,
|
||||
None,
|
||||
Some(client),
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
if should_stop {
|
||||
stop_early = should_stop;
|
||||
skip_if_stop_early = r_after_all_iters.skip_if_stopped.unwrap_or(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if old_status.retry.fail_count > 0
|
||||
&& matches!(&new_status, Some(FlowStatusModule::Success { .. }))
|
||||
{
|
||||
@@ -1247,7 +1186,6 @@ async fn compute_bool_from_expr(
|
||||
expr: String,
|
||||
flow_args: Marc<HashMap<String, Box<RawValue>>>,
|
||||
result: Arc<Box<RawValue>>,
|
||||
all_iters: Option<Arc<Box<RawValue>>>,
|
||||
by_id: Option<IdContext>,
|
||||
client: Option<&AuthedClient>,
|
||||
resumes: Option<(Arc<Box<RawValue>>, Arc<Box<RawValue>>, Arc<Box<RawValue>>)>,
|
||||
@@ -1255,9 +1193,6 @@ async fn compute_bool_from_expr(
|
||||
) -> error::Result<bool> {
|
||||
let mut context = HashMap::with_capacity(if resumes.is_some() { 7 } else { 3 });
|
||||
context.insert("result".to_string(), result.clone());
|
||||
if let Some(all_iters) = all_iters {
|
||||
context.insert("all_iters".to_string(), all_iters);
|
||||
}
|
||||
context.insert("previous_result".to_string(), result.clone());
|
||||
|
||||
if let Some(resumes) = resumes {
|
||||
@@ -1633,7 +1568,6 @@ async fn push_next_flow_job<R: rsmq_async::RsmqConnection + Send + Sync + Clone>
|
||||
arc_flow_job_args.clone(),
|
||||
Arc::new(to_raw_value(&json!("{}"))),
|
||||
None,
|
||||
None,
|
||||
Some(client),
|
||||
None,
|
||||
Some(vec![(
|
||||
@@ -3048,7 +2982,6 @@ async fn compute_next_flow_transform(
|
||||
b.expr.to_string(),
|
||||
arc_flow_job_args.clone(),
|
||||
arc_last_job_result.clone(),
|
||||
None,
|
||||
Some(idcontext.clone()),
|
||||
Some(client),
|
||||
Some((resumes.clone(), resume.clone(), approvers.clone())),
|
||||
@@ -3325,7 +3258,6 @@ fn is_simple_modules(modules: &Vec<FlowModule>, flow: &FlowValue) -> bool {
|
||||
&& modules[0].cache_ttl.is_none()
|
||||
&& modules[0].retry.is_none()
|
||||
&& modules[0].stop_after_if.is_none()
|
||||
&& modules[0].stop_after_all_iters_if.is_none()
|
||||
&& (modules[0].mock.is_none() || modules[0].mock.as_ref().is_some_and(|m| !m.enabled))
|
||||
&& flow.failure_module.is_none();
|
||||
is_simple
|
||||
|
||||
+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.383.0";
|
||||
export const VERSION = "v1.381.0";
|
||||
|
||||
export async function login(email: string, password: string): Promise<string> {
|
||||
return await windmill.UserService.login({
|
||||
|
||||
+33
-18
@@ -12,7 +12,7 @@ import {
|
||||
yamlParse,
|
||||
} from "./deps.ts";
|
||||
import { requireLogin, resolveWorkspace, validatePath } from "./context.ts";
|
||||
import { resolve, track_job } from "./script.ts";
|
||||
import { findGlobalDeps, resolve, track_job } from "./script.ts";
|
||||
import { defaultFlowDefinition } from "./bootstrap/flow_bootstrap.ts";
|
||||
import { generateFlowLockInternal } from "./metadata.ts";
|
||||
import { SyncOptions, mergeConfigWithConfigFile } from "./conf.ts";
|
||||
@@ -115,20 +115,14 @@ export async function pushFlow(
|
||||
});
|
||||
} else {
|
||||
log.info(colors.bold.yellow("Creating new flow..."));
|
||||
try {
|
||||
await FlowService.createFlow({
|
||||
workspace: workspace,
|
||||
requestBody: {
|
||||
path: remotePath.replaceAll(SEP, "/"),
|
||||
deployment_message: message,
|
||||
...localFlow,
|
||||
},
|
||||
});
|
||||
} catch (e) {
|
||||
throw new Error(
|
||||
`Failed to create flow ${remotePath}: ${e.body ?? e.message}`
|
||||
);
|
||||
}
|
||||
await FlowService.createFlow({
|
||||
workspace: workspace,
|
||||
requestBody: {
|
||||
path: remotePath.replaceAll(SEP, "/"),
|
||||
deployment_message: message,
|
||||
...localFlow,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,8 +237,15 @@ async function generateLocks(
|
||||
await requireLogin(opts);
|
||||
opts = await mergeConfigWithConfigFile(opts);
|
||||
if (folder) {
|
||||
const globalDeps = await findGlobalDeps();
|
||||
// read script metadata file
|
||||
await generateFlowLockInternal(folder, false, workspace);
|
||||
await generateFlowLockInternal(
|
||||
folder,
|
||||
false,
|
||||
workspace,
|
||||
globalDeps,
|
||||
opts.defaultTs
|
||||
);
|
||||
} else {
|
||||
const ignore = await ignoreF(opts);
|
||||
const elems = Object.keys(
|
||||
@@ -264,8 +265,16 @@ async function generateLocks(
|
||||
).map((x) => x.substring(0, x.lastIndexOf(SEP)));
|
||||
let hasAny = false;
|
||||
|
||||
const globalDeps = await findGlobalDeps();
|
||||
|
||||
for (const folder of elems) {
|
||||
const candidate = await generateFlowLockInternal(folder, true, workspace);
|
||||
const candidate = await generateFlowLockInternal(
|
||||
folder,
|
||||
true,
|
||||
workspace,
|
||||
globalDeps,
|
||||
opts.defaultTs
|
||||
);
|
||||
if (candidate) {
|
||||
hasAny = true;
|
||||
log.info(colors.green(`+ ${candidate}`));
|
||||
@@ -287,7 +296,13 @@ async function generateLocks(
|
||||
return;
|
||||
}
|
||||
for (const folder of elems) {
|
||||
await generateFlowLockInternal(folder, false, workspace);
|
||||
await generateFlowLockInternal(
|
||||
folder,
|
||||
false,
|
||||
workspace,
|
||||
globalDeps,
|
||||
opts.defaultTs
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -92,7 +92,8 @@ export async function pushFolder(
|
||||
},
|
||||
});
|
||||
} catch (e) {
|
||||
throw Error(`Failed to create folder ${name}: ${e.body ?? e.message}`);
|
||||
console.error(e.body);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ addEventListener("error", (event) => {
|
||||
}
|
||||
});
|
||||
|
||||
export const VERSION = "v1.383.0";
|
||||
export const VERSION = "v1.381.0";
|
||||
|
||||
let command: any = new Command()
|
||||
.name("wmill")
|
||||
|
||||
+115
-44
@@ -46,7 +46,7 @@ import { FlowFile, replaceInlineScripts } from "./flow.ts";
|
||||
export async function generateAllMetadata() {}
|
||||
|
||||
function findClosestRawReqs(
|
||||
lang: "bun" | "python3" | "php" | undefined,
|
||||
lang: "bun" | "python3" | "php" | string | undefined,
|
||||
remotePath: string,
|
||||
globalDeps: GlobalDeps
|
||||
): string | undefined {
|
||||
@@ -84,20 +84,56 @@ function findClosestRawReqs(
|
||||
}
|
||||
|
||||
const TOP_HASH = "__flow_hash";
|
||||
async function generateFlowHash(folder: string) {
|
||||
async function generateFlowHash(
|
||||
folder: string,
|
||||
globalDeps: GlobalDeps,
|
||||
defaultTs: "bun" | "deno" | undefined
|
||||
): Promise<{
|
||||
hashes: Record<string, string>;
|
||||
pathsWithRawReqs: string[];
|
||||
}> {
|
||||
const elems = await FSFSElement(path.join(Deno.cwd(), folder), []);
|
||||
const hashes: Record<string, string> = {};
|
||||
const pathsWithRawReqs: string[] = [];
|
||||
|
||||
for await (const f of elems.getChildren()) {
|
||||
if (exts.some((e) => f.path.endsWith(e))) {
|
||||
hashes[f.path] = await generateHash(await f.getContentText());
|
||||
const found_ext = exts.find((e) => f.path.endsWith(e));
|
||||
|
||||
if (found_ext) {
|
||||
const lang = inferContentTypeFromFilePath(f.path, defaultTs);
|
||||
// log.info(remote_path + "/script" + ext);
|
||||
const raw = findClosestRawReqs(
|
||||
lang as "bun" | "php" | "python3" | undefined,
|
||||
path.join(folder, f.path),
|
||||
globalDeps
|
||||
);
|
||||
// if (raw) {
|
||||
// rawReqs[ext] = raw;
|
||||
// }
|
||||
|
||||
let text = await f.getContentText();
|
||||
if (raw) {
|
||||
text = raw + text;
|
||||
pathsWithRawReqs.push(f.path);
|
||||
}
|
||||
hashes[f.path] = await generateHash(text);
|
||||
}
|
||||
}
|
||||
return { ...hashes, [TOP_HASH]: await generateHash(JSON.stringify(hashes)) };
|
||||
return {
|
||||
hashes: {
|
||||
...hashes,
|
||||
[TOP_HASH]: await generateHash(JSON.stringify(hashes)),
|
||||
},
|
||||
pathsWithRawReqs,
|
||||
};
|
||||
}
|
||||
|
||||
export async function generateFlowLockInternal(
|
||||
folder: string,
|
||||
dryRun: boolean,
|
||||
workspace: Workspace,
|
||||
globalDeps: GlobalDeps,
|
||||
defaultTs: "bun" | "deno" | undefined,
|
||||
justUpdateMetadataLock?: boolean
|
||||
): Promise<string | undefined> {
|
||||
if (folder.endsWith(SEP)) {
|
||||
@@ -110,7 +146,11 @@ export async function generateFlowLockInternal(
|
||||
log.info(`Generating lock for flow ${folder} at ${remote_path}`);
|
||||
}
|
||||
|
||||
let hashes = await generateFlowHash(folder);
|
||||
let { hashes, pathsWithRawReqs } = await generateFlowHash(
|
||||
folder,
|
||||
globalDeps,
|
||||
defaultTs
|
||||
);
|
||||
|
||||
const conf = await readLockfile();
|
||||
if (await checkifMetadataUptodate(folder, hashes[TOP_HASH], conf, TOP_HASH)) {
|
||||
@@ -126,6 +166,7 @@ export async function generateFlowLockInternal(
|
||||
await Deno.readTextFile(folder! + SEP + "flow.yaml")
|
||||
) as FlowFile;
|
||||
|
||||
const fullReqs: Partial<Record<ScriptLanguage, string>> = {};
|
||||
if (!justUpdateMetadataLock) {
|
||||
const changedScripts = [];
|
||||
//find hashes that do not correspond to previous hashes
|
||||
@@ -139,6 +180,19 @@ export async function generateFlowLockInternal(
|
||||
}
|
||||
|
||||
log.info(`Recomputing locks of ${changedScripts.join(", ")} in ${folder}`);
|
||||
|
||||
for (const script of changedScripts) {
|
||||
if (pathsWithRawReqs.includes(script)) {
|
||||
const lang = inferContentTypeFromFilePath(script, defaultTs);
|
||||
log.info(`Inline script ${script} has raw requirements`);
|
||||
let req = fullReqs[lang];
|
||||
if (!req) {
|
||||
const rawReq = findClosestRawReqs(lang, script, globalDeps) ?? "";
|
||||
const fullReq = await getLockfileFromWindmill();
|
||||
fullReqs[lang] = req;
|
||||
}
|
||||
}
|
||||
}
|
||||
replaceInlineScripts(
|
||||
flowValue.value.modules,
|
||||
folder + SEP!,
|
||||
@@ -161,7 +215,7 @@ export async function generateFlowLockInternal(
|
||||
});
|
||||
}
|
||||
|
||||
hashes = await generateFlowHash(folder);
|
||||
hashes = (await generateFlowHash(folder, globalDeps, defaultTs)).hashes;
|
||||
|
||||
for (const [path, hash] of Object.entries(hashes)) {
|
||||
await updateMetadataGlobalLock(folder, hash, path);
|
||||
@@ -308,27 +362,13 @@ export async function updateScriptSchema(
|
||||
metadataContent.schema = newSchema;
|
||||
}
|
||||
|
||||
async function updateScriptLock(
|
||||
async function getLockfileFromWindmill(
|
||||
workspace: Workspace,
|
||||
scriptContent: string,
|
||||
language: ScriptLanguage,
|
||||
remotePath: string,
|
||||
metadataContent: Record<string, any>,
|
||||
rawDeps: string | undefined
|
||||
): Promise<void> {
|
||||
if (
|
||||
!(
|
||||
language == "bun" ||
|
||||
language == "python3" ||
|
||||
language == "go" ||
|
||||
language == "deno" ||
|
||||
language == "php"
|
||||
)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
// generate the script lock running a dependency job in Windmill and update it inplace
|
||||
// TODO: update this once the client is released
|
||||
): Promise<{ lock: string | undefined }> {
|
||||
const rawResponse = await fetch(
|
||||
`${workspace.remote}api/w/${workspace.workspaceId}/jobs/run/dependencies`,
|
||||
{
|
||||
@@ -354,27 +394,7 @@ async function updateScriptLock(
|
||||
let responseText = "reading response failed";
|
||||
try {
|
||||
responseText = await rawResponse.text();
|
||||
const response = JSON.parse(responseText);
|
||||
const lock = response.lock;
|
||||
if (lock === undefined) {
|
||||
throw new Error(
|
||||
`Failed to generate lockfile. Full response was: ${JSON.stringify(
|
||||
response
|
||||
)}`
|
||||
);
|
||||
}
|
||||
const lockPath = remotePath + ".script.lock";
|
||||
if (lock != "") {
|
||||
await Deno.writeTextFile(lockPath, lock);
|
||||
metadataContent.lock = "!inline " + lockPath.replaceAll(SEP, "/");
|
||||
} else {
|
||||
try {
|
||||
if (await Deno.stat(lockPath)) {
|
||||
await Deno.remove(lockPath);
|
||||
}
|
||||
} catch {}
|
||||
metadataContent.lock = "";
|
||||
}
|
||||
return JSON.parse(responseText);
|
||||
} catch (e) {
|
||||
throw new Error(
|
||||
`Failed to generate lockfile. Status was: ${rawResponse.statusText}, ${responseText}, ${e}`
|
||||
@@ -382,6 +402,57 @@ async function updateScriptLock(
|
||||
}
|
||||
}
|
||||
|
||||
async function updateScriptLock(
|
||||
workspace: Workspace,
|
||||
scriptContent: string,
|
||||
language: ScriptLanguage,
|
||||
remotePath: string,
|
||||
metadataContent: Record<string, any>,
|
||||
rawDeps: string | undefined
|
||||
): Promise<void> {
|
||||
if (
|
||||
!(
|
||||
language == "bun" ||
|
||||
language == "python3" ||
|
||||
language == "go" ||
|
||||
language == "deno" ||
|
||||
language == "php"
|
||||
)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
// generate the script lock running a dependency job in Windmill and update it inplace
|
||||
// TODO: update this once the client is released
|
||||
|
||||
const response = getLockfileFromWindmill(
|
||||
workspace,
|
||||
scriptContent,
|
||||
language,
|
||||
remotePath,
|
||||
rawDeps
|
||||
);
|
||||
const lock = response.lock;
|
||||
if (lock === undefined) {
|
||||
throw new Error(
|
||||
`Failed to generate lockfile. Full response was: ${JSON.stringify(
|
||||
response
|
||||
)}`
|
||||
);
|
||||
}
|
||||
const lockPath = remotePath + ".script.lock";
|
||||
if (lock != "") {
|
||||
await Deno.writeTextFile(lockPath, lock);
|
||||
metadataContent.lock = "!inline " + lockPath.replaceAll(SEP, "/");
|
||||
} else {
|
||||
try {
|
||||
if (await Deno.stat(lockPath)) {
|
||||
await Deno.remove(lockPath);
|
||||
}
|
||||
} catch {}
|
||||
metadataContent.lock = "";
|
||||
}
|
||||
}
|
||||
|
||||
export async function updateFlow(
|
||||
workspace: Workspace,
|
||||
flow_value: FlowValue,
|
||||
|
||||
+5
-13
@@ -366,19 +366,11 @@ async function createScript(
|
||||
workspace: Workspace
|
||||
) {
|
||||
if (!bundleContent) {
|
||||
try {
|
||||
// no parent hash
|
||||
await ScriptService.createScript({
|
||||
workspace: workspaceId,
|
||||
requestBody: body,
|
||||
});
|
||||
} catch (e) {
|
||||
throw Error(
|
||||
`Script creation for ${body.path} with parent ${
|
||||
body.parent_hash
|
||||
} was not successful: ${e.body ?? e.message}`
|
||||
);
|
||||
}
|
||||
// no parent hash
|
||||
await ScriptService.createScript({
|
||||
workspace: workspaceId,
|
||||
requestBody: body,
|
||||
});
|
||||
} else {
|
||||
const form = new FormData();
|
||||
form.append("script", JSON.stringify(body));
|
||||
|
||||
+8
-1
@@ -1070,7 +1070,14 @@ export async function pull(opts: GlobalOptions & SyncOptions) {
|
||||
}
|
||||
for (const change of changedFlows) {
|
||||
log.info(`Updating lock for flow ${change}`);
|
||||
await generateFlowLockInternal(change, false, workspace, true);
|
||||
await generateFlowLockInternal(
|
||||
change,
|
||||
false,
|
||||
workspace,
|
||||
globalDeps,
|
||||
opts.defaultTs,
|
||||
true
|
||||
);
|
||||
}
|
||||
log.info(
|
||||
colors.bold.green.underline(
|
||||
|
||||
Generated
+25
-48
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "windmill-components",
|
||||
"version": "1.383.0",
|
||||
"version": "1.381.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "windmill-components",
|
||||
"version": "1.383.0",
|
||||
"version": "1.381.0",
|
||||
"license": "AGPL-3.0",
|
||||
"dependencies": {
|
||||
"@aws-crypto/sha256-js": "^4.0.0",
|
||||
@@ -16,7 +16,7 @@
|
||||
"@redocly/json-to-json-schema": "^0.0.1",
|
||||
"@tanstack/svelte-table": "^8.9.9",
|
||||
"@windmill-labs/svelte-dnd-action": "latest",
|
||||
"@xyflow/svelte": "^0.1.15",
|
||||
"@xyflow/svelte": "^0.1.14",
|
||||
"ag-charts-community": "^9.0.1",
|
||||
"ag-charts-enterprise": "^9.0.1",
|
||||
"ag-grid-community": "^31.0.0",
|
||||
@@ -2294,8 +2294,7 @@
|
||||
"node_modules/@types/pug": {
|
||||
"version": "2.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/pug/-/pug-2.0.9.tgz",
|
||||
"integrity": "sha512-Yg4LkgFYvn1faISbDNWmcAC1XoDT8IoMUFspp5mnagKk+UvD2N0IWt5A7GRdMubsNWqgCLmrkf8rXkzNqb4szA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-Yg4LkgFYvn1faISbDNWmcAC1XoDT8IoMUFspp5mnagKk+UvD2N0IWt5A7GRdMubsNWqgCLmrkf8rXkzNqb4szA=="
|
||||
},
|
||||
"node_modules/@types/semver": {
|
||||
"version": "7.5.5",
|
||||
@@ -2516,24 +2515,23 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@xyflow/svelte": {
|
||||
"version": "0.1.15",
|
||||
"resolved": "https://registry.npmjs.org/@xyflow/svelte/-/svelte-0.1.15.tgz",
|
||||
"integrity": "sha512-QGM7rlBkoLG6jhHA9U8ZyMtqL62Cpn/T4OElTAUuKTgwuLTdzWqwSCdXpFTs8T6eiJD/Y4jYbVYsmQKDaB9rOw==",
|
||||
"license": "MIT",
|
||||
"version": "0.1.14",
|
||||
"resolved": "https://registry.npmjs.org/@xyflow/svelte/-/svelte-0.1.14.tgz",
|
||||
"integrity": "sha512-DdlFz+JKW1sQt8Q8O1DoSsroTvFk1RzmpcEZcGARt1REbnLy4BYG/03piaiclaC4iHK6feaPDvxpF057CkMCTw==",
|
||||
"dependencies": {
|
||||
"@svelte-put/shortcut": "^3.1.0",
|
||||
"@xyflow/system": "0.0.38",
|
||||
"classcat": "^5.0.4"
|
||||
"@xyflow/system": "0.0.37",
|
||||
"classcat": "^5.0.4",
|
||||
"svelte-preprocess": "^5.1.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"svelte": "^3.0.0 || ^4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@xyflow/system": {
|
||||
"version": "0.0.38",
|
||||
"resolved": "https://registry.npmjs.org/@xyflow/system/-/system-0.0.38.tgz",
|
||||
"integrity": "sha512-auJU8djbT59S5Afb9lFds1lQJvKIb0zUoHhO+il/ogDDG5BbFds6D8g5a8Q3oHdyR6dy0TaD1oZq9s7Ydhn41g==",
|
||||
"license": "MIT",
|
||||
"version": "0.0.37",
|
||||
"resolved": "https://registry.npmjs.org/@xyflow/system/-/system-0.0.37.tgz",
|
||||
"integrity": "sha512-hSIhezhxgftPUpC+xiQVIorcRILZUOWlLjpYPTyGWRu8s4RJvM4GqvrsFmD5OnMKXLgpU7/PqqUibDVO67oWQQ==",
|
||||
"dependencies": {
|
||||
"@types/d3-drag": "^3.0.7",
|
||||
"@types/d3-selection": "^3.0.10",
|
||||
@@ -3006,7 +3004,6 @@
|
||||
"version": "0.2.13",
|
||||
"resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
|
||||
"integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
@@ -3346,8 +3343,7 @@
|
||||
"node_modules/concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
|
||||
"devOptional": true
|
||||
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
|
||||
},
|
||||
"node_modules/confbox": {
|
||||
"version": "0.1.6",
|
||||
@@ -3959,7 +3955,6 @@
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz",
|
||||
"integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
@@ -4186,8 +4181,7 @@
|
||||
"node_modules/es6-promise": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz",
|
||||
"integrity": "sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg=="
|
||||
},
|
||||
"node_modules/esbuild": {
|
||||
"version": "0.21.5",
|
||||
@@ -4881,8 +4875,7 @@
|
||||
"node_modules/fs.realpath": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
|
||||
"devOptional": true
|
||||
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.3",
|
||||
@@ -5000,7 +4993,6 @@
|
||||
"version": "7.2.3",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
|
||||
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
@@ -5032,7 +5024,6 @@
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
@@ -5042,7 +5033,6 @@
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
},
|
||||
@@ -5159,8 +5149,7 @@
|
||||
"node_modules/graceful-fs": {
|
||||
"version": "4.2.11",
|
||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
|
||||
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
|
||||
},
|
||||
"node_modules/graphemer": {
|
||||
"version": "1.4.0",
|
||||
@@ -5468,7 +5457,6 @@
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
||||
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"once": "^1.3.0",
|
||||
"wrappy": "1"
|
||||
@@ -5477,8 +5465,7 @@
|
||||
"node_modules/inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
||||
"devOptional": true
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
||||
},
|
||||
"node_modules/ini": {
|
||||
"version": "1.3.8",
|
||||
@@ -5958,7 +5945,7 @@
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
|
||||
"integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
@@ -7037,7 +7024,6 @@
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
|
||||
"integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
@@ -7126,7 +7112,6 @@
|
||||
"version": "0.5.6",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
|
||||
"integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"minimist": "^1.2.6"
|
||||
},
|
||||
@@ -7239,7 +7224,7 @@
|
||||
"version": "3.3.7",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
|
||||
"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
@@ -7548,7 +7533,6 @@
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
@@ -7745,7 +7729,6 @@
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||
"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
|
||||
"devOptional": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
@@ -7833,7 +7816,7 @@
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz",
|
||||
"integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==",
|
||||
"dev": true
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/picomatch-browser": {
|
||||
"version": "2.2.6",
|
||||
@@ -7923,7 +7906,7 @@
|
||||
"version": "8.4.41",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.41.tgz",
|
||||
"integrity": "sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
@@ -8098,7 +8081,7 @@
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.1.tgz",
|
||||
"integrity": "sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"lilconfig": "^2.0.5",
|
||||
"yaml": "^2.1.1"
|
||||
@@ -9065,7 +9048,6 @@
|
||||
"version": "0.5.1",
|
||||
"resolved": "https://registry.npmjs.org/sander/-/sander-0.5.1.tgz",
|
||||
"integrity": "sha512-3lVqBir7WuKDHGrKRDn/1Ye3kwpXaDOMsiRP1wd6wpZW56gJhsbp5RqQpA6JG/P+pkXizygnr1dKR8vzWaVsfA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"es6-promise": "^3.1.2",
|
||||
"graceful-fs": "^4.1.3",
|
||||
@@ -9077,7 +9059,6 @@
|
||||
"version": "2.7.1",
|
||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
|
||||
"integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"glob": "^7.1.3"
|
||||
},
|
||||
@@ -9247,7 +9228,6 @@
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/sorcery/-/sorcery-0.11.0.tgz",
|
||||
"integrity": "sha512-J69LQ22xrQB1cIFJhPfgtLuI6BpWRiWu1Y3vSsIwK/eAScqJxd/+CJlUuHQRdX2C9NGFamq+KqNywGgaThwfHw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/sourcemap-codec": "^1.4.14",
|
||||
"buffer-crc32": "^0.2.5",
|
||||
@@ -9905,7 +9885,6 @@
|
||||
"version": "5.1.4",
|
||||
"resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-5.1.4.tgz",
|
||||
"integrity": "sha512-IvnbQ6D6Ao3Gg6ftiM5tdbR6aAETwjhHV+UKGf5bHGYR69RQvF1ho0JKPcbUON4vy4R7zom13jPjgdOWCQ5hDA==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@types/pug": "^2.0.6",
|
||||
@@ -9967,7 +9946,6 @@
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz",
|
||||
"integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"min-indent": "^1.0.0"
|
||||
},
|
||||
@@ -10347,7 +10325,7 @@
|
||||
"version": "5.2.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz",
|
||||
"integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
@@ -10810,8 +10788,7 @@
|
||||
"node_modules/wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
||||
"devOptional": true
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
|
||||
},
|
||||
"node_modules/write-file-atomic": {
|
||||
"version": "5.0.1",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "windmill-components",
|
||||
"version": "1.383.0",
|
||||
"version": "1.381.0",
|
||||
"scripts": {
|
||||
"dev": "vite dev",
|
||||
"build": "vite build",
|
||||
@@ -97,7 +97,7 @@
|
||||
"@redocly/json-to-json-schema": "^0.0.1",
|
||||
"@tanstack/svelte-table": "^8.9.9",
|
||||
"@windmill-labs/svelte-dnd-action": "latest",
|
||||
"@xyflow/svelte": "^0.1.15",
|
||||
"@xyflow/svelte": "^0.1.14",
|
||||
"ag-charts-community": "^9.0.1",
|
||||
"ag-charts-enterprise": "^9.0.1",
|
||||
"ag-grid-community": "^31.0.0",
|
||||
|
||||
@@ -1 +1 @@
|
||||
export let base: string = import.meta.env.VITE_BASE_URL ?? ''
|
||||
export const base: string = import.meta.env.VITE_BASE_URL ?? ''
|
||||
|
||||
@@ -45,7 +45,6 @@
|
||||
import CodeCompletionStatus from './copilot/CodeCompletionStatus.svelte'
|
||||
import Popover from './Popover.svelte'
|
||||
import ResourceEditorDrawer from './ResourceEditorDrawer.svelte'
|
||||
import type { EditorBarUi } from './custom_ui'
|
||||
|
||||
export let lang: SupportedLanguage | 'bunnative' | undefined
|
||||
export let editor: Editor | undefined
|
||||
@@ -69,7 +68,6 @@
|
||||
export let args: Record<string, any>
|
||||
export let noHistory = false
|
||||
export let saveToWorkspace = false
|
||||
export let customUi: EditorBarUi = {}
|
||||
|
||||
let contextualVariablePicker: ItemPicker
|
||||
let variablePicker: ItemPicker
|
||||
@@ -315,7 +313,6 @@
|
||||
{/if}
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
|
||||
<ItemPicker
|
||||
bind:this={contextualVariablePicker}
|
||||
pickCallback={(path, name) => {
|
||||
@@ -516,7 +513,7 @@ $res = json_decode(curl_exec($ch));`)
|
||||
class="rounded-full w-2 h-2 mx-2 {validCode ? 'bg-green-300' : 'bg-red-300'}"
|
||||
/>
|
||||
<div class="flex items-center gap-0.5">
|
||||
{#if showContextVarPicker && customUi?.contextVar != false}
|
||||
{#if showContextVarPicker}
|
||||
<Button
|
||||
title="Add context variable"
|
||||
color="light"
|
||||
@@ -529,7 +526,7 @@ $res = json_decode(curl_exec($ch));`)
|
||||
>+Context Var
|
||||
</Button>
|
||||
{/if}
|
||||
{#if showVarPicker && customUi?.variable != false}
|
||||
{#if showVarPicker}
|
||||
<Button
|
||||
title="Add variable"
|
||||
color="light"
|
||||
@@ -559,7 +556,7 @@ $res = json_decode(curl_exec($ch));`)
|
||||
</Button>
|
||||
{/if}
|
||||
|
||||
{#if showResourceTypePicker && customUi?.type != false}
|
||||
{#if showResourceTypePicker}
|
||||
<Button
|
||||
title="Add resource type"
|
||||
btnClasses="!font-medium text-tertiary"
|
||||
@@ -587,41 +584,37 @@ $res = json_decode(curl_exec($ch));`)
|
||||
Reset
|
||||
</Button>
|
||||
|
||||
{#if customUi?.assistants != false}
|
||||
{#if lang == 'deno' || lang == 'python3' || lang == 'go' || lang == 'bash'}
|
||||
<Button
|
||||
btnClasses="!font-medium text-tertiary"
|
||||
size="xs"
|
||||
spacingSize="md"
|
||||
color="light"
|
||||
on:click={() => editor?.reloadWebsocket()}
|
||||
startIcon={{
|
||||
icon: RotateCw,
|
||||
classes: websocketAlive[lang] == false ? 'animate-spin' : ''
|
||||
}}
|
||||
title="Reload assistants"
|
||||
>
|
||||
{#if !iconOnly}
|
||||
Assistants
|
||||
{#if lang == 'deno' || lang == 'python3' || lang == 'go' || lang == 'bash'}
|
||||
<Button
|
||||
btnClasses="!font-medium text-tertiary"
|
||||
size="xs"
|
||||
spacingSize="md"
|
||||
color="light"
|
||||
on:click={() => editor?.reloadWebsocket()}
|
||||
startIcon={{
|
||||
icon: RotateCw,
|
||||
classes: websocketAlive[lang] == false ? 'animate-spin' : ''
|
||||
}}
|
||||
title="Reload assistants"
|
||||
>
|
||||
{#if !iconOnly}
|
||||
Assistants
|
||||
{/if}
|
||||
<span class="-my-1">
|
||||
{#if lang == 'deno'}
|
||||
(<span class={websocketAlive.deno ? 'green' : 'text-red-700'}>Deno</span>)
|
||||
{:else if lang == 'go'}
|
||||
(<span class={websocketAlive.go ? 'green' : 'text-red-700'}>Go</span>)
|
||||
{:else if lang == 'python3'}
|
||||
(<span class={websocketAlive.pyright ? 'green' : 'text-red-700'}>Pyright</span>
|
||||
<span class={websocketAlive.ruff ? 'green' : 'text-red-700'}>Ruff</span>)
|
||||
{:else if lang == 'bash'}
|
||||
(<span class={websocketAlive.shellcheck ? 'green' : 'text-red-700'}>Shellcheck</span>)
|
||||
{/if}
|
||||
<span class="-my-1">
|
||||
{#if lang == 'deno'}
|
||||
(<span class={websocketAlive.deno ? 'green' : 'text-red-700'}>Deno</span>)
|
||||
{:else if lang == 'go'}
|
||||
(<span class={websocketAlive.go ? 'green' : 'text-red-700'}>Go</span>)
|
||||
{:else if lang == 'python3'}
|
||||
(<span class={websocketAlive.pyright ? 'green' : 'text-red-700'}>Pyright</span>
|
||||
<span class={websocketAlive.ruff ? 'green' : 'text-red-700'}>Ruff</span>)
|
||||
{:else if lang == 'bash'}
|
||||
(<span class={websocketAlive.shellcheck ? 'green' : 'text-red-700'}>Shellcheck</span
|
||||
>)
|
||||
{/if}
|
||||
</span>
|
||||
</Button>
|
||||
{/if}
|
||||
</span>
|
||||
</Button>
|
||||
{/if}
|
||||
|
||||
{#if collabMode && customUi?.multiplayer != false}
|
||||
{#if collabMode}
|
||||
<div class="flex items-center px-3">
|
||||
<Toggle
|
||||
options={{ right: '' }}
|
||||
@@ -655,15 +648,11 @@ $res = json_decode(curl_exec($ch));`)
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if customUi?.autoformatting != false}
|
||||
<FormatOnSave />
|
||||
{/if}
|
||||
{#if customUi?.aiGen != false}
|
||||
<ScriptGen {editor} {diffEditor} {lang} {iconOnly} {args} />
|
||||
{/if}
|
||||
{#if customUi?.aiFix != false}
|
||||
<CodeCompletionStatus />
|
||||
{/if}
|
||||
<FormatOnSave />
|
||||
|
||||
<ScriptGen {editor} {diffEditor} {lang} {iconOnly} {args} />
|
||||
|
||||
<CodeCompletionStatus />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -682,7 +671,7 @@ $res = json_decode(curl_exec($ch));`)
|
||||
History
|
||||
</Button>
|
||||
{/if}
|
||||
{#if SCRIPT_EDITOR_SHOW_EXPLORE_OTHER_SCRIPTS && customUi?.library != false}
|
||||
{#if SCRIPT_EDITOR_SHOW_EXPLORE_OTHER_SCRIPTS}
|
||||
<Button
|
||||
btnClasses="!font-medium text-tertiary"
|
||||
size="xs"
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import CustomPopover from './CustomPopover.svelte'
|
||||
import Summary from './Summary.svelte'
|
||||
import type { FlowBuilderWhitelabelCustomUi } from './custom_ui'
|
||||
import type { WhitelabelCustomUi } from './custom_ui'
|
||||
|
||||
export let initialPath: string = ''
|
||||
export let pathStoreInit: string | undefined = undefined
|
||||
@@ -96,7 +96,7 @@
|
||||
})
|
||||
| undefined = undefined
|
||||
export let diffDrawer: DiffDrawer | undefined = undefined
|
||||
export let customUi: FlowBuilderWhitelabelCustomUi = {}
|
||||
export let customUi: WhitelabelCustomUi = {}
|
||||
|
||||
$: setContext('customUi', customUi)
|
||||
|
||||
@@ -205,16 +205,13 @@
|
||||
draft?: Flow
|
||||
}
|
||||
|
||||
let savedAtNewPath = false
|
||||
if (newFlow) {
|
||||
dispatch('saveInitial', $pathStore)
|
||||
} else if (savedFlow?.draft_only && $pathStore !== initialPath) {
|
||||
savedAtNewPath = true
|
||||
initialPath = $pathStore
|
||||
// this is so we can use the flow builder outside of sveltekit
|
||||
dispatch('saveDraftOnlyAtNewPath', { path: $pathStore, selectedId: getSelectedId() })
|
||||
}
|
||||
dispatch('saveDraft', { path: $pathStore, savedAtNewPath, newFlow })
|
||||
sendUserToast('Saved as draft')
|
||||
} catch (error) {
|
||||
sendUserToast(`Error while saving the flow as a draft: ${error.body || error.message}`, true)
|
||||
@@ -403,8 +400,7 @@
|
||||
testStepStore,
|
||||
saveDraft,
|
||||
initialPath,
|
||||
flowInputsStore: writable<FlowInput>({}),
|
||||
customUi
|
||||
flowInputsStore: writable<FlowInput>({})
|
||||
})
|
||||
|
||||
async function loadSchedule() {
|
||||
@@ -490,20 +486,18 @@
|
||||
onClick: () => void
|
||||
}> = []
|
||||
|
||||
if (customUi.topBar?.extraDeployOptions != false) {
|
||||
if (savedFlow?.draft_only === false || savedFlow?.draft_only === undefined) {
|
||||
dropdownItems.push({
|
||||
label: 'Exit & see details',
|
||||
onClick: () => dispatch('details', $pathStore)
|
||||
})
|
||||
}
|
||||
if (savedFlow?.draft_only === false || savedFlow?.draft_only === undefined) {
|
||||
dropdownItems.push({
|
||||
label: 'Exit & see details',
|
||||
onClick: () => dispatch('details', $pathStore)
|
||||
})
|
||||
}
|
||||
|
||||
if (!newFlow) {
|
||||
dropdownItems.push({
|
||||
label: 'Fork',
|
||||
onClick: () => window.open(`/flows/add?template=${initialPath}`)
|
||||
})
|
||||
}
|
||||
if (!newFlow) {
|
||||
dropdownItems.push({
|
||||
label: 'Fork',
|
||||
onClick: () => window.open(`/flows/add?template=${initialPath}`)
|
||||
})
|
||||
}
|
||||
|
||||
let flowCopilotContext: FlowCopilotContext = {
|
||||
@@ -1029,7 +1023,7 @@
|
||||
|
||||
$: onCustomUiChange(customUi)
|
||||
|
||||
function onCustomUiChange(customUi: FlowBuilderWhitelabelCustomUi | undefined) {
|
||||
function onCustomUiChange(customUi: WhitelabelCustomUi | undefined) {
|
||||
moreItems = [
|
||||
...(customUi?.topBar?.history != false
|
||||
? [
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
import FlowGraphViewerStep from './FlowGraphViewerStep.svelte'
|
||||
import FlowGraphV2 from './graph/FlowGraphV2.svelte'
|
||||
import { dfs } from './flows/dfs'
|
||||
|
||||
export let flow: {
|
||||
summary: string
|
||||
@@ -14,7 +13,6 @@
|
||||
value: FlowValue
|
||||
schema?: any
|
||||
}
|
||||
|
||||
export let overflowAuto = false
|
||||
export let noSide = false
|
||||
export let download = false
|
||||
@@ -37,8 +35,7 @@
|
||||
modules={flow?.value?.modules}
|
||||
failureModule={flow?.value?.failure_module}
|
||||
on:select={(e) => {
|
||||
const mod = dfs(flow?.value?.modules ?? [], (m) => m).find((m) => m?.id === e?.detail)
|
||||
stepDetail = mod ?? e.detail
|
||||
stepDetail = e.detail
|
||||
dispatch('select', stepDetail)
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -12,9 +12,6 @@
|
||||
export let flowStateStore: Writable<FlowState> = writable({})
|
||||
export let selectedJobStep: string | undefined = undefined
|
||||
export let hideFlowResult = false
|
||||
export let hideTimeline = false
|
||||
export let hideDownloadInGraph = false
|
||||
export let hideNodeDefinition = false
|
||||
|
||||
export let isOwner = false
|
||||
export let wideResults = false
|
||||
@@ -26,10 +23,7 @@
|
||||
setContext<FlowStatusViewerContext>('FlowStatusViewer', {
|
||||
flowStateStore,
|
||||
suspendStatus,
|
||||
retryStatus,
|
||||
hideDownloadInGraph,
|
||||
hideNodeDefinition,
|
||||
hideTimeline
|
||||
retryStatus
|
||||
})
|
||||
|
||||
function loadOwner(path: string) {
|
||||
|
||||
@@ -32,14 +32,8 @@
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
let {
|
||||
flowStateStore,
|
||||
retryStatus,
|
||||
suspendStatus,
|
||||
hideDownloadInGraph,
|
||||
hideTimeline,
|
||||
hideNodeDefinition
|
||||
} = getContext<FlowStatusViewerContext>('FlowStatusViewer')
|
||||
let { flowStateStore, retryStatus, suspendStatus } =
|
||||
getContext<FlowStatusViewerContext>('FlowStatusViewer')
|
||||
|
||||
export let jobId: string
|
||||
export let workspaceId: string | undefined = undefined
|
||||
@@ -782,7 +776,7 @@
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
{:else if innerModules.length > 0 && (job.raw_flow?.modules.length ?? 0) > 0}
|
||||
{:else if innerModules.length > 0}
|
||||
<ul class="w-full">
|
||||
<h3 class="text-md leading-6 font-bold text-primary border-b mb-4 py-2">
|
||||
Step-by-step
|
||||
@@ -902,8 +896,6 @@
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
{:else}
|
||||
<div class="p-2 text-tertiary text-sm italic">Empty flow</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
@@ -930,7 +922,7 @@
|
||||
</div>
|
||||
|
||||
<FlowGraphV2
|
||||
download={!hideDownloadInGraph}
|
||||
download
|
||||
minHeight={wrapperHeight}
|
||||
success={jobId != undefined && isSuccess(job?.['success'])}
|
||||
flowModuleStates={$localModuleStates}
|
||||
@@ -970,14 +962,9 @@
|
||||
class="border-l border-tertiary-inverse pt-1 overflow-auto min-h-[700px] flex flex-col z-0 h-full"
|
||||
>
|
||||
<Tabs bind:selected={rightColumnSelect}>
|
||||
{#if !hideTimeline}
|
||||
<Tab value="timeline"><span class="font-semibold text-md">Timeline</span></Tab>
|
||||
{/if}
|
||||
<Tab value="timeline"><span class="font-semibold text-md">Timeline</span></Tab>
|
||||
<Tab value="node_status"><span class="font-semibold">Node status</span></Tab>
|
||||
{#if !hideNodeDefinition}
|
||||
<Tab value="node_definition"><span class="font-semibold">Node definition</span></Tab
|
||||
>
|
||||
{/if}
|
||||
<Tab value="node_definition"><span class="font-semibold">Node definition</span></Tab>
|
||||
{#if Object.keys(job?.flow_status?.user_states ?? {}).length > 0}
|
||||
<Tab value="user_states"><span class="font-semibold">User States</span></Tab>
|
||||
{/if}
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
<script lang="ts">
|
||||
import Highlight from 'svelte-highlight'
|
||||
import json from 'svelte-highlight/languages/json'
|
||||
import type { FlowValue } from '$lib/gen'
|
||||
import { Tab, Tabs, TabContent } from './common'
|
||||
import { Tab, Tabs, TabContent, Button } from './common'
|
||||
import SchemaViewer from './SchemaViewer.svelte'
|
||||
import FieldHeader from './FieldHeader.svelte'
|
||||
import { copyToClipboard } from '../utils'
|
||||
import FlowGraphViewer from './FlowGraphViewer.svelte'
|
||||
|
||||
import { Clipboard } from 'lucide-svelte'
|
||||
import YAML from 'yaml'
|
||||
import { yaml } from 'svelte-highlight/languages'
|
||||
import HighlightTheme from './HighlightTheme.svelte'
|
||||
import FlowViewerInner from './FlowViewerInner.svelte'
|
||||
|
||||
export let flow: {
|
||||
summary: string
|
||||
@@ -17,11 +22,19 @@
|
||||
export let initialOpen: number | undefined = undefined
|
||||
export let noSide = false
|
||||
|
||||
$: flowFiltered = {
|
||||
summary: flow.summary,
|
||||
description: flow.description,
|
||||
value: flow.value,
|
||||
schema: flow.schema
|
||||
}
|
||||
|
||||
export let noGraph: boolean = false
|
||||
|
||||
export let tab: 'ui' | 'raw' | 'schema' = noGraph ? 'schema' : 'ui'
|
||||
export let noSummary = false
|
||||
export let noGraphDownload = false
|
||||
|
||||
let rawType: 'json' | 'yaml' = 'yaml'
|
||||
|
||||
let open: { [id: number]: boolean } = {}
|
||||
if (initialOpen) {
|
||||
@@ -74,12 +87,40 @@
|
||||
{:else}
|
||||
<div class="text-secondary text-xs italic mb-4">No inputs</div>
|
||||
{/if}
|
||||
|
||||
<FlowGraphViewer download={!noGraphDownload} {noSide} {flow} overflowAuto />
|
||||
<FlowGraphViewer download {noSide} {flow} overflowAuto />
|
||||
</div>
|
||||
</TabContent>
|
||||
<TabContent value="raw">
|
||||
<FlowViewerInner {flow} />
|
||||
<TabContent value="raw"
|
||||
><Tabs bind:selected={rawType} wrapperClass="mt-4">
|
||||
<Tab value="yaml">YAML</Tab>
|
||||
<Tab value="json">JSON</Tab>
|
||||
<svelte:fragment slot="content">
|
||||
<div class="relative pt-2">
|
||||
<Button
|
||||
on:click={() =>
|
||||
copyToClipboard(
|
||||
rawType === 'yaml'
|
||||
? YAML.stringify(flowFiltered)
|
||||
: JSON.stringify(flowFiltered, null, 4)
|
||||
)}
|
||||
color="light"
|
||||
variant="border"
|
||||
size="xs"
|
||||
startIcon={{ icon: Clipboard }}
|
||||
btnClasses="absolute top-2 right-2 w-min"
|
||||
>
|
||||
Copy content
|
||||
</Button>
|
||||
<Highlight
|
||||
class="overflow-auto px-1"
|
||||
language={rawType === 'yaml' ? yaml : json}
|
||||
code={rawType === 'yaml'
|
||||
? YAML.stringify(flowFiltered)
|
||||
: JSON.stringify(flowFiltered, null, 4)}
|
||||
/>
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
</Tabs>
|
||||
</TabContent>
|
||||
<TabContent value="schema">
|
||||
<div class="my-4" />
|
||||
|
||||
@@ -1,132 +0,0 @@
|
||||
<script lang="ts">
|
||||
import Highlight from 'svelte-highlight'
|
||||
import json from 'svelte-highlight/languages/json'
|
||||
import type { FlowValue } from '$lib/gen'
|
||||
import { Tab, Tabs, Button } from './common'
|
||||
import { copyToClipboard } from '../utils'
|
||||
|
||||
import { ArrowDown, Clipboard } from 'lucide-svelte'
|
||||
import YAML from 'yaml'
|
||||
import { yaml } from 'svelte-highlight/languages'
|
||||
import HighlightTheme from './HighlightTheme.svelte'
|
||||
|
||||
export let flow: {
|
||||
summary: string
|
||||
description?: string
|
||||
value: FlowValue
|
||||
schema?: any
|
||||
}
|
||||
|
||||
$: flowFiltered = {
|
||||
summary: flow.summary,
|
||||
description: flow.description,
|
||||
value: flow.value,
|
||||
schema: flow.schema
|
||||
}
|
||||
|
||||
let rawType: 'json' | 'yaml' = 'yaml'
|
||||
|
||||
function trimStringToLines(inputString: string, maxLines: number = 100): string {
|
||||
const lines = inputString?.split('\n') ?? []
|
||||
const linesToKeep = lines.slice(0, maxLines)
|
||||
|
||||
return linesToKeep.join('\n')
|
||||
}
|
||||
|
||||
let code: string = ''
|
||||
|
||||
function computeCode() {
|
||||
const str =
|
||||
rawType === 'json' ? JSON.stringify(flowFiltered, null, 4) : YAML.stringify(flowFiltered)
|
||||
|
||||
const numberOfLines = str.split('\n').length
|
||||
|
||||
if (numberOfLines > maxLines) {
|
||||
shouldDisplayLoadMore = true
|
||||
}
|
||||
|
||||
code = str
|
||||
}
|
||||
|
||||
let shouldDisplayLoadMore = false
|
||||
|
||||
$: flowFiltered && rawType && computeCode()
|
||||
|
||||
let maxLines = 100
|
||||
</script>
|
||||
|
||||
<HighlightTheme />
|
||||
|
||||
<div>
|
||||
<Tabs
|
||||
bind:selected={rawType}
|
||||
on:selected={() => {
|
||||
maxLines = 100
|
||||
}}
|
||||
>
|
||||
<Tab value="yaml">YAML</Tab>
|
||||
<Tab value="json">JSON</Tab>
|
||||
<svelte:fragment slot="content">
|
||||
<div class="relative pt-2">
|
||||
<Button
|
||||
on:click={() =>
|
||||
copyToClipboard(
|
||||
rawType === 'yaml'
|
||||
? YAML.stringify(flowFiltered)
|
||||
: JSON.stringify(flowFiltered, null, 4)
|
||||
)}
|
||||
color="light"
|
||||
variant="border"
|
||||
size="xs"
|
||||
startIcon={{ icon: Clipboard }}
|
||||
btnClasses="absolute top-2 right-2 w-min"
|
||||
>
|
||||
Copy content
|
||||
</Button>
|
||||
|
||||
<div class={shouldDisplayLoadMore ? 'code-container' : ''}>
|
||||
<Highlight
|
||||
class="overflow-auto px-1"
|
||||
language={rawType === 'yaml' ? yaml : json}
|
||||
code={trimStringToLines(code, maxLines)}
|
||||
/>
|
||||
</div>
|
||||
{#if shouldDisplayLoadMore}
|
||||
<Button
|
||||
on:click={() => {
|
||||
maxLines += 500
|
||||
|
||||
// If the code is less than the max lines, we don't need to show the button
|
||||
if (maxLines >= code?.split('\n').length) {
|
||||
shouldDisplayLoadMore = false
|
||||
}
|
||||
}}
|
||||
color="light"
|
||||
size="xs"
|
||||
btnClasses="mb-2 mx-2"
|
||||
startIcon={{ icon: ArrowDown }}
|
||||
>
|
||||
Show more
|
||||
</Button>
|
||||
{/if}
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
</Tabs>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.code-container {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.code-container::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 100px;
|
||||
background: linear-gradient(to bottom, rgba(255, 255, 255, 0), rgb(var(--color-surface)));
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
||||
@@ -67,7 +67,6 @@
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import CustomPopover from './CustomPopover.svelte'
|
||||
import Summary from './Summary.svelte'
|
||||
import type { ScriptBuilderWhitelabelCustomUi } from './custom_ui'
|
||||
|
||||
export let script: NewScript
|
||||
export let fullyLoaded: boolean = true
|
||||
@@ -82,7 +81,6 @@
|
||||
export let disableHistoryChange = false
|
||||
export let replaceStateFn: (url: string) => void = (url) =>
|
||||
window.history.replaceState(null, '', url)
|
||||
export let customUi: ScriptBuilderWhitelabelCustomUi = {}
|
||||
|
||||
let metadataOpen =
|
||||
showMeta ||
|
||||
@@ -425,7 +423,7 @@
|
||||
|
||||
function computeDropdownItems(initialPath: string) {
|
||||
let dropdownItems: { label: string; onClick: () => void }[] =
|
||||
initialPath != '' && customUi?.topBar?.extraDeployOptions != false
|
||||
initialPath != ''
|
||||
? [
|
||||
{
|
||||
label: 'Deploy & Stay here',
|
||||
@@ -1052,34 +1050,32 @@
|
||||
{$scheduleStore.cron ?? ''}
|
||||
</Button>
|
||||
{/if}
|
||||
{#if customUi?.topBar?.path != false}
|
||||
<div class="flex justify-start w-full border rounded-md overflow-hidden">
|
||||
<div>
|
||||
<button
|
||||
on:click={async () => {
|
||||
metadataOpen = true
|
||||
}}
|
||||
>
|
||||
<Badge
|
||||
color="gray"
|
||||
class="center-center !bg-surface-secondary !text-tertiary !h-[28px] !w-[70px] rounded-none hover:!bg-surface-hover transition-all"
|
||||
>
|
||||
<Pen size={12} class="mr-2" /> Path
|
||||
</Badge>
|
||||
</button>
|
||||
</div>
|
||||
<input
|
||||
type="text"
|
||||
readonly
|
||||
value={script.path}
|
||||
size={script.path?.length || 50}
|
||||
class="font-mono !text-xs !min-w-[96px] !max-w-[300px] !w-full !h-[28px] !my-0 !py-0 !border-l-0 !rounded-l-none !border-0 !shadow-none"
|
||||
on:focus={({ currentTarget }) => {
|
||||
currentTarget.select()
|
||||
<div class="flex justify-start w-full border rounded-md overflow-hidden">
|
||||
<div>
|
||||
<button
|
||||
on:click={async () => {
|
||||
metadataOpen = true
|
||||
}}
|
||||
/>
|
||||
>
|
||||
<Badge
|
||||
color="gray"
|
||||
class="center-center !bg-surface-secondary !text-tertiary !h-[28px] !w-[70px] rounded-none hover:!bg-surface-hover transition-all"
|
||||
>
|
||||
<Pen size={12} class="mr-2" /> Path
|
||||
</Badge>
|
||||
</button>
|
||||
</div>
|
||||
{/if}
|
||||
<input
|
||||
type="text"
|
||||
readonly
|
||||
value={script.path}
|
||||
size={script.path?.length || 50}
|
||||
class="font-mono !text-xs !min-w-[96px] !max-w-[300px] !w-full !h-[28px] !my-0 !py-0 !border-l-0 !rounded-l-none !border-0 !shadow-none"
|
||||
on:focus={({ currentTarget }) => {
|
||||
currentTarget.select()
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if $enterpriseLicense && initialPath != ''}
|
||||
@@ -1110,19 +1106,17 @@
|
||||
<span class="hidden lg:flex"> Diff </span>
|
||||
</div>
|
||||
</Button>
|
||||
{#if customUi?.topBar?.settings != false}
|
||||
<Button
|
||||
color="light"
|
||||
variant="border"
|
||||
size="xs"
|
||||
on:click={() => {
|
||||
metadataOpen = true
|
||||
}}
|
||||
startIcon={{ icon: Settings }}
|
||||
>
|
||||
<span class="hidden lg:flex"> Settings </span>
|
||||
</Button>
|
||||
{/if}
|
||||
<Button
|
||||
color="light"
|
||||
variant="border"
|
||||
size="xs"
|
||||
on:click={() => {
|
||||
metadataOpen = true
|
||||
}}
|
||||
startIcon={{ icon: Settings }}
|
||||
>
|
||||
<span class="hidden lg:flex"> Settings </span>
|
||||
</Button>
|
||||
<Button
|
||||
loading={loadingDraft}
|
||||
size="xs"
|
||||
@@ -1176,7 +1170,6 @@
|
||||
</div>
|
||||
|
||||
<ScriptEditor
|
||||
{customUi}
|
||||
collabMode
|
||||
edit={initialPath != ''}
|
||||
on:format={() => {
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
import DiffEditor from './DiffEditor.svelte'
|
||||
import { Clipboard, CornerDownLeft, Github, Play } from 'lucide-svelte'
|
||||
import { setLicense } from '$lib/enterpriseUtils'
|
||||
import type { ScriptEditorWhitelabelCustomUi } from './custom_ui'
|
||||
|
||||
// Exported
|
||||
export let schema: Schema | any = emptySchema()
|
||||
@@ -44,7 +43,6 @@
|
||||
export let noHistory = false
|
||||
export let saveToWorkspace = false
|
||||
export let watchChanges = false
|
||||
export let customUi: ScriptEditorWhitelabelCustomUi = {}
|
||||
|
||||
let websocketAlive = {
|
||||
pyright: false,
|
||||
@@ -245,7 +243,6 @@
|
||||
setCollaborationMode()
|
||||
}
|
||||
}}
|
||||
customUi={customUi?.editorBar}
|
||||
collabLive={wsProvider?.shouldConnect}
|
||||
{collabMode}
|
||||
{validCode}
|
||||
@@ -263,7 +260,7 @@
|
||||
{noHistory}
|
||||
{saveToWorkspace}
|
||||
/>
|
||||
{#if !noSyncFromGithub && customUi?.editorBar?.useVsCode != false}
|
||||
{#if !noSyncFromGithub}
|
||||
<div class="py-1">
|
||||
<Button
|
||||
target="_blank"
|
||||
|
||||
@@ -8,9 +8,7 @@
|
||||
import FlowModuleScript from './flows/content/FlowModuleScript.svelte'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import Button from './common/button/Button.svelte'
|
||||
import { ExternalLink, Pencil, ArrowRight, X, Diff, Code } from 'lucide-svelte'
|
||||
import ToggleButtonGroup from './common/toggleButton-v2/ToggleButtonGroup.svelte'
|
||||
import ToggleButton from './common/toggleButton-v2/ToggleButton.svelte'
|
||||
import { ExternalLink, Pencil, ArrowRight, X } from 'lucide-svelte'
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
@@ -21,7 +19,6 @@
|
||||
let deploymentMsgUpdate: string | undefined = undefined
|
||||
|
||||
let selectedVersion: ScriptHistory | undefined = undefined
|
||||
let selectedVersionIndex: number | undefined = undefined
|
||||
let versions: ScriptHistory[] | undefined = undefined
|
||||
let loading: boolean = false
|
||||
|
||||
@@ -56,9 +53,6 @@
|
||||
}
|
||||
|
||||
loadVersions()
|
||||
|
||||
let showDiff: boolean = false
|
||||
let previousHash: string | undefined = undefined
|
||||
</script>
|
||||
|
||||
<Splitpanes class="!overflow-visible">
|
||||
@@ -68,34 +62,17 @@
|
||||
{#if !loading}
|
||||
{#if versions && versions.length > 0}
|
||||
<div class="flex gap-2 flex-col">
|
||||
{#each versions ?? [] as version, versionIndex}
|
||||
{#each versions ?? [] as version}
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div
|
||||
class={classNames(
|
||||
'border flex gap-1 truncate justify-between flex-row w-full items-center p-2 rounded-md cursor-pointer ',
|
||||
'border flex gap-1 truncate justify-between flex-row w-full items-center p-2 rounded-md cursor-pointer hover:bg-blue-50 hover:text-blue-400',
|
||||
selectedVersion?.script_hash == version.script_hash
|
||||
? 'bg-surface-selected'
|
||||
: '',
|
||||
'hover:bg-surface-hover'
|
||||
? 'bg-blue-100 text-blue-600'
|
||||
: ''
|
||||
)}
|
||||
on:click={() => {
|
||||
selectedVersion = version
|
||||
selectedVersionIndex = versionIndex
|
||||
|
||||
if (showDiff && versions && selectedVersionIndex === versions.length - 1) {
|
||||
showDiff = false
|
||||
}
|
||||
|
||||
const availableVersions = versions?.slice(selectedVersionIndex + 1)
|
||||
|
||||
if (
|
||||
previousHash &&
|
||||
!availableVersions?.find((v) => v.script_hash === previousHash)
|
||||
) {
|
||||
previousHash = availableVersions?.[0]?.script_hash
|
||||
}
|
||||
|
||||
deploymentMsgUpdate = undefined
|
||||
deploymentMsgUpdateMode = false
|
||||
}}
|
||||
@@ -132,7 +109,7 @@
|
||||
<div class="h-full w-full overflow-auto">
|
||||
{#if selectedVersion}
|
||||
{#key selectedVersion}
|
||||
<div class="flex flex-col min-h-full">
|
||||
<div class="flex flex-col">
|
||||
<span class="flex flex-row text-sm p-2 text-tertiary">
|
||||
{#if deploymentMsgUpdateMode}
|
||||
<div class="flex w-full">
|
||||
@@ -191,41 +168,7 @@
|
||||
</button>
|
||||
{/if}
|
||||
</span>
|
||||
|
||||
{#if selectedVersionIndex !== undefined && versions?.slice(selectedVersionIndex + 1).length}
|
||||
<div class="p-2 flex flex-row items-center gap-2 h-8">
|
||||
<div class="w-min">
|
||||
<ToggleButtonGroup bind:selected={showDiff}>
|
||||
<ToggleButton light small value={false} label="Code" icon={Code} />
|
||||
<ToggleButton light small value={true} label="Diff" icon={Diff} />
|
||||
</ToggleButtonGroup>
|
||||
</div>
|
||||
|
||||
{#if showDiff}
|
||||
<div class="text-xs">Versions:</div>
|
||||
<select bind:value={previousHash} class="!text-xs !w-40">
|
||||
{#each versions?.slice(selectedVersionIndex + 1) ?? [] as version}
|
||||
<option
|
||||
value={version.script_hash}
|
||||
selected={version.script_hash === selectedVersion.script_hash}
|
||||
class="!text-xs"
|
||||
>
|
||||
{version.deployment_msg ?? version.script_hash}
|
||||
</option>
|
||||
{/each}
|
||||
</select>
|
||||
{/if}
|
||||
</div>
|
||||
{:else}
|
||||
<div class="p-2 text-xs text-secondary"> No previous version found </div>
|
||||
{/if}
|
||||
<FlowModuleScript
|
||||
showDate
|
||||
path={scriptPath}
|
||||
hash={selectedVersion.script_hash}
|
||||
{previousHash}
|
||||
{showDiff}
|
||||
/>
|
||||
<FlowModuleScript showDate path={scriptPath} hash={selectedVersion.script_hash} />
|
||||
</div>
|
||||
{/key}
|
||||
{:else}
|
||||
|
||||
@@ -30,12 +30,6 @@
|
||||
configuration
|
||||
)
|
||||
|
||||
$: editorMode && onEditorMode()
|
||||
|
||||
function onEditorMode() {
|
||||
autosize()
|
||||
setTimeout(() => autosize(), 50)
|
||||
}
|
||||
const { app, worldStore, mode, componentControl } =
|
||||
getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
@@ -137,7 +131,6 @@
|
||||
el.style.cssText = 'height:auto; padding:0'
|
||||
el.style.cssText = 'height:' + el.scrollHeight + 'px'
|
||||
}
|
||||
// console.log(el, el?.scrollHeight)
|
||||
}, 0)
|
||||
}
|
||||
</script>
|
||||
@@ -170,6 +163,7 @@
|
||||
if (!editorMode) {
|
||||
editorMode = true
|
||||
document.getElementById(`text-${id}`)?.focus()
|
||||
autosize()
|
||||
}
|
||||
}}
|
||||
on:keydown|stopPropagation
|
||||
@@ -178,7 +172,7 @@
|
||||
<AlignWrapper {verticalAlignment}>
|
||||
<textarea
|
||||
class={twMerge(
|
||||
'whitespace-pre-wrap !outline-none !border-0 !bg-transparent !resize-none !ring-0 !p-0',
|
||||
'whitespace-pre-wrap !outline-none !border-0 !bg-transparent !resize-none !overflow-hidden !ring-0 !p-0',
|
||||
css?.text?.class,
|
||||
'wm-text',
|
||||
classes,
|
||||
@@ -220,7 +214,7 @@
|
||||
class="flex flex-wrap gap-2 pb-0.5 w-full {$mode === 'dnd' &&
|
||||
(componentInput?.type == 'template' || componentInput?.type == 'templatev2')
|
||||
? 'cursor-text'
|
||||
: 'overflow-auto'}"
|
||||
: ''}"
|
||||
>
|
||||
<svelte:element
|
||||
this={component}
|
||||
|
||||
@@ -35,12 +35,10 @@
|
||||
let localColumnDefs = columnDefs
|
||||
let lastTable = table
|
||||
|
||||
$: lastTable != undefined && table && onTableChange()
|
||||
|
||||
function onTableChange() {
|
||||
$: {
|
||||
if (table !== lastTable) {
|
||||
lastTable = table
|
||||
localColumnDefs = []
|
||||
lastTable = table
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -136,12 +136,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
function onNativeChange(e: Event) {
|
||||
const target = e.target as HTMLSelectElement
|
||||
const value = target.value
|
||||
setValue(value)
|
||||
}
|
||||
|
||||
function setValue(nvalue: any) {
|
||||
let result: any = undefined
|
||||
try {
|
||||
@@ -237,46 +231,35 @@
|
||||
}}
|
||||
>
|
||||
{#if Array.isArray(listItems) && listItems.every((x) => x && typeof x == 'object' && typeof x['label'] == 'string' && `value` in x)}
|
||||
{#if resolvedConfig.nativeHtmlSelect}
|
||||
<select class={css?.input?.class} style={css?.input?.style} on:change={onNativeChange}>
|
||||
{#if resolvedConfig.placeholder}
|
||||
<option value="" disabled selected>{resolvedConfig.placeholder}</option>
|
||||
{/if}
|
||||
{#each listItems as item (item.value)}
|
||||
<option value={item.value} selected={item.value === value}>{item.label}</option>
|
||||
{/each}
|
||||
</select>
|
||||
{:else}
|
||||
<Select
|
||||
inAppEditor={true}
|
||||
--border-radius="0.250rem"
|
||||
--clear-icon-color="#6b7280"
|
||||
--border={$darkMode ? '1px solid #6b7280' : '1px solid #d1d5db'}
|
||||
bind:filterText
|
||||
on:filter={handleFilter}
|
||||
on:clear={onClear}
|
||||
on:change={onChange}
|
||||
items={listItems}
|
||||
listAutoWidth={resolvedConfig.fullWidth}
|
||||
inputStyles={SELECT_INPUT_DEFAULT_STYLE.inputStyles}
|
||||
containerStyles={($darkMode
|
||||
? SELECT_INPUT_DEFAULT_STYLE.containerStylesDark
|
||||
: SELECT_INPUT_DEFAULT_STYLE.containerStyles) + css?.input?.style}
|
||||
{value}
|
||||
class={css?.input?.class}
|
||||
placeholder={resolvedConfig.placeholder}
|
||||
disabled={resolvedConfig.disabled}
|
||||
on:focus={() => {
|
||||
if (!$connectingInput.opened) {
|
||||
$selectedComponent = [id]
|
||||
}
|
||||
}}
|
||||
>
|
||||
<svelte:fragment slot="item" let:item
|
||||
>{#if resolvedConfig.create}{item.created ? 'Add new: ' : ''}{/if}{item.label}
|
||||
</svelte:fragment>
|
||||
</Select>
|
||||
{/if}
|
||||
<Select
|
||||
inAppEditor={true}
|
||||
--border-radius="0.250rem"
|
||||
--clear-icon-color="#6b7280"
|
||||
--border={$darkMode ? '1px solid #6b7280' : '1px solid #d1d5db'}
|
||||
bind:filterText
|
||||
on:filter={handleFilter}
|
||||
on:clear={onClear}
|
||||
on:change={onChange}
|
||||
items={listItems}
|
||||
listAutoWidth={resolvedConfig.fullWidth}
|
||||
inputStyles={SELECT_INPUT_DEFAULT_STYLE.inputStyles}
|
||||
containerStyles={($darkMode
|
||||
? SELECT_INPUT_DEFAULT_STYLE.containerStylesDark
|
||||
: SELECT_INPUT_DEFAULT_STYLE.containerStyles) + css?.input?.style}
|
||||
{value}
|
||||
class={css?.input?.class}
|
||||
placeholder={resolvedConfig.placeholder}
|
||||
disabled={resolvedConfig.disabled}
|
||||
on:focus={() => {
|
||||
if (!$connectingInput.opened) {
|
||||
$selectedComponent = [id]
|
||||
}
|
||||
}}
|
||||
>
|
||||
<svelte:fragment slot="item" let:item
|
||||
>{#if resolvedConfig.create}{item.created ? 'Add new: ' : ''}{/if}{item.label}
|
||||
</svelte:fragment>
|
||||
</Select>
|
||||
{:else}
|
||||
<Popover notClickable placement="bottom" popupClass="!bg-surface border w-96">
|
||||
<div
|
||||
|
||||
@@ -230,11 +230,6 @@
|
||||
input: getCountInput(resourceValue, tableValue, dbType, columnDefs, whereClause),
|
||||
id: x.id + '_count'
|
||||
})
|
||||
console.log(
|
||||
x.id,
|
||||
getCountInput(resourceValue, tableValue, dbType, columnDefs, whereClause),
|
||||
columnDefs
|
||||
)
|
||||
r.push({
|
||||
input: getInsertInput(tableValue, columnDefs, resourceValue, dbType),
|
||||
id: x.id + '_insert'
|
||||
|
||||
@@ -2106,13 +2106,6 @@ This is a paragraph.
|
||||
|
||||
tooltip: 'Preselect first item in the options if no default value is set'
|
||||
},
|
||||
nativeHtmlSelect: {
|
||||
type: 'static',
|
||||
fieldType: 'boolean',
|
||||
value: false,
|
||||
|
||||
tooltip: 'Use a native html select instead of the Windmill select component'
|
||||
},
|
||||
fullWidth: {
|
||||
type: 'static',
|
||||
fieldType: 'boolean',
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { SupportedLanguage } from '$lib/common'
|
||||
|
||||
export type FlowBuilderWhitelabelCustomUi = {
|
||||
export type WhitelabelCustomUi = {
|
||||
topBar?: {
|
||||
path?: boolean
|
||||
export?: boolean
|
||||
@@ -8,18 +8,8 @@ export type FlowBuilderWhitelabelCustomUi = {
|
||||
aiBuilder?: boolean
|
||||
tutorials?: boolean
|
||||
diff?: boolean
|
||||
extraDeployOptions?: boolean
|
||||
}
|
||||
settingsPanel?: boolean
|
||||
settingsTabs?: {
|
||||
schedule?: boolean
|
||||
sharedDiretory?: boolean
|
||||
earlyStop?: boolean
|
||||
earlyReturn?: boolean
|
||||
workerGroup?: boolean
|
||||
concurrency?: boolean
|
||||
cache?: boolean
|
||||
}
|
||||
triggers?: boolean
|
||||
flowNode?: boolean
|
||||
hub?: boolean
|
||||
@@ -28,31 +18,4 @@ export type FlowBuilderWhitelabelCustomUi = {
|
||||
stepAdvancedSettings?: boolean
|
||||
languages?: (SupportedLanguage | 'docker' | 'bunnative')[]
|
||||
scriptFork?: boolean
|
||||
editorBar?: EditorBarUi
|
||||
}
|
||||
|
||||
export type EditorBarUi = {
|
||||
contextVar?: boolean
|
||||
variable?: boolean
|
||||
type?: boolean
|
||||
assistants?: boolean
|
||||
multiplayer?: boolean
|
||||
autoformatting?: boolean
|
||||
aiGen?: boolean
|
||||
aiFix?: boolean
|
||||
library?: boolean
|
||||
useVsCode?: boolean
|
||||
}
|
||||
|
||||
export type ScriptEditorWhitelabelCustomUi = {
|
||||
editorBar?: EditorBarUi
|
||||
}
|
||||
|
||||
export type ScriptBuilderWhitelabelCustomUi = {
|
||||
topBar?: {
|
||||
path?: boolean
|
||||
settings?: boolean
|
||||
extraDeployOptions?: boolean
|
||||
}
|
||||
editorBar?: EditorBarUi
|
||||
}
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
<script lang="ts">
|
||||
import { Tabs, Tab, TabContent } from '$lib/components/common'
|
||||
import { CalendarCheck2, MailIcon, Terminal, Webhook } from 'lucide-svelte'
|
||||
|
||||
import { Tabs, Tab, TabContent, Button } from '$lib/components/common'
|
||||
import { copyToClipboard } from '$lib/utils'
|
||||
import { CalendarCheck2, Clipboard, MailIcon, Terminal, Webhook } from 'lucide-svelte'
|
||||
import { Highlight } from 'svelte-highlight'
|
||||
import { yaml } from 'svelte-highlight/languages'
|
||||
import json from 'svelte-highlight/languages/json'
|
||||
import { Pane, Splitpanes } from 'svelte-splitpanes'
|
||||
import YAML from 'yaml'
|
||||
import HighlightTheme from '../HighlightTheme.svelte'
|
||||
import FlowViewerInner from '../FlowViewerInner.svelte'
|
||||
|
||||
export let triggerSelected: 'webhooks' | 'email' | 'schedule' | 'cli' = 'webhooks'
|
||||
export let flow_json: any | undefined = undefined
|
||||
@@ -14,6 +17,8 @@
|
||||
|
||||
export let selected: string
|
||||
|
||||
let rawType: 'json' | 'yaml' = 'yaml'
|
||||
|
||||
$: if (hasStepDetails) {
|
||||
selected = 'flow_step'
|
||||
}
|
||||
@@ -92,7 +97,36 @@
|
||||
</Splitpanes>
|
||||
</TabContent>
|
||||
<TabContent value="raw" class="flex flex-col flex-1 h-full overflow-auto">
|
||||
<FlowViewerInner flow={flow_json} />
|
||||
<Tabs bind:selected={rawType} wrapperClass="mt-4">
|
||||
<Tab value="yaml">YAML</Tab>
|
||||
<Tab value="json">JSON</Tab>
|
||||
<svelte:fragment slot="content">
|
||||
<div class="relative pt-2">
|
||||
<Button
|
||||
on:click={() =>
|
||||
copyToClipboard(
|
||||
rawType === 'yaml'
|
||||
? YAML.stringify(flow_json)
|
||||
: JSON.stringify(flow_json, null, 4)
|
||||
)}
|
||||
color="light"
|
||||
variant="border"
|
||||
size="xs"
|
||||
startIcon={{ icon: Clipboard }}
|
||||
btnClasses="absolute top-2 right-2 w-min"
|
||||
>
|
||||
Copy content
|
||||
</Button>
|
||||
<Highlight
|
||||
class="overflow-auto px-1"
|
||||
language={rawType === 'yaml' ? yaml : json}
|
||||
code={rawType === 'yaml'
|
||||
? YAML.stringify(flow_json)
|
||||
: JSON.stringify(flow_json, null, 4)}
|
||||
/>
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
</Tabs>
|
||||
</TabContent>
|
||||
<TabContent value="flow_step" class="flex flex-col flex-1 h-full">
|
||||
<slot name="flow_step" />
|
||||
|
||||
@@ -60,10 +60,10 @@
|
||||
}
|
||||
|
||||
function computeFlowWebhooks(path: string) {
|
||||
let webhooksBase = `${$page.url.origin}${base}/api/w/${$workspaceStore}/jobs`
|
||||
let base = `${$page.url.origin}/api/w/${$workspaceStore}/jobs`
|
||||
|
||||
let urlAsync = `${webhooksBase}/run/f/${path}`
|
||||
let urlSync = `${webhooksBase}/run_wait_result/f/${path}`
|
||||
let urlAsync = `${base}/run/f/${path}`
|
||||
let urlSync = `${base}/run_wait_result/f/${path}`
|
||||
return {
|
||||
async: {
|
||||
path: urlAsync
|
||||
|
||||
@@ -91,7 +91,6 @@
|
||||
on:close={() => {
|
||||
drawer?.closeDrawer()
|
||||
}}
|
||||
noPadding
|
||||
>
|
||||
<Splitpanes class="!overflow-visible">
|
||||
<Pane size={20}>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
import { defaultScriptLanguages, processLangs } from '$lib/scripts'
|
||||
import type { SupportedLanguage } from '$lib/common'
|
||||
import DefaultScripts from '$lib/components/DefaultScripts.svelte'
|
||||
import type { FlowBuilderWhitelabelCustomUi } from '$lib/components/custom_ui'
|
||||
import type { WhitelabelCustomUi } from '$lib/components/custom_ui'
|
||||
|
||||
export let failureModule: boolean
|
||||
export let shouldDisableTriggerScripts: boolean = false
|
||||
@@ -55,7 +55,7 @@
|
||||
return kind == 'script' && !failureModule
|
||||
}
|
||||
|
||||
let customUi: undefined | FlowBuilderWhitelabelCustomUi = getContext('customUi')
|
||||
let customUi: undefined | WhitelabelCustomUi = getContext('customUi')
|
||||
</script>
|
||||
|
||||
<div class="p-4 h-full flex flex-col" id="flow-editor-flow-inputs">
|
||||
|
||||
@@ -55,8 +55,7 @@
|
||||
flowStore,
|
||||
pathStore,
|
||||
saveDraft,
|
||||
flowInputsStore,
|
||||
customUi
|
||||
flowInputsStore
|
||||
} = getContext<FlowEditorContext>('FlowEditorContext')
|
||||
|
||||
export let flowModule: FlowModule
|
||||
@@ -266,7 +265,6 @@
|
||||
{#if flowModule.value.type === 'rawscript' && !noEditor}
|
||||
<div class="border-b-2 shadow-sm px-1">
|
||||
<EditorBar
|
||||
customUi={customUi?.editorBar}
|
||||
{validCode}
|
||||
{editor}
|
||||
{diffEditor}
|
||||
@@ -404,12 +402,7 @@
|
||||
{#if !$selectedId.includes('failure')}
|
||||
<Tab value="runtime">Runtime</Tab>
|
||||
<Tab value="cache" active={Boolean(flowModule.cache_ttl)}>Cache</Tab>
|
||||
<Tab
|
||||
value="early-stop"
|
||||
active={Boolean(
|
||||
flowModule.stop_after_if || flowModule.stop_after_all_iters_if
|
||||
)}
|
||||
>
|
||||
<Tab value="early-stop" active={Boolean(flowModule.stop_after_if)}>
|
||||
Early Stop
|
||||
</Tab>
|
||||
<Tab value="suspend" active={Boolean(flowModule.suspend)}>Suspend</Tab>
|
||||
|
||||
@@ -2,14 +2,13 @@
|
||||
import SimpleEditor from '$lib/components/SimpleEditor.svelte'
|
||||
import Toggle from '$lib/components/Toggle.svelte'
|
||||
import PropPickerWrapper from '$lib/components/flows/propPicker/PropPickerWrapper.svelte'
|
||||
import type { Flow, FlowModule } from '$lib/gen'
|
||||
import type { FlowModule } from '$lib/gen'
|
||||
import Tooltip from '$lib/components/Tooltip.svelte'
|
||||
import type { FlowEditorContext } from '../types'
|
||||
import { getContext } from 'svelte'
|
||||
import { NEVER_TESTED_THIS_FAR } from '../models'
|
||||
import Section from '$lib/components/Section.svelte'
|
||||
import { getStepPropPicker } from '../previousResults'
|
||||
import { dfs } from '../previousResults'
|
||||
|
||||
const { flowStateStore, flowStore, previewArgs } =
|
||||
getContext<FlowEditorContext>('FlowEditorContext')
|
||||
@@ -27,207 +26,80 @@
|
||||
false
|
||||
)
|
||||
|
||||
function checkIfParentLoop(flowStore: typeof $flowStore): string | null {
|
||||
const flow: Flow = JSON.parse(JSON.stringify(flowStore))
|
||||
const parents = dfs(flowModule.id, flow, true)
|
||||
for (const parent of parents.slice(1)) {
|
||||
if (parent.value.type === 'forloopflow' || parent.value.type === 'whileloopflow') {
|
||||
return parent.id
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
$: isLoop = flowModule.value.type === 'forloopflow' || flowModule.value.type === 'whileloopflow'
|
||||
$: isBranchAll = flowModule.value.type === 'branchall'
|
||||
$: isStopAfterIfEnabled = Boolean(flowModule.stop_after_if)
|
||||
$: isStopAfterAllIterationsEnabled = Boolean(flowModule.stop_after_all_iters_if)
|
||||
$: result = $flowStateStore[flowModule.id]?.previewResult ?? NEVER_TESTED_THIS_FAR
|
||||
$: parentLoopId = checkIfParentLoop($flowStore)
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col items-start space-y-2 {$$props.class}">
|
||||
{#if !isBranchAll}
|
||||
<Section
|
||||
label={(isLoop
|
||||
? 'Break loop'
|
||||
: parentLoopId
|
||||
? 'Break parent loop module ' + parentLoopId
|
||||
: 'Stop flow early') + (isLoop ? ' (evaluated after each iteration)' : '')}
|
||||
class="w-full"
|
||||
>
|
||||
<svelte:fragment slot="header">
|
||||
<Tooltip documentationLink="https://www.windmill.dev/docs/flows/early_stop">
|
||||
If defined, at the end of the step, the predicate expression will be evaluated to decide
|
||||
if the flow should stop early or break if inside a for/while loop.
|
||||
</Tooltip>
|
||||
</svelte:fragment>
|
||||
<Section label="Early stop/Break" class="w-full">
|
||||
<svelte:fragment slot="header">
|
||||
<Tooltip documentationLink="https://www.windmill.dev/docs/flows/early_stop">
|
||||
If defined, at the end of the step, the predicate expression will be evaluated to decide if
|
||||
the flow should stop early.
|
||||
</Tooltip>
|
||||
</svelte:fragment>
|
||||
|
||||
<Toggle
|
||||
checked={isStopAfterIfEnabled}
|
||||
on:change={() => {
|
||||
if (isStopAfterIfEnabled && flowModule.stop_after_if) {
|
||||
flowModule.stop_after_if = undefined
|
||||
} else {
|
||||
flowModule.stop_after_if = {
|
||||
expr: 'result == undefined',
|
||||
skip_if_stopped: false
|
||||
}
|
||||
<Toggle
|
||||
checked={isStopAfterIfEnabled}
|
||||
on:change={() => {
|
||||
if (isStopAfterIfEnabled && flowModule.stop_after_if) {
|
||||
flowModule.stop_after_if = undefined
|
||||
} else {
|
||||
flowModule.stop_after_if = {
|
||||
expr: 'result == undefined',
|
||||
skip_if_stopped: false
|
||||
}
|
||||
}}
|
||||
options={{
|
||||
right: isLoop
|
||||
? 'Break loop'
|
||||
: parentLoopId
|
||||
? 'Break parent loop module'
|
||||
: 'Stop flow' + ' if condition met'
|
||||
}}
|
||||
/>
|
||||
}
|
||||
}}
|
||||
options={{
|
||||
right: 'Early stop or Break if condition met'
|
||||
}}
|
||||
/>
|
||||
|
||||
<div
|
||||
class="w-full border p-2 flex flex-col {flowModule.stop_after_if
|
||||
? ''
|
||||
: 'bg-surface-secondary'}"
|
||||
>
|
||||
{#if flowModule.stop_after_if}
|
||||
{@const earlyStopResult = isLoop
|
||||
? Array.isArray(result) && result.length > 0
|
||||
? result[result.length - 1]
|
||||
: result === NEVER_TESTED_THIS_FAR
|
||||
? result
|
||||
: undefined
|
||||
: result}
|
||||
{#if !parentLoopId && !isLoop}
|
||||
<Toggle
|
||||
size="xs"
|
||||
bind:checked={flowModule.stop_after_if.skip_if_stopped}
|
||||
options={{
|
||||
right: 'Label flow as "skipped" if stopped'
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
<span class="mt-2 text-xs font-bold">Stop condition expression</span>
|
||||
<div class="border w-full">
|
||||
<PropPickerWrapper
|
||||
notSelectable
|
||||
flow_input={stepPropPicker.pickableProperties.flow_input}
|
||||
pickableProperties={undefined}
|
||||
result={earlyStopResult}
|
||||
extraResults={isLoop ? { all_iters: result } : undefined}
|
||||
on:select={({ detail }) => {
|
||||
editor?.insertAtCursor(detail)
|
||||
editor?.focus()
|
||||
}}
|
||||
>
|
||||
<SimpleEditor
|
||||
bind:this={editor}
|
||||
lang="javascript"
|
||||
bind:code={flowModule.stop_after_if.expr}
|
||||
class="few-lines-editor"
|
||||
extraLib={`declare const result = ${JSON.stringify(earlyStopResult)};` +
|
||||
(isLoop ? `\ndeclare const all_iters = ${JSON.stringify(result)};` : '')}
|
||||
/>
|
||||
</PropPickerWrapper>
|
||||
</div>
|
||||
{:else}
|
||||
{#if !parentLoopId && !isLoop}
|
||||
<Toggle
|
||||
disabled
|
||||
size="xs"
|
||||
options={{
|
||||
right: 'Label flow as "skipped" if stopped'
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
<span class="mt-2 text-xs font-bold">Stop condition expression</span>
|
||||
<textarea disabled rows="3" class="min-h-[80px]" />
|
||||
{/if}
|
||||
</div>
|
||||
</Section>
|
||||
{/if}
|
||||
|
||||
{#if isLoop || isBranchAll}
|
||||
<Section
|
||||
label={(parentLoopId ? 'Break parent loop module ' + parentLoopId : 'Stop flow early') +
|
||||
(isBranchAll
|
||||
? ' (evaluated after all branches have been run)'
|
||||
: ' (evaluated after all iterations)')}
|
||||
class="w-full"
|
||||
<div
|
||||
class="w-full border p-2 flex flex-col {flowModule.stop_after_if
|
||||
? ''
|
||||
: 'bg-surface-secondary'}"
|
||||
>
|
||||
<svelte:fragment slot="header">
|
||||
<Tooltip documentationLink="https://www.windmill.dev/docs/flows/early_stop">
|
||||
If defined, at the end of the step, the predicate expression will be evaluated to decide
|
||||
if the flow should stop early or break if inside a for/while loop.
|
||||
</Tooltip>
|
||||
</svelte:fragment>
|
||||
|
||||
<Toggle
|
||||
checked={isStopAfterAllIterationsEnabled}
|
||||
on:change={() => {
|
||||
if (isStopAfterAllIterationsEnabled && flowModule.stop_after_all_iters_if) {
|
||||
flowModule.stop_after_all_iters_if = undefined
|
||||
} else {
|
||||
flowModule.stop_after_all_iters_if = {
|
||||
expr: 'result == undefined',
|
||||
skip_if_stopped: false
|
||||
}
|
||||
}
|
||||
}}
|
||||
options={{
|
||||
right: (parentLoopId ? 'Break parent loop module' : 'Stop flow') + ' if condition met'
|
||||
}}
|
||||
/>
|
||||
|
||||
<div
|
||||
class="w-full border p-2 flex flex-col {flowModule.stop_after_all_iters_if
|
||||
? ''
|
||||
: 'bg-surface-secondary'}"
|
||||
>
|
||||
{#if flowModule.stop_after_all_iters_if}
|
||||
{#if !parentLoopId}
|
||||
<Toggle
|
||||
size="xs"
|
||||
bind:checked={flowModule.stop_after_all_iters_if.skip_if_stopped}
|
||||
options={{
|
||||
right: 'Label flow as "skipped" if stopped'
|
||||
}}
|
||||
{#if flowModule.stop_after_if}
|
||||
<Toggle
|
||||
size="xs"
|
||||
bind:checked={flowModule.stop_after_if.skip_if_stopped}
|
||||
options={{
|
||||
right: 'Label flow as "skipped" if stopped'
|
||||
}}
|
||||
/>
|
||||
<span class="mt-2 text-xs font-bold">Stop condition expression</span>
|
||||
<div class="border w-full">
|
||||
<PropPickerWrapper
|
||||
notSelectable
|
||||
flow_input={stepPropPicker.pickableProperties.flow_input}
|
||||
pickableProperties={undefined}
|
||||
{result}
|
||||
on:select={({ detail }) => {
|
||||
editor?.insertAtCursor(detail)
|
||||
editor?.focus()
|
||||
}}
|
||||
>
|
||||
<SimpleEditor
|
||||
bind:this={editor}
|
||||
lang="javascript"
|
||||
bind:code={flowModule.stop_after_if.expr}
|
||||
class="few-lines-editor"
|
||||
extraLib={`declare const result = ${JSON.stringify(result)};`}
|
||||
/>
|
||||
{/if}
|
||||
<span class="mt-2 text-xs font-bold">Stop condition expression</span>
|
||||
<div class="border w-full">
|
||||
<PropPickerWrapper
|
||||
notSelectable
|
||||
flow_input={stepPropPicker.pickableProperties.flow_input}
|
||||
pickableProperties={undefined}
|
||||
{result}
|
||||
on:select={({ detail }) => {
|
||||
editor?.insertAtCursor(detail)
|
||||
editor?.focus()
|
||||
}}
|
||||
>
|
||||
<SimpleEditor
|
||||
bind:this={editor}
|
||||
lang="javascript"
|
||||
bind:code={flowModule.stop_after_all_iters_if.expr}
|
||||
class="few-lines-editor"
|
||||
extraLib={`declare const result = ${JSON.stringify(result)};`}
|
||||
/>
|
||||
</PropPickerWrapper>
|
||||
</div>
|
||||
{:else}
|
||||
{#if !parentLoopId}
|
||||
<Toggle
|
||||
disabled
|
||||
size="xs"
|
||||
options={{
|
||||
right: 'Label flow as "skipped" if stopped'
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
<span class="mt-2 text-xs font-bold">Stop condition expression</span>
|
||||
<textarea disabled rows="3" class="min-h-[80px]" />
|
||||
{/if}
|
||||
</div>
|
||||
</Section>
|
||||
{/if}
|
||||
</PropPickerWrapper>
|
||||
</div>
|
||||
{:else}
|
||||
<Toggle
|
||||
disabled
|
||||
size="xs"
|
||||
options={{
|
||||
right: 'Label flow as "skipped" if stopped'
|
||||
}}
|
||||
/> <span class="mt-2 text-xs font-bold">Stop condition expression</span>
|
||||
<textarea disabled rows="3" class="min-h-[80px]" />
|
||||
{/if}
|
||||
</div>
|
||||
</Section>
|
||||
</div>
|
||||
|
||||
@@ -19,14 +19,14 @@
|
||||
import { sendUserToast } from '$lib/utils'
|
||||
import { workerTags } from '$lib/stores'
|
||||
import { getLatestHashForScript } from '$lib/scripts'
|
||||
import type { FlowBuilderWhitelabelCustomUi } from '$lib/components/custom_ui'
|
||||
import type { WhitelabelCustomUi } from '$lib/components/custom_ui'
|
||||
|
||||
export let module: FlowModule
|
||||
const { scriptEditorDrawer, flowStore, selectedId } =
|
||||
getContext<FlowEditorContext>('FlowEditorContext')
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
let customUi: undefined | FlowBuilderWhitelabelCustomUi = getContext('customUi')
|
||||
let customUi: undefined | WhitelabelCustomUi = getContext('customUi')
|
||||
|
||||
loadWorkerGroups()
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
<svelte:fragment slot="text">Cache</svelte:fragment>
|
||||
</Popover>
|
||||
{/if}
|
||||
{#if module.stop_after_if || module.stop_after_all_iters_if}
|
||||
{#if module.stop_after_if}
|
||||
<Popover
|
||||
placement="bottom"
|
||||
class="center-center rounded p-2 bg-blue-100 text-blue-800 border border-blue-300 hover:bg-blue-200 dark:bg-frost-700 dark:text-frost-100 dark:border-frost-600"
|
||||
|
||||
@@ -1,20 +1,17 @@
|
||||
<script lang="ts">
|
||||
import type { SupportedLanguage } from '$lib/common'
|
||||
import DiffEditor from '$lib/components/DiffEditor.svelte'
|
||||
import HighlightCode from '$lib/components/HighlightCode.svelte'
|
||||
import TimeAgo from '$lib/components/TimeAgo.svelte'
|
||||
import { ScriptService } from '$lib/gen'
|
||||
import { getScriptByPath, scriptLangToEditorLang } from '$lib/scripts'
|
||||
import { getScriptByPath } from '$lib/scripts'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
|
||||
export let path: string
|
||||
export let hash: string | undefined = undefined
|
||||
export let previousHash: string | undefined = undefined
|
||||
export let showDate = false
|
||||
export let showAllCode: boolean = true
|
||||
|
||||
let code: string
|
||||
let previousCode: string
|
||||
let language: SupportedLanguage
|
||||
let lock: string | undefined = undefined
|
||||
let date: string | undefined = undefined
|
||||
@@ -27,7 +24,6 @@
|
||||
? await ScriptService.getScriptByHash({ workspace: $workspaceStore!, hash })
|
||||
: await getScriptByPath(path!)
|
||||
code = script.content
|
||||
|
||||
language = script.language
|
||||
lock = script.lock
|
||||
date = script.created_at
|
||||
@@ -37,26 +33,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function loadPreviousCode(previousHash: string) {
|
||||
try {
|
||||
const previousScript = await ScriptService.getScriptByHash({
|
||||
workspace: $workspaceStore!,
|
||||
hash: previousHash
|
||||
})
|
||||
previousCode = previousScript.content
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
$: path && loadCode(path, hash)
|
||||
$: path && previousHash && loadPreviousCode(previousHash)
|
||||
|
||||
function toggleShowAll() {
|
||||
showAllCode = !showAllCode
|
||||
}
|
||||
|
||||
export let showDiff: boolean = false
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col flex-1 h-full overflow-auto p-2">
|
||||
@@ -66,20 +47,7 @@
|
||||
{#if notFound}
|
||||
<div class="text-red-400">script not found at {path} in workspace {$workspaceStore}</div>
|
||||
{:else if showAllCode}
|
||||
{#if showDiff}
|
||||
{#key previousCode + code}
|
||||
<DiffEditor
|
||||
class="h-screen"
|
||||
readOnly
|
||||
automaticLayout
|
||||
defaultLang={scriptLangToEditorLang(language)}
|
||||
defaultOriginal={previousCode}
|
||||
defaultModified={code}
|
||||
/>
|
||||
{/key}
|
||||
{:else}
|
||||
<HighlightCode {language} {code} />
|
||||
{/if}
|
||||
<HighlightCode {language} {code} />
|
||||
{:else}
|
||||
<div class="code-container h-full">
|
||||
<HighlightCode {language} code={code?.split('\n').slice(0, 10).join('\n')} />
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
export let noEditor: boolean
|
||||
|
||||
const { selectedId, flowStore, initialPath, previewArgs, pathStore, schedule, customUi } =
|
||||
const { selectedId, flowStore, initialPath, previewArgs, pathStore, schedule } =
|
||||
getContext<FlowEditorContext>('FlowEditorContext')
|
||||
|
||||
let hostname = BROWSER ? window.location.protocol + '//' + window.location.host : 'SSR'
|
||||
@@ -52,33 +52,22 @@
|
||||
<div class="h-full flex-1">
|
||||
<Tabs bind:selected={$selectedId}>
|
||||
<Tab value="settings-metadata">Metadata</Tab>
|
||||
{#if !noEditor && customUi?.settingsTabs?.schedule != false}
|
||||
{#if !noEditor}
|
||||
<Tab value="settings-schedule" active={$schedule.enabled}>Schedule</Tab>
|
||||
{/if}
|
||||
{#if customUi?.settingsTabs?.sharedDiretory != false}
|
||||
<Tab value="settings-same-worker" active={$flowStore.value.same_worker}>
|
||||
Shared Directory
|
||||
</Tab>
|
||||
{/if}
|
||||
{#if customUi?.settingsTabs?.earlyStop != false}
|
||||
<Tab value="settings-early-stop" active={Boolean($flowStore.value.skip_expr)}>
|
||||
Early Stop
|
||||
</Tab>
|
||||
{/if}
|
||||
{#if customUi?.settingsTabs?.earlyReturn != false}
|
||||
<Tab value="settings-early-return" active={Boolean($flowStore.value.early_return)}>
|
||||
Early Return
|
||||
</Tab>
|
||||
{/if}
|
||||
{#if customUi?.settingsTabs?.workerGroup != false}
|
||||
<Tab value="settings-worker-group">Worker Group</Tab>
|
||||
{/if}
|
||||
{#if customUi?.settingsTabs?.concurrency != false}
|
||||
<Tab value="settings-concurrency">Concurrency</Tab>
|
||||
{/if}
|
||||
{#if customUi?.settingsTabs?.cache != false}
|
||||
<Tab value="settings-cache" active={Boolean($flowStore.value.cache_ttl)}>Cache</Tab>
|
||||
{/if}
|
||||
<Tab value="settings-same-worker" active={$flowStore.value.same_worker}>
|
||||
Shared Directory
|
||||
</Tab>
|
||||
<Tab value="settings-early-stop" active={Boolean($flowStore.value.skip_expr)}>
|
||||
Early Stop
|
||||
</Tab>
|
||||
<Tab value="settings-early-return" active={Boolean($flowStore.value.early_return)}>
|
||||
Early Return
|
||||
</Tab>
|
||||
<Tab value="settings-worker-group">Worker Group</Tab>
|
||||
<Tab value="settings-concurrency">Concurrency</Tab>
|
||||
<Tab value="settings-cache" active={Boolean($flowStore.value.cache_ttl)}>Cache</Tab>
|
||||
|
||||
<svelte:fragment slot="content">
|
||||
<TabContent value="settings-metadata" class="p-4 h-full overflow-auto">
|
||||
<Section label="Metadata">
|
||||
|
||||
@@ -85,9 +85,6 @@ function getModuleExprs(x: FlowModule): string[] {
|
||||
if (x.stop_after_if?.expr) {
|
||||
exprs.push(x.stop_after_if.expr)
|
||||
}
|
||||
if (x.stop_after_all_iters_if?.expr) {
|
||||
exprs.push(x.stop_after_all_iters_if.expr)
|
||||
}
|
||||
exprs.push(...getExpr(x.sleep))
|
||||
}
|
||||
return exprs
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import StepGen from '$lib/components/copilot/StepGen.svelte'
|
||||
import type { FlowModule } from '$lib/gen'
|
||||
import BarsStaggered from '$lib/components/icons/BarsStaggered.svelte'
|
||||
import type { FlowBuilderWhitelabelCustomUi } from '$lib/components/custom_ui'
|
||||
import type { WhitelabelCustomUi } from '$lib/components/custom_ui'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
@@ -18,7 +18,7 @@
|
||||
export let disableAi = false
|
||||
|
||||
$: !open && (funcDesc = '')
|
||||
let customUi: undefined | FlowBuilderWhitelabelCustomUi = getContext('customUi')
|
||||
let customUi: undefined | WhitelabelCustomUi = getContext('customUi')
|
||||
</script>
|
||||
|
||||
<Menu
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
$: itemProps = {
|
||||
selected: $selectedId === mod.id,
|
||||
retry: mod.retry?.constant != undefined || mod.retry?.exponential != undefined,
|
||||
earlyStop: mod.stop_after_if != undefined || mod.stop_after_all_iters_if != undefined,
|
||||
earlyStop: mod.stop_after_if != undefined,
|
||||
suspend: Boolean(mod.suspend),
|
||||
sleep: Boolean(mod.sleep),
|
||||
cache: Boolean(mod.cache_ttl),
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
|
||||
export let pickableProperties: PickableProperties | undefined
|
||||
export let result: any = undefined
|
||||
export let extraResults: any = undefined
|
||||
export let flow_input: any = undefined
|
||||
export let error: boolean = false
|
||||
export let displayContext = true
|
||||
@@ -74,7 +73,6 @@
|
||||
{#if result}
|
||||
<PropPickerResult
|
||||
{result}
|
||||
{extraResults}
|
||||
{flow_input}
|
||||
on:select={({ detail }) => {
|
||||
if (!notSelectable && !$propPickerConfig) {
|
||||
|
||||
@@ -4,7 +4,6 @@ import type { Writable } from 'svelte/store'
|
||||
import type ScriptEditorDrawer from './content/ScriptEditorDrawer.svelte'
|
||||
import type { FlowState } from './flowState'
|
||||
import type { Schedule } from './scheduleUtils'
|
||||
import type { FlowBuilderWhitelabelCustomUi } from '../custom_ui'
|
||||
|
||||
export type FlowInput = Record<
|
||||
string,
|
||||
@@ -40,5 +39,4 @@ export type FlowEditorContext = {
|
||||
saveDraft: () => void
|
||||
initialPath: string
|
||||
flowInputsStore: Writable<FlowInput>
|
||||
customUi: FlowBuilderWhitelabelCustomUi
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { type FlowModule } from '../../gen'
|
||||
import { NODE, type GraphModuleState } from '.'
|
||||
import { createEventDispatcher, onMount, setContext } from 'svelte'
|
||||
import { createEventDispatcher, setContext } from 'svelte'
|
||||
|
||||
import { writable, type Writable } from 'svelte/store'
|
||||
import '@xyflow/svelte/dist/style.css'
|
||||
@@ -226,10 +226,6 @@
|
||||
}
|
||||
|
||||
$: width && centerViewport(width)
|
||||
|
||||
onMount(() => {
|
||||
centerViewport(width)
|
||||
})
|
||||
</script>
|
||||
|
||||
<div style={`height: ${height}px; max-height: ${maxHeight}px;`} bind:clientWidth={width}>
|
||||
|
||||
@@ -33,9 +33,6 @@ export type FlowStatusViewerContext = {
|
||||
flowStateStore?: Writable<FlowState>
|
||||
retryStatus: Writable<Record<string, number | undefined>>
|
||||
suspendStatus: Writable<Record<string, { nb: number; job: Job }>>
|
||||
hideDownloadInGraph?: boolean
|
||||
hideTimeline?: boolean
|
||||
hideNodeDefinition?: boolean
|
||||
}
|
||||
export type GraphModuleState = {
|
||||
type: FlowStatusModule['type']
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
import ObjectViewer from './ObjectViewer.svelte'
|
||||
|
||||
export let result: any
|
||||
export let extraResults: any = undefined
|
||||
export let flow_input: any = undefined
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
@@ -12,11 +11,7 @@
|
||||
<div class="w-full px-2">
|
||||
<span class="font-bold text-sm">Result</span>
|
||||
<div class="overflow-y-auto mb-2 w-full">
|
||||
<ObjectViewer
|
||||
allowCopy={false}
|
||||
json={{ result, ...(extraResults ? extraResults : {}) }}
|
||||
on:select
|
||||
/>
|
||||
<ObjectViewer allowCopy={false} json={{ result }} on:select />
|
||||
</div>
|
||||
{#if flow_input}
|
||||
<span class="font-bold text-sm">Flow Input</span>
|
||||
|
||||
@@ -5,11 +5,6 @@ export type Changelog = {
|
||||
}
|
||||
|
||||
const changelogs: Changelog[] = [
|
||||
{
|
||||
label: 'Continue on disapproval/timeout',
|
||||
href: 'https://www.windmill.dev/changelog/continue-on-disapproval',
|
||||
date: '2024-08-14'
|
||||
},
|
||||
{
|
||||
label: 'Nativets runtime supports npm packages and relative imports',
|
||||
href: 'https://www.windmill.dev/changelog/native-runtime-imports',
|
||||
|
||||
@@ -437,7 +437,7 @@
|
||||
overflowAuto
|
||||
noSide={true}
|
||||
on:select={(e) => {
|
||||
if (e.detail) {
|
||||
if (e.detail.id) {
|
||||
stepDetail = e.detail
|
||||
} else {
|
||||
stepDetail = undefined
|
||||
|
||||
@@ -475,7 +475,7 @@
|
||||
|
||||
{#if script}
|
||||
<Drawer bind:open={versionsDrawerOpen} size="1200px">
|
||||
<DrawerContent title="Versions History" on:close={() => (versionsDrawerOpen = false)} noPadding>
|
||||
<DrawerContent title="Versions History" on:close={() => (versionsDrawerOpen = false)}>
|
||||
<ScriptVersionHistory
|
||||
scriptPath={script.path}
|
||||
openDetails
|
||||
|
||||
@@ -189,10 +189,10 @@
|
||||
let queueMetricsDrawer: Drawer
|
||||
let selectedTab: string = 'default'
|
||||
|
||||
$: groupedWorkers && selectedTab == 'default' && updateSelectedTabIfDefaultDoesNotExist()
|
||||
$: workerGroups && selectedTab == 'default' && updateSelectedTabIfDefaultDoesNotExist()
|
||||
|
||||
function updateSelectedTabIfDefaultDoesNotExist() {
|
||||
if (selectedTab == 'default' && !groupedWorkers.some((x) => x[0] == 'default')) {
|
||||
if (selectedTab == 'default' && !workerGroups?.hasOwnProperty('default')) {
|
||||
selectedTab = Object.keys(workerGroups ?? {})[0] ?? 'default'
|
||||
}
|
||||
}
|
||||
@@ -567,7 +567,7 @@
|
||||
<Cell>
|
||||
<div class="flex flex-col gap-1">
|
||||
<div>
|
||||
{vcpus ? (vcpus / 100000).toFixed(2) + ' vCPUs' : '--'}
|
||||
{vcpus ? (vcpus / 100000).toFixed(1) + ' vCPUs' : '--'}
|
||||
</div>
|
||||
<div>
|
||||
{memory ? Math.round(memory / 1024 / 1024) + 'MB' : '--'}
|
||||
|
||||
@@ -96,8 +96,7 @@
|
||||
testStepStore,
|
||||
saveDraft: () => {},
|
||||
initialPath: '',
|
||||
flowInputsStore: writable<FlowInput>({}),
|
||||
customUi: {}
|
||||
flowInputsStore: writable<FlowInput>({})
|
||||
})
|
||||
|
||||
type LastEdit = {
|
||||
|
||||
@@ -1,61 +1,22 @@
|
||||
<script lang="ts">
|
||||
// import EditableSchemaWrapper from '$lib/components/schema/EditableSchemaWrapper.svelte'
|
||||
import EditableSchemaWrapper from '$lib/components/schema/EditableSchemaWrapper.svelte'
|
||||
|
||||
// import FlowBuilder from '$lib/components/FlowBuilder.svelte'
|
||||
import ScriptBuilder from '$lib/components/ScriptBuilder.svelte'
|
||||
// import type { OpenFlow } from '$lib/gen'
|
||||
// import { writable, type Writable } from 'svelte/store'
|
||||
|
||||
// let schema = {
|
||||
// type: 'object',
|
||||
// properties: {
|
||||
// foo: {
|
||||
// type: 'string',
|
||||
// description: '',
|
||||
// required: [],
|
||||
// nullable: false,
|
||||
// default: '',
|
||||
// disableVariablePicker: false,
|
||||
// disableCreate: false,
|
||||
// password: false
|
||||
// }
|
||||
// },
|
||||
// order: ['foo']
|
||||
// }
|
||||
|
||||
// let flowStore: Writable<OpenFlow> = writable({
|
||||
// summary: 'foo',
|
||||
// value: {
|
||||
// modules: []
|
||||
// }
|
||||
// })
|
||||
// let flowStateStore: Writable<Record<string, any>> = writable({})
|
||||
let schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: {
|
||||
type: 'string',
|
||||
description: '',
|
||||
required: [],
|
||||
nullable: false,
|
||||
default: '',
|
||||
disableVariablePicker: false,
|
||||
disableCreate: false,
|
||||
password: false
|
||||
}
|
||||
},
|
||||
order: ['foo']
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- <EditableSchemaWrapper on:change={() => console.log('FOO')} {schema} /> -->
|
||||
<!-- <FlowBuilder
|
||||
newFlow={false}
|
||||
initialPath="u/admin/foo"
|
||||
selectedId={undefined}
|
||||
{flowStore}
|
||||
{flowStateStore}
|
||||
customUi={{
|
||||
topBar: {
|
||||
extraDeployOptions: false
|
||||
},
|
||||
settingsTabs: {
|
||||
workerGroup: false
|
||||
},
|
||||
settingsPanel: false
|
||||
}}
|
||||
/> -->
|
||||
|
||||
<ScriptBuilder
|
||||
script={{
|
||||
summary: 'foo',
|
||||
path: 'u/admin/foo',
|
||||
description: 'foo',
|
||||
language: 'python3',
|
||||
content: 'print("foo")'
|
||||
}}
|
||||
/>
|
||||
<EditableSchemaWrapper on:change={() => console.log('FOO')} {schema} />
|
||||
|
||||
+2
-2
@@ -4,8 +4,8 @@ verify_ssl = true
|
||||
name = "pypi"
|
||||
|
||||
[packages]
|
||||
wmill = ">=1.383.0"
|
||||
wmill_pg = ">=1.383.0"
|
||||
wmill = ">=1.381.0"
|
||||
wmill_pg = ">=1.381.0"
|
||||
sendgrid = "*"
|
||||
mysql-connector-python = "*"
|
||||
pymongo = "*"
|
||||
|
||||
+1
-10
@@ -1,7 +1,7 @@
|
||||
openapi: "3.0.3"
|
||||
|
||||
info:
|
||||
version: 1.383.0
|
||||
version: 1.381.0
|
||||
title: OpenFlow Spec
|
||||
contact:
|
||||
name: Ruben Fiszel
|
||||
@@ -103,15 +103,6 @@ components:
|
||||
type: string
|
||||
required:
|
||||
- expr
|
||||
stop_after_all_iters_if:
|
||||
type: object
|
||||
properties:
|
||||
skip_if_stopped:
|
||||
type: boolean
|
||||
expr:
|
||||
type: string
|
||||
required:
|
||||
- expr
|
||||
sleep:
|
||||
$ref: "#/components/schemas/InputTransform"
|
||||
cache_ttl:
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
RootModule = 'WindmillClient.psm1'
|
||||
|
||||
# Version number of this module.
|
||||
ModuleVersion = '1.383.0'
|
||||
ModuleVersion = '1.381.0'
|
||||
|
||||
# Supported PSEditions
|
||||
# CompatiblePSEditions = @()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[tool.poetry]
|
||||
name = "wmill"
|
||||
version = "1.383.0"
|
||||
version = "1.381.0"
|
||||
description = "A client library for accessing Windmill server wrapping the Windmill client API"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://windmill.dev"
|
||||
@@ -16,7 +16,7 @@ include = ["wmill/py.typed"]
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.7"
|
||||
httpx = ">=0.24"
|
||||
httpx = "^0.24"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry>=1.0.2", "poetry-dynamic-versioning"]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[tool.poetry]
|
||||
name = "wmill-pg"
|
||||
version = "1.383.0"
|
||||
version = "1.381.0"
|
||||
description = "An extension client for the wmill client library focused on pg"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://windmill.dev"
|
||||
|
||||
@@ -134,7 +134,7 @@ export async function runFlow(
|
||||
console.info(`running \`${path}\` synchronously with args:`, args);
|
||||
}
|
||||
|
||||
const jobId = await runFlowAsync(path, args, null, false);
|
||||
const jobId = await runFlowAsync(path, args);
|
||||
return await waitJob(jobId, verbose);
|
||||
}
|
||||
|
||||
@@ -272,8 +272,7 @@ export async function runScriptAsync(
|
||||
export async function runFlowAsync(
|
||||
path: string | null,
|
||||
args: Record<string, any> | null,
|
||||
scheduledInSeconds: number | null = null,
|
||||
flowOutlivesParent: boolean = true
|
||||
scheduledInSeconds: number | null = null
|
||||
): Promise<string> {
|
||||
// Create a script job and return its job id.
|
||||
|
||||
@@ -284,11 +283,9 @@ export async function runFlowAsync(
|
||||
params["scheduled_in_secs"] = scheduledInSeconds;
|
||||
}
|
||||
|
||||
if (!flowOutlivesParent) {
|
||||
let parentJobId = getEnv("WM_JOB_ID");
|
||||
if (parentJobId !== undefined) {
|
||||
params["parent_job"] = parentJobId;
|
||||
}
|
||||
let parentJobId = getEnv("WM_JOB_ID");
|
||||
if (parentJobId !== undefined) {
|
||||
params["parent_job"] = parentJobId;
|
||||
}
|
||||
|
||||
let rootJobId = getEnv("WM_ROOT_FLOW_JOB_ID");
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@windmill/windmill",
|
||||
"version": "1.383.0",
|
||||
"version": "1.381.0",
|
||||
"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.383.0",
|
||||
"version": "1.381.0",
|
||||
"author": "Ruben Fiszel",
|
||||
"license": "Apache 2.0",
|
||||
"devDependencies": {
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
1.383.0
|
||||
1.381.0
|
||||
|
||||
Reference in New Issue
Block a user