+
+ {cloud.pending && Talking to the cloud…}
+
+ {!cloud.pending && cloud.refusal && {cloud.refusal}}
+
+ {!cloud.pending && !cloud.refusal && availability.kind === 'checking' && (
+ Checking what your account allows…
+ )}
+
+ {!cloud.pending && !cloud.refusal && availability.kind === 'unknown' && (
+
+
+ Can't reach the cloud, so we can't tell whether this can run there.
+ {onCloud
+ ? ' It stays scheduled in the cloud; nothing changed.'
+ : ' This workflow still runs on this device.'}
+
+
+
+ )}
+
+ {!cloud.pending && !cloud.refusal && availability.kind === 'blocked' && (
+
+
+ {availability.reason}
+ {availability.action === 'sign_in' && (
+
+ )}
+ {availability.action === 'plans' && (
+
+ )}
+
+
+ )}
+
+ {!cloud.pending && !cloud.refusal && availability.kind === 'available' && !onCloud && (
+ Cloud runs fire on our servers, so they still happen with this app closed.
+ )}
+
+ {!cloud.pending && onCloud && hosted === null && cloud.probe.phase === 'answered' && cloud.probe.status.state === 'ready' && (
+
+
+ This is set to run in the cloud, but the cloud has no copy of it, so nothing is running it.
+
+
+
+ )}
+
+ {!cloud.pending && onCloud && hosted && !hosted.in_sync && (
+
+
+ The cloud is still running the version you sent it. Your later edits are not up there yet.
+
+
+
+ )}
+
+ {onCloud && hosted && {nextCloudRunText(hosted)}}
+ {usage && {usage}}
+
+ );
+};
+
+export default CloudRunSection;
diff --git a/frontend/src/app/pages/Workflows/app/ScheduleCard.tsx b/frontend/src/app/pages/Workflows/app/ScheduleCard.tsx
index a9ab59a5..94c20975 100644
--- a/frontend/src/app/pages/Workflows/app/ScheduleCard.tsx
+++ b/frontend/src/app/pages/Workflows/app/ScheduleCard.tsx
@@ -7,6 +7,8 @@ import {
freqOf, patchForFreq, intervalMinutes, timeInputValue, parseTimeInput, ordinal, nextRunText, type Freq,
} from './model';
import { useWorkflowPatch } from './useWorkflowPatch';
+import { useCloudStatus } from './useCloudStatus';
+import CloudRunSection from './CloudRunSection';
import RepeatField from './RepeatField';
const FREQS: Array<[Freq, string]> = [['daily', 'Daily'], ['weekly', 'Weekly'], ['monthly', 'Monthly'], ['interval', 'Interval']];
@@ -15,9 +17,11 @@ const DAY_LABELS: Array<[string, number]> = [['S', 0], ['M', 1], ['T', 2], ['W',
const ScheduleCard: React.FC<{ workflow: Workflow }> = ({ workflow }) => {
const WC = useWC();
const patch = useWorkflowPatch();
+ const cloud = useCloudStatus(workflow);
const sched = workflow.schedule;
const freq = freqOf(sched);
const enabled = sched.enabled;
+ const onCloud = workflow.execution_target === 'cloud';
const patchSched = (p: Partial) => patch(workflow, { schedule: { ...sched, ...p } });
@@ -32,6 +36,11 @@ const ScheduleCard: React.FC<{ workflow: Workflow }> = ({ workflow }) => {
// Turning a weekly schedule on with no days picked is "unconfigured", so the backend silently forces it back off and the switch looks dead. Seed today's weekday so the default Weekly 9am toggles on (and stays on) in one click.
const toggleEnabled = () => {
+ // While the cloud holds the timer, this switch is the CLOUD's switch: flipping only our copy would pause nothing.
+ if (onCloud) {
+ cloud.choose('cloud', !enabled);
+ return;
+ }
if (!enabled && sched.repeat_unit === 'week' && sched.on_days.length === 0) {
patchSched({ enabled: true, on_days: [new Date().getDay()] });
} else {
@@ -197,16 +206,21 @@ const ScheduleCard: React.FC<{ workflow: Workflow }> = ({ workflow }) => {
{describeSchedule(sched)}
-
-
- Next run {nextRunText(workflow, workflow.next_run_at ? new Date(workflow.next_run_at) : null)}
-
+ {/* On cloud our copy of next_run_at is a mirror that only refreshes on a probe, so the cloud section prints the time it just fetched instead. */}
+ {!onCloud && (
+
+
+ Next run {nextRunText(workflow, workflow.next_run_at ? new Date(workflow.next_run_at) : null)}
+