import { SymbolView } from "../../components/AppSymbol"; import { connectionStatusText } from "@t3tools/client-runtime/connection"; import type { AtomCommandResult } from "@t3tools/client-runtime/state/runtime"; import { type EnvironmentId, resolveEnvironmentMachineKind } from "@t3tools/contracts"; import { useAtomValue } from "@effect/atom-react"; import * as Cause from "effect/Cause"; import { AsyncResult } from "effect/unstable/reactivity"; import { useCallback, useState } from "react"; import { Alert, Pressable, View } from "react-native"; import Animated, { FadeIn, FadeOut, LinearTransition } from "react-native-reanimated"; import { AppText as Text, AppTextInput as TextInput } from "../../components/AppText"; import { EnvironmentMachineSymbol } from "../../components/EnvironmentMachineSymbol"; import { cn } from "../../lib/cn"; import { copyTextWithHaptic } from "../../lib/copyTextWithHaptic"; import type { ConnectedEnvironmentSummary } from "../../state/remote-runtime-types"; import { serverEnvironment } from "../../state/server"; import { ConnectionStatusDot } from "./ConnectionStatusDot"; function connectionStatusLabel(environment: ConnectedEnvironmentSummary): string | null { return connectionStatusText({ phase: environment.connectionState, error: environment.connectionError, traceId: environment.connectionErrorTraceId, }); } export function ConnectionEnvironmentRow(props: { readonly environment: ConnectedEnvironmentSummary; readonly expanded: boolean; readonly onToggle: () => void; readonly onReconnect: (environmentId: EnvironmentId) => void; readonly onRemove: (environmentId: EnvironmentId) => void; readonly onUpdate: ( environmentId: EnvironmentId, updates: { readonly label: string; readonly displayUrl: string }, ) => Promise>; }) { const [label, setLabel] = useState(props.environment.environmentLabel); const [url, setUrl] = useState(props.environment.displayUrl); const serverConfig = useAtomValue( serverEnvironment.configValueAtom(props.environment.environmentId), ); const statusLabel = connectionStatusLabel(props.environment); const statusTraceId = props.environment.connectionErrorTraceId; const hasConnectionFailure = props.environment.connectionError !== null; const isRetrying = props.environment.connectionState === "connecting" || props.environment.connectionState === "reconnecting"; const handleSave = useCallback(async () => { const result = await props.onUpdate(props.environment.environmentId, { label: label.trim(), displayUrl: url.trim(), }); if (AsyncResult.isSuccess(result)) { props.onToggle(); return; } const error = Cause.squash(result.cause); Alert.alert( "Could not update environment", error instanceof Error ? error.message : "The environment could not be updated.", ); }, [label, url, props]); return ( {props.environment.environmentLabel} {props.environment.displayUrl} {statusLabel ? ( {statusLabel} {statusTraceId ? ( <> {" Trace ID: "} { event.stopPropagation(); copyTextWithHaptic(statusTraceId, { target: "connection-trace-id" }); }} onPress={(event) => { event.stopPropagation(); }} > {statusTraceId} ) : null} ) : null} {props.expanded ? ( {props.environment.isRelayManaged ? ( Managed by T3 Connect. Tunnel details update automatically. ) : ( <> Label URL )} {props.environment.isRelayManaged ? null : ( Save )} props.onReconnect(props.environment.environmentId)} > props.onRemove(props.environment.environmentId)} > ) : null} ); }