diff --git a/src/app/[orgId]/resources/[resourceId]/components/ClientLayout.tsx b/src/app/[orgId]/resources/[resourceId]/components/ClientLayout.tsx
deleted file mode 100644
index 831743e1..00000000
--- a/src/app/[orgId]/resources/[resourceId]/components/ClientLayout.tsx
+++ /dev/null
@@ -1,50 +0,0 @@
-"use client";
-
-import { SidebarNav } from "@app/components/sidebar-nav";
-import { useResourceContext } from "@app/hooks/useResourceContext";
-
-const sidebarNavItems = [
- {
- title: "General",
- href: "/{orgId}/resources/{resourceId}",
- },
- {
- title: "Targets",
- href: "/{orgId}/resources/{resourceId}/targets",
- },
- // {
- // title: "Notifications",
- // href: "/{orgId}/resources/{resourceId}/notifications",
- // },
-]
-
-export function ClientLayout({ isCreate, children }: { isCreate: boolean; children: React.ReactNode }) {
- const { resource } = useResourceContext();
- return (
-
-
- {isCreate
- ? "New Resource"
- : resource?.name + " Settings"}
-
-
- {isCreate
- ? "Create a new resource"
- : "Configure the settings on your resource: " +
- resource?.name || ""}
- .
-
-
-
-
);
-}
\ No newline at end of file
diff --git a/src/app/[orgId]/resources/[resourceId]/components/GeneralForm.tsx b/src/app/[orgId]/resources/[resourceId]/components/GeneralForm.tsx
deleted file mode 100644
index c53e7b5e..00000000
--- a/src/app/[orgId]/resources/[resourceId]/components/GeneralForm.tsx
+++ /dev/null
@@ -1,259 +0,0 @@
-"use client"
-
-import Link from "next/link"
-import { zodResolver } from "@hookform/resolvers/zod"
-import { useFieldArray, useForm } from "react-hook-form"
-import { z } from "zod"
-
-import { cn } from "@/lib/utils"
-import { toast } from "@/hooks/use-toast"
-
-import { Button } from "@/components/ui/button"
-import {
- Form,
- FormControl,
- FormDescription,
- FormField,
- FormItem,
- FormLabel,
- FormMessage,
-} from "@/components/ui/form"
-import { CalendarIcon, CaretSortIcon, CheckIcon, ChevronDownIcon } from "@radix-ui/react-icons"
-
-import { Input } from "@/components/ui/input"
-import {
- Select,
- SelectContent,
- SelectItem,
- SelectTrigger,
- SelectValue,
-} from "@/components/ui/select"
-import { Textarea } from "@/components/ui/textarea"
-import {
- Command,
- CommandEmpty,
- CommandGroup,
- CommandInput,
- CommandItem,
- CommandList,
-} from "@/components/ui/command"
-
-import {
- Popover,
- PopoverContent,
- PopoverTrigger,
-} from "@/components/ui/popover"
-import { useResourceContext } from "@app/hooks/useResourceContext"
-import { ListSitesResponse } from "@server/routers/site"
-import { useEffect, useState } from "react"
-import { AxiosResponse } from "axios"
-import api from "@app/api"
-import { useParams } from "next/navigation";
-
-const GeneralFormSchema = z.object({
- name: z.string(),
- siteId: z.number()
-})
-
-type GeneralFormValues = z.infer
-
-export function GeneralForm() {
- const params = useParams();
- const orgId = params.orgId;
- const { resource, updateResource } = useResourceContext();
- const [sites, setSites] = useState([]);
-
- const form = useForm({
- resolver: zodResolver(GeneralFormSchema),
- defaultValues: {
- name: resource?.name,
- siteId: resource?.siteId
- },
- mode: "onChange",
- })
-
- useEffect(() => {
- if (typeof window !== "undefined") {
- const fetchSites = async () => {
- const res = await api.get>(`/org/${orgId}/sites/`);
- setSites(res.data.data.sites);
- };
- fetchSites();
- }
- }, []);
-
- // const { fields, append } = useFieldArray({
- // name: "urls",
- // control: form.control,
- // })
-
- async function onSubmit(data: GeneralFormValues) {
- await updateResource({ name: data.name, siteId: data.siteId });
- }
-
- return (
-
-
- )
-}
diff --git a/src/app/[orgId]/resources/[resourceId]/layout.tsx b/src/app/[orgId]/resources/[resourceId]/layout.tsx
deleted file mode 100644
index 83bb9df2..00000000
--- a/src/app/[orgId]/resources/[resourceId]/layout.tsx
+++ /dev/null
@@ -1,84 +0,0 @@
-import { Metadata } from "next";
-import Image from "next/image";
-
-import { Separator } from "@/components/ui/separator";
-import { SidebarNav } from "@/components/sidebar-nav";
-import ResourceProvider from "@app/providers/ResourceProvider";
-import { internal } from "@app/api";
-import { GetResourceResponse } from "@server/routers/resource";
-import { AxiosResponse } from "axios";
-import { redirect } from "next/navigation";
-import { authCookieHeader } from "@app/api/cookies";
-import Link from "next/link";
-import { ArrowLeft, ChevronLeft } from "lucide-react";
-import { useEffect, useState } from "react";
-import { toast } from "@app/hooks/use-toast";
-import { ClientLayout } from "./components/ClientLayout";
-
-export const metadata: Metadata = {
- title: "Forms",
- description: "Advanced form example using react-hook-form and Zod.",
-};
-
-interface SettingsLayoutProps {
- children: React.ReactNode;
- params: Promise<{ resourceId: number | string; orgId: string }>;
-}
-
-export default async function SettingsLayout(props: SettingsLayoutProps) {
- const params = await props.params;
-
- const {
- children
- } = props;
-
- let resource = null;
-
- if (params.resourceId !== "create") {
- try {
- const res = await internal.get>(
- `/resource/${params.resourceId}`,
- await authCookieHeader(),
- );
- resource = res.data.data;
- } catch {
- redirect(`/${params.orgId}/resources`);
- }
- }
-
- return (
- <>
-
-
-
-
-
-
-
-
-
-
-
-
- {children}
-
- >
- );
-}
diff --git a/src/app/[orgId]/components/Header.tsx b/src/app/[orgId]/settings/components/Header.tsx
similarity index 100%
rename from src/app/[orgId]/components/Header.tsx
rename to src/app/[orgId]/settings/components/Header.tsx
diff --git a/src/app/[orgId]/components/TopbarNav.tsx b/src/app/[orgId]/settings/components/TopbarNav.tsx
similarity index 100%
rename from src/app/[orgId]/components/TopbarNav.tsx
rename to src/app/[orgId]/settings/components/TopbarNav.tsx
diff --git a/src/app/[orgId]/layout.tsx b/src/app/[orgId]/settings/layout.tsx
similarity index 84%
rename from src/app/[orgId]/layout.tsx
rename to src/app/[orgId]/settings/layout.tsx
index 291c37db..399c0fc2 100644
--- a/src/app/[orgId]/layout.tsx
+++ b/src/app/[orgId]/settings/layout.tsx
@@ -1,51 +1,48 @@
import { Metadata } from "next";
import { TopbarNav } from "./components/TopbarNav";
-import { Cog, Combine, LayoutGrid, Tent, Users, Waypoints } from "lucide-react";
+import { Cog, Combine, Users, Waypoints } from "lucide-react";
import Header from "./components/Header";
import { verifySession } from "@app/lib/auth/verifySession";
import { redirect } from "next/navigation";
-import { cache } from "react";
import { internal } from "@app/api";
import { AxiosResponse } from "axios";
import { GetOrgResponse, ListOrgsResponse } from "@server/routers/org";
import { authCookieHeader } from "@app/api/cookies";
export const metadata: Metadata = {
- title: `Configuration - Pangolin`,
+ title: `Settings - Pangolin`,
description: "",
};
const topNavItems = [
{
title: "Sites",
- href: "/{orgId}/sites",
+ href: "/{orgId}/settings/sites",
icon: ,
},
{
title: "Resources",
- href: "/{orgId}/resources",
+ href: "/{orgId}/settings/resources",
icon: ,
},
{
title: "Users",
- href: "/{orgId}/users",
+ href: "/{orgId}/settings/users",
icon: ,
},
{
title: "General",
- href: "/{orgId}/general",
+ href: "/{orgId}/settings/general",
icon: ,
},
];
-interface ConfigurationLaytoutProps {
+interface SettingsLayoutProps {
children: React.ReactNode;
params: Promise<{ orgId: string }>;
}
-export default async function ConfigurationLaytout(
- props: ConfigurationLaytoutProps
-) {
+export default async function SettingsLayout(props: SettingsLayoutProps) {
const params = await props.params;
const { children } = props;
diff --git a/src/app/[orgId]/page.tsx b/src/app/[orgId]/settings/page.tsx
similarity index 59%
rename from src/app/[orgId]/page.tsx
rename to src/app/[orgId]/settings/page.tsx
index 414de54b..9956bc85 100644
--- a/src/app/[orgId]/page.tsx
+++ b/src/app/[orgId]/settings/page.tsx
@@ -4,9 +4,9 @@ type OrgPageProps = {
params: Promise<{ orgId: string }>;
};
-export default async function Page(props: OrgPageProps) {
+export default async function SettingsPage(props: OrgPageProps) {
const params = await props.params;
- redirect(`/${params.orgId}/sites`);
+ redirect(`/${params.orgId}/settings/sites`);
return <>>;
}
diff --git a/src/app/[orgId]/settings/resources/[resourceId]/components/ClientLayout.tsx b/src/app/[orgId]/settings/resources/[resourceId]/components/ClientLayout.tsx
new file mode 100644
index 00000000..f0c3a761
--- /dev/null
+++ b/src/app/[orgId]/settings/resources/[resourceId]/components/ClientLayout.tsx
@@ -0,0 +1,47 @@
+"use client";
+
+import { SidebarNav } from "@app/components/sidebar-nav";
+import { useResourceContext } from "@app/hooks/useResourceContext";
+
+const sidebarNavItems = [
+ {
+ title: "General",
+ href: "/{orgId}/settings/resources/{resourceId}",
+ },
+ {
+ title: "Targets",
+ href: "/{orgId}/settings/resources/{resourceId}/targets",
+ },
+];
+
+export function ClientLayout({
+ isCreate,
+ children,
+}: {
+ isCreate: boolean;
+ children: React.ReactNode;
+}) {
+ const { resource } = useResourceContext();
+ return (
+
+
+
+ {isCreate ? "New Resource" : resource?.name + " Settings"}
+
+
+ {isCreate
+ ? "Create a new resource"
+ : "Configure the settings on your resource: " +
+ resource?.name || ""}
+ .
+
+
+
+
+ );
+}
diff --git a/src/app/[orgId]/resources/[resourceId]/components/CreateResource.tsx b/src/app/[orgId]/settings/resources/[resourceId]/components/CreateResource.tsx
similarity index 77%
rename from src/app/[orgId]/resources/[resourceId]/components/CreateResource.tsx
rename to src/app/[orgId]/settings/resources/[resourceId]/components/CreateResource.tsx
index 4e59f416..49ba2ab8 100644
--- a/src/app/[orgId]/resources/[resourceId]/components/CreateResource.tsx
+++ b/src/app/[orgId]/settings/resources/[resourceId]/components/CreateResource.tsx
@@ -1,13 +1,15 @@
-"use client"
+"use client";
-import { zodResolver } from "@hookform/resolvers/zod"
-import { CalendarIcon, CaretSortIcon, CheckIcon, ChevronDownIcon } from "@radix-ui/react-icons"
-import { useForm } from "react-hook-form"
-import { z } from "zod"
-
-import { cn } from "@/lib/utils"
-import { toast } from "@/hooks/use-toast"
-import { Button, buttonVariants } from "@/components/ui/button"
+import { zodResolver } from "@hookform/resolvers/zod";
+import {
+ CaretSortIcon,
+ CheckIcon,
+} from "@radix-ui/react-icons";
+import { useForm } from "react-hook-form";
+import { z } from "zod";
+import { cn } from "@/lib/utils";
+import { toast } from "@/hooks/use-toast";
+import { Button} from "@/components/ui/button";
import {
Form,
FormControl,
@@ -16,14 +18,12 @@ import {
FormItem,
FormLabel,
FormMessage,
-} from "@/components/ui/form"
-import { Input } from "@/components/ui/input"
+} from "@/components/ui/form";
+import { Input } from "@/components/ui/input";
import React, { useState, useEffect } from "react";
import { api } from "@/api";
import { useParams } from "next/navigation";
import { useRouter } from "next/navigation";
-import { Checkbox } from "@app/components/ui/checkbox"
-
import {
Command,
CommandEmpty,
@@ -31,16 +31,15 @@ import {
CommandInput,
CommandItem,
CommandList,
-} from "@/components/ui/command"
-
+} from "@/components/ui/command";
import {
Popover,
PopoverContent,
PopoverTrigger,
-} from "@/components/ui/popover"
-import { ListSitesResponse } from "@server/routers/site"
-import { AxiosResponse } from "axios"
-import CustomDomainInput from "./CustomDomainInput"
+} from "@/components/ui/popover";
+import { ListSitesResponse } from "@server/routers/site";
+import { AxiosResponse } from "axios";
+import CustomDomainInput from "./CustomDomainInput";
const method = [
{ label: "Wireguard", value: "wg" },
@@ -57,14 +56,14 @@ const accountFormSchema = z.object({
message: "Name must not be longer than 30 characters.",
}),
name: z.string(),
- siteId: z.number()
+ siteId: z.number(),
});
type AccountFormValues = z.infer;
const defaultValues: Partial = {
subdomain: "someanimalherefromapi",
- name: "My Resource"
+ name: "My Resource",
};
export function CreateResourceForm() {
@@ -83,7 +82,9 @@ export function CreateResourceForm() {
useEffect(() => {
if (typeof window !== "undefined") {
const fetchSites = async () => {
- const res = await api.get>(`/org/${orgId}/sites/`);
+ const res = await api.get>(
+ `/org/${orgId}/sites/`
+ );
setSites(res.data.data.sites);
};
fetchSites();
@@ -101,21 +102,24 @@ export function CreateResourceForm() {
})
.catch((e) => {
toast({
- title: "Error creating resource..."
+ title: "Error creating resource...",
});
});
if (res && res.status === 201) {
const niceId = res.data.data.niceId;
// navigate to the resource page
- router.push(`/${orgId}/resources/${niceId}`);
+ router.push(`/${orgId}/settings/resources/${niceId}`);
}
}
return (
<>
-
+
- This is the name that will be displayed for this resource.
+ This is the name that will be displayed for
+ this resource.
@@ -140,35 +145,20 @@ export function CreateResourceForm() {
Subdomain
{/* */}
-
- This is the fully qualified domain name that will be used to access the resource.
+ This is the fully qualified domain name that
+ will be used to access the resource.
)}
/>
- {/* (
-
- Subdomain
-
-
-
-
- The subdomain of the resource. This will be used to access resources on the resource.
-
-
-
- )}
- /> */}
{field.value
? sites.find(
- (site) => site.siteId === field.value
- )?.name
+ (site) =>
+ site.siteId ===
+ field.value
+ )?.name
: "Select site"}
@@ -199,20 +192,26 @@ export function CreateResourceForm() {
- No site found.
+
+ No site found.
+
{sites.map((site) => (
{
- form.setValue("siteId", site.siteId)
+ form.setValue(
+ "siteId",
+ site.siteId
+ );
}}
>
- This is the site that will be used in the dashboard.
+ This is the site that will be used in the
+ dashboard.
diff --git a/src/app/[orgId]/resources/[resourceId]/components/CustomDomainInput.tsx b/src/app/[orgId]/settings/resources/[resourceId]/components/CustomDomainInput.tsx
similarity index 99%
rename from src/app/[orgId]/resources/[resourceId]/components/CustomDomainInput.tsx
rename to src/app/[orgId]/settings/resources/[resourceId]/components/CustomDomainInput.tsx
index d03b9333..b7b9c2ac 100644
--- a/src/app/[orgId]/resources/[resourceId]/components/CustomDomainInput.tsx
+++ b/src/app/[orgId]/settings/resources/[resourceId]/components/CustomDomainInput.tsx
@@ -16,7 +16,7 @@ export default function CustomDomainInput(
onChange,
}: CustomDomainInputProps = {
domainSuffix: ".example.com",
- },
+ }
) {
const [value, setValue] = React.useState("");
diff --git a/src/app/[orgId]/settings/resources/[resourceId]/components/GeneralForm.tsx b/src/app/[orgId]/settings/resources/[resourceId]/components/GeneralForm.tsx
new file mode 100644
index 00000000..777ed323
--- /dev/null
+++ b/src/app/[orgId]/settings/resources/[resourceId]/components/GeneralForm.tsx
@@ -0,0 +1,174 @@
+"use client";
+
+import { zodResolver } from "@hookform/resolvers/zod";
+import { z } from "zod";
+import { cn } from "@/lib/utils";
+import { Button } from "@/components/ui/button";
+import {
+ Form,
+ FormControl,
+ FormDescription,
+ FormField,
+ FormItem,
+ FormLabel,
+ FormMessage,
+} from "@/components/ui/form";
+import { CaretSortIcon, CheckIcon } from "@radix-ui/react-icons";
+import { Input } from "@/components/ui/input";
+import {
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
+} from "@/components/ui/command";
+
+import {
+ Popover,
+ PopoverContent,
+ PopoverTrigger,
+} from "@/components/ui/popover";
+import { useResourceContext } from "@app/hooks/useResourceContext";
+import { ListSitesResponse } from "@server/routers/site";
+import { useEffect, useState } from "react";
+import { AxiosResponse } from "axios";
+import api from "@app/api";
+import { useParams } from "next/navigation";
+import { useForm } from "react-hook-form";
+
+const GeneralFormSchema = z.object({
+ name: z.string(),
+ siteId: z.number(),
+});
+
+type GeneralFormValues = z.infer;
+
+export function GeneralForm() {
+ const params = useParams();
+ const orgId = params.orgId;
+ const { resource, updateResource } = useResourceContext();
+ const [sites, setSites] = useState([]);
+
+ const form = useForm({
+ resolver: zodResolver(GeneralFormSchema),
+ defaultValues: {
+ name: resource?.name,
+ siteId: resource?.siteId,
+ },
+ mode: "onChange",
+ });
+
+ useEffect(() => {
+ if (typeof window !== "undefined") {
+ const fetchSites = async () => {
+ const res = await api.get>(
+ `/org/${orgId}/sites/`
+ );
+ setSites(res.data.data.sites);
+ };
+ fetchSites();
+ }
+ }, []);
+
+ async function onSubmit(data: GeneralFormValues) {
+ await updateResource({ name: data.name, siteId: data.siteId });
+ }
+
+ return (
+
+
+ (
+
+ Name
+
+
+
+
+ This is the display name of the resource.
+
+
+
+ )}
+ />
+ (
+
+ Site
+
+
+
+
+ {field.value
+ ? sites.find(
+ (site) =>
+ site.siteId ===
+ field.value
+ )?.name
+ : "Select site"}
+
+
+
+
+
+
+
+
+
+ No site found.
+
+
+ {sites.map((site) => (
+ {
+ form.setValue(
+ "siteId",
+ site.siteId
+ );
+ }}
+ >
+
+ {site.name}
+
+ ))}
+
+
+
+
+
+
+ This is the site that will be used in the
+ dashboard.
+
+
+
+ )}
+ />
+ Update Resource
+
+
+ );
+}
diff --git a/src/app/[orgId]/settings/resources/[resourceId]/layout.tsx b/src/app/[orgId]/settings/resources/[resourceId]/layout.tsx
new file mode 100644
index 00000000..0e6eb108
--- /dev/null
+++ b/src/app/[orgId]/settings/resources/[resourceId]/layout.tsx
@@ -0,0 +1,51 @@
+import Image from "next/image";
+import ResourceProvider from "@app/providers/ResourceProvider";
+import { internal } from "@app/api";
+import { GetResourceResponse } from "@server/routers/resource";
+import { AxiosResponse } from "axios";
+import { redirect } from "next/navigation";
+import { authCookieHeader } from "@app/api/cookies";
+import Link from "next/link";
+import { ClientLayout } from "./components/ClientLayout";
+
+interface ResourceLayoutProps {
+ children: React.ReactNode;
+ params: Promise<{ resourceId: number | string; orgId: string }>;
+}
+
+export default async function ResourceLayout(props: ResourceLayoutProps) {
+ const params = await props.params;
+
+ const { children } = props;
+
+ let resource = null;
+
+ if (params.resourceId !== "create") {
+ try {
+ const res = await internal.get>(
+ `/resource/${params.resourceId}`,
+ await authCookieHeader()
+ );
+ resource = res.data.data;
+ } catch {
+ redirect(`/${params.orgId}/settings/resources`);
+ }
+ }
+
+ return (
+ <>
+
+
+
+
+
+
+ {children}
+
+
+ >
+ );
+}
diff --git a/src/app/[orgId]/resources/[resourceId]/page.tsx b/src/app/[orgId]/settings/resources/[resourceId]/page.tsx
similarity index 87%
rename from src/app/[orgId]/resources/[resourceId]/page.tsx
rename to src/app/[orgId]/settings/resources/[resourceId]/page.tsx
index 1487d406..9598ffcb 100644
--- a/src/app/[orgId]/resources/[resourceId]/page.tsx
+++ b/src/app/[orgId]/settings/resources/[resourceId]/page.tsx
@@ -3,11 +3,9 @@ import { Separator } from "@/components/ui/separator";
import { CreateResourceForm } from "./components/CreateResource";
import { GeneralForm } from "./components/GeneralForm";
-export default async function SettingsPage(
- props: {
- params: Promise<{ resourceId: number | string }>;
- }
-) {
+export default async function ResourcePage(props: {
+ params: Promise<{ resourceId: number | string }>;
+}) {
const params = await props.params;
const isCreate = params.resourceId === "create";
diff --git a/src/app/[orgId]/resources/[resourceId]/targets/page.tsx b/src/app/[orgId]/settings/resources/[resourceId]/targets/page.tsx
similarity index 100%
rename from src/app/[orgId]/resources/[resourceId]/targets/page.tsx
rename to src/app/[orgId]/settings/resources/[resourceId]/targets/page.tsx
diff --git a/src/app/[orgId]/resources/components/ResourcesDataTable.tsx b/src/app/[orgId]/settings/resources/components/ResourcesDataTable.tsx
similarity index 99%
rename from src/app/[orgId]/resources/components/ResourcesDataTable.tsx
rename to src/app/[orgId]/settings/resources/components/ResourcesDataTable.tsx
index 36c85ca4..6e6bbf47 100644
--- a/src/app/[orgId]/resources/components/ResourcesDataTable.tsx
+++ b/src/app/[orgId]/settings/resources/components/ResourcesDataTable.tsx
@@ -94,7 +94,7 @@ export function ResourcesDataTable({
: flexRender(
header.column.columnDef
.header,
- header.getContext(),
+ header.getContext()
)}
);
@@ -115,7 +115,7 @@ export function ResourcesDataTable({
{flexRender(
cell.column.columnDef.cell,
- cell.getContext(),
+ cell.getContext()
)}
))}
diff --git a/src/app/[orgId]/resources/components/ResourcesTable.tsx b/src/app/[orgId]/settings/resources/components/ResourcesTable.tsx
similarity index 86%
rename from src/app/[orgId]/resources/components/ResourcesTable.tsx
rename to src/app/[orgId]/settings/resources/components/ResourcesTable.tsx
index 47ef7148..63d2ec3e 100644
--- a/src/app/[orgId]/resources/components/ResourcesTable.tsx
+++ b/src/app/[orgId]/settings/resources/components/ResourcesTable.tsx
@@ -74,7 +74,7 @@ export const columns: ColumnDef[] = [
.then(() => {
router.refresh();
});
- }
+ };
return (
@@ -87,13 +87,18 @@ export const columns: ColumnDef[] = [
View settings
- deleteResource(resourceRow.id)} className="text-red-600 hover:text-red-800 hover:underline cursor-pointer">Delete
+ deleteResource(resourceRow.id)}
+ className="text-red-600 hover:text-red-800 hover:underline cursor-pointer"
+ >
+ Delete
+
@@ -115,7 +120,7 @@ export default function SitesTable({ resources, orgId }: ResourcesTableProps) {
columns={columns}
data={resources}
addResource={() => {
- router.push(`/${orgId}/resources/create`);
+ router.push(`/${orgId}/settings/resources/create`);
}}
/>
);
diff --git a/src/app/[orgId]/resources/page.tsx b/src/app/[orgId]/settings/resources/page.tsx
similarity index 92%
rename from src/app/[orgId]/resources/page.tsx
rename to src/app/[orgId]/settings/resources/page.tsx
index 1fb87654..6b6aa33c 100644
--- a/src/app/[orgId]/resources/page.tsx
+++ b/src/app/[orgId]/settings/resources/page.tsx
@@ -8,13 +8,13 @@ type ResourcesPageProps = {
params: Promise<{ orgId: string }>;
};
-export default async function Page(props: ResourcesPageProps) {
+export default async function ResourcesPage(props: ResourcesPageProps) {
const params = await props.params;
let resources: ListResourcesResponse["resources"] = [];
try {
const res = await internal.get>(
`/org/${params.orgId}/resources`,
- await authCookieHeader(),
+ await authCookieHeader()
);
resources = res.data.data.resources;
} catch (e) {
@@ -45,4 +45,4 @@ export default async function Page(props: ResourcesPageProps) {
>
);
-}
\ No newline at end of file
+}
diff --git a/src/app/[orgId]/sites/[niceId]/components/ClientLayout.tsx b/src/app/[orgId]/settings/sites/[niceId]/components/ClientLayout.tsx
similarity index 78%
rename from src/app/[orgId]/sites/[niceId]/components/ClientLayout.tsx
rename to src/app/[orgId]/settings/sites/[niceId]/components/ClientLayout.tsx
index 3b3049ee..d6feefdb 100644
--- a/src/app/[orgId]/sites/[niceId]/components/ClientLayout.tsx
+++ b/src/app/[orgId]/settings/sites/[niceId]/components/ClientLayout.tsx
@@ -6,20 +6,8 @@ import { useSiteContext } from "@app/hooks/useSiteContext";
const sidebarNavItems = [
{
title: "General",
- href: "/{orgId}/sites/{niceId}",
+ href: "/{orgId}/settings/sites/{niceId}",
},
- // {
- // title: "Appearance",
- // href: "/{orgId}/sites/{niceId}/appearance",
- // },
- // {
- // title: "Notifications",
- // href: "/{orgId}/sites/{niceId}/notifications",
- // },
- // {
- // title: "Display",
- // href: "/{orgId}/sites/{niceId}/display",
- // },
];
export function ClientLayout({ isCreate, children }: { isCreate: boolean; children: React.ReactNode }) {
diff --git a/src/app/[orgId]/sites/[niceId]/components/CreateSite.tsx b/src/app/[orgId]/settings/sites/[niceId]/components/CreateSite.tsx
similarity index 70%
rename from src/app/[orgId]/sites/[niceId]/components/CreateSite.tsx
rename to src/app/[orgId]/settings/sites/[niceId]/components/CreateSite.tsx
index 55b8e088..efe4497e 100644
--- a/src/app/[orgId]/sites/[niceId]/components/CreateSite.tsx
+++ b/src/app/[orgId]/settings/sites/[niceId]/components/CreateSite.tsx
@@ -1,13 +1,12 @@
-"use client"
+"use client";
-import { zodResolver } from "@hookform/resolvers/zod"
-import { CalendarIcon, CaretSortIcon, CheckIcon, ChevronDownIcon } from "@radix-ui/react-icons"
-import { useForm } from "react-hook-form"
-import { z } from "zod"
-
-import { cn } from "@/lib/utils"
-import { toast } from "@/hooks/use-toast"
-import { Button, buttonVariants } from "@/components/ui/button"
+import { zodResolver } from "@hookform/resolvers/zod";
+import { ChevronDownIcon } from "@radix-ui/react-icons";
+import { useForm } from "react-hook-form";
+import { z } from "zod";
+import { cn } from "@/lib/utils";
+import { toast } from "@/hooks/use-toast";
+import { Button, buttonVariants } from "@/components/ui/button";
import {
Form,
FormControl,
@@ -16,15 +15,15 @@ import {
FormItem,
FormLabel,
FormMessage,
-} from "@/components/ui/form"
-import { Input } from "@/components/ui/input"
+} from "@/components/ui/form";
+import { Input } from "@/components/ui/input";
import { generateKeypair } from "./wireguardConfig";
import React, { useState, useEffect } from "react";
import { api } from "@/api";
import { useParams } from "next/navigation";
import { useRouter } from "next/navigation";
-import { Checkbox } from "@app/components/ui/checkbox"
-import { PickSiteDefaultsResponse } from "@server/routers/site"
+import { Checkbox } from "@app/components/ui/checkbox";
+import { PickSiteDefaultsResponse } from "@server/routers/site";
const method = [
{ label: "Wireguard", value: "wg" },
@@ -47,7 +46,7 @@ type AccountFormValues = z.infer;
const defaultValues: Partial = {
name: "",
- method: "wg"
+ method: "wg",
};
export function CreateSiteForm() {
@@ -55,10 +54,14 @@ export function CreateSiteForm() {
const orgId = params.orgId;
const router = useRouter();
- const [keypair, setKeypair] = useState<{ publicKey: string; privateKey: string } | null>(null);
+ const [keypair, setKeypair] = useState<{
+ publicKey: string;
+ privateKey: string;
+ } | null>(null);
const [isLoading, setIsLoading] = useState(true);
const [isChecked, setIsChecked] = useState(false);
- const [siteDefaults, setSiteDefaults] = useState(null);
+ const [siteDefaults, setSiteDefaults] =
+ useState(null);
const handleCheckboxChange = (checked: boolean) => {
setIsChecked(checked);
@@ -75,17 +78,17 @@ export function CreateSiteForm() {
setKeypair(generatedKeypair);
setIsLoading(false);
- api
- .get(`/org/${orgId}/pickSiteDefaults`)
- .catch((e) => {
- toast({
- title: "Error creating site..."
+ api.get(`/org/${orgId}/pickSiteDefaults`)
+ .catch((e) => {
+ toast({
+ title: "Error creating site...",
+ });
+ })
+ .then((res) => {
+ if (res && res.status === 200) {
+ setSiteDefaults(res.data.data);
+ }
});
- }).then((res) => {
- if (res && res.status === 200) {
- setSiteDefaults(res.data.data);
- }
- });
}
}, []);
@@ -99,19 +102,20 @@ export function CreateSiteForm() {
})
.catch((e) => {
toast({
- title: "Error creating site..."
+ title: "Error creating site...",
});
});
if (res && res.status === 201) {
const niceId = res.data.data.niceId;
// navigate to the site page
- router.push(`/${orgId}/sites/${niceId}`);
+ router.push(`/${orgId}/settings/sites/${niceId}`);
}
}
- const wgConfig = keypair && siteDefaults
- ? `[Interface]
+ const wgConfig =
+ keypair && siteDefaults
+ ? `[Interface]
Address = ${siteDefaults.subnet}
ListenPort = 51820
PrivateKey = ${keypair.privateKey}
@@ -121,7 +125,7 @@ PublicKey = ${siteDefaults.publicKey}
AllowedIPs = ${siteDefaults.address.split("/")[0]}/32
Endpoint = ${siteDefaults.endpoint}:${siteDefaults.listenPort}
PersistentKeepalive = 5`
- : "";
+ : "";
const newtConfig = `curl -fsSL https://get.docker.com -o get-docker.sh
sh get-docker.sh`;
@@ -129,7 +133,10 @@ sh get-docker.sh`;
return (
<>
-
+
- This is the name that will be displayed for this site.
+ This is the name that will be displayed for
+ this site.
)}
/>
- {/* (
-
- Subdomain
-
-
-
-
- The subdomain of the site. This will be used to access resources on the site.
-
-
-
- )}
- /> */}
- WireGuard
+
+ WireGuard
+
Newt
- This is how you will connect your site to Fossorial.
+ This is how you will connect your site to
+ Fossorial.
@@ -192,18 +189,25 @@ sh get-docker.sh`;
/>
{form.watch("method") === "wg" && !isLoading ? (
- {wgConfig}
+
+ {wgConfig}
+
) : form.watch("method") === "wg" && isLoading ? (
Loading WireGuard configuration...
) : (
- {newtConfig}
+
+ {newtConfig}
+
)}
-
+
- Create Site
+
+ Create Site
+
>
diff --git a/src/app/[orgId]/settings/sites/[niceId]/components/GeneralForm.tsx b/src/app/[orgId]/settings/sites/[niceId]/components/GeneralForm.tsx
new file mode 100644
index 00000000..e380ffdd
--- /dev/null
+++ b/src/app/[orgId]/settings/sites/[niceId]/components/GeneralForm.tsx
@@ -0,0 +1,63 @@
+"use client";
+
+import { zodResolver } from "@hookform/resolvers/zod";
+import { z } from "zod";
+import { Button } from "@/components/ui/button";
+import {
+ Form,
+ FormControl,
+ FormDescription,
+ FormField,
+ FormItem,
+ FormLabel,
+ FormMessage,
+} from "@/components/ui/form";
+import { Input } from "@/components/ui/input";
+import { useSiteContext } from "@app/hooks/useSiteContext";
+import { useForm } from "react-hook-form";
+
+const GeneralFormSchema = z.object({
+ name: z.string(),
+});
+
+type GeneralFormValues = z.infer;
+
+export function GeneralForm() {
+ const { site, updateSite } = useSiteContext();
+
+ const form = useForm({
+ resolver: zodResolver(GeneralFormSchema),
+ defaultValues: {
+ name: site?.name,
+ },
+ mode: "onChange",
+ });
+
+ async function onSubmit(data: GeneralFormValues) {
+ await updateSite({ name: data.name });
+ }
+
+ return (
+
+
+ (
+
+ Name
+
+
+
+
+ This is the display name of the site.
+
+
+
+ )}
+ />
+ Update Site
+
+
+ );
+}
diff --git a/src/app/[orgId]/settings/sites/[niceId]/components/NewtConfig.tsx b/src/app/[orgId]/settings/sites/[niceId]/components/NewtConfig.tsx
new file mode 100644
index 00000000..e3e40dd8
--- /dev/null
+++ b/src/app/[orgId]/settings/sites/[niceId]/components/NewtConfig.tsx
@@ -0,0 +1,12 @@
+"use client";
+
+export function NewtConfig() {
+ const config = `curl -fsSL https://get.docker.com -o get-docker.sh
+sh get-docker.sh`;
+
+ return (
+
+ {config}
+
+ );
+}
diff --git a/src/app/[orgId]/sites/[niceId]/components/wireguardConfig.ts b/src/app/[orgId]/settings/sites/[niceId]/components/wireguardConfig.ts
similarity index 100%
rename from src/app/[orgId]/sites/[niceId]/components/wireguardConfig.ts
rename to src/app/[orgId]/settings/sites/[niceId]/components/wireguardConfig.ts
diff --git a/src/app/[orgId]/sites/[niceId]/layout.tsx b/src/app/[orgId]/settings/sites/[niceId]/layout.tsx
similarity index 52%
rename from src/app/[orgId]/sites/[niceId]/layout.tsx
rename to src/app/[orgId]/settings/sites/[niceId]/layout.tsx
index fe151a4f..96dc25b8 100644
--- a/src/app/[orgId]/sites/[niceId]/layout.tsx
+++ b/src/app/[orgId]/settings/sites/[niceId]/layout.tsx
@@ -1,5 +1,3 @@
-import Image from "next/image";
-
import SiteProvider from "@app/providers/SiteProvider";
import { internal } from "@app/api";
import { GetSiteResponse } from "@server/routers/site";
@@ -9,11 +7,6 @@ import { authCookieHeader } from "@app/api/cookies";
import Link from "next/link";
import { ClientLayout } from "./components/ClientLayout";
-// export const metadata: Metadata = {
-// title: "Forms",
-// description: "Advanced form example using react-hook-form and Zod.",
-// };
-
interface SettingsLayoutProps {
children: React.ReactNode;
params: Promise<{ niceId: string; orgId: string }>;
@@ -22,9 +15,7 @@ interface SettingsLayoutProps {
export default async function SettingsLayout(props: SettingsLayoutProps) {
const params = await props.params;
- const {
- children
- } = props;
+ const { children } = props;
let site = null;
@@ -32,45 +23,26 @@ export default async function SettingsLayout(props: SettingsLayoutProps) {
try {
const res = await internal.get>(
`/org/${params.orgId}/site/${params.niceId}`,
- await authCookieHeader(),
+ await authCookieHeader()
);
site = res.data.data;
} catch {
- redirect(`/${params.orgId}/sites`);
+ redirect(`/${params.orgId}/settings/sites`);
}
}
return (
<>
-
-
-
-
-
-
+ >
-
- {children}
+
+ {children}
>
diff --git a/src/app/[orgId]/sites/[niceId]/page.tsx b/src/app/[orgId]/settings/sites/[niceId]/page.tsx
similarity index 88%
rename from src/app/[orgId]/sites/[niceId]/page.tsx
rename to src/app/[orgId]/settings/sites/[niceId]/page.tsx
index 84154f74..e611c73e 100644
--- a/src/app/[orgId]/sites/[niceId]/page.tsx
+++ b/src/app/[orgId]/settings/sites/[niceId]/page.tsx
@@ -3,11 +3,9 @@ import { Separator } from "@/components/ui/separator";
import { CreateSiteForm } from "./components/CreateSite";
import { GeneralForm } from "./components/GeneralForm";
-export default async function SettingsPage(
- props: {
- params: Promise<{ niceId: string }>;
- }
-) {
+export default async function SitePage(props: {
+ params: Promise<{ niceId: string }>;
+}) {
const params = await props.params;
const isCreate = params.niceId === "create";
diff --git a/src/app/[orgId]/sites/components/SitesDataTable.tsx b/src/app/[orgId]/settings/sites/components/SitesDataTable.tsx
similarity index 98%
rename from src/app/[orgId]/sites/components/SitesDataTable.tsx
rename to src/app/[orgId]/settings/sites/components/SitesDataTable.tsx
index dcbe954c..5d15238c 100644
--- a/src/app/[orgId]/sites/components/SitesDataTable.tsx
+++ b/src/app/[orgId]/settings/sites/components/SitesDataTable.tsx
@@ -23,7 +23,7 @@ import {
import { Button } from "@app/components/ui/button";
import { useState } from "react";
import { Input } from "@app/components/ui/input";
-import { DataTablePagination } from "../../../../components/DataTablePagination";
+import { DataTablePagination } from "../../../../../components/DataTablePagination";
import { Plus } from "lucide-react";
interface DataTableProps {
diff --git a/src/app/[orgId]/sites/components/SitesTable.tsx b/src/app/[orgId]/settings/sites/components/SitesTable.tsx
similarity index 95%
rename from src/app/[orgId]/sites/components/SitesTable.tsx
rename to src/app/[orgId]/settings/sites/components/SitesTable.tsx
index f5f3d29e..b8da14d9 100644
--- a/src/app/[orgId]/sites/components/SitesTable.tsx
+++ b/src/app/[orgId]/settings/sites/components/SitesTable.tsx
@@ -92,7 +92,7 @@ export const columns: ColumnDef[] = [
View settings
@@ -120,7 +120,7 @@ export default function SitesTable({ sites, orgId }: SitesTableProps) {
columns={columns}
data={sites}
addSite={() => {
- router.push(`/${orgId}/sites/create`);
+ router.push(`/${orgId}/settings/sites/create`);
}}
/>
);
diff --git a/src/app/[orgId]/sites/page.tsx b/src/app/[orgId]/settings/sites/page.tsx
similarity index 93%
rename from src/app/[orgId]/sites/page.tsx
rename to src/app/[orgId]/settings/sites/page.tsx
index 8ba61034..9dcc6a45 100644
--- a/src/app/[orgId]/sites/page.tsx
+++ b/src/app/[orgId]/settings/sites/page.tsx
@@ -8,13 +8,13 @@ type SitesPageProps = {
params: Promise<{ orgId: string }>;
};
-export default async function Page(props: SitesPageProps) {
+export default async function SitesPage(props: SitesPageProps) {
const params = await props.params;
let sites: ListSitesResponse["sites"] = [];
try {
const res = await internal.get>(
`/org/${params.orgId}/sites`,
- await authCookieHeader(),
+ await authCookieHeader()
);
sites = res.data.data.sites;
} catch (e) {
diff --git a/src/app/[orgId]/sites/[niceId]/components/GeneralForm.tsx b/src/app/[orgId]/sites/[niceId]/components/GeneralForm.tsx
deleted file mode 100644
index b5acd692..00000000
--- a/src/app/[orgId]/sites/[niceId]/components/GeneralForm.tsx
+++ /dev/null
@@ -1,173 +0,0 @@
-"use client"
-
-import Link from "next/link"
-import { zodResolver } from "@hookform/resolvers/zod"
-import { useFieldArray, useForm } from "react-hook-form"
-import { z } from "zod"
-
-import { cn } from "@/lib/utils"
-import { toast } from "@/hooks/use-toast"
-
-import { Button } from "@/components/ui/button"
-import {
- Form,
- FormControl,
- FormDescription,
- FormField,
- FormItem,
- FormLabel,
- FormMessage,
-} from "@/components/ui/form"
-import { Input } from "@/components/ui/input"
-import {
- Select,
- SelectContent,
- SelectItem,
- SelectTrigger,
- SelectValue,
-} from "@/components/ui/select"
-import { Textarea } from "@/components/ui/textarea"
-import { useSiteContext } from "@app/hooks/useSiteContext"
-
-const GeneralFormSchema = z.object({
- name: z.string()
- // email: z
- // .string({
- // required_error: "Please select an email to display.",
- // })
- // .email(),
- // bio: z.string().max(160).min(4),
- // urls: z
- // .array(
- // z.object({
- // value: z.string().url({ message: "Please enter a valid URL." }),
- // })
- // )
- // .optional(),
-})
-
-type GeneralFormValues = z.infer
-
-export function GeneralForm() {
- const { site, updateSite } = useSiteContext();
-
- const form = useForm({
- resolver: zodResolver(GeneralFormSchema),
- defaultValues: {
- name: site?.name
- },
- mode: "onChange",
- })
-
- // const { fields, append } = useFieldArray({
- // name: "urls",
- // control: form.control,
- // })
-
- async function onSubmit(data: GeneralFormValues) {
- await updateSite({ name: data.name });
- }
-
- return (
-
-
- (
-
- Name
-
-
-
-
- This is the display name of the site.
-
-
-
- )}
- />
- {/* (
-
- Email
-
-
-
-
-
-
-
- m@example.com
- m@google.com
- m@support.com
-
-
-
- You can manage verified email addresses in your{" "}
- email settings.
-
-
-
- )}
- />
- (
-
- Bio
-
-
-
-
- You can @mention other users and organizations to
- link to them.
-
-
-
- )}
- />
-
- {fields.map((field, index) => (
- (
-
-
- URLs
-
-
- Add links to your website, blog, or social media profiles.
-
-
-
-
-
-
- )}
- />
- ))}
- append({ value: "" })}
- >
- Add URL
-
-
*/}
- Update Site
-
-
- )
-}
diff --git a/src/app/[orgId]/sites/[niceId]/components/NewtConfig.tsx b/src/app/[orgId]/sites/[niceId]/components/NewtConfig.tsx
deleted file mode 100644
index 478c3d4e..00000000
--- a/src/app/[orgId]/sites/[niceId]/components/NewtConfig.tsx
+++ /dev/null
@@ -1,12 +0,0 @@
-"use client"
-
-export function NewtConfig() {
- const config = `curl -fsSL https://get.docker.com -o get-docker.sh
-sh get-docker.sh`;
-
- return (
-
- {config}
-
- );
-};
\ No newline at end of file
diff --git a/src/app/auth/layout.tsx b/src/app/auth/layout.tsx
index 189b6f6f..24bc8c11 100644
--- a/src/app/auth/layout.tsx
+++ b/src/app/auth/layout.tsx
@@ -1,3 +1,10 @@
+import { Metadata } from "next";
+
+export const metadata: Metadata = {
+ title: `Auth - Pangolin`,
+ description: "",
+};
+
type AuthLayoutProps = {
children: React.ReactNode;
};
@@ -5,9 +12,7 @@ type AuthLayoutProps = {
export default async function AuthLayout({ children }: AuthLayoutProps) {
return (
<>
-
- {children}
-
+ {children}
>
);
}
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index 44fd7068..9ce33521 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -3,12 +3,6 @@ import "./globals.css";
import { Inter } from "next/font/google";
import { Toaster } from "@/components/ui/toaster";
import { ThemeProvider } from "@app/providers/ThemeProvider";
-import { ListOrgsResponse } from "@server/routers/org";
-import { internal } from "@app/api";
-import { AxiosResponse } from "axios";
-import { authCookieHeader } from "@app/api/cookies";
-import { redirect } from "next/navigation";
-import { verifySession } from "@app/lib/auth/verifySession";
export const metadata: Metadata = {
title: `Dashboard - Pangolin`,
diff --git a/src/app/page.tsx b/src/app/page.tsx
index 6b6553a9..b1197cce 100644
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -46,7 +46,7 @@ export default async function Page(props: {
{orgs.map((org) => (
diff --git a/src/app/profile/layout.tsx b/src/app/profile/layout.tsx
index 5b7ee085..c8a5459e 100644
--- a/src/app/profile/layout.tsx
+++ b/src/app/profile/layout.tsx
@@ -3,7 +3,7 @@ import Image from "next/image"
import { Separator } from "@/components/ui/separator"
import { SidebarNav } from "@/components/sidebar-nav"
-import Header from "../[orgId]/components/Header"
+import Header from "../[orgId]/settings/components/Header"
export const metadata: Metadata = {
title: "Forms",
diff --git a/src/app/setup/layout.tsx b/src/app/setup/layout.tsx
index 0a861d7d..00fb0917 100644
--- a/src/app/setup/layout.tsx
+++ b/src/app/setup/layout.tsx
@@ -1,3 +1,10 @@
+import { Metadata } from "next";
+
+export const metadata: Metadata = {
+ title: `Setup - Pangolin`,
+ description: "",
+};
+
export default async function SetupLayout({
children,
}: {