diff --git a/ui/src/api/Admin.ts b/ui/src/api/Admin.ts index 9a09b25..4a3edfb 100644 --- a/ui/src/api/Admin.ts +++ b/ui/src/api/Admin.ts @@ -271,7 +271,7 @@ export const getGetSetting = (params: RequestParams = {}) => }); /** - * @description 更新系统设置 + * @description 更新为增量更新,只传需要更新的字段 * * @tags Admin * @name PutUpdateSetting diff --git a/ui/src/api/OpenAiv1.ts b/ui/src/api/OpenAiv1.ts index f3409af..8b9335b 100644 --- a/ui/src/api/OpenAiv1.ts +++ b/ui/src/api/OpenAiv1.ts @@ -13,6 +13,9 @@ import request, { ContentType, RequestParams } from "./httpClient"; import { DomainAcceptCompletionReq, + DomainCreateSecurityScanningReq, + DomainListSecurityScanningBriefResp, + DomainListSecurityScanningReq, DomainModelListResp, DomainReportReq, WebResp, @@ -146,3 +149,56 @@ export const postReport = ( format: "json", ...params, }); + +/** + * @description 分页逻辑只支持用 next_token + * + * @tags OpenAIV1 + * @name GetListSecurityScanning + * @summary 扫描任务列表 + * @request GET:/v1/security/scanning + * @response `200` `(WebResp & { + data?: DomainListSecurityScanningBriefResp, + +})` OK + */ + +export const getListSecurityScanning = ( + param: DomainListSecurityScanningReq, + params: RequestParams = {}, +) => + request< + WebResp & { + data?: DomainListSecurityScanningBriefResp; + } + >({ + path: `/v1/security/scanning`, + method: "GET", + body: param, + type: ContentType.Json, + format: "json", + ...params, + }); + +/** + * @description 创建扫描任务 + * + * @tags OpenAIV1 + * @name PostCreateSecurityScanning + * @summary 创建扫描任务 + * @request POST:/v1/security/scanning + * @response `200` `WebResp` OK + */ + +export const postCreateSecurityScanning = ( + param: DomainCreateSecurityScanningReq, + params: RequestParams = {}, +) => + request({ + path: `/v1/security/scanning`, + method: "POST", + body: param, + type: ContentType.Json, + format: "json", + ...params, + }); diff --git a/ui/src/api/SecurityScanning.ts b/ui/src/api/SecurityScanning.ts new file mode 100644 index 0000000..e7f8d50 --- /dev/null +++ b/ui/src/api/SecurityScanning.ts @@ -0,0 +1,82 @@ +/* eslint-disable */ +/* tslint:disable */ +// @ts-nocheck +/* + * --------------------------------------------------------------- + * ## THIS FILE WAS GENERATED VIA SWAGGER-TYPESCRIPT-API ## + * ## ## + * ## AUTHOR: acacode ## + * ## SOURCE: https://github.com/acacode/swagger-typescript-api ## + * --------------------------------------------------------------- + */ + +import request, { ContentType, RequestParams } from "./httpClient"; +import { + DomainListSecurityScanningResp, + DomainSecurityScanningRiskDetail, + GetSecurityScanningDetailParams, + GetSecurityScanningListParams, + WebResp, +} from "./types"; + +/** + * @description 获取扫描结果 + * + * @tags Security Scanning + * @name GetSecurityScanningList + * @summary 获取扫描结果 + * @request GET:/api/v1/security/scanning + * @response `200` `(WebResp & { + data?: DomainListSecurityScanningResp, + +})` OK + * @response `401` `string` Unauthorized + */ + +export const getSecurityScanningList = ( + query: GetSecurityScanningListParams, + params: RequestParams = {}, +) => + request< + WebResp & { + data?: DomainListSecurityScanningResp; + } + >({ + path: `/api/v1/security/scanning`, + method: "GET", + query: query, + type: ContentType.Json, + format: "json", + ...params, + }); + +/** + * @description 获取扫描风险详情 + * + * @tags Security Scanning + * @name GetSecurityScanningDetail + * @summary 获取扫描风险详情 + * @request GET:/api/v1/security/scanning/detail + * @response `200` `(WebResp & { + data?: (DomainSecurityScanningRiskDetail)[], + +})` OK + * @response `401` `string` Unauthorized + */ + +export const getSecurityScanningDetail = ( + query: GetSecurityScanningDetailParams, + params: RequestParams = {}, +) => + request< + WebResp & { + data?: DomainSecurityScanningRiskDetail[]; + } + >({ + path: `/api/v1/security/scanning/detail`, + method: "GET", + query: query, + type: ContentType.Json, + format: "json", + ...params, + }); diff --git a/ui/src/api/UserSecurityScanning.ts b/ui/src/api/UserSecurityScanning.ts new file mode 100644 index 0000000..ed1e5ee --- /dev/null +++ b/ui/src/api/UserSecurityScanning.ts @@ -0,0 +1,82 @@ +/* eslint-disable */ +/* tslint:disable */ +// @ts-nocheck +/* + * --------------------------------------------------------------- + * ## THIS FILE WAS GENERATED VIA SWAGGER-TYPESCRIPT-API ## + * ## ## + * ## AUTHOR: acacode ## + * ## SOURCE: https://github.com/acacode/swagger-typescript-api ## + * --------------------------------------------------------------- + */ + +import request, { ContentType, RequestParams } from "./httpClient"; +import { + DomainListSecurityScanningResp, + DomainSecurityScanningRiskDetail, + GetUserSecurityScanningDetailParams, + GetUserSecurityScanningListParams, + WebResp, +} from "./types"; + +/** + * @description 获取用户扫描结果 + * + * @tags User Security Scanning + * @name GetUserSecurityScanningList + * @summary 获取用户扫描结果 + * @request GET:/api/v1/user/security/scanning + * @response `200` `(WebResp & { + data?: DomainListSecurityScanningResp, + +})` OK + * @response `401` `string` Unauthorized + */ + +export const getUserSecurityScanningList = ( + query: GetUserSecurityScanningListParams, + params: RequestParams = {}, +) => + request< + WebResp & { + data?: DomainListSecurityScanningResp; + } + >({ + path: `/api/v1/user/security/scanning`, + method: "GET", + query: query, + type: ContentType.Json, + format: "json", + ...params, + }); + +/** + * @description 获取用户扫描风险详情 + * + * @tags User Security Scanning + * @name GetUserSecurityScanningDetail + * @summary 获取用户扫描风险详情 + * @request GET:/api/v1/user/security/scanning/detail + * @response `200` `(WebResp & { + data?: (DomainSecurityScanningRiskDetail)[], + +})` OK + * @response `401` `string` Unauthorized + */ + +export const getUserSecurityScanningDetail = ( + query: GetUserSecurityScanningDetailParams, + params: RequestParams = {}, +) => + request< + WebResp & { + data?: DomainSecurityScanningRiskDetail[]; + } + >({ + path: `/api/v1/user/security/scanning/detail`, + method: "GET", + query: query, + type: ContentType.Json, + format: "json", + ...params, + }); diff --git a/ui/src/api/index.ts b/ui/src/api/index.ts index c9c02ae..c7c24e0 100644 --- a/ui/src/api/index.ts +++ b/ui/src/api/index.ts @@ -4,10 +4,12 @@ export * from './Cli' export * from './Dashboard' export * from './Model' export * from './OpenAiv1' +export * from './SecurityScanning' export * from './User' export * from './UserDashboard' export * from './UserManage' export * from './UserRecord' +export * from './UserSecurityScanning' export * from './WorkspaceFile' export * from './types' diff --git a/ui/src/api/types.ts b/ui/src/api/types.ts index 189846a..bd5b1ee 100644 --- a/ui/src/api/types.ts +++ b/ui/src/api/types.ts @@ -40,6 +40,47 @@ export enum ConstsUserPlatform { UserPlatformCustom = "custom", } +export enum ConstsSecurityScanningStatus { + SecurityScanningStatusPending = "pending", + SecurityScanningStatusRunning = "running", + SecurityScanningStatusSuccess = "success", + SecurityScanningStatusFailed = "failed", +} + +export enum ConstsSecurityScanningRiskLevel { + SecurityScanningRiskLevelSevere = "severe", + SecurityScanningRiskLevelCritical = "critical", + SecurityScanningRiskLevelSuggest = "suggest", +} + +export enum ConstsSecurityScanningLanguage { + SecurityScanningLanguageCpp = "C/C++", + SecurityScanningLanguageJava = "Java", + SecurityScanningLanguagePython = "Python", + SecurityScanningLanguageJavaScript = "JavaScript", + SecurityScanningLanguageGo = "Go", + SecurityScanningLanguagePHP = "PHP", + SecurityScanningLanguageCS = "C#", + SecurityScanningLanguageSwift = "Swift", + SecurityScanningLanguageRuby = "Ruby", + SecurityScanningLanguageRust = "Rust", + SecurityScanningLanguageHTML = "HTML", + SecurityScanningLanguageObjectiveC = "Objective-C/C++", + SecurityScanningLanguageOCaml = "OCaml", + SecurityScanningLanguageKotlin = "Kotlin", + SecurityScanningLanguageScala = "Scala", + SecurityScanningLanguageSolidity = "Solidity", + SecurityScanningLanguageCOBOL = "COBOL", + SecurityScanningLanguageShell = "Shell", + SecurityScanningLanguageSQL = "SQL", + SecurityScanningLanguageFortran = "Fortran", + SecurityScanningLanguageDart = "Dart", + SecurityScanningLanguageGroovy = "Groovy", + SecurityScanningLanguageLua = "Lua", + SecurityScanningLanguageSecrets = "Secrets", + SecurityScanningLanguageIaC = "IaC", +} + export enum ConstsReportAction { ReportActionAccept = "accept", ReportActionSuggest = "suggest", @@ -313,6 +354,13 @@ export interface DomainCreateModelReq { show_name?: string; } +export interface DomainCreateSecurityScanningReq { + /** 扫描语言 */ + language?: ConstsSecurityScanningLanguage; + /** 项目目录 */ + workspace?: string; +} + export interface DomainCreateWorkspaceFileReq { /** 文件内容 */ content?: string; @@ -504,6 +552,41 @@ export interface DomainListLoginHistoryResp { total_count?: number; } +export interface DomainListSecurityScanningBriefResp { + has_next_page?: boolean; + items?: DomainSecurityScanningBrief[]; + next_token?: string; + total_count?: number; +} + +export interface DomainListSecurityScanningReq { + /** 作者 */ + author?: string; + /** 下一页标识 */ + next_token?: string; + /** + * 分页 + * @min 1 + * @default 1 + */ + page?: number; + /** 项目名称 */ + project_name?: string; + /** + * 每页多少条记录 + * @min 1 + * @default 10 + */ + size?: number; +} + +export interface DomainListSecurityScanningResp { + has_next_page?: boolean; + items?: DomainSecurityScanningResult[]; + next_token?: string; + total_count?: number; +} + export interface DomainListUserResp { has_next_page?: boolean; next_token?: string; @@ -695,7 +778,57 @@ export interface DomainReportReq { user_input?: string; } +export interface DomainSecurityScanningBrief { + /** 创建时间 */ + created_at?: number; + /** 报告url */ + report_url?: string; + /** 扫描状态 */ + status?: ConstsSecurityScanningStatus; + /** 项目目录 */ + workspace?: string; +} + +export interface DomainSecurityScanningResult { + /** 扫描开始时间 */ + created_at?: number; + /** 扫描任务id */ + id?: string; + /** 扫描任务 */ + name?: string; + /** 项目名称 */ + project_name?: string; + /** 风险结果 */ + risk?: DomainSecurityScanningRiskResult; + /** 扫描状态 */ + status?: ConstsSecurityScanningStatus; + /** 用户 */ + user?: DomainUser; +} + +export interface DomainSecurityScanningRiskDetail { + /** 风险描述 */ + desc?: string; + /** 风险文件名 */ + filename?: string; + /** 风险id */ + id?: string; + /** 风险等级 */ + level?: ConstsSecurityScanningRiskLevel; +} + +export interface DomainSecurityScanningRiskResult { + /** 高危数 */ + critical_count?: number; + /** 严重数 */ + severe_count?: number; + /** 建议数 */ + suggest_count?: number; +} + export interface DomainSetting { + /** base url 配置,为了支持前置代理 */ + base_url?: string; /** 创建时间 */ created_at?: number; /** 自定义OAuth接入 */ @@ -829,6 +962,8 @@ export interface DomainUpdateModelReq { } export interface DomainUpdateSettingReq { + /** base url 配置,为了支持前置代理 */ + base_url?: string; /** 自定义OAuth配置 */ custom_oauth?: DomainCustomOAuthReq; /** 钉钉OAuth配置 */ @@ -1230,6 +1365,32 @@ export interface GetGetTokenUsageParams { model_type: "llm" | "coder" | "embedding" | "audio" | "reranker"; } +export interface GetSecurityScanningListParams { + /** 作者 */ + author?: string; + /** 下一页标识 */ + next_token?: string; + /** + * 分页 + * @min 1 + * @default 1 + */ + page?: number; + /** 项目名称 */ + project_name?: string; + /** + * 每页多少条记录 + * @min 1 + * @default 10 + */ + size?: number; +} + +export interface GetSecurityScanningDetailParams { + /** 扫描任务id */ + id: string; +} + export interface GetUserChatInfoParams { /** 对话记录ID */ id: string; @@ -1384,6 +1545,32 @@ export interface GetUserOauthSignupOrInParams { source: "plugin" | "browser"; } +export interface GetUserSecurityScanningListParams { + /** 作者 */ + author?: string; + /** 下一页标识 */ + next_token?: string; + /** + * 分页 + * @min 1 + * @default 1 + */ + page?: number; + /** 项目名称 */ + project_name?: string; + /** + * 每页多少条记录 + * @min 1 + * @default 10 + */ + size?: number; +} + +export interface GetUserSecurityScanningDetailParams { + /** 扫描任务id */ + id: string; +} + export interface GetListWorkspaceFilesParams { /** 编程语言筛选 */ language?: string; diff --git a/ui/src/components/sidebar/index.tsx b/ui/src/components/sidebar/index.tsx index 9d75780..08284fd 100644 --- a/ui/src/components/sidebar/index.tsx +++ b/ui/src/components/sidebar/index.tsx @@ -58,10 +58,10 @@ const ADMIN_MENUS = [ disabled: false, }, { - label: '管理员', - value: '/admin', - pathname: 'admin', - icon: 'icon-guanliyuan1', + label: '通用设置', + value: '/general-setting', + pathname: 'general-setting', + icon: 'icon-setting', show: true, disabled: false, }, diff --git a/ui/src/pages/admin/index.tsx b/ui/src/pages/admin/index.tsx deleted file mode 100644 index 2a15d9e..0000000 --- a/ui/src/pages/admin/index.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import React from 'react'; -import LoginHistory from './loginHistory'; -import AdminTable from './adminTable'; -import { Grid2 as Grid, Stack } from '@mui/material'; - -const Admin = () => { - return ( - - - - - - - - - ); -}; - -export default Admin; diff --git a/ui/src/pages/auth/index.tsx b/ui/src/pages/auth/index.tsx index 63088b2..ccc68a3 100644 --- a/ui/src/pages/auth/index.tsx +++ b/ui/src/pages/auth/index.tsx @@ -15,7 +15,7 @@ import { Divider, Stack, } from '@mui/material'; -import { Icon, message } from '@c-x/ui'; +import { CusTabs, Icon, message } from '@c-x/ui'; // @ts-ignore import { AestheticFluidBg } from '@/assets/jsm/AestheticFluidBg.module.js'; @@ -43,7 +43,7 @@ const StyledPaper = styled(Paper)(({ theme }) => ({ position: 'relative', zIndex: 9, padding: theme.spacing(4), - background: 'rgba(255, 255, 255, 0.85)', + background: 'rgba(240, 240, 240, 0.85)', backdropFilter: 'blur(10px)', width: 458, borderRadius: theme.spacing(2), @@ -133,6 +133,12 @@ const AuthPage = () => { // 处理登录表单提交 const onSubmit = useCallback( async (data: LoginFormData) => { + // 检查是否使用 admin 账户登录 + if (data.username === 'admin') { + message.error('请使用研发成员的账户登录,本页面不支持管理员账户访问'); + return; + } + setLoading(true); setError(null); @@ -344,6 +350,40 @@ const AuthPage = () => { Monkey Code + + {!loginSetting.disable_password_login && renderLoginForm()} {oauthEnable && oauthLogin()} diff --git a/ui/src/pages/admin/loginHistory.tsx b/ui/src/pages/generalSetting/components/adminLoginHistory.tsx similarity index 80% rename from ui/src/pages/admin/loginHistory.tsx rename to ui/src/pages/generalSetting/components/adminLoginHistory.tsx index 2df5fbc..0bec985 100644 --- a/ui/src/pages/admin/loginHistory.tsx +++ b/ui/src/pages/generalSetting/components/adminLoginHistory.tsx @@ -12,7 +12,7 @@ type LoginHistory = NonNullable< DomainListAdminLoginHistoryResp['login_histories'] >[number]; -const LoginHistory = () => { +const AdminLoginHistory = () => { const { data, loading } = useRequest(() => getAdminLoginHistory({})); const columns: ColumnsType = [ { @@ -55,9 +55,23 @@ const LoginHistory = () => { direction='row' justifyContent='space-between' alignItems='center' - sx={{ mb: 2 }} + sx={{ + mb: 2, + height: 32, + fontWeight: 'bold', + }} > - 管理员登录记录 + 管理员登录记录 { ); }; -export default LoginHistory; +export default AdminLoginHistory; diff --git a/ui/src/pages/admin/adminTable.tsx b/ui/src/pages/generalSetting/components/adminUser.tsx similarity index 87% rename from ui/src/pages/admin/adminTable.tsx rename to ui/src/pages/generalSetting/components/adminUser.tsx index 0e8c041..207386a 100644 --- a/ui/src/pages/admin/adminTable.tsx +++ b/ui/src/pages/generalSetting/components/adminUser.tsx @@ -151,7 +151,7 @@ const AddAdminModal = ({ ); }; -const AdminTable = () => { +const AdminUser = () => { const [open, setOpen] = useState(false); const { data, loading, refresh } = useRequest(() => getListAdminUser({})); const onDeleteAdmin = (data: DomainAdminUser) => { @@ -187,19 +187,27 @@ const AdminTable = () => { }, }, { - title: '最近活跃时间', + title: '加入时间', + dataIndex: 'created_at', + width: 140, + render: (text) => { + return dayjs.unix(text).fromNow(); + }, + }, + { + title: '最近活跃', dataIndex: 'last_active_at', + width: 140, render: (text, record) => { - return - {record.created_at ? dayjs.unix(record.created_at).fromNow() + '加入' : '加入时间未知'} - {record.last_active_at ? dayjs.unix(record.last_active_at).fromNow() + '活跃' : '活跃时间未知'} - + return record.last_active_at === 0 + ? '从未使用' + : dayjs.unix(text).fromNow(); }, }, { title: '', dataIndex: 'opt', - width: 200, + width: 100, render: (_, record) => { return ( } + + + + + 用于解决 VSCode 插件无法连接 MonkeyCode 服务的问题 + + + + + +} + +export default CardServiceSettings; \ No newline at end of file diff --git a/ui/src/pages/generalSetting/index.tsx b/ui/src/pages/generalSetting/index.tsx new file mode 100644 index 0000000..0459e7f --- /dev/null +++ b/ui/src/pages/generalSetting/index.tsx @@ -0,0 +1,18 @@ +import CardServiceSettings from './components/cardServiceSettings'; +import { Grid2 as Grid } from '@mui/material'; +import CardAdminUser from './components/cardAdminUser'; + +const GeneralSetting = () => { + return ( + + + + + + + + + ); +}; + +export default GeneralSetting; diff --git a/ui/src/pages/login/index.tsx b/ui/src/pages/login/index.tsx index b6f2801..b89f98f 100644 --- a/ui/src/pages/login/index.tsx +++ b/ui/src/pages/login/index.tsx @@ -42,7 +42,7 @@ const StyledPaper = styled(Paper)(({ theme }) => ({ position: 'relative', zIndex: 9, padding: theme.spacing(4), - background: 'rgba(255, 255, 255, 0.85)', + background: 'rgba(240, 240, 240, 0.85)', backdropFilter: 'blur(10px)', width: 458, borderRadius: theme.spacing(2), @@ -209,8 +209,8 @@ const LoginPage = () => { { diff --git a/ui/src/pages/memberManage/memberManage.tsx b/ui/src/pages/memberManage/memberManage.tsx index bd7ac5a..a32a7b7 100644 --- a/ui/src/pages/memberManage/memberManage.tsx +++ b/ui/src/pages/memberManage/memberManage.tsx @@ -266,7 +266,7 @@ const MemberManage = () => { { title: '加入时间', dataIndex: 'created_at', - width: 120, + width: 140, render: (text) => { return dayjs.unix(text).fromNow(); }, @@ -274,7 +274,7 @@ const MemberManage = () => { { title: '最近活跃', dataIndex: 'last_active_at', - width: 120, + width: 140, render: (text, record) => { return record.last_active_at === 0 ? '从未使用' @@ -284,7 +284,7 @@ const MemberManage = () => { { title: '', dataIndex: 'action', - width: 100, + width: 80, render: (_, record) => { return ( import('@/pages/chat'))); const Completion = LazyLoadable(lazy(() => import('@/pages/completion'))); const Model = LazyLoadable(lazy(() => import('@/pages/model'))); const MemberManage = LazyLoadable(lazy(() => import('@/pages/memberManage'))); -const Admin = LazyLoadable(lazy(() => import('@/pages/admin'))); +const GeneralSetting = LazyLoadable(lazy(() => import('@/pages/generalSetting'))); const Invite = LazyLoadable(lazy(() => import('@/pages/invite'))); const Auth = LazyLoadable(lazy(() => import('@/pages/auth'))); const Login = LazyLoadable(lazy(() => import('@/pages/login'))); @@ -83,8 +83,8 @@ const routerConfig = [ element: , }, { - path: 'admin', - element: , + path: 'general-setting', + element: , }, ], },