diff --git a/apps/mobile/src/features/settings/SettingsScheduledTasksRouteScreen.tsx b/apps/mobile/src/features/settings/SettingsScheduledTasksRouteScreen.tsx
index b3a949e65e59..e8593ff407f0 100644
--- a/apps/mobile/src/features/settings/SettingsScheduledTasksRouteScreen.tsx
+++ b/apps/mobile/src/features/settings/SettingsScheduledTasksRouteScreen.tsx
@@ -4,7 +4,10 @@ import type {
ScheduledTask,
ScheduledTaskUpsertInput,
} from "@t3tools/contracts";
-import { resolveEnvironmentMachineKind } from "@t3tools/contracts";
+import {
+ MAX_WEBHOOK_DELIVERY_AGE_MINUTES,
+ resolveEnvironmentMachineKind,
+} from "@t3tools/contracts";
import type { MenuAction } from "@react-native-menu/menu";
import { DateTimePicker } from "@expo/ui/community/datetime-picker";
import {
@@ -12,6 +15,10 @@ import {
squashAtomCommandFailure,
type AtomCommandResult,
} from "@t3tools/client-runtime/state/runtime";
+import {
+ DEFAULT_WEBHOOK_PROMPT,
+ parseMaxDeliveryAge,
+} from "@t3tools/client-runtime/scheduled-task-webhook";
import {
useCallback,
useEffect,
@@ -59,7 +66,6 @@ import { SettingsSection } from "./components/SettingsSection";
import { useSettingsEnvironmentFilter, type SettingsTarget } from "./settings-environment-filter";
import {
editDraft,
- DEFAULT_WEBHOOK_PROMPT,
scheduledTaskDefaultModel,
scheduleFromDraft,
type ScheduledTaskDraft as Draft,
@@ -132,7 +138,7 @@ function FormField(props: {
readonly label: string;
readonly value: string;
readonly onChange: (value: string) => void;
- readonly keyboardType?: "decimal-pad";
+ readonly keyboardType?: "decimal-pad" | "number-pad";
readonly disabled?: boolean;
readonly placeholder?: string;
readonly borderTop?: boolean;
@@ -611,6 +617,16 @@ function TaskForm({
? { ...draft.schedule, signature: liveTask.schedule.signature }
: draft.schedule,
);
+ if (
+ draft.schedule.mode === "webhook" &&
+ parseMaxDeliveryAge(draft.schedule.maxDeliveryAgeMinutes) === undefined
+ ) {
+ Alert.alert(
+ "Invalid age limit",
+ `Enter whole minutes from 1 to ${MAX_WEBHOOK_DELIVERY_AGE_MINUTES}, or leave it blank.`,
+ );
+ return;
+ }
if (
!draft.title.trim() ||
!draft.prompt.trim() ||
@@ -823,7 +839,7 @@ function TaskForm({
options={[
{ value: "fixed_time", label: "At a time" },
{ value: "interval", label: "Interval" },
- { value: "webhook", label: "Webhook" },
+ { value: "webhook", label: "On webhook" },
]}
selected={draft.schedule.mode}
onSelect={(mode) => {
@@ -910,13 +926,31 @@ function TaskForm({
/>
>
) : draft.schedule.mode === "webhook" ? (
- {note}
+ {cloudLink.data.holdWebhooksWhileOffline
+ ? "Held for up to 24 hours while this environment is offline. "
+ : "Forwarded live. Requests fail while this environment is offline. "}
+
+ Change in Connections
+
+