mirror of
https://github.com/hamster1963/nezha-dash.git
synced 2025-04-24 21:10:45 +08:00
Merge branch 'cloudflare' into cloudflare-dev
This commit is contained in:
commit
f248869b35
7
.github/workflows/Deploy.yml
vendored
7
.github/workflows/Deploy.yml
vendored
@ -30,13 +30,6 @@ jobs:
|
|||||||
username: ${{ secrets.DOCKER_USERNAME }}
|
username: ${{ secrets.DOCKER_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Login to AliYun Container Registry
|
|
||||||
uses: docker/login-action@v3
|
|
||||||
with:
|
|
||||||
registry: registry.cn-guangzhou.aliyuncs.com
|
|
||||||
username: ${{ secrets.ALI_USERNAME }}
|
|
||||||
password: ${{ secrets.ALI_TOKEN }}
|
|
||||||
|
|
||||||
- name: Extract metadata (tags, labels) for Docker
|
- name: Extract metadata (tags, labels) for Docker
|
||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@v5
|
uses: docker/metadata-action@v5
|
||||||
|
4
.github/workflows/sync.yml
vendored
4
.github/workflows/sync.yml
vendored
@ -25,8 +25,8 @@ jobs:
|
|||||||
uses: aormsby/Fork-Sync-With-Upstream-action@v3.4
|
uses: aormsby/Fork-Sync-With-Upstream-action@v3.4
|
||||||
with:
|
with:
|
||||||
upstream_sync_repo: hamster1963/nezha-dash
|
upstream_sync_repo: hamster1963/nezha-dash
|
||||||
upstream_sync_branch: main
|
upstream_sync_branch: cloudflare
|
||||||
target_sync_branch: main
|
target_sync_branch: cloudflare
|
||||||
target_repo_token: ${{ secrets.GITHUB_TOKEN }} # automatically generated, no need to set
|
target_repo_token: ${{ secrets.GITHUB_TOKEN }} # automatically generated, no need to set
|
||||||
|
|
||||||
# Set test_mode true to run tests instead of the true action!!
|
# Set test_mode true to run tests instead of the true action!!
|
||||||
|
16
README.md
16
README.md
@ -8,15 +8,16 @@
|
|||||||
| 一键部署到 Vercel-推荐 | Docker部署 | Cloudflare部署 | 如何更新? |
|
| 一键部署到 Vercel-推荐 | Docker部署 | Cloudflare部署 | 如何更新? |
|
||||||
| ----------------------------------------------------- | --------------------------------------------------------------- | ----------------------------------------------------------------------- | --------------------------------------------------------- |
|
| ----------------------------------------------------- | --------------------------------------------------------------- | ----------------------------------------------------------------------- | --------------------------------------------------------- |
|
||||||
| [部署简易教程](https://buycoffee.top/blog/tech/nezha) | [Docker 部署教程](https://buycoffee.top/blog/tech/nezha-docker) | [Cloudflare 部署教程](https://buycoffee.top/blog/tech/nezha-cloudflare) | [更新教程](https://buycoffee.top/blog/tech/nezha-upgrade) |
|
| [部署简易教程](https://buycoffee.top/blog/tech/nezha) | [Docker 部署教程](https://buycoffee.top/blog/tech/nezha-docker) | [Cloudflare 部署教程](https://buycoffee.top/blog/tech/nezha-cloudflare) | [更新教程](https://buycoffee.top/blog/tech/nezha-upgrade) |
|
||||||
| [Vercel-demo](https://nezha-dash-ruddy.vercel.app) | [Docker-demo](https://nezha-docker.buycoffee.tech) | [Cloudflare-demo](https://nezha-cloudflare.buycoffee.tech) |
|
| [Vercel-demo](https://nezha-vercel.buycoffee.top) | [Docker-demo](https://nezha-docker.buycoffee.tech) | [Cloudflare-demo](https://nezha-cloudflare.buycoffee.tech) |
|
||||||
|
|
||||||
#### 环境变量
|
#### 环境变量
|
||||||
|
|
||||||
| 变量名 | 含义 | 示例 |
|
| 变量名 | 含义 | 示例 |
|
||||||
| ------------------------------ | -------------------------------- | ------------------------------------------------------------- |
|
| ------------------------------ | ------------------------ | ------------------------------------------------------------- |
|
||||||
| NezhaBaseUrl | nezha 面板地址 | http://120.x.x.x:8008 |
|
| NezhaBaseUrl | nezha 面板地址 | http://120.x.x.x:8008 |
|
||||||
| NezhaAuth | nezha 面板 API Token | 5hAY3QX6Nl9B3Uxxxx26KMvOMyXS1Udi |
|
| NezhaAuth | nezha 面板 API Token | 5hAY3QX6Nl9B3Uxxxx26KMvOMyXS1Udi |
|
||||||
| DefaultLocale | 面板默认显示语言(代码参考下表) | **默认**:en |
|
| SitePassword | 页面密码 | 123456 |
|
||||||
|
| DefaultLocale | 面板默认显示语言 | **默认**:en [简中:zh 繁中:zh-t 英语:en 日语:ja] |
|
||||||
| ForceShowAllServers | 是否强制显示所有服务器 | **默认**:false |
|
| ForceShowAllServers | 是否强制显示所有服务器 | **默认**:false |
|
||||||
| NEXT_PUBLIC_NezhaFetchInterval | 获取数据间隔(毫秒) | **默认**:2000 |
|
| NEXT_PUBLIC_NezhaFetchInterval | 获取数据间隔(毫秒) | **默认**:2000 |
|
||||||
| NEXT_PUBLIC_ShowFlag | 是否显示旗帜 | **默认**:false |
|
| NEXT_PUBLIC_ShowFlag | 是否显示旗帜 | **默认**:false |
|
||||||
@ -28,15 +29,6 @@
|
|||||||
| NEXT_PUBLIC_CustomTitle | 自定义标题 | |
|
| NEXT_PUBLIC_CustomTitle | 自定义标题 | |
|
||||||
| NEXT_PUBLIC_CustomDescription | 自定义描述(无多语言支持) | |
|
| NEXT_PUBLIC_CustomDescription | 自定义描述(无多语言支持) | |
|
||||||
|
|
||||||
#### 多语言支持
|
|
||||||
|
|
||||||
| 语言 | 代码 | 是否完成翻译 |
|
|
||||||
| -------- | ---- | ------------ |
|
|
||||||
| 简体中文 | zh | 是 |
|
|
||||||
| 繁体中文 | zh-t | 是 |
|
|
||||||
| 英语 | en | 是 |
|
|
||||||
| 日语 | ja | 是 |
|
|
||||||
|
|
||||||

|

|
||||||

|

|
||||||

|

|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
|
import { ServerDetailChartLoading } from "@/app/[locale]/(main)/ClientComponents/ServerDetailLoading";
|
||||||
|
import { NezhaAPISafe } from "@/app/[locale]/types/nezha-api";
|
||||||
import AnimatedCircularProgressBar from "@/components/ui/animated-circular-progress-bar";
|
import AnimatedCircularProgressBar from "@/components/ui/animated-circular-progress-bar";
|
||||||
import { Card, CardContent } from "@/components/ui/card";
|
import { Card, CardContent } from "@/components/ui/card";
|
||||||
import { ChartConfig, ChartContainer } from "@/components/ui/chart";
|
import { ChartConfig, ChartContainer } from "@/components/ui/chart";
|
||||||
@ -18,8 +20,6 @@ import {
|
|||||||
} from "recharts";
|
} from "recharts";
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
|
|
||||||
import { NezhaAPISafe } from "../../types/nezha-api";
|
|
||||||
|
|
||||||
type cpuChartData = {
|
type cpuChartData = {
|
||||||
timeStamp: string;
|
timeStamp: string;
|
||||||
cpu: number;
|
cpu: number;
|
||||||
@ -83,7 +83,7 @@ export default function ServerDetailChartClient({
|
|||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (!data) return null;
|
if (!data) return <ServerDetailChartLoading />;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="grid md:grid-cols-2 lg:grid-cols-3 grid-cols-1 gap-3">
|
<section className="grid md:grid-cols-2 lg:grid-cols-3 grid-cols-1 gap-3">
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
|
import { ServerDetailLoading } from "@/app/[locale]/(main)/ClientComponents/ServerDetailLoading";
|
||||||
import { NezhaAPISafe } from "@/app/[locale]/types/nezha-api";
|
import { NezhaAPISafe } from "@/app/[locale]/types/nezha-api";
|
||||||
import { BackIcon } from "@/components/Icon";
|
import { BackIcon } from "@/components/Icon";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
@ -10,8 +11,6 @@ import { useLocale, useTranslations } from "next-intl";
|
|||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
|
|
||||||
import ServerDetailLoading from "./ServerDetailLoading";
|
|
||||||
|
|
||||||
export default function ServerDetailClient({
|
export default function ServerDetailClient({
|
||||||
server_id,
|
server_id,
|
||||||
}: {
|
}: {
|
||||||
|
@ -1,25 +1,11 @@
|
|||||||
import { BackIcon } from "@/components/Icon";
|
import { BackIcon } from "@/components/Icon";
|
||||||
import { Separator } from "@/components/ui/separator";
|
|
||||||
import { Skeleton } from "@/components/ui/skeleton";
|
import { Skeleton } from "@/components/ui/skeleton";
|
||||||
import { useLocale } from "next-intl";
|
import { useLocale } from "next-intl";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
|
|
||||||
export default function ServerDetailLoading() {
|
export function ServerDetailChartLoading() {
|
||||||
const router = useRouter();
|
|
||||||
const locale = useLocale();
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div
|
|
||||||
onClick={() => {
|
|
||||||
router.push(`/${locale}/`);
|
|
||||||
}}
|
|
||||||
className="flex flex-none cursor-pointer font-semibold leading-none items-center break-all tracking-tight gap-0.5 text-xl"
|
|
||||||
>
|
|
||||||
<BackIcon />
|
|
||||||
<Skeleton className="h-[20px] w-24 rounded-[5px] bg-muted-foreground/10 animate-none"></Skeleton>
|
|
||||||
</div>
|
|
||||||
<Skeleton className="flex flex-wrap gap-2 h-[100px] w-1/2 mt-3 rounded-[5px] bg-muted-foreground/10 animate-none"></Skeleton>
|
|
||||||
<Separator className="my-4" />
|
|
||||||
<section className="grid md:grid-cols-2 lg:grid-cols-3 grid-cols-1 gap-3">
|
<section className="grid md:grid-cols-2 lg:grid-cols-3 grid-cols-1 gap-3">
|
||||||
<Skeleton className="h-[182px] w-full rounded-[5px] bg-muted-foreground/10 animate-none"></Skeleton>
|
<Skeleton className="h-[182px] w-full rounded-[5px] bg-muted-foreground/10 animate-none"></Skeleton>
|
||||||
<Skeleton className="h-[182px] w-full rounded-[5px] bg-muted-foreground/10 animate-none"></Skeleton>
|
<Skeleton className="h-[182px] w-full rounded-[5px] bg-muted-foreground/10 animate-none"></Skeleton>
|
||||||
@ -31,3 +17,23 @@ export default function ServerDetailLoading() {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function ServerDetailLoading() {
|
||||||
|
const router = useRouter();
|
||||||
|
const locale = useLocale();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div
|
||||||
|
onClick={() => {
|
||||||
|
router.push(`/${locale}/`);
|
||||||
|
}}
|
||||||
|
className="flex flex-none cursor-pointer font-semibold leading-none items-center break-all tracking-tight gap-0.5 text-xl"
|
||||||
|
>
|
||||||
|
<BackIcon />
|
||||||
|
<Skeleton className="h-[20px] w-24 rounded-[5px] bg-muted-foreground/10 animate-none"></Skeleton>
|
||||||
|
</div>
|
||||||
|
<Skeleton className="flex flex-wrap gap-2 h-[81px] w-1/2 mt-3 rounded-[5px] bg-muted-foreground/10 animate-none"></Skeleton>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
import { LanguageSwitcher } from "@/components/LanguageSwitcher";
|
import { LanguageSwitcher } from "@/components/LanguageSwitcher";
|
||||||
import { ModeToggle } from "@/components/ThemeSwitcher";
|
import { ModeToggle } from "@/components/ThemeSwitcher";
|
||||||
import { Separator } from "@/components/ui/separator";
|
import { Separator } from "@/components/ui/separator";
|
||||||
|
import { Skeleton } from "@/components/ui/skeleton";
|
||||||
import getEnv from "@/lib/env-entry";
|
import getEnv from "@/lib/env-entry";
|
||||||
import { DateTime } from "luxon";
|
import { DateTime } from "luxon";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
@ -20,7 +21,6 @@ function Header() {
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const locale = useLocale();
|
const locale = useLocale();
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mx-auto w-full max-w-5xl">
|
<div className="mx-auto w-full max-w-5xl">
|
||||||
<section className="flex items-center justify-between">
|
<section className="flex items-center justify-between">
|
||||||
@ -96,9 +96,9 @@ function Overview() {
|
|||||||
<p className="text-sm font-medium opacity-50">
|
<p className="text-sm font-medium opacity-50">
|
||||||
{t("p_2390-2457_wherethetimeis")}
|
{t("p_2390-2457_wherethetimeis")}
|
||||||
</p>
|
</p>
|
||||||
{mouted && (
|
{mouted ? (
|
||||||
<p className="opacity-1 text-sm font-medium">{timeString}</p>
|
<p className="opacity-1 text-sm font-medium">{timeString}</p>
|
||||||
)}
|
) : <Skeleton className="h-[20px] w-[50px] rounded-[5px] bg-muted-foreground/10 animate-none"></Skeleton>}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
|
@ -1,20 +1,23 @@
|
|||||||
import Footer from "@/app/[locale]/(main)/footer";
|
import Footer from "@/app/[locale]/(main)/footer";
|
||||||
import Header from "@/app/[locale]/(main)/header";
|
import Header from "@/app/[locale]/(main)/header";
|
||||||
import { auth } from "@/auth";
|
import { auth } from "@/auth";
|
||||||
|
import { SignIn } from "@/components/sign-in";
|
||||||
import getEnv from "@/lib/env-entry";
|
import getEnv from "@/lib/env-entry";
|
||||||
import React from "react";
|
|
||||||
import { redirect } from "next/navigation";
|
import { redirect } from "next/navigation";
|
||||||
import { getLocale } from "next-intl/server";
|
import React from "react";
|
||||||
|
|
||||||
type DashboardProps = {
|
type DashboardProps = {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
};
|
};
|
||||||
export default async function MainLayout({ children }: DashboardProps) {
|
export default async function MainLayout({ children }: DashboardProps) {
|
||||||
const session = await auth()
|
const session = await auth();
|
||||||
const locale = await getLocale()
|
|
||||||
|
|
||||||
if (!session && getEnv("SITE_PASSWORD")) {
|
if (!session && getEnv("SitePassword")) {
|
||||||
redirect(`/${locale}/login`);
|
if (getEnv("CF_PAGES")) {
|
||||||
|
redirect("/api/auth/signin");
|
||||||
|
} else {
|
||||||
|
return <SignIn />;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
// @auto-i18n-check. Please do not delete the line.
|
// @auto-i18n-check. Please do not delete the line.
|
||||||
|
import { auth } from "@/auth";
|
||||||
import { locales } from "@/i18n-metadata";
|
import { locales } from "@/i18n-metadata";
|
||||||
import getEnv from "@/lib/env-entry";
|
import getEnv from "@/lib/env-entry";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
@ -13,7 +14,6 @@ import { Inter as FontSans } from "next/font/google";
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import "/node_modules/flag-icons/css/flag-icons.min.css";
|
import "/node_modules/flag-icons/css/flag-icons.min.css";
|
||||||
import { auth } from "@/auth";
|
|
||||||
|
|
||||||
const fontSans = FontSans({
|
const fontSans = FontSans({
|
||||||
subsets: ["latin"],
|
subsets: ["latin"],
|
||||||
@ -41,6 +41,11 @@ export const viewport: Viewport = {
|
|||||||
userScalable: false,
|
userScalable: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// optimization: force static for vercel
|
||||||
|
export const dynamic = process.env.VERCEL ? "force-static" : "auto";
|
||||||
|
|
||||||
|
export const runtime = "edge";
|
||||||
|
|
||||||
export async function generateStaticParams() {
|
export async function generateStaticParams() {
|
||||||
return locales.map((locale) => ({ locale }));
|
return locales.map((locale) => ({ locale }));
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ import { useTranslations } from "next-intl";
|
|||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
|
||||||
export const runtime = 'edge';
|
export const runtime = "edge";
|
||||||
|
|
||||||
export default function NotFoundPage() {
|
export default function NotFoundPage() {
|
||||||
const t = useTranslations("NotFoundPage");
|
const t = useTranslations("NotFoundPage");
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
import { NezhaAPISafe } from "@/app/[locale]/types/nezha-api";
|
import { NezhaAPISafe } from "@/app/[locale]/types/nezha-api";
|
||||||
|
import { auth } from "@/auth";
|
||||||
|
import getEnv from "@/lib/env-entry";
|
||||||
import { GetServerDetail } from "@/lib/serverFetch";
|
import { GetServerDetail } from "@/lib/serverFetch";
|
||||||
import { NextResponse } from "next/server";
|
import { NextResponse } from "next/server";
|
||||||
import { auth } from "@/auth"
|
|
||||||
import getEnv from "@/lib/env-entry";
|
export const runtime = 'edge';
|
||||||
|
|
||||||
export const dynamic = "force-dynamic";
|
export const dynamic = "force-dynamic";
|
||||||
export const runtime = 'edge';
|
export const runtime = 'edge';
|
||||||
@ -13,8 +15,7 @@ interface NezhaDataResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const GET = auth(async function GET(req) {
|
export const GET = auth(async function GET(req) {
|
||||||
|
if (!req.auth && getEnv("SitePassword")) {
|
||||||
if (!req.auth && getEnv("SITE_PASSWORD")) {
|
|
||||||
return NextResponse.json({ message: "Not authenticated" }, { status: 401 });
|
return NextResponse.json({ message: "Not authenticated" }, { status: 401 });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,8 @@ import getEnv from "@/lib/env-entry";
|
|||||||
import { GetServerMonitor } from "@/lib/serverFetch";
|
import { GetServerMonitor } from "@/lib/serverFetch";
|
||||||
import { NextResponse } from "next/server";
|
import { NextResponse } from "next/server";
|
||||||
|
|
||||||
|
export const runtime = "edge";
|
||||||
|
|
||||||
export const dynamic = "force-dynamic";
|
export const dynamic = "force-dynamic";
|
||||||
export const runtime = 'edge';
|
export const runtime = 'edge';
|
||||||
|
|
||||||
@ -13,8 +15,7 @@ interface NezhaDataResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const GET = auth(async function GET(req) {
|
export const GET = auth(async function GET(req) {
|
||||||
|
if (!req.auth && getEnv("SitePassword")) {
|
||||||
if (!req.auth && getEnv("SITE_PASSWORD")) {
|
|
||||||
return NextResponse.json({ message: "Not authenticated" }, { status: 401 });
|
return NextResponse.json({ message: "Not authenticated" }, { status: 401 });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
|
|
||||||
import { NezhaAPI, ServerApi } from "@/app/[locale]/types/nezha-api";
|
import { NezhaAPI, ServerApi } from "@/app/[locale]/types/nezha-api";
|
||||||
import { auth } from "@/auth";
|
|
||||||
import { MakeOptional } from "@/app/[locale]/types/utils";
|
import { MakeOptional } from "@/app/[locale]/types/utils";
|
||||||
|
import { auth } from "@/auth";
|
||||||
import getEnv from "@/lib/env-entry";
|
import getEnv from "@/lib/env-entry";
|
||||||
import { NextResponse } from "next/server";
|
import { NextResponse } from "next/server";
|
||||||
|
|
||||||
export const dynamic = "force-dynamic";
|
export const dynamic = "force-dynamic";
|
||||||
|
|
||||||
export const runtime = 'edge';
|
export const runtime = "edge";
|
||||||
|
|
||||||
interface NezhaDataResponse {
|
interface NezhaDataResponse {
|
||||||
error?: string;
|
error?: string;
|
||||||
@ -15,8 +14,7 @@ interface NezhaDataResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const GET = auth(async function GET(req) {
|
export const GET = auth(async function GET(req) {
|
||||||
|
if (!req.auth && getEnv("SitePassword")) {
|
||||||
if (!req.auth && getEnv("SITE_PASSWORD")) {
|
|
||||||
return NextResponse.json({ message: "Not authenticated" }, { status: 401 });
|
return NextResponse.json({ message: "Not authenticated" }, { status: 401 });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
15
auth.ts
15
auth.ts
@ -1,6 +1,7 @@
|
|||||||
import NextAuth from "next-auth"
|
import NextAuth from "next-auth";
|
||||||
import Credentials from "next-auth/providers/credentials"
|
import Credentials from "next-auth/providers/credentials";
|
||||||
import getEnv from "./lib/env-entry"
|
|
||||||
|
import getEnv from "./lib/env-entry";
|
||||||
|
|
||||||
export const { handlers, signIn, signOut, auth } = NextAuth({
|
export const { handlers, signIn, signOut, auth } = NextAuth({
|
||||||
secret: "this_is_nezha_dash_web_secret",
|
secret: "this_is_nezha_dash_web_secret",
|
||||||
@ -10,11 +11,11 @@ export const { handlers, signIn, signOut, auth } = NextAuth({
|
|||||||
password: {},
|
password: {},
|
||||||
},
|
},
|
||||||
authorize: async (credentials) => {
|
authorize: async (credentials) => {
|
||||||
if (credentials.password === getEnv("SITE_PASSWORD")) {
|
if (credentials.password === getEnv("SitePassword")) {
|
||||||
return { id: "0" }
|
return { id: "0" };
|
||||||
}
|
}
|
||||||
return null
|
return null;
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
})
|
});
|
||||||
|
@ -1,21 +1,20 @@
|
|||||||
import Footer from "@/app/[locale]/(main)/footer"
|
import Footer from "@/app/[locale]/(main)/footer";
|
||||||
import Header from "@/app/[locale]/(main)/header"
|
import Header from "@/app/[locale]/(main)/header";
|
||||||
import { signIn } from "@/auth"
|
import { signIn } from "@/auth";
|
||||||
import { useLocale } from "next-intl"
|
import { useLocale } from "next-intl";
|
||||||
import { redirect } from "next/navigation"
|
import { redirect } from "next/navigation";
|
||||||
|
|
||||||
export const runtime = 'edge';
|
export const runtime = 'edge';
|
||||||
|
|
||||||
export function SignIn() {
|
export function SignIn() {
|
||||||
const locale = useLocale()
|
const locale = useLocale();
|
||||||
|
|
||||||
|
|
||||||
async function handleSubmit(formData: FormData) {
|
async function handleSubmit(formData: FormData) {
|
||||||
'use server'
|
"use server";
|
||||||
try {
|
try {
|
||||||
await signIn("credentials", formData)
|
await signIn("credentials", formData);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
redirect(`/${locale}`)
|
redirect(`/${locale}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,13 +29,19 @@ export function SignIn() {
|
|||||||
<section className="flex flex-col items-start gap-2">
|
<section className="flex flex-col items-start gap-2">
|
||||||
<label className="flex flex-col items-start gap-1 ">
|
<label className="flex flex-col items-start gap-1 ">
|
||||||
<p className="text-base font-semibold">请输入页面密码</p>
|
<p className="text-base font-semibold">请输入页面密码</p>
|
||||||
<input className="px-1 border-[1px] rounded-[5px]" name="password" type="password" />
|
<input
|
||||||
|
className="px-1 border-[1px] rounded-[5px]"
|
||||||
|
name="password"
|
||||||
|
type="password"
|
||||||
|
/>
|
||||||
</label>
|
</label>
|
||||||
<button className=" px-1.5 py-0.5 w-fit text-sm font-semibold rounded-[8px] border bg-card hover:brightness-95 transition-all text-card-foreground shadow-lg shadow-neutral-200/40 dark:shadow-none">确认</button>
|
<button className=" px-1.5 py-0.5 w-fit text-sm font-semibold rounded-[8px] border bg-card hover:brightness-95 transition-all text-card-foreground shadow-lg shadow-neutral-200/40 dark:shadow-none">
|
||||||
|
确认
|
||||||
|
</button>
|
||||||
</section>
|
</section>
|
||||||
</form>
|
</form>
|
||||||
<Footer />
|
<Footer />
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
version: "3"
|
|
||||||
services:
|
|
||||||
nezha-dash:
|
|
||||||
container_name: nezha-dash
|
|
||||||
image: registry.cn-guangzhou.aliyuncs.com/hamster-home/nezha-dash:latest
|
|
||||||
volumes:
|
|
||||||
- ./.env:/app/.env
|
|
||||||
restart: always
|
|
||||||
ports:
|
|
||||||
- "4123:3000"
|
|
@ -25,7 +25,7 @@ const nextConfig = {
|
|||||||
reactStrictMode: true,
|
reactStrictMode: true,
|
||||||
experimental: {
|
experimental: {
|
||||||
serverActions: {
|
serverActions: {
|
||||||
allowedOrigins: ['*'],
|
allowedOrigins: ["*"],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
logging: {
|
logging: {
|
||||||
|
Loading…
Reference in New Issue
Block a user