import * as Haptics from "expo-haptics"; import { SymbolView } from "expo-symbols"; import type { EnvironmentId, ThreadId } from "@t3tools/contracts"; import { useNavigation } from "@react-navigation/native"; import { useMemo, useState } from "react"; import { Linking, Pressable, ScrollView, type ColorValue, View } from "react-native"; import { AppText as Text } from "../../components/AppText"; import type { ThreadFeedActivity } from "../../lib/threadActivity"; import { buildThreadActivityInspector } from "../../lib/threadActivityInspector"; import { resolveWorkspaceRelativeFilePath } from "../files/filePath"; import { threadEnvironment } from "../../state/threads"; import { useAtomCommand } from "../../state/use-atom-command"; import { useV2ItemSupport } from "../../state/v2-item-support"; import { buildThreadActivityFileParams } from "./threadActivityFileNavigation"; export function ThreadActivityInspector(props: { readonly activity: ThreadFeedActivity; readonly currentThreadId: ThreadId; readonly environmentId: EnvironmentId; readonly iconColor: ColorValue; readonly workspaceRoot?: string | null; }) { const navigation = useNavigation(); const row = props.activity.projectedItem; const support = useV2ItemSupport({ environmentId: props.environmentId, sourceThreadId: row.sourceThreadId, sourceItemId: row.sourceItemId, }); const model = useMemo( () => buildThreadActivityInspector(props.activity, support, props.currentThreadId), [props.activity, props.currentThreadId, support], ); const revertCheckpoint = useAtomCommand(threadEnvironment.revertCheckpoint, { label: "checkpoint rollback", reportFailure: true, }); const [rollingBack, setRollingBack] = useState(false); return ( {model.fields.map((field) => ( {field.label} {field.value} ))} {model.blocks.map((block) => ( {block.label} {block.value} ))} {model.fileLinks.length > 0 ? ( Files {model.fileLinks.map((link) => { const relativePath = resolveWorkspaceRelativeFilePath(props.workspaceRoot, link.path) ?? (link.path.startsWith("/") ? null : link.path); return ( { if (!relativePath) return; void Haptics.selectionAsync(); navigation.navigate( "ThreadFile", buildThreadActivityFileParams({ environmentId: props.environmentId, currentThreadId: props.currentThreadId, activitySourceThreadId: row.sourceThreadId, relativePath, line: link.line, }), ); }} className="min-h-9 flex-row items-center gap-2 rounded-md border border-adaptive-neutral-300-a60-white-a12 px-2.5 py-1.5" > {link.label} ); })} ) : null} {model.webLinks.length > 0 ? ( Sources {model.webLinks.map((link) => ( void Linking.openURL(link.url)} className="min-h-9 flex-row items-center gap-2 rounded-md border border-adaptive-neutral-300-a60-white-a12 px-2.5 py-1.5" > {link.label} ))} ) : null} {model.rollbackTarget ? ( { setRollingBack(true); void Haptics.selectionAsync(); void revertCheckpoint({ environmentId: props.environmentId, input: { threadId: model.rollbackTarget!.threadId, checkpointId: model.rollbackTarget!.checkpointId, scopeId: model.rollbackTarget!.scopeId, }, }).finally(() => setRollingBack(false)); }} className="min-h-10 flex-row items-center justify-center gap-2 rounded-lg border border-adaptive-neutral-300-a60-white-a12 px-3 py-2" > {rollingBack ? "Rolling back…" : "Roll back to checkpoint"} ) : null} Structured details {model.structuredDetails} ); }