diff --git a/.github/workflows/Deploy.yml b/.github/workflows/Deploy.yml index 76be8c1..6440c3f 100644 --- a/.github/workflows/Deploy.yml +++ b/.github/workflows/Deploy.yml @@ -30,13 +30,6 @@ jobs: username: ${{ secrets.DOCKER_USERNAME }} 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 id: meta uses: docker/metadata-action@v5 diff --git a/.github/workflows/sync.yml b/.github/workflows/sync.yml index e917047..ac09e07 100644 --- a/.github/workflows/sync.yml +++ b/.github/workflows/sync.yml @@ -25,8 +25,8 @@ jobs: uses: aormsby/Fork-Sync-With-Upstream-action@v3.4 with: upstream_sync_repo: hamster1963/nezha-dash - upstream_sync_branch: main - target_sync_branch: main + upstream_sync_branch: cloudflare + target_sync_branch: cloudflare target_repo_token: ${{ secrets.GITHUB_TOKEN }} # automatically generated, no need to set # Set test_mode true to run tests instead of the true action!! diff --git a/README.md b/README.md index 3857359..12dc995 100644 --- a/README.md +++ b/README.md @@ -8,34 +8,26 @@ | 一键部署到 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) | -| [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 | -| NezhaAuth | nezha 面板 API Token | 5hAY3QX6Nl9B3Uxxxx26KMvOMyXS1Udi | -| DefaultLocale | 面板默认显示语言(代码参考下表) | **默认**:en | -| ForceShowAllServers | 是否强制显示所有服务器 | **默认**:false | -| NEXT_PUBLIC_NezhaFetchInterval | 获取数据间隔(毫秒) | **默认**:2000 | -| NEXT_PUBLIC_ShowFlag | 是否显示旗帜 | **默认**:false | -| NEXT_PUBLIC_DisableCartoon | 是否禁用卡通人物 | **默认**:false | -| NEXT_PUBLIC_ShowTag | 是否显示标签 | **默认**:false | -| NEXT_PUBLIC_ShowNetTransfer | 是否显示流量信息 | **默认**:false | -| NEXT_PUBLIC_ForceUseSvgFlag | 是否强制使用SVG旗帜 | **默认**:false | -| NEXT_PUBLIC_CustomLogo | 自定义Logo | **示例**:https://nezha-cf.buycoffee.top/apple-touch-icon.png | -| NEXT_PUBLIC_CustomTitle | 自定义标题 | | -| NEXT_PUBLIC_CustomDescription | 自定义描述(无多语言支持) | | - -#### 多语言支持 - -| 语言 | 代码 | 是否完成翻译 | -| -------- | ---- | ------------ | -| 简体中文 | zh | 是 | -| 繁体中文 | zh-t | 是 | -| 英语 | en | 是 | -| 日语 | ja | 是 | +| 变量名 | 含义 | 示例 | +| ------------------------------ | ------------------------ | ------------------------------------------------------------- | +| NezhaBaseUrl | nezha 面板地址 | http://120.x.x.x:8008 | +| NezhaAuth | nezha 面板 API Token | 5hAY3QX6Nl9B3Uxxxx26KMvOMyXS1Udi | +| SitePassword | 页面密码 | 123456 | +| DefaultLocale | 面板默认显示语言 | **默认**:en [简中:zh 繁中:zh-t 英语:en 日语:ja] | +| ForceShowAllServers | 是否强制显示所有服务器 | **默认**:false | +| NEXT_PUBLIC_NezhaFetchInterval | 获取数据间隔(毫秒) | **默认**:2000 | +| NEXT_PUBLIC_ShowFlag | 是否显示旗帜 | **默认**:false | +| NEXT_PUBLIC_DisableCartoon | 是否禁用卡通人物 | **默认**:false | +| NEXT_PUBLIC_ShowTag | 是否显示标签 | **默认**:false | +| NEXT_PUBLIC_ShowNetTransfer | 是否显示流量信息 | **默认**:false | +| NEXT_PUBLIC_ForceUseSvgFlag | 是否强制使用SVG旗帜 | **默认**:false | +| NEXT_PUBLIC_CustomLogo | 自定义Logo | **示例**:https://nezha-cf.buycoffee.top/apple-touch-icon.png | +| NEXT_PUBLIC_CustomTitle | 自定义标题 | | +| NEXT_PUBLIC_CustomDescription | 自定义描述(无多语言支持) | | ![screen](/.github/shot-1.png) ![screen](/.github/shot-2.png) diff --git a/app/[locale]/(main)/ClientComponents/ServerDetailChartClient.tsx b/app/[locale]/(main)/ClientComponents/ServerDetailChartClient.tsx index 9e05bcb..43e41cc 100644 --- a/app/[locale]/(main)/ClientComponents/ServerDetailChartClient.tsx +++ b/app/[locale]/(main)/ClientComponents/ServerDetailChartClient.tsx @@ -1,5 +1,7 @@ "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 { Card, CardContent } from "@/components/ui/card"; import { ChartConfig, ChartContainer } from "@/components/ui/chart"; @@ -18,8 +20,6 @@ import { } from "recharts"; import useSWR from "swr"; -import { NezhaAPISafe } from "../../types/nezha-api"; - type cpuChartData = { timeStamp: string; cpu: number; @@ -83,7 +83,7 @@ export default function ServerDetailChartClient({ ); } - if (!data) return null; + if (!data) return ; return (
diff --git a/app/[locale]/(main)/ClientComponents/ServerDetailClient.tsx b/app/[locale]/(main)/ClientComponents/ServerDetailClient.tsx index 718f814..1c05446 100644 --- a/app/[locale]/(main)/ClientComponents/ServerDetailClient.tsx +++ b/app/[locale]/(main)/ClientComponents/ServerDetailClient.tsx @@ -1,5 +1,6 @@ "use client"; +import { ServerDetailLoading } from "@/app/[locale]/(main)/ClientComponents/ServerDetailLoading"; import { NezhaAPISafe } from "@/app/[locale]/types/nezha-api"; import { BackIcon } from "@/components/Icon"; import { Badge } from "@/components/ui/badge"; @@ -10,8 +11,6 @@ import { useLocale, useTranslations } from "next-intl"; import { useRouter } from "next/navigation"; import useSWR from "swr"; -import ServerDetailLoading from "./ServerDetailLoading"; - export default function ServerDetailClient({ server_id, }: { diff --git a/app/[locale]/(main)/ClientComponents/ServerDetailLoading.tsx b/app/[locale]/(main)/ClientComponents/ServerDetailLoading.tsx index 2dc538b..1036e3e 100644 --- a/app/[locale]/(main)/ClientComponents/ServerDetailLoading.tsx +++ b/app/[locale]/(main)/ClientComponents/ServerDetailLoading.tsx @@ -1,25 +1,11 @@ import { BackIcon } from "@/components/Icon"; -import { Separator } from "@/components/ui/separator"; import { Skeleton } from "@/components/ui/skeleton"; import { useLocale } from "next-intl"; import { useRouter } from "next/navigation"; -export default function ServerDetailLoading() { - const router = useRouter(); - const locale = useLocale(); +export function ServerDetailChartLoading() { return (
-
{ - router.push(`/${locale}/`); - }} - className="flex flex-none cursor-pointer font-semibold leading-none items-center break-all tracking-tight gap-0.5 text-xl" - > - - -
- -
@@ -31,3 +17,23 @@ export default function ServerDetailLoading() {
); } + +export function ServerDetailLoading() { + const router = useRouter(); + const locale = useLocale(); + + return ( + <> +
{ + router.push(`/${locale}/`); + }} + className="flex flex-none cursor-pointer font-semibold leading-none items-center break-all tracking-tight gap-0.5 text-xl" + > + + +
+ + + ); +} diff --git a/app/[locale]/(main)/header.tsx b/app/[locale]/(main)/header.tsx index a7d9ec7..e09323f 100644 --- a/app/[locale]/(main)/header.tsx +++ b/app/[locale]/(main)/header.tsx @@ -3,6 +3,7 @@ import { LanguageSwitcher } from "@/components/LanguageSwitcher"; import { ModeToggle } from "@/components/ThemeSwitcher"; import { Separator } from "@/components/ui/separator"; +import { Skeleton } from "@/components/ui/skeleton"; import getEnv from "@/lib/env-entry"; import { DateTime } from "luxon"; import { useTranslations } from "next-intl"; @@ -20,7 +21,6 @@ function Header() { const router = useRouter(); const locale = useLocale(); - return (
@@ -63,7 +63,7 @@ function Header() { // https://github.com/streamich/react-use/blob/master/src/useInterval.ts const useInterval = (callback: Function, delay?: number | null) => { - const savedCallback = useRef(() => { }); + const savedCallback = useRef(() => {}); useEffect(() => { savedCallback.current = callback; }); @@ -96,9 +96,9 @@ function Overview() {

{t("p_2390-2457_wherethetimeis")}

- {mouted && ( + {mouted ? (

{timeString}

- )} + ) : }
); diff --git a/app/[locale]/(main)/layout.tsx b/app/[locale]/(main)/layout.tsx index dd0530d..bb2a8de 100644 --- a/app/[locale]/(main)/layout.tsx +++ b/app/[locale]/(main)/layout.tsx @@ -1,20 +1,23 @@ import Footer from "@/app/[locale]/(main)/footer"; import Header from "@/app/[locale]/(main)/header"; import { auth } from "@/auth"; +import { SignIn } from "@/components/sign-in"; import getEnv from "@/lib/env-entry"; -import React from "react"; import { redirect } from "next/navigation"; -import { getLocale } from "next-intl/server"; +import React from "react"; type DashboardProps = { children: React.ReactNode; }; export default async function MainLayout({ children }: DashboardProps) { - const session = await auth() - const locale = await getLocale() + const session = await auth(); - if (!session && getEnv("SITE_PASSWORD")) { - redirect(`/${locale}/login`); + if (!session && getEnv("SitePassword")) { + if (getEnv("CF_PAGES")) { + redirect("/api/auth/signin"); + } else { + return ; + } } return ( diff --git a/app/[locale]/layout.tsx b/app/[locale]/layout.tsx index 2b2864f..db96506 100644 --- a/app/[locale]/layout.tsx +++ b/app/[locale]/layout.tsx @@ -1,4 +1,5 @@ // @auto-i18n-check. Please do not delete the line. +import { auth } from "@/auth"; import { locales } from "@/i18n-metadata"; import getEnv from "@/lib/env-entry"; import { cn } from "@/lib/utils"; @@ -13,7 +14,6 @@ import { Inter as FontSans } from "next/font/google"; import React from "react"; import "/node_modules/flag-icons/css/flag-icons.min.css"; -import { auth } from "@/auth"; const fontSans = FontSans({ subsets: ["latin"], @@ -41,6 +41,11 @@ export const viewport: Viewport = { userScalable: false, }; +// optimization: force static for vercel +export const dynamic = process.env.VERCEL ? "force-static" : "auto"; + +export const runtime = "edge"; + export async function generateStaticParams() { return locales.map((locale) => ({ locale })); } diff --git a/app/[locale]/not-found.tsx b/app/[locale]/not-found.tsx index 07cd8d6..237a1e0 100644 --- a/app/[locale]/not-found.tsx +++ b/app/[locale]/not-found.tsx @@ -2,7 +2,7 @@ import { useTranslations } from "next-intl"; import Image from "next/image"; import Link from "next/link"; -export const runtime = 'edge'; +export const runtime = "edge"; export default function NotFoundPage() { const t = useTranslations("NotFoundPage"); diff --git a/app/api/detail/route.ts b/app/api/detail/route.ts index 81538db..0cc589b 100644 --- a/app/api/detail/route.ts +++ b/app/api/detail/route.ts @@ -1,8 +1,10 @@ import { NezhaAPISafe } from "@/app/[locale]/types/nezha-api"; +import { auth } from "@/auth"; +import getEnv from "@/lib/env-entry"; import { GetServerDetail } from "@/lib/serverFetch"; 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 runtime = 'edge'; @@ -13,8 +15,7 @@ interface NezhaDataResponse { } export const GET = auth(async function GET(req) { - - if (!req.auth && getEnv("SITE_PASSWORD")) { + if (!req.auth && getEnv("SitePassword")) { return NextResponse.json({ message: "Not authenticated" }, { status: 401 }); } diff --git a/app/api/monitor/route.ts b/app/api/monitor/route.ts index 0f44513..f37462a 100644 --- a/app/api/monitor/route.ts +++ b/app/api/monitor/route.ts @@ -4,6 +4,8 @@ import getEnv from "@/lib/env-entry"; import { GetServerMonitor } from "@/lib/serverFetch"; import { NextResponse } from "next/server"; +export const runtime = "edge"; + export const dynamic = "force-dynamic"; export const runtime = 'edge'; @@ -13,8 +15,7 @@ interface NezhaDataResponse { } export const GET = auth(async function GET(req) { - - if (!req.auth && getEnv("SITE_PASSWORD")) { + if (!req.auth && getEnv("SitePassword")) { return NextResponse.json({ message: "Not authenticated" }, { status: 401 }); } diff --git a/app/api/server/route.ts b/app/api/server/route.ts index 41db0d5..1fe524d 100644 --- a/app/api/server/route.ts +++ b/app/api/server/route.ts @@ -1,13 +1,12 @@ - import { NezhaAPI, ServerApi } from "@/app/[locale]/types/nezha-api"; -import { auth } from "@/auth"; import { MakeOptional } from "@/app/[locale]/types/utils"; +import { auth } from "@/auth"; import getEnv from "@/lib/env-entry"; import { NextResponse } from "next/server"; export const dynamic = "force-dynamic"; -export const runtime = 'edge'; +export const runtime = "edge"; interface NezhaDataResponse { error?: string; @@ -15,8 +14,7 @@ interface NezhaDataResponse { } export const GET = auth(async function GET(req) { - - if (!req.auth && getEnv("SITE_PASSWORD")) { + if (!req.auth && getEnv("SitePassword")) { return NextResponse.json({ message: "Not authenticated" }, { status: 401 }); } diff --git a/auth.ts b/auth.ts index a908388..d53aeae 100644 --- a/auth.ts +++ b/auth.ts @@ -1,20 +1,21 @@ -import NextAuth from "next-auth" -import Credentials from "next-auth/providers/credentials" -import getEnv from "./lib/env-entry" - +import NextAuth from "next-auth"; +import Credentials from "next-auth/providers/credentials"; + +import getEnv from "./lib/env-entry"; + export const { handlers, signIn, signOut, auth } = NextAuth({ - secret:"this_is_nezha_dash_web_secret", + secret: "this_is_nezha_dash_web_secret", providers: [ Credentials({ credentials: { password: {}, }, authorize: async (credentials) => { - if (credentials.password === getEnv("SITE_PASSWORD")) { - return { id: "0" } + if (credentials.password === getEnv("SitePassword")) { + return { id: "0" }; } - return null + return null; }, }), ], -}) \ No newline at end of file +}); diff --git a/components/sign-in.tsx b/components/sign-in.tsx index 033ccf0..e16ccc3 100644 --- a/components/sign-in.tsx +++ b/components/sign-in.tsx @@ -1,42 +1,47 @@ -import Footer from "@/app/[locale]/(main)/footer" -import Header from "@/app/[locale]/(main)/header" -import { signIn } from "@/auth" -import { useLocale } from "next-intl" -import { redirect } from "next/navigation" +import Footer from "@/app/[locale]/(main)/footer"; +import Header from "@/app/[locale]/(main)/header"; +import { signIn } from "@/auth"; +import { useLocale } from "next-intl"; +import { redirect } from "next/navigation"; export const runtime = 'edge'; export function SignIn() { - const locale = useLocale() + const locale = useLocale(); - - async function handleSubmit(formData: FormData) { - 'use server' - try { - await signIn("credentials", formData) - } catch (error) { - redirect(`/${locale}`) - } + async function handleSubmit(formData: FormData) { + "use server"; + try { + await signIn("credentials", formData); + } catch (error) { + redirect(`/${locale}`); } + } - return ( -
-
-
-
-
- - -
-
-
-
-
- ) + return ( +
+
+
+
+
+ + +
+
+
+
+ ); } diff --git a/docker/docker-compose.yml.cn b/docker/docker-compose.yml.cn deleted file mode 100644 index 99a97c7..0000000 --- a/docker/docker-compose.yml.cn +++ /dev/null @@ -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" diff --git a/next.config.mjs b/next.config.mjs index 5713407..a68be47 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -25,7 +25,7 @@ const nextConfig = { reactStrictMode: true, experimental: { serverActions: { - allowedOrigins: ['*'], + allowedOrigins: ["*"], }, }, logging: {