TypeScript · 5682 bytes Raw Blame History
1 import { useState, useEffect } from "react";
2 import { getPrefixes, repairPrefix, getWemodStatus, updateWemod } from "../hooks/useApi";
3 import type { PrefixInfo, WemodStatus } from "../types";
4
5 export default function PrefixesView() {
6 const [prefixes, setPrefixes] = useState<PrefixInfo[]>([]);
7 const [wemodStatus, setWemodStatus] = useState<WemodStatus | null>(null);
8 const [loading, setLoading] = useState(true);
9 const [repairing, setRepairing] = useState<string | null>(null);
10 const [updating, setUpdating] = useState(false);
11 const [error, setError] = useState<string | null>(null);
12
13 useEffect(() => {
14 loadData();
15 }, []);
16
17 async function loadData() {
18 try {
19 setLoading(true);
20 const [prefixList, wemod] = await Promise.all([getPrefixes(), getWemodStatus()]);
21 setPrefixes(prefixList);
22 setWemodStatus(wemod);
23 } catch (err) {
24 setError(String(err));
25 } finally {
26 setLoading(false);
27 }
28 }
29
30 async function handleRepair(name: string) {
31 setRepairing(name);
32 try {
33 await repairPrefix(name);
34 await loadData();
35 } catch (err) {
36 setError(String(err));
37 } finally {
38 setRepairing(null);
39 }
40 }
41
42 async function handleUpdateWemod() {
43 setUpdating(true);
44 try {
45 await updateWemod();
46 await loadData();
47 } catch (err) {
48 setError(String(err));
49 } finally {
50 setUpdating(false);
51 }
52 }
53
54 function getHealthBadge(health: string) {
55 switch (health) {
56 case "healthy":
57 return <span className="badge badge-success">Healthy</span>;
58 case "needs_repair":
59 return <span className="badge badge-warning">Needs Repair</span>;
60 case "corrupted":
61 return <span className="badge badge-error">Corrupted</span>;
62 default:
63 return <span className="badge">Unknown</span>;
64 }
65 }
66
67 if (loading) {
68 return (
69 <div>
70 <div className="page-header">
71 <h1 className="page-title">Prefixes</h1>
72 </div>
73 <div style={{ textAlign: "center", padding: "50px" }}>
74 <div className="spinner" style={{ margin: "0 auto" }} />
75 </div>
76 </div>
77 );
78 }
79
80 return (
81 <div>
82 <div className="page-header">
83 <h1 className="page-title">Prefixes</h1>
84 </div>
85
86 {error && (
87 <div
88 className="card"
89 style={{ backgroundColor: "rgba(248, 113, 113, 0.1)", marginBottom: "20px" }}
90 >
91 <p style={{ color: "var(--error)" }}>{error}</p>
92 </div>
93 )}
94
95 {/* WeMod Status */}
96 <div className="card">
97 <div className="card-header">
98 <h2 className="card-title">WeMod Status</h2>
99 {wemodStatus?.update_available && (
100 <button
101 className="btn btn-primary btn-small"
102 onClick={handleUpdateWemod}
103 disabled={updating}
104 >
105 {updating ? "Updating..." : `Update to ${wemodStatus.latest_version}`}
106 </button>
107 )}
108 </div>
109 {wemodStatus ? (
110 <div>
111 <p>
112 <strong>Installed:</strong>{" "}
113 {wemodStatus.installed ? (
114 <span style={{ color: "var(--success)" }}>Yes</span>
115 ) : (
116 <span style={{ color: "var(--error)" }}>No</span>
117 )}
118 </p>
119 {wemodStatus.version && (
120 <p>
121 <strong>Version:</strong> {wemodStatus.version}
122 </p>
123 )}
124 {wemodStatus.update_available && (
125 <p style={{ color: "var(--warning)" }}>
126 Update available: {wemodStatus.latest_version}
127 </p>
128 )}
129 </div>
130 ) : (
131 <p style={{ color: "var(--text-secondary)" }}>Loading...</p>
132 )}
133 </div>
134
135 {/* Prefix List */}
136 <h2 className="card-title" style={{ marginBottom: "15px" }}>
137 Wine Prefixes
138 </h2>
139
140 {prefixes.length === 0 ? (
141 <div className="card">
142 <p style={{ color: "var(--text-secondary)" }}>No prefixes found</p>
143 </div>
144 ) : (
145 <div className="prefix-list">
146 {prefixes.map((prefix) => (
147 <div key={prefix.name} className="prefix-item">
148 <div className="prefix-info">
149 <h3>
150 {prefix.name} {getHealthBadge(prefix.health)}
151 </h3>
152 <p>{prefix.path}</p>
153 {prefix.proton_version && (
154 <p>
155 <small>Proton: {prefix.proton_version}</small>
156 </p>
157 )}
158 {prefix.wemod_installed && prefix.wemod_version && (
159 <p>
160 <small>WeMod: {prefix.wemod_version}</small>
161 </p>
162 )}
163 {prefix.issues.length > 0 && (
164 <ul style={{ marginTop: "10px", color: "var(--warning)", fontSize: "0.8rem" }}>
165 {prefix.issues.map((issue, i) => (
166 <li key={i}>{issue}</li>
167 ))}
168 </ul>
169 )}
170 </div>
171 <div>
172 {prefix.health === "needs_repair" && (
173 <button
174 className="btn btn-secondary btn-small"
175 onClick={() => handleRepair(prefix.name)}
176 disabled={repairing === prefix.name}
177 >
178 {repairing === prefix.name ? "Repairing..." : "Repair"}
179 </button>
180 )}
181 </div>
182 </div>
183 ))}
184 </div>
185 )}
186 </div>
187 );
188 }