mirror of
https://github.com/outbackdingo/firezone.git
synced 2026-01-27 18:18:55 +00:00
Previously, we opted into the X11 GTK backend when rendering the GUI Client's window. This is causing issues on newer Linux distributions such as Fedora 43 where Wayland is now the only available compositor. Removing the X11 GTK requires us to draw our own CSDs such as titlebars and a close button. This PR does exactly that by adding a minimalistic title bar. To make better use of the space, we move the section headers into there. |Before|After| |---|---| |<img width="1900" height="1174" alt="Screenshot From 2025-11-11 11-14-11" src="https://github.com/user-attachments/assets/9439a69b-65ba-41d6-b1f8-4448e0f80728" />|<img width="1800" height="1000" alt="Screenshot From 2025-11-11 11-40-55" src="https://github.com/user-attachments/assets/7884b2cc-3d9c-4b47-9a1e-c6462aef36ab" />| |<img width="1900" height="1174" alt="Screenshot From 2025-11-11 11-14-16" src="https://github.com/user-attachments/assets/2cfea825-5c08-45a5-873c-5afcbc1dbf16" />|<img width="1800" height="1000" alt="Screenshot From 2025-11-11 11-40-58" src="https://github.com/user-attachments/assets/43ddd7c9-ce65-42f7-b972-28c6b172b70d" />| |<img width="1900" height="1174" alt="Screenshot From 2025-11-11 11-14-19" src="https://github.com/user-attachments/assets/446873a7-9023-4266-9377-ea7b8b4353ee" />|<img width="1800" height="1000" alt="Screenshot From 2025-11-11 11-41-01" src="https://github.com/user-attachments/assets/64439383-f33f-461d-9b4a-6b4138bd675b" />| |<img width="1900" height="1174" alt="Screenshot From 2025-11-11 11-14-22" src="https://github.com/user-attachments/assets/6c39e06c-1d77-471f-91f1-32a78b90a21c" />|<img width="1800" height="1000" alt="Screenshot From 2025-11-11 11-41-04" src="https://github.com/user-attachments/assets/b56912cb-9c85-4b5a-9295-dae6139b25c6" />| |<img width="1900" height="1174" alt="Screenshot From 2025-11-11 11-14-26" src="https://github.com/user-attachments/assets/5a5d638c-15bf-4523-8466-2e0977a03e22" />|<img width="1800" height="1000" alt="Screenshot From 2025-11-11 11-41-06" src="https://github.com/user-attachments/assets/ed169b52-ef86-4dc4-8f25-852da622eaa1" />|
204 lines
6.5 KiB
TypeScript
204 lines
6.5 KiB
TypeScript
import {
|
|
Bars3Icon,
|
|
CogIcon,
|
|
DocumentMagnifyingGlassIcon,
|
|
HomeIcon,
|
|
InformationCircleIcon,
|
|
SwatchIcon,
|
|
WrenchScrewdriverIcon,
|
|
} from "@heroicons/react/24/solid";
|
|
import {
|
|
Sidebar,
|
|
SidebarCollapse,
|
|
SidebarItemGroup,
|
|
SidebarItems,
|
|
} from "flowbite-react";
|
|
import React, { useEffect, useState } from "react";
|
|
import { Route, Routes } from "react-router";
|
|
import About from "./AboutPage";
|
|
import AdvancedSettingsPage from "./AdvancedSettingsPage";
|
|
import ReactRouterSidebarItem from "./ReactRouterSidebarItem";
|
|
import ColorPalette from "./ColorPalettePage";
|
|
import Diagnostics from "./DiagnosticsPage";
|
|
import GeneralSettingsPage from "./GeneralSettingsPage";
|
|
import Overview from "./OverviewPage";
|
|
import {
|
|
AdvancedSettingsViewModel,
|
|
commands,
|
|
events,
|
|
FileCount,
|
|
GeneralSettingsViewModel,
|
|
SessionViewModel,
|
|
} from "../generated/bindings";
|
|
import Titlebar from "./Titlebar";
|
|
|
|
export default function App() {
|
|
const [session, setSession] = useState<SessionViewModel | null>(null);
|
|
const [logCount, setLogCount] = useState<FileCount | null>(null);
|
|
const [generalSettings, setGeneralSettings] =
|
|
useState<GeneralSettingsViewModel | null>(null);
|
|
const [advancedSettings, setAdvancedSettings] =
|
|
useState<AdvancedSettingsViewModel | null>(null);
|
|
|
|
useEffect(() => {
|
|
const sessionChangedUnlisten = events.sessionChanged.listen((e) => {
|
|
const session = e.payload;
|
|
|
|
console.log("session_changed", { session });
|
|
setSession(session);
|
|
});
|
|
const generalSettingsChangedUnlisten = events.generalSettingsChanged.listen(
|
|
(e) => {
|
|
const generalSettings = e.payload;
|
|
|
|
console.log("general_settings_changed", { settings: generalSettings });
|
|
setGeneralSettings(generalSettings);
|
|
}
|
|
);
|
|
const advancedSettingsChangedUnlisten =
|
|
events.advancedSettingsChanged.listen((e) => {
|
|
const advancedSettings = e.payload;
|
|
|
|
console.log("advanced_settings_changed", {
|
|
settings: advancedSettings,
|
|
});
|
|
setAdvancedSettings(advancedSettings);
|
|
});
|
|
const logsRecountedUnlisten = events.logsRecounted.listen((e) => {
|
|
const file_count = e.payload;
|
|
|
|
console.log("logs_recounted", { file_count });
|
|
setLogCount(file_count);
|
|
});
|
|
|
|
commands.updateState(); // Let the backend know that we (re)-initialised
|
|
|
|
return () => {
|
|
sessionChangedUnlisten.then((unlistenFn) => unlistenFn());
|
|
generalSettingsChangedUnlisten.then((unlistenFn) => unlistenFn());
|
|
advancedSettingsChangedUnlisten.then((unlistenFn) => unlistenFn());
|
|
logsRecountedUnlisten.then((unlistenFn) => unlistenFn());
|
|
};
|
|
}, []);
|
|
|
|
const isDev = import.meta.env.DEV;
|
|
|
|
return (
|
|
<div className="h-screen flex flex-col rounded-lg border border-neutral-300 overflow-hidden">
|
|
<Routes>
|
|
<Route path="/overview" element={<Titlebar title={"Firezone"} />} />
|
|
<Route
|
|
path="/general-settings"
|
|
element={<Titlebar title={"General Settings"} />}
|
|
/>
|
|
<Route
|
|
path="/advanced-settings"
|
|
element={<Titlebar title={"Advanced Settings"} />}
|
|
/>
|
|
<Route
|
|
path="/diagnostics"
|
|
element={<Titlebar title={"Diagnostics"} />}
|
|
/>
|
|
<Route path="/about" element={<Titlebar title={"About"} />} />
|
|
<Route
|
|
path="/colour-palette"
|
|
element={<Titlebar title={"Colour Palette"} />}
|
|
/>
|
|
</Routes>
|
|
<div className="flex-1 bg-neutral-50 flex flex-row">
|
|
<Sidebar
|
|
aria-label="Sidebar"
|
|
className="w-52 flex-shrink-0 border-r border-neutral-200"
|
|
>
|
|
<SidebarItems>
|
|
<SidebarItemGroup>
|
|
<ReactRouterSidebarItem icon={HomeIcon} href="/overview">
|
|
Overview
|
|
</ReactRouterSidebarItem>
|
|
<SidebarCollapse label="Settings" open={true} icon={Bars3Icon}>
|
|
<ReactRouterSidebarItem icon={CogIcon} href="/general-settings">
|
|
General
|
|
</ReactRouterSidebarItem>
|
|
<ReactRouterSidebarItem
|
|
icon={WrenchScrewdriverIcon}
|
|
href="/advanced-settings"
|
|
>
|
|
Advanced
|
|
</ReactRouterSidebarItem>
|
|
</SidebarCollapse>
|
|
<ReactRouterSidebarItem
|
|
icon={DocumentMagnifyingGlassIcon}
|
|
href="/diagnostics"
|
|
>
|
|
Diagnostics
|
|
</ReactRouterSidebarItem>
|
|
<ReactRouterSidebarItem
|
|
icon={InformationCircleIcon}
|
|
href="/about"
|
|
>
|
|
About
|
|
</ReactRouterSidebarItem>
|
|
</SidebarItemGroup>
|
|
{isDev && (
|
|
<SidebarItemGroup>
|
|
<ReactRouterSidebarItem
|
|
icon={SwatchIcon}
|
|
href="/colour-palette"
|
|
>
|
|
Color Palette
|
|
</ReactRouterSidebarItem>
|
|
</SidebarItemGroup>
|
|
)}
|
|
</SidebarItems>
|
|
</Sidebar>
|
|
<main className="flex-grow overflow-auto">
|
|
<Routes>
|
|
<Route
|
|
path="/overview"
|
|
element={
|
|
<Overview
|
|
session={session}
|
|
signIn={commands.signIn}
|
|
signOut={commands.signOut}
|
|
/>
|
|
}
|
|
/>
|
|
<Route
|
|
path="/general-settings"
|
|
element={
|
|
<GeneralSettingsPage
|
|
settings={generalSettings}
|
|
saveSettings={commands.applyGeneralSettings}
|
|
resetSettings={commands.resetGeneralSettings}
|
|
/>
|
|
}
|
|
/>
|
|
<Route
|
|
path="/advanced-settings"
|
|
element={
|
|
<AdvancedSettingsPage
|
|
settings={advancedSettings}
|
|
saveSettings={commands.applyAdvancedSettings}
|
|
resetSettings={commands.resetAdvancedSettings}
|
|
/>
|
|
}
|
|
/>
|
|
<Route
|
|
path="/diagnostics"
|
|
element={
|
|
<Diagnostics
|
|
logCount={logCount}
|
|
exportLogs={commands.exportLogs}
|
|
clearLogs={commands.clearLogs}
|
|
/>
|
|
}
|
|
/>
|
|
<Route path="/about" element={<About />} />
|
|
<Route path="/colour-palette" element={<ColorPalette />} />
|
|
</Routes>
|
|
</main>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|