Compare commits
2 Commits
master
...
dev/zhaoyu
Author | SHA1 | Date | |
---|---|---|---|
|
3ff83f12b4 | ||
|
6f15f82122 |
@ -4,7 +4,7 @@ import {VirtualizerScrollView} from "@fluentui/react-components/unstable";
|
||||
import React from "react";
|
||||
import {useStoreBucket} from "../../store/bucket";
|
||||
import {Bucket} from "../../interfaces/connection";
|
||||
import {useStoreFile} from "../../store/file";
|
||||
import {useStoreFile, useStoreFileFilter} from "../../store/file";
|
||||
import {useStoreConnection} from "../../store/connection";
|
||||
|
||||
const useStyles = makeStyles({
|
||||
@ -35,13 +35,13 @@ const useStyles = makeStyles({
|
||||
export function ListBucketComponent() {
|
||||
|
||||
const styles = useStyles();
|
||||
const {conn_active} = useStoreConnection()
|
||||
const {bucket_set, bucket_list} = useStoreBucket()
|
||||
const {files_get} = useStoreFile()
|
||||
const {filter_set, prefix_set} = useStoreFileFilter()
|
||||
|
||||
async function handleClick(item: Bucket) {
|
||||
bucket_set(item)
|
||||
files_get(conn_active!, item, "")
|
||||
await bucket_set(item)
|
||||
await filter_set('')
|
||||
await prefix_set('')
|
||||
}
|
||||
|
||||
function handleRightClick(e: React.MouseEvent<HTMLDivElement>, item: Bucket) {
|
||||
@ -50,7 +50,7 @@ export function ListBucketComponent() {
|
||||
|
||||
return <MenuList className={styles.container}>
|
||||
<VirtualizerScrollView
|
||||
numItems={bucket_list?bucket_list.length:0}
|
||||
numItems={bucket_list ? bucket_list.length : 0}
|
||||
itemSize={32}
|
||||
container={{role: 'list', style: {maxHeight: 'calc(100vh - 9rem)'}}}
|
||||
>
|
||||
|
@ -90,7 +90,7 @@ const useStyles = makeStyles({
|
||||
export function ConnectionList() {
|
||||
const styles = useStyles()
|
||||
const {dispatchMessage} = useToast();
|
||||
const {conn_list, conn_update} = useStoreConnection();
|
||||
const {conn_get, conn_list, conn_set} = useStoreConnection();
|
||||
const [conn_filter, set_conn_filter] = useState<string>('');
|
||||
const {bucket_get, bucket_set} = useStoreBucket()
|
||||
const [ctx_menu, set_ctx_menu] = useState<{
|
||||
@ -104,6 +104,9 @@ export function ConnectionList() {
|
||||
document.addEventListener("click", (e) => {
|
||||
set_ctx_menu({x: 0, y: 0, display: 'none'});
|
||||
})
|
||||
setTimeout(() => {
|
||||
conn_get().then()
|
||||
}, 1000)
|
||||
return () => {
|
||||
document.removeEventListener("click", (e) => {
|
||||
})
|
||||
@ -113,7 +116,7 @@ export function ConnectionList() {
|
||||
async function handleSelect(item: Connection) {
|
||||
conn_list.map((one: Connection) => {
|
||||
if (item.id === one.id && one.active) {
|
||||
conn_update(one)
|
||||
conn_set(one)
|
||||
bucket_get(one, false)
|
||||
bucket_set(null)
|
||||
}
|
||||
@ -128,9 +131,9 @@ export function ConnectionList() {
|
||||
return
|
||||
}
|
||||
|
||||
conn_update({...item, active: true})
|
||||
await conn_set({...item, active: true})
|
||||
bucket_get(item, true)
|
||||
bucket_set(null)
|
||||
await bucket_set(null)
|
||||
}
|
||||
|
||||
async function handleDisconnect(item: Connection | null) {
|
||||
@ -140,7 +143,7 @@ export function ConnectionList() {
|
||||
dispatchMessage(res.msg, "error")
|
||||
return
|
||||
}
|
||||
conn_update({...item, active: false})
|
||||
await conn_set({...item, active: false})
|
||||
}
|
||||
|
||||
async function handleRightClick(e: React.MouseEvent<HTMLDivElement>, item: Connection) {
|
||||
@ -148,8 +151,8 @@ export function ConnectionList() {
|
||||
set_menu_conn(item)
|
||||
|
||||
const ele = document.querySelector('#list-connection-container')
|
||||
const eleX = ele ? ele.clientWidth : 0
|
||||
const eleY = ele ? ele.clientHeight : 0
|
||||
const eleX = ele ? ele.clientWidth : 0;
|
||||
const eleY = ele ? ele.clientHeight : 0;
|
||||
const positionX = (e.pageX + eleX > window.innerWidth) ? e.pageX - eleX : e.pageX
|
||||
const positionY = (e.pageY + eleY > window.innerHeight) ? e.pageY - eleY : e.pageY
|
||||
|
||||
|
@ -69,7 +69,7 @@ export function ConnectionCreate(props: ConnectionCreateProps) {
|
||||
dispatchMessage(res.msg, res.status === 200 ? "success" : "error");
|
||||
if (res.status === 200) {
|
||||
dispatchMessage("新建连接成功", "success");
|
||||
conn_get()
|
||||
await conn_get()
|
||||
props.openFn(false)
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,8 @@ import {ListBucketComponent} from "../bucket/list_bucket";
|
||||
import {makeStyles} from "@fluentui/react-components";
|
||||
import {useStoreBucket} from "../../store/bucket";
|
||||
import {ListFileComponent} from "./list_file";
|
||||
import {useState} from "react";
|
||||
import {PreviewFile} from "../preview/preview";
|
||||
|
||||
const useStyles = makeStyles({
|
||||
content: {
|
||||
@ -17,13 +19,17 @@ const useStyles = makeStyles({
|
||||
export function Content() {
|
||||
|
||||
const styles = useStyles()
|
||||
const {bucket_active } = useStoreBucket()
|
||||
const [preview, set_preview] = useState<{ url: string, content_type: string }>({url: '', content_type: ''})
|
||||
const {bucket_active} = useStoreBucket()
|
||||
|
||||
return <div className={styles.content}>
|
||||
<Path/>
|
||||
{
|
||||
bucket_active ?
|
||||
<ListFileComponent/> :
|
||||
<ListBucketComponent/>
|
||||
preview.url ? <PreviewFile url={preview.url} content_type={preview.content_type}/> :
|
||||
(
|
||||
bucket_active ?
|
||||
<ListFileComponent set_preview_fn={set_preview}/> : <ListBucketComponent/>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
import {makeStyles, MenuItem, MenuList, Text, tokens} from "@fluentui/react-components";
|
||||
import {makeStyles, MenuItem, MenuList, Spinner, Text, tokens} from "@fluentui/react-components";
|
||||
import {
|
||||
ArrowDownloadFilled,
|
||||
DeleteRegular,
|
||||
@ -18,18 +18,45 @@ import {VirtualizerScrollView} from "@fluentui/react-components/unstable";
|
||||
import React, {useEffect, useState} from "react";
|
||||
import {useStoreBucket} from "../../store/bucket";
|
||||
import {S3File} from "../../interfaces/connection";
|
||||
import {useStoreFile} from "../../store/file";
|
||||
import {useStoreFile, useStoreFileFilter} from "../../store/file";
|
||||
import {useStoreConnection} from "../../store/connection";
|
||||
import {TrimSuffix} from "../../hook/strings";
|
||||
import {Dial} from "../../api";
|
||||
import {useToast} from "../../message";
|
||||
import {CanPreview} from "../../hook/preview";
|
||||
import {useStorePreview} from "../../store/preview";
|
||||
|
||||
const useStyles = makeStyles({
|
||||
container: {
|
||||
marginTop: '0.5rem',
|
||||
maxWidth: 'calc(100vw - 25rem - 1px)',
|
||||
width: 'calc(100vw - 25rem - 1px)',
|
||||
height: 'calc(100vh - 9rem)',
|
||||
maxWidth: 'calc(100vw - 25.2rem)',
|
||||
width: 'calc(100vw - 25.2rem)',
|
||||
maxHeight: 'calc(100vh - 10rem)',
|
||||
height: 'calc(100vh - 10rem)',
|
||||
},
|
||||
loading: {
|
||||
flex: "1",
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
flexDirection: 'column',
|
||||
},
|
||||
no_data: {
|
||||
flex: "1",
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
fontSize: '8rem',
|
||||
flexDirection: 'column',
|
||||
},
|
||||
list: {
|
||||
flex: "1",
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
},
|
||||
row: {
|
||||
height: '32px',
|
||||
@ -49,16 +76,6 @@ const useStyles = makeStyles({
|
||||
width: 'calc(100vw - 32rem)',
|
||||
display: "block",
|
||||
},
|
||||
no_data: {
|
||||
flex: "1",
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
fontSize: '8rem',
|
||||
flexDirection: 'column',
|
||||
},
|
||||
ctx_menu: {
|
||||
position: "absolute",
|
||||
zIndex: "1000",
|
||||
@ -70,18 +87,27 @@ const useStyles = makeStyles({
|
||||
},
|
||||
})
|
||||
|
||||
export function ListFileComponent() {
|
||||
|
||||
export interface ListFileComponentProps {
|
||||
set_preview_fn: React.Dispatch<React.SetStateAction<{url:string, content_type: string}>>
|
||||
}
|
||||
|
||||
export function ListFileComponent(props: ListFileComponentProps) {
|
||||
|
||||
const styles = useStyles();
|
||||
const {dispatchMessage} = useToast();
|
||||
const {conn_active} = useStoreConnection();
|
||||
const {bucket_active} = useStoreBucket()
|
||||
const {file_active, files_get, file_set, files_list} = useStoreFile()
|
||||
const {prefix, filter, prefix_set} = useStoreFileFilter()
|
||||
const [preview_content_type, set_preview_content_type] = useState('')
|
||||
const {preview_get} = useStorePreview()
|
||||
const [ctx_menu, set_ctx_menu] = useState<{
|
||||
x: number,
|
||||
y: number,
|
||||
display: 'none' | 'block'
|
||||
}>({x: 0, y: 0, display: 'none'});
|
||||
const [loading, set_loading] = useState(true)
|
||||
|
||||
useEffect(() => {
|
||||
document.addEventListener("click", (e) => {
|
||||
@ -93,6 +119,13 @@ export function ListFileComponent() {
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
set_loading(true)
|
||||
files_get(conn_active!, bucket_active!, prefix, filter).then(() => {
|
||||
set_loading(false)
|
||||
})
|
||||
}, [conn_active, bucket_active, prefix, filter]);
|
||||
|
||||
const filename = (key: string) => {
|
||||
let strs = TrimSuffix(key, "/").split("/")
|
||||
return strs[strs.length - 1]
|
||||
@ -100,7 +133,7 @@ export function ListFileComponent() {
|
||||
|
||||
async function handleClick(item: S3File) {
|
||||
if (item.type === 1) {
|
||||
files_get(conn_active!, bucket_active!, item.key)
|
||||
await prefix_set(item.key)
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -108,9 +141,10 @@ export function ListFileComponent() {
|
||||
async function handleRightClick(e: React.MouseEvent<HTMLDivElement>, item: S3File) {
|
||||
e.preventDefault()
|
||||
await file_set(item.key)
|
||||
set_preview_content_type(CanPreview(item.name))
|
||||
const ele = document.querySelector('#list-file-container')
|
||||
const eleX = ele ? ele.clientWidth : 0
|
||||
const eleY = ele ? ele.clientHeight : 0
|
||||
let eleX = ele ? ele.clientWidth : 0
|
||||
let eleY = ele ? ele.clientHeight : 0
|
||||
const positionX = (e.pageX + eleX > window.innerWidth) ? e.pageX - eleX : e.pageX
|
||||
const positionY = (e.pageY + eleY > window.innerHeight) ? e.pageY - eleY : e.pageY
|
||||
set_ctx_menu({
|
||||
@ -118,12 +152,11 @@ export function ListFileComponent() {
|
||||
y: positionY,
|
||||
display: 'block',
|
||||
})
|
||||
// const res = await Dial('/api/file/info', {conn_id: conn_active?.id, bucket: bucket_active?.name, key: item.key})
|
||||
}
|
||||
|
||||
async function handleDownload(file: string | null) {
|
||||
if (!file) return
|
||||
const res1 = await Dial<{result:string}>("/runtime/dialog/save", {
|
||||
const res1 = await Dial<{ result: string }>("/runtime/dialog/save", {
|
||||
default_filename: file,
|
||||
})
|
||||
if (res1.status !== 200) {
|
||||
@ -141,7 +174,20 @@ export function ListFileComponent() {
|
||||
}
|
||||
}
|
||||
|
||||
return <>
|
||||
async function handlePreview() {
|
||||
const res = await Dial<{url:string, method: string}>('/api/file/get', {
|
||||
conn_id: conn_active?.id,
|
||||
bucket: bucket_active?.name,
|
||||
key: file_active ?? "",
|
||||
})
|
||||
if (res.status !== 200) {
|
||||
dispatchMessage('预览失败', 'warning')
|
||||
return
|
||||
}
|
||||
props.set_preview_fn({url: res.data.url, content_type: preview_content_type})
|
||||
}
|
||||
|
||||
return <div className={styles.container}>
|
||||
<div
|
||||
id={'list-file-container'}
|
||||
className={styles.ctx_menu}
|
||||
@ -154,50 +200,52 @@ export function ListFileComponent() {
|
||||
}}
|
||||
icon={<ArrowDownloadFilled/>}>下载</MenuItem>
|
||||
<MenuItem
|
||||
disabled
|
||||
disabled={!preview_content_type}
|
||||
onClick={async () => {
|
||||
// await handleDisconnect(menu_conn)
|
||||
await handlePreview()
|
||||
}}
|
||||
icon={<PreviewLinkRegular/>}>预览</MenuItem>
|
||||
<MenuItem icon={<DeleteRegular/>}>删除</MenuItem>
|
||||
</MenuList>
|
||||
</div>
|
||||
<MenuList className={styles.container}>
|
||||
{files_list.length ?
|
||||
<VirtualizerScrollView
|
||||
numItems={files_list.length}
|
||||
itemSize={32}
|
||||
container={{role: 'list', style: {maxHeight: 'calc(100vh - 9rem)'}}}
|
||||
>
|
||||
{(idx) => {
|
||||
return <div
|
||||
className={styles.row} key={idx}
|
||||
onClick={async () => {
|
||||
await handleClick(files_list[idx])
|
||||
}}
|
||||
onContextMenu={async (e) => {
|
||||
await handleRightClick(e, files_list[idx])
|
||||
}}>
|
||||
<MenuItem className={styles.item}
|
||||
icon={files_list[idx].type ? <FolderRegular/> :
|
||||
<FileIcon name={files_list[idx].name}/>}>
|
||||
<Text truncate wrap={false} className={styles.text}>
|
||||
{filename(files_list[idx].key)}
|
||||
</Text>
|
||||
</MenuItem>
|
||||
</div>
|
||||
}}
|
||||
</VirtualizerScrollView> : <div className={styles.no_data}>
|
||||
<div>
|
||||
<DocumentDismissRegular/>
|
||||
<div className={styles.loading} style={{display: loading ? 'flex' : 'none'}}>
|
||||
<Spinner appearance="primary" label="加载中..."/>
|
||||
</div>
|
||||
<div className={styles.no_data} style={{display: (!loading && !files_list.length) ? 'flex' : 'none'}}>
|
||||
<div>
|
||||
<DocumentDismissRegular/>
|
||||
</div>
|
||||
<Text size={900}>
|
||||
没有文件
|
||||
</Text>
|
||||
</div>
|
||||
<div style={{display: (!loading && files_list.length) ? 'block' : 'none'}}>
|
||||
<VirtualizerScrollView
|
||||
numItems={files_list.length}
|
||||
itemSize={32}
|
||||
container={{role: 'list', style: {maxHeight: 'calc(100vh - 9rem)'}}}
|
||||
>
|
||||
{(idx) => {
|
||||
return <div
|
||||
className={styles.row} key={idx}
|
||||
onClick={async () => {
|
||||
await handleClick(files_list[idx])
|
||||
}}
|
||||
onContextMenu={async (e) => {
|
||||
await handleRightClick(e, files_list[idx])
|
||||
}}>
|
||||
<MenuItem className={styles.item}
|
||||
icon={files_list[idx].type ? <FolderRegular/> :
|
||||
<FileIcon name={files_list[idx].name}/>}>
|
||||
<Text truncate wrap={false} className={styles.text}>
|
||||
{filename(files_list[idx].key)}
|
||||
</Text>
|
||||
</MenuItem>
|
||||
</div>
|
||||
<Text size={900}>
|
||||
没有文件
|
||||
</Text>
|
||||
</div>
|
||||
}
|
||||
</MenuList>
|
||||
</>
|
||||
}}
|
||||
</VirtualizerScrollView>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
type FileIconProps = {
|
||||
|
@ -1,10 +1,12 @@
|
||||
import {Button, Input, makeStyles, Text, tokens, Tooltip} from "@fluentui/react-components";
|
||||
import {useStoreBucket} from "../../store/bucket";
|
||||
import {ArchiveRegular, ArrowCurveUpLeftFilled} from "@fluentui/react-icons";
|
||||
import {useStoreFile} from "../../store/file";
|
||||
import React from "react";
|
||||
import {useStoreFile, useStoreFileFilter} from "../../store/file";
|
||||
import React, {useState} from "react";
|
||||
import {debounce} from 'lodash'
|
||||
import {useStoreConnection} from "../../store/connection";
|
||||
import {ListFileComponent} from "./list_file";
|
||||
import {ListBucketComponent} from "../bucket/list_bucket";
|
||||
|
||||
const useStyles = makeStyles({
|
||||
container: {
|
||||
@ -51,17 +53,18 @@ const useStyles = makeStyles({
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
export function Path() {
|
||||
const styles = useStyles()
|
||||
const {conn_active} = useStoreConnection()
|
||||
const {bucket_active, bucket_get, bucket_set} = useStoreBucket()
|
||||
const {prefix, files_get} = useStoreFile()
|
||||
const {prefix, filter, prefix_set, filter_set} = useStoreFileFilter()
|
||||
|
||||
async function handleClickUp() {
|
||||
const dirs = prefix.split('/').filter((item => item))
|
||||
if (dirs.length > 0) {
|
||||
dirs.pop()
|
||||
files_get(conn_active!, bucket_active!, dirs.join("/"))
|
||||
await prefix_set(dirs.join('/'))
|
||||
return
|
||||
}
|
||||
|
||||
@ -70,8 +73,8 @@ export function Path() {
|
||||
}
|
||||
|
||||
|
||||
const handleFilterChange = debounce((e) => {
|
||||
files_get(conn_active!, bucket_active!, prefix, e.target.value)
|
||||
const handleFilterChange = debounce(async (e) => {
|
||||
await filter_set(e.target.value)
|
||||
}, 500)
|
||||
|
||||
return <div className={styles.container}>
|
||||
|
@ -12,7 +12,7 @@ import {useToast} from "../../message";
|
||||
import {Dial} from "../../api";
|
||||
import {useStoreConnection} from "../../store/connection";
|
||||
import {useStoreBucket} from "../../store/bucket";
|
||||
import {useStoreFile} from "../../store/file";
|
||||
import {useStoreFile, useStoreFileFilter} from "../../store/file";
|
||||
import {MoreHorizontalRegular} from "@fluentui/react-icons";
|
||||
|
||||
const useStyle = makeStyles({
|
||||
@ -43,7 +43,8 @@ export function UploadFiles(props: UploadFilesProps) {
|
||||
|
||||
const { conn_active} = useStoreConnection();
|
||||
const {bucket_active} = useStoreBucket();
|
||||
const {prefix, files_get} = useStoreFile()
|
||||
const {files_get} = useStoreFile()
|
||||
const {prefix } = useStoreFileFilter()
|
||||
|
||||
const [selected, set_selected] = useState<string[]>([]);
|
||||
|
||||
|
@ -1,11 +1,4 @@
|
||||
import {Button, Input, makeStyles, MenuItem, MenuList, mergeClasses, tokens, Tooltip} from "@fluentui/react-components";
|
||||
import {DismissRegular} from "@fluentui/react-icons";
|
||||
import {useEffect, useState} from "react";
|
||||
import {Connection} from "../../interfaces/connection";
|
||||
import {useStoreBucket} from "../../store/bucket";
|
||||
import {useStoreConnection} from "../../store/connection";
|
||||
import {Dial} from "../../api";
|
||||
import {useToast} from "../../message";
|
||||
import {makeStyles} from "@fluentui/react-components";
|
||||
import {ConnectionList} from "../connection/list";
|
||||
import {Content} from "../file/content";
|
||||
|
||||
@ -20,15 +13,9 @@ const useStyles = makeStyles({
|
||||
|
||||
export function Body() {
|
||||
const styles = useStyles();
|
||||
const {conn_get} = useStoreConnection();
|
||||
|
||||
useEffect(() => {
|
||||
conn_get()
|
||||
}, []);
|
||||
|
||||
|
||||
return <div className={styles.body}>
|
||||
<ConnectionList/>
|
||||
<Content />
|
||||
<Content/>
|
||||
</div>
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
import {Button, Dialog, DialogTrigger, makeStyles} from "@fluentui/react-components";
|
||||
import {Button, Dialog, DialogTrigger, makeStyles} from "@fluentui/react-components";
|
||||
import {ConnectionCreate} from "../connection/new";
|
||||
import {AppsAddInRegular, DocumentArrowUpRegular, PlugConnectedAddRegular} from "@fluentui/react-icons";
|
||||
import {AppsAddInRegular, DocumentArrowUpRegular, PlugConnectedAddRegular} from "@fluentui/react-icons";
|
||||
import {useState} from "react";
|
||||
import {useStoreConnection} from "../../store/connection";
|
||||
import {BucketCreate} from "../bucket/new";
|
||||
@ -10,6 +10,7 @@ import {UploadFiles} from "../file/upload_files";
|
||||
const useStyles = makeStyles({
|
||||
header: {
|
||||
height: "5rem",
|
||||
minHeight: '5rem',
|
||||
width: "100%",
|
||||
display: 'flex',
|
||||
alignItems: "center",
|
||||
@ -64,7 +65,7 @@ export function Header() {
|
||||
open={open_upload}
|
||||
onOpenChange={(event, data) => set_open_upload(data.open)}>
|
||||
<DialogTrigger disableButtonEnhancement>
|
||||
<Button appearance="primary" icon={<DocumentArrowUpRegular />}>
|
||||
<Button appearance="primary" icon={<DocumentArrowUpRegular/>}>
|
||||
上传
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
|
@ -1,3 +1,21 @@
|
||||
export function PreviewFile() {
|
||||
import {CardPreview, makeStyles} from "@fluentui/react-components";
|
||||
|
||||
const useStyle = makeStyles({
|
||||
container: {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
}
|
||||
})
|
||||
export function PreviewFile(props: {url:string, content_type:string}) {
|
||||
const styles = useStyle()
|
||||
return <div className={styles.container}>
|
||||
<CardPreview
|
||||
>
|
||||
<img src={props.url} />
|
||||
</CardPreview>
|
||||
</div>
|
||||
}
|
13
frontend/src/hook/preview.ts
Normal file
13
frontend/src/hook/preview.ts
Normal file
@ -0,0 +1,13 @@
|
||||
export function CanPreview(filename: string) {
|
||||
const fs = filename.split(".")
|
||||
switch (fs[fs.length - 1]) {
|
||||
case "jpg":
|
||||
return "image/jpg"
|
||||
case "jpeg":
|
||||
return "image/jpg"
|
||||
case "png":
|
||||
return "image/png"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
@ -5,8 +5,8 @@ import {Dial} from "../api";
|
||||
interface StoreConnection {
|
||||
conn_active: Connection | null;
|
||||
conn_list: Connection[];
|
||||
conn_get: () => void;
|
||||
conn_update: (connection: Connection) => Promise<void>;
|
||||
conn_get: () => Promise<void>;
|
||||
conn_set: (connection: Connection) => Promise<void>;
|
||||
}
|
||||
|
||||
export const useStoreConnection = create<StoreConnection>()((set) => ({
|
||||
@ -21,7 +21,7 @@ export const useStoreConnection = create<StoreConnection>()((set) => ({
|
||||
set({conn_list: res.data.list})
|
||||
},
|
||||
|
||||
conn_update: async (connection: Connection) => {
|
||||
conn_set: async (connection: Connection) => {
|
||||
set((state) => {
|
||||
return {
|
||||
conn_active: connection.active? connection: null,
|
||||
|
@ -5,10 +5,8 @@ import {Dial} from "../api";
|
||||
interface StoreFile {
|
||||
file_active: string | null,
|
||||
file_set: (key: string) => Promise<void>,
|
||||
prefix: string;
|
||||
filter: string;
|
||||
files_list: S3File[];
|
||||
files_get: (conn: Connection, bucket: Bucket, prefix?: string, filter?: string) => void;
|
||||
files_get: (conn: Connection, bucket: Bucket, prefix?: string, filter?: string) => Promise<void>;
|
||||
}
|
||||
|
||||
export const useStoreFile = create<StoreFile>()((set) => ({
|
||||
@ -18,8 +16,6 @@ export const useStoreFile = create<StoreFile>()((set) => ({
|
||||
return {file_active: key}
|
||||
})
|
||||
},
|
||||
prefix: "",
|
||||
filter: "",
|
||||
files_list: [],
|
||||
files_get: async (conn: Connection, bucket: Bucket, prefix = '', filter = '') => {
|
||||
const res = await Dial<{ list: S3File[] }>('/api/bucket/files', {
|
||||
@ -33,7 +29,25 @@ export const useStoreFile = create<StoreFile>()((set) => ({
|
||||
}
|
||||
|
||||
set((state) => {
|
||||
return {files_list: res.data.list, prefix: prefix, filter: filter}
|
||||
return {files_list: res.data.list}
|
||||
})
|
||||
}
|
||||
},
|
||||
}))
|
||||
|
||||
interface StoreFileFilter {
|
||||
prefix: string;
|
||||
filter: string;
|
||||
prefix_set: (prefix: string) => Promise<void>;
|
||||
filter_set: (filter: string) => Promise<void>;
|
||||
}
|
||||
|
||||
export const useStoreFileFilter = create<StoreFileFilter>()((set) => ({
|
||||
prefix: '',
|
||||
filter: '',
|
||||
prefix_set: async (keyword: string) => {
|
||||
set(state => {return {prefix: keyword}})
|
||||
},
|
||||
filter_set: async (keyword: string) => {
|
||||
set(state => {return {filter: keyword}})
|
||||
},
|
||||
}))
|
@ -1,18 +1,33 @@
|
||||
import {create} from 'zustand'
|
||||
import {Dial} from "../api";
|
||||
import {Bucket, Connection} from "../interfaces/connection";
|
||||
|
||||
interface StorePreview {
|
||||
preview_key: string;
|
||||
preview_url: string;
|
||||
preview_content_type: string;
|
||||
preview_set: (key: string) => void;
|
||||
preview_get: (conn:Connection,bucket: Bucket,key: string) => Promise<void>;
|
||||
}
|
||||
|
||||
export const useStorePreview = create<StorePreview>()((set) => ({
|
||||
preview_key: '',
|
||||
preview_url: '',
|
||||
preview_content_type: '',
|
||||
preview_set: async (key: string) => set(state => {
|
||||
return {preview_key: key}
|
||||
}),
|
||||
preview_get: async (conn: Connection, bucket: Bucket,key: string) => {
|
||||
if (key === '') {
|
||||
return set(()=>{return {preview_url: ''}})
|
||||
}
|
||||
|
||||
let res = await Dial<{url:string,method:string}>('/api/file/get', {
|
||||
conn_id: conn.id,
|
||||
bucket: bucket.name,
|
||||
key: key
|
||||
})
|
||||
|
||||
if(res.status!=200) {
|
||||
return set(()=>{return {preview_url: ''}})
|
||||
}
|
||||
|
||||
set(()=>{
|
||||
return {preview_url:res.data.url}
|
||||
})
|
||||
},
|
||||
}))
|
||||
|
@ -8,7 +8,6 @@ import (
|
||||
"github.com/loveuer/nf-disk/internal/s3"
|
||||
"github.com/loveuer/nf-disk/ndh"
|
||||
"github.com/samber/lo"
|
||||
"time"
|
||||
)
|
||||
|
||||
func ConnectionTest(c *ndh.Ctx) error {
|
||||
@ -210,11 +209,5 @@ func ConnectionBuckets(c *ndh.Ctx) error {
|
||||
return c.Send500(err.Error())
|
||||
}
|
||||
|
||||
// todo: for frontend test
|
||||
buckets = append(buckets, &s3.ListBucketRes{
|
||||
Name: "这是一个非常长非常长非常长非常长非常长非常长非常长非常长非常长非常长非常长非常长非常长非常长非常长非常长非常长非常长非常长非常长非常长非常长非常长非常长非常长非常长非常长非常长的名字",
|
||||
CreatedAt: time.Now().UnixMilli(),
|
||||
})
|
||||
|
||||
return c.Send200(map[string]any{"list": buckets})
|
||||
}
|
||||
|
@ -12,10 +12,10 @@ import (
|
||||
)
|
||||
|
||||
type ObjectInfo struct {
|
||||
Bucket string
|
||||
Key string
|
||||
ContentType string
|
||||
Expire int64
|
||||
Bucket string `json:"bucket"`
|
||||
Key string `json:"key"`
|
||||
ContentType string `json:"content_type"`
|
||||
Expire int64 `json:"expire"`
|
||||
}
|
||||
|
||||
func (c *Client) GetObjectInfo(ctx context.Context, bucket string, key string) (*ObjectInfo, error) {
|
||||
@ -62,9 +62,9 @@ func (presigner *Presigner) GetObject(ctx context.Context, bucketName string, ob
|
||||
}
|
||||
|
||||
type ObjectEntry struct {
|
||||
URL string
|
||||
Method string
|
||||
Header http.Header
|
||||
URL string `json:"url"`
|
||||
Method string `json:"method"`
|
||||
Header http.Header `json:"header"`
|
||||
}
|
||||
|
||||
func (c *Client) GetObjectEntry(ctx context.Context, bucket string, key string, lifetimes ...int64) (*ObjectEntry, error) {
|
||||
@ -92,7 +92,7 @@ func (c *Client) GetObjectEntry(ctx context.Context, bucket string, key string,
|
||||
|
||||
type ObjectEntity struct {
|
||||
ObjectInfo
|
||||
Body io.ReadCloser
|
||||
Body io.ReadCloser `json:"body"`
|
||||
}
|
||||
|
||||
func (c *Client) GetObject(ctx context.Context, bucket string, key string) (*ObjectEntity, error) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user