fix: custom tag helper

This commit is contained in:
Ruben Fiszel
2025-09-12 13:16:00 +00:00
parent 84757a68d7
commit bef6bb826f
3 changed files with 147 additions and 4 deletions
@@ -0,0 +1,24 @@
{
"db_name": "PostgreSQL",
"query": "SELECT EXISTS(SELECT 1 FROM folder WHERE name = $1 AND workspace_id = $2 AND $3 = ANY(owners))",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "exists",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Text",
"Text",
"Text"
]
},
"nullable": [
null
]
},
"hash": "6a0b04a34032ae0e28bbb4895ad8409185d273c022c4971329f5bce85097bc22"
}
+33 -1
View File
@@ -202,6 +202,7 @@ async fn create_folder(
));
}
if let Err(e) =
sqlx::query_as!(
Folder,
"INSERT INTO folder (workspace_id, name, display_name, owners, extra_perms, summary, created_by, edited_at) VALUES ($1, $2, $3, $4, $5, $6, $7, now())",
@@ -214,7 +215,38 @@ async fn create_folder(
authed.username
)
.execute(&mut *tx)
.await?;
.await {
let exists_for_user = sqlx::query_scalar!(
"SELECT EXISTS(SELECT 1 FROM folder WHERE name = $1 AND workspace_id = $2 AND $3 = ANY(owners))",
ng.name,
w_id,
authed.username
)
.fetch_one(&mut *tx)
.await?
.unwrap_or(false);
let exists = sqlx::query_scalar!(
"SELECT EXISTS(SELECT 1 FROM folder WHERE name = $1 AND workspace_id = $2)",
ng.name,
w_id
)
.fetch_one(&db)
.await?
.unwrap_or(false);
if !exists_for_user && exists {
return Err(windmill_common::error::Error::BadRequest(format!(
"Folder '{}' already exists in workspace '{}' but you do not have permission to read to it", ng.name, w_id
)));
} else if exists {
return Err(windmill_common::error::Error::BadRequest(format!(
"Folder '{}' already exists in workspace '{}'", ng.name, w_id
)));
} else {
return Err(windmill_common::error::Error::InternalErr(format!(
"Failed to create folder: {}", e
)));
}
}
audit_log(
&mut *tx,
@@ -32,6 +32,34 @@
const dispatch = createEventDispatcher()
const customTagRegex = /^([\w-]+)\(((?:[\w-]+\+)*[\w-]+|(?:\^[\w-]+)+)\)$/
const dynamicTagRegex = /\$args\[((?:\w+\.)*\w+)\]/
let dynamicTag = $derived.by(() => {
let r = newTag.trim()
if (r == '') return undefined
let matched = r.match(dynamicTagRegex)
return matched?.[1]
})
let extractedCustomTag = $derived.by(() => {
let r = newTag.trim()
if (r == '') return undefined
let matched = r.match(customTagRegex)
console.log(matched)
let tag = matched?.[1]
let workspaces_raw = matched?.[2]
let tag_type = workspaces_raw?.includes('^') ? 'exclude' : 'include'
if (tag_type == 'exclude') {
workspaces_raw = workspaces_raw?.slice(1)
}
let workspaces = workspaces_raw?.split(tag_type == 'include' ? '+' : '^')
if (!workspaces_raw || workspaces_raw?.length == 0) {
return undefined
}
return { tag, workspaces, tag_type }
})
loadCustomTags()
</script>
@@ -64,6 +92,53 @@
{/each}
</div>
<input type="text" bind:value={newTag} />
{#if extractedCustomTag}
<div class="text-2xs text-tertiary p-2 bg-gray-50 rounded border">
<div class="font-medium mb-1">Workspace specific tag</div>
<div>
<b>Tag:</b>
{extractedCustomTag.tag}
</div>
<div>
<b>Workspaces:</b>
{#if extractedCustomTag.tag_type == 'include'}
{extractedCustomTag.workspaces?.join(', ')}
{:else}
All workspaces except {extractedCustomTag.workspaces?.join(', ')}
{/if}
</div>
</div>
{:else if newTag.trim()}
{#if newTag.includes('(') || newTag.includes(')') || newTag.includes('+') || newTag.includes('^') || ((newTag.includes('.') || newTag.includes('$args[')) && !dynamicTag)}
<div class="text-2xs text-tertiary p-2 bg-gray-50 rounded border">
<div class="font-medium mb-1 text-red-500">Invalid tag</div>
<div>
<b>Tag:</b>
{newTag.trim()}
</div>
</div>
{:else}
<div class="text-2xs text-tertiary p-2 bg-gray-50 rounded border">
<div class="font-medium mb-1">
{#if newTag.includes('$workspace') || newTag.includes('$args')}
Dynamic tag
{:else}
Simple tag
{/if}
</div>
<div>
<b>Tag:</b>
{newTag.trim()}
</div>
{#if newTag.includes('$workspace') && !dynamicTag}
<div>Interpolated tag based on workspace id the job was created in </div>
{/if}
{#if dynamicTag}
<div>Interpolated tag based on args input of <b>{dynamicTag}</b></div>
{/if}
</div>
{/if}
{/if}
<Button
variant="contained"
@@ -96,13 +171,25 @@
></span
>
<span class="text-2xs text-tertiary"
>To exclude 'workspace1' and 'workspace2' from a tag, use <pre
class="inline">tag(^workspace1^workspace2)</pre
>To exclude 'workspace1' and 'workspace2' from a tag, use <pre class="inline"
>tag(^workspace1^workspace2)</pre
></span
>
<span class="text-2xs text-tertiary"
>For dynamic tags based on the workspace, use <pre class="inline">$workspace</pre>, e.g:
>For <a
href="https://www.windmill.dev/docs/core_concepts/worker_groups#dynamic-tag"
target="_blank">dynamic tags</a
>
based on the workspace, use <pre class="inline">$workspace</pre>, e.g:
<pre class="inline">tag-$workspace</pre></span
>
<span class="text-2xs text-tertiary"
>For <a
href="https://www.windmill.dev/docs/core_concepts/worker_groups#dynamic-tag"
target="_blank">dynamic tags</a
>
based on args input, use <pre class="inline">$args[a.b.c]</pre> where
<pre class="inline">a.b.c</pre> is the path to the value in the args object</span
>
{/if}
</div>