更新依赖项版本,添加新功能和改进应用程序结构

This commit is contained in:
2025-12-30 03:00:46 +08:00
parent 3ca2820516
commit 8670fd3bfc
8 changed files with 208 additions and 56 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
node_modules

5
package.json Normal file
View File

@@ -0,0 +1,5 @@
{
"dependencies": {
"nanoid": "^5.1.6"
}
}

24
pnpm-lock.yaml generated Normal file
View File

@@ -0,0 +1,24 @@
lockfileVersion: '9.0'
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
importers:
.:
dependencies:
nanoid:
specifier: ^5.1.6
version: 5.1.6
packages:
nanoid@5.1.6:
resolution: {integrity: sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg==}
engines: {node: ^18 || >=20}
hasBin: true
snapshots:
nanoid@5.1.6: {}

View File

@@ -27,11 +27,11 @@
"@kevisual/query": "^0.0.33",
"@kevisual/query-login": "^0.0.7",
"@kevisual/registry": "^0.0.1",
"@kevisual/router": "^0.0.49",
"@kevisual/router": "^0.0.51",
"@radix-ui/react-slot": "^1.2.4",
"@tailwindcss/vite": "^4.1.18",
"@uiw/react-md-editor": "^4.0.11",
"antd": "^6.1.2",
"antd": "^6.1.3",
"astro": "^5.16.6",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
@@ -55,7 +55,7 @@
"access": "public"
},
"devDependencies": {
"@kevisual/api": "^0.0.5",
"@kevisual/api": "^0.0.10",
"@kevisual/types": "^0.0.10",
"@types/react": "^19.2.7",
"@types/react-dom": "^19.2.3",

72
web/pnpm-lock.yaml generated
View File

@@ -33,8 +33,8 @@ importers:
specifier: ^0.0.1
version: 0.0.1(typescript@5.9.3)
'@kevisual/router':
specifier: ^0.0.49
version: 0.0.49
specifier: ^0.0.51
version: 0.0.51
'@radix-ui/react-slot':
specifier: ^1.2.4
version: 1.2.4(@types/react@19.2.7)(react@19.2.3)
@@ -45,8 +45,8 @@ importers:
specifier: ^4.0.11
version: 4.0.11(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
antd:
specifier: ^6.1.2
version: 6.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
specifier: ^6.1.3
version: 6.1.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
astro:
specifier: ^5.16.6
version: 5.16.6(@types/node@24.7.2)(idb-keyval@6.2.2)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.52.4)(typescript@5.9.3)
@@ -103,8 +103,8 @@ importers:
version: 5.0.9(@types/react@19.2.7)(react@19.2.3)
devDependencies:
'@kevisual/api':
specifier: ^0.0.5
version: 0.0.5
specifier: ^0.0.10
version: 0.0.10
'@kevisual/types':
specifier: ^0.0.10
version: 0.0.10
@@ -681,8 +681,8 @@ packages:
'@jridgewell/trace-mapping@0.3.31':
resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
'@kevisual/api@0.0.5':
resolution: {integrity: sha512-5pBu0aSeUeKZM037OgihVzoBfBFqEvywcRo66I51AwGF9/h2xP4PuFqOM7Kqp3KWL+USH8kyEwgwSdJ+FCb5RQ==}
'@kevisual/api@0.0.10':
resolution: {integrity: sha512-AF5DcXPfVEZtvIJw9EC8EXkhU33dS08v9+b4mIrzCi0ETRvwAlQ2cg8WgfY6exJYzbFg6M4h+POhXvPujrk9mA==}
'@kevisual/cache@0.0.3':
resolution: {integrity: sha512-BWEck69KYL96/ywjYVkML974RHjDJTj2ITQND1zFPR+hlBV1H1p55QZgSYRJCObg3EAV1S9Zic/fR2T4pfe8yg==}
@@ -690,6 +690,12 @@ packages:
'@kevisual/context@0.0.4':
resolution: {integrity: sha512-HJeLeZQLU+7tCluSfOyvkgKLs0HjCZrdJlZgEgKRSa8XTwZfMAUt6J7qZTbrZAHBlPtX68EPu/PI8JMCeu3WAQ==}
'@kevisual/js-filter@0.0.2':
resolution: {integrity: sha512-SS8diRpjrAIEQKT8YMTa1XTucQKuPbG04UChXtp7wd1jPsvQaNKYapErRA8qx4igwoVQt6eAYADwYzXhB1fN2A==}
'@kevisual/load@0.0.6':
resolution: {integrity: sha512-+3YTFehRcZ1haGel5DKYMUwmi5i6f2psyaPZlfkKU/cOXgkpwoG9/BEqPCnPjicKqqnksEpixVRkyHJ+5bjLVA==}
'@kevisual/query-login@0.0.7':
resolution: {integrity: sha512-oOyPIz337cdTt7WncFj7Wr7nxUHh0pBB6KSAJlas+lQiWBPwQEZhpEd7YciydCRlMc9IJMcZRV1Bw3qgy8FFqQ==}
peerDependencies:
@@ -701,8 +707,8 @@ packages:
'@kevisual/registry@0.0.1':
resolution: {integrity: sha512-//OHu9m4JDrMjgP8o8dcjZd3D3IAUkRVlkTSviouZEH7r5m7mccA3Hvzw0XJ/lelx6exC6LWsyv6c4uV0Dp+gw==}
'@kevisual/router@0.0.49':
resolution: {integrity: sha512-2HXuOnnWdRfkO0LyqolWU9cvWHGXi8FV3OqEvWgfO+f7wx8GT8T6Bb8dCzdldDaAxve1dgLBavtdmnHyCkp+1Q==}
'@kevisual/router@0.0.51':
resolution: {integrity: sha512-i9qYBeS/um78oC912oWJD3iElB+5NTKyTrz1Hzf4DckiUFnjLL81UPwjIh5I2l9+ul0IZ/Pxx+sFSF99fJkzKg==}
'@kevisual/types@0.0.10':
resolution: {integrity: sha512-Q73uzzjk9UidumnmCvOpgzqDDvQxsblz22bIFuoiioUFJWwaparx8bpd8ArRyFojicYL1YJoFDzDZ9j9NN8grA==}
@@ -951,8 +957,8 @@ packages:
resolution: {integrity: sha512-qgGdcVIF604M9EqjNF0hbUTz42bz/RDtxWdWuU5EQe3hi7M8ob54B6B35rOsvX5eSvIHIzT9iH1R3n+hk3CGfg==}
engines: {node: '>=14.x'}
'@rc-component/cascader@1.9.0':
resolution: {integrity: sha512-2jbthe1QZrMBgtCvNKkJFjZYC3uKl4N/aYm5SsMvO3T+F+qRT1CGsSM9bXnh1rLj7jDk/GK0natShWF/jinhWQ==}
'@rc-component/cascader@1.10.0':
resolution: {integrity: sha512-D1XOKvbhdo9kX+cG1p8qJOnSq+sMK3L84iVYjGQIx950kJt0ixN+Xac75ykyK/AC8V3GUanjNK14Qkv149RrEw==}
peerDependencies:
react: '>=18.0.0'
react-dom: '>=18.0.0'
@@ -1131,8 +1137,8 @@ packages:
react: '>=16.0.0'
react-dom: '>=16.0.0'
'@rc-component/select@1.3.6':
resolution: {integrity: sha512-CzbJ9TwmWcF5asvTMZ9BMiTE9CkkrigeOGRPpzCNmeZP7KBwwmYrmOIiKh9tMG7d6DyGAEAQ75LBxzPx+pGTHA==}
'@rc-component/select@1.4.0':
resolution: {integrity: sha512-DDCsUkx3lHAO42fyPiBADzZgbqOp3gepjBCusuy6DDN51Vx73cwX0aqsid1asxpIwHPMYGgYg+wXbLi4YctzLQ==}
engines: {node: '>=8.x'}
peerDependencies:
react: '*'
@@ -1191,8 +1197,8 @@ packages:
react: '>=16.9.0'
react-dom: '>=16.9.0'
'@rc-component/tree-select@1.4.0':
resolution: {integrity: sha512-I3UAlO2hNqy9CSKc8EBaESgnmKk2QaRzuZ2XHZGFCgsSMkGl06mdF97sVfROM02YIb64ocgLKefsjE0Ch4ocwQ==}
'@rc-component/tree-select@1.5.0':
resolution: {integrity: sha512-1nBAMreFJXkCIeZlWG0l+6i0jLWzlmmRv/TrtZjLkoq8WmpzSuDhP32YroC7rAhGFR34thpHkvCedPzBXIL/XQ==}
peerDependencies:
react: '*'
react-dom: '*'
@@ -1675,8 +1681,8 @@ packages:
resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==}
engines: {node: '>=12'}
antd@6.1.2:
resolution: {integrity: sha512-pqYaZECL/7TBiNxxz+LieLiPCem6DaEzudqN44EZ3SvJjixLP7K41n6clo0zxe/2HiOUe9KxTMxGN+icOkL6Tw==}
antd@6.1.3:
resolution: {integrity: sha512-kvaLtOm0UwCIdtR424/Mo6pyJxN34/6003e1io3GIKWQOdlddplFylv767iGxXLMrxfNoQmxuNJcF1miFbxCZQ==}
peerDependencies:
react: '>=18.0.0'
react-dom: '>=18.0.0'
@@ -4139,8 +4145,10 @@ snapshots:
'@jridgewell/resolve-uri': 3.1.2
'@jridgewell/sourcemap-codec': 1.5.5
'@kevisual/api@0.0.5':
'@kevisual/api@0.0.10':
dependencies:
'@kevisual/js-filter': 0.0.2
'@kevisual/load': 0.0.6
es-toolkit: 1.43.0
nanoid: 5.1.6
@@ -4150,6 +4158,12 @@ snapshots:
'@kevisual/context@0.0.4': {}
'@kevisual/js-filter@0.0.2': {}
'@kevisual/load@0.0.6':
dependencies:
eventemitter3: 5.0.1
'@kevisual/query-login@0.0.7(@kevisual/query@0.0.33)':
dependencies:
'@kevisual/cache': 0.0.3
@@ -4176,7 +4190,7 @@ snapshots:
- react-native
- typescript
'@kevisual/router@0.0.49':
'@kevisual/router@0.0.51':
dependencies:
path-to-regexp: 8.3.0
selfsigned: 5.4.0
@@ -4475,9 +4489,9 @@ snapshots:
dependencies:
'@babel/runtime': 7.28.4
'@rc-component/cascader@1.9.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)':
'@rc-component/cascader@1.10.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)':
dependencies:
'@rc-component/select': 1.3.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@rc-component/select': 1.4.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@rc-component/tree': 1.1.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@rc-component/util': 1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
clsx: 2.1.1
@@ -4688,7 +4702,7 @@ snapshots:
react: 19.2.3
react-dom: 19.2.3(react@19.2.3)
'@rc-component/select@1.3.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3)':
'@rc-component/select@1.4.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)':
dependencies:
'@rc-component/overflow': 1.0.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@rc-component/trigger': 3.7.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
@@ -4766,9 +4780,9 @@ snapshots:
react: 19.2.3
react-dom: 19.2.3(react@19.2.3)
'@rc-component/tree-select@1.4.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)':
'@rc-component/tree-select@1.5.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)':
dependencies:
'@rc-component/select': 1.3.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@rc-component/select': 1.4.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@rc-component/tree': 1.1.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@rc-component/util': 1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
clsx: 2.1.1
@@ -5303,7 +5317,7 @@ snapshots:
ansi-styles@6.2.3: {}
antd@6.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3):
antd@6.1.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3):
dependencies:
'@ant-design/colors': 8.0.0
'@ant-design/cssinjs': 2.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
@@ -5312,7 +5326,7 @@ snapshots:
'@ant-design/icons': 6.1.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@ant-design/react-slick': 2.0.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@babel/runtime': 7.28.4
'@rc-component/cascader': 1.9.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@rc-component/cascader': 1.10.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@rc-component/checkbox': 1.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@rc-component/collapse': 1.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@rc-component/color-picker': 3.0.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
@@ -5335,7 +5349,7 @@ snapshots:
'@rc-component/rate': 1.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@rc-component/resize-observer': 1.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@rc-component/segmented': 1.3.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@rc-component/select': 1.3.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@rc-component/select': 1.4.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@rc-component/slider': 1.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@rc-component/steps': 1.2.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@rc-component/switch': 1.0.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
@@ -5345,7 +5359,7 @@ snapshots:
'@rc-component/tooltip': 1.4.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@rc-component/tour': 2.2.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@rc-component/tree': 1.1.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@rc-component/tree-select': 1.4.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@rc-component/tree-select': 1.5.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@rc-component/trigger': 3.7.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@rc-component/upload': 1.1.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@rc-component/util': 1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)

