Skip to content

Commit a5bf39d

Browse files
committed
Show slim launch modal when existing server is protocol-activated
1 parent 2d43be1 commit a5bf39d

5 files changed

Lines changed: 140 additions & 40 deletions

File tree

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import Modal from "react-bootstrap/Modal";
2+
3+
import Button from "./Button";
4+
5+
import { ServerEntry } from "@/app/types";
6+
7+
export default function LaunchServerModal({
8+
server,
9+
show,
10+
setShow,
11+
launchServer,
12+
}: {
13+
server?: ServerEntry;
14+
show: boolean;
15+
setShow: (newShow: boolean) => void;
16+
launchServer: (uuid: string | undefined) => void;
17+
}) {
18+
return (
19+
<Modal show={show} onHide={() => setShow(false)} centered={true}>
20+
<Modal.Header>
21+
<Modal.Title>{server?.description}</Modal.Title>
22+
</Modal.Header>
23+
<Modal.Body>This server is already in your server list.</Modal.Body>
24+
<Modal.Footer>
25+
<Button
26+
onClick={() => setShow(false)}
27+
variant="primary"
28+
text="Cancel"
29+
/>
30+
<Button
31+
onClick={() => {
32+
setShow(false);
33+
launchServer(server?.uuid);
34+
}}
35+
variant="success"
36+
text="Launch"
37+
/>
38+
</Modal.Footer>
39+
</Modal>
40+
);
41+
}

