Compare commits

..

6 Commits

Author SHA1 Message Date
lcx e484dbd55b fix: incorrect Swagger display in service details 2026-04-27 11:37:46 +08:00
Dot.L 9192b3995f Merge pull request #409 from APIParkLab/feature/liujian-1.9
fix bug
2025-10-26 22:28:24 +08:00
Liujian 7b54e12950 fix bug 2025-10-24 17:18:29 +08:00
Dot.L 8857fc4f33 Merge pull request #407 from APIParkLab/fix/cx
fix: issue#395
2025-10-21 18:38:58 +08:00
Dot.L 6bed4f7672 Merge pull request #406 from APIParkLab/feature/liujian-1.9
MCP transports supports Streamable HTTP
2025-10-21 18:00:12 +08:00
Liujian ea32fb1cd6 MCP transports supports Streamable HTTP 2025-10-21 17:52:50 +08:00
574 changed files with 4033 additions and 5545 deletions
+5 -1
View File
@@ -113,9 +113,13 @@ func (i *imlAPIController) Edit(ctx *gin.Context, serviceId string, apiId string
if input.AiModel.Type != "local" {
provider = input.AiModel.Provider
}
modelName := input.AiModel.Name
if modelName == "" {
modelName = input.AiModel.Id
}
proxy.Plugins["ai_formatter"] = api.PluginSetting{
Config: plugin_model.ConfigType{
"model": input.AiModel.Name,
"model": modelName,
"provider": provider,
"config": input.AiModel.Config,
},
+71 -31
View File
@@ -21,13 +21,14 @@ import (
var _ IMcpController = (*imlMcpController)(nil)
type imlMcpController struct {
settingModule system.ISettingModule `autowired:""`
authorizationModule application_authorization.IAuthorizationModule `autowired:""`
appModule service.IAppModule `autowired:""`
mcpModule mcp.IMcpModule `autowired:""`
sessionKeys sync.Map
server map[string]http.Handler
openServer http.Handler
settingModule system.ISettingModule `autowired:""`
authorizationModule application_authorization.IAuthorizationModule `autowired:""`
appModule service.IAppModule `autowired:""`
mcpModule mcp.IMcpModule `autowired:""`
sessionKeys sync.Map
sseServers map[string]http.Handler
openSseServer http.Handler
openStreamableServer http.Handler
}
func (i *imlMcpController) AppMCPHandle(ctx *gin.Context) {
@@ -42,12 +43,12 @@ func (i *imlMcpController) AppMCPHandle(ctx *gin.Context) {
paths := strings.Split(req.URL.Path, "/")
req.URL.Path = fmt.Sprintf("/api/v1/%s/%s", mcp_server.GlobalBasePath, paths[len(paths)-1])
locale := utils.I18n(ctx)
if v, ok := i.server[locale]; ok {
if v, ok := i.sseServers[locale]; ok {
v.ServeHTTP(ctx.Writer, req)
return
}
i.server[languageEnUs].ServeHTTP(ctx.Writer, req)
i.sseServers[languageEnUs].ServeHTTP(ctx.Writer, req)
}
func (i *imlMcpController) AppHandleSSE(ctx *gin.Context) {
@@ -68,7 +69,7 @@ func (i *imlMcpController) AppHandleSSE(ctx *gin.Context) {
}
ctx.Request.URL.Path = fmt.Sprintf("/openapi/v1/%s/sse", mcp_server.GlobalBasePath)
i.handleSSE(ctx, i.openServer, SessionInfo{
i.handleSSE(ctx, i.openSseServer, SessionInfo{
Apikey: apikey,
App: appId,
})
@@ -81,8 +82,29 @@ func (i *imlMcpController) AppHandleMessage(ctx *gin.Context) {
return
}
ctx.Request.URL.Path = fmt.Sprintf("/openapi/v1/%s/message", mcp_server.GlobalBasePath)
ctx.Request = ctx.Request.WithContext(utils.SetLabel(ctx.Request.Context(), "app", appId))
i.handleMessage(ctx, i.openServer)
//ctx.Request = ctx.Request.WithContext(utils.SetLabel(ctx.Request.Context(), "app", appId))
i.handleMessage(ctx, i.openSseServer)
}
func (i *imlMcpController) AppHandleStreamHTTP(ctx *gin.Context) {
apikey := ctx.Request.Header.Get("Authorization")
apikey = strings.TrimPrefix(apikey, "Bearer ")
if apikey == "" {
ctx.AbortWithStatusJSON(403, gin.H{"code": -1, "msg": "invalid apikey", "success": "fail"})
return
}
appId := ctx.Request.Header.Get("X-Application-Id")
if appId == "" {
ctx.AbortWithStatusJSON(403, gin.H{"code": -1, "msg": "invalid app id", "success": "fail"})
return
}
cfg := i.settingModule.Get(ctx)
req := ctx.Request.WithContext(utils.SetGatewayInvoke(ctx.Request.Context(), cfg.InvokeAddress))
req = req.WithContext(utils.SetLabel(req.Context(), "apikey", apikey))
req = req.WithContext(utils.SetLabel(req.Context(), "app", appId))
req.URL.Path = mcp_server.OpenGlobalMCPPath
i.openStreamableServer.ServeHTTP(ctx.Writer, req)
}
func (i *imlMcpController) AppMCPConfig(ctx *gin.Context, appId string) (string, error) {
@@ -94,36 +116,44 @@ func (i *imlMcpController) AppMCPConfig(ctx *gin.Context, appId string) (string,
if err != nil {
return "", fmt.Errorf("get app info error: %v", err)
}
return fmt.Sprintf(mcpDefaultConfig, appInfo.Name, fmt.Sprintf("%s/openapi/v1/mcp/app/%s/sse?apikey={your_api_key}", strings.TrimSuffix(cfg.SitePrefix, "/"), appId)), nil
}
var mcpDefaultConfig = `{
"mcpServers": {
"%s": {
"url": "%s"
}
}
return mcp_server.NewMCPConfig(
mcp_server.TransportTypeStreamableHTTP,
fmt.Sprintf("%s%s", strings.TrimSuffix(cfg.SitePrefix, "/"), mcp_server.OpenAppMCPPath),
map[string]string{
"Authorization": "Bearer {your_api_key}",
"X-Application-Id": appId,
},
nil,
).ToString(appInfo.Name), nil
}
`
func (i *imlMcpController) GlobalMCPConfig(ctx *gin.Context) (string, error) {
cfg := i.settingModule.Get(ctx)
if cfg.SitePrefix == "" {
return "", fmt.Errorf("site prefix is empty")
}
return fmt.Sprintf(mcpDefaultConfig, "APIPark-MCP-Server", fmt.Sprintf("%s/openapi/v1/%s/sse?apikey={your_api_key}", strings.TrimSuffix(cfg.SitePrefix, "/"), mcp_server.GlobalBasePath)), nil
return mcp_server.NewMCPConfig(
mcp_server.TransportTypeStreamableHTTP,
fmt.Sprintf("%s%s", strings.TrimSuffix(cfg.SitePrefix, "/"), mcp_server.OpenGlobalMCPPath),
map[string]string{
"Authorization": "Bearer {your_api_key}",
},
nil,
).ToString("APIPark-MCP-Server"), nil
}
func (i *imlMcpController) OnComplete() {
i.server = make(map[string]http.Handler)
i.sseServers = make(map[string]http.Handler)
for language, tools := range mcpToolsByLanguage {
s := server.NewMCPServer("APIPark MCP Server", "1.0.0", server.WithLogging())
s.AddTool(tools[ToolServiceList], i.mcpModule.Services)
s.AddTool(tools[ToolOpenAPIDocument], i.mcpModule.APIs)
s.AddTool(tools[ToolInvokeAPI], i.mcpModule.Invoke)
i.server[language] = server.NewSSEServer(s, server.WithStaticBasePath(fmt.Sprintf("/api/v1/%s", mcp_server.GlobalBasePath)))
i.sseServers[language] = server.NewSSEServer(s, server.WithStaticBasePath(fmt.Sprintf("/api/v1/%s", mcp_server.GlobalBasePath)))
if language == languageEnUs {
i.openServer = server.NewSSEServer(s, server.WithStaticBasePath(fmt.Sprintf("/openapi/v1/%s", strings.Trim(mcp_server.GlobalBasePath, "/"))))
i.openSseServer = server.NewSSEServer(s, server.WithStaticBasePath(fmt.Sprintf("/openapi/v1/%s", strings.Trim(mcp_server.GlobalBasePath, "/"))))
i.openStreamableServer = server.NewStreamableHTTPServer(s, server.WithEndpointPath(mcp_server.OpenGlobalMCPPath))
}
}
}
@@ -132,16 +162,16 @@ func (i *imlMcpController) GlobalMCPHandle(ctx *gin.Context) {
cfg := i.settingModule.Get(ctx)
req := ctx.Request.WithContext(utils.SetGatewayInvoke(ctx.Request.Context(), cfg.InvokeAddress))
locale := utils.I18n(ctx)
if v, ok := i.server[locale]; ok {
if v, ok := i.sseServers[locale]; ok {
v.ServeHTTP(ctx.Writer, req)
return
}
i.server[languageEnUs].ServeHTTP(ctx.Writer, req)
i.sseServers[languageEnUs].ServeHTTP(ctx.Writer, req)
}
func (i *imlMcpController) GlobalHandleSSE(ctx *gin.Context) {
apikey := ctx.Request.URL.Query().Get("apikey")
i.handleSSE(ctx, i.openServer, SessionInfo{
i.handleSSE(ctx, i.openSseServer, SessionInfo{
Apikey: apikey,
})
}
@@ -167,7 +197,16 @@ func (i *imlMcpController) handleSSE(ctx *gin.Context, server http.Handler, sIn
}
func (i *imlMcpController) GlobalHandleMessage(ctx *gin.Context) {
i.handleMessage(ctx, i.openServer)
i.handleMessage(ctx, i.openSseServer)
}
func (i *imlMcpController) GlobalHandleStreamHTTP(ctx *gin.Context) {
apikey := ctx.Request.Header.Get("Authorization")
apikey = strings.TrimPrefix(apikey, "Bearer ")
cfg := i.settingModule.Get(ctx)
req := ctx.Request.WithContext(utils.SetGatewayInvoke(ctx.Request.Context(), cfg.InvokeAddress))
req = req.WithContext(utils.SetLabel(req.Context(), "apikey", apikey))
i.openStreamableServer.ServeHTTP(ctx.Writer, req)
}
func (i *imlMcpController) MCPHandle(ctx *gin.Context) {
@@ -204,12 +243,13 @@ func (i *imlMcpController) ServiceHandleMessage(ctx *gin.Context) {
}
func (i *imlMcpController) ServiceHandleStreamHTTP(ctx *gin.Context) {
apikey := ctx.Request.URL.Query().Get("apikey")
serviceId := ctx.Param("serviceId")
apikey := ctx.Request.Header.Get("Authorization")
serviceId := ctx.Request.Header.Get("X-Service-Id")
if serviceId == "" {
ctx.AbortWithStatusJSON(403, gin.H{"code": -1, "msg": "invalid service id", "success": "fail"})
return
}
apikey = strings.TrimPrefix(apikey, "Bearer ")
ok, err := i.authorizationModule.CheckAPIKeyAuthorizationByService(ctx, serviceId, apikey)
if err != nil {
ctx.AbortWithStatusJSON(403, gin.H{"code": -1, "msg": err.Error(), "success": "fail"})
+2
View File
@@ -13,11 +13,13 @@ type IMcpController interface {
GlobalMCPHandle(ctx *gin.Context)
GlobalHandleSSE(ctx *gin.Context)
GlobalHandleMessage(ctx *gin.Context)
GlobalHandleStreamHTTP(ctx *gin.Context)
GlobalMCPConfig(ctx *gin.Context) (string, error)
AppMCPHandle(ctx *gin.Context)
AppHandleSSE(ctx *gin.Context)
AppHandleMessage(ctx *gin.Context)
AppHandleStreamHTTP(ctx *gin.Context)
AppMCPConfig(ctx *gin.Context, appId string) (string, error)
ServiceHandleSSE(ctx *gin.Context)
+16 -10
View File
@@ -520,16 +520,21 @@ func (i *imlServiceController) createAIService(ctx *gin.Context, teamID string,
modelId := ""
modelCfg := ""
modelType := "online"
if input.Model != nil {
modelId = *input.Model
}
if *input.Provider == ai_provider_local.ProviderLocal {
modelType = "local"
list, err := i.aiLocalModel.SimpleList(ctx)
if err != nil {
return nil, err
if modelId == "" {
list, err := i.aiLocalModel.SimpleList(ctx)
if err != nil {
return nil, err
}
if len(list) == 0 {
return nil, fmt.Errorf("no local model")
}
modelId = list[0].Id
}
if len(list) == 0 {
return nil, fmt.Errorf("no local model")
}
modelId = list[0].Id
modelCfg = ai_provider_local.LocalConfig
} else {
pv, err := i.providerModule.Provider(ctx, *input.Provider)
@@ -540,14 +545,15 @@ func (i *imlServiceController) createAIService(ctx *gin.Context, teamID string,
if !has {
return nil, fmt.Errorf("provider not found")
}
m, has := p.GetModel(pv.DefaultLLM)
if modelId == "" {
modelId = pv.DefaultLLM
}
m, has := p.GetModel(modelId)
if !has {
return nil, fmt.Errorf("model %s not found", pv.DefaultLLM)
}
//modelId = m.ID()
modelId = m.Name()
modelCfg = m.DefaultConfig()
}
var info *service_dto.Service
+1 -1
View File
@@ -21,7 +21,7 @@
"plugins": ["react", "@typescript-eslint", "prettier", "unused-imports"],
"rules": {
"react/react-in-jsx-scope": "off",
"prettier/prettier": "off",
"prettier/prettier": "error",
"@typescript-eslint/no-explicit-any": "warn",
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": "off",
+1 -1
View File
@@ -6,7 +6,7 @@ yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
.next/
node_modules
dist
market_dist
-42
View File
@@ -1,42 +0,0 @@
const fs = require('fs');
const path = require('path');
const srcDir = path.join(__dirname, 'src');
const filesToDelete = [
'package.json',
'tsconfig.json',
'tsconfig.node.json',
'vite.config.ts',
'postcss.config.js',
'tailwind.config.js',
'.eslintrc.cjs',
'index.html',
'start-vite.js'
];
function walkDirAndClean(dir) {
if (!fs.existsSync(dir)) return;
fs.readdirSync(dir).forEach(f => {
let dirPath = path.join(dir, f);
try {
let stat = fs.statSync(dirPath);
if (stat.isDirectory() && f !== 'node_modules') {
// If it's a top-level module directory like src/core, src/common
if (dir === srcDir) {
filesToDelete.forEach(file => {
const fileToDelete = path.join(dirPath, file);
if (fs.existsSync(fileToDelete)) {
fs.unlinkSync(fileToDelete);
console.log(`Deleted: ${fileToDelete}`);
}
});
}
}
} catch(e) {}
});
}
walkDirAndClean(srcDir);
console.log('Cleanup completed!');
-50
View File
@@ -1,50 +0,0 @@
const fs = require('fs');
const path = require('path');
const srcDir = path.join(__dirname, 'src');
function walkDir(dir, callback) {
if (dir.includes('node_modules')) return;
fs.readdirSync(dir).forEach(f => {
let dirPath = path.join(dir, f);
try {
let isDirectory = fs.statSync(dirPath).isDirectory();
isDirectory ? walkDir(dirPath, callback) : callback(path.join(dir, f));
} catch(e) {}
});
}
const filesToRename = [];
const filesToUpdate = [];
walkDir(srcDir, (filePath) => {
if (filePath.endsWith('.module.css')) {
filesToRename.push(filePath);
} else if (filePath.endsWith('.tsx') || filePath.endsWith('.ts')) {
filesToUpdate.push(filePath);
}
});
filesToRename.forEach(oldPath => {
const newPath = oldPath.replace(/\.module\.css$/, '.css');
// Read and remove :global wrappers entirely
let content = fs.readFileSync(oldPath, 'utf8');
content = content.replace(/:global\(([^)]+)\)/g, '$1'); // replace :global(.foo) with .foo
content = content.replace(/:global\s+/g, ''); // replace :global .foo with .foo
fs.writeFileSync(oldPath, content);
fs.renameSync(oldPath, newPath);
console.log(`Renamed and cleaned: ${path.basename(oldPath)} -> ${path.basename(newPath)}`);
});
filesToUpdate.forEach(filePath => {
let content = fs.readFileSync(filePath, 'utf8');
if (content.includes('.module.css')) {
content = content.replace(/\.module\.css/g, '.css');
fs.writeFileSync(filePath, content);
console.log(`Updated imports in: ${path.basename(filePath)}`);
}
});
console.log('Done!');
+7
View File
@@ -0,0 +1,7 @@
{
"packages": [
"packages/*"
],
"version": "independent"
}
-144
View File
@@ -1,144 +0,0 @@
const fs = require('fs');
const path = require('path');
const rootDir = __dirname;
const packagesDir = path.join(rootDir, 'packages');
const srcDir = path.join(rootDir, 'src');
const appDir = path.join(srcDir, 'app');
console.log('🚀 开始拆除 Lerna 并迁移至 Next.js...');
// 1. 创建基础目录
if (!fs.existsSync(srcDir)) fs.mkdirSync(srcDir);
if (!fs.existsSync(appDir)) fs.mkdirSync(appDir);
// 2. 读取并合并 package.json
const rootPkgPath = path.join(rootDir, 'package.json');
const rootPkg = JSON.parse(fs.readFileSync(rootPkgPath, 'utf8'));
const mergedDeps = { ...rootPkg.dependencies };
const mergedDevDeps = { ...rootPkg.devDependencies };
if (fs.existsSync(packagesDir)) {
const packages = fs.readdirSync(packagesDir);
for (const pkg of packages) {
const pkgPath = path.join(packagesDir, pkg);
if (fs.statSync(pkgPath).isDirectory()) {
// 合并依赖
const childPkgPath = path.join(pkgPath, 'package.json');
if (fs.existsSync(childPkgPath)) {
const childPkg = JSON.parse(fs.readFileSync(childPkgPath, 'utf8'));
Object.assign(mergedDeps, childPkg.dependencies || {});
Object.assign(mergedDevDeps, childPkg.devDependencies || {});
}
// 移动目录到 src 下
const destPath = path.join(srcDir, pkg);
if (!fs.existsSync(destPath)) {
fs.renameSync(pkgPath, destPath);
console.log(`📦 已迁移模块: packages/${pkg} -> src/${pkg}`);
}
}
}
// 删除空的 packages 文件夹
try { fs.rmdirSync(packagesDir); } catch (e) { console.error('Failed to remove packages dir, skipping', e) }
}
// 3. 清理并更新根 package.json
delete rootPkg.workspaces; // 移除 lerna workspaces
rootPkg.scripts = {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
};
// 移除 Vite 和 Lerna 相关依赖
const removeDeps = ['lerna', 'vite', '@originjs/vite-plugin-federation', '@vitejs/plugin-react', 'vite-tsconfig-paths'];
removeDeps.forEach(dep => {
delete mergedDeps[dep];
delete mergedDevDeps[dep];
});
// 添加 Next.js 和 React 最新核心依赖 (与 xroute-ui 对齐)
mergedDeps['next'] = "15.4.5";
mergedDeps['react'] = "19.1.0";
mergedDeps['react-dom'] = "19.1.0";
mergedDevDeps['@types/react'] = "^19";
mergedDevDeps['@types/react-dom'] = "^19";
rootPkg.dependencies = mergedDeps;
rootPkg.devDependencies = mergedDevDeps;
fs.writeFileSync(rootPkgPath, JSON.stringify(rootPkg, null, 2));
console.log('✅ package.json 依赖已合并并重写');
// 4. 生成 tsconfig.json (配置路径别名)
const tsconfigPath = path.join(rootDir, 'tsconfig.json');
const tsconfig = {
compilerOptions: {
target: "es5",
lib: ["dom", "dom.iterable", "esnext"],
allowJs: true,
skipLibCheck: true,
strict: false,
noEmit: true,
esModuleInterop: true,
module: "esnext",
moduleResolution: "bundler",
resolveJsonModule: true,
isolatedModules: true,
jsx: "preserve",
incremental: true,
plugins: [{ name: "next" }],
baseUrl: ".",
paths: {
"@/*": ["src/*"],
// 欺骗原有代码,使其能找到拍平后的新路径
"@apipark/common/*": ["src/common/src/*"],
"@apipark/core/*": ["src/core/src/*"],
"@apipark/dashboard/*": ["src/dashboard/src/*"],
"@apipark/market/*": ["src/market/src/*"],
"@apipark/openApi/*": ["src/openApi/src/*"],
"@apipark/systemRunning/*": ["src/systemRunning/src/*"]
}
},
include: ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
exclude: ["node_modules"]
};
fs.writeFileSync(tsconfigPath, JSON.stringify(tsconfig, null, 2));
console.log('✅ tsconfig.json 别名映射已配置');
// 5. 创建 Next.js App Router 挂载点
const layoutCode = `export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}`;
fs.writeFileSync(path.join(appDir, 'layout.tsx'), layoutCode);
const slugDir = path.join(appDir, '[[...slug]]');
if (!fs.existsSync(slugDir)) fs.mkdirSync(slugDir, { recursive: true });
const pageCode = `"use client";
import dynamic from 'next/dynamic';
import { useEffect, useState } from 'react';
// 动态导入原有的 Vite SPA 根组件,禁用 SSR 避免 window 报错
const ApiParkApp = dynamic(() => import('@/core/src/App'), {
ssr: false,
loading: () => <div style={{ padding: 50 }}>Loading APIPark...</div>
});
export default function Page() {
const [mounted, setMounted] = useState(false);
useEffect(() => setMounted(true), []);
if (!mounted) return null;
return <ApiParkApp />;
}`;
fs.writeFileSync(path.join(slugDir, 'page.tsx'), pageCode);
console.log('✅ Next.js 路由挂载点创建完毕!');
console.log('🎉 迁移完成!请执行 pnpm install 重新安装依赖。');
-4
View File
@@ -1,4 +0,0 @@
/// <reference types="next" />
// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
-42
View File
@@ -1,42 +0,0 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
images: {
disableStaticImages: true,
},
experimental: {
optimizePackageImports: ["@heroui/react"],
},
transpilePackages: ['@heroui/react', '@heroui/theme', '@ant-design', 'antd', 'rc-util', 'rc-pagination', 'rc-picker', 'rc-tree', 'rc-table'],
async rewrites() {
return [
{
source: '/api/v1/:path*',
destination: 'http://172.18.166.219:8288/api/v1/:path*', // Proxy to backend
},
{
source: '/api2/v1/:path*',
destination: 'http://172.18.166.219:8288/api2/v1/:path*', // Proxy to backend 2
}
];
},
webpack: (config) => {
config.module.rules.push({
test: /\.(svg|png|jpe?g|gif|webp)$/i,
type: 'asset/resource',
generator: {
filename: 'static/media/[name].[hash][ext]'
}
});
// 解决一些 Node.js polyfill 在浏览器端缺失的问题
config.resolve.fallback = {
...config.resolve.fallback,
fs: false,
path: false,
os: false,
};
return config;
},
};
module.exports = nextConfig;
+28 -57
View File
@@ -2,12 +2,20 @@
"name": "frontend",
"version": "1.0.0",
"private": true,
"workspaces": [
"packages/*"
],
"description": "",
"scripts": {
"dev": "next dev -p 5000",
"build": "next build",
"start": "next start -p 5000",
"lint": "next lint"
"test": "jest",
"build": "set NODE_OPTIONS=--max-old-space-size=8192 && lerna run build --scope=core --stream --verbose ",
"serve": "lerna run preview --parallel",
"serve:remotes": "lerna run serve --scope=remote --parallel",
"dev": "lerna run dev --scope=core --stream",
"stop": "kill-port --port 5000",
"scan": "i18next-scanner --config i18next-scanner.config.js",
"lint": "eslint . --ext .js,.jsx,.ts,.tsx --fix",
"lint:fix": "eslint . --ext .js,.jsx,.ts,.tsx --fix && prettier --write ."
},
"keywords": [],
"author": "",
@@ -15,88 +23,51 @@
"dependencies": {
"@ant-design/icons": "^5.2.6",
"@ant-design/pro-components": "2.7.19",
"@emotion/react": "^11.14.0",
"@floating-ui/react": "^0.26.24",
"@formkit/auto-animate": "^0.8.1",
"@heroui/react": "^3.0.3",
"@heroui/styles": "^3.0.3",
"@heroui/theme": "^2.4.20",
"@lexical/code": "^0.17.1",
"@lexical/react": "^0.17.1",
"@lexical/selection": "^0.17.1",
"@lexical/text": "^0.17.1",
"@lexical/utils": "^0.17.1",
"@modelcontextprotocol/sdk": "^1.9.0",
"@mui/icons-material": "^5.15.6",
"@mui/lab": "5.0.0-alpha.150",
"@mui/material": "5.14.14",
"@mui/x-data-grid-pro": "6.18.1",
"@originjs/vite-plugin-federation": "^1.3.3",
"@rollup/plugin-dynamic-import-vars": "^2.1.2",
"@tinymce/tinymce-react": "^4.3.2",
"@types/dompurify": "^3.0.5",
"@types/lodash-es": "^4.17.12",
"@types/uuid": "^9.0.7",
"@xyflow/react": "^12.3.6",
"ahooks": "^3.8.1",
"allotment": "^1.20.0",
"@vitejs/plugin-react": "^4.2.0",
"autoprefixer": "^10.4.16",
"copy-to-clipboard": "^3.3.3",
"crc": "^4.3.2",
"dayjs": "^1.11.10",
"dompurify": "^3.1.6",
"echarts": "^5.5.0",
"echarts-for-react": "^3.0.2",
"framer-motion": "^10.16.4",
"fs-extra": "^11.2.0",
"highlight.js": "^11.9.0",
"i18next": "^23.12.2",
"i18next-browser-languagedetector": "^8.0.0",
"js-base64": "^3.7.5",
"lexical": "^0.17.1",
"mockjs": "^1.1.0",
"next": "15.4.5",
"postcss": "^8.4.31",
"postcss-import": "^16.1.0",
"postcss-nesting": "^12.1.5",
"rc-picker": "^4.1.1",
"react": "19.1.0",
"react": "^18.2.0",
"react-ace": "^10.1.0",
"react-dom": "19.1.0",
"react-dropzone": "^14.2.3",
"react-hook-form": "^7.49.3",
"react-dom": "^18.2.0",
"react-i18next": "^15.0.1",
"react-joyride": "^2.8.2",
"react-json-view": "^1.21.3",
"react-router-dom": "6.20.0",
"react-virtuoso": "^4.7.11",
"swagger-ui-react": "^5.17.14",
"tailwindcss": "^4.2.1",
"tinymce": "^6.8.1",
"use-context-selector": "^2.0.0",
"tailwindcss": "^3.3.5",
"uuid": "^9.0.1",
"zod": "^3.23.8"
"vite-tsconfig-paths": "^4.3.2",
"react-json-view": "^1.21.3",
"zod": "^3.23.8",
"@modelcontextprotocol/sdk": "^1.9.0",
"echarts-for-react": "^3.0.2"
},
"devDependencies": {
"@ant-design/cssinjs": "^1.18.2",
"@antv/g6": "^4.8.24",
"@formily/antd-v5": "^1.2.1",
"@formily/core": "^2.2.13",
"@formily/react": "^2.2.13",
"@formily/reactive": "^2.2.13",
"@iconify/react": "^5.0.2",
"@monaco-editor/react": "^4.6.0",
"@tailwindcss/postcss": "^4.2.1",
"lightningcss": "^1.32.0",
"@testing-library/jest-dom": "^6.4.5",
"@testing-library/react": "^15.0.7",
"@testing-library/react-hooks": "^8.0.1",
"@types/file-saver": "^2.0.7",
"@types/jest": "^29.5.12",
"@types/node": "^20.10.5",
"@types/react": "^19",
"@types/react-dom": "^19",
"@types/react": "^18.2.37",
"@types/react-dom": "^18.2.15",
"@typescript-eslint/eslint-plugin": "^6.10.0",
"@typescript-eslint/parser": "^6.10.0",
"@vitejs/plugin-react": "^4.2.0",
"antd": "^5.19.4",
"babel-jest": "^29.7.0",
"eslint": "^8.53.0",
@@ -106,22 +77,22 @@
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.4",
"eslint-plugin-unused-imports": "^4.1.4",
"exceljs": "^4.4.0",
"file-saver": "^2.0.5",
"i18next-scanner": "^4.5.0",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"jest-fetch-mock": "^3.0.3",
"jsdom": "^24.0.0",
"lerna": "^8.1.3",
"less": "^4.2.0",
"lodash": "^4.17.21",
"lodash-es": "^4.17.21",
"monaco-editor": "^0.45.0",
"postcss-nested": "^6.0.1",
"prettier": "^3.1.1",
"react-test-renderer": "^18.3.1",
"ts-jest": "^29.1.2",
"typescript": "^5.2.2",
"vite": "^5.0.0",
"vite-jest": "^0.1.4"
}
}
}
+41
View File
@@ -0,0 +1,41 @@
{
"name": "common",
"version": "1.0.0",
"description": "Common library for AO Platform",
"scripts": {
"dev": "vite",
"build": "vite build",
"test": "node ./__tests__/common.test.js"
},
"dependencies": {
"@floating-ui/react": "^0.26.24",
"@formkit/auto-animate": "^0.8.1",
"@lexical/code": "^0.17.1",
"@lexical/react": "^0.17.1",
"@lexical/selection": "^0.17.1",
"@lexical/text": "^0.17.1",
"@lexical/utils": "^0.17.1",
"@mui/icons-material": "^5.15.6",
"@mui/lab": "5.0.0-alpha.150",
"@mui/material": "5.14.14",
"@mui/x-data-grid-pro": "6.18.1",
"ahooks": "^3.8.1",
"allotment": "^1.20.0",
"echarts": "^5.5.0",
"lexical": "^0.17.1",
"mockjs": "^1.1.0",
"rc-picker": "^4.1.1",
"react-dropzone": "^14.2.3",
"react-hook-form": "^7.49.3",
"use-context-selector": "^2.0.0"
},
"devDependencies": {
"@formily/antd-v5": "^1.2.1",
"@formily/core": "^2.2.13",
"@formily/react": "^2.2.13",
"@formily/reactive": "^2.2.13",
"@monaco-editor/react": "^4.6.0",
"exceljs": "^4.4.0",
"monaco-editor": "^0.45.0"
}
}
@@ -0,0 +1,10 @@
export default {
plugins: {
'postcss-import': {},
'tailwindcss/nesting': {},
tailwindcss: {},
autoprefixer: {}
},
}

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 6.5 KiB

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

@@ -15,7 +15,7 @@ import { useEffect, useMemo, useState } from 'react'
import { Outlet, useLocation, useNavigate } from 'react-router-dom'
import LanguageSetting from './LanguageSetting'
const APP_MODE = process.env.NEXT_PUBLIC_APP_MODE || 'production'
const APP_MODE = import.meta.env.VITE_APP_MODE
export type MenuItem = Required<MenuProps>['items'][number]
const themeToken = {
@@ -1,9 +1,9 @@
.eo_page_list .ant-pro-card .ant-pro-card-body{
:global .eo_page_list .ant-pro-card .ant-pro-card-body{
padding:0 !important;
}
.eo_page_list .ant-pro-table-list-toolbar-container{
:global .eo_page_list .ant-pro-table-list-toolbar-container{
.ant-pro-table-list-toolbar-right{
justify-content: flex-start;
@@ -14,7 +14,7 @@
display:none;
}
}
.eo_page_list .ant-table-wrapper {
:global .eo_page_list .ant-table-wrapper {
.ant-table-pagination.ant-pagination {
margin: 1px 10px 0 !important;
padding: 10px 0;
@@ -18,7 +18,7 @@ import {
useState
} from 'react'
import { useGlobalContext } from '../../contexts/GlobalStateContext'
import './PageList.css'
import './PageList.module.css'
export type PageProColumns<T = any, ValueType = 'text'> = ProColumns<T, ValueType> & { btnNums?: number }

Some files were not shown because too many files have changed in this diff Show More