View File

@@ -0,0 +1,24 @@
import { toast, ToastContainer } from 'react-toastify';
export const AppProvider = () => {
return <main className='w-full'>
<App />
<ToastContainer
position="top-right"
autoClose={3000}
hideProgressBar
newestOnTop
closeOnClick
rtl={false}
pauseOnFocusLoss
draggable
pauseOnHover
theme="light" />
</main>
}
export const App = () => {
return (
<div>Studio App</div>
)
}

View File

@@ -1,7 +1,7 @@
import { toast, ToastContainer } from 'react-toastify';
import { useStudioStore } from './store.ts';
import { useEffect, useState } from 'react';
import { Play } from 'lucide-react';
import { MonitorPlay, Play } from 'lucide-react';
export const AppProvider = () => {
return <main className='w-full'>
<App />
@@ -87,14 +87,22 @@ export const App = () => {
</div>
)}
</div>
<div className='inline-flex items-center justify-center gap-1'>
<button
className="inline-flex items-center justify-center p-1.5 rounded-md text-gray-500 hover:text-green-600 hover:bg-green-50 transition-all duration-200 cursor-pointer"
title="运行"
className="p-1.5 rounded-md text-gray-500 hover:text-gray-900 hover:bg-gray-200 transition-all duration-200 cursor-pointer"
title="直接运行"
onClick={() => run(route)}
>
<Play size={14} strokeWidth={2.5} />
</button>
<button className="p-1.5 rounded-md text-gray-20 hover:text-gray-900 hover:bg-gray-200 transition-all duration-200 cursor-pointer"
title="高级运行"
onClick={() => run(route)}>
<MonitorPlay size={14} strokeWidth={2.5} />
</button>
</div>
</div>
{/* Description with expand/collapse */}

