Compare commits
2 Commits
5bdeb180b5
...
445ce075d4
Author | SHA1 | Date | |
---|---|---|---|
445ce075d4 | |||
c2b9ef6c2f |
@ -1,52 +0,0 @@
|
||||
<template>
|
||||
<object
|
||||
v-if="props.type === 'pdf'"
|
||||
:data="dataURL"
|
||||
type="application/pdf"
|
||||
width="100%"
|
||||
height="100%"
|
||||
></object>
|
||||
<a-image
|
||||
v-else-if="props.type === 'image'"
|
||||
width="50%"
|
||||
:src="dataURL"
|
||||
@click="() => setVisible(true)"
|
||||
:previewMask="false"
|
||||
:preview="{
|
||||
visibleImg,
|
||||
onVisibleChange: setVisible
|
||||
}"
|
||||
/>
|
||||
<!-- Unknown case -->
|
||||
<h1 v-else>Unsupported file type</h1>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { watchEffect, ref } from 'vue'
|
||||
import Router from '@/router/index'
|
||||
import { url_document_get } from '@/repositories/Document'
|
||||
|
||||
const dataURL = ref('')
|
||||
watchEffect(() => {
|
||||
dataURL.value = new URL(
|
||||
url_document_get + Router.currentRoute.value.path,
|
||||
location.origin
|
||||
).toString()
|
||||
})
|
||||
const emit = defineEmits({
|
||||
visibleImg(value: boolean) {
|
||||
return value
|
||||
}
|
||||
})
|
||||
|
||||
function setVisible(value: boolean) {
|
||||
emit('visibleImg', value)
|
||||
}
|
||||
|
||||
const props = defineProps<{
|
||||
type?: string
|
||||
visibleImg: boolean
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<style></style>
|
@ -9,7 +9,7 @@
|
||||
<SvgButton
|
||||
name="create-folder"
|
||||
data-tooltip="New folder"
|
||||
@click="() => documentStore.fileExplorer.newFolder()"
|
||||
@click="() => documentStore.fileExplorer!.newFolder()"
|
||||
/>
|
||||
<slot></slot>
|
||||
<div class="spacer smallgap"></div>
|
||||
@ -42,15 +42,15 @@ const showSearchInput = ref<boolean>(false)
|
||||
const search = ref<HTMLInputElement | null>()
|
||||
const searchButton = ref<HTMLButtonElement | null>()
|
||||
|
||||
const closeSearch = ev => {
|
||||
const closeSearch = (ev: Event) => {
|
||||
if (!showSearchInput.value) return // Already closing
|
||||
showSearchInput.value = false
|
||||
const breadcrumb = document.querySelector('.breadcrumb') as HTMLElement
|
||||
breadcrumb.focus()
|
||||
updateSearch(ev)
|
||||
}
|
||||
const updateSearch = ev => {
|
||||
const q = ev.target.value
|
||||
const updateSearch = (ev: Event) => {
|
||||
const q = (ev.target as HTMLInputElement).value
|
||||
let p = props.path.join('/')
|
||||
p = p ? `/${p}` : ''
|
||||
const url = q ? `${p}//${q}` : (p || '/')
|
||||
@ -58,9 +58,9 @@ const updateSearch = ev => {
|
||||
if (!props.query && q) router.push(url)
|
||||
else router.replace(url)
|
||||
}
|
||||
const toggleSearchInput = () => {
|
||||
const toggleSearchInput = (ev: Event) => {
|
||||
showSearchInput.value = !showSearchInput.value
|
||||
if (!showSearchInput.value) return closeSearch()
|
||||
if (!showSearchInput.value) return closeSearch(ev)
|
||||
nextTick(() => {
|
||||
const input = search.value
|
||||
if (input) input.focus()
|
||||
|
@ -34,7 +34,7 @@ const op = (op: string, dst?: string) => {
|
||||
// @ts-ignore
|
||||
if (dst !== undefined) msg.dst = dst
|
||||
const control = connect(controlUrl, {
|
||||
message(ev: WebSocmetMessageEvent) {
|
||||
message(ev: MessageEvent) {
|
||||
const res = JSON.parse(ev.data)
|
||||
if ('error' in res) {
|
||||
console.error('Control socket error', msg, res.error)
|
||||
|
@ -1,27 +0,0 @@
|
||||
<template>
|
||||
<template v-for="upload in documentStore.uploadingDocuments" :key="upload.key">
|
||||
<span>{{ upload.name }}</span>
|
||||
<div class="progress-container">
|
||||
<a-progress :percent="upload.progress" />
|
||||
<CloseCircleOutlined class="close-button" @click="dismissUpload(upload.key)" />
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { useDocumentStore } from '@/stores/documents'
|
||||
const documentStore = useDocumentStore()
|
||||
|
||||
function dismissUpload(key: number) {
|
||||
documentStore.deleteUploadingDocument(key)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.progress-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.close-button:hover {
|
||||
color: #b81414;
|
||||
}
|
||||
</style>
|
@ -11,29 +11,38 @@ const props = defineProps({
|
||||
path: Array<string>
|
||||
})
|
||||
|
||||
type CloudFile = {
|
||||
file: File
|
||||
cloudName: string
|
||||
cloudPos: number
|
||||
}
|
||||
|
||||
function uploadHandler(event: Event) {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
// @ts-ignore
|
||||
let infiles = Array.from(event.dataTransfer?.files || event.target.files) as File[]
|
||||
const infiles = Array.from(event.dataTransfer?.files || event.target.files) as File[]
|
||||
if (!infiles.length) return
|
||||
const loc = props.path!.join('/')
|
||||
for (const f of infiles) {
|
||||
f.cloudName = loc + '/' + (f.webkitRelativePath || f.name)
|
||||
f.cloudPos = 0
|
||||
let files = []
|
||||
for (const file of infiles) {
|
||||
files.push({
|
||||
file,
|
||||
cloudName: loc + '/' + (file.webkitRelativePath || file.name),
|
||||
cloudPos: 0,
|
||||
})
|
||||
}
|
||||
const dotfiles = infiles.filter(f => f.cloudName.includes('/.'))
|
||||
const dotfiles = files.filter(f => f.cloudName.includes('/.'))
|
||||
if (dotfiles.length) {
|
||||
documentStore.error = "Won't upload dotfiles"
|
||||
console.log("Dotfiles omitted", dotfiles)
|
||||
infiles = infiles.filter(f => !f.cloudName.includes('/.'))
|
||||
files = files.filter(f => !f.cloudName.includes('/.'))
|
||||
}
|
||||
if (!infiles.length) return
|
||||
infiles.sort((a, b) => collator.compare(a.cloudName, b.cloudName))
|
||||
if (!files.length) return
|
||||
files.sort((a, b) => collator.compare(a.cloudName, b.cloudName))
|
||||
// @ts-ignore
|
||||
upqueue = upqueue.concat(infiles)
|
||||
statsAdd(infiles)
|
||||
upqueue = [...upqueue, ...files]
|
||||
statsAdd(files)
|
||||
startWorker()
|
||||
}
|
||||
|
||||
@ -49,13 +58,14 @@ const uprogress_init = {
|
||||
tlast: 0,
|
||||
statbytes: 0,
|
||||
statdur: 0,
|
||||
files: [],
|
||||
files: [] as CloudFile[],
|
||||
filestart: 0,
|
||||
fileidx: 0,
|
||||
filecount: 0,
|
||||
filename: '',
|
||||
filesize: 0,
|
||||
filepos: 0,
|
||||
status: 'idle',
|
||||
}
|
||||
const uprogress = reactive({...uprogress_init})
|
||||
const percent = computed(() => uprogress.uploaded / uprogress.total * 100)
|
||||
@ -78,7 +88,7 @@ setInterval(() => {
|
||||
uprogress.statdur *= .9
|
||||
}
|
||||
}, 100)
|
||||
const statUpdate = ({name, size, start, end}) => {
|
||||
const statUpdate = ({name, size, start, end}: {name: string, size: number, start: number, end: number}) => {
|
||||
if (name !== uprogress.filename) return // If stats have been reset
|
||||
const now = Date.now()
|
||||
uprogress.uploaded = uprogress.filestart + end
|
||||
@ -97,7 +107,7 @@ const statNextFile = () => {
|
||||
const f = uprogress.files.shift()
|
||||
if (!f) return statReset()
|
||||
uprogress.filepos = 0
|
||||
uprogress.filesize = f.size
|
||||
uprogress.filesize = f.file.size
|
||||
uprogress.filename = f.cloudName
|
||||
}
|
||||
const statReset = () => {
|
||||
@ -105,14 +115,14 @@ const statReset = () => {
|
||||
uprogress.t0 = Date.now()
|
||||
uprogress.tlast = uprogress.t0 + 1
|
||||
}
|
||||
const statsAdd = (f: Array<File>) => {
|
||||
const statsAdd = (f: CloudFile[]) => {
|
||||
if (uprogress.files.length === 0) statReset()
|
||||
uprogress.total += f.reduce((a, b) => a + b.size, 0)
|
||||
uprogress.total += f.reduce((a, b) => a + b.file.size, 0)
|
||||
uprogress.filecount += f.length
|
||||
uprogress.files = uprogress.files.concat(f)
|
||||
uprogress.files = [...uprogress.files, ...f]
|
||||
statNextFile()
|
||||
}
|
||||
let upqueue = [] as File[]
|
||||
let upqueue = [] as CloudFile[]
|
||||
|
||||
// TODO: Rewrite as WebSocket class
|
||||
const WSCreate = async () => await new Promise<WebSocket>(resolve => {
|
||||
@ -155,17 +165,19 @@ const worker = async () => {
|
||||
const ws = await WSCreate()
|
||||
while (upqueue.length) {
|
||||
const f = upqueue[0]
|
||||
if (f.cloudPos === f.size) {
|
||||
if (f.cloudPos === f.file.size) {
|
||||
upqueue.shift()
|
||||
continue
|
||||
}
|
||||
const start = f.cloudPos
|
||||
const end = Math.min(f.size, start + (1<<20))
|
||||
const control = { name: f.cloudName, size: f.size, start, end }
|
||||
const data = f.slice(start, end)
|
||||
const end = Math.min(f.file.size, start + (1<<20))
|
||||
const control = { name: f.cloudName, size: f.file.size, start, end }
|
||||
const data = f.file.slice(start, end)
|
||||
f.cloudPos = end
|
||||
// Note: files may get modified during I/O
|
||||
// @ts-ignore FIXME proper WebSocket class, avoid attaching functions to WebSocket object
|
||||
ws.sendMsg(control)
|
||||
// @ts-ignore
|
||||
await ws.sendData(data)
|
||||
}
|
||||
if (upqueue.length) startWorker()
|
||||
|
@ -109,7 +109,7 @@ const handleWatchMessage = (event: MessageEvent) => {
|
||||
}
|
||||
}
|
||||
|
||||
function handleRootMessage({ root }: { root: DirEntry }) {
|
||||
function handleRootMessage({ root }: { root: FileEntry[] }) {
|
||||
const store = useDocumentStore()
|
||||
console.log('Watch root', root)
|
||||
store.updateRoot(root)
|
||||
|
@ -21,9 +21,7 @@ export const useDocumentStore = defineStore({
|
||||
state: () => ({
|
||||
document: [] as Document[],
|
||||
selected: new Set<FUID>(),
|
||||
uploadingDocuments: [],
|
||||
uploadCount: 0 as number,
|
||||
fileExplorer: null,
|
||||
fileExplorer: null as any,
|
||||
error: '' as string,
|
||||
connected: false,
|
||||
server: {} as Record<string, any>,
|
||||
@ -53,7 +51,6 @@ export const useDocumentStore = defineStore({
|
||||
})
|
||||
loc.push(name)
|
||||
}
|
||||
console.log("Documents", docs)
|
||||
this.document = docs as Document[]
|
||||
},
|
||||
updateModified() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user