| author | |
| committer | |
| log | 05a8c6016a4070b92f5d51e7a79b9c76814947df |
| tree | 43a8c20dfe0299c5525db554a0f3e3bf69e59920 |
| parent | 5a39013313a7e6e9d6fbeeb915b8c176ea3dd126 |
| signature | Signed by PGP key B5690EEEBB952194 |
4 files changed, 69 insertions(+), 51 deletions(-)
apps/mobile/src/features/connection/CloudEnvironmentRows.tsx+10-17| ... | @@ -1,3 +1,4 @@ | ... | @@ -1,3 +1,4 @@ |
| 1 | import { ConnectionTraceId } from "./ConnectionTraceId"; | ||
| 1 | import { useAuth } from "@clerk/expo"; | 2 | import { useAuth } from "@clerk/expo"; |
| 2 | import { SymbolView } from "../../components/AppSymbol"; | 3 | import { SymbolView } from "../../components/AppSymbol"; |
| 3 | import { | 4 | import { |
| ... | @@ -405,23 +406,15 @@ function CloudEnvironmentRowShell(props: { | ... | @@ -405,23 +406,15 @@ function CloudEnvironmentRowShell(props: { |
| 405 | > | 406 | > |
| 406 | {statusText} | 407 | {statusText} |
| 407 | {errorTraceId ? ( | 408 | {errorTraceId ? ( |
| 408 | <> | 409 | <ConnectionTraceId |
| 409 | {" Trace ID: "} | 410 | traceId={errorTraceId} |
| 410 | <Text | 411 | tone={ |
| 411 | accessibilityHint="Copies the trace ID" | 412 | props.connectionError && props.connectionState !== "unsupported" |
| 412 | accessibilityRole="button" | 413 | ? "danger" |
| 413 | className={cn("text-xs underline decoration-dotted", statusClassName)} | 414 | : "muted" |
| 414 | onLongPress={(event) => { | 415 | } |
| 415 | event.stopPropagation(); | 416 | activation="longPress" |
| 416 | copyTextWithHaptic(errorTraceId, { target: "connection-trace-id" }); | 417 | /> |
| 417 | }} | ||
| 418 | onPress={(event) => { | ||
| 419 | event.stopPropagation(); | ||
| 420 | }} | ||
| 421 | > | ||
| 422 | {errorTraceId} | ||
| 423 | </Text> | ||
| 424 | </> | ||
| 425 | ) : null} | 418 | ) : null} |
| 426 | </Text> | 419 | </Text> |
| 427 | {errorCanExpand ? ( | 420 | {errorCanExpand ? ( |
apps/mobile/src/features/connection/ConnectionEnvironmentRow.tsx+6-18| ... | @@ -1,3 +1,4 @@ | ... | @@ -1,3 +1,4 @@ |
| 1 | import { ConnectionTraceId } from "./ConnectionTraceId"; | ||
| 1 | import { SymbolView } from "../../components/AppSymbol"; | 2 | import { SymbolView } from "../../components/AppSymbol"; |
| 2 | import { connectionStatusText } from "@t3tools/client-runtime/connection"; | 3 | import { connectionStatusText } from "@t3tools/client-runtime/connection"; |
| 3 | import type { AtomCommandResult } from "@t3tools/client-runtime/state/runtime"; | 4 | import type { AtomCommandResult } from "@t3tools/client-runtime/state/runtime"; |
| ... | @@ -15,7 +16,6 @@ import { MaterialButton } from "../../components/MaterialButton"; | ... | @@ -15,7 +16,6 @@ import { MaterialButton } from "../../components/MaterialButton"; |
| 15 | import { MaterialIconButton } from "../../components/MaterialIconButton"; | 16 | import { MaterialIconButton } from "../../components/MaterialIconButton"; |
| 16 | import { ThemedSwitch } from "../../components/ThemedSwitch"; | 17 | import { ThemedSwitch } from "../../components/ThemedSwitch"; |
| 17 | import { cn } from "../../lib/cn"; | 18 | import { cn } from "../../lib/cn"; |
| 18 | import { copyTextWithHaptic } from "../../lib/copyTextWithHaptic"; | ||
| 19 | import type { ConnectedEnvironmentSummary } from "../../state/remote-runtime-types"; | 19 | import type { ConnectedEnvironmentSummary } from "../../state/remote-runtime-types"; |
| 20 | import { serverEnvironment } from "../../state/server"; | 20 | import { serverEnvironment } from "../../state/server"; |
| 21 | import { ConnectionStatusDot } from "./ConnectionStatusDot"; | 21 | import { ConnectionStatusDot } from "./ConnectionStatusDot"; |
| ... | @@ -114,23 +114,11 @@ export function ConnectionEnvironmentRow(props: { | ... | @@ -114,23 +114,11 @@ export function ConnectionEnvironmentRow(props: { |
| 114 | > | 114 | > |
| 115 | {statusLabel} | 115 | {statusLabel} |
| 116 | {statusTraceId ? ( | 116 | {statusTraceId ? ( |
| 117 | <> | 117 | <ConnectionTraceId |
| 118 | {" Trace ID: "} | 118 | traceId={statusTraceId} |
| 119 | <Text | 119 | tone={hasConnectionFailure ? "danger" : "muted"} |
| 120 | accessibilityHint="Copies the trace ID" | 120 | activation="longPress" |
| 121 | accessibilityRole="button" | 121 | /> |
| 122 | className="underline decoration-dotted" | ||
| 123 | onLongPress={(event) => { | ||
| 124 | event.stopPropagation(); | ||
| 125 | copyTextWithHaptic(statusTraceId, { target: "connection-trace-id" }); | ||
| 126 | }} | ||
| 127 | onPress={(event) => { | ||
| 128 | event.stopPropagation(); | ||
| 129 | }} | ||
| 130 | > | ||
| 131 | {statusTraceId} | ||
| 132 | </Text> | ||
| 133 | </> | ||
| 134 | ) : null} | 122 | ) : null} |
| 135 | </Text> | 123 | </Text> |
| 136 | ) : null} | 124 | ) : null} |
apps/mobile/src/features/connection/ConnectionTraceId.tsx created+51| ... | @@ -0,0 +1,51 @@ | ||
| 1 | import { AppText as Text } from "../../components/AppText"; | ||
| 2 | import { cn } from "../../lib/cn"; | ||
| 3 | import { copyTextWithHaptic } from "../../lib/copyTextWithHaptic"; | ||
| 4 | |||
| 5 | /** Inline trace control; disclosure rows reserve ordinary taps for their own navigation. */ | ||
| 6 | export function ConnectionTraceId({ | ||
| 7 | traceId, | ||
| 8 | tone = "muted", | ||
| 9 | activation = "press", | ||
| 10 | }: { | ||
| 11 | readonly traceId: string; | ||
| 12 | readonly tone?: "muted" | "danger"; | ||
| 13 | readonly activation?: "press" | "longPress"; | ||
| 14 | }) { | ||
| 15 | const copy = () => copyTextWithHaptic(traceId, { target: "connection-trace-id" }); | ||
| 16 | return ( | ||
| 17 | <> | ||
| 18 | {" Trace ID: "} | ||
| 19 | <Text | ||
| 20 | accessibilityHint={ | ||
| 21 | activation === "longPress" ? "Long press to copy the trace ID" : "Copies the trace ID" | ||
| 22 | } | ||
| 23 | accessibilityLabel={`Copy trace ID ${traceId}`} | ||
| 24 | accessibilityRole="button" | ||
| 25 | accessibilityActions={[{ name: "activate", label: "Copy trace ID" }]} | ||
| 26 | onAccessibilityAction={(event) => { | ||
| 27 | event.stopPropagation(); | ||
| 28 | if (event.nativeEvent.actionName === "activate") copy(); | ||
| 29 | }} | ||
| 30 | className={cn( | ||
| 31 | "underline decoration-dotted", | ||
| 32 | tone === "danger" ? "text-danger-foreground" : "text-foreground-muted", | ||
| 33 | )} | ||
| 34 | onLongPress={ | ||
| 35 | activation === "longPress" | ||
| 36 | ? (event) => { | ||
| 37 | event.stopPropagation(); | ||
| 38 | copy(); | ||
| 39 | } | ||
| 40 | : undefined | ||
| 41 | } | ||
| 42 | onPress={(event) => { | ||
| 43 | event.stopPropagation(); | ||
| 44 | if (activation === "press") copy(); | ||
| 45 | }} | ||
| 46 | > | ||
| 47 | {traceId} | ||
| 48 | </Text> | ||
| 49 | </> | ||
| 50 | ); | ||
| 51 | } | ||
apps/mobile/src/features/connection/EnvironmentConnectionNotice.tsx+2-16| ... | @@ -1,3 +1,4 @@ | ... | @@ -1,3 +1,4 @@ |
| 1 | import { ConnectionTraceId } from "./ConnectionTraceId"; | ||
| 1 | import { | 2 | import { |
| 2 | type EnvironmentConnectionPhase, | 3 | type EnvironmentConnectionPhase, |
| 3 | type EnvironmentConnectionPresentation, | 4 | type EnvironmentConnectionPresentation, |
| ... | @@ -6,7 +7,6 @@ import { SymbolView } from "../../components/AppSymbol"; | ... | @@ -6,7 +7,6 @@ import { SymbolView } from "../../components/AppSymbol"; |
| 6 | import { ActivityIndicator, Pressable, View } from "react-native"; | 7 | import { ActivityIndicator, Pressable, View } from "react-native"; |
| 7 | 8 | ||
| 8 | import { AppText as Text } from "../../components/AppText"; | 9 | import { AppText as Text } from "../../components/AppText"; |
| 9 | import { copyTextWithHaptic } from "../../lib/copyTextWithHaptic"; | ||
| 10 | 10 | ||
| 11 | function noticeTitle(phase: EnvironmentConnectionPhase, environmentLabel: string): string { | 11 | function noticeTitle(phase: EnvironmentConnectionPhase, environmentLabel: string): string { |
| 12 | switch (phase) { | 12 | switch (phase) { |
| ... | @@ -81,21 +81,7 @@ export function EnvironmentConnectionNotice(props: { | ... | @@ -81,21 +81,7 @@ export function EnvironmentConnectionNotice(props: { |
| 81 | <Text className="text-center text-sm leading-normal text-foreground-muted"> | 81 | <Text className="text-center text-sm leading-normal text-foreground-muted"> |
| 82 | {noticeDetail(props.connection.phase, props.resourceName, props.connection.error)} | 82 | {noticeDetail(props.connection.phase, props.resourceName, props.connection.error)} |
| 83 | {props.connection.traceId ? ( | 83 | {props.connection.traceId ? ( |
| 84 | <> | 84 | <ConnectionTraceId traceId={props.connection.traceId} /> |
| 85 | {" Trace ID: "} | ||
| 86 | <Text | ||
| 87 | accessibilityHint="Copies the trace ID" | ||
| 88 | accessibilityRole="button" | ||
| 89 | className="underline decoration-dotted" | ||
| 90 | onPress={() => | ||
| 91 | copyTextWithHaptic(props.connection.traceId!, { | ||
| 92 | target: "connection-trace-id", | ||
| 93 | }) | ||
| 94 | } | ||
| 95 | > | ||
| 96 | {props.connection.traceId} | ||
| 97 | </Text> | ||
| 98 | </> | ||
| 99 | ) : null} | 85 | ) : null} |
| 100 | </Text> | 86 | </Text> |
| 101 | 87 |