226 lines
8.1 KiB
TypeScript
226 lines
8.1 KiB
TypeScript
import { useShallow } from 'zustand/react/shallow';
|
||
import { useUserAppStore } from '../store';
|
||
import { useEffect } from 'react';
|
||
import { Button, Form, Input, Space, Modal, Select, Tooltip, Switch } from 'antd';
|
||
import { CodeOutlined, DeleteOutlined, EditOutlined, LinkOutlined, PlusOutlined, UnorderedListOutlined } from '@ant-design/icons';
|
||
import { isObjectNull } from '@/utils/is-null';
|
||
import { useNewNavigate } from '@/modules';
|
||
import { marked } from 'marked';
|
||
import clsx from 'clsx';
|
||
import { message } from '@/modules/message';
|
||
const FormModal = () => {
|
||
const [form] = Form.useForm();
|
||
const containerStore = useUserAppStore(
|
||
useShallow((state) => {
|
||
return {
|
||
showEdit: state.showEdit,
|
||
setShowEdit: state.setShowEdit,
|
||
formData: state.formData,
|
||
updateData: state.updateData,
|
||
};
|
||
}),
|
||
);
|
||
useEffect(() => {
|
||
const open = containerStore.showEdit;
|
||
if (open) {
|
||
if (open) {
|
||
const isNull = isObjectNull(containerStore.formData);
|
||
if (isNull) {
|
||
form.setFieldsValue({});
|
||
} else form.setFieldsValue(containerStore.formData);
|
||
}
|
||
}
|
||
}, [containerStore.showEdit]);
|
||
const onFinish = async (values: any) => {
|
||
containerStore.updateData(values);
|
||
};
|
||
const onClose = () => {
|
||
containerStore.setShowEdit(false);
|
||
form.resetFields();
|
||
};
|
||
const isEdit = containerStore.formData.id;
|
||
return (
|
||
<Modal
|
||
title={isEdit ? 'Edit' : 'Add'}
|
||
open={containerStore.showEdit}
|
||
onClose={() => containerStore.setShowEdit(false)}
|
||
destroyOnClose
|
||
footer={false}
|
||
width={800}
|
||
onCancel={onClose}>
|
||
<Form
|
||
form={form}
|
||
onFinish={onFinish}
|
||
labelCol={{
|
||
span: 4,
|
||
}}
|
||
wrapperCol={{
|
||
span: 20,
|
||
}}>
|
||
<Form.Item name='id' hidden>
|
||
<Input />
|
||
</Form.Item>
|
||
<Form.Item name='title' label='title'>
|
||
<Input />
|
||
</Form.Item>
|
||
<Form.Item name='domain' label='domain'>
|
||
<Input />
|
||
</Form.Item>
|
||
<Form.Item name='key' label='key'>
|
||
<Input />
|
||
</Form.Item>
|
||
<Form.Item name='description' label='description'>
|
||
<Input.TextArea rows={4} />
|
||
</Form.Item>
|
||
<Form.Item name='proxy' label='proxy' tooltip='静态网站设置,如果是静态网站,不需要重定向到index.html的页面。'>
|
||
<Switch />
|
||
</Form.Item>
|
||
<Form.Item name='status' label='status'>
|
||
<Select
|
||
options={[
|
||
{ label: 'Running', value: 'running' },
|
||
{ label: 'Stop', value: 'stop' },
|
||
]}
|
||
/>
|
||
</Form.Item>
|
||
<Form.Item label=' ' colon={false}>
|
||
<Button type='primary' htmlType='submit'>
|
||
Submit
|
||
</Button>
|
||
<Button className='ml-2' htmlType='reset' onClick={onClose}>
|
||
Cancel
|
||
</Button>
|
||
</Form.Item>
|
||
</Form>
|
||
</Modal>
|
||
);
|
||
};
|
||
|
||
export const List = () => {
|
||
const [modal, contextHolder] = Modal.useModal();
|
||
|
||
const userAppStore = useUserAppStore(
|
||
useShallow((state) => {
|
||
return {
|
||
list: state.list,
|
||
getList: state.getList,
|
||
setShowEdit: state.setShowEdit,
|
||
formData: state.formData,
|
||
setFormData: state.setFormData,
|
||
deleteData: state.deleteData,
|
||
};
|
||
}),
|
||
);
|
||
const navicate = useNewNavigate();
|
||
useEffect(() => {
|
||
userAppStore.getList();
|
||
}, []);
|
||
return (
|
||
<div className='w-full h-full flex bg-slate-100'>
|
||
<div className='p-2 h-full bg-white flex flex-col gap-2'>
|
||
<Button
|
||
onClick={() => {
|
||
userAppStore.setShowEdit(true);
|
||
}}
|
||
icon={<PlusOutlined />}></Button>
|
||
<Tooltip title='To Container'>
|
||
<Button
|
||
onClick={() => {
|
||
navicate('/container');
|
||
}}
|
||
icon={<CodeOutlined />}></Button>
|
||
</Tooltip>
|
||
</div>
|
||
<div className='grow'>
|
||
<div className='w-full h-full p-4'>
|
||
<div className='w-full h-full bg-white rounded-lg p-2 scrollbar '>
|
||
<div className='flex flex-wrap gap-2'>
|
||
{userAppStore.list.map((item) => {
|
||
const isRunning = item.status === 'running';
|
||
const hasDescription = !!item.description;
|
||
const content = marked.parse(item.description);
|
||
return (
|
||
<div className='card border-t border-gray-200 w-[300px] ' key={item.id}>
|
||
<div className='card-title flex justify-between' onClick={() => {}}>
|
||
{item.title}
|
||
<div>
|
||
<div className={`${isRunning ? 'bg-green-500' : 'bg-red-500'} w-4 h-4 rounded-full`}></div>
|
||
</div>
|
||
</div>
|
||
<div>
|
||
<div className='text-xs'>domain: {item.domain}</div>
|
||
<div className='text-xs'>version: {item.version}</div>
|
||
<div className={clsx('text-sm border border-gray-200 p-2 max-h-[140px] scrollbar my-1', !hasDescription && 'hidden')}>
|
||
<div dangerouslySetInnerHTML={{ __html: content }}></div>
|
||
</div>
|
||
</div>
|
||
<div className='mt-2'>
|
||
<Space.Compact>
|
||
<Tooltip title={'Edit'}>
|
||
<Button
|
||
icon={<EditOutlined />}
|
||
onClick={() => {
|
||
userAppStore.setFormData(item);
|
||
userAppStore.setShowEdit(true);
|
||
}}></Button>
|
||
</Tooltip>
|
||
<Tooltip title={'App Version List'}>
|
||
<Button
|
||
icon={<UnorderedListOutlined />}
|
||
onClick={() => {
|
||
navicate(`/app/${item.key}/version/list`);
|
||
}}></Button>
|
||
</Tooltip>
|
||
<Tooltip title={'To App'}>
|
||
<Button
|
||
icon={<LinkOutlined />}
|
||
onClick={() => {
|
||
if (isRunning) {
|
||
let baseUri = location.origin;
|
||
if (item.domain) {
|
||
if (item.domain.startsWith('http://') || item.domain.startsWith('https://')) {
|
||
baseUri = item.domain;
|
||
} else {
|
||
baseUri = new URL(item.domain).origin;
|
||
}
|
||
}
|
||
if (DEV_SERVER) {
|
||
baseUri = 'http://localhost:3005';
|
||
}
|
||
const link = new URL(`/${item.user}/${item.key}`, baseUri);
|
||
window.open(link.toString(), '_blank');
|
||
} else {
|
||
message.error('The app is not running');
|
||
}
|
||
}}></Button>
|
||
</Tooltip>
|
||
<Tooltip title={'Delete'}>
|
||
<Button
|
||
icon={<DeleteOutlined />}
|
||
onClick={(e) => {
|
||
console.log('delete', item);
|
||
modal.confirm({
|
||
title: 'Delete',
|
||
content: 'Are you sure delete this data?',
|
||
onOk: () => {
|
||
userAppStore.deleteData(item.id);
|
||
},
|
||
});
|
||
e.stopPropagation();
|
||
}}></Button>
|
||
</Tooltip>
|
||
</Space.Compact>
|
||
</div>
|
||
</div>
|
||
);
|
||
})}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
{contextHolder}
|
||
<FormModal />
|
||
</div>
|
||
);
|
||
};
|