diff --git a/plugins/flex.js b/plugins/flex.js index ad53cd5..168657a 100644 --- a/plugins/flex.js +++ b/plugins/flex.js @@ -19,6 +19,7 @@ const flexCenter = plugin(function ({ addUtilities }) { '.card-subtitle': {}, '.card-body': {}, '.card-footer': {}, + '.card-key': {}, }); }); diff --git a/src/App.tsx b/src/App.tsx index 1e929a3..ac2b3a3 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -6,7 +6,7 @@ import { App as PublishApp } from './pages/publish'; import { App as CodeEditorApp } from './pages/code-editor'; import { App as MapApp } from './pages/map'; import { App as PromptApp } from './pages/prompt'; - +import { App as AiAgentApp } from './pages/ai-agent'; import '@abearxiong/container/dist/container.css'; export const App = () => { @@ -25,6 +25,7 @@ export const App = () => { } /> } /> } /> + } /> 404} /> 404} /> diff --git a/src/globals.css b/src/globals.css index 51fd0b6..8e73f15 100644 --- a/src/globals.css +++ b/src/globals.css @@ -42,6 +42,9 @@ .card-body { @apply text-gray-700; } + .card-key { + @apply text-xs text-gray-400; + } .card-footer { @apply text-sm text-gray-500; } diff --git a/src/pages/ai-agent/edit/List.tsx b/src/pages/ai-agent/edit/List.tsx new file mode 100644 index 0000000..674a3bb --- /dev/null +++ b/src/pages/ai-agent/edit/List.tsx @@ -0,0 +1,156 @@ +import { useShallow } from 'zustand/react/shallow'; +import { useAgentStore } from '../store'; +import { useEffect } from 'react'; +import { CardBlank } from '@/components/card/CardBlank'; +import { Button, Form, Input, message, Modal, Tooltip } from 'antd'; +import copy from 'copy-to-clipboard'; +import { useNavigate } from 'react-router'; +import { EditOutlined, SettingOutlined, LinkOutlined, SaveOutlined, DeleteOutlined, LeftOutlined, CaretRightOutlined } from '@ant-design/icons'; +import clsx from 'clsx'; +import { isObjectNull } from '@/utils/is-null'; +const FormModal = () => { + const [form] = Form.useForm(); + const containerStore = useAgentStore( + useShallow((state) => { + return { + showEdit: state.showEdit, + setShowEdit: state.setShowEdit, + formData: state.formData, + updateData: state.updateData, + }; + }), + ); + useEffect(() => { + const open = containerStore.showEdit; + if (open) { + const isNull = isObjectNull(containerStore.formData); + if (isNull) { + form.setFieldsValue({}); + } else form.setFieldsValue(containerStore.formData); + } + }, [containerStore.showEdit]); + const onFinish = async (values: any) => { + if (!values.id) { + message.error('Cant add data'); + return; + } + containerStore.updateData(values); + }; + const onClose = () => { + containerStore.setShowEdit(false); + form.resetFields(); + }; + const isEdit = containerStore.formData.id; + return ( + containerStore.setShowEdit(false)} + destroyOnClose + footer={false} + width={800} + onCancel={onClose}> +
+ + + + + + + + + + + +
+
+ ); +}; +export const List = () => { + const agentStore = useAgentStore( + useShallow((state) => { + return { + setFormData: state.setFormData, + setShowEdit: state.setShowEdit, + list: state.list, + deleteData: state.deleteData, + getList: state.getList, + loading: state.loading, + publishData: state.publishData, + updateData: state.updateData, + formData: state.formData, + }; + }), + ); + useEffect(() => { + agentStore.getList(); + }, []); + return ( +
+
+
+ {agentStore.list.map((item) => { + return ( +
+
+ {item.model}
{item.key}
+
+
+
+ + + + + + + + +
+
+
+ ); + })} + {agentStore.list.length === 0 &&
No data
} + +
+
+ +
+ ); +}; diff --git a/src/pages/ai-agent/index.tsx b/src/pages/ai-agent/index.tsx new file mode 100644 index 0000000..54c7e20 --- /dev/null +++ b/src/pages/ai-agent/index.tsx @@ -0,0 +1,14 @@ +import { Navigate, Route, Routes } from 'react-router-dom'; +import { List } from './edit/List'; +import { Main } from './layouts'; +export const App = () => { + return ( + + }> + }> + } /> + + + + ); +}; diff --git a/src/pages/ai-agent/layouts/index.tsx b/src/pages/ai-agent/layouts/index.tsx new file mode 100644 index 0000000..b8b230d --- /dev/null +++ b/src/pages/ai-agent/layouts/index.tsx @@ -0,0 +1,14 @@ +import { Outlet } from 'react-router'; + +export const Main = () => { + return ( +
+
Agent
+
+
+ +
+
+
+ ); +}; diff --git a/src/pages/ai-agent/store/index.ts b/src/pages/ai-agent/store/index.ts new file mode 100644 index 0000000..ee46b0c --- /dev/null +++ b/src/pages/ai-agent/store/index.ts @@ -0,0 +1,94 @@ +import { create } from 'zustand'; +import { query } from '@/modules'; +import { message } from 'antd'; +type AgentStore = { + showEdit: boolean; + setShowEdit: (showEdit: boolean) => void; + formData: any; + setFormData: (formData: any) => void; + loading: boolean; + setLoading: (loading: boolean) => void; + list: any[]; + getList: () => Promise; + updateData: (data: any) => Promise; + deleteData: (id: string) => Promise; + publishData: (data: any) => Promise; +}; +export const useAgentStore = create((set, get) => { + return { + showEdit: false, + setShowEdit: (showEdit) => set({ showEdit }), + formData: {}, + setFormData: (formData) => set({ formData }), + loading: false, + setLoading: (loading) => set({ loading }), + list: [], + getList: async () => { + set({ loading: true }); + + const res = await query.post({ + path: 'agent', + key: 'list', + }); + set({ loading: false }); + if (res.code === 200) { + set({ list: res.data }); + } else { + message.error(res.msg || 'Request failed'); + } + }, + updateData: async (data) => { + const { getList } = get(); + const res = await query.post({ + path: 'agent', + key: 'update', + data, + }); + if (res.code === 200) { + message.success('Success'); + set({ showEdit: false, formData: [] }); + getList(); + } else { + message.error(res.msg || 'Request failed'); + } + }, + deleteData: async (id) => { + const { getList } = get(); + const res = await query.post({ + path: 'agent', + key: 'delete', + id, + }); + if (res.code === 200) { + getList(); + message.success('Success'); + } else { + message.error(res.msg || 'Request failed'); + } + }, + publishData: async (data) => { + const hasPublish = !!data.publish?.name; + const publish = { + name: 'test-import', + }; + if (!hasPublish) { + console.error('need publish.name'); + return; + } + const res = await query.post({ + path: 'agent', + key: 'publish', + data: { + id: data.id, + publish: publish, + type: 'patch', + }, + }); + if (res.code === 200) { + message.success('Success'); + } else { + message.error(res.msg || 'Request failed'); + } + }, + }; +}); diff --git a/src/pages/code-editor/store.ts b/src/pages/code-editor/store.ts index 3cf4100..cc22d22 100644 --- a/src/pages/code-editor/store.ts +++ b/src/pages/code-editor/store.ts @@ -1,6 +1,7 @@ import { create } from 'zustand'; import { produce } from 'immer'; import { query } from '@/modules'; +import { message } from 'antd'; type QueryPath = { key?: string; @@ -50,8 +51,12 @@ export const useCodeEditorStore = create((set, get) => ({ _newData = data; } if (path && key) { + const load = message.loading('loading...', 0); + const res = await query.post({ path, key, data: _newData }); + load(); if (res.code === 200) { + message.success('success'); set( produce((state) => { state.data = res.data; diff --git a/src/pages/container/edit/List.tsx b/src/pages/container/edit/List.tsx index d3118b9..a4f12d1 100644 --- a/src/pages/container/edit/List.tsx +++ b/src/pages/container/edit/List.tsx @@ -8,6 +8,7 @@ import copy from 'copy-to-clipboard'; import { useNavigate } from 'react-router'; import { EditOutlined, SettingOutlined, LinkOutlined, SaveOutlined, DeleteOutlined, LeftOutlined } from '@ant-design/icons'; import clsx from 'clsx'; +import { isObjectNull } from '@/utils/is-null'; const FormModal = () => { const [form] = Form.useForm(); const containerStore = useContainerStore( @@ -23,7 +24,12 @@ const FormModal = () => { useEffect(() => { const open = containerStore.showEdit; if (open) { - form.setFieldsValue(containerStore.formData || {}); + if (open) { + const isNull = isObjectNull(containerStore.formData); + if (isNull) { + form.setFieldsValue({}); + } else form.setFieldsValue(containerStore.formData); + } } }, [containerStore.showEdit]); const onFinish = async (values: any) => { diff --git a/src/pages/map/index.tsx b/src/pages/map/index.tsx index 205fcad..d68b8a7 100644 --- a/src/pages/map/index.tsx +++ b/src/pages/map/index.tsx @@ -19,9 +19,13 @@ const serverPath = [ links: ['/'], }, { - path: 'ai-chat', + path: 'prompt', links: ['/'], }, + { + path: 'agent', + links: ['edit/list'], + }, ]; const ServerPath = () => { const navigate = useNavigate(); @@ -41,6 +45,11 @@ const ServerPath = () => { if (hasId) { return; } + console.log('link', link); + if (link === '/') { + navigate(`/${item.path}`); + return; + } if (link) { navigate(`/${item.path}/${link}`); } else { diff --git a/src/pages/panel/deck/Model.tsx b/src/pages/panel/deck/Model.tsx new file mode 100644 index 0000000..65b863e --- /dev/null +++ b/src/pages/panel/deck/Model.tsx @@ -0,0 +1,127 @@ +import { isObjectNull } from '@/utils/is-null'; +import { Button, Form, Input, message, Modal, Select } from 'antd'; +import { useEffect, useState } from 'react'; +import { useShallow } from 'zustand/react/shallow'; +import { useDeckPageStore } from './deck-store'; +export const FormModal = () => { + const [form] = Form.useForm(); + const [options, setOptions] = useState<{ label: string; value: any }[]>([]); + const deckPageStore = useDeckPageStore( + useShallow((state) => { + return { + showEdit: state.showEdit, + setShowEdit: state.setShowEdit, + pageData: state.pageData, + getPageData: state.getPageData, + formData: state.formData, + setFormData: state.setFormData, + id: state.id, + setSelected: state.setSelected, + getSeleted: state.getSeleted, + }; + }), + ); + useEffect(() => { + if (!deckPageStore.showEdit) return; + const pageData = deckPageStore.getPageData() || []; + const data = pageData.map((item) => { + const { container } = item?.data || {}; + const label = container?.title; + return { + label: label || item.id, + value: item.id, + }; + }); + setOptions(data); + const selected = deckPageStore.getSeleted(); + const { cid } = selected?.data || {}; + if (cid) { + form.setFieldsValue({ cid }); + return; + } + const isNull = isObjectNull(deckPageStore.formData); + if (isNull) { + form.setFieldsValue({}); + form.resetFields(); + } else { + form.setFieldsValue(deckPageStore.formData); + } + }, [deckPageStore.showEdit, deckPageStore.pageData]); + const onFinish = async (values: any) => { + const pageData = deckPageStore.getPageData() || []; + const page = pageData.find((item) => item.id === values.cid); + if (!page) { + message.error('Page not found'); + return; + } + const cid = values.cid; + if (!cid) { + return; + } + const el = document.querySelector(`[data-cid="${values.cid}"]`); + if (el) { + const data = (el as HTMLDivElement).dataset; + const { cid, pid } = data; + document.querySelectorAll('.active').forEach((item) => { + item.classList.remove('active'); + }); + el.classList.add('active'); + // el.scrollIntoView({ behavior: 'smooth', }); + deckPageStore.setSelected({ type: 'active', data: { cid, pid, rid: deckPageStore.id } }); + } + onClose(); + }; + const onClose = () => { + deckPageStore.setShowEdit(false); + deckPageStore.setFormData({}); + form.setFieldsValue({}); + }; + return ( + deckPageStore.setShowEdit(false)} + destroyOnClose + footer={false} + width={800} + onCancel={onClose}> +
+ + +