Repository navigation
Expand file tree
/
Copy pathOutdatedServerUpdateSection.tsx
More file actions
118 lines (113 loc) · 4.24 KB
/
Copy pathOutdatedServerUpdateSection.tsx
File metadata and controls
118 lines (113 loc) · 4.24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import { useAtom, useAtomValue } from "@effect/atom-react";
import { squashAtomCommandFailure } from "@t3tools/client-runtime/state/runtime";
import type { EnvironmentId } from "@t3tools/contracts";
import { AsyncResult } from "effect/reactivity";
import { useState } from "react";
import { View } from "react-native";
import { AppText as Text } from "../../components/ui/AppText";
import * as Dialog from "../../components/ui/Dialog";
import {
describeOutdatedServer,
serverEnvironment,
updateOutdatedServer,
} from "../../state/server";
import { useAtomCommand } from "../../state/use-atom-command";
import { ListActionRow as SettingsActionRow } from "../../components/ui/ListActionRow";
import { SettingsSection } from "./components/SettingsSection";
import {
environmentReleaseCheckAtom,
releaseCheckError,
releaseCheckValue,
} from "./environmentUpdateCheck";
export function OutdatedServerUpdateSection({
environmentId,
label,
}: {
readonly environmentId: EnvironmentId;
readonly label: string;
}) {
const describe = useAtomCommand(describeOutdatedServer, { reportFailure: false });
const update = useAtomCommand(updateOutdatedServer, { reportFailure: false });
const state = useAtomValue(serverEnvironment.updateStateAtom(environmentId));
const [checkResult, startCheck] = useAtom(environmentReleaseCheckAtom(environmentId));
const release = releaseCheckValue(checkResult);
const checking = checkResult.waiting;
// Starting an update replaces a failed check's message with the update's own state.
const [checkErrorDismissed, setCheckErrorDismissed] = useState(false);
const error = checkErrorDismissed ? null : releaseCheckError(checkResult);
const busy = checking || state.status === "running";
function check() {
if (busy) return;
setCheckErrorDismissed(false);
startCheck(async () => {
const description = await describe(environmentId);
if (AsyncResult.isFailure(description)) throw squashAtomCommandFailure(description);
return description.value.serverVersion;
});
}
function requestUpdate() {
const targetVersion = release?.targetVersion;
if (busy || !release || !targetVersion) return;
Dialog.alert(
`Update ${label}?`,
`Install T3 Code ${targetVersion}. T3 Code restarts on that machine and reconnects. Running threads may be interrupted.`,
[
{ text: "Cancel", style: "cancel" },
{
text: "Update",
onPress: () => {
setCheckErrorDismissed(true);
void update({
environmentId,
input: { targetVersion },
fromVersion: release.fromVersion,
});
},
},
],
);
}
return (
<SettingsSection title="T3 Code">
<View className="gap-1 p-4">
<Text className="text-base text-foreground">
{release ? `Version ${release.fromVersion}` : "Update required"}
</Text>
<Text className="text-sm text-foreground-muted">
{state.status === "running"
? state.stage === "resuming"
? "Restarting and reconnecting…"
: state.stage === "installing"
? "Installing update…"
: "Downloading update…"
: release
? release.targetVersion
? `Version ${release.targetVersion} is available.`
: "No newer version is available yet."
: "This app needs a newer version of T3 Code on this machine."}
</Text>
{error || state.status === "failed" ? (
<Text selectable accessibilityRole="alert" className="text-sm text-danger-foreground">
{error ?? (state.status === "failed" ? state.message : null)}
</Text>
) : null}
</View>
<SettingsActionRow
icon="arrow.clockwise"
label="Check for updates"
disabled={busy}
loading={checking}
onPress={check}
/>
{release?.targetVersion ? (
<SettingsActionRow
icon="arrow.up.circle"
label={state.status === "failed" ? "Retry update" : `Update to ${release.targetVersion}`}
disabled={busy}
loading={state.status === "running"}
onPress={requestUpdate}
/>
) : null}
</SettingsSection>
);
}