mirror of
https://github.com/Dvorinka/Primora.git
synced 2026-10-28 15:51:23 +00:00
feat: Function triggers — schedule, inbound hook, domain events
Migration 00016: function_id on scheduled_jobs/inbound_hooks, event_pattern on functions, 'event' in the run-trigger enum. - Jobs deliver to a function instead of HTTP when function_id is set; the run's status_code mirrors the process exit code. Clearing the field returns the job to URL delivery. - Inbound hooks gain mode "function" — received body becomes stdin payload, acked immediately, run recorded async. - event_pattern (document.*, *, exact type) fires the function detached on matching publishEvent — never blocks realtime/webhook fan-out. - One executeFunction path serves manual/schedule/hook/event; run rows record the trigger source. - Backend image now ships bun 1.3.14 so Functions work under compose. Dashboard: job target picker, hook function mode, event-pattern field. Verified live: job run → success (status_code 0), hook POST → run, document.created → event run with correct payload. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
c094afad65
commit
a84049b8fc
40 files changed
+716
-157
No files matched your search
@@ -4,11 +4,13 @@ import {
|
||||
AutomationService,
|
||||
CreateInboundHookRequest,
|
||||
CreateIntegrationRequest,
|
||||
FunctionsService,
|
||||
InboundService,
|
||||
IntegrationsService,
|
||||
UpsertAlertRuleRequest,
|
||||
WebhooksService,
|
||||
type AlertRule,
|
||||
type Function as PrimoraFunction,
|
||||
type InboundHook,
|
||||
type ScheduledJob,
|
||||
type Integration,
|
||||
@@ -74,7 +76,8 @@ export function IntegrationsPage(props: IntegrationsPageProps) {
|
||||
const [showCreateWebhook, setShowCreateWebhook] = createSignal(false);
|
||||
const [showCreateAlert, setShowCreateAlert] = createSignal(false);
|
||||
const [showCreateInbound, setShowCreateInbound] = createSignal(false);
|
||||
const [inboundForm, setInboundForm] = createSignal({ name: "", mode: CreateInboundHookRequest.mode.EVENT as CreateInboundHookRequest.mode, job_id: "", secret: "" });
|
||||
const [inboundForm, setInboundForm] = createSignal({ name: "", mode: CreateInboundHookRequest.mode.EVENT as CreateInboundHookRequest.mode, job_id: "", function_id: "", secret: "" });
|
||||
const [functions, setFunctions] = createSignal<PrimoraFunction[]>([]);
|
||||
const [copiedUrl, setCopiedUrl] = createSignal("");
|
||||
const [alertForm, setAlertForm] = createSignal({
|
||||
name: "",
|
||||
@@ -97,18 +100,20 @@ export function IntegrationsPage(props: IntegrationsPageProps) {
|
||||
setLoading(true);
|
||||
setError("");
|
||||
try {
|
||||
const [int, hooks, rules, inbound, jobs] = await Promise.all([
|
||||
const [int, hooks, rules, inbound, jobs, fns] = await Promise.all([
|
||||
intSvc(props.demoMode).listIntegrations({ projectId: props.projectID }),
|
||||
hookSvc(props.demoMode).listWebhooks({ projectId: props.projectID }),
|
||||
props.demoMode ? Promise.resolve({ items: [] }) : AlertsService.listAlertRules({ projectId: props.projectID }),
|
||||
props.demoMode ? Promise.resolve({ items: [] }) : InboundService.listInboundHooks({ projectId: props.projectID }),
|
||||
props.demoMode ? Promise.resolve({ items: [] }) : AutomationService.listScheduledJobs({ projectId: props.projectID }),
|
||||
props.demoMode ? Promise.resolve({ items: [] }) : FunctionsService.listFunctions({ projectId: props.projectID }),
|
||||
]);
|
||||
setIntegrations(int.items ?? []);
|
||||
setWebhooks(hooks.items ?? []);
|
||||
setAlertRules(rules.items ?? []);
|
||||
setInboundHooks(inbound.items ?? []);
|
||||
setScheduledJobs(jobs.items ?? []);
|
||||
setFunctions(fns.items ?? []);
|
||||
} catch (e) {
|
||||
setError(err(e));
|
||||
} finally {
|
||||
@@ -268,11 +273,12 @@ export function IntegrationsPage(props: IntegrationsPageProps) {
|
||||
name: form.name.trim(),
|
||||
mode: form.mode,
|
||||
job_id: form.mode === CreateInboundHookRequest.mode.JOB ? form.job_id : undefined,
|
||||
function_id: form.mode === CreateInboundHookRequest.mode.FUNCTION ? form.function_id : undefined,
|
||||
secret: form.secret.trim() || undefined,
|
||||
},
|
||||
});
|
||||
setShowCreateInbound(false);
|
||||
setInboundForm({ name: "", mode: CreateInboundHookRequest.mode.EVENT, job_id: "", secret: "" });
|
||||
setInboundForm({ name: "", mode: CreateInboundHookRequest.mode.EVENT, job_id: "", function_id: "", secret: "" });
|
||||
}, "Inbound hook created");
|
||||
};
|
||||
|
||||
@@ -706,7 +712,9 @@ export function IntegrationsPage(props: IntegrationsPageProps) {
|
||||
<tr>
|
||||
<td class="font-medium">{hook.name}</td>
|
||||
<td>
|
||||
<Badge variant="neutral">{hook.mode === "job" ? "job trigger" : "event"}</Badge>
|
||||
<Badge variant="neutral">
|
||||
{hook.mode === "job" ? "job trigger" : hook.mode === "function" ? `ƒ ${functions().find((f) => f.id === hook.function_id)?.name ?? "function"}` : "event"}
|
||||
</Badge>
|
||||
<Show when={!hook.enabled}>
|
||||
{" "}<Badge variant="warning">disabled</Badge>
|
||||
</Show>
|
||||
@@ -943,8 +951,21 @@ export function IntegrationsPage(props: IntegrationsPageProps) {
|
||||
options={[
|
||||
{ value: "event", label: "Publish inbound.received event" },
|
||||
{ value: "job", label: "Trigger a scheduled job" },
|
||||
{ value: "function", label: "Invoke a function" },
|
||||
]}
|
||||
/>
|
||||
<Show when={inboundForm().mode === CreateInboundHookRequest.mode.FUNCTION}>
|
||||
<Select
|
||||
label="Function"
|
||||
value={inboundForm().function_id}
|
||||
onChange={(e) => setInboundForm((c) => ({ ...c, function_id: e.currentTarget.value }))}
|
||||
options={[
|
||||
{ value: "", label: "Select a function…" },
|
||||
...functions().map((f) => ({ value: f.id, label: f.name })),
|
||||
]}
|
||||
/>
|
||||
<p class="text-text-2 text-xs">The received body becomes the function's stdin payload.</p>
|
||||
</Show>
|
||||
<Show when={inboundForm().mode === CreateInboundHookRequest.mode.JOB}>
|
||||
<Select
|
||||
label="Job"
|
||||
|
||||
Reference in new issue
Block a user