diff --git a/src/api/api.ts b/src/api/api.ts index 8573440..4c9e6b6 100644 --- a/src/api/api.ts +++ b/src/api/api.ts @@ -6,7 +6,7 @@ interface CommonResponse { function buildUrl(path: string, data?: any): string { if (!data) return path - const url = new URL(path) + const url = new URL(window.location.origin + path) for (const key in data) { url.searchParams.append(key, data[key]) } @@ -25,7 +25,7 @@ let lastestRefreshTokenAt = 0 export async function fetcher(method: FetcherMethod, path: string, data?: any): Promise { let response - if (method === FetcherMethod.GET || method === FetcherMethod.DELETE) { + if (method === FetcherMethod.GET || method === FetcherMethod.DELETE) { response = await fetch(buildUrl(path, data), { method: "GET", }) diff --git a/src/api/oauth2.ts b/src/api/oauth2.ts new file mode 100644 index 0000000..6289b39 --- /dev/null +++ b/src/api/oauth2.ts @@ -0,0 +1,33 @@ +import { ModelOauth2LoginResponse } from "@/types" + +import { FetcherMethod, fetcher } from "./api" + +export enum Oauth2RequestType { + LOGIN = 1, + BIND = 2, +} + +export const getOauth2RedirectURL = async (provider: string, rType: Oauth2RequestType): Promise => { + return fetcher(FetcherMethod.GET, `/api/v1/oauth2/${provider}`, { + "type": rType, + }) +} + + +export const bindOauth2 = async (provider: string, state: string, code: string): Promise => { + return fetcher(FetcherMethod.POST, `/api/v1/oauth2/${provider}/bind`, { + "state": state, + "code": code, + }) +} + +export const unbindOauth2 = async (provider: string): Promise => { + return fetcher(FetcherMethod.POST, `/api/v1/oauth2/${provider}/unbind`) +} + + +export const oauth2callback = async (provider: string, state: string, code: string): Promise => { + return fetcher(FetcherMethod.POST, `/api/v1/oauth2/${provider}/callback`, { + state, code + }) +} diff --git a/src/components/install-commands.tsx b/src/components/install-commands.tsx index 6a92efd..86ac9df 100644 --- a/src/components/install-commands.tsx +++ b/src/components/install-commands.tsx @@ -8,7 +8,7 @@ import { import { useAuth } from "@/hooks/useAuth" import useSettings from "@/hooks/useSetting" import { copyToClipboard } from "@/lib/utils" -import { ModelProfile, ModelSettingResponse } from "@/types" +import { ModelProfile, ModelConfig } from "@/types" import i18next from "i18next" import { Check, Clipboard } from "lucide-react" import { forwardRef, useState } from "react" @@ -33,8 +33,8 @@ export const InstallCommandsMenu = forwardRef((p try { setCopy(true) if (!profile) throw new Error("Profile is not found.") - if (!settings) throw new Error("Settings is not found.") - await copyToClipboard(generateCommand(type, settings, profile) || "") + if (!settings?.config) throw new Error("Settings is not found.") + await copyToClipboard(generateCommand(type, settings!.config, profile) || "") } catch (e: Error | any) { console.error(e) toast(t("Error"), { @@ -88,7 +88,7 @@ export const InstallCommandsMenu = forwardRef((p const generateCommand = ( type: number, - { agent_secret_key, install_host, tls }: ModelSettingResponse, + { agent_secret_key, install_host, tls }: ModelConfig, { agent_secret, role }: ModelProfile, ) => { if (!install_host) throw new Error(i18next.t("Results.InstallHostRequired")) diff --git a/src/components/server.tsx b/src/components/server.tsx index c3f0d4e..fd77a21 100644 --- a/src/components/server.tsx +++ b/src/components/server.tsx @@ -62,7 +62,7 @@ export const ServerCard: React.FC = ({ data, mutate }) => { const [open, setOpen] = useState(false) const onSubmit = async (values: z.infer) => { - await updateServer(data.id, values) + await updateServer(data!.id!, values) setOpen(false) await mutate() form.reset() @@ -122,7 +122,6 @@ export const ServerCard: React.FC = ({ data, mutate }) => { {...field} value={conv.arrToStr(field.value || [])} onChange={(e) => { - console.log(field.value) const arr = conv .strToArr(e.target.value) .map(Number) diff --git a/src/hooks/useAuth.tsx b/src/hooks/useAuth.tsx index 4ffa543..3c3429f 100644 --- a/src/hooks/useAuth.tsx +++ b/src/hooks/useAuth.tsx @@ -5,11 +5,13 @@ import { useNavigate } from "react-router-dom" import { toast } from "sonner" import { useMainStore } from "./useMainStore" +import { oauth2callback } from "@/api/oauth2" const AuthContext = createContext({ profile: undefined, - login: () => {}, - logout: () => {}, + login: () => { }, + loginOauth2: () => { }, + logout: () => { }, }) export const AuthProvider = ({ children }: { children: React.ReactNode }) => { @@ -17,7 +19,7 @@ export const AuthProvider = ({ children }: { children: React.ReactNode }) => { const setProfile = useMainStore((store) => store.setProfile) useEffect(() => { - ;(async () => { + ; (async () => { try { const user = await getProfile() user.role = user.role || 0 @@ -43,6 +45,20 @@ export const AuthProvider = ({ children }: { children: React.ReactNode }) => { } } + const loginOauth2 = async (provider: string, state: string, code: string) => { + try { + await oauth2callback(provider, state, code) + const user = await getProfile() + user.role = user.role || 0 + setProfile(user) + navigate("/dashboard") + } catch (error: any) { + toast(error.message) + } finally { + window.history.replaceState({}, document.title, window.location.pathname) + } + } + const logout = () => { document.cookie.split(";").forEach(function (c) { document.cookie = c @@ -57,6 +73,7 @@ export const AuthProvider = ({ children }: { children: React.ReactNode }) => { () => ({ profile, login, + loginOauth2, logout, }), [profile], diff --git a/src/hooks/useSetting.tsx b/src/hooks/useSetting.tsx index cebccef..3f433e4 100644 --- a/src/hooks/useSetting.tsx +++ b/src/hooks/useSetting.tsx @@ -1,7 +1,8 @@ import { swrFetcher } from "@/api/api" -import { ModelSettingResponse } from "@/types" +import { GithubComNezhahqNezhaModelSettingResponseModelConfig } from "@/types" import useSWR from "swr" export default function useSetting() { - return useSWR("/api/v1/setting", swrFetcher) + return useSWR("/api/v1/setting", swrFetcher) } + diff --git a/src/routes/login.tsx b/src/routes/login.tsx index 215196d..5b20924 100644 --- a/src/routes/login.tsx +++ b/src/routes/login.tsx @@ -1,3 +1,4 @@ +import { getOauth2RedirectURL, Oauth2RequestType } from "@/api/oauth2" import { Button } from "@/components/ui/button" import { Form, @@ -9,10 +10,13 @@ import { } from "@/components/ui/form" import { Input } from "@/components/ui/input" import { useAuth } from "@/hooks/useAuth" +import useSetting from "@/hooks/useSetting" import { zodResolver } from "@hookform/resolvers/zod" import i18next from "i18next" +import { useEffect } from "react" import { useForm } from "react-hook-form" import { useTranslation } from "react-i18next" +import { toast } from "sonner" import { z } from "zod" const formSchema = z.object({ @@ -25,7 +29,17 @@ const formSchema = z.object({ }) function Login() { - const { login } = useAuth() + const { login, loginOauth2 } = useAuth() + const { data: settingData } = useSetting() + + useEffect(() => { + const oauth2Code = new URLSearchParams(window.location.search).get("code") + const oauth2State = new URLSearchParams(window.location.search).get("state") + const oauth2Provider = new URLSearchParams(window.location.search).get("provider") + if (oauth2Code && oauth2State && oauth2Provider) { + loginOauth2(oauth2Provider, oauth2State, oauth2Code) + } + }, [window.location.search]) const form = useForm>({ resolver: zodResolver(formSchema), @@ -39,6 +53,15 @@ function Login() { login(values.username, values.password) } + async function loginWith(provider: string) { + try { + const redirectUrl = await getOauth2RedirectURL(provider, Oauth2RequestType.LOGIN) + window.location.href = redirectUrl.redirect! + } catch (error: any) { + toast.error(error.message) + } + } + const { t } = useTranslation() return ( @@ -79,6 +102,11 @@ function Login() { +
+ {settingData?.config?.oauth2_providers?.map((p: string) => + + )} +
) } diff --git a/src/routes/profile.tsx b/src/routes/profile.tsx index 873b685..f8936e3 100644 --- a/src/routes/profile.tsx +++ b/src/routes/profile.tsx @@ -1,16 +1,62 @@ +import { bindOauth2, getOauth2RedirectURL, Oauth2RequestType, unbindOauth2 } from "@/api/oauth2" +import { getProfile } from "@/api/user" import { ProfileCard } from "@/components/profile" import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" +import { Button } from "@/components/ui/button" import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" import { useMainStore } from "@/hooks/useMainStore" import { useMediaQuery } from "@/hooks/useMediaQuery" import { useServer } from "@/hooks/useServer" +import useSetting from "@/hooks/useSetting" import { Boxes, Server } from "lucide-react" +import { useEffect } from "react" +import { toast } from "sonner" export default function ProfilePage() { - const { profile } = useMainStore() + const { profile, setProfile } = useMainStore() const { servers, serverGroups } = useServer() + const { data: settingData } = useSetting() const isDesktop = useMediaQuery("(min-width: 890px)") + useEffect(() => { + const oauth2Code = new URLSearchParams(window.location.search).get("code") + const oauth2State = new URLSearchParams(window.location.search).get("state") + const oauth2Provider = new URLSearchParams(window.location.search).get("provider") + if (oauth2Code && oauth2State && oauth2Provider) { + bindOauth2(oauth2Provider, oauth2State, oauth2Code) + .catch((error) => { + toast.error(error.message) + }) + .then(() => { + getProfile().then((profile) => { + setProfile(profile) + }) + }).finally(() => { + window.history.replaceState({}, document.title, window.location.pathname) + }) + } + }, [window.location.search]) + + const bindO2 = async (provider: string) => { + try { + const redirectUrl = await getOauth2RedirectURL(provider, Oauth2RequestType.BIND) + window.location.href = redirectUrl.redirect! + } catch (error: any) { + toast.error(error.message) + } + } + + const unbindO2 = async (provider: string) => { + try { + await unbindOauth2(provider) + getProfile().then((profile) => { + setProfile(profile) + }) + } catch (error: any) { + toast.error(error.message) + } + } + return ( profile && (
@@ -62,6 +108,22 @@ export default function ProfilePage() { {serverGroups?.length || 0} + + + + + Oauth2 bindings + + + + {settingData?.config?.oauth2_providers?.map((provider) =>
+ {provider}: {profile.oauth2_bind?.[provider.toLowerCase()]} {profile.oauth2_bind?.[provider.toLowerCase()] ? + + : + } +
)} +
+
diff --git a/src/routes/root.tsx b/src/routes/root.tsx index 4c91d09..b517785 100644 --- a/src/routes/root.tsx +++ b/src/routes/root.tsx @@ -13,14 +13,14 @@ export default function Root() { const { data: settingData, error } = useSetting() useEffect(() => { - document.title = settingData?.site_name || "哪吒监控 Nezha Monitoring" - }, [settingData?.site_name]) + document.title = settingData?.config?.site_name || "哪吒监控 Nezha Monitoring" + }, [settingData?.config?.site_name]) useEffect(() => { - if (settingData?.custom_code_dashboard) { - InjectContext(settingData?.custom_code_dashboard) + if (settingData?.config?.custom_code_dashboard) { + InjectContext(settingData?.config?.custom_code_dashboard) } - }, [settingData?.custom_code_dashboard]) + }, [settingData?.config?.custom_code_dashboard]) if (error) { throw error @@ -30,8 +30,8 @@ export default function Root() { return null } - if (settingData?.language && !localStorage.getItem("language")) { - i18n.changeLanguage(settingData?.language) + if (settingData?.config?.language && !localStorage.getItem("language")) { + i18n.changeLanguage(settingData?.config?.language) } return ( diff --git a/src/routes/settings.tsx b/src/routes/settings.tsx index f08961a..8d27ca3 100644 --- a/src/routes/settings.tsx +++ b/src/routes/settings.tsx @@ -67,31 +67,31 @@ export default function SettingsPage() { resolver: zodResolver(settingFormSchema), defaultValues: config ? { - ...config, - language: config.language, - site_name: config.site_name || "", - user_template: - config.user_template || - Object.keys(config.frontend_templates?.filter((t) => !t.is_admin) || {})[0] || - "user-dist", - } + ...config, + language: config?.config?.language, + site_name: config.config?.site_name || "", + user_template: + config.config?.user_template || + Object.keys(config.frontend_templates?.filter((t) => !t.is_admin) || {})[0] || + "user-dist", + } : { - ip_change_notification_group_id: 0, - cover: 1, - site_name: "", - language: "", - user_template: "user-dist", - }, + ip_change_notification_group_id: 0, + cover: 1, + site_name: "", + language: "", + user_template: "user-dist", + }, resetOptions: { keepDefaultValues: false, }, }) useEffect(() => { - if (config) { - form.reset(config) + if (config?.config) { + form.reset(config?.config) } - }, [config, form]) + }, [config?.config, form]) const onSubmit = async (values: z.infer) => { try { @@ -172,7 +172,7 @@ export default function SettingsPage() { (t) => t.path === value, ) if (template) { - form.setValue("user_template", template.path) + form.setValue("user_template", template!.path!) } }} > @@ -188,7 +188,7 @@ export default function SettingsPage() { ) || [] ).map((template) => (
- +
{template.name} @@ -229,15 +229,15 @@ export default function SettingsPage() { {!config?.frontend_templates?.find( (t) => t.path === field.value, )?.is_official && ( -
-
- {t("CommunityThemeWarning")} +
+
+ {t("CommunityThemeWarning")} +
+
+ {t("CommunityThemeDescription")} +
-
- {t("CommunityThemeDescription")} -
-
- )} + )} )} /> diff --git a/src/types/api.ts b/src/types/api.ts index fc96871..2899ec1 100644 --- a/src/types/api.ts +++ b/src/types/api.ts @@ -1,3 +1,4 @@ +/* eslint-disable */ /* tslint:disable */ /* * --------------------------------------------------------------- @@ -8,707 +9,738 @@ * --------------------------------------------------------------- */ -export interface GithubComNezhahqNezhaModelCommonResponseAny { - data: any - error: string - success: boolean -} - -export interface GithubComNezhahqNezhaModelCommonResponseArrayModelAlertRule { - data: ModelAlertRule[] - error: string - success: boolean -} - -export interface GithubComNezhahqNezhaModelCommonResponseArrayModelCron { - data: ModelCron[] - error: string - success: boolean -} - -export interface GithubComNezhahqNezhaModelCommonResponseArrayModelDDNSProfile { - data: ModelDDNSProfile[] - error: string - success: boolean -} - -export interface GithubComNezhahqNezhaModelCommonResponseArrayModelNAT { - data: ModelNAT[] - error: string - success: boolean -} - -export interface GithubComNezhahqNezhaModelCommonResponseArrayModelNotification { - data: ModelNotification[] - error: string - success: boolean -} - -export interface GithubComNezhahqNezhaModelCommonResponseArrayModelNotificationGroupResponseItem { - data: ModelNotificationGroupResponseItem[] - error: string - success: boolean -} - -export interface GithubComNezhahqNezhaModelCommonResponseArrayModelServer { - data: ModelServer[] - error: string - success: boolean -} - -export interface GithubComNezhahqNezhaModelCommonResponseArrayModelServerGroupResponseItem { - data: ModelServerGroupResponseItem[] - error: string - success: boolean -} - -export interface GithubComNezhahqNezhaModelCommonResponseArrayModelService { - data: ModelService[] - error: string - success: boolean -} - -export interface GithubComNezhahqNezhaModelCommonResponseArrayModelServiceInfos { - data: ModelServiceInfos[] - error: string - success: boolean -} - -export interface GithubComNezhahqNezhaModelCommonResponseArrayModelUser { - data: ModelUser[] - error: string - success: boolean -} - -export interface GithubComNezhahqNezhaModelCommonResponseArrayModelWAFApiMock { - data: ModelWAFApiMock[] - error: string - success: boolean -} - -export interface GithubComNezhahqNezhaModelCommonResponseArrayString { - data: string[] - error: string - success: boolean -} - -export interface GithubComNezhahqNezhaModelCommonResponseArrayUint64 { - data: number[] - error: string - success: boolean -} - -export interface GithubComNezhahqNezhaModelCommonResponseModelForceUpdateResponse { - data: ModelForceUpdateResponse - error: string - success: boolean -} - -export interface GithubComNezhahqNezhaModelCommonResponseModelLoginResponse { - data: ModelLoginResponse - error: string - success: boolean -} - -export interface GithubComNezhahqNezhaModelCommonResponseModelProfile { - data: ModelProfile - error: string - success: boolean -} - -export interface GithubComNezhahqNezhaModelCommonResponseModelServiceResponse { - data: ModelServiceResponse - error: string - success: boolean -} - -export interface GithubComNezhahqNezhaModelCommonResponseModelSettingResponse { - data: ModelSettingResponse - error: string - success: boolean -} - -export interface GithubComNezhahqNezhaModelCommonResponseUint64 { - data: number - error: string - success: boolean -} - -export interface ModelAlertRule { - created_at: string - enable: boolean - /** 失败时执行的触发任务id */ - fail_trigger_tasks: number[] - id: number - name: string - /** 该报警规则所在的通知组 */ - notification_group_id: number - /** 恢复时执行的触发任务id */ - recover_trigger_tasks: number[] - rules: ModelRule[] - /** 触发模式: 0-始终触发(默认) 1-单次触发 */ - trigger_mode: number - updated_at: string -} - -export interface ModelAlertRuleForm { - enable?: boolean - /** 失败时触发的任务id */ - fail_trigger_tasks: number[] - /** @minLength 1 */ - name: string - notification_group_id: number - /** 恢复时触发的任务id */ - recover_trigger_tasks: number[] - rules: ModelRule[] - /** @default 0 */ - trigger_mode: number -} - -export interface ModelCreateFMResponse { - session_id: string -} - -export interface ModelCreateTerminalResponse { - server_id: number - server_name: string - session_id: string -} - -export interface ModelCron { - command: string - /** 计划任务覆盖范围 (0:仅覆盖特定服务器 1:仅忽略特定服务器 2:由触发该计划任务的服务器执行) */ - cover: number - created_at: string - cron_job_id: number - id: number - /** 最后一次执行时间 */ - last_executed_at: string - /** 最后一次执行结果 */ - last_result: boolean - name: string - /** 指定通知方式的分组 */ - notification_group_id: number - /** 推送成功的通知 */ - push_successful: boolean - /** 分钟 小时 天 月 星期 */ - scheduler: string - servers: number[] - /** 0:计划任务 1:触发任务 */ - task_type: number - updated_at: string -} - -export interface ModelCronForm { - command?: string - /** @default 0 */ - cover: number - /** @minLength 1 */ - name: string - notification_group_id: number - push_successful?: boolean - scheduler: string - servers: number[] - /** - * 0:计划任务 1:触发任务 - * @default 0 - */ - task_type: number -} - -export interface ModelCycleTransferStats { - from: string - max: number - min: number - name: string - next_update: Record - server_name: Record - to: string - transfer: Record -} - -export interface ModelDDNSForm { - access_id?: string - access_secret?: string - domains: string[] - enable_ipv4?: boolean - enable_ipv6?: boolean - /** @default 3 */ - max_retries: number - /** @minLength 1 */ - name: string - provider: string - webhook_headers?: string - /** @default 1 */ - webhook_method?: number - webhook_request_body?: string - /** @default 1 */ - webhook_request_type?: number - webhook_url?: string -} - -export interface ModelDDNSProfile { - access_id: string - access_secret: string - created_at: string - domains: string[] - enable_ipv4: boolean - enable_ipv6: boolean - id: number - max_retries: number - name: string - provider: string - updated_at: string - webhook_headers: string - webhook_method: number - webhook_request_body: string - webhook_request_type: number - webhook_url: string -} - -export interface ModelForceUpdateResponse { - failure?: number[] - offline?: number[] - success?: number[] -} - -export interface ModelFrontendTemplate { - author: string - is_admin: boolean - is_official: boolean - name: string - path: string - repository: string - version: string -} - -export interface ModelGeoIP { - country_code: string - ip: ModelIP -} - -export interface ModelHost { - arch: string - boot_time: number - cpu: string[] - disk_total: number - gpu: string[] - mem_total: number - platform: string - platform_version: string - swap_total: number - version: string - virtualization: string -} - -export interface ModelHostState { - cpu: number - disk_used: number - gpu: number[] - load_1: number - load_15: number - load_5: number - mem_used: number - net_in_speed: number - net_in_transfer: number - net_out_speed: number - net_out_transfer: number - process_count: number - swap_used: number - tcp_conn_count: number - temperatures: ModelSensorTemperature[] - udp_conn_count: number - uptime: number -} - -export interface ModelIP { - ipv4_addr: string - ipv6_addr: string -} - -export interface ModelLoginRequest { - password: string - username: string -} - -export interface ModelLoginResponse { - expire: string - token: string -} - -export interface ModelNAT { - created_at: string - domain: string - host: string - id: number - name: string - server_id: number - updated_at: string -} - -export interface ModelNATForm { - domain: string - host: string - /** @minLength 1 */ - name: string - server_id: number -} - -export interface ModelNotification { - created_at: string - id: number - name: string - request_body: string - request_header: string - request_method: number - request_type: number - updated_at: string - url: string - verify_tls: boolean -} - -export interface ModelNotificationForm { - /** @minLength 1 */ - name: string - request_body: string - request_header: string - request_method: number - request_type: number - skip_check?: boolean - url: string - verify_tls?: boolean -} - -export interface ModelNotificationGroup { - created_at: string - id: number - name: string - updated_at: string -} - -export interface ModelNotificationGroupForm { - /** @minLength 1 */ - name: string - notifications: number[] -} - -export interface ModelNotificationGroupResponseItem { - group: ModelNotificationGroup - notifications: number[] -} - -export interface ModelProfile { - created_at: string - id: number - login_ip: string - password: string - updated_at: string - username: string - role: number - agent_secret: string -} - -export interface ModelProfileForm { - new_password: string - new_username: string - original_password: string -} - -export interface ModelRule { - /** 覆盖范围 RuleCoverAll/IgnoreAll */ - cover: number - /** 流量统计周期 */ - cycle_interval?: number - /** 流量统计的开始时间 */ - cycle_start?: string - /** - * 流量统计周期单位,默认hour,可选(hour, day, week, month, year) - * @default "hour" - */ - cycle_unit?: "hour" | "day" | "week" | "month" | "year" - /** 持续时间 (秒) */ - duration?: number - /** 覆盖范围的排除 */ - ignore?: Record - /** 最大阈值 (百分比、字节 kb ÷ 1024) */ - max?: number - /** 最小阈值 (百分比、字节 kb ÷ 1024) */ - min?: number - /** - * 指标类型,cpu、memory、swap、disk、net_in_speed、net_out_speed - * net_all_speed、transfer_in、transfer_out、transfer_all、offline - * transfer_in_cycle、transfer_out_cycle、transfer_all_cycle - */ - type: string -} - -export interface ModelSensorTemperature { - name?: string - temperature?: number -} - -export interface ModelServer { - created_at: string - /** DDNS配置 */ - ddns_profiles?: number[] - /** 展示排序,越大越靠前 */ - display_index: number - /** 启用DDNS */ - enable_ddns: boolean - geoip: ModelGeoIP - /** 对游客隐藏 */ - hide_for_guest: boolean - host: ModelHost - id: number - last_active: string - name: string - /** 管理员可见备注 */ - note: string - /** 公开备注 */ - public_note: string - state: ModelHostState - updated_at: string - uuid: string -} - -export interface ModelServerForm { - /** DDNS配置 */ - ddns_profiles?: number[] - /** - * 展示排序,越大越靠前 - * @default 0 - */ - display_index: number - /** 启用DDNS */ - enable_ddns?: boolean - /** 对游客隐藏 */ - hide_for_guest?: boolean - name: string - /** 管理员可见备注 */ - note?: string - /** 公开备注 */ - public_note?: string -} - -export interface ModelServerGroup { - created_at: string - id: number - name: string - updated_at: string -} - -export interface ModelServerGroupForm { - /** @minLength 1 */ - name: string - servers: number[] -} - -export interface ModelServerGroupResponseItem { - group: ModelServerGroup - servers: number[] -} - -export interface ModelService { - cover: number - created_at: string - duration: number - enable_show_in_service: boolean - enable_trigger_task: boolean - /** 失败时执行的触发任务id */ - fail_trigger_tasks: number[] - id: number - latency_notify: boolean - max_latency: number - min_latency: number - name: string - /** 当前服务监控所属的通知组 ID */ - notification_group_id: number - notify: boolean - /** 恢复时执行的触发任务id */ - recover_trigger_tasks: number[] - skip_servers: Record - target: string - type: number - updated_at: string -} - -export interface ModelServiceForm { - cover: number - duration: number - enable_show_in_service?: boolean - enable_trigger_task?: boolean - fail_trigger_tasks: number[] - latency_notify?: boolean - /** @default 0 */ - max_latency: number - /** @default 0 */ - min_latency: number - /** @minLength 1 */ - name: string - notification_group_id: number - notify?: boolean - recover_trigger_tasks: number[] - skip_servers: Record - target: string - type: number -} - -export interface ModelServiceInfos { - avg_delay: number[] - created_at: number[] - monitor_id: number - monitor_name: string - server_id: number - server_name: string -} - -export interface ModelServiceResponse { - cycle_transfer_stats: Record - services: Record -} - -export interface ModelServiceResponseItem { - current_down: number - current_up: number - delay: number[] - down: number[] - service_name: string - total_down: number - total_up: number - up: number[] -} - -export interface ModelSettingForm { - cover: number - custom_code?: string - custom_code_dashboard?: string - dns_servers?: string - enable_ip_change_notification?: boolean - enable_plain_ip_in_notification?: boolean - ignored_ip_notification?: string - install_host?: string - /** IP变更提醒的通知组 */ - ip_change_notification_group_id: number - /** @minLength 2 */ - language: string - /** 真实IP */ - real_ip_header?: string - /** @minLength 1 */ - site_name: string - tls?: boolean - user_template?: string -} - -export interface ModelUserTemplateItem { - path: string - name: string - repository: string - author: string - version: string - is_admin: boolean - is_official: boolean -} - -export interface ModelSettingResponse { - admin_template: string - agent_secret_key: string - avg_ping_count: number - /** 覆盖范围(0:提醒未被 IgnoredIPNotification 包含的所有服务器; 1:仅提醒被 IgnoredIPNotification 包含的服务器;) */ - cover: number - custom_code: string - custom_code_dashboard: string - /** debug模式开关 */ - debug: boolean - dns_servers: string - /** IP变更提醒 */ - enable_ip_change_notification: boolean - /** 通知信息IP不打码 */ - enable_plain_ip_in_notification: boolean - frontend_templates: ModelFrontendTemplate[] - /** 特定服务器IP(多个服务器用逗号分隔) */ - ignored_ip_notification: string - /** [ServerID] -> bool(值为true代表当前ServerID在特定服务器列表内) */ - ignored_ip_notification_server_ids: Record - install_host: string - ip_change_notification_group_id: number - jwt_secret_key: string - /** 系统语言,默认 zh_CN */ - language: string - listen_host: string - listen_port: number - /** 时区,默认为 Asia/Shanghai */ - location: string - /** 真实IP */ - real_ip_header: string - site_name: string - tls: boolean - user_template: string - version: string -} - -export interface ModelStreamServer { - country_code: string - /** 展示排序,越大越靠前 */ - display_index: number - host: ModelHost - id: number - last_active: string - name: string - /** 公开备注,只第一个数据包有值 */ - public_note: string - state: ModelHostState -} - -export interface ModelStreamServerData { - now: number - servers: ModelStreamServer[] -} - -export interface ModelTerminalForm { - protocol: string - server_id: number -} - -export interface ModelUser { - created_at: string - id: number - password: string - updated_at: string - username: string - role: number -} - -export interface ModelUserForm { - password: string - username: string -} - -export interface Pagination { - limit: number - offset: number - total: number -} - -export interface ModelWAF { - count: number - ip: string - block_identifier: number - block_reason: number - block_timestamp: number -} - -export interface ModelWAFApiMock { - pagination: Pagination - value: ModelWAF[] -} - -export interface ModelOnlineUser { - connected_at: string - ip: string - user_id: number -} - -export interface ModelOnlineUserApi { - pagination: Pagination - value: ModelOnlineUser[] -} +export interface GithubComNezhahqNezhaModelCommonResponseAny { + data?: any + error?: string + success?: boolean +} + +export interface GithubComNezhahqNezhaModelCommonResponseArrayModelAlertRule { + data?: ModelAlertRule[] + error?: string + success?: boolean +} + +export interface GithubComNezhahqNezhaModelCommonResponseArrayModelCron { + data?: ModelCron[] + error?: string + success?: boolean +} + +export interface GithubComNezhahqNezhaModelCommonResponseArrayModelDDNSProfile { + data?: ModelDDNSProfile[] + error?: string + success?: boolean +} + +export interface GithubComNezhahqNezhaModelCommonResponseArrayModelNAT { + data?: ModelNAT[] + error?: string + success?: boolean +} + +export interface GithubComNezhahqNezhaModelCommonResponseArrayModelNotification { + data?: ModelNotification[] + error?: string + success?: boolean +} + +export interface GithubComNezhahqNezhaModelCommonResponseArrayModelNotificationGroupResponseItem { + data?: ModelNotificationGroupResponseItem[] + error?: string + success?: boolean +} + +export interface GithubComNezhahqNezhaModelCommonResponseArrayModelServer { + data?: ModelServer[] + error?: string + success?: boolean +} + +export interface GithubComNezhahqNezhaModelCommonResponseArrayModelServerGroupResponseItem { + data?: ModelServerGroupResponseItem[] + error?: string + success?: boolean +} + +export interface GithubComNezhahqNezhaModelCommonResponseArrayModelService { + data?: ModelService[] + error?: string + success?: boolean +} + +export interface GithubComNezhahqNezhaModelCommonResponseArrayModelServiceInfos { + data?: ModelServiceInfos[] + error?: string + success?: boolean +} + +export interface GithubComNezhahqNezhaModelCommonResponseArrayModelUser { + data?: ModelUser[] + error?: string + success?: boolean +} + +export interface GithubComNezhahqNezhaModelCommonResponseArrayString { + data?: string[] + error?: string + success?: boolean +} + +export interface GithubComNezhahqNezhaModelCommonResponseArrayUint64 { + data?: number[] + error?: string + success?: boolean +} + +export interface GithubComNezhahqNezhaModelCommonResponseGithubComNezhahqNezhaModelSettingResponseModelConfig { + data?: GithubComNezhahqNezhaModelSettingResponseModelConfig + error?: string + success?: boolean +} + +export interface GithubComNezhahqNezhaModelCommonResponseModelForceUpdateResponse { + data?: ModelForceUpdateResponse + error?: string + success?: boolean +} + +export interface GithubComNezhahqNezhaModelCommonResponseModelLoginResponse { + data?: ModelLoginResponse + error?: string + success?: boolean +} + +export interface GithubComNezhahqNezhaModelCommonResponseModelProfile { + data?: ModelProfile + error?: string + success?: boolean +} + +export interface GithubComNezhahqNezhaModelCommonResponseModelServiceResponse { + data?: ModelServiceResponse + error?: string + success?: boolean +} + +export interface GithubComNezhahqNezhaModelCommonResponseUint64 { + data?: number + error?: string + success?: boolean +} + +export interface GithubComNezhahqNezhaModelPaginatedResponseArrayModelOnlineUserModelOnlineUser { + data?: GithubComNezhahqNezhaModelValueArrayModelOnlineUser + error?: string + success?: boolean +} + +export interface GithubComNezhahqNezhaModelPaginatedResponseArrayModelWAFApiMockModelWAFApiMock { + data?: GithubComNezhahqNezhaModelValueArrayModelWAFApiMock + error?: string + success?: boolean +} + +export interface GithubComNezhahqNezhaModelSettingResponseModelConfig { + config?: ModelConfig + frontend_templates?: ModelFrontendTemplate[] + version?: string +} + +export interface GithubComNezhahqNezhaModelValueArrayModelOnlineUser { + pagination?: ModelPagination + value?: ModelOnlineUser[] +} + +export interface GithubComNezhahqNezhaModelValueArrayModelWAFApiMock { + pagination?: ModelPagination + value?: ModelWAFApiMock[] +} + +export interface ModelAlertRule { + created_at?: string + enable?: boolean + /** 失败时执行的触发任务id */ + fail_trigger_tasks?: number[] + id?: number + name?: string + /** 该报警规则所在的通知组 */ + notification_group_id?: number + /** 恢复时执行的触发任务id */ + recover_trigger_tasks?: number[] + rules?: ModelRule[] + /** 触发模式: 0-始终触发(默认) 1-单次触发 */ + trigger_mode?: number + updated_at?: string +} + +export interface ModelAlertRuleForm { + enable?: boolean + /** 失败时触发的任务id */ + fail_trigger_tasks?: number[] + /** @minLength 1 */ + name?: string + notification_group_id?: number + /** 恢复时触发的任务id */ + recover_trigger_tasks?: number[] + rules?: ModelRule[] + /** @default 0 */ + trigger_mode?: number +} + +export interface ModelConfig { + admin_template?: string + agent_secret_key?: string + avg_ping_count?: number + /** 覆盖范围(0:提醒未被 IgnoredIPNotification 包含的所有服务器; 1:仅提醒被 IgnoredIPNotification 包含的服务器;) */ + cover?: number + custom_code?: string + custom_code_dashboard?: string + /** debug模式开关 */ + debug?: boolean + dns_servers?: string + /** IP变更提醒 */ + enable_ip_change_notification?: boolean + /** 通知信息IP不打码 */ + enable_plain_ip_in_notification?: boolean + /** 特定服务器IP(多个服务器用逗号分隔) */ + ignored_ip_notification?: string + /** [ServerID] -> bool(值为true代表当前ServerID在特定服务器列表内) */ + ignored_ip_notification_server_ids?: Record + install_host?: string + ip_change_notification_group_id?: number + jwt_secret_key?: string + /** 系统语言,默认 zh_CN */ + language?: string + listen_host?: string + listen_port?: number + /** 时区,默认为 Asia/Shanghai */ + location?: string + /** oauth2 配置 */ + oauth2?: Record + /** oauth2 供应商列表,无需配置,自动生成 */ + oauth2_providers?: string[] + /** 真实IP */ + real_ip_header?: string + site_name?: string + tls?: boolean + user_template?: string +} + +export interface ModelCreateFMResponse { + session_id?: string +} + +export interface ModelCreateTerminalResponse { + server_id?: number + server_name?: string + session_id?: string +} + +export interface ModelCron { + command?: string + /** 计划任务覆盖范围 (0:仅覆盖特定服务器 1:仅忽略特定服务器 2:由触发该计划任务的服务器执行) */ + cover?: number + created_at?: string + cron_job_id?: number + id?: number + /** 最后一次执行时间 */ + last_executed_at?: string + /** 最后一次执行结果 */ + last_result?: boolean + name?: string + /** 指定通知方式的分组 */ + notification_group_id?: number + /** 推送成功的通知 */ + push_successful?: boolean + /** 分钟 小时 天 月 星期 */ + scheduler?: string + servers?: number[] + /** 0:计划任务 1:触发任务 */ + task_type?: number + updated_at?: string +} + +export interface ModelCronForm { + command?: string + /** @default 0 */ + cover?: number + /** @minLength 1 */ + name?: string + notification_group_id?: number + push_successful?: boolean + scheduler?: string + servers?: number[] + /** + * 0:计划任务 1:触发任务 + * @default 0 + */ + task_type?: number +} + +export interface ModelCycleTransferStats { + from?: string + max?: number + min?: number + name?: string + next_update?: Record + server_name?: Record + to?: string + transfer?: Record +} + +export interface ModelDDNSForm { + access_id?: string + access_secret?: string + domains?: string[] + enable_ipv4?: boolean + enable_ipv6?: boolean + /** @default 3 */ + max_retries?: number + /** @minLength 1 */ + name?: string + provider?: string + webhook_headers?: string + /** @default 1 */ + webhook_method?: number + webhook_request_body?: string + /** @default 1 */ + webhook_request_type?: number + webhook_url?: string +} + +export interface ModelDDNSProfile { + access_id?: string + access_secret?: string + created_at?: string + domains?: string[] + enable_ipv4?: boolean + enable_ipv6?: boolean + id?: number + max_retries?: number + name?: string + provider?: string + updated_at?: string + webhook_headers?: string + webhook_method?: number + webhook_request_body?: string + webhook_request_type?: number + webhook_url?: string +} + +export interface ModelForceUpdateResponse { + failure?: number[] + offline?: number[] + success?: number[] +} + +export interface ModelFrontendTemplate { + author?: string + is_admin?: boolean + is_official?: boolean + name?: string + path?: string + repository?: string + version?: string +} + +export interface ModelGeoIP { + country_code?: string + ip?: ModelIP +} + +export interface ModelHost { + arch?: string + boot_time?: number + cpu?: string[] + disk_total?: number + gpu?: string[] + mem_total?: number + platform?: string + platform_version?: string + swap_total?: number + version?: string + virtualization?: string +} + +export interface ModelHostState { + cpu?: number + disk_used?: number + gpu?: number[] + load_1?: number + load_15?: number + load_5?: number + mem_used?: number + net_in_speed?: number + net_in_transfer?: number + net_out_speed?: number + net_out_transfer?: number + process_count?: number + swap_used?: number + tcp_conn_count?: number + temperatures?: ModelSensorTemperature[] + udp_conn_count?: number + uptime?: number +} + +export interface ModelIP { + ipv4_addr?: string + ipv6_addr?: string +} + +export interface ModelLoginRequest { + password?: string + username?: string +} + +export interface ModelLoginResponse { + expire?: string + token?: string +} + +export interface ModelNAT { + created_at?: string + domain?: string + host?: string + id?: number + name?: string + server_id?: number + updated_at?: string +} + +export interface ModelNATForm { + domain?: string + host?: string + /** @minLength 1 */ + name?: string + server_id?: number +} + +export interface ModelNotification { + created_at?: string + id?: number + name?: string + request_body?: string + request_header?: string + request_method?: number + request_type?: number + updated_at?: string + url?: string + verify_tls?: boolean +} + +export interface ModelNotificationForm { + /** @minLength 1 */ + name?: string + request_body?: string + request_header?: string + request_method?: number + request_type?: number + skip_check?: boolean + url?: string + verify_tls?: boolean +} + +export interface ModelNotificationGroup { + created_at?: string + id?: number + name?: string + updated_at?: string +} + +export interface ModelNotificationGroupForm { + /** @minLength 1 */ + name?: string + notifications?: number[] +} + +export interface ModelNotificationGroupResponseItem { + group?: ModelNotificationGroup + notifications?: number[] +} + +export interface ModelOauth2Callback { + code?: string + state?: string +} + +export interface ModelOauth2Config { + client_id?: string + client_secret?: string + endpoint?: ModelOauth2Endpoint + scopes?: string[] + user_id_path?: string + user_info_url?: string +} + +export interface ModelOauth2Endpoint { + auth_url?: string + token_url?: string +} + +export interface ModelOauth2LoginResponse { + redirect?: string +} + +export interface ModelOnlineUser { + connected_at?: string + ip?: string + user_id?: number +} + +export interface ModelPagination { + limit?: number + offset?: number + total?: number +} + +export interface ModelProfile { + agent_secret?: string + created_at?: string + id?: number + login_ip?: string + oauth2_bind?: Record + password?: string + role?: number + updated_at?: string + username?: string +} + +export interface ModelProfileForm { + new_password?: string + new_username?: string + original_password?: string +} + +export interface ModelRule { + /** 覆盖范围 RuleCoverAll/IgnoreAll */ + cover?: number + /** 流量统计周期 */ + cycle_interval?: number + /** 流量统计的开始时间 */ + cycle_start?: string + /** + * 流量统计周期单位,默认hour,可选(hour, day, week, month, year) + * @default "hour" + */ + cycle_unit?: "hour" | "day" | "week" | "month" | "year" + /** 持续时间 (秒) */ + duration?: number + /** 覆盖范围的排除 */ + ignore?: Record + /** 最大阈值 (百分比、字节 kb ÷ 1024) */ + max?: number + /** 最小阈值 (百分比、字节 kb ÷ 1024) */ + min?: number + /** + * 指标类型,cpu、memory、swap、disk、net_in_speed、net_out_speed + * net_all_speed、transfer_in、transfer_out、transfer_all、offline + * transfer_in_cycle、transfer_out_cycle、transfer_all_cycle + */ + type?: string +} + +export interface ModelSensorTemperature { + name?: string + temperature?: number +} + +export interface ModelServer { + created_at?: string + /** DDNS配置 */ + ddns_profiles?: number[] + /** 展示排序,越大越靠前 */ + display_index?: number + /** 启用DDNS */ + enable_ddns?: boolean + geoip?: ModelGeoIP + /** 对游客隐藏 */ + hide_for_guest?: boolean + host?: ModelHost + id?: number + last_active?: string + name?: string + /** 管理员可见备注 */ + note?: string + /** 公开备注 */ + public_note?: string + state?: ModelHostState + updated_at?: string + uuid?: string +} + +export interface ModelServerForm { + /** DDNS配置 */ + ddns_profiles?: number[] + /** + * 展示排序,越大越靠前 + * @default 0 + */ + display_index?: number + /** 启用DDNS */ + enable_ddns?: boolean + /** 对游客隐藏 */ + hide_for_guest?: boolean + name?: string + /** 管理员可见备注 */ + note?: string + /** 公开备注 */ + public_note?: string +} + +export interface ModelServerGroup { + created_at?: string + id?: number + name?: string + updated_at?: string +} + +export interface ModelServerGroupForm { + /** @minLength 1 */ + name?: string + servers?: number[] +} + +export interface ModelServerGroupResponseItem { + group?: ModelServerGroup + servers?: number[] +} + +export interface ModelService { + cover?: number + created_at?: string + duration?: number + enable_show_in_service?: boolean + enable_trigger_task?: boolean + /** 失败时执行的触发任务id */ + fail_trigger_tasks?: number[] + id?: number + latency_notify?: boolean + max_latency?: number + min_latency?: number + name?: string + /** 当前服务监控所属的通知组 ID */ + notification_group_id?: number + notify?: boolean + /** 恢复时执行的触发任务id */ + recover_trigger_tasks?: number[] + skip_servers?: Record + target?: string + type?: number + updated_at?: string +} + +export interface ModelServiceForm { + cover?: number + duration?: number + enable_show_in_service?: boolean + enable_trigger_task?: boolean + fail_trigger_tasks?: number[] + latency_notify?: boolean + /** @default 0 */ + max_latency?: number + /** @default 0 */ + min_latency?: number + /** @minLength 1 */ + name?: string + notification_group_id?: number + notify?: boolean + recover_trigger_tasks?: number[] + skip_servers?: Record + target?: string + type?: number +} + +export interface ModelServiceInfos { + avg_delay?: number[] + created_at?: number[] + monitor_id?: number + monitor_name?: string + server_id?: number + server_name?: string +} + +export interface ModelServiceResponse { + cycle_transfer_stats?: Record + services?: Record +} + +export interface ModelServiceResponseItem { + current_down?: number + current_up?: number + delay?: number[] + down?: number[] + service_name?: string + total_down?: number + total_up?: number + up?: number[] +} + +export interface ModelSettingForm { + cover?: number + custom_code?: string + custom_code_dashboard?: string + dns_servers?: string + enable_ip_change_notification?: boolean + enable_plain_ip_in_notification?: boolean + ignored_ip_notification?: string + install_host?: string + /** IP变更提醒的通知组 */ + ip_change_notification_group_id?: number + /** @minLength 2 */ + language?: string + /** 真实IP */ + real_ip_header?: string + /** @minLength 1 */ + site_name?: string + tls?: boolean + user_template?: string +} + +export interface ModelStreamServer { + country_code?: string + /** 展示排序,越大越靠前 */ + display_index?: number + host?: ModelHost + id?: number + last_active?: string + name?: string + /** 公开备注,只第一个数据包有值 */ + public_note?: string + state?: ModelHostState +} + +export interface ModelStreamServerData { + now?: number + online?: number + servers?: ModelStreamServer[] +} + +export interface ModelTerminalForm { + protocol?: string + server_id?: number +} + +export interface ModelUser { + agent_secret?: string + created_at?: string + id?: number + password?: string + role?: number + updated_at?: string + username?: string +} + +export interface ModelUserForm { + password?: string + role?: number + username?: string +} + +export interface ModelWAFApiMock { + block_identifier?: number + block_reason?: number + block_timestamp?: number + count?: number + ip?: string +} diff --git a/src/types/authContext.ts b/src/types/authContext.ts index 1fe257a..84d7049 100644 --- a/src/types/authContext.ts +++ b/src/types/authContext.ts @@ -3,5 +3,6 @@ import { ModelProfile } from "@/types" export interface AuthContextProps { profile: ModelProfile | undefined login: (username: string, password: string) => void + loginOauth2: (provider: string, state: string, code: string) => void logout: () => void }