Redesign the frontend UI on twui
Rebuild every page on a shared set of twui-based primitives with a dense ops-console look, WireGuard red accent and light/dark/system theming. - Add design tokens (WireGuard red accent, zinc neutrals, theme-flipping semantic colours) and a no-flash theme cookie + toggle - Add shared components: page header, panel, sub-nav, data table with mobile card list, stat tile, status dot, key-value list, copy button, inline alert, empty state, form section/actions, confirm dialog and toast providers - New admin shell (sidebar, sticky header, mobile drawer) and a centered shell for auth and 404; strip the public template pages - Unify adding clients at /admin/clients/add with a host picker; tabbed client detail (Overview / Rules / Config & QR) with config copy/download - Re-run client setup after rule changes on the detail page so the firewall matches the DB - Split Setup into status/maintenance/firewall and Settings into profile/password subpages - Replace window.confirm/alert and page reloads with in-app dialogs, toasts and in-place list updates - Fix nested rule form submitting the client form, prefilled signup passwords, hidden submit buttons, fields not updating after "next free" lookups, and TinyMCE white-on-white in dark mode Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
@@ -1,12 +1,11 @@
|
||||
import { RotateCcw, Wrench } from "lucide-react";
|
||||
import fetchApi from "@/src/components/twui/utils/fetch/fetchApi";
|
||||
import Row from "@/src/components/twui/layout/Row";
|
||||
import Span from "@/src/components/twui/layout/Span";
|
||||
import type useSystemSetupStatus from "../(hooks)/use-system-setup-status";
|
||||
import SetupActionCard from "../(partials)/setup-action-card";
|
||||
import SetupUpdateWgUiAction from "../(partials)/setup-update-wg-ui-action";
|
||||
import Panel from "@/src/components/general/panel";
|
||||
import type { ApiReqParams } from "@/src/types";
|
||||
import type { APIResponseObject } from "@moduletrace/bunext/types";
|
||||
import { RotateCcw, TriangleAlert, Wrench } from "lucide-react";
|
||||
import type useSystemSetupStatus from "../(hooks)/use-system-setup-status";
|
||||
import SetupActionRow from "../(partials)/setup-action-row";
|
||||
import SetupUpdateWgUiAction from "../(partials)/setup-update-wg-ui-action";
|
||||
|
||||
type Props = {
|
||||
setup: ReturnType<typeof useSystemSetupStatus>;
|
||||
@@ -25,41 +24,21 @@ export default function SetupActionsSection({ setup }: Props) {
|
||||
.filter((tool) => WG_TOOL_COMMANDS.includes(tool.command))
|
||||
.every((tool) => tool.installed);
|
||||
|
||||
const show_restart =
|
||||
!setup_status.is_dev && setup_status.init_system !== "unknown";
|
||||
const show_restart = !setup_status.is_dev && setup_status.init_system !== "unknown";
|
||||
|
||||
return (
|
||||
<>
|
||||
{!setup_status.is_root ? (
|
||||
<Row className="gap-2 items-center bg-warning/5 rounded-lg px-3 py-2.5 text-warning">
|
||||
<TriangleAlert size={16} className="shrink-0" />
|
||||
<Span className="text-[12.5px]">
|
||||
The server is not running as root — installs and
|
||||
tunnel management may fail. Run wg-ui as root for full
|
||||
functionality.
|
||||
</Span>
|
||||
</Row>
|
||||
) : null}
|
||||
|
||||
<SetupActionCard
|
||||
<Panel flush>
|
||||
<SetupActionRow
|
||||
title="WireGuard tools"
|
||||
description="Installs or updates the WireGuard tools (wg, wg-quick, iproute2) using your distro's package manager. Safe to re-run — the installer is idempotent."
|
||||
icon={<Wrench size={19} />}
|
||||
button_title={
|
||||
have_wg_tools
|
||||
? "Update WireGuard tools"
|
||||
: "Install WireGuard tools"
|
||||
}
|
||||
description="Installs or updates wg, wg-quick and iproute2 with your distro's package manager. Safe to re-run."
|
||||
icon={<Wrench size={15} />}
|
||||
button_title={have_wg_tools ? "Update tools" : "Install tools"}
|
||||
on_run={async () => {
|
||||
const res = await fetchApi<ApiReqParams, APIResponseObject>(
|
||||
`/api/admin/setup-wireguard-tools`,
|
||||
{
|
||||
method: "POST",
|
||||
},
|
||||
{ method: "POST" },
|
||||
);
|
||||
|
||||
setup.refresh();
|
||||
|
||||
return res;
|
||||
}}
|
||||
/>
|
||||
@@ -67,25 +46,27 @@ export default function SetupActionsSection({ setup }: Props) {
|
||||
<SetupUpdateWgUiAction setup={setup} />
|
||||
|
||||
{show_restart ? (
|
||||
<SetupActionCard
|
||||
<SetupActionRow
|
||||
title="Restart service"
|
||||
description={`Restarts the ${setup_status.service_name} system service. Use this after manual changes — the server goes briefly offline.`}
|
||||
icon={<RotateCcw size={19} />}
|
||||
button_title="Restart service"
|
||||
description={`Restarts the ${setup_status.service_name} system service. Use after manual changes.`}
|
||||
icon={<RotateCcw size={15} />}
|
||||
button_title="Restart"
|
||||
confirm_params={{
|
||||
title: "Restart wg-ui?",
|
||||
message: `The ${setup_status.service_name} service restarts and this dashboard goes briefly offline.`,
|
||||
confirm_label: "Restart service",
|
||||
tone: "danger",
|
||||
}}
|
||||
on_run={async () => {
|
||||
const res = await fetchApi<
|
||||
ApiReqParams,
|
||||
APIResponseObject
|
||||
>(`/api/admin/restart-wg-ui-service`, {
|
||||
method: "POST",
|
||||
});
|
||||
|
||||
const res = await fetchApi<ApiReqParams, APIResponseObject>(
|
||||
`/api/admin/restart-wg-ui-service`,
|
||||
{ method: "POST" },
|
||||
);
|
||||
setup.refresh();
|
||||
|
||||
return res;
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
</>
|
||||
</Panel>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user