Compare commits

..

No commits in common. "445ce075d493b4fc1617dc2bd94b0a40e7602697" and "5bdeb180b5b145ab38ff0f7a7cd4781d22f0824b" have entirely different histories.

7 changed files with 112 additions and 42 deletions

View File

@ -0,0 +1,52 @@
<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>

View File

@ -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: Event) => {
const closeSearch = ev => {
if (!showSearchInput.value) return // Already closing
showSearchInput.value = false
const breadcrumb = document.querySelector('.breadcrumb') as HTMLElement
breadcrumb.focus()
updateSearch(ev)
}
const updateSearch = (ev: Event) => {
const q = (ev.target as HTMLInputElement).value
const updateSearch = ev => {
const q = ev.target.value
let p = props.path.join('/')
p = p ? `/${p}` : ''
const url = q ? `${p}//${q}` : (p || '/')
@ -58,9 +58,9 @@ const updateSearch = (ev: Event) => {
if (!props.query && q) router.push(url)
else router.replace(url)
}
const toggleSearchInput = (ev: Event) => {
const toggleSearchInput = () => {
showSearchInput.value = !showSearchInput.value
if (!showSearchInput.value) return closeSearch(ev)
if (!showSearchInput.value) return closeSearch()
nextTick(() => {
const input = search.value
if (input) input.focus()

View File

@ -34,7 +34,7 @@ const op = (op: string, dst?: string) => {
// @ts-ignore
if (dst !== undefined) msg.dst = dst
const control = connect(controlUrl, {
message(ev: MessageEvent) {
message(ev: WebSocmetMessageEvent) {
const res = JSON.parse(ev.data)
if ('error' in res) {
console.error('Control socket error', msg, res.error)

View File

@ -0,0 +1,27 @@
<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>

View File

@ -11,38 +11,29 @@ const props = defineProps({
path: Array<string>
})
type CloudFile = {
file: File
cloudName: string
cloudPos: number
}
function uploadHandler(event: Event) {
event.preventDefault()
event.stopPropagation()
// @ts-ignore
const infiles = Array.from(event.dataTransfer?.files || event.target.files) as File[]
let infiles = Array.from(event.dataTransfer?.files || event.target.files) as File[]
if (!infiles.length) return
const loc = props.path!.join('/')
let files = []
for (const file of infiles) {
files.push({
file,
cloudName: loc + '/' + (file.webkitRelativePath || file.name),
cloudPos: 0,
})
for (const f of infiles) {
f.cloudName = loc + '/' + (f.webkitRelativePath || f.name)
f.cloudPos = 0
}
const dotfiles = files.filter(f => f.cloudName.includes('/.'))
const dotfiles = infiles.filter(f => f.cloudName.includes('/.'))
if (dotfiles.length) {
documentStore.error = "Won't upload dotfiles"
console.log("Dotfiles omitted", dotfiles)
files = files.filter(f => !f.cloudName.includes('/.'))
infiles = infiles.filter(f => !f.cloudName.includes('/.'))
}
if (!files.length) return
files.sort((a, b) => collator.compare(a.cloudName, b.cloudName))
if (!infiles.length) return
infiles.sort((a, b) => collator.compare(a.cloudName, b.cloudName))
// @ts-ignore
upqueue = [...upqueue, ...files]
statsAdd(files)
upqueue = upqueue.concat(infiles)
statsAdd(infiles)
startWorker()
}
@ -58,14 +49,13 @@ const uprogress_init = {
tlast: 0,
statbytes: 0,
statdur: 0,
files: [] as CloudFile[],
files: [],
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)
@ -88,7 +78,7 @@ setInterval(() => {
uprogress.statdur *= .9
}
}, 100)
const statUpdate = ({name, size, start, end}: {name: string, size: number, start: number, end: number}) => {
const statUpdate = ({name, size, start, end}) => {
if (name !== uprogress.filename) return // If stats have been reset
const now = Date.now()
uprogress.uploaded = uprogress.filestart + end
@ -107,7 +97,7 @@ const statNextFile = () => {
const f = uprogress.files.shift()
if (!f) return statReset()
uprogress.filepos = 0
uprogress.filesize = f.file.size
uprogress.filesize = f.size
uprogress.filename = f.cloudName
}
const statReset = () => {
@ -115,14 +105,14 @@ const statReset = () => {
uprogress.t0 = Date.now()
uprogress.tlast = uprogress.t0 + 1
}
const statsAdd = (f: CloudFile[]) => {
const statsAdd = (f: Array<File>) => {
if (uprogress.files.length === 0) statReset()
uprogress.total += f.reduce((a, b) => a + b.file.size, 0)
uprogress.total += f.reduce((a, b) => a + b.size, 0)
uprogress.filecount += f.length
uprogress.files = [...uprogress.files, ...f]
uprogress.files = uprogress.files.concat(f)
statNextFile()
}
let upqueue = [] as CloudFile[]
let upqueue = [] as File[]
// TODO: Rewrite as WebSocket class
const WSCreate = async () => await new Promise<WebSocket>(resolve => {
@ -165,19 +155,17 @@ const worker = async () => {
const ws = await WSCreate()
while (upqueue.length) {
const f = upqueue[0]
if (f.cloudPos === f.file.size) {
if (f.cloudPos === f.size) {
upqueue.shift()
continue
}
const start = f.cloudPos
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)
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)
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()

View File

@ -109,7 +109,7 @@ const handleWatchMessage = (event: MessageEvent) => {
}
}
function handleRootMessage({ root }: { root: FileEntry[] }) {
function handleRootMessage({ root }: { root: DirEntry }) {
const store = useDocumentStore()
console.log('Watch root', root)
store.updateRoot(root)

View File

@ -21,7 +21,9 @@ export const useDocumentStore = defineStore({
state: () => ({
document: [] as Document[],
selected: new Set<FUID>(),
fileExplorer: null as any,
uploadingDocuments: [],
uploadCount: 0 as number,
fileExplorer: null,
error: '' as string,
connected: false,
server: {} as Record<string, any>,
@ -51,6 +53,7 @@ export const useDocumentStore = defineStore({
})
loc.push(name)
}
console.log("Documents", docs)
this.document = docs as Document[]
},
updateModified() {