- RouteModal: routeType, networkRange, domains, distributionGroups, metric - SetupKeyModal: createTitle, nameHelp, usageLimitHelp, expiresIn - CreateAccessTokenModal: tokenName, tokenNameHelp, tokenExpiresIn - Add corresponding keys to en.ts and zh.ts
10 KiB
10 KiB
仓库指南
项目概述
NetBird Dashboard 是 NetBird 管理服务的 Web 界面。这是一个 Next.js 应用程序,为 NetBird 网络提供网络管理、对等节点监控、访问控制和配置功能。
在线版本: https://app.netbird.io/ 源代码: https://github.com/netbirdio/dashboard
架构与数据流
技术栈
- 框架: Next.js 13+ 使用 App Router
- 语言: TypeScript
- 样式: Tailwind CSS + shadcn/ui 组件
- 状态管理: React Context + SWR 用于服务器状态
- 认证: OIDC 通过 @axa-fr/react-oidc
- 国际化: next-intl
- 测试: Cypress (E2E)
- 部署: Docker + Nginx
高级结构
src/
├── app/ # Next.js App Router 页面
│ ├── (dashboard)/ # 主仪表板路由(分组布局)
│ ├── (remote-access)/ # 远程访问路由
│ ├── install/ # 安装向导
│ ├── invite/ # 用户邀请流程
│ └── setup/ # 初始设置流程
├── assets/ # 静态资源(图标、图片、字体)
├── auth/ # OIDC 认证组件
├── components/ # 共享 UI 组件(基于 shadcn/ui)
├── contexts/ # React Context 提供者
├── hooks/ # 自定义 React 钩子
├── i18n/ # 国际化配置和消息
├── interfaces/ # TypeScript 类型定义
├── layouts/ # 布局组件
├── modules/ # 功能模块(领域特定)
└── utils/ # 工具函数
数据流
- 认证: OIDC 提供者处理认证 → 令牌存储在内存中
- API 调用:
useFetchApi钩子 → SWR → OIDC 请求 → 管理 API - 状态: 服务器状态通过 SWR 缓存,UI 状态通过 React Context
- 渲染: 默认使用服务器组件,需要时使用客户端组件
关键目录
src/app/ - 页面和路由
- 使用 Next.js App Router 和路由分组
(dashboard)/包含主要应用页面和共享布局- 每个路由有
page.tsx和可选的layout.tsx - 通过
error/page.tsx实现错误边界
src/modules/ - 功能模块
按功能组织的领域特定组件:
peers/- 对等节点管理组件networks/- 网络配置access-control/- ACL 策略dns/- DNS 管理routes/- 网络路由users/- 用户管理groups/- 分组管理setup-keys/- 设置密钥管理activity/- 活动日志settings/- 账户设置
src/components/ - 共享 UI 组件
基于 shadcn/ui 构建,具有自定义变体:
Input.tsx- 带验证的表单输入Select.tsx- 下拉选择Dialog.tsx- 模态对话框Table.tsx- 数据表格Button.tsx- 操作按钮Badge.tsx- 状态徽章Tooltip.tsx- 信息提示
src/contexts/ - 状态提供者
全局状态的 React Context 提供者:
ApplicationProvider.tsx- 应用级配置PeersProvider.tsx- 对等节点数据GroupsProvider.tsx- 分组数据RoutesProvider.tsx- 路由数据PoliciesProvider.tsx- ACL 策略PermissionsProvider.tsx- 用户权限GlobalThemeProvider.tsx- 主题管理LocaleProvider.tsx- 语言/区域设置
src/hooks/ - 自定义钩子
可复用的 React 钩子:
useLocalStorage.tsx- 持久化本地存储useDebounce.tsx- 防抖值useSearch.ts- 搜索功能useCopyToClipboard.ts- 剪贴板操作useElementSize.ts- DOM 元素尺寸useIntersectionObserver.ts- 可见性检测
src/interfaces/ - 类型定义
领域模型的 TypeScript 接口:
Peer.ts- 网络对等节点Group.ts- 对等节点分组Route.ts- 网络路由Nameserver.ts- DNS 名称服务器Account.ts- 用户账户SetupKey.ts- 设置密钥AccessToken.ts- API 访问令牌
src/utils/ - 工具函数
辅助函数:
api.tsx- 集成 SWR 的 API 客户端helpers.ts- 通用工具(cn, randomString 等)config.ts- 配置加载器ip.ts- IP 地址工具wireguard.ts- WireGuard 辅助函数version.ts- 版本比较
开发命令
# 安装依赖
npm install
# 启动开发服务器(端口 3000)
npm run dev
# 使用 Turbopack 启动(更快)
npm run turbo
# 构建生产版本
npm run build
# 启动生产服务器
npm start
# 运行代码检查
npm run lint
# 打开 Cypress 测试运行器
npm run cypress:open
# 复制 OIDC 服务工作者(认证必需)
npm run copy
npm run copytrusted
代码规范和常见模式
组件模式
// 使用 shadcn/ui 和 class-variance-authority 实现变体
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@utils/helpers";
const buttonVariants = cva("base-classes", {
variants: {
variant: {
default: "default-classes",
destructive: "destructive-classes",
},
},
});
interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {}
export function Button({ className, variant, ...props }: ButtonProps) {
return (
<button
className={cn(buttonVariants({ variant }), className)}
{...props}
/>
);
}
Context 提供者模式
import React, { useMemo } from "react";
import useFetchApi from "@utils/api";
const DataContext = React.createContext({} as DataType);
export default function DataProvider({ children }: { children: React.ReactNode }) {
const { data, isLoading } = useFetchApi<Data[]>("/endpoint");
const value = useMemo(() => ({ data, isLoading }), [data, isLoading]);
return (
<DataContext.Provider value={value}>
{children}
</DataContext.Provider>
);
}
export const useData = () => React.useContext(DataContext);
API 钩子模式
import useFetchApi from "@utils/api";
// GET 请求使用 SWR
const { data, isLoading, error } = useFetchApi<Data[]>("/endpoint");
// POST/PUT/DELETE 请求
const { mutate } = useFetchApi("/endpoint", { method: "POST" });
样式模式
import { cn } from "@utils/helpers";
// 合并 Tailwind 类
<div className={cn(
"base-classes",
condition && "conditional-classes",
className
)} />
导入顺序
由 simple-import-sort ESLint 插件强制执行:
- 副作用导入 (
import "polyfill") - 外部包 (
import React from "react") - 内部别名 (
import { Button } from "@/components") - 相对导入 (
import { useData } from "./context")
文件命名
- 组件: PascalCase (
PeerTable.tsx,GroupSelector.tsx) - 钩子: camelCase 带
use前缀 (useLocalStorage.tsx) - 工具函数: camelCase (
helpers.ts,api.tsx) - 接口: PascalCase (
Peer.ts,Group.ts) - 页面:
page.tsx(Next.js App Router 要求) - 布局:
layout.tsx(Next.js App Router 要求)
重要文件
入口点
src/app/layout.tsx- 根布局(提供者、字体、元数据)src/app/(dashboard)/layout.tsx- 仪表板布局(导航、认证)src/app/page.tsx- 首页重定向
配置文件
next.config.js- Next.js 配置tailwind.config.ts- Tailwind CSS 配置components.json- shadcn/ui 配置config.json- 应用配置(API 端点、认证).eslintrc.json- ESLint 规则tsconfig.json- TypeScript 配置
关键工具
src/utils/api.tsx- API 客户端(SWR + OIDC)src/utils/config.ts- 配置加载器src/utils/helpers.ts- 共享工具src/auth/OIDCProvider.tsx- 认证提供者
运行时/工具偏好
必需环境
- Node.js 18+(推荐 LTS)
- npm(包管理器)
本地开发设置
- 克隆仓库
- 创建
.local-config.json覆盖config.json中的值 - 运行
npm install - 运行
npm run copy(复制 OIDC 服务工作者) - 运行
npm run dev
Docker 部署
docker run -d --name netbird-dashboard \
-p 80:80 \
-e AUTH0_DOMAIN=<domain> \
-e AUTH0_CLIENT_ID=<client-id> \
-e AUTH0_AUDIENCE=<audience> \
-e NETBIRD_MGMT_API_ENDPOINT=<api-url> \
netbirdio/dashboard:main
配置
config.json- 默认配置.local-config.json- 本地覆盖(已忽略)- Docker 部署的环境变量
测试与质量保证
E2E 测试(Cypress)
# 打开 Cypress UI
npm run cypress:open
# 无头运行测试
npx cypress run
测试位置: cypress/e2e/
支持文件: cypress/support/
测试数据: cypress/fixtures/
代码检查
npm run lint
ESLint 配置:
next/core-web-vitals- Next.js 最佳实践prettier- 代码格式化simple-import-sort- 导入排序
类型检查
TypeScript 严格模式已启用。运行 npx tsc --noEmit 检查类型。
模块上下文
参见 docs/contexts/ 获取特定模块的详细文档:
peers.md- 对等节点管理模块networks.md- 网络配置模块access-control.md- ACL 策略模块dns.md- DNS 管理模块api-client.md- API 客户端模式authentication.md- OIDC 认证流程
常见问题与注意事项
OIDC 服务工作者
安装后必须运行 npm run copy 将 OIDC 服务工作者复制到 public/。
本地配置
创建 .local-config.json 覆盖 config.json 中的本地开发值。
静态导出
应用在 Next.js 配置中使用 output: "export" - 运行时无服务器端渲染。
暗黑模式
主题通过 GlobalThemeProvider 管理。使用 Tailwind 暗黑模式类。
API 端点
所有 API 调用通过 src/utils/api.tsx,它处理:
- OIDC 令牌注入
- 令牌刷新
- 错误处理
- SWR 缓存
快速参考
添加新页面
- 创建
src/app/(dashboard)/new-page/page.tsx - 在
src/layouts/Navigation.tsx中添加导航 - 如需要,在
src/contexts/中创建上下文提供者 - 在
src/interfaces/中添加类型
添加新组件
- 在
src/components/(共享)或src/modules/<feature>/(功能特定)中创建 - 遵循 shadcn/ui 模式并实现变体
- 从组件文件导出
添加新 API 端点
- 在组件或上下文中使用
useFetchApi钩子 - 在
src/interfaces/中添加 TypeScript 接口 - 如果数据在组件间共享,创建上下文提供者
添加新模块
- 在
src/modules/<feature>/中创建目录 - 为该功能添加组件
- 在
src/contexts/中创建上下文提供者 - 在
src/app/(dashboard)/<feature>/中添加页面 - 更新导航
本文档由 AI 自动生成。随着代码库的发展而更新。