mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-05 00:03:08 +00:00
Merge branch 'main' into alp/docker_non_root
This commit is contained in:
@@ -1,5 +1,12 @@
|
||||
# Changelog
|
||||
|
||||
## [1.441.0](https://github.com/windmill-labs/windmill/compare/v1.440.3...v1.441.0) (2024-12-20)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* interactive slack approvals ([#4942](https://github.com/windmill-labs/windmill/issues/4942)) ([6308bf0](https://github.com/windmill-labs/windmill/commit/6308bf0dcb1d6670e839a1a1e0b794bf3ce6520c))
|
||||
|
||||
## [1.440.3](https://github.com/windmill-labs/windmill/compare/v1.440.2...v1.440.3) (2024-12-19)
|
||||
|
||||
|
||||
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT\n queue.job_kind AS \"job_kind: JobKind\",\n queue.script_hash AS \"script_hash: ScriptHash\",\n queue.raw_flow AS \"raw_flow: sqlx::types::Json<Box<RawValue>>\",\n completed_job.parent_job AS \"parent_job: Uuid\"\n FROM queue\n JOIN completed_job ON completed_job.parent_job = queue.id\n WHERE completed_job.id = $1 AND completed_job.workspace_id = $2\n LIMIT 1",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "job_kind: JobKind",
|
||||
"type_info": {
|
||||
"Custom": {
|
||||
"name": "job_kind",
|
||||
"kind": {
|
||||
"Enum": [
|
||||
"script",
|
||||
"preview",
|
||||
"flow",
|
||||
"dependencies",
|
||||
"flowpreview",
|
||||
"script_hub",
|
||||
"identity",
|
||||
"flowdependencies",
|
||||
"http",
|
||||
"graphql",
|
||||
"postgresql",
|
||||
"noop",
|
||||
"appdependencies",
|
||||
"deploymentcallback",
|
||||
"singlescriptflow",
|
||||
"flowscript",
|
||||
"flownode",
|
||||
"appscript"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "script_hash: ScriptHash",
|
||||
"type_info": "Int8"
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "raw_flow: sqlx::types::Json<Box<RawValue>>",
|
||||
"type_info": "Jsonb"
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "parent_job: Uuid",
|
||||
"type_info": "Uuid"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Uuid",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "bb6141ad0e93986b38ccdf4d027c486137d4fe79906e22842b711f4a9379b8c8"
|
||||
}
|
||||
Generated
+41
-41
@@ -1400,18 +1400,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck"
|
||||
version = "1.20.0"
|
||||
version = "1.21.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b37c88a63ffd85d15b406896cc343916d7cf57838a847b3a6f2ca5d39a5695a"
|
||||
checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3"
|
||||
dependencies = [
|
||||
"bytemuck_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck_derive"
|
||||
version = "1.8.0"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bcfcc3cd946cb52f0bbfdbbcfa2f4e24f75ebb6c0e1002f7c25904fada18b9ec"
|
||||
checksum = "3fa76293b4f7bb636ab88fd78228235b5248b4d05cc589aed610f954af5d7c7a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -1530,9 +1530,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.4"
|
||||
version = "1.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9157bbaa6b165880c27a4293a474c91cdcf265cc68cc829bf10be0964a391caf"
|
||||
checksum = "c31a0499c1dc64f458ad13872de75c0eb7e3fdb0e67964610c914b034fc5956e"
|
||||
dependencies = [
|
||||
"jobserver",
|
||||
"libc",
|
||||
@@ -2585,7 +2585,7 @@ dependencies = [
|
||||
"http 1.2.0",
|
||||
"http-body-util",
|
||||
"hyper 1.5.2",
|
||||
"hyper-rustls 0.27.4",
|
||||
"hyper-rustls 0.27.5",
|
||||
"hyper-util",
|
||||
"ipnet",
|
||||
"percent-encoding",
|
||||
@@ -3310,9 +3310,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "foldhash"
|
||||
version = "0.1.3"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2"
|
||||
checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f"
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types"
|
||||
@@ -4270,9 +4270,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hyper-rustls"
|
||||
version = "0.27.4"
|
||||
version = "0.27.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6884a48c6826ec44f524c7456b163cebe9e55a18d7b5e307cb4f100371cc767"
|
||||
checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2"
|
||||
dependencies = [
|
||||
"futures-util",
|
||||
"http 1.2.0",
|
||||
@@ -4824,9 +4824,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.168"
|
||||
version = "0.2.169"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d"
|
||||
checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
|
||||
|
||||
[[package]]
|
||||
name = "libgit2-sys"
|
||||
@@ -6976,7 +6976,7 @@ dependencies = [
|
||||
"http-body 1.0.1",
|
||||
"http-body-util",
|
||||
"hyper 1.5.2",
|
||||
"hyper-rustls 0.27.4",
|
||||
"hyper-rustls 0.27.5",
|
||||
"hyper-tls 0.6.0",
|
||||
"hyper-util",
|
||||
"ipnet",
|
||||
@@ -9359,9 +9359,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "1.8.0"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938"
|
||||
checksum = "022db8904dfa342efe721985167e9fcd16c29b226db4397ed752a761cfce81e8"
|
||||
dependencies = [
|
||||
"tinyvec_macros",
|
||||
]
|
||||
@@ -10657,7 +10657,7 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windmill"
|
||||
version = "1.440.3"
|
||||
version = "1.441.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"axum",
|
||||
@@ -10698,7 +10698,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-api"
|
||||
version = "1.440.3"
|
||||
version = "1.441.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"argon2",
|
||||
@@ -10783,7 +10783,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-api-client"
|
||||
version = "1.440.3"
|
||||
version = "1.441.0"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"chrono",
|
||||
@@ -10801,7 +10801,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-audit"
|
||||
version = "1.440.3"
|
||||
version = "1.441.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"serde",
|
||||
@@ -10814,7 +10814,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-autoscaling"
|
||||
version = "1.440.3"
|
||||
version = "1.441.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"serde",
|
||||
@@ -10828,7 +10828,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-common"
|
||||
version = "1.440.3"
|
||||
version = "1.441.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-stream",
|
||||
@@ -10887,7 +10887,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-git-sync"
|
||||
version = "1.440.3"
|
||||
version = "1.441.0"
|
||||
dependencies = [
|
||||
"regex",
|
||||
"serde",
|
||||
@@ -10901,7 +10901,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-indexer"
|
||||
version = "1.440.3"
|
||||
version = "1.441.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@@ -10924,7 +10924,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-macros"
|
||||
version = "1.440.3"
|
||||
version = "1.441.0"
|
||||
dependencies = [
|
||||
"itertools 0.13.0",
|
||||
"lazy_static",
|
||||
@@ -10936,7 +10936,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser"
|
||||
version = "1.440.3"
|
||||
version = "1.441.0"
|
||||
dependencies = [
|
||||
"convert_case 0.6.0",
|
||||
"serde",
|
||||
@@ -10945,7 +10945,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-bash"
|
||||
version = "1.440.3"
|
||||
version = "1.441.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"lazy_static",
|
||||
@@ -10957,7 +10957,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-csharp"
|
||||
version = "1.440.3"
|
||||
version = "1.441.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"serde_json",
|
||||
@@ -10969,7 +10969,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-go"
|
||||
version = "1.440.3"
|
||||
version = "1.441.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"gosyn",
|
||||
@@ -10981,7 +10981,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-graphql"
|
||||
version = "1.440.3"
|
||||
version = "1.441.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"lazy_static",
|
||||
@@ -10993,7 +10993,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-php"
|
||||
version = "1.440.3"
|
||||
version = "1.441.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"itertools 0.13.0",
|
||||
@@ -11004,7 +11004,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-py"
|
||||
version = "1.440.3"
|
||||
version = "1.441.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"itertools 0.13.0",
|
||||
@@ -11015,7 +11015,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-py-imports"
|
||||
version = "1.440.3"
|
||||
version = "1.441.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-recursion",
|
||||
@@ -11033,7 +11033,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-rust"
|
||||
version = "1.440.3"
|
||||
version = "1.441.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"convert_case 0.6.0",
|
||||
@@ -11050,7 +11050,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-sql"
|
||||
version = "1.440.3"
|
||||
version = "1.441.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"lazy_static",
|
||||
@@ -11062,7 +11062,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-ts"
|
||||
version = "1.440.3"
|
||||
version = "1.441.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"lazy_static",
|
||||
@@ -11080,7 +11080,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-wasm"
|
||||
version = "1.440.3"
|
||||
version = "1.441.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"getrandom 0.2.15",
|
||||
@@ -11102,7 +11102,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-yaml"
|
||||
version = "1.440.3"
|
||||
version = "1.441.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"serde_json",
|
||||
@@ -11112,7 +11112,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-queue"
|
||||
version = "1.440.3"
|
||||
version = "1.441.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-recursion",
|
||||
@@ -11146,7 +11146,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-sql-datatype-parser-wasm"
|
||||
version = "1.440.3"
|
||||
version = "1.441.0"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-test",
|
||||
@@ -11156,7 +11156,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-worker"
|
||||
version = "1.440.3"
|
||||
version = "1.441.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-recursion",
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "windmill"
|
||||
version = "1.440.3"
|
||||
version = "1.441.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
@@ -30,7 +30,7 @@ members = [
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
version = "1.440.3"
|
||||
version = "1.441.0"
|
||||
authors = ["Ruben Fiszel <ruben@windmill.dev>"]
|
||||
edition = "2021"
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
openapi: "3.0.3"
|
||||
|
||||
info:
|
||||
version: 1.440.3
|
||||
version: 1.441.0
|
||||
title: Windmill API
|
||||
|
||||
contact:
|
||||
@@ -6943,6 +6943,42 @@ paths:
|
||||
- resume
|
||||
- cancel
|
||||
|
||||
/w/{workspace}/jobs/slack_approval/{id}:
|
||||
get:
|
||||
summary: generate interactive slack approval for suspended job
|
||||
operationId: getSlackApprovalPayload
|
||||
tags:
|
||||
- job
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/WorkspaceId"
|
||||
- $ref: "#/components/parameters/JobId"
|
||||
- name: approver
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
- name: message
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
- name: slack_resource_path
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
- name: channel_id
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
- name: flow_step_id
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
description: Interactive slack approval message sent successfully
|
||||
|
||||
/w/{workspace}/jobs_u/resume/{id}/{resume_id}/{signature}:
|
||||
get:
|
||||
summary: resume a job for a suspended flow
|
||||
|
||||
@@ -2160,7 +2160,7 @@ pub struct SuspendedJobFlow {
|
||||
pub approvers: Vec<Approval>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct QueryApprover {
|
||||
pub approver: Option<String>,
|
||||
}
|
||||
@@ -2373,11 +2373,11 @@ fn create_signature(
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[derive(Serialize)]
|
||||
#[derive(Serialize, Debug)]
|
||||
pub struct ResumeUrls {
|
||||
approvalPage: String,
|
||||
cancel: String,
|
||||
resume: String,
|
||||
pub approvalPage: String,
|
||||
pub cancel: String,
|
||||
pub resume: String,
|
||||
}
|
||||
|
||||
fn build_resume_url(
|
||||
@@ -2397,6 +2397,14 @@ pub async fn get_resume_urls(
|
||||
Extension(db): Extension<DB>,
|
||||
Path((w_id, job_id, resume_id)): Path<(String, Uuid, u32)>,
|
||||
Query(approver): Query<QueryApprover>,
|
||||
) -> error::JsonResult<ResumeUrls> {
|
||||
get_resume_urls_internal(Extension(db), Path((w_id, job_id, resume_id)), Query(approver)).await
|
||||
}
|
||||
|
||||
pub async fn get_resume_urls_internal(
|
||||
Extension(db): Extension<DB>,
|
||||
Path((w_id, job_id, resume_id)): Path<(String, Uuid, u32)>,
|
||||
Query(approver): Query<QueryApprover>,
|
||||
) -> error::JsonResult<ResumeUrls> {
|
||||
let key = get_workspace_key(&w_id, &db).await?;
|
||||
let signature = create_signature(key, job_id, resume_id, approver.approver.clone())?;
|
||||
@@ -5561,3 +5569,4 @@ async fn delete_completed_job<'a>(
|
||||
let response = Json(cj).into_response();
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ use crate::{
|
||||
use anyhow::Context;
|
||||
use argon2::Argon2;
|
||||
use axum::extract::DefaultBodyLimit;
|
||||
use axum::{middleware::from_extractor, routing::get, Extension, Router};
|
||||
use axum::{middleware::from_extractor, routing::get, routing::post, Extension, Router};
|
||||
use db::DB;
|
||||
use http::HeaderValue;
|
||||
use reqwest::Client;
|
||||
@@ -109,6 +109,7 @@ mod websocket_triggers;
|
||||
mod workers;
|
||||
mod workspaces;
|
||||
mod workspaces_ee;
|
||||
mod slack_approvals;
|
||||
mod workspaces_export;
|
||||
mod workspaces_extra;
|
||||
|
||||
@@ -415,6 +416,8 @@ pub async fn run_server(
|
||||
"/w/:workspace_id/jobs_u",
|
||||
jobs::workspace_unauthed_service().layer(cors.clone()),
|
||||
)
|
||||
.route("/slack", post(slack_approvals::slack_app_callback_handler))
|
||||
.route("/w/:workspace_id/jobs/slack_approval/:job_id", get(slack_approvals::request_slack_approval))
|
||||
.nest(
|
||||
"/w/:workspace_id/resources_u",
|
||||
resources::public_service().layer(cors.clone()),
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,6 +2,7 @@ use std::collections::HashMap;
|
||||
|
||||
use futures::future::BoxFuture;
|
||||
use futures::{FutureExt, TryFutureExt};
|
||||
use reqwest::Client;
|
||||
use serde_json::{json, value::RawValue, Value};
|
||||
use windmill_common::error::to_anyhow;
|
||||
use windmill_common::jobs::QueuedJob;
|
||||
@@ -9,11 +10,11 @@ use windmill_common::{error::Error, worker::to_raw_value};
|
||||
use windmill_parser_sql::{
|
||||
parse_bigquery_sig, parse_db_resource, parse_sql_blocks, parse_sql_statement_named_params,
|
||||
};
|
||||
use windmill_queue::{CanceledBy, HTTP_CLIENT};
|
||||
use windmill_queue::CanceledBy;
|
||||
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::common::OccupancyMetrics;
|
||||
use crate::common::{build_http_client, OccupancyMetrics};
|
||||
use crate::handle_child::run_future_with_polling_update_job_poller;
|
||||
use crate::{
|
||||
common::{build_args_values, resolve_job_timeout},
|
||||
@@ -68,9 +69,10 @@ fn do_bigquery_inner<'a>(
|
||||
all_statement_values: &'a HashMap<String, Value>,
|
||||
project_id: &'a str,
|
||||
token: &'a str,
|
||||
timeout_ms: i32,
|
||||
timeout_ms: u64,
|
||||
column_order: Option<&'a mut Option<Vec<String>>>,
|
||||
skip_collect: bool,
|
||||
http_client: &'a Client,
|
||||
) -> windmill_common::error::Result<BoxFuture<'a, windmill_common::error::Result<Box<RawValue>>>> {
|
||||
let param_names = parse_sql_statement_named_params(query, '@');
|
||||
|
||||
@@ -86,7 +88,7 @@ fn do_bigquery_inner<'a>(
|
||||
.collect::<Vec<&Value>>();
|
||||
|
||||
let result_f = async move {
|
||||
let response = HTTP_CLIENT
|
||||
let response = http_client
|
||||
.post(
|
||||
"https://bigquery.googleapis.com/bigquery/v2/projects/".to_string()
|
||||
+ project_id
|
||||
@@ -249,13 +251,10 @@ pub async fn do_bigquery(
|
||||
.await
|
||||
.map_err(|e| Error::ExecutionErr(e.to_string()))?;
|
||||
|
||||
let timeout_ms = i32::try_from(
|
||||
resolve_job_timeout(&db, &job.workspace_id, job.id, job.timeout)
|
||||
.await
|
||||
.0
|
||||
.as_millis(),
|
||||
)
|
||||
.unwrap_or(200000);
|
||||
let (timeout_duration, _, _) =
|
||||
resolve_job_timeout(&db, &job.workspace_id, job.id, job.timeout).await;
|
||||
let timeout_ms = timeout_duration.as_millis() as u64;
|
||||
let http_client = build_http_client(timeout_duration)?;
|
||||
|
||||
let project_id = authentication_manager
|
||||
.project_id()
|
||||
@@ -325,6 +324,7 @@ pub async fn do_bigquery(
|
||||
timeout_ms,
|
||||
None,
|
||||
annotations.return_last_result && i < queries.len() - 1,
|
||||
&http_client,
|
||||
)
|
||||
})
|
||||
.collect::<windmill_common::error::Result<Vec<_>>>()?;
|
||||
@@ -353,6 +353,7 @@ pub async fn do_bigquery(
|
||||
timeout_ms,
|
||||
Some(column_order),
|
||||
false,
|
||||
&http_client,
|
||||
)?
|
||||
};
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ use async_recursion::async_recursion;
|
||||
use itertools::Itertools;
|
||||
use lazy_static::lazy_static;
|
||||
use regex::Regex;
|
||||
use reqwest::Client;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::value::RawValue;
|
||||
use serde_json::{json, Value};
|
||||
@@ -32,11 +33,7 @@ use windmill_common::{
|
||||
use anyhow::{anyhow, Result};
|
||||
|
||||
use std::path::Path;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
sync::Arc,
|
||||
time::Duration,
|
||||
};
|
||||
use std::{collections::HashMap, sync::Arc, time::Duration};
|
||||
|
||||
use uuid::Uuid;
|
||||
use windmill_common::{variables, DB};
|
||||
@@ -965,3 +962,12 @@ pub fn use_flow_root_path(flow_path: &str) -> String {
|
||||
return flow_path.to_string();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build_http_client(timeout_duration: std::time::Duration) -> error::Result<Client> {
|
||||
reqwest::ClientBuilder::new()
|
||||
.user_agent("windmill/beta")
|
||||
.timeout(timeout_duration)
|
||||
.connect_timeout(std::time::Duration::from_secs(10))
|
||||
.build()
|
||||
.map_err(|e| Error::InternalErr(format!("Error building http client: {e:#}")))
|
||||
}
|
||||
|
||||
@@ -8,11 +8,11 @@ use windmill_common::jobs::QueuedJob;
|
||||
use windmill_common::worker::to_raw_value;
|
||||
use windmill_common::{error::Error, worker::CLOUD_HOSTED};
|
||||
use windmill_parser_graphql::parse_graphql_sig;
|
||||
use windmill_queue::{CanceledBy, HTTP_CLIENT};
|
||||
use windmill_queue::CanceledBy;
|
||||
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::common::OccupancyMetrics;
|
||||
use crate::common::{build_http_client, resolve_job_timeout, OccupancyMetrics};
|
||||
use crate::handle_child::run_future_with_polling_update_job_poller;
|
||||
use crate::{common::build_args_map, AuthedClientBackgroundTask};
|
||||
|
||||
@@ -81,8 +81,12 @@ pub async fn do_graphql(
|
||||
}
|
||||
}
|
||||
}
|
||||
let (timeout_duration, _, _) =
|
||||
resolve_job_timeout(&db, &job.workspace_id, job.id, job.timeout).await;
|
||||
|
||||
let mut request = HTTP_CLIENT.post(api.base_url).json(&json!({
|
||||
let http_client = build_http_client(timeout_duration)?;
|
||||
|
||||
let mut request = http_client.post(api.base_url).json(&json!({
|
||||
"query": query,
|
||||
"variables": variables
|
||||
}));
|
||||
|
||||
@@ -332,6 +332,7 @@ pub async fn uv_pip_compile(
|
||||
.env_clear()
|
||||
.env("HOME", HOME_ENV.to_string())
|
||||
.env("PATH", PATH_ENV.to_string())
|
||||
.envs(PROXY_ENVS.clone())
|
||||
.args(&args)
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped());
|
||||
|
||||
@@ -4,7 +4,7 @@ use core::fmt::Write;
|
||||
use futures::future::BoxFuture;
|
||||
use futures::{FutureExt, TryFutureExt};
|
||||
use jsonwebtoken::{encode, Algorithm, EncodingKey, Header};
|
||||
use reqwest::Response;
|
||||
use reqwest::{Client, Response};
|
||||
use serde_json::{json, value::RawValue, Value};
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::collections::HashMap;
|
||||
@@ -17,7 +17,7 @@ use windmill_queue::{CanceledBy, HTTP_CLIENT};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::common::{resolve_job_timeout, OccupancyMetrics};
|
||||
use crate::common::{build_http_client, resolve_job_timeout, OccupancyMetrics};
|
||||
use crate::handle_child::run_future_with_polling_update_job_poller;
|
||||
use crate::{common::build_args_values, AuthedClientBackgroundTask};
|
||||
|
||||
@@ -122,6 +122,7 @@ fn do_snowflake_inner<'a>(
|
||||
token_is_keypair: bool,
|
||||
column_order: Option<&'a mut Option<Vec<String>>>,
|
||||
skip_collect: bool,
|
||||
http_client: &'a Client,
|
||||
) -> windmill_common::error::Result<BoxFuture<'a, windmill_common::error::Result<Box<RawValue>>>> {
|
||||
body.insert("statement".to_string(), json!(query));
|
||||
|
||||
@@ -145,7 +146,7 @@ fn do_snowflake_inner<'a>(
|
||||
}
|
||||
|
||||
let result_f = async move {
|
||||
let mut request = HTTP_CLIENT
|
||||
let mut request = http_client
|
||||
.post(format!(
|
||||
"https://{}.snowflakecomputing.com/api/v2/statements/",
|
||||
account_identifier.to_uppercase()
|
||||
@@ -365,6 +366,11 @@ pub async fn do_snowflake(
|
||||
|
||||
let queries = parse_sql_blocks(query);
|
||||
|
||||
let (timeout_duration, _, _) =
|
||||
resolve_job_timeout(&db, &job.workspace_id, job.id, job.timeout).await;
|
||||
|
||||
let http_client = build_http_client(timeout_duration)?;
|
||||
|
||||
let result_f = if queries.len() > 1 {
|
||||
let futures = queries
|
||||
.iter()
|
||||
@@ -379,6 +385,7 @@ pub async fn do_snowflake(
|
||||
token_is_keypair,
|
||||
None,
|
||||
annotations.return_last_result && i < queries.len() - 1,
|
||||
&http_client,
|
||||
)
|
||||
})
|
||||
.collect::<windmill_common::error::Result<Vec<_>>>()?;
|
||||
@@ -407,6 +414,7 @@ pub async fn do_snowflake(
|
||||
token_is_keypair,
|
||||
Some(column_order),
|
||||
false,
|
||||
&http_client,
|
||||
)?
|
||||
};
|
||||
let r = run_future_with_polling_update_job_poller(
|
||||
|
||||
+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.440.3";
|
||||
export const VERSION = "v1.441.0";
|
||||
|
||||
export async function login(email: string, password: string): Promise<string> {
|
||||
return await windmill.UserService.login({
|
||||
|
||||
+1
-1
@@ -60,7 +60,7 @@ export {
|
||||
// }
|
||||
// });
|
||||
|
||||
export const VERSION = "1.440.3";
|
||||
export const VERSION = "1.441.0";
|
||||
|
||||
const command = new Command()
|
||||
.name("wmill")
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "windmill-components",
|
||||
"version": "1.440.3",
|
||||
"version": "1.441.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "windmill-components",
|
||||
"version": "1.440.3",
|
||||
"version": "1.441.0",
|
||||
"license": "AGPL-3.0",
|
||||
"dependencies": {
|
||||
"@anthropic-ai/sdk": "^0.32.1",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "windmill-components",
|
||||
"version": "1.440.3",
|
||||
"version": "1.441.0",
|
||||
"scripts": {
|
||||
"dev": "vite dev",
|
||||
"build": "vite build",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { type Job } from '$lib/gen'
|
||||
import { isScriptPreview } from '$lib/utils'
|
||||
import { onDestroy } from 'svelte'
|
||||
|
||||
export let job: Job | undefined = undefined
|
||||
@@ -23,7 +24,7 @@
|
||||
!busy &&
|
||||
job &&
|
||||
'running' in job &&
|
||||
(job.job_kind == 'script' || job?.job_kind == 'preview')
|
||||
(job.job_kind == 'script' || isScriptPreview(job?.job_kind))
|
||||
)
|
||||
start(job)
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
import Tabs from './common/tabs/Tabs.svelte'
|
||||
import { type DurationStatus, type FlowStatusViewerContext, type GraphModuleState } from './graph'
|
||||
import ModuleStatus from './ModuleStatus.svelte'
|
||||
import { emptyString, msToSec, truncateRev } from '$lib/utils'
|
||||
import { emptyString, isScriptPreview, msToSec, truncateRev } from '$lib/utils'
|
||||
import JobArgs from './JobArgs.svelte'
|
||||
import { ChevronDown, Hourglass, Loader2 } from 'lucide-svelte'
|
||||
import FlowStatusWaitingForEvents from './FlowStatusWaitingForEvents.svelte'
|
||||
@@ -728,11 +728,7 @@
|
||||
})
|
||||
}
|
||||
|
||||
if (
|
||||
jobLoaded.job_kind == 'script' ||
|
||||
jobLoaded.job_kind == 'flowscript' ||
|
||||
jobLoaded.job_kind == 'preview'
|
||||
) {
|
||||
if (jobLoaded.job_kind == 'script' || isScriptPreview(jobLoaded.job_kind)) {
|
||||
let id: string | undefined = undefined
|
||||
if (
|
||||
(innerModule?.type == 'forloopflow' || innerModule?.type == 'whileloopflow') &&
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import type { SupportedLanguage } from '$lib/common'
|
||||
import { sendUserToast } from '$lib/toast'
|
||||
import { isScriptPreview } from '$lib/utils'
|
||||
|
||||
export let isLoading = false
|
||||
export let job: Job | undefined = undefined
|
||||
@@ -192,7 +193,7 @@
|
||||
let getProgress: boolean | undefined = undefined
|
||||
// We only pull individual job progress this way
|
||||
// Flow's progress we are getting from FlowStatusModule of flow job
|
||||
if (job.job_kind == 'script' || job.job_kind == 'preview') {
|
||||
if (job.job_kind == 'script' || isScriptPreview(job.job_kind)) {
|
||||
// First time, before running job, lastTimeCheckedProgress is always undefined
|
||||
if (lastTimeCheckedProgress) {
|
||||
const lastTimeCheckedMs = Date.now() - lastTimeCheckedProgress
|
||||
|
||||
@@ -30,10 +30,10 @@
|
||||
|
||||
import ItemPicker from '$lib/components/ItemPicker.svelte'
|
||||
import VariableEditor from '$lib/components/VariableEditor.svelte'
|
||||
import { VariableService, type Job, type Policy } from '$lib/gen'
|
||||
import { VariableService, type Policy } from '$lib/gen'
|
||||
import { initHistory } from '$lib/history'
|
||||
import { Component, Minus, Paintbrush, Plus, Smartphone, Scan, Hand, Grab } from 'lucide-svelte'
|
||||
import { findGridItem, findGridItemParentGrid } from './appUtils'
|
||||
import { animateTo, findGridItem, findGridItemParentGrid } from './appUtils'
|
||||
import ComponentNavigation from './component/ComponentNavigation.svelte'
|
||||
import CssSettings from './componentsPanel/CssSettings.svelte'
|
||||
import SettingsPanel from './SettingsPanel.svelte'
|
||||
@@ -49,7 +49,6 @@
|
||||
import { getTheme } from './componentsPanel/themeUtils'
|
||||
import StylePanel from './settingsPanel/StylePanel.svelte'
|
||||
import type DiffDrawer from '$lib/components/DiffDrawer.svelte'
|
||||
import RunnableJobPanel from './RunnableJobPanel.svelte'
|
||||
import HideButton from './settingsPanel/HideButton.svelte'
|
||||
import AppEditorBottomPanel from './AppEditorBottomPanel.svelte'
|
||||
import panzoom from 'panzoom'
|
||||
@@ -386,27 +385,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
function animateTo(start: number, end: number, onUpdate: (newValue: number) => void) {
|
||||
const duration = 400
|
||||
const startTime = performance.now()
|
||||
|
||||
function animate(time: number) {
|
||||
const elapsed = time - startTime
|
||||
const progress = Math.min(elapsed / duration, 1)
|
||||
const currentValue = start + (end - start) * easeInOut(progress)
|
||||
onUpdate(currentValue)
|
||||
if (progress < 1) {
|
||||
requestAnimationFrame(animate)
|
||||
}
|
||||
}
|
||||
|
||||
requestAnimationFrame(animate)
|
||||
}
|
||||
|
||||
function easeInOut(t: number) {
|
||||
return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t
|
||||
}
|
||||
|
||||
$: $cssEditorOpen && selectCss()
|
||||
|
||||
function selectCss() {
|
||||
@@ -583,13 +561,11 @@
|
||||
} else {
|
||||
leftPanelSize = storedLeftPanelSize
|
||||
}
|
||||
storedLeftPanelSize = 0
|
||||
}
|
||||
|
||||
function showRightPanel() {
|
||||
rightPanelSize = storedRightPanelSize
|
||||
centerPanelSize = centerPanelSize - storedRightPanelSize
|
||||
storedRightPanelSize = 0
|
||||
}
|
||||
|
||||
function showBottomPanel(animate: boolean = false) {
|
||||
@@ -611,7 +587,6 @@
|
||||
runnablePanelSize = storedBottomPanelSize
|
||||
gridPanelSize = gridPanelSize - storedBottomPanelSize
|
||||
}
|
||||
storedBottomPanelSize = 0
|
||||
}
|
||||
|
||||
function keydown(event: KeyboardEvent) {
|
||||
@@ -705,9 +680,6 @@
|
||||
|
||||
$: $connectingInput.opened, updatePannelInConnecting()
|
||||
|
||||
let testJob: Job | undefined = undefined
|
||||
let jobToWatch: { componentId: string; job: string } | undefined = undefined
|
||||
|
||||
$: updateCursorStyle(!!$connectingInput.opened && !$panzoomActive)
|
||||
|
||||
function updateCursorStyle(disabled: boolean) {
|
||||
@@ -1125,14 +1097,7 @@
|
||||
{rightPanelSize}
|
||||
{centerPanelWidth}
|
||||
{runnablePanelSize}
|
||||
>
|
||||
<RunnableJobPanel
|
||||
float={rightPanelSize !== 0}
|
||||
hidden={runnablePanelSize === 0}
|
||||
bind:testJob
|
||||
bind:jobToWatch
|
||||
/>
|
||||
</AppEditorBottomPanel>
|
||||
/>
|
||||
</Pane>
|
||||
{/if}
|
||||
</Splitpanes>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<script lang="ts">
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import InlineScriptsPanel from './inlineScriptsPanel/InlineScriptsPanel.svelte'
|
||||
import RunnableJobPanel from './RunnableJobPanel.svelte'
|
||||
|
||||
@@ -10,15 +9,13 @@
|
||||
|
||||
{#if rightPanelSize !== 0}
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div class={twMerge('relative h-full w-full overflow-x-visible')} on:mouseenter on:mouseleave>
|
||||
<div class="relative h-full w-full overflow-x-visible" on:mouseenter on:mouseleave>
|
||||
<InlineScriptsPanel on:hidePanel />
|
||||
<RunnableJobPanel hidden={runnablePanelSize === 0} />
|
||||
<slot />
|
||||
</div>
|
||||
{:else}
|
||||
<div class="flex flex-row relative w-full h-full">
|
||||
<InlineScriptsPanel width={centerPanelWidth - 400} on:hidePanel />
|
||||
|
||||
<slot />
|
||||
<InlineScriptsPanel width={centerPanelWidth * 0.66} on:hidePanel />
|
||||
<RunnableJobPanel float={false} hidden={runnablePanelSize === 0} />
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -41,7 +41,8 @@
|
||||
truncateRev,
|
||||
orderedJsonStringify,
|
||||
type Value,
|
||||
replaceFalseWithUndefined
|
||||
replaceFalseWithUndefined,
|
||||
isFlowPreview
|
||||
} from '../../../utils'
|
||||
import type {
|
||||
AppInput,
|
||||
@@ -1404,7 +1405,7 @@
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if job?.job_kind !== 'flow' && job?.job_kind !== 'flowpreview'}
|
||||
{#if job?.job_kind !== 'flow' && !isFlowPreview(job?.job_kind)}
|
||||
{@const jobResult = $jobsById[selectedJobId]}
|
||||
<Splitpanes horizontal class="grow border w-full">
|
||||
<Pane size={50} minSize={10}>
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
export let hidden: boolean = false
|
||||
export let testJob: Job | undefined = undefined
|
||||
export let jobToWatch: { componentId: string; job: string } | undefined = undefined
|
||||
export let width: number | undefined = undefined
|
||||
|
||||
const { runnableJobEditorPanel, selectedComponentInEditor } =
|
||||
getContext<AppEditorContext>('AppEditorContext')
|
||||
@@ -16,7 +17,7 @@
|
||||
|
||||
let testJobLoader: TestJobLoader
|
||||
|
||||
$: $runnableJobEditorPanel.focused &&
|
||||
$: ($runnableJobEditorPanel.focused || !float) &&
|
||||
$selectedComponentInEditor &&
|
||||
$runnableJobEditorPanel.jobs &&
|
||||
updateSelectedJob()
|
||||
@@ -59,7 +60,10 @@
|
||||
<RunnableJobPanelInner {testIsLoading} {frontendJob} {testJob} />
|
||||
</div>
|
||||
{:else}
|
||||
<div class="flex flex-col w-full">
|
||||
<div
|
||||
class="flex flex-col min-w-0 grow h-full"
|
||||
style={width !== undefined ? `width:${width}px;` : ''}
|
||||
>
|
||||
{#if $selectedComponentInEditor}
|
||||
<RunnableJobPanelInner {testIsLoading} {frontendJob} {testJob} />
|
||||
{:else if !hidden}
|
||||
|
||||
@@ -1281,3 +1281,24 @@ export function areShadowsTheSame(
|
||||
shadow1.h === shadow2.h
|
||||
)
|
||||
}
|
||||
|
||||
export function animateTo(start: number, end: number, onUpdate: (newValue: number) => void) {
|
||||
const duration = 400
|
||||
const startTime = performance.now()
|
||||
|
||||
function animate(time: number) {
|
||||
const elapsed = time - startTime
|
||||
const progress = Math.min(elapsed / duration, 1)
|
||||
const currentValue = start + (end - start) * easeInOut(progress)
|
||||
onUpdate(currentValue)
|
||||
if (progress < 1) {
|
||||
requestAnimationFrame(animate)
|
||||
}
|
||||
}
|
||||
|
||||
requestAnimationFrame(animate)
|
||||
}
|
||||
|
||||
function easeInOut(t: number) {
|
||||
return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t
|
||||
}
|
||||
|
||||
+53
-56
@@ -1,7 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { getContext } from 'svelte'
|
||||
import type { AppEditorContext, AppViewerContext, HiddenRunnable } from '../../types'
|
||||
import SplitPanesWrapper from '$lib/components/splitPanes/SplitPanesWrapper.svelte'
|
||||
import { Pane, Splitpanes } from 'svelte-splitpanes'
|
||||
import InlineScriptsPanelList from './InlineScriptsPanelList.svelte'
|
||||
import InlineScriptEditor from './InlineScriptEditor.svelte'
|
||||
@@ -105,60 +104,58 @@
|
||||
export let width: number | undefined = undefined
|
||||
</script>
|
||||
|
||||
<SplitPanesWrapper>
|
||||
<Splitpanes
|
||||
class={twMerge('!overflow-visible')}
|
||||
style={width !== undefined ? `width:${width}px;` : ''}
|
||||
>
|
||||
<Pane size={25}>
|
||||
<InlineScriptsPanelList on:hidePanel />
|
||||
</Pane>
|
||||
<Pane size={75}>
|
||||
{#if !$selectedComponentInEditor}
|
||||
<div class="text-sm text-secondary text-center py-8 px-2">
|
||||
Select a script on the left panel
|
||||
</div>
|
||||
{:else if gridItem}
|
||||
{#key gridItem?.id}
|
||||
<InlineScriptsPanelWithTable
|
||||
<Splitpanes
|
||||
class={twMerge('!overflow-visible')}
|
||||
style={width !== undefined ? `width:${width}px;` : 'width: 100%;'}
|
||||
>
|
||||
<Pane size={25}>
|
||||
<InlineScriptsPanelList on:hidePanel />
|
||||
</Pane>
|
||||
<Pane size={75}>
|
||||
{#if !$selectedComponentInEditor}
|
||||
<div class="text-sm text-secondary text-center py-8 px-2">
|
||||
Select a script on the left panel
|
||||
</div>
|
||||
{:else if gridItem}
|
||||
{#key gridItem?.id}
|
||||
<InlineScriptsPanelWithTable
|
||||
on:createScriptFromInlineScript={(e) => {
|
||||
createScriptFromInlineScript(gridItem?.id ?? 'unknown', e.detail)
|
||||
}}
|
||||
bind:gridItem
|
||||
/>
|
||||
{/key}
|
||||
{:else if unusedInlineScript > -1 && $app.unusedInlineScripts?.[unusedInlineScript]}
|
||||
{#key unusedInlineScript}
|
||||
<InlineScriptEditor
|
||||
on:createScriptFromInlineScript={() =>
|
||||
sendUserToast('Cannot save to workspace unused scripts', true)}
|
||||
id={`unused-${unusedInlineScript}`}
|
||||
bind:name={$app.unusedInlineScripts[unusedInlineScript].name}
|
||||
bind:inlineScript={$app.unusedInlineScripts[unusedInlineScript].inlineScript}
|
||||
on:delete={() => {
|
||||
// remove the script from the array at the index
|
||||
$app.unusedInlineScripts.splice(unusedInlineScript, 1)
|
||||
$app.unusedInlineScripts = [...$app.unusedInlineScripts]
|
||||
}}
|
||||
/>
|
||||
{/key}
|
||||
{:else if hiddenInlineScript > -1}
|
||||
{#key hiddenInlineScript}
|
||||
{#if $app.hiddenInlineScripts?.[hiddenInlineScript]}
|
||||
<InlineScriptHiddenRunnable
|
||||
on:createScriptFromInlineScript={(e) => {
|
||||
createScriptFromInlineScript(gridItem?.id ?? 'unknown', e.detail)
|
||||
createScriptFromInlineScript(BG_PREFIX + hiddenInlineScript, e.detail)
|
||||
}}
|
||||
bind:gridItem
|
||||
/>
|
||||
{/key}
|
||||
{:else if unusedInlineScript > -1 && $app.unusedInlineScripts?.[unusedInlineScript]}
|
||||
{#key unusedInlineScript}
|
||||
<InlineScriptEditor
|
||||
on:createScriptFromInlineScript={() =>
|
||||
sendUserToast('Cannot save to workspace unused scripts', true)}
|
||||
id={`unused-${unusedInlineScript}`}
|
||||
bind:name={$app.unusedInlineScripts[unusedInlineScript].name}
|
||||
bind:inlineScript={$app.unusedInlineScripts[unusedInlineScript].inlineScript}
|
||||
on:delete={() => {
|
||||
// remove the script from the array at the index
|
||||
$app.unusedInlineScripts.splice(unusedInlineScript, 1)
|
||||
$app.unusedInlineScripts = [...$app.unusedInlineScripts]
|
||||
}}
|
||||
/>
|
||||
{/key}
|
||||
{:else if hiddenInlineScript > -1}
|
||||
{#key hiddenInlineScript}
|
||||
{#if $app.hiddenInlineScripts?.[hiddenInlineScript]}
|
||||
<InlineScriptHiddenRunnable
|
||||
on:createScriptFromInlineScript={(e) => {
|
||||
createScriptFromInlineScript(BG_PREFIX + hiddenInlineScript, e.detail)
|
||||
}}
|
||||
transformer={$selectedComponentInEditor?.endsWith('_transformer')}
|
||||
on:delete={() => deleteBackgroundScript(hiddenInlineScript)}
|
||||
id={BG_PREFIX + hiddenInlineScript}
|
||||
bind:runnable={$app.hiddenInlineScripts[hiddenInlineScript]}
|
||||
/>{/if}{/key}
|
||||
{:else}
|
||||
<div class="text-sm text-tertiary text-center py-8 px-2">
|
||||
No script found at id {$selectedComponentInEditor}
|
||||
</div>
|
||||
{/if}
|
||||
</Pane>
|
||||
</Splitpanes>
|
||||
</SplitPanesWrapper>
|
||||
transformer={$selectedComponentInEditor?.endsWith('_transformer')}
|
||||
on:delete={() => deleteBackgroundScript(hiddenInlineScript)}
|
||||
id={BG_PREFIX + hiddenInlineScript}
|
||||
bind:runnable={$app.hiddenInlineScripts[hiddenInlineScript]}
|
||||
/>{/if}{/key}
|
||||
{:else}
|
||||
<div class="text-sm text-tertiary text-center py-8 px-2">
|
||||
No script found at id {$selectedComponentInEditor}
|
||||
</div>
|
||||
{/if}
|
||||
</Pane>
|
||||
</Splitpanes>
|
||||
|
||||
+18
-11
@@ -18,13 +18,18 @@
|
||||
export let defaultUserInput = false
|
||||
export let hideCreateScript = false
|
||||
export let onlyFlow = false
|
||||
|
||||
let tab: Tab = onlyFlow ? 'workspaceflows' : 'inlinescripts'
|
||||
let filter: string = ''
|
||||
let picker: Drawer
|
||||
export let rawApps = false
|
||||
|
||||
const { app, workspace } = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
let tab: Tab = onlyFlow
|
||||
? 'workspaceflows'
|
||||
: $app?.unusedInlineScripts?.length > 0
|
||||
? 'inlinescripts'
|
||||
: 'workspacescripts'
|
||||
let filter: string = ''
|
||||
let picker: Drawer
|
||||
|
||||
const dispatch = createEventDispatcher<{
|
||||
pick: {
|
||||
runnable: Runnable
|
||||
@@ -138,15 +143,17 @@
|
||||
<div class="max-w-6xl">
|
||||
<Tabs bind:selected={tab}>
|
||||
{#if !onlyFlow}
|
||||
<Tab size="sm" value="inlinescripts">
|
||||
<div class="flex gap-2 items-center my-1">
|
||||
<Building size={18} strokeWidth={1.5} />
|
||||
Detached Inline Scripts
|
||||
</div>
|
||||
</Tab>
|
||||
{#if !rawApps}
|
||||
<Tab size="sm" value="inlinescripts">
|
||||
<div class="flex gap-2 items-center my-1">
|
||||
<Building size={18} strokeWidth={1.5} />
|
||||
Detached Inline Scripts
|
||||
</div>
|
||||
</Tab>
|
||||
{/if}
|
||||
<Tab size="sm" value="workspacescripts">
|
||||
<div class="flex gap-2 items-center my-1">
|
||||
<Building size={18} strokeWidth={1.5}/>
|
||||
<Building size={18} strokeWidth={1.5} />
|
||||
Workspace Scripts
|
||||
</div>
|
||||
</Tab>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import WorkflowTimeline from '../WorkflowTimeline.svelte'
|
||||
import Popover from '../Popover.svelte'
|
||||
import { truncateRev } from '$lib/utils'
|
||||
import { isFlowPreview, isScriptPreview, truncateRev } from '$lib/utils'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { ListFilter } from 'lucide-svelte'
|
||||
|
||||
@@ -154,7 +154,7 @@
|
||||
{/if}
|
||||
|
||||
<div class=" w-full rounded-md min-h-full">
|
||||
{#if job?.is_flow_step == false && job?.flow_status && (job?.job_kind == 'preview' || job?.job_kind == 'script') && !(typeof job.flow_status == 'object' && '_metadata' in job.flow_status)}
|
||||
{#if job?.is_flow_step == false && job?.flow_status && (isScriptPreview(job?.job_kind) || job?.job_kind == 'script') && !(typeof job.flow_status == 'object' && '_metadata' in job.flow_status)}
|
||||
<WorkflowTimeline
|
||||
flow_status={asWorkflowStatus(job.flow_status)}
|
||||
flowDone={job.type == 'CompletedJob'}
|
||||
@@ -165,14 +165,14 @@
|
||||
<Tabs bind:selected={viewTab}>
|
||||
<Tab size="xs" value="result">Result</Tab>
|
||||
<Tab size="xs" value="logs">Logs</Tab>
|
||||
{#if job?.job_kind == 'preview'}
|
||||
{#if isScriptPreview(job?.job_kind)}
|
||||
<Tab size="xs" value="code">Code</Tab>
|
||||
{/if}
|
||||
</Tabs>
|
||||
|
||||
<Skeleton loading={!job} layout={[[5]]} />
|
||||
{#if job}
|
||||
{#if viewTab == 'result' && (job?.job_kind == 'flow' || job?.job_kind == 'flowpreview')}
|
||||
{#if viewTab == 'result' && (job?.job_kind == 'flow' || isFlowPreview(job?.job_kind))}
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="w-full mt-10 mb-20">
|
||||
<FlowStatusViewer jobId={job.id} workspaceId={job.workspace_id} />
|
||||
@@ -215,7 +215,7 @@
|
||||
{/if}
|
||||
{/if}
|
||||
{:else if job && `running` in job ? job.running : false}
|
||||
{#if job?.job_kind == 'flow' || job?.job_kind == 'flowpreview'}
|
||||
{#if job?.job_kind == 'flow' || isFlowPreview(job?.job_kind)}
|
||||
<div class="flex flex-col gap-2 w-full">
|
||||
<FlowProgressBar {job} class="py-4" />
|
||||
<FlowStatusViewer jobId={job.id} workspaceId={job.workspace_id} />
|
||||
|
||||
@@ -2,7 +2,15 @@
|
||||
import { base } from '$lib/base'
|
||||
import { goto } from '$lib/navigation'
|
||||
import type { Job } from '$lib/gen'
|
||||
import { displayDate, msToReadableTime, truncateHash, truncateRev, isJobCancelable } from '$lib/utils'
|
||||
import {
|
||||
displayDate,
|
||||
msToReadableTime,
|
||||
truncateHash,
|
||||
truncateRev,
|
||||
isJobCancelable,
|
||||
isFlowPreview,
|
||||
isScriptPreview
|
||||
} from '$lib/utils'
|
||||
import { Badge, Button } from '../common'
|
||||
import ScheduleEditor from '../ScheduleEditor.svelte'
|
||||
import BarsStaggered from '$lib/components/icons/BarsStaggered.svelte'
|
||||
@@ -38,7 +46,6 @@
|
||||
let scheduleEditor: ScheduleEditor
|
||||
|
||||
$: isExternal = job && job.id === '-'
|
||||
|
||||
</script>
|
||||
|
||||
<Portal name="run-row">
|
||||
@@ -110,7 +117,7 @@
|
||||
{#if job && 'duration_ms' in job && job.duration_ms != undefined}
|
||||
(Ran in {msToReadableTime(
|
||||
job.duration_ms
|
||||
)}{#if job.job_kind == 'flow' || job.job_kind == 'flowpreview'} total{/if})
|
||||
)}{#if job.job_kind == 'flow' || isFlowPreview(job.job_kind)} total{/if})
|
||||
{/if}
|
||||
{#if job && (job.self_wait_time_ms || job.aggregate_wait_time_ms)}
|
||||
<WaitTimeWarning
|
||||
@@ -123,7 +130,6 @@
|
||||
Scheduled for {displayDate(job.scheduled_for)}
|
||||
{:else if job.canceled}
|
||||
Cancelling job... (created <TimeAgo agoOnlyIfRecent date={job.created_at || ''} />)
|
||||
|
||||
{:else}
|
||||
Waiting for executor (created <TimeAgo agoOnlyIfRecent date={job.created_at || ''} />)
|
||||
{/if}
|
||||
@@ -176,7 +182,7 @@
|
||||
</Button>
|
||||
{/if}
|
||||
</div>
|
||||
{:else if 'job_kind' in job && job.job_kind == 'preview'}
|
||||
{:else if 'job_kind' in job && isScriptPreview(job.job_kind)}
|
||||
<a href="{base}/run/{job.id}?workspace={job.workspace_id}">Preview without path </a>
|
||||
{:else if 'job_kind' in job && job.job_kind == 'dependencies'}
|
||||
<a href="{base}/run/{job.id}?workspace={job.workspace_id}">
|
||||
|
||||
@@ -1089,3 +1089,13 @@ export function validateFileExtension(ext: string) {
|
||||
const validExtensionRegex = /^[a-zA-Z0-9]+([._][a-zA-Z0-9]+)*$/
|
||||
return validExtensionRegex.test(ext)
|
||||
}
|
||||
|
||||
export function isFlowPreview(job_kind: Job['job_kind'] | undefined) {
|
||||
return !!job_kind && (job_kind === 'flowpreview' || job_kind === 'flownode')
|
||||
}
|
||||
|
||||
export function isScriptPreview(job_kind: Job['job_kind'] | undefined) {
|
||||
return (
|
||||
!!job_kind && (job_kind === 'preview' || job_kind === 'flowscript' || job_kind === 'appscript')
|
||||
)
|
||||
}
|
||||
|
||||
@@ -59,6 +59,7 @@
|
||||
import autosize from '$lib/autosize'
|
||||
import EditableSchemaWrapper from '$lib/components/schema/EditableSchemaWrapper.svelte'
|
||||
import ResourceEditorDrawer from '$lib/components/ResourceEditorDrawer.svelte'
|
||||
import GfmMarkdown from '$lib/components/GfmMarkdown.svelte'
|
||||
|
||||
type ResourceW = ListableResource & { canWrite: boolean; marked?: string }
|
||||
type ResourceTypeW = ResourceType & { canWrite: boolean }
|
||||
@@ -437,7 +438,7 @@
|
||||
<div>
|
||||
<h1 class="mb-8 mt-4"><IconedResourceType name={resourceTypeViewerObj.rt} formatExtension={resourceTypeViewerObj.formatExtension} /></h1>
|
||||
<div class="py-2 box prose mb-8 text-secondary">
|
||||
{resourceTypeViewerObj.description ?? ''}
|
||||
<GfmMarkdown md={resourceTypeViewerObj.description ?? ''} />
|
||||
</div>
|
||||
{#if resourceTypeViewerObj.formatExtension}
|
||||
<Alert type="info" title="Plain text file resource (.{resourceTypeViewerObj.formatExtension})">
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
displayDate,
|
||||
emptyString,
|
||||
encodeState,
|
||||
isFlowPreview,
|
||||
isScriptPreview,
|
||||
truncateHash,
|
||||
truncateRev
|
||||
} from '$lib/utils'
|
||||
@@ -288,7 +290,7 @@
|
||||
}
|
||||
|
||||
function forkPreview() {
|
||||
if (job?.job_kind == 'flowpreview') {
|
||||
if (isFlowPreview(job?.job_kind)) {
|
||||
$initialArgsStore = job?.args
|
||||
const state = {
|
||||
flow: { value: job?.raw_flow },
|
||||
@@ -355,7 +357,7 @@
|
||||
|
||||
<ScheduleEditor bind:this={scheduleEditor} />
|
||||
|
||||
{#if (job?.job_kind == 'flow' || job?.job_kind == 'flowpreview') && job?.['running'] && job?.parent_job == undefined}
|
||||
{#if (job?.job_kind == 'flow' || isFlowPreview(job?.job_kind)) && job?.['running'] && job?.parent_job == undefined}
|
||||
<Drawer bind:this={debugViewer} size="800px">
|
||||
<DrawerContent title="Debug Detail" on:close={debugViewer.closeDrawer}>
|
||||
<svelte:fragment slot="actions">
|
||||
@@ -472,7 +474,7 @@
|
||||
{@const stem = `/${job?.job_kind}s`}
|
||||
{@const isScript = job?.job_kind === 'script'}
|
||||
{@const viewHref = `${stem}/get/${isScript ? job?.script_hash : job?.script_path}`}
|
||||
{#if (job?.job_kind == 'flow' || job?.job_kind == 'flowpreview') && job?.['running'] && job?.parent_job == undefined}
|
||||
{#if (job?.job_kind == 'flow' || isFlowPreview(job?.job_kind)) && job?.['running'] && job?.parent_job == undefined}
|
||||
<div class="inline">
|
||||
<ButtonDropdown hasPadding={false}>
|
||||
<svelte:fragment slot="buttonReplacement">
|
||||
@@ -488,7 +490,7 @@
|
||||
</ButtonDropdown>
|
||||
</div>
|
||||
{/if}
|
||||
{#if job?.job_kind === 'flowpreview' || job?.job_kind === 'preview'}
|
||||
{#if isFlowPreview(job?.job_kind) || isScriptPreview(job?.job_kind)}
|
||||
<Button
|
||||
color="dark"
|
||||
size="md"
|
||||
@@ -496,7 +498,7 @@
|
||||
startIcon={{ icon: GitBranch }}
|
||||
on:click={forkPreview}
|
||||
>
|
||||
Fork {job?.job_kind == 'flowpreview' ? 'flow' : 'code'} preview
|
||||
Fork {isFlowPreview(job?.job_kind) ? 'flow' : 'code'} preview
|
||||
</Button>
|
||||
{/if}
|
||||
{#if persistentScriptDefinition !== undefined}
|
||||
@@ -833,8 +835,8 @@
|
||||
<h2 class="mt-10">Scheduled to be executed later: {displayDate(job?.['scheduled_for'])}</h2>
|
||||
</div>
|
||||
{/if}
|
||||
{#if job?.job_kind !== 'flow' && job?.job_kind !== 'flowpreview' && job?.job_kind !== 'singlescriptflow' && job?.job_kind !== 'flownode'}
|
||||
{#if ['python3', 'bun', 'deno'].includes(job?.language ?? '') && (job?.job_kind == 'script' || job?.job_kind == 'preview')}
|
||||
{#if job?.job_kind !== 'flow' && job?.job_kind !== 'singlescriptflow' && !isFlowPreview(job?.job_kind)}
|
||||
{#if ['python3', 'bun', 'deno'].includes(job?.language ?? '') && (job?.job_kind == 'script' || isScriptPreview(job?.job_kind))}
|
||||
<ExecutionDuration bind:job bind:longRunning={currentJobIsLongRunning} />
|
||||
{/if}
|
||||
<div class="max-w-7xl mx-auto w-full px-4 mb-10">
|
||||
@@ -854,7 +856,7 @@
|
||||
<Tab value="result">Result</Tab>
|
||||
<Tab value="logs">Logs</Tab>
|
||||
<Tab value="stats">Metrics</Tab>
|
||||
{#if job?.job_kind == 'preview'}
|
||||
{#if isScriptPreview(job?.job_kind)}
|
||||
<Tab value="code">Code</Tab>
|
||||
{/if}
|
||||
</Tabs>
|
||||
|
||||
+2
-2
@@ -4,8 +4,8 @@ verify_ssl = true
|
||||
name = "pypi"
|
||||
|
||||
[packages]
|
||||
wmill = ">=1.440.3"
|
||||
wmill_pg = ">=1.440.3"
|
||||
wmill = ">=1.441.0"
|
||||
wmill_pg = ">=1.441.0"
|
||||
sendgrid = "*"
|
||||
mysql-connector-python = "*"
|
||||
pymongo = "*"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
openapi: "3.0.3"
|
||||
|
||||
info:
|
||||
version: 1.440.3
|
||||
version: 1.441.0
|
||||
title: OpenFlow Spec
|
||||
contact:
|
||||
name: Ruben Fiszel
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
RootModule = 'WindmillClient.psm1'
|
||||
|
||||
# Version number of this module.
|
||||
ModuleVersion = '1.440.3'
|
||||
ModuleVersion = '1.441.0'
|
||||
|
||||
# Supported PSEditions
|
||||
# CompatiblePSEditions = @()
|
||||
|
||||
+24
-4
@@ -6,7 +6,13 @@ cp ../backend/windmill-api/openapi.yaml openapi/openapi.yaml
|
||||
|
||||
npx @redocly/openapi-cli@latest bundle openapi/openapi.yaml > openapi-bundled.yaml
|
||||
|
||||
sed -z 's/FlowModuleValue:/FlowModuleValue2:/' openapi-bundled.yaml > openapi-decycled.yaml
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
# sed -z is not supported on macOS, use perl instead
|
||||
perl -0777 -pe 's/FlowModuleValue:/FlowModuleValue2:/g' openapi-bundled.yaml > openapi-decycled.yaml
|
||||
else
|
||||
sed -z 's/FlowModuleValue:/FlowModuleValue2:/' openapi-bundled.yaml > openapi-decycled.yaml
|
||||
fi
|
||||
|
||||
echo " FlowModuleValue: {}" >> openapi-decycled.yaml
|
||||
npx @redocly/openapi-cli@latest bundle openapi-decycled.yaml --ext json -d > openapi-deref.json
|
||||
|
||||
@@ -20,9 +26,19 @@ rm -rf openapi/
|
||||
rm openapi*
|
||||
|
||||
cp LICENSE windmill-api/
|
||||
sed -i '5 i license = "Apache-2.0"' windmill-api/pyproject.toml
|
||||
|
||||
sed -i 's/authors = \[\]/authors = \["Ruben Fiszel <ruben@windmill.dev>"\]/g' windmill-api/pyproject.toml
|
||||
# Check if running on macOS
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
# macOS version
|
||||
sed -i '' '5 i\
|
||||
license = "Apache-2.0"' windmill-api/pyproject.toml
|
||||
sed -i '' 's/authors = \[\]/\nauthors = \["Ruben Fiszel <ruben@windmill.dev>"\]/g' windmill-api/pyproject.toml
|
||||
else
|
||||
# Linux version
|
||||
sed -i '5 i license = "Apache-2.0"' windmill-api/pyproject.toml
|
||||
|
||||
sed -i 's/authors = \[\]/authors = \["Ruben Fiszel <ruben@windmill.dev>"\]/g' windmill-api/pyproject.toml
|
||||
fi
|
||||
|
||||
echo "# Autogenerated Windmill OpenApi Client" >> windmill-api/README.md.tmp
|
||||
echo "This is the raw autogenerated api client. You are most likely more interested \
|
||||
@@ -33,8 +49,12 @@ user friendly experience. We use \
|
||||
|
||||
echo "" >> windmill-api/README.md.tmp
|
||||
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
tail -r windmill-api/README.md | tail -n +14 | tail -r >> windmill-api/README.md.tmp
|
||||
else
|
||||
head -n -13 windmill-api/README.md >> windmill-api/README.md.tmp
|
||||
fi
|
||||
|
||||
head -n -13 windmill-api/README.md >> windmill-api/README.md.tmp
|
||||
mv windmill-api/README.md.tmp windmill-api/README.md
|
||||
|
||||
cd windmill-api && poetry build
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#! /usr/bin/env nu
|
||||
|
||||
let cache = "/tmp/windmill/cache/pip/"
|
||||
let cache = "/tmp/windmill/cache/python_311/"
|
||||
|
||||
# Clean cache
|
||||
def "main clean" [] {
|
||||
@@ -42,7 +42,7 @@ def main [
|
||||
rm -rf ($cache ++ wmill*/wmill/*)
|
||||
|
||||
# Copy files from local ./dist to every wm-client version in cache
|
||||
ls /tmp/windmill/cache/pip/wmill* | each {
|
||||
ls /tmp/windmill/cache/python_311/wmill* | each {
|
||||
|i|
|
||||
|
||||
let path = $i | get name;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[tool.poetry]
|
||||
name = "wmill"
|
||||
version = "1.440.3"
|
||||
version = "1.441.0"
|
||||
description = "A client library for accessing Windmill server wrapping the Windmill client API"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://windmill.dev"
|
||||
|
||||
@@ -623,6 +623,46 @@ class Windmill:
|
||||
params={"approver": approver},
|
||||
).json()
|
||||
|
||||
def request_interactive_slack_approval(
|
||||
self,
|
||||
slack_resource_path: str,
|
||||
channel_id: str,
|
||||
message: str = None,
|
||||
approver: str = None,
|
||||
) -> None:
|
||||
"""
|
||||
Request interactive Slack approval
|
||||
:param slack_resource_path: Slack resource path
|
||||
:param channel_id: Slack channel
|
||||
:param message: Message to send to Slack
|
||||
:param approver: Approver name
|
||||
"""
|
||||
workspace = self.workspace
|
||||
flow_job_id = os.environ.get("WM_FLOW_JOB_ID")
|
||||
|
||||
if not flow_job_id:
|
||||
raise Exception(
|
||||
"You can't use 'request_interactive_slack_approval' function in a standalone script or flow step preview. Please use it in a flow or a flow preview."
|
||||
)
|
||||
|
||||
# Only include non-empty parameters
|
||||
params = {}
|
||||
if message:
|
||||
params["message"] = message
|
||||
if approver:
|
||||
params["approver"] = approver
|
||||
if slack_resource_path:
|
||||
params["slack_resource_path"] = slack_resource_path
|
||||
if channel_id:
|
||||
params["channel_id"] = channel_id
|
||||
if os.environ.get("WM_FLOW_STEP_ID"):
|
||||
params["flow_step_id"] = os.environ.get("WM_FLOW_STEP_ID")
|
||||
|
||||
self.get(
|
||||
f"/w/{workspace}/jobs/slack_approval/{os.environ.get('WM_JOB_ID', 'NO_JOB_ID')}",
|
||||
params=params,
|
||||
)
|
||||
|
||||
def username_to_email(self, username: str) -> str:
|
||||
"""
|
||||
Get email from workspace username
|
||||
@@ -972,6 +1012,19 @@ def get_state_path() -> str:
|
||||
def get_resume_urls(approver: str = None) -> dict:
|
||||
return _client.get_resume_urls(approver)
|
||||
|
||||
@init_global_client
|
||||
def request_interactive_slack_approval(
|
||||
slack_resource_path: str,
|
||||
channel_id: str,
|
||||
message: str = None,
|
||||
approver: str = None,
|
||||
) -> None:
|
||||
return _client.request_interactive_slack_approval(
|
||||
slack_resource_path=slack_resource_path,
|
||||
channel_id=channel_id,
|
||||
message=message,
|
||||
approver=approver,
|
||||
)
|
||||
|
||||
@init_global_client
|
||||
def cancel_running() -> dict:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[tool.poetry]
|
||||
name = "wmill-pg"
|
||||
version = "1.440.3"
|
||||
version = "1.441.0"
|
||||
description = "An extension client for the wmill client library focused on pg"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://windmill.dev"
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
# Generate windmill-client bundle
|
||||
|
||||
```bash
|
||||
./node_modules/.bin/esbuild src/index.ts --b
|
||||
undle --outfile=windmill.js --format=esm
|
||||
./node_modules/.bin/esbuild src/index.ts --bundle --outfile=windmill.js --format=esm --platform=node
|
||||
```
|
||||
|
||||
# Generate d.ts bundle
|
||||
|
||||
@@ -14,5 +14,5 @@ cp "${script_dirpath}/s3Types.ts" "${script_dirpath}/src/"
|
||||
echo "" >> "${script_dirpath}/src/index.ts"
|
||||
echo 'export type { S3Object, DenoS3LightClientSettings } from "./s3Types";' >> "${script_dirpath}/src/index.ts"
|
||||
echo "" >> "${script_dirpath}/src/index.ts"
|
||||
echo 'export { type Base64, setClient, getVariable, setVariable, getResource, setResource, getResumeUrls, setState, getState, getIdToken, denoS3LightClientSettings, loadS3FileStream, loadS3File, writeS3File, task, runScript, runScriptAsync, runFlow, runFlowAsync, waitJob, getRootJobId, setFlowUserState, getFlowUserState, usernameToEmail } from "./client";' >> "${script_dirpath}/src/index.ts"
|
||||
echo 'export { type Base64, setClient, getVariable, setVariable, getResource, setResource, getResumeUrls, setState, getState, getIdToken, denoS3LightClientSettings, loadS3FileStream, loadS3File, writeS3File, task, runScript, runScriptAsync, runFlow, runFlowAsync, waitJob, getRootJobId, setFlowUserState, getFlowUserState, usernameToEmail, requestInteractiveSlackApproval} from "./client";' >> "${script_dirpath}/src/index.ts"
|
||||
|
||||
|
||||
@@ -22,10 +22,15 @@ const baseUrl = getEnv("BASE_INTERNAL_URL") ?? getEnv("BASE_URL") ?? "http://loc
|
||||
const baseUrlApi = (baseUrl ?? '') + "/api";
|
||||
|
||||
EOF
|
||||
sed -i 's/WITH_CREDENTIALS: false/WITH_CREDENTIALS: true/g' src/core/OpenAPI.ts
|
||||
sed -i 's/TOKEN: undefined/TOKEN: getEnv("WM_TOKEN")/g' src/core/OpenAPI.ts
|
||||
sed -i "s/BASE: '\/api'/BASE: baseUrlApi/g" src/core/OpenAPI.ts
|
||||
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
sed -i '' 's/WITH_CREDENTIALS: false/WITH_CREDENTIALS: true/g' src/core/OpenAPI.ts
|
||||
sed -i '' 's/TOKEN: undefined/TOKEN: getEnv("WM_TOKEN")/g' src/core/OpenAPI.ts
|
||||
sed -i '' "s/BASE: '\/api'/BASE: baseUrlApi/g" src/core/OpenAPI.ts
|
||||
else
|
||||
sed -i 's/WITH_CREDENTIALS: false/WITH_CREDENTIALS: true/g' src/core/OpenAPI.ts
|
||||
sed -i 's/TOKEN: undefined/TOKEN: getEnv("WM_TOKEN")/g' src/core/OpenAPI.ts
|
||||
sed -i "s/BASE: '\/api'/BASE: baseUrlApi/g" src/core/OpenAPI.ts
|
||||
fi
|
||||
|
||||
|
||||
|
||||
@@ -34,4 +39,4 @@ cp "${script_dirpath}/s3Types.ts" "${script_dirpath}/src/"
|
||||
echo "" >> "${script_dirpath}/src/index.ts"
|
||||
echo 'export type { S3Object, DenoS3LightClientSettings } from "./s3Types";' >> "${script_dirpath}/src/index.ts"
|
||||
echo "" >> "${script_dirpath}/src/index.ts"
|
||||
echo 'export { type Base64, setClient, getVariable, setVariable, getResource, setResource, getResumeUrls, setState, setProgress, getProgress, getState, getIdToken, denoS3LightClientSettings, loadS3FileStream, loadS3File, writeS3File, task, runScript, runScriptAsync, runFlow, runFlowAsync, waitJob, getRootJobId, setFlowUserState, getFlowUserState, usernameToEmail } from "./client";' >> "${script_dirpath}/src/index.ts"
|
||||
echo 'export { type Base64, setClient, getVariable, setVariable, getResource, setResource, getResumeUrls, setState, setProgress, getProgress, getState, getIdToken, denoS3LightClientSettings, loadS3FileStream, loadS3File, writeS3File, task, runScript, runScriptAsync, runFlow, runFlowAsync, waitJob, getRootJobId, setFlowUserState, getFlowUserState, usernameToEmail, requestInteractiveSlackApproval } from "./client";' >> "${script_dirpath}/src/index.ts"
|
||||
|
||||
@@ -9,7 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
||||
});
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.usernameToEmail = exports.uint8ArrayToBase64 = exports.base64ToUint8Array = exports.getIdToken = exports.getResumeEndpoints = exports.getResumeUrls = exports.writeS3File = exports.loadS3FileStream = exports.loadS3File = exports.denoS3LightClientSettings = exports.databaseUrlFromResource = exports.setVariable = exports.getVariable = exports.getState = exports.getInternalState = exports.getFlowUserState = exports.setFlowUserState = exports.setState = exports.setInternalState = exports.setResource = exports.getStatePath = exports.resolveDefaultResource = exports.runScriptAsync = exports.task = exports.getResultMaybe = exports.getResult = exports.waitJob = exports.runScript = exports.getRootJobId = exports.getResource = exports.getWorkspace = exports.setClient = exports.SHARED_FOLDER = exports.WorkspaceService = exports.UserService = exports.SettingsService = exports.ScheduleService = exports.ScriptService = exports.VariableService = exports.ResourceService = exports.JobService = exports.GroupService = exports.GranularAclService = exports.FlowService = exports.AuditService = exports.AdminService = void 0;
|
||||
exports.requestInteractiveSlackApproval = exports.usernameToEmail = exports.uint8ArrayToBase64 = exports.base64ToUint8Array = exports.getIdToken = exports.getResumeEndpoints = exports.getResumeUrls = exports.writeS3File = exports.loadS3FileStream = exports.loadS3File = exports.denoS3LightClientSettings = exports.databaseUrlFromResource = exports.setVariable = exports.getVariable = exports.getState = exports.getInternalState = exports.getFlowUserState = exports.setFlowUserState = exports.setState = exports.setInternalState = exports.setResource = exports.getStatePath = exports.resolveDefaultResource = exports.runScriptAsync = exports.task = exports.getResultMaybe = exports.getResult = exports.waitJob = exports.runScript = exports.getRootJobId = exports.getResource = exports.getWorkspace = exports.setClient = exports.SHARED_FOLDER = exports.WorkspaceService = exports.UserService = exports.SettingsService = exports.ScheduleService = exports.ScriptService = exports.VariableService = exports.ResourceService = exports.JobService = exports.GroupService = exports.GranularAclService = exports.FlowService = exports.AuditService = exports.AdminService = void 0;
|
||||
const index_1 = require("./index");
|
||||
const index_2 = require("./index");
|
||||
var index_3 = require("./index");
|
||||
|
||||
@@ -395,15 +395,15 @@ export async function setState(state: any): Promise<void> {
|
||||
*/
|
||||
export async function setProgress(percent: number, jobId?: any): Promise<void> {
|
||||
const workspace = getWorkspace();
|
||||
let flowId = getEnv("WM_FLOW_JOB_ID");
|
||||
let flowId = getEnv("WM_FLOW_JOB_ID");
|
||||
|
||||
// If jobId specified we need to find if there is a parent/flow
|
||||
if (jobId) {
|
||||
const job = await JobService.getJob({
|
||||
id: jobId ?? "NO_JOB_ID",
|
||||
workspace,
|
||||
noLogs: true
|
||||
});
|
||||
noLogs: true,
|
||||
});
|
||||
|
||||
// Could be actual flowId or undefined
|
||||
flowId = job.parent_job;
|
||||
@@ -415,22 +415,22 @@ export async function setProgress(percent: number, jobId?: any): Promise<void> {
|
||||
requestBody: {
|
||||
// In case user inputs float, it should be converted to int
|
||||
percent: Math.floor(percent),
|
||||
flow_job_id: (flowId == "") ? undefined : flowId,
|
||||
}
|
||||
flow_job_id: flowId == "" ? undefined : flowId,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the progress
|
||||
* @param jobId? Job to get progress from
|
||||
* @returns Optional clamped between 0 and 100 progress value
|
||||
* @returns Optional clamped between 0 and 100 progress value
|
||||
*/
|
||||
export async function getProgress(jobId?: any): Promise<number | null> {
|
||||
// TODO: Delete or set to 100 completed job metrics
|
||||
return await MetricsService.getJobProgress({
|
||||
id: jobId ?? getEnv("WM_JOB_ID") ?? "NO_JOB_ID",
|
||||
workspace: getWorkspace(),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -846,3 +846,57 @@ export async function usernameToEmail(username: string): Promise<string> {
|
||||
const workspace = getWorkspace();
|
||||
return await UserService.usernameToEmail({ username, workspace });
|
||||
}
|
||||
|
||||
interface SlackApprovalOptions {
|
||||
slackResourcePath: string;
|
||||
channelId: string;
|
||||
message?: string;
|
||||
approver?: string;
|
||||
}
|
||||
|
||||
export async function requestInteractiveSlackApproval({
|
||||
slackResourcePath,
|
||||
channelId,
|
||||
message,
|
||||
approver,
|
||||
}: SlackApprovalOptions): Promise<void> {
|
||||
const workspace = getWorkspace();
|
||||
const flowJobId = getEnv("WM_FLOW_JOB_ID");
|
||||
|
||||
if (!flowJobId) {
|
||||
throw new Error(
|
||||
"You can't use this function in a standalone script or flow step preview. Please use it in a flow or a flow preview."
|
||||
);
|
||||
}
|
||||
|
||||
const flowStepId = getEnv("WM_FLOW_STEP_ID");
|
||||
if (!flowStepId) {
|
||||
throw new Error("This function can only be called as a flow step");
|
||||
}
|
||||
|
||||
// Only include non-empty parameters
|
||||
const params: {
|
||||
approver?: string;
|
||||
message?: string;
|
||||
slackResourcePath: string;
|
||||
channelId: string;
|
||||
flowStepId: string;
|
||||
} = {
|
||||
slackResourcePath,
|
||||
channelId,
|
||||
flowStepId,
|
||||
};
|
||||
|
||||
if (message) {
|
||||
params.message = message;
|
||||
}
|
||||
if (approver) {
|
||||
params.approver = approver;
|
||||
}
|
||||
|
||||
await JobService.getSlackApprovalPayload({
|
||||
workspace,
|
||||
...params,
|
||||
id: getEnv("WM_JOB_ID") ?? "NO_JOB_ID",
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@windmill/windmill",
|
||||
"version": "1.440.3",
|
||||
"version": "1.441.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.440.3",
|
||||
"version": "1.441.0",
|
||||
"author": "Ruben Fiszel",
|
||||
"license": "Apache 2.0",
|
||||
"devDependencies": {
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
1.440.3
|
||||
1.441.0
|
||||
|
||||
Reference in New Issue
Block a user