this repo has no description
1import React from "@moonlight-mod/wp/react";
2import * as Components from "@moonlight-mod/wp/discord/components/common/index";
3import { useStateFromStores, useStateFromStoresObject } from "@moonlight-mod/wp/discord/packages/flux";
4import spacepack from "@moonlight-mod/wp/spacepack_spacepack";
5import { MoonbaseSettingsStore } from "@moonlight-mod/wp/moonbase_stores";
6import { RepositoryManifest, UpdateState } from "../types";
7
8const { Button, TabBar } = Components;
9const TabBarClasses = spacepack.findByCode(/tabBar:"tabBar_[a-z0-9]+",tabBarItem:"tabBarItem_[a-z0-9]+"/)[0].exports;
10
11const logger = moonlight.getLogger("moonbase/crashScreen");
12
13type ErrorState = {
14 error: Error;
15 info: {
16 componentStack: string;
17 };
18 __moonlight_update?: UpdateState;
19};
20
21type WrapperProps = {
22 action: React.ReactNode;
23 state: ErrorState;
24};
25
26type UpdateCardProps = {
27 id: number;
28 ext: {
29 version: string;
30 download: string;
31 updateManifest: RepositoryManifest;
32 };
33};
34
35const updateStrings: Record<UpdateState, string> = {
36 [UpdateState.Ready]: "A new version of moonlight is available.",
37 [UpdateState.Working]: "Updating moonlight...",
38 [UpdateState.Installed]: "Updated moonlight. Click Reload to apply changes.",
39 [UpdateState.Failed]: "Failed to update moonlight. Please use the installer."
40};
41const buttonStrings: Record<UpdateState, string> = {
42 [UpdateState.Ready]: "Update moonlight",
43 [UpdateState.Working]: "Updating moonlight...",
44 [UpdateState.Installed]: "",
45 [UpdateState.Failed]: "Update failed"
46};
47const extensionButtonStrings: Record<UpdateState, string> = {
48 [UpdateState.Ready]: "Update",
49 [UpdateState.Working]: "Updating...",
50 [UpdateState.Installed]: "Updated",
51 [UpdateState.Failed]: "Update failed"
52};
53
54function ExtensionUpdateCard({ id, ext }: UpdateCardProps) {
55 const [state, setState] = React.useState(UpdateState.Ready);
56 const installed = useStateFromStores([MoonbaseSettingsStore], () => MoonbaseSettingsStore.getExtension(id), [id]);
57
58 return (
59 <div className="moonbase-crash-extensionCard">
60 <div className="moonbase-crash-extensionCard-meta">
61 <div className="moonbase-crash-extensionCard-title">
62 {ext.updateManifest.meta?.name ?? ext.updateManifest.id}
63 </div>
64 <div className="moonbase-crash-extensionCard-version">{`v${installed?.manifest?.version ?? "???"} -> v${
65 ext.version
66 }`}</div>
67 </div>
68 <div className="moonbase-crash-extensionCard-button">
69 <Button
70 color={Button.Colors.GREEN}
71 disabled={state !== UpdateState.Ready}
72 onClick={() => {
73 setState(UpdateState.Working);
74 MoonbaseSettingsStore.installExtension(id)
75 .then(() => setState(UpdateState.Installed))
76 .catch(() => setState(UpdateState.Failed));
77 }}
78 >
79 {extensionButtonStrings[state]}
80 </Button>
81 </div>
82 </div>
83 );
84}
85
86export function wrapAction({ action, state }: WrapperProps) {
87 const [tab, setTab] = React.useState("crash");
88
89 const { updates, updateCount } = useStateFromStoresObject([MoonbaseSettingsStore], () => {
90 const { updates } = MoonbaseSettingsStore;
91 return {
92 updates: Object.entries(updates),
93 updateCount: Object.keys(updates).length
94 };
95 });
96
97 return (
98 <div className="moonbase-crash-wrapper">
99 {action}
100 <TabBar
101 className={`${TabBarClasses.tabBar} moonbase-crash-tabs`}
102 type="top"
103 selectedItem={tab}
104 onItemSelect={(v) => setTab(v)}
105 >
106 <TabBar.Item className={TabBarClasses.tabBarItem} id="crash">
107 Crash Details
108 </TabBar.Item>
109 <TabBar.Item className={TabBarClasses.tabBarItem} id="extensions" disabled={updateCount === 0}>
110 {`Extension Updates (${updateCount})`}
111 </TabBar.Item>
112 </TabBar>
113 {tab === "crash" ? (
114 <div className="moonbase-crash-details-wrapper">
115 <pre className="moonbase-crash-details">
116 <code>
117 {state.error.stack}
118 {"\n\nComponent stack:"}
119 {state.info.componentStack}
120 </code>
121 </pre>
122 </div>
123 ) : null}
124 {tab === "extensions" ? (
125 <div className="moonbase-crash-extensions">
126 {updates.map(([id, ext]) => (
127 <ExtensionUpdateCard id={Number(id)} ext={ext} />
128 ))}
129 </div>
130 ) : null}
131 </div>
132 );
133}
134
135export function UpdateText({ state, setState }: { state: ErrorState; setState: (state: ErrorState) => void }) {
136 if (!state.__moonlight_update) {
137 setState({
138 ...state,
139 __moonlight_update: UpdateState.Ready
140 });
141 }
142 const newVersion = useStateFromStores([MoonbaseSettingsStore], () => MoonbaseSettingsStore.newVersion);
143
144 return newVersion == null ? null : (
145 <p>{state.__moonlight_update !== undefined ? updateStrings[state.__moonlight_update] : ""}</p>
146 );
147}
148
149export function UpdateButton({ state, setState }: { state: ErrorState; setState: (state: ErrorState) => void }) {
150 const newVersion = useStateFromStores([MoonbaseSettingsStore], () => MoonbaseSettingsStore.newVersion);
151 return newVersion == null ||
152 state.__moonlight_update === UpdateState.Installed ||
153 state.__moonlight_update === undefined ? null : (
154 <Button
155 size={Button.Sizes.LARGE}
156 disabled={state.__moonlight_update !== UpdateState.Ready}
157 onClick={() => {
158 setState({
159 ...state,
160 __moonlight_update: UpdateState.Working
161 });
162
163 MoonbaseSettingsStore.updateMoonlight()
164 .then(() => {
165 setState({
166 ...state,
167 __moonlight_update: UpdateState.Installed
168 });
169 })
170 .catch((e) => {
171 logger.error(e);
172 setState({
173 ...state,
174 __moonlight_update: UpdateState.Failed
175 });
176 });
177 }}
178 >
179 {state.__moonlight_update !== undefined ? buttonStrings[state.__moonlight_update] : ""}
180 </Button>
181 );
182}