diff --git a/frontend/src/lib/components/assets/AssetGraph/AssetGraphCanvas.svelte b/frontend/src/lib/components/assets/AssetGraph/AssetGraphCanvas.svelte index 15ea720a60..7e442f1d04 100644 --- a/frontend/src/lib/components/assets/AssetGraph/AssetGraphCanvas.svelte +++ b/frontend/src/lib/components/assets/AssetGraph/AssetGraphCanvas.svelte @@ -21,7 +21,7 @@ import { layoutAssetGraph, PIPELINE_NODE_EXTRA_ROW } from './assetGraphLayout' import { assetsOnlyView, type AssetUpstream } from './assetsOnlyView' import { TRIGGER_NODE_STYLE } from './TriggerNode.svelte' - import { describeCron } from '$lib/utils/describeCron' + import { describeSchedule } from '$lib/utils/describeCron' import Toggle from '$lib/components/Toggle.svelte' import { computeMutedReadKeys, dbtAssociations } from './resolveGraph' import { buildDownstreamMap } from './graphTraversal' @@ -732,6 +732,7 @@ missing: boolean draft: boolean schedule?: string + timezone?: string summary?: string // First target script (drives the per-script create/edit flows). runnable_path?: string @@ -751,6 +752,7 @@ draft: boolean, runnable_path?: string, schedule?: string, + timezone?: string, summary?: string ) { const prev = triggerSourceNodes.get(id) @@ -762,6 +764,7 @@ missing, draft, schedule, + timezone, summary, runnable_path, runnable_paths: runnable_path ? [runnable_path] : [] @@ -820,6 +823,7 @@ // on every attached native trigger. t.runnable_path, t.schedule, + t.timezone, t.summary ) edges.push({ @@ -850,6 +854,7 @@ missing: info.missing, draft: info.draft, schedule: info.schedule, + timezone: info.timezone, summary: info.summary, runnable_path: info.runnable_path, // data_upload nodes go green once a file is staged for their @@ -910,7 +915,7 @@ const style = TRIGGER_NODE_STYLE[t.kind as TriggerNodeKind] const label = t.kind === 'schedule' && t.data?.schedule - ? (describeCron(t.data.schedule) ?? `Schedule (${t.data.schedule})`) + ? (describeSchedule(t.data.schedule, t.data.timezone) ?? `Schedule (${t.data.schedule})`) : (style?.label ?? t.kind) return { label, @@ -1450,7 +1455,7 @@ {#if assetsOnlyToggle} diff --git a/frontend/src/lib/components/assets/AssetGraph/PipelineInsertMenu.svelte b/frontend/src/lib/components/assets/AssetGraph/PipelineInsertMenu.svelte index b6105c5207..e32b2c2fa9 100644 --- a/frontend/src/lib/components/assets/AssetGraph/PipelineInsertMenu.svelte +++ b/frontend/src/lib/components/assets/AssetGraph/PipelineInsertMenu.svelte @@ -67,6 +67,7 @@ import DateTimeInput from '$lib/components/DateTimeInput.svelte' import ScheduleAdvancedOptions, { emptyScheduleAdvanced, + loadDefaultScheduleAdvanced, scheduleAdvancedCfg } from '$lib/components/triggers/schedules/ScheduleAdvancedOptions.svelte' import { workspaceStore } from '$lib/stores' @@ -147,14 +148,31 @@ tableEdited: false }) let config = $state(buildEmptyConfig()) + loadAdvancedDefaults() + + // The workspace's default handlers, as the schedule drawer applies to a new schedule. + function loadAdvancedDefaults() { + const ws = $workspaceStore + if (!ws) return + const target = config + loadDefaultScheduleAdvanced(ws) + .then((d) => { + if (config === target) config.advanced = d + }) + .catch(() => {}) + } function resetWizard() { selected = buildEmptySelected() config = buildEmptyConfig() + loadAdvancedDefaults() step = 0 } const TABLE_NAME_RE = /^[^/\s]+$/ + // The path grammar of `Path.svelte`: word segments, no empty or trailing ones. + const SCRIPT_NAME_RE = /^[\w-]+(\/[\w-]+)*$/ + let scriptNameValid = $derived(SCRIPT_NAME_RE.test(selected.scriptPath.trim())) let assetValid = $derived( !!config.asset?.store && TABLE_NAME_RE.test(config.asset.table.trim()) ) @@ -163,7 +181,7 @@ ? config.validCron && !!config.schedule.trim() && !config.schedulePathError : currentConfigStep === 'asset' ? assetValid - : !!selected.scriptPath.trim() + : scriptNameValid && !!selected.triggerId && !!selected.language && !!selected.outputId ) function enterAssetStep() { @@ -428,14 +446,30 @@ {#snippet bottomSection(close: () => void)}