zhaoyupeng 777253063b feat: 完成了 新建桶; 上传文件(基本功能)
todo: 上传 rename, 上传 public 权限选择
bug: 首次加载 conns list; 上传的时候前缀过滤失败
2024-10-12 17:46:20 +08:00

211 lines
6.9 KiB
TypeScript

import {
Button,
Input,
makeStyles,
MenuItem,
MenuList,
mergeClasses,
tokens,
Tooltip
} from "@fluentui/react-components"
import {DatabaseLinkRegular, DismissRegular} from "@fluentui/react-icons";
import React, { useEffect, useState} from "react";
import { Connection} from "../../interfaces/connection";
import {useToast} from "../../message";
import {Dial} from "../../api";
import {useStoreConnection} from "../../store/connection";
import {useStoreBucket} from "../../store/bucket";
const useStyles = makeStyles({
list: {
display: "flex",
flexDirection: "row",
height: "100%",
},
content: {
height: "100%",
width: "25rem",
display: "flex",
flexDirection: "column",
},
filter: {
height: "4rem",
width: "100%",
display: "flex",
alignItems: "center",
},
filter_input: {
width: "100%",
marginLeft: "0.5rem",
marginRight: "0.5rem",
},
ctx_menu: {
position: "absolute",
zIndex: "1000",
width: "15rem",
backgroundColor: tokens.colorNeutralBackground1,
boxShadow: `${tokens.shadow16}`,
paddingTop: "4px",
paddingBottom: "4px",
},
items: {
height: "100%",
width: "100%",
},
items_one: {
marginLeft: "0.5rem",
marginRight: "0.5rem",
"&:hover": {
color: tokens.colorNeutralForeground2BrandPressed,
},
"&.active": {
color: tokens.colorNeutralForeground2BrandPressed,
fontWeight: "bold",
},
"& > span": {
display: "flex",
},
},
items_disconn: {
marginLeft: "auto",
},
slider: {
height: '100%', width: '1px',
// todo: resize
// cursor: 'ew-resize',
'& > div': {
height: '100%', width: '1px',
backgroundColor: 'lightgray',
},
},
})
export function ConnectionList() {
const styles = useStyles()
const {dispatchMessage} = useToast();
const {conn_list, conn_update} = useStoreConnection();
const [conn_filter, set_conn_filter] = useState<string>('');
const {bucket_get, bucket_set} = useStoreBucket()
const [ctx_menu, set_ctx_menu] = useState<{
x: number,
y: number,
display: 'none' | 'block'
}>({x: 0, y: 0, display: 'none'});
useEffect(() => {
document.addEventListener("click", (e) => {
set_ctx_menu({x: 0, y: 0, display: 'none'});
})
return () => {
document.removeEventListener("click", (e) => {})
}
}, [])
async function handleSelect(item: Connection) {
conn_list.map((one: Connection) => {
if (item.id === one.id && one.active) {
conn_update(one)
bucket_get(one, false)
bucket_set(null)
}
})
}
async function handleConnect(item: Connection) {
let res = await Dial('/api/connection/connect', {id: item.id});
if (res.status !== 200) {
dispatchMessage(res.msg, "error")
return
}
conn_update({...item, active: true})
bucket_get(item, true)
bucket_set(null)
}
async function handleDisconnect(item: Connection) {
let res = await Dial('/api/connection/disconnect', {id: item.id})
if (res.status !== 200) {
dispatchMessage(res.msg, "error")
return
}
conn_update({...item, active: false})
}
async function handleRightClick(e: React.MouseEvent<HTMLDivElement>, item: Connection) {
e.preventDefault()
console.log('[DEBUG] right click connection =', item, 'event =', e)
console.log(`[DEBUG] click position: [${e.pageX}, ${e.pageY}]`)
set_ctx_menu({
x: e.pageX,
y: e.pageY,
display: 'block',
})
}
return (
<div className={styles.list}>
<div className={styles.content}>
<div className={styles.filter}>
<Input
value={conn_filter}
className={styles.filter_input}
contentAfter={
<Button appearance={'transparent'} onClick={async () => {
set_conn_filter('')
}} size="small" icon={<DismissRegular/>}/>
}
placeholder="搜索连接"
onChange={(e) => set_conn_filter(e.target.value)}
/>
</div>
<div className={styles.ctx_menu}
style={{left: ctx_menu.x, top: ctx_menu.y, display: ctx_menu.display}}
>
<MenuList>
<MenuItem></MenuItem>
<MenuItem></MenuItem>
<MenuItem></MenuItem>
</MenuList>
</div>
<div className={styles.items}>
<MenuList>
{conn_list.filter(item => item.name.includes(conn_filter)).map(item => {
return <MenuItem
className={item.active ? mergeClasses(styles.items_one, "active") : styles.items_one}
onClick={async () => {
await handleSelect(item)
}}
onDoubleClick={async () => {
await handleConnect(item)
}}
onContextMenu={async (e) => {
await handleRightClick(e, item)
}}
icon={<DatabaseLinkRegular/>}
key={item.id}>
{item.name}
<Tooltip
content="断开连接"
relationship="label">
<Button
appearance={'transparent'}
size="small"
icon={<DismissRegular/>}
className={styles.items_disconn}
onClick={async () => {
await handleDisconnect(item)
}}/>
</Tooltip>
</MenuItem>
})}
</MenuList>
</div>
</div>
<div className={styles.slider}>
<div></div>
</div>
</div>
)
}