Merge branch 'main' into fr/xyflow

This commit is contained in:
Faton Ramadani
2024-08-06 17:44:54 +02:00
committed by GitHub
9 changed files with 83 additions and 24 deletions

View File

@@ -1383,7 +1383,30 @@ async fn build_args(
let arg_str = v.get();
if !arg_str.contains("\"$var:") && !arg_str.contains("\"$res:") {
if arg_str.starts_with("\"$ctx:") {
let prop = arg_str.trim_start_matches("\"$ctx:").trim_end_matches("\"");
let value = match prop {
"username" => authed.as_ref().map(|a| {
serde_json::to_value(a.username_override.as_ref().unwrap_or(&a.username))
}),
"email" => authed.as_ref().map(|a| serde_json::to_value(&a.email)),
"workspace" => Some(serde_json::to_value(&w_id)),
"groups" => authed.as_ref().map(|a| serde_json::to_value(&a.groups)),
"author" => Some(serde_json::to_value(&policy.on_behalf_of_email)),
_ => {
return Err(Error::BadRequest(format!(
"context variable {} not allowed",
prop
)))
}
};
safe_args.insert(
k.to_string(),
to_raw_value(&value.unwrap_or(Ok(serde_json::Value::Null)).map_err(|e| {
Error::InternalErr(format!("failed to serialize ctx variable for {}: {}", k, e))
})?),
);
} else if !arg_str.contains("\"$var:") && !arg_str.contains("\"$res:") {
safe_args.insert(k.to_string(), v);
} else {
safe_args.insert(

View File

@@ -25,6 +25,7 @@
import { userStore } from '$lib/stores'
import { get } from 'svelte/store'
import RefreshButton from '$lib/components/apps/components/helpers/RefreshButton.svelte'
import { ctxRegex } from '../../utils'
// Component props
export let id: string
@@ -341,7 +342,12 @@
allowUserResources.push(k)
}
} else if (field?.type == 'eval' || (field?.type == 'evalv2' && inputValues[k])) {
nonStaticRunnableInputs[k] = await inputValues[k]?.computeExpr()
const ctxMatch = field.expr.match(ctxRegex)
if (ctxMatch) {
nonStaticRunnableInputs[k] = '$ctx:' + ctxMatch[1]
} else {
nonStaticRunnableInputs[k] = await inputValues[k]?.computeExpr()
}
if (isEditor && field?.type == 'evalv2' && field.allowUserResources) {
allowUserResources.push(k)
}

View File

@@ -363,6 +363,7 @@
component.type === 'aggridinfinitecomponentee'
? ['offset', 'limit', 'orderBy', 'isDesc', 'search']
: []}
securedContext
/>
</div>
{/if}

View File

@@ -42,6 +42,7 @@
export let showOnDemandOnlyToggle = true
export let documentationLink: string | undefined = undefined
export let markdownTooltip: string | undefined = undefined
export let securedContext = false
const { connectingInput, app } = getContext<AppViewerContext>('AppViewerContext')
@@ -185,6 +186,7 @@
{fixedOverflowWidgets}
{recomputeOnInputChanged}
{showOnDemandOnlyToggle}
{securedContext}
/>
{:else if componentInput?.type === 'upload'}
<UploadInputEditor bind:componentInput {fileUpload} />

View File

@@ -18,6 +18,7 @@
export let acceptSelf: boolean = false
export let recomputeOnInputChanged = true
export let showOnDemandOnlyToggle = false
export let securedContext = false
export let overridenByComponent: string[] = []
$: finalInputSpecsConfiguration = inputSpecsConfiguration ?? inputSpecs
@@ -79,6 +80,7 @@
{displayType}
{recomputeOnInputChanged}
{showOnDemandOnlyToggle}
{securedContext}
/>
{#if deletable}
<div class="flex flex-row-reverse -mt-4">

View File

@@ -4,13 +4,14 @@
import { getContext } from 'svelte'
import type { AppEditorContext, AppViewerContext } from '$lib/components/apps/types'
import SimpleEditor from '$lib/components/SimpleEditor.svelte'
import { buildExtraLib } from '$lib/components/apps/utils'
import { buildExtraLib, ctxRegex } from '$lib/components/apps/utils'
import { inferDeps } from '../../appUtilsInfer'
import { Maximize2, X } from 'lucide-svelte'
import { Maximize2, Shield, X } from 'lucide-svelte'
import { Drawer } from '$lib/components/common'
import { Pane, Splitpanes } from 'svelte-splitpanes'
import Toggle from '$lib/components/Toggle.svelte'
import { zIndexes } from '$lib/zIndexes'
import Popover from '$lib/components/Popover.svelte'
export let componentInput: EvalV2AppInput | undefined
export let id: string
@@ -19,6 +20,7 @@
export let acceptSelf: boolean = false
export let recomputeOnInputChanged = true
export let showOnDemandOnlyToggle = false
export let securedContext = false
const { onchange, worldStore, state, app } = getContext<AppViewerContext>('AppViewerContext')
const { evalPreview } = getContext<AppEditorContext>('AppEditorContext')
@@ -119,6 +121,17 @@
inferDepsFromCode(e.detail.code)
}}
/>
{#if securedContext && componentInput?.expr?.match(ctxRegex)}
<div class="border bg-surface absolute top-0.5 right-8 p-0.5">
<Popover notClickable>
<Shield size={12} />
<svelte:fragment slot="text">
This context variable is securely provided by the backend and cannot be altered by
users
</svelte:fragment>
</Popover>
</div>
{/if}
<button
class="border bg-surface absolute top-0.5 right-2 p-0.5"
on:click={() => (fullscreen = true)}><Maximize2 size={12} /></button

View File

@@ -442,3 +442,5 @@ export function getImageDataURL(imageKind: string | undefined, image: string | u
return image
}
}
export const ctxRegex = /^ctx\.(workspace|groups|username|email|author)$/

View File

@@ -44,12 +44,12 @@
}
}
let emailDomain: string = "mail." + $page.url.hostname
let emailDomain: string | null = null
async function getEmailDomain() {
emailDomain =
((await SettingService.getGlobal({
key: 'email_domain'
})) as any) ?? ("mail." + $page.url.hostname)
})) as any) ?? null
}
getEmailDomain()
@@ -393,26 +393,37 @@ done`
{/key}
</TabContent>
<TabContent value="email">
<div class="flex flex-col gap-4">
{#key args}
{#key requestType}
{#key webhookType}
{#key tokenType}
{#key token}
<div class="flex flex-col gap-2">
<ClipboardPanel title="Email address" content={emailAddress()} />
</div>
{#if emailDomain}
<div class="flex flex-col gap-4">
{#key args}
{#key requestType}
{#key webhookType}
{#key tokenType}
{#key token}
<div class="flex flex-col gap-2">
<ClipboardPanel title="Email address" content={emailAddress()} />
</div>
{/key}
{/key}
{/key}
{/key}
{/key}
{/key}
<Alert title="Email triggers" size="xs">
To trigger the job by email, send an email to the address above. The job will receive
two arguments: `raw_email` containing the raw email as string, and `parsed_email`
containing the parsed email as an object.
</Alert>
</div>
<Alert title="Email triggers" size="xs">
To trigger the job by email, send an email to the address above. The job will
receive two arguments: `raw_email` containing the raw email as string, and
`parsed_email` containing the parsed email as an object.
</Alert>
</div>
{:else}
<div>
<Alert title="Email triggers are disabled" size="xs" kind="danger">
Ask an instance superadmin to setup the instance for email triggering (<a
target="_blank"
href="https://windmill.dev/docs/advanced/email_triggers">docs</a
>) and to set the email domain in the instance settings.
</Alert>
</div>
{/if}
</TabContent>
{/key}
</svelte:fragment>

View File

@@ -46,8 +46,7 @@ export const settings: Record<string, Setting[]> = {
},
{
label: 'Email domain',
description:
'Domain to display in webhooks for email triggers, default is the webpage domain prefixed by "mail."',
description: 'Domain to display in webhooks for email triggers (should match the MX record)',
key: 'email_domain',
fieldType: 'text',
storage: 'setting',