import * as Haptics from "expo-haptics"; import { SymbolView } from "expo-symbols"; import { deriveThreadQueueWorkflowState } from "@t3tools/client-runtime/state/thread-workflows"; import type { EnvironmentId, RunId, ThreadId } from "@t3tools/contracts"; import { useMemo, useState } from "react"; import { Pressable, ScrollView, View } from "react-native"; import { AppText as Text } from "../../components/AppText"; import { useUniwindTheme } from "../../lib/useUniwindTheme"; import { threadEnvironment } from "../../state/threads"; import { useAtomCommand } from "../../state/use-atom-command"; import { useThreadProjection } from "../../state/use-thread-detail"; import { buildCancelQueuedRunCommand, resolveThreadQueueRowControls, } from "./threadQueueControlPresentation"; export function ThreadQueueControl(props: { readonly environmentId: EnvironmentId; readonly threadId: ThreadId; }) { const scoped = useThreadProjection(props); const workflow = useMemo( () => (scoped ? deriveThreadQueueWorkflowState(scoped.projection) : null), [scoped], ); const reorder = useAtomCommand(threadEnvironment.reorderQueuedRun, "reorder queued message"); const promote = useAtomCommand(threadEnvironment.promoteQueuedRun, "promote queued message"); const cancel = useAtomCommand(threadEnvironment.cancelQueuedRun, "cancel queued message"); const [busyRunId, setBusyRunId] = useState(null); const theme = useUniwindTheme(); const iconColor = theme["--color-icon-subtle"]; if (!workflow || workflow.queuedRuns.length === 0) return null; const move = async (runId: RunId, beforeRunId: RunId | null) => { setBusyRunId(runId); void Haptics.selectionAsync(); await reorder({ environmentId: props.environmentId, input: { threadId: props.threadId, runId, beforeRunId }, }); setBusyRunId(null); }; const steer = async (queuedRunId: RunId) => { if (!workflow.activeRun || !workflow.canPromoteToSteer) return; setBusyRunId(queuedRunId); void Haptics.selectionAsync(); await promote({ environmentId: props.environmentId, input: { threadId: props.threadId, queuedRunId, targetRunId: workflow.activeRun.id, }, }); setBusyRunId(null); }; const dismiss = async (runId: RunId) => { setBusyRunId(runId); void Haptics.selectionAsync(); await cancel( buildCancelQueuedRunCommand({ environmentId: props.environmentId, runId, threadId: props.threadId, }), ); setBusyRunId(null); }; return ( Queue {workflow.queuedRuns.length} {workflow.queuedRuns.map(({ run, text }, index) => { const controls = resolveThreadQueueRowControls({ busy: busyRunId !== null, canPromoteToSteer: workflow.canPromoteToSteer, canReorder: workflow.canReorder, index, queuedCount: workflow.queuedRuns.length, text, }); return ( {index + 1} {controls.displayText} void move(run.id, workflow.queuedRuns[index - 1]?.run.id ?? null)} className="h-9 w-9 items-center justify-center disabled:opacity-30" > void move(run.id, workflow.queuedRuns[index + 2]?.run.id ?? null)} className="h-9 w-9 items-center justify-center disabled:opacity-30" > void steer(run.id)} className="min-h-8 flex-row items-center gap-1 rounded-lg border border-adaptive-neutral-300-a60-white-a12 px-2 disabled:opacity-30" > Steer void dismiss(run.id)} className="h-9 w-9 items-center justify-center disabled:opacity-30" > ); })} ); }