Merge branch 'main' into fr/xyflow

This commit is contained in:
Faton Ramadani
2024-08-08 10:16:40 +02:00
committed by GitHub
48 changed files with 432 additions and 142 deletions
+28
View File
@@ -1,5 +1,33 @@
# Changelog
## [1.376.1](https://github.com/windmill-labs/windmill/compare/v1.376.0...v1.376.1) (2024-08-07)
### Bug Fixes
* email triggers sqlx CE and improve email parsing ([#4203](https://github.com/windmill-labs/windmill/issues/4203)) ([6e9c350](https://github.com/windmill-labs/windmill/commit/6e9c350b4aa27355d03cb409da36e8f44ff548dc))
* mysql params starting with underscore ([#4201](https://github.com/windmill-labs/windmill/issues/4201)) ([e7148f6](https://github.com/windmill-labs/windmill/commit/e7148f672303ccf2b5c49bd9d75ee9764657490e))
## [1.376.0](https://github.com/windmill-labs/windmill/compare/v1.375.0...v1.376.0) (2024-08-06)
### Features
* email triggers ([#4163](https://github.com/windmill-labs/windmill/issues/4163)) ([a87f34f](https://github.com/windmill-labs/windmill/commit/a87f34fb4a5e54da38e2dbabf2ac551d35b021ee))
* secure ctx variables in runnable inputs ([#4142](https://github.com/windmill-labs/windmill/issues/4142)) ([b54edf1](https://github.com/windmill-labs/windmill/commit/b54edf153ec90b9bafad9ed7bc92c29345951fe6))
* Tag filter on Runs page ([#4193](https://github.com/windmill-labs/windmill/issues/4193)) ([7b31281](https://github.com/windmill-labs/windmill/commit/7b3128171ea7193efea569297a099bb9ee6935e1))
### Bug Fixes
* fix native scripts access to reserved variables ([7886f8f](https://github.com/windmill-labs/windmill/commit/7886f8f471bcb33f7cc640eab64ffc0dd3cb1726))
* **frontend:** disable email triggers by default ([#4199](https://github.com/windmill-labs/windmill/issues/4199)) ([5e3a3e2](https://github.com/windmill-labs/windmill/commit/5e3a3e2103ce6218a60c570546355ef6ca574df2))
* **frontend:** fix the app created from a script or flow with the new topbar ([#4194](https://github.com/windmill-labs/windmill/issues/4194)) ([657f03b](https://github.com/windmill-labs/windmill/commit/657f03bc67f84a8593b28483684c2ad8ad432865))
* **frontend:** Fr/improve suspend drawer ([#4189](https://github.com/windmill-labs/windmill/issues/4189)) ([5104dba](https://github.com/windmill-labs/windmill/commit/5104dba63140e2186dc1eed7f0bf4e14e357bf3d))
* **frontend:** Hide AgChart background to make styling work ([#4197](https://github.com/windmill-labs/windmill/issues/4197)) ([b9b30e6](https://github.com/windmill-labs/windmill/commit/b9b30e66ec485cc019561b092fc27d08aa4666b3))
* **frontend:** Remove full height for the event handlers of runnables ([#4196](https://github.com/windmill-labs/windmill/issues/4196)) ([6749f2c](https://github.com/windmill-labs/windmill/commit/6749f2c1367bdbecb12941baaa87b63c4b4c6f20))
* mysql support for underscore in named param ([#4200](https://github.com/windmill-labs/windmill/issues/4200)) ([cfa20ae](https://github.com/windmill-labs/windmill/commit/cfa20ae0d740014baea2e534cea5f787acaeb028))
## [1.375.0](https://github.com/windmill-labs/windmill/compare/v1.374.0...v1.375.0) (2024-08-05)
@@ -0,0 +1,20 @@
{
"db_name": "PostgreSQL",
"query": "SELECT value FROM metrics WHERE id = 'email_trigger_usage' AND created_at > NOW() - INTERVAL '1 day' ORDER BY created_at DESC LIMIT 1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "value",
"type_info": "Jsonb"
}
],
"parameters": {
"Left": []
},
"nullable": [
false
]
},
"hash": "4e6e4ecaa7a874b07b6599b6b7b3f307eb201534aa25d8a2049d1949f4ec9e77"
}
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "SELECT worker, worker_instance, vcpus, memory, ping_at, started_at FROM worker_ping WHERE ping_at > now() - interval '30 days'",
"query": "SELECT worker, worker_instance, vcpus, memory, ping_at, started_at FROM worker_ping WHERE ping_at > now() - interval '30 days' ORDER BY started_at",
"describe": {
"columns": [
{
@@ -46,5 +46,5 @@
false
]
},
"hash": "43cc4e7d9846dbce81b61a25e8ceca636a08451db3288969ed9105fa0cb4e5b8"
"hash": "a51007ca7b509b92faa6fe7aa59fa738594a2b7eaab8e38f3ca30e548f9a49a7"
}
@@ -0,0 +1,12 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO metrics (id, value) VALUES ('email_trigger_usage', to_jsonb(1))",
"describe": {
"columns": [],
"parameters": {
"Left": []
},
"nullable": []
},
"hash": "a7d107fbeb8749d16ea3fea091573324cd5cbae2c3b77f24027802ea3896ef26"
}
@@ -1,26 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "WITH active_users as (SELECT distinct username as email FROM audit WHERE timestamp > NOW() - INTERVAL '1 month' AND (operation = 'users.login' OR operation = 'oauth.login')),\n active_user_count as (SELECT count(email)::INT as count from active_users),\n active_author_count as (SELECT count(distinct email)::INT as count FROM usr WHERE usr.operator IS false AND email IN (SELECT email FROM active_users))\n SELECT active_author_count.count as author_count, active_user_count.count - active_author_count.count as operator_count FROM active_user_count, active_author_count",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "author_count",
"type_info": "Int4"
},
{
"ordinal": 1,
"name": "operator_count",
"type_info": "Int4"
}
],
"parameters": {
"Left": []
},
"nullable": [
null,
null
]
},
"hash": "ad8d9c00bd2d3515ad4afa87aa24b243615484bbad5a793438e23908c3f20c2f"
}
@@ -0,0 +1,38 @@
{
"db_name": "PostgreSQL",
"query": "WITH active_users as (SELECT distinct username as email FROM audit WHERE timestamp > NOW() - INTERVAL '1 month' AND (operation = 'users.login' OR operation = 'oauth.login')),\n active_authors as (SELECT distinct email FROM usr WHERE usr.operator IS false AND email IN (SELECT email FROM active_users)),\n active_authors_agg as (SELECT array_agg(email) as authors FROM active_authors),\n active_ops_agg as (SELECT array_agg(email) as operators from active_users WHERE email NOT IN (SELECT email FROM active_authors))\n SELECT active_authors_agg.authors, active_ops_agg.operators, array_length(active_authors_agg.authors, 1) as author_count, array_length(active_ops_agg.operators, 1) as operator_count FROM active_authors_agg, active_ops_agg",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "authors",
"type_info": "VarcharArray"
},
{
"ordinal": 1,
"name": "operators",
"type_info": "VarcharArray"
},
{
"ordinal": 2,
"name": "author_count",
"type_info": "Int4"
},
{
"ordinal": 3,
"name": "operator_count",
"type_info": "Int4"
}
],
"parameters": {
"Left": []
},
"nullable": [
null,
null,
null,
null
]
},
"hash": "cce991f582bc9d2ba28a5b2b41c679366bb07bc6a100727721a787160ac6910c"
}
@@ -0,0 +1,14 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE metrics SET value = $1 WHERE id = 'email_trigger_usage' AND created_at > NOW() - INTERVAL '1 day'",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Jsonb"
]
},
"nullable": []
},
"hash": "f4942f502ba7f66bafb0b2de6979601723de8092796f3bbeb78191c1da30d225"
}
+29 -29
View File
@@ -5412,9 +5412,9 @@ dependencies = [
[[package]]
name = "object"
version = "0.36.2"
version = "0.36.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f203fa8daa7bb185f760ae12bd8e097f63d17041dcdcaf675ac54cdf863170e"
checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9"
dependencies = [
"memchr",
]
@@ -7170,9 +7170,9 @@ dependencies = [
[[package]]
name = "rustls-pki-types"
version = "1.7.0"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d"
checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0"
[[package]]
name = "rustls-tokio-stream"
@@ -7280,9 +7280,9 @@ checksum = "ad97d4ce1560a5e27cec89519dc8300d1aa6035b099821261c651486a19e44d5"
[[package]]
name = "safetensors"
version = "0.4.3"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ced76b22c7fba1162f11a5a75d9d8405264b467a07ae0c9c29be119b9297db9"
checksum = "7725d4d98fa515472f43a6e2bbf956c48e06b89bb50593a040e5945160214450"
dependencies = [
"serde",
"serde_json",
@@ -9013,15 +9013,15 @@ dependencies = [
[[package]]
name = "tempfile"
version = "3.11.0"
version = "3.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8fcd239983515c23a32fb82099f97d0b11b8c72f654ed659363a95c3dad7a53"
checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64"
dependencies = [
"cfg-if",
"fastrand 2.1.0",
"once_cell",
"rustix 0.38.34",
"windows-sys 0.52.0",
"windows-sys 0.59.0",
]
[[package]]
@@ -10393,7 +10393,7 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windmill"
version = "1.375.0"
version = "1.376.1"
dependencies = [
"anyhow",
"axum",
@@ -10433,7 +10433,7 @@ dependencies = [
[[package]]
name = "windmill-api"
version = "1.375.0"
version = "1.376.1"
dependencies = [
"anyhow",
"argon2",
@@ -10516,7 +10516,7 @@ dependencies = [
[[package]]
name = "windmill-api-client"
version = "1.375.0"
version = "1.376.1"
dependencies = [
"base64 0.21.7",
"chrono",
@@ -10534,7 +10534,7 @@ dependencies = [
[[package]]
name = "windmill-audit"
version = "1.375.0"
version = "1.376.1"
dependencies = [
"chrono",
"serde",
@@ -10547,7 +10547,7 @@ dependencies = [
[[package]]
name = "windmill-common"
version = "1.375.0"
version = "1.376.1"
dependencies = [
"anyhow",
"async-stream",
@@ -10588,7 +10588,7 @@ dependencies = [
[[package]]
name = "windmill-git-sync"
version = "1.375.0"
version = "1.376.1"
dependencies = [
"regex",
"rsmq_async",
@@ -10603,7 +10603,7 @@ dependencies = [
[[package]]
name = "windmill-indexer"
version = "1.375.0"
version = "1.376.1"
dependencies = [
"anyhow",
"bytes",
@@ -10624,7 +10624,7 @@ dependencies = [
[[package]]
name = "windmill-parser"
version = "1.375.0"
version = "1.376.1"
dependencies = [
"serde",
"serde_json",
@@ -10632,7 +10632,7 @@ dependencies = [
[[package]]
name = "windmill-parser-bash"
version = "1.375.0"
version = "1.376.1"
dependencies = [
"anyhow",
"lazy_static",
@@ -10643,7 +10643,7 @@ dependencies = [
[[package]]
name = "windmill-parser-go"
version = "1.375.0"
version = "1.376.1"
dependencies = [
"anyhow",
"gosyn",
@@ -10655,7 +10655,7 @@ dependencies = [
[[package]]
name = "windmill-parser-graphql"
version = "1.375.0"
version = "1.376.1"
dependencies = [
"anyhow",
"lazy_static",
@@ -10666,7 +10666,7 @@ dependencies = [
[[package]]
name = "windmill-parser-php"
version = "1.375.0"
version = "1.376.1"
dependencies = [
"anyhow",
"convert_case 0.6.0",
@@ -10680,7 +10680,7 @@ dependencies = [
[[package]]
name = "windmill-parser-py"
version = "1.375.0"
version = "1.376.1"
dependencies = [
"anyhow",
"itertools 0.13.0",
@@ -10691,7 +10691,7 @@ dependencies = [
[[package]]
name = "windmill-parser-py-imports"
version = "1.375.0"
version = "1.376.1"
dependencies = [
"anyhow",
"async-recursion",
@@ -10708,7 +10708,7 @@ dependencies = [
[[package]]
name = "windmill-parser-sql"
version = "1.375.0"
version = "1.376.1"
dependencies = [
"anyhow",
"lazy_static",
@@ -10719,7 +10719,7 @@ dependencies = [
[[package]]
name = "windmill-parser-ts"
version = "1.375.0"
version = "1.376.1"
dependencies = [
"anyhow",
"convert_case 0.6.0",
@@ -10738,7 +10738,7 @@ dependencies = [
[[package]]
name = "windmill-parser-wasm"
version = "1.375.0"
version = "1.376.1"
dependencies = [
"anyhow",
"getrandom 0.2.15",
@@ -10757,7 +10757,7 @@ dependencies = [
[[package]]
name = "windmill-queue"
version = "1.375.0"
version = "1.376.1"
dependencies = [
"anyhow",
"async-recursion",
@@ -10790,7 +10790,7 @@ dependencies = [
[[package]]
name = "windmill-sql-datatype-parser-wasm"
version = "1.375.0"
version = "1.376.1"
dependencies = [
"wasm-bindgen",
"wasm-bindgen-test",
@@ -10800,7 +10800,7 @@ dependencies = [
[[package]]
name = "windmill-worker"
version = "1.375.0"
version = "1.376.1"
dependencies = [
"anyhow",
"async-recursion",
+3 -2
View File
@@ -1,6 +1,6 @@
[package]
name = "windmill"
version = "1.375.0"
version = "1.376.1"
authors.workspace = true
edition.workspace = true
@@ -25,7 +25,7 @@ members = [
]
[workspace.package]
version = "1.375.0"
version = "1.376.1"
authors = ["Ruben Fiszel <ruben@windmill.dev>"]
edition = "2021"
@@ -54,6 +54,7 @@ openidconnect = ["windmill-api/openidconnect"]
cloud = ["windmill-queue/cloud", "windmill-worker/cloud"]
jemalloc = ["windmill-common/jemalloc", "dep:tikv-jemallocator", "dep:tikv-jemalloc-sys", "dep:tikv-jemalloc-ctl"]
tantivy = ["dep:windmill-indexer", "windmill-api/tantivy"]
sqlx = ["windmill-worker/sqlx"]
[dependencies]
anyhow.workspace = true
+1 -1
View File
@@ -1 +1 @@
70e475a5cec356d2fe992038f303aea8988b5046
86cfcdef47f8b740cbbdf568f7a2282984ea7460
@@ -336,12 +336,12 @@ pub fn parse_sql_statement_named_params(code: &str, prefix: char) -> HashSet<Str
char == prefix
&& chars
.peek()
.is_some_and(|&(_, next_char)| next_char.is_alphanumeric())
.is_some_and(|&(_, next_char)| next_char.is_alphanumeric() || next_char == '_')
},
|_, chars| {
let mut arg_name = String::new();
while let Some(&(_, char)) = chars.peek() {
if char.is_alphanumeric() {
if char.is_alphanumeric() || char == '_' {
arg_name.push(char);
chars.next();
} else {
@@ -751,8 +751,8 @@ SELECT ?, ?;
let code = r#"
-- :param1 (int) = 3
-- :param2 (text)
-- :param3 (text)
SELECT :param3, :param1;
-- :param_3 (text)
SELECT :param_3, :param1;
SELECT :param2;
"#;
assert_eq!(
@@ -779,7 +779,7 @@ SELECT :param2;
},
Arg {
otyp: Some("text".to_string()),
name: "param3".to_string(),
name: "param_3".to_string(),
typ: Typ::Str(None),
default: None,
has_default: false,
+1 -1
View File
@@ -1,7 +1,7 @@
openapi: "3.0.3"
info:
version: 1.375.0
version: 1.376.1
title: Windmill API
contact:
+2 -2
View File
@@ -56,8 +56,8 @@ pub struct ListableFlow {
pub path: String,
pub summary: String,
pub description: String,
pub edited_by: String,
pub edited_at: chrono::DateTime<chrono::Utc>,
pub edited_by: Option<String>,
pub edited_at: Option<chrono::DateTime<chrono::Utc>>,
pub archived: bool,
pub extra_perms: serde_json::Value,
pub starred: bool,
+1
View File
@@ -17,6 +17,7 @@ flamegraph = []
parquet = ["windmill-common/parquet", "dep:object_store"]
flow_testing = []
cloud = []
sqlx = []
[dependencies]
windmill-queue.workspace = true
+1 -7
View File
@@ -12,7 +12,7 @@ use windmill_common::{
error::{self, Error},
jobs::QueuedJob,
utils::calculate_hash,
worker::{save_cache, CLOUD_HOSTED},
worker::save_cache,
};
use windmill_parser_go::{parse_go_imports, REQUIRE_PARSE};
use windmill_queue::{append_logs, CanceledBy};
@@ -301,12 +301,6 @@ func Run(req Req) (interface{{}}, error){{
)
.await?;
if cache && *CLOUD_HOSTED {
//do not keep the binary in the cache if it is cloud hosted to avoid filling up the disk
if let Err(e) = tokio::fs::remove_file(&bin_path).await {
tracing::error!("could not remove {bin_path} from go cache: {e:?}");
}
}
read_result(job_dir).await
}
+1 -1
View File
@@ -2278,7 +2278,7 @@ async fn handle_queued_job<R: rsmq_async::RsmqConnection + Send + Sync + Clone>(
return Err(Error::ExecutionErr(e.to_string()));
}
#[cfg(not(feature = "enterprise"))]
#[cfg(any(not(feature = "enterprise"), feature = "sqlx"))]
if job.created_by.starts_with("email-trigger-") {
let daily_count = sqlx::query!(
"SELECT value FROM metrics WHERE id = 'email_trigger_usage' AND created_at > NOW() - INTERVAL '1 day' ORDER BY created_at DESC LIMIT 1"
+1 -1
View File
@@ -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.375.0";
export const VERSION = "v1.376.1";
export async function login(email: string, password: string): Promise<string> {
return await windmill.UserService.login({
+1 -1
View File
@@ -34,7 +34,7 @@ addEventListener("error", (event) => {
}
});
export const VERSION = "v1.375.0";
export const VERSION = "v1.376.1";
let command: any = new Command()
.name("wmill")
+3
View File
@@ -166,6 +166,9 @@ export async function handleFile(
platform: "node",
packages: "bundle",
target: "node20.15.1",
loader: {
".node": "file",
},
});
bundleContent = out.outputFiles[0].text;
if (Array.isArray(codebase.assets) && codebase.assets.length > 0) {
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "windmill-components",
"version": "1.375.0",
"version": "1.376.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "windmill-components",
"version": "1.375.0",
"version": "1.376.1",
"license": "AGPL-3.0",
"dependencies": {
"@aws-crypto/sha256-js": "^4.0.0",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "windmill-components",
"version": "1.375.0",
"version": "1.376.1",
"scripts": {
"dev": "vite dev",
"build": "vite build",
@@ -6,6 +6,8 @@
import AppConnectInner from './AppConnectInner.svelte'
import DarkModeObserver from './DarkModeObserver.svelte'
let expressOAuthSetup = false
let drawer: Drawer
let resourceType = ''
let step = 1
@@ -16,12 +18,17 @@
let appConnectInner: AppConnectInner | undefined = undefined
let rtToLoad: string | undefined = ''
export async function open(rt?: string) {
export async function open(rt?: string, express?: boolean) {
expressOAuthSetup = express ?? false
rtToLoad = rt
drawer.openDrawer?.()
}
$: appConnectInner?.open(rtToLoad)
$: appConnectInner && onRtToLoadChange(rtToLoad)
function onRtToLoadChange(rtToLoad: string | undefined) {
appConnectInner?.open(rtToLoad, expressOAuthSetup)
}
const dispatch = createEventDispatcher()
@@ -1,5 +1,5 @@
<script lang="ts">
import { workspaceStore } from '$lib/stores'
import { userStore, workspaceStore } from '$lib/stores'
import IconedResourceType from './IconedResourceType.svelte'
import {
OauthService,
@@ -75,11 +75,14 @@
let pathError = ''
export async function open(rt?: string) {
let expressOAuthSetup = false
export async function open(rt?: string, express?: boolean) {
expressOAuthSetup = express ?? false
if (!rt) {
loadResourceTypes()
}
step = 1
step = 1 //express && !manual ? 3 : 1
value = ''
description = ''
resourceType = rt ?? ''
@@ -87,6 +90,10 @@
await loadConnects()
manual = !connects?.includes(resourceType)
if (rt) {
if (!manual && expressOAuthSetup) {
await getScopesAndParams()
step = 2
}
next()
}
}
@@ -167,6 +174,10 @@
value = data.res.access_token!
valueToken = data.res
step = 4
if (expressOAuthSetup) {
path = `u/${$userStore?.username}/${resourceType}_${new Date().getTime()}`
next()
}
}
}
@@ -315,7 +315,7 @@
<ToggleButton
small
light
tooltip="Javascript expression ('flow_input' or 'results')."
tooltip="JavaScript expression ('flow_input' or 'results')."
value="javascript"
icon={FunctionSquare}
/>
@@ -17,9 +17,11 @@
export let value: string | undefined = initialValue
export let valueType: string | undefined = undefined
export let resourceType: string | undefined = undefined
export let disabled = false
export let disablePortal = false
export let showSchemaExplorer = false
export let selectFirst = false
export let expressOAuthSetup = false
let valueSelect =
initialValue || value
@@ -36,6 +38,10 @@
let collection = valueSelect ? [valueSelect] : []
export async function askNewResource() {
appConnect?.open?.(resourceType)
}
async function loadResources(resourceType: string | undefined) {
const nc = (
await ResourceService.listResource({
@@ -101,31 +107,37 @@
/>
<div class="flex flex-col w-full items-start">
<div class="flex flex-row gap-x-1 w-full">
<Select
portal={!disablePortal}
value={valueSelect}
on:change={(e) => {
value = e.detail.value
valueType = e.detail.type
valueSelect = e.detail
}}
on:clear={() => {
value = undefined
valueType = undefined
valueSelect = undefined
}}
items={collection}
class="text-clip grow min-w-0"
placeholder="{resourceType ?? 'any'} resource"
inputStyles={SELECT_INPUT_DEFAULT_STYLE.inputStyles}
containerStyles={darkMode
? SELECT_INPUT_DEFAULT_STYLE.containerStylesDark
: SELECT_INPUT_DEFAULT_STYLE.containerStyles}
/>
<div class="flex flex-row gap-x-1 w-full items-center">
{#if collection?.length > 0}
<Select
{disabled}
portal={!disablePortal}
value={valueSelect}
on:change={(e) => {
value = e.detail.value
valueType = e.detail.type
valueSelect = e.detail
}}
on:clear={() => {
value = undefined
valueType = undefined
valueSelect = undefined
}}
items={collection}
class="text-clip grow min-w-0"
placeholder="{resourceType ?? 'any'} resource"
inputStyles={SELECT_INPUT_DEFAULT_STYLE.inputStyles}
containerStyles={darkMode
? SELECT_INPUT_DEFAULT_STYLE.containerStylesDark
: SELECT_INPUT_DEFAULT_STYLE.containerStyles}
/>
{:else}
<div class="text-2xs text-tertiary mr-2">0 found</div>
{/if}
{#if value && value != ''}
<Button
{disabled}
color="light"
variant="border"
size="xs"
@@ -138,6 +150,7 @@
{#if resourceType?.includes(',')}
{#each resourceType.split(',') as rt}
<Button
{disabled}
color="light"
variant="border"
size="xs"
@@ -147,13 +160,17 @@
{/each}
{:else}
<Button
{disabled}
color="light"
variant="border"
size="xs"
on:click={() => appConnect?.open?.(resourceType)}
on:click={() => appConnect?.open?.(resourceType, expressOAuthSetup)}
startIcon={{ icon: Plus }}
iconOnly
/>
iconOnly={collection?.length > 0}
>{#if collection?.length == 0}
Add a {resourceType} resource
{/if}</Button
>
{/if}
<Button
@@ -25,7 +25,7 @@ function create_context_function_template(
) {
let hasReturnAsLastLine = noReturn || eval_string.split('\n').some((x) => x.startsWith('return '))
return `
return async function (context, state, goto, setTab, recompute, getAgGrid, setValue, setSelectedIndex, openModal, closeModal, open, close, validate, invalidate, validateAll, clearFiles, showToast, waitJob) {
return async function (context, state, goto, setTab, recompute, getAgGrid, setValue, setSelectedIndex, openModal, closeModal, open, close, validate, invalidate, validateAll, clearFiles, showToast, waitJob, askNewResource) {
"use strict";
${
contextKeys && contextKeys.length > 0
@@ -61,7 +61,8 @@ type WmFunctor = (
validateAll,
clearFiles,
showToast,
waitJob
waitJob,
askNewResource
) => Promise<any>
let functorCache: Record<number, WmFunctor> = {}
@@ -111,6 +112,7 @@ export async function eval_like(
clearFiles?: () => void
showToast?: (message: string, error?: boolean) => void
waitJob?: (jobId: string) => void
askNewResource?: () => void
}
>,
worldStore: World | undefined,
@@ -189,6 +191,9 @@ export async function eval_like(
(message, error) => {
sendUserToast(message, error)
},
async (id) => waitJob(id)
async (id) => waitJob(id),
(id) => {
controlComponents[id]?.askNewResource?.()
}
)
}
@@ -0,0 +1,109 @@
<script lang="ts">
import { getContext, onDestroy } from 'svelte'
import { initConfig, initOutput } from '../../editor/appUtils'
import type {
AppViewerContext,
ComponentCustomCSS,
ListContext,
ListInputs,
RichConfigurations
} from '../../types'
import { initCss } from '../../utils'
import AlignWrapper from '../helpers/AlignWrapper.svelte'
import InitializeComponent from '../helpers/InitializeComponent.svelte'
import { components } from '../../editor/component'
import ResolveConfig from '../helpers/ResolveConfig.svelte'
import ResolveStyle from '../helpers/ResolveStyle.svelte'
import ResourcePicker from '$lib/components/ResourcePicker.svelte'
export let id: string
export let configuration: RichConfigurations
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
export let customCss: ComponentCustomCSS<'userresourcecomponent'> | undefined = undefined
export let render: boolean
const { app, worldStore, componentControl } = getContext<AppViewerContext>('AppViewerContext')
let resolvedConfig = initConfig(
components['userresourcecomponent'].initialData.configuration,
configuration
)
const iterContext = getContext<ListContext>('ListWrapperContext')
const listInputs: ListInputs | undefined = getContext<ListInputs>('ListInputs')
let outputs = initOutput($worldStore, id, {
result: undefined as string | undefined
})
let value: string | undefined = outputs.result.peak()?.replace('$res:', '')
value && assignValue(outputs.result.peak())
onDestroy(() => {
listInputs?.remove(id)
})
$componentControl[id] = {
setValue(nvalue: string) {
value = nvalue
},
askNewResource() {
resourcePicker?.askNewResource()
}
}
function assignValue(value: string) {
let nval
if (!value || value === '') {
nval = undefined
} else {
nval = '$res:' + value.replace('$res:', '')
}
outputs?.result.set(nval)
if (iterContext && listInputs) {
listInputs.set(id, nval)
}
}
let css = initCss($app.css?.['userresourcecomponent'], customCss)
let resourcePicker: ResourcePicker | undefined = undefined
</script>
{#each Object.keys(components['userresourcecomponent'].initialData.configuration) as key (key)}
<ResolveConfig
{id}
{key}
bind:resolvedConfig={resolvedConfig[key]}
configuration={configuration[key]}
/>
{/each}
{#each Object.keys(css ?? {}) as key (key)}
<ResolveStyle
{id}
{customCss}
{key}
bind:css={css[key]}
componentStyle={$app.css?.textinputcomponent}
/>
{/each}
<InitializeComponent {id} />
{#if render}
<AlignWrapper {render} {verticalAlignment}>
<div class="relative w-full">
<ResourcePicker
expressOAuthSetup={resolvedConfig.expressOauthSetup}
bind:this={resourcePicker}
{value}
on:change={(e) => {
assignValue(e.detail)
}}
disabled={resolvedConfig.disabled}
resourceType={resolvedConfig.resourceType}
/>
</div>
</AlignWrapper>
{/if}
@@ -79,6 +79,7 @@
import AppDateSelect from '../../components/inputs/AppDateSelect.svelte'
import AppDisplayComponentByJobId from '../../components/display/AppRecomputeAll.svelte'
import AppRecomputeAll from '../../components/display/AppRecomputeAll.svelte'
import AppUserResource from '../../components/inputs/AppUserResource.svelte'
export let component: AppComponent
export let selected: boolean
@@ -434,6 +435,14 @@
onSelect={component.onSelect}
{render}
/>
{:else if component.type === 'userresourcecomponent'}
<AppUserResource
id={component.id}
verticalAlignment={component.verticalAlignment}
configuration={component.configuration}
customCss={component.customCss}
{render}
/>
{:else if component.type === 'multiselectcomponent'}
<AppMultiSelect
id={component.id}
@@ -181,6 +181,10 @@ export type ResourceSelectComponent = BaseComponent<'resourceselectcomponent'> &
RecomputeOthersSource & {
onSelect?: string[]
}
export type ResourceConnectComponent = BaseComponent<'userresourcecomponent'> &
RecomputeOthersSource & {
onSelect?: string[]
}
export type MultiSelectComponent = BaseComponent<'multiselectcomponent'>
export type MultiSelectComponentV2 = BaseComponent<'multiselectcomponentv2'>
export type CheckboxComponent = BaseComponent<'checkboxcomponent'> &
@@ -361,6 +365,7 @@ export type TypedComponent =
| DateSelectComponent
| JobIdDisplayComponent
| RecomputeAllComponent
| ResourceConnectComponent
export type AppComponent = BaseAppComponent & TypedComponent
@@ -2216,7 +2221,7 @@ This is a paragraph.
}
},
resourceselectcomponent: {
name: 'Resource Select',
name: 'Static Resource Select',
icon: List,
documentationLink: `${documentationBaseUrl}/resource_select`,
dims: '2:1-3:1' as AppComponentDimensions,
@@ -2254,6 +2259,38 @@ This is a paragraph.
}
}
},
userresourcecomponent: {
name: 'User Resource Input',
icon: List,
documentationLink: `${documentationBaseUrl}/resource_select`,
dims: '2:1-3:1' as AppComponentDimensions,
customCss: {
input: { style: '' }
},
initialData: {
verticalAlignment: 'center',
componentInput: undefined,
configuration: {
resourceType: {
type: 'static',
fieldType: 'text',
value: 'postgresql'
},
expressOauthSetup: {
type: 'static',
fieldType: 'boolean',
value: false,
tooltip:
'If enabled, skip some steps while adding oauth resources: No scopes to set prior to OAuth sign-in, and no path to set after OAuth sign-in'
},
disabled: {
type: 'static',
fieldType: 'boolean',
value: false
}
}
}
},
numberinputcomponent: {
name: 'Number',
icon: Binary,
@@ -54,6 +54,7 @@ const inputs: ComponentSet = {
'checkboxcomponent',
'selectcomponent',
'resourceselectcomponent',
'userresourcecomponent',
'multiselectcomponentv2',
'selecttabcomponent',
'selectstepcomponent'
@@ -748,6 +748,9 @@ export const quickStyleProperties: Record<
resourceselectcomponent: {
input: inputDefaultProps
},
userresourcecomponent: {
input: inputDefaultProps
},
verticaldividercomponent: {
divider: dividerDefaultProps,
container: containerDefaultProps
@@ -17,6 +17,7 @@
'formbuttoncomponent',
'checkboxcomponent',
'resourceselectcomponent',
'userresourcecomponent',
'selectcomponent',
'tabscomponent',
'conditionalwrapper',
@@ -64,7 +65,7 @@
bind:value={item.data.onToggle}
/>
{/if}
{#if item.data.type === 'resourceselectcomponent' || item.data.type === 'selectcomponent'}
{#if item.data.type === 'resourceselectcomponent' || item.data.type === 'selectcomponent' || item.data.type == 'userresourcecomponent'}
<EventHandlerItem
title="on select"
tooltip="Contrary to onSuccess, this will only trigger recompute when a human select an item, not if it set by a default value or by setValue"
@@ -262,6 +262,7 @@ export type AppViewerContext = {
clearFiles?: () => void
showToast?: (message: string, error?: boolean) => void
recompute?: () => void
askNewResource?: () => void
}
>
>
@@ -267,6 +267,11 @@ declare function showToast(message: string, error?: boolean): void;
declare async function waitJob(id: string): Promise<any>;
/**
* ask user resource on a UserResourceComponent
*/
declare async function askNewResource(id: string): void;
`
: ''
}
@@ -52,7 +52,7 @@ Here's the user's request: ${instructions}
You can find the details of all the steps below:
${flowDetails}
Determine for the user the javascript expression for the branching condition composed of the previous results or the flow inputs.
Determine for the user the JavaScript expression for the branching condition composed of the previous results or the flow inputs.
All inputs start with either results. or flow_input. and are followed by the key of the input.
Here's a summary of the available data:
<available>
@@ -20,6 +20,7 @@
import HighlightTheme from '../HighlightTheme.svelte'
import Alert from '../common/alert/Alert.svelte'
import { SettingService } from '$lib/gen'
import { base } from '$lib/base'
let userSettings: UserSettings
@@ -56,16 +57,16 @@
$: webhooks = isFlow ? computeFlowWebhooks(path) : computeScriptWebhooks(hash, path)
function computeScriptWebhooks(hash: string | undefined, path: string) {
let base = `${$page.url.origin}/api/w/${$workspaceStore}/jobs`
let webhookBase = `${$page.url.origin}${base}/api/w/${$workspaceStore}/jobs`
return {
async: {
hash: `${base}/run/h/${hash}`,
path: `${base}/run/p/${path}`
hash: `${webhookBase}/run/h/${hash}`,
path: `${webhookBase}/run/p/${path}`
},
sync: {
hash: `${base}/run_wait_result/h/${hash}`,
path: `${base}/run_wait_result/p/${path}`,
get_path: `${base}/run_wait_result/p/${path}`
hash: `${webhookBase}/run_wait_result/h/${hash}`,
path: `${webhookBase}/run_wait_result/p/${path}`,
get_path: `${webhookBase}/run_wait_result/p/${path}`
}
}
}
@@ -27,7 +27,7 @@
role="alert"
id="dynamic-input-help-box"
>
Single javascript expression. The following functions and objects are available:
Single JavaScript expression. The following functions and objects are available:
<ul class="ml-4">
<li><b>{'results.<id>'}</b>: the result of step at id 'id'</li>
<li><b>flow_input</b>: the object containing the flow input arguments</li>
@@ -88,7 +88,7 @@
popover: {
title: 'Iterator expression',
description:
'The iterator expression is a javascript expression that respresents the array to iterate on. Here we will iterate on the firstname input letter by letter',
'The iterator expression is a JavaScript expression that respresents the array to iterate on. Here we will iterate on the firstname input letter by letter',
onNextClick: () => {
updateFlowModuleById($flowStore, id, (module) => {
if (module.value.type === 'forloopflow') {
+4 -6
View File
@@ -2,7 +2,7 @@ import { goto as svelteGoto } from '$app/navigation'
import { base as svelteBase } from '$app/paths'
export function goto(path, options = {}) {
if (svelteBase == '') {
if (svelteBase == '' || path.startsWith('?')) {
return svelteGoto(path, options)
} else {
const fullPath = path.startsWith(svelteBase) ? path : `${svelteBase}${path}`
@@ -22,9 +22,7 @@ export async function setQuery(
url.searchParams.delete(key)
}
await goto(
currentHash
? `?${url.searchParams.toString()}${currentHash}`
: `?${url.searchParams.toString()}`
)
let searchParams = url.searchParams.toString()
await goto(currentHash ? `?${searchParams}${currentHash}` : `?${searchParams}`)
}
@@ -565,7 +565,7 @@
}
let jobId = await JobService.runScriptByPath({
workspace: $workspaceStore!,
path: 'hub/7925/git-repo-test-read-write-windmill',
path: 'hub/8944/git-repo-test-read-write-windmill',
requestBody: {
repo_url_resource_path: gitSyncRepository.git_repo_resource_path.replace('$res:', '')
}
+2 -2
View File
@@ -4,8 +4,8 @@ verify_ssl = true
name = "pypi"
[packages]
wmill = ">=1.375.0"
wmill_pg = ">=1.375.0"
wmill = ">=1.376.1"
wmill_pg = ">=1.376.1"
sendgrid = "*"
mysql-connector-python = "*"
pymongo = "*"
+1 -1
View File
@@ -1,7 +1,7 @@
openapi: "3.0.3"
info:
version: 1.375.0
version: 1.376.1
title: OpenFlow Spec
contact:
name: Ruben Fiszel
@@ -12,7 +12,7 @@
RootModule = 'WindmillClient.psm1'
# Version number of this module.
ModuleVersion = '1.375.0'
ModuleVersion = '1.376.1'
# Supported PSEditions
# CompatiblePSEditions = @()
+1 -1
View File
@@ -1,6 +1,6 @@
[tool.poetry]
name = "wmill"
version = "1.375.0"
version = "1.376.1"
description = "A client library for accessing Windmill server wrapping the Windmill client API"
license = "Apache-2.0"
homepage = "https://windmill.dev"
+1 -1
View File
@@ -1,6 +1,6 @@
[tool.poetry]
name = "wmill-pg"
version = "1.375.0"
version = "1.376.1"
description = "An extension client for the wmill client library focused on pg"
license = "Apache-2.0"
homepage = "https://windmill.dev"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@windmill/windmill",
"version": "1.375.0",
"version": "1.376.1",
"exports": "./src/index.ts",
"publish": {
"exclude": ["!src", "./s3Types.ts", "./client.ts"]
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "windmill-client",
"description": "Windmill SDK client for browsers and Node.js",
"version": "1.375.0",
"version": "1.376.1",
"author": "Ruben Fiszel",
"license": "Apache 2.0",
"devDependencies": {
+1 -1
View File
@@ -1 +1 @@
1.375.0
1.376.1