‎app/page.tsx‎

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ import {
4949
import ForgotPasswordModal from "./components/ForgotPasswordModal";
5050
import ConfirmationModal from "./components/ConfirmationModal";
5151
import { useRouter } from "next/navigation";
52+
import LaunchServerModal from "./components/LaunchServerModal";
5253

5354
const DEFAULT_TAGLINE =
5455
"Welcome to OpenFusion.\nSelect a server from the list below to get started.";
@@ -70,7 +71,7 @@ export default function Home() {
7071
const [servers, setServers] = useState<ServerEntry[]>([]);
7172
const [versions, setVersions] = useState<VersionEntry[]>([]);
7273

73-
const [selectedIdx, setSelectedIdx] = useState<number>(-1);
74+
const [selectedServerUuid, setSelectedServerUuid] = useState<string>();
7475
const [currentSession, setCurrentSession] = useState<
7576
LoginSession | undefined
7677
>(undefined);
@@ -82,6 +83,7 @@ export default function Home() {
8283
const [addServerDetails, setAddServerDetails] = useState<NewServerDetails>();
8384
const [showEditModal, setShowEditModal] = useState(false);
8485
const [showDeleteModal, setShowDeleteModal] = useState(false);
86+
const [showLaunchModal, setShowLaunchModal] = useState(false);
8587

8688
const [showLoginModal, setShowLoginModal] = useState(false);
8789
const [showForgotPasswordModal, setShowForgotPasswordModal] = useState(false);
@@ -107,22 +109,17 @@ export default function Home() {
107109
setShowAddModal(true);
108110
};
109111

112+
const openLaunchServer = (uuid: string) => {
113+
setSelectedServer(uuid);
114+
setShowLaunchModal(true);
115+
};
116+
110117
const getSelectedServer = () => {
111-
if (selectedIdx >= 0 && selectedIdx < servers.length) {
112-
return servers[selectedIdx];
113-
}
114-
return undefined;
118+
return servers.find((server) => server.uuid == selectedServerUuid);
115119
};
116120

117121
const setSelectedServer = (uuid?: string) => {
118-
if (uuid) {
119-
const idx = servers.findIndex((server) => server.uuid == uuid);
120-
if (idx >= 0) {
121-
setSelectedIdx(idx);
122-
}
123-
} else {
124-
setSelectedIdx(-1);
125-
}
122+
setSelectedServerUuid(uuid);
126123
setCurrentSession(undefined);
127124
};
128125

@@ -275,17 +272,6 @@ export default function Home() {
275272
if (e.key === "Escape") {
276273
setSelectedServer(undefined);
277274
}
278-
279-
// Server selector controls
280-
// const modulo = servers.length;
281-
// if (e.key === "ArrowUp" || e.key === "ArrowLeft") {
282-
// const newIdx = (selectedIdx <= 0 ? modulo - 1 : (selectedIdx - 1));
283-
// setSelectedIdx(newIdx);
284-
// }
285-
// if (e.key === "ArrowDown" || e.key === "ArrowRight") {
286-
// const newIdx = (selectedIdx + 1) % modulo;
287-
// setSelectedIdx(newIdx);
288-
// }
289275
};
290276

291277
const doInit = async () => {
@@ -533,6 +519,13 @@ export default function Home() {
533519
}
534520
};
535521

522+
const launchServer = async (serverUuid?: string) => {
523+
if (serverUuid) {
524+
setConnecting(true);
525+
onConnect(serverUuid);
526+
}
527+
};
528+
536529
const sendOneTimePassword = async (email: string) => {
537530
try {
538531
await invoke("send_otp", {
@@ -585,7 +578,10 @@ export default function Home() {
585578
for (const activation of pending) {
586579
switch (activation.type) {
587580
case "add_server":
588-
openAddServer(activation.details);
581+
openAddServer(activation.payload);
582+
break;
583+
case "show_existing_server":
584+
openLaunchServer(activation.payload);
589585
break;
590586
}
591587
}
@@ -616,7 +612,7 @@ export default function Home() {
616612
return () => {
617613
window.removeEventListener("keydown", handleKeydown);
618614
};
619-
}, [servers, selectedIdx]);
615+
}, [servers, selectedServerUuid]);
620616

621617
// Padding for custom titlebar
622618
useEffect(() => {
@@ -758,6 +754,12 @@ export default function Home() {
758754
setShow={setShowDeleteModal}
759755
deleteServer={deleteServer}
760756
/>
757+
<LaunchServerModal
758+
server={getSelectedServer()}
759+
show={showLaunchModal}
760+
setShow={setShowLaunchModal}
761+
launchServer={launchServer}
762+
/>
761763
<LoginModal
762764
server={getSelectedServer()}
763765
show={showLoginModal}

‎app/types.ts‎

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,9 @@ export type NewServerDetails = {
1313
endpoint?: string;
1414
};
1515

16-
export type ProtocolActivation = {
17-
type: string;
18-
details: NewServerDetails;
19-
};
16+
export type ProtocolActivation =
17+
| { type: "add_server"; payload: NewServerDetails }
18+
| { type: "show_existing_server"; payload: string };
2019

2120
export type Servers = {
2221
servers: ServerEntry[];

‎src-tauri/src/state.rs‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,10 @@ impl From<FlatServer> for Server {
549549
}
550550
}
551551
impl Server {
552+
pub fn get_uuid(&self) -> Uuid {
553+
self.uuid
554+
}
555+
552556
pub fn get_description(&self) -> Option<String> {
553557
self.description.clone()
554558
}
@@ -665,6 +669,26 @@ impl Servers {
665669
}
666670
Err(format!("Server with UUID {} not found", entry.uuid).into())
667671
}
672+
673+
pub fn find_simple_entry(&self, ip: &str, version: &str) -> Option<&Server> {
674+
self.servers.iter().find(|s| match &s.info {
675+
ServerInfo::Simple {
676+
ip: server_ip,
677+
version: server_version,
678+
} => server_ip == ip && server_version == version,
679+
ServerInfo::Endpoint { .. } => false,
680+
})
681+
}
682+
683+
pub fn find_endpoint_entry(&self, endpoint: &str) -> Option<&Server> {
684+
self.servers.iter().find(|s| match &s.info {
685+
ServerInfo::Endpoint {
686+
endpoint: server_endpoint,
687+
..
688+
} => server_endpoint == endpoint,
689+
ServerInfo::Simple { .. } => false,
690+
})
691+
}
668692
}
669693

670694
impl From<FlatServers> for Servers {

‎src-tauri/src/util.rs‎

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -452,20 +452,54 @@ pub(crate) fn send_alert(app_handle: tauri::AppHandle, variant: AlertVariant, me
452452
}
453453

454454
#[derive(Debug, Clone, Serialize)]
455-
#[serde(tag = "type", content = "details", rename_all = "snake_case")]
455+
#[serde(tag = "type", content = "payload", rename_all = "snake_case")]
456456
pub(crate) enum ProtocolActivation {
457457
AddServer(NewServerDetails),
458+
ShowExistingServer(Uuid),
458459
}
459460

460-
pub(crate) fn queue_activation(app_handle: tauri::AppHandle, activation: ProtocolActivation) {
461+
async fn queue_activation(app_handle: tauri::AppHandle, activation: ProtocolActivation) {
462+
// since this might run on cold start, the app state might not be ready yet
463+
state::wait_for_app_state().await;
464+
let state = app_handle.state::<tokio::sync::Mutex<AppState>>();
465+
state.lock().await.pending_activations.push(activation);
466+
467+
if let Err(e) = app_handle.emit("activation_pending", ()) {
468+
error!("Failed to emit activation pending event: {}", e);
469+
}
470+
}
471+
472+
fn handle_server_activation(app_handle: tauri::AppHandle, details: NewServerDetails) {
461473
tauri::async_runtime::spawn(async move {
462474
state::wait_for_app_state().await;
463475
let state = app_handle.state::<tokio::sync::Mutex<AppState>>();
464-
state.lock().await.pending_activations.push(activation);
476+
let existing_server_uuid = {
477+
let state = state.lock().await;
478+
479+
// Check if the server is already added.
480+
if let Some(endpoint) = &details.endpoint {
481+
state
482+
.servers
483+
.find_endpoint_entry(endpoint)
484+
.map(|s| s.get_uuid())
485+
} else if let Some(ip) = &details.ip
486+
&& let Some(version) = &details.version
487+
{
488+
state
489+
.servers
490+
.find_simple_entry(ip, version)
491+
.map(|s| s.get_uuid())
492+
} else {
493+
None
494+
}
495+
};
465496

466-
if let Err(e) = app_handle.emit("activation_pending", ()) {
467-
error!("Failed to emit activation pending event: {}", e);
468-
}
497+
let activation = match existing_server_uuid {
498+
Some(uuid) => ProtocolActivation::ShowExistingServer(uuid),
499+
None => ProtocolActivation::AddServer(details),
500+
};
501+
502+
queue_activation(app_handle, activation).await;
469503
});
470504
}
471505

@@ -486,15 +520,15 @@ pub(crate) fn handle_protocol_activation(app_handle: tauri::AppHandle, uri: &str
486520
debug!("Protocol activation params: {:?}", params);
487521

488522
match command {
489-
"add-server" => {
490-
queue_activation(
523+
"server" => {
524+
handle_server_activation(
491525
app_handle,
492-
ProtocolActivation::AddServer(NewServerDetails {
526+
NewServerDetails {
493527
description: params.get("description").cloned().unwrap_or_default(),
494528
ip: params.get("ip").cloned(),
495529
version: params.get("version").cloned(),
496530
endpoint: params.get("endpoint").cloned(),
497-
}),
531+
},
498532
);
499533
}
500534
_ => {

0 commit comments

Comments
 (0)