diff --git a/app/api/applications/get/route.ts b/app/api/applications/get/route.ts
index 5c0eaab..9f64dc0 100644
--- a/app/api/applications/get/route.ts
+++ b/app/api/applications/get/route.ts
@@ -32,6 +32,8 @@ export async function POST(request: NextRequest) {
}
});
+ const servers_all = await prisma.server.findMany()
+
const applicationsWithServers = applications.map(app => ({
...app,
server: servers.find(s => s.id === app.serverId)?.name || 'No server'
@@ -42,7 +44,7 @@ export async function POST(request: NextRequest) {
return NextResponse.json({
applications: applicationsWithServers,
- servers,
+ servers: servers_all,
maxPage
});
} catch (error: any) {
diff --git a/app/dashboard/applications/Applications.tsx b/app/dashboard/applications/Applications.tsx
index ec4b8d7..d86c549 100644
--- a/app/dashboard/applications/Applications.tsx
+++ b/app/dashboard/applications/Applications.tsx
@@ -75,7 +75,7 @@ export default function Dashboard() {
const [loading, setLoading] = useState(true);
useEffect(() => {
- const savedLayout = Cookies.get('layoutPreference');
+ const savedLayout = Cookies.get('layoutPreference-app');
const layout_bool = savedLayout === 'grid'
setIsGridLayout(layout_bool);
setItemsPerPage(layout_bool ? 15 : 5)
@@ -84,7 +84,7 @@ export default function Dashboard() {
const toggleLayout = () => {
const newLayout = !isGridLayout;
setIsGridLayout(newLayout);
- Cookies.set('layoutPreference', newLayout ? 'grid' : 'standard', {
+ Cookies.set('layoutPreference-app', newLayout ? 'grid' : 'standard', {
expires: 365,
path: '/',
sameSite: 'strict'
diff --git a/app/dashboard/servers/Servers.tsx b/app/dashboard/servers/Servers.tsx
index bf82b38..a15d877 100644
--- a/app/dashboard/servers/Servers.tsx
+++ b/app/dashboard/servers/Servers.tsx
@@ -76,14 +76,14 @@ export default function Dashboard() {
const [loading, setLoading] = useState(true);
useEffect(() => {
- const savedLayout = Cookies.get('layoutPreference');
+ const savedLayout = Cookies.get('layoutPreference-servers');
setIsGridLayout(savedLayout === 'grid');
}, []);
const toggleLayout = () => {
const newLayout = !isGridLayout;
setIsGridLayout(newLayout);
- Cookies.set('layoutPreference', newLayout ? 'grid' : 'standard', {
+ Cookies.set('layoutPreference-servers', newLayout ? 'grid' : 'standard', {
expires: 365,
path: '/',
sameSite: 'strict'
diff --git a/app/dashboard/settings/Settings.tsx b/app/dashboard/settings/Settings.tsx
new file mode 100644
index 0000000..e245c13
--- /dev/null
+++ b/app/dashboard/settings/Settings.tsx
@@ -0,0 +1,78 @@
+import { AppSidebar } from "@/components/app-sidebar"
+import {
+ Breadcrumb,
+ BreadcrumbItem,
+ BreadcrumbList,
+ BreadcrumbPage,
+ BreadcrumbSeparator,
+} from "@/components/ui/breadcrumb"
+import { Separator } from "@/components/ui/separator"
+import {
+ SidebarInset,
+ SidebarProvider,
+ SidebarTrigger,
+} from "@/components/ui/sidebar"
+import { Card, CardHeader } from "@/components/ui/card"
+import { useTheme } from "next-themes"
+import {
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
+} from "@/components/ui/select"
+
+export default function Settings() {
+ const { theme, setTheme } = useTheme()
+
+ return (
+
+
+
+
+
+
Settings
+
+
+
+ Theme
+
+
+
+
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/app/dashboard/settings/page.tsx b/app/dashboard/settings/page.tsx
new file mode 100644
index 0000000..4334702
--- /dev/null
+++ b/app/dashboard/settings/page.tsx
@@ -0,0 +1,59 @@
+"use client";
+
+import { useEffect, useState } from "react";
+import Cookies from "js-cookie";
+import { useRouter } from "next/navigation";
+import Settings from "./Settings"
+import axios from "axios";
+
+export default function DashboardPage() {
+ const router = useRouter();
+ const [isAuthChecked, setIsAuthChecked] = useState(false);
+ const [isValid, setIsValid] = useState(false);
+
+ useEffect(() => {
+ const token = Cookies.get("token");
+ if (!token) {
+ router.push("/");
+ } else {
+ const checkToken = async () => {
+ try {
+ const response = await axios.post("/api/auth/validate", {
+ token: token,
+ });
+
+ if (response.status === 200) {
+ setIsValid(true);
+ }
+ } catch (error: any) {
+ Cookies.remove("token");
+ router.push("/");
+ }
+ }
+ checkToken();
+ }
+ setIsAuthChecked(true);
+ }, [router]);
+
+ if (!isAuthChecked) {
+ return (
+
+
+
+
Loading...
+
+
+ )
+ }
+
+ return isValid ? : null;
+}
\ No newline at end of file
diff --git a/app/layout.tsx b/app/layout.tsx
index 1ca1b4b..332c576 100644
--- a/app/layout.tsx
+++ b/app/layout.tsx
@@ -30,7 +30,7 @@ export default function RootLayout({
>
diff --git a/components/app-sidebar.tsx b/components/app-sidebar.tsx
index a90016b..f2a601d 100644
--- a/components/app-sidebar.tsx
+++ b/components/app-sidebar.tsx
@@ -50,7 +50,7 @@ const data = {
{
title: "Settings",
icon: Settings,
- url: "/Dashboard/setting",
+ url: "/dashboard/settings",
},
],
}
diff --git a/components/ui/dropdown-menu.tsx b/components/ui/dropdown-menu.tsx
new file mode 100644
index 0000000..ec51e9c
--- /dev/null
+++ b/components/ui/dropdown-menu.tsx
@@ -0,0 +1,257 @@
+"use client"
+
+import * as React from "react"
+import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
+import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"
+
+import { cn } from "@/lib/utils"
+
+function DropdownMenu({
+ ...props
+}: React.ComponentProps) {
+ return
+}
+
+function DropdownMenuPortal({
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+function DropdownMenuTrigger({
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+function DropdownMenuContent({
+ className,
+ sideOffset = 4,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+
+
+ )
+}
+
+function DropdownMenuGroup({
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+function DropdownMenuItem({
+ className,
+ inset,
+ variant = "default",
+ ...props
+}: React.ComponentProps & {
+ inset?: boolean
+ variant?: "default" | "destructive"
+}) {
+ return (
+
+ )
+}
+
+function DropdownMenuCheckboxItem({
+ className,
+ children,
+ checked,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+
+
+
+
+
+ {children}
+
+ )
+}
+
+function DropdownMenuRadioGroup({
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+function DropdownMenuRadioItem({
+ className,
+ children,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+
+
+
+
+
+ {children}
+
+ )
+}
+
+function DropdownMenuLabel({
+ className,
+ inset,
+ ...props
+}: React.ComponentProps & {
+ inset?: boolean
+}) {
+ return (
+
+ )
+}
+
+function DropdownMenuSeparator({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+function DropdownMenuShortcut({
+ className,
+ ...props
+}: React.ComponentProps<"span">) {
+ return (
+
+ )
+}
+
+function DropdownMenuSub({
+ ...props
+}: React.ComponentProps) {
+ return
+}
+
+function DropdownMenuSubTrigger({
+ className,
+ inset,
+ children,
+ ...props
+}: React.ComponentProps & {
+ inset?: boolean
+}) {
+ return (
+
+ {children}
+
+
+ )
+}
+
+function DropdownMenuSubContent({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+export {
+ DropdownMenu,
+ DropdownMenuPortal,
+ DropdownMenuTrigger,
+ DropdownMenuContent,
+ DropdownMenuGroup,
+ DropdownMenuLabel,
+ DropdownMenuItem,
+ DropdownMenuCheckboxItem,
+ DropdownMenuRadioGroup,
+ DropdownMenuRadioItem,
+ DropdownMenuSeparator,
+ DropdownMenuShortcut,
+ DropdownMenuSub,
+ DropdownMenuSubTrigger,
+ DropdownMenuSubContent,
+}
diff --git a/package-lock.json b/package-lock.json
index f326c3e..70208ee 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -12,6 +12,7 @@
"@prisma/extension-accelerate": "^1.3.0",
"@radix-ui/react-alert-dialog": "^1.1.7",
"@radix-ui/react-dialog": "^1.1.7",
+ "@radix-ui/react-dropdown-menu": "^2.1.7",
"@radix-ui/react-label": "^2.1.3",
"@radix-ui/react-select": "^2.1.7",
"@radix-ui/react-separator": "^1.1.3",
@@ -1332,6 +1333,35 @@
}
}
},
+ "node_modules/@radix-ui/react-dropdown-menu": {
+ "version": "2.1.7",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.7.tgz",
+ "integrity": "sha512-7/1LiuNZuCQE3IzdicGoHdQOHkS2Q08+7p8w6TXZ6ZjgAULaCI85ZY15yPl4o4FVgoKLRT43/rsfNVN8osClQQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.2",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-id": "1.1.1",
+ "@radix-ui/react-menu": "2.1.7",
+ "@radix-ui/react-primitive": "2.0.3",
+ "@radix-ui/react-use-controllable-state": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@radix-ui/react-focus-guards": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.2.tgz",
@@ -1413,6 +1443,46 @@
}
}
},
+ "node_modules/@radix-ui/react-menu": {
+ "version": "2.1.7",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.7.tgz",
+ "integrity": "sha512-tBODsrk68rOi1/iQzbM54toFF+gSw/y+eQgttFflqlGekuSebNqvFNHjJgjqPhiMb4Fw9A0zNFly1QT6ZFdQ+Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.2",
+ "@radix-ui/react-collection": "1.1.3",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-direction": "1.1.1",
+ "@radix-ui/react-dismissable-layer": "1.1.6",
+ "@radix-ui/react-focus-guards": "1.1.2",
+ "@radix-ui/react-focus-scope": "1.1.3",
+ "@radix-ui/react-id": "1.1.1",
+ "@radix-ui/react-popper": "1.2.3",
+ "@radix-ui/react-portal": "1.1.5",
+ "@radix-ui/react-presence": "1.1.3",
+ "@radix-ui/react-primitive": "2.0.3",
+ "@radix-ui/react-roving-focus": "1.1.3",
+ "@radix-ui/react-slot": "1.2.0",
+ "@radix-ui/react-use-callback-ref": "1.1.1",
+ "aria-hidden": "^1.2.4",
+ "react-remove-scroll": "^2.6.3"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@radix-ui/react-popper": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.3.tgz",
@@ -1516,6 +1586,37 @@
}
}
},
+ "node_modules/@radix-ui/react-roving-focus": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.3.tgz",
+ "integrity": "sha512-ufbpLUjZiOg4iYgb2hQrWXEPYX6jOLBbR27bDyAff5GYMRrCzcze8lukjuXVUQvJ6HZe8+oL+hhswDcjmcgVyg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.2",
+ "@radix-ui/react-collection": "1.1.3",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-direction": "1.1.1",
+ "@radix-ui/react-id": "1.1.1",
+ "@radix-ui/react-primitive": "2.0.3",
+ "@radix-ui/react-use-callback-ref": "1.1.1",
+ "@radix-ui/react-use-controllable-state": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@radix-ui/react-select": {
"version": "2.1.7",
"resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.1.7.tgz",
diff --git a/package.json b/package.json
index 59472ef..a76a688 100644
--- a/package.json
+++ b/package.json
@@ -13,6 +13,7 @@
"@prisma/extension-accelerate": "^1.3.0",
"@radix-ui/react-alert-dialog": "^1.1.7",
"@radix-ui/react-dialog": "^1.1.7",
+ "@radix-ui/react-dropdown-menu": "^2.1.7",
"@radix-ui/react-label": "^2.1.3",
"@radix-ui/react-select": "^2.1.7",
"@radix-ui/react-separator": "^1.1.3",