diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b512c09 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..7458734 --- /dev/null +++ b/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "nanoid": "^5.1.6" + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..2549325 --- /dev/null +++ b/pnpm-lock.yaml @@ -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: {} diff --git a/web/package.json b/web/package.json index 6d1036d..6a682c4 100644 --- a/web/package.json +++ b/web/package.json @@ -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", diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml index 4abe80b..44dfd10 100644 --- a/web/pnpm-lock.yaml +++ b/web/pnpm-lock.yaml @@ -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) diff --git a/web/src/apps/setting/index.tsx b/web/src/apps/setting/index.tsx new file mode 100644 index 0000000..4135cba --- /dev/null +++ b/web/src/apps/setting/index.tsx @@ -0,0 +1,24 @@ +import { toast, ToastContainer } from 'react-toastify'; + +export const AppProvider = () => { + return
+ + +
+} + +export const App = () => { + return ( +
Studio App
+ ) +} \ No newline at end of file diff --git a/web/src/apps/studio/index.tsx b/web/src/apps/studio/index.tsx index cf0f919..95b2069 100644 --- a/web/src/apps/studio/index.tsx +++ b/web/src/apps/studio/index.tsx @@ -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
@@ -87,14 +87,22 @@ export const App = () => { )} +
- + + + +
{/* Description with expand/collapse */} diff --git a/web/src/apps/studio/store.ts b/web/src/apps/studio/store.ts index cc5ae16..f7b6126 100644 --- a/web/src/apps/studio/store.ts +++ b/web/src/apps/studio/store.ts @@ -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; } +// 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; getRoutes: () => Promise; run: (route: RouteItem) => Promise; + 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((set) => ({ +export const useStudioStore = create((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)) + } +} \ No newline at end of file