View File

@@ -1,16 +1,10 @@
import { create } from 'zustand';
import { QueryProxy } from '@kevisual/api'
import { QueryProxy, ProxyItem } from '@kevisual/api'
// import { query } from '@/modules/query.ts'
import { Query } from '@kevisual/query';
import { QueryClient } from '@kevisual/query';
import { toast } from 'react-toastify';
const url = localStorage.getItem('BROWSER_HELPER_URL') || 'http://localhost:52000/api/router';
const query = new Query({
url,
})
import { QueryRouterServer } from '@kevisual/router/src/route.ts'
const router = new QueryRouterServer();
const qp = new QueryProxy({ query, router });
type RouteItem = {
id: string;
@@ -19,29 +13,111 @@ type RouteItem = {
description?: string;
metadata?: Record<string, any>;
}
// type ProxyItem = {
// title?: string;
// type?: 'api' | 'context' | 'page';
// description?: string;
// api?: {
// url: string;
// },
// context?: {
// key: string;
// },
// page?: {},
// where?: string;
// whereList?: Array<{ title: string; where: string }>;
// }
interface StudioState {
routes: Array<RouteItem>;
getRoutes: () => Promise<void>;
run: (route: RouteItem) => Promise<void>;
queryProxy?: QueryProxy;
router?: QueryRouterServer;
init: (opts?: { url?: string }) => Promise<{ router: QueryRouterServer; queryProxy: QueryProxy }>;
proxy?: ProxyItem;
setProxy?: (proxy: ProxyItem) => void;
proxyList?: ProxyItem[];
setProxyList?: (list: ProxyItem[]) => void;
}
const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
export const useStudioStore = create<StudioState>((set) => ({
export const useStudioStore = create<StudioState>((set, get) => ({
routes: [],
getRoutes: async () => {
await qp.init();
await sleep(200); // wait for routes to be registered
console.log('query proxy', qp.router);
const routes: any[] = await qp.listRoutes()
const state = get();
let queryProxy = state.queryProxy;
if (!queryProxy) {
const init = await state.init();
queryProxy = init.queryProxy;
}
console.log('query proxy', queryProxy.router);
const routes: any[] = await queryProxy.listRoutes(() => true, "")
console.log('fetched routes', routes);
set({ routes });
},
run: async (route: RouteItem) => {
console.log('running route', route);
const res = await qp.run({ path: route.path, key: route.key });
const state = get();
let queryProxy = state.queryProxy!;
if (!state.queryProxy) {
const init = await state.init();
queryProxy = init.queryProxy;
}
console.log('running route', route, queryProxy.query.url);
const res = await queryProxy.run({ path: route.path, key: route.key });
console.log('route run result', res);
if (res.code !== 200) {
toast.error(`运行失败:${res.message || '未知错误'}`);
} else if (res.code === 200) {
//
}
}
},
queryProxy: undefined,
router: undefined,
init: async () => {
const proxy = get().proxy || localStorageProxy.get();
const url = proxy.type === 'api' && proxy.api ? proxy.api.url : '/client/router';
// let _url = 'http://localhost:52002/api/router';
let _url = 'http://localhost:52000/api/router';
// let _url = '/api/router';
const query = new QueryClient({
url: _url,
});
const router = new QueryRouterServer();
const queryProxy = new QueryProxy({ query, router });
await queryProxy.init();
set({ queryProxy, router });
return { router, queryProxy }
},
proxy: undefined,
setProxy: (proxy: ProxyItem) => {
localStorageProxy.set(proxy);
set({ proxy });
},
proxyList: [],
setProxyList: (list: ProxyItem[]) => {
set({ proxyList: list });
},
}));
export const localStorageProxy = {
get: (): ProxyItem => {
const data = localStorage.getItem('PROXY_CONFIG')
if (data) {
return JSON.parse(data)
}
const defult: ProxyItem = {
title: '默认',
description: '默认',
type: 'api',
api: {
url: '/client/router'
},
}
localStorageProxy.set(defult)
return defult;
},
set: (proxy: ProxyItem) => {
localStorage.setItem('PROXY_CONFIG', JSON.stringify(proxy))
}
}