major ui tweaks and refactoring

This commit is contained in:
Milo Schwartz
2025-01-04 20:22:01 -05:00
parent 51bf5c1408
commit 64158a823b
91 changed files with 1791 additions and 1246 deletions

View File

@@ -36,6 +36,9 @@ import { createApiClient } from "@app/lib/api";
import { useEnvContext } from "@app/hooks/useEnvContext";
import { SiteRow } from "./SitesTable";
import { AxiosResponse } from "axios";
import { Button } from "@app/components/ui/button";
import Link from "next/link";
import { ArrowUpRight } from "lucide-react";
const createSiteFormSchema = z.object({
name: z
@@ -274,6 +277,24 @@ PersistentKeepalive = 5`
You will only be able to see the configuration once.
</span>
{form.watch("method") === "newt" && (
<>
<br />
<Link
className="text-sm text-primary flex items-center gap-1"
href="https://docs.fossorial.io/Newt/install"
target="_blank"
rel="noopener noreferrer"
>
<span>
{" "}
Learn how to install Newt on your system
</span>
<ArrowUpRight className="w-5 h-5" />
</Link>
</>
)}
<div className="flex items-center space-x-2">
<Checkbox
id="terms"

View File

@@ -16,6 +16,7 @@ import {
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableHeader,
TableRow,
@@ -89,7 +90,7 @@ export function SitesDataTable<TData, TValue>({
<Plus className="mr-2 h-4 w-4" /> Add Site
</Button>
</div>
<div className="border rounded-md">
<TableContainer>
<Table>
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
@@ -141,7 +142,7 @@ export function SitesDataTable<TData, TValue>({
)}
</TableBody>
</Table>
</div>
</TableContainer>
<div className="mt-4">
<DataTablePagination table={table} />
</div>

View File

@@ -0,0 +1,98 @@
"use client";
import React, { useState, useEffect } from "react";
import { Card, CardContent } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { ArrowRight, DockIcon as Docker, Globe, Server, X } from "lucide-react";
import Link from "next/link";
export const SitesSplashCard = () => {
const [isDismissed, setIsDismissed] = useState(true);
const key = "sites-splash-card-dismissed";
useEffect(() => {
const dismissed = localStorage.getItem(key);
if (dismissed === "true") {
setIsDismissed(true);
} else {
setIsDismissed(false);
}
}, []);
const handleDismiss = () => {
setIsDismissed(true);
localStorage.setItem(key, "true");
};
if (isDismissed) {
return null;
}
return (
<Card className="w-full mx-auto overflow-hidden mb-8 hidden md:block relative">
<button
onClick={handleDismiss}
className="absolute top-2 right-2 p-2"
aria-label="Dismiss"
>
<X className="w-5 h-5" />
</button>
<CardContent className="grid gap-6 p-6 sm:grid-cols-2">
<div className="space-y-4">
<h3 className="text-xl font-semibold flex items-center gap-2">
<Globe className="text-blue-500" />
Newt (Recommended)
</h3>
<p className="text-sm">
For the best user experience, use Newt. It uses
WireGuard under the hood and allows you to address your
private resources by their LAN address on your private
network from within the Pangolin dashboard.
</p>
<ul className="text-sm text-muted-foreground space-y-2">
<li className="flex items-center gap-2">
<Server className="text-green-500 w-4 h-4" />
Runs in Docker
</li>
<li className="flex items-center gap-2">
<Server className="text-green-500 w-4 h-4" />
Runs in shell on macOS, Linux, and Windows
</li>
</ul>
<Button className="w-full" variant="secondary">
<Link
href="https://docs.fossorial.io/Newt/install"
target="_blank"
rel="noopener noreferrer"
className="flex items-center"
>
Install Newt <ArrowRight className="ml-2 w-4 h-4" />
</Link>
</Button>
</div>
<div className="space-y-4">
<h3 className="text-xl font-semibold flex items-center gap-2">
Basic WireGuard
</h3>
<p className="text-sm">
Use any WireGuard client to connect. You will have to
address your internal resources using the peer IP.
</p>
<ul className="text-sm text-muted-foreground space-y-2">
<li className="flex items-center gap-2">
<Docker className="text-purple-500 w-4 h-4" />
Compatible with all WireGuard clients
</li>
<li className="flex items-center gap-2">
<Server className="text-purple-500 w-4 h-4" />
Manual configuration required
</li>
</ul>
</div>
</CardContent>
</Card>
);
};
export default SitesSplashCard;

View File

@@ -256,7 +256,7 @@ export default function SitesTable({ sites, orgId }: SitesTableProps) {
<Link
href={`/${siteRow.orgId}/settings/sites/${siteRow.nice}`}
>
<Button variant={"gray"} className="ml-2">
<Button variant={"outline"} className="ml-2">
Edit
<ArrowRight className="ml-2 w-4 h-4" />
</Button>

View File

@@ -10,20 +10,29 @@ import {
FormField,
FormItem,
FormLabel,
FormMessage,
FormMessage
} from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import { useSiteContext } from "@app/hooks/useSiteContext";
import { useForm } from "react-hook-form";
import { useToast } from "@app/hooks/useToast";
import { useRouter } from "next/navigation";
import SettingsSectionTitle from "@app/components/SettingsSectionTitle";
import { formatAxiosError } from "@app/lib/api";;
import {
SettingsContainer,
SettingsSection,
SettingsSectionHeader,
SettingsSectionTitle,
SettingsSectionDescription,
SettingsSectionBody,
SettingsSectionForm,
SettingsSectionFooter
} from "@app/components/Settings";
import { formatAxiosError } from "@app/lib/api";
import { createApiClient } from "@app/lib/api";
import { useEnvContext } from "@app/hooks/useEnvContext";
const GeneralFormSchema = z.object({
name: z.string(),
name: z.string()
});
type GeneralFormValues = z.infer<typeof GeneralFormSchema>;
@@ -39,15 +48,15 @@ export default function GeneralPage() {
const form = useForm<GeneralFormValues>({
resolver: zodResolver(GeneralFormSchema),
defaultValues: {
name: site?.name,
name: site?.name
},
mode: "onChange",
mode: "onChange"
});
async function onSubmit(data: GeneralFormValues) {
await api
.post(`/site/${site?.siteId}`, {
name: data.name,
name: data.name
})
.catch((e) => {
toast({
@@ -56,7 +65,7 @@ export default function GeneralPage() {
description: formatAxiosError(
e,
"An error occurred while updating the site."
),
)
});
});
@@ -66,39 +75,53 @@ export default function GeneralPage() {
}
return (
<>
<div className="space-y-4 max-w-xl">
<SettingsSectionTitle
title="General Settings"
description="Configure the general settings for this site"
size="1xl"
/>
<SettingsContainer>
<SettingsSection>
<SettingsSectionHeader>
<SettingsSectionTitle>
General Settings
</SettingsSectionTitle>
<SettingsSectionDescription>
Configure the general settings for this site
</SettingsSectionDescription>
</SettingsSectionHeader>
<Form {...form}>
<form
onSubmit={form.handleSubmit(onSubmit)}
className="space-y-4"
>
<FormField
control={form.control}
name="name"
render={({ field }) => (
<FormItem>
<FormLabel>Name</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormDescription>
This is the display name of the site
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<Button type="submit">Save Changes</Button>
</form>
</Form>
</div>
</>
<SettingsSectionBody>
<SettingsSectionForm>
<Form {...form}>
<form
onSubmit={form.handleSubmit(onSubmit)}
className="space-y-4"
id="general-settings-form"
>
<FormField
control={form.control}
name="name"
render={({ field }) => (
<FormItem>
<FormLabel>Name</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormDescription>
This is the display name of the
site
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
</form>
</Form>
</SettingsSectionForm>
</SettingsSectionBody>
<SettingsSectionFooter>
<Button type="submit" form="general-settings-form">
Save Settings
</Button>
</SettingsSectionFooter>
</SettingsSection>
</SettingsContainer>
);
}

View File

@@ -4,6 +4,7 @@ import { ListSitesResponse } from "@server/routers/site";
import { AxiosResponse } from "axios";
import SitesTable, { SiteRow } from "./SitesTable";
import SettingsSectionTitle from "@app/components/SettingsSectionTitle";
import SitesSplashCard from "./SitesSplashCard";
type SitesPageProps = {
params: Promise<{ orgId: string }>;
@@ -47,6 +48,8 @@ export default async function SitesPage(props: SitesPageProps) {
return (
<>
<SitesSplashCard />
<SettingsSectionTitle
title="Manage Sites"
description="Allow connectivity to your network through secure tunnels"