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 <SvgButton
name="create-folder" name="create-folder"
data-tooltip="New folder" data-tooltip="New folder"
@click="() => documentStore.fileExplorer!.newFolder()" @click="() => documentStore.fileExplorer.newFolder()"
/> />
<slot></slot> <slot></slot>
<div class="spacer smallgap"></div> <div class="spacer smallgap"></div>
@ -42,15 +42,15 @@ const showSearchInput = ref<boolean>(false)
const search = ref<HTMLInputElement | null>() const search = ref<HTMLInputElement | null>()
const searchButton = ref<HTMLButtonElement | null>() const searchButton = ref<HTMLButtonElement | null>()
const closeSearch = (ev: Event) => { const closeSearch = ev => {
if (!showSearchInput.value) return // Already closing if (!showSearchInput.value) return // Already closing
showSearchInput.value = false showSearchInput.value = false
const breadcrumb = document.querySelector('.breadcrumb') as HTMLElement const breadcrumb = document.querySelector('.breadcrumb') as HTMLElement
breadcrumb.focus() breadcrumb.focus()
updateSearch(ev) updateSearch(ev)
} }
const updateSearch = (ev: Event) => { const updateSearch = ev => {
const q = (ev.target as HTMLInputElement).value const q = ev.target.value
let p = props.path.join('/') let p = props.path.join('/')
p = p ? `/${p}` : '' p = p ? `/${p}` : ''
const url = q ? `${p}//${q}` : (p || '/') const url = q ? `${p}//${q}` : (p || '/')
@ -58,9 +58,9 @@ const updateSearch = (ev: Event) => {
if (!props.query && q) router.push(url) if (!props.query && q) router.push(url)
else router.replace(url) else router.replace(url)
} }
const toggleSearchInput = (ev: Event) => { const toggleSearchInput = () => {
showSearchInput.value = !showSearchInput.value showSearchInput.value = !showSearchInput.value
if (!showSearchInput.value) return closeSearch(ev) if (!showSearchInput.value) return closeSearch()
nextTick(() => { nextTick(() => {
const input = search.value const input = search.value
if (input) input.focus() if (input) input.focus()

View File

@ -34,7 +34,7 @@ const op = (op: string, dst?: string) => {
// @ts-ignore // @ts-ignore
if (dst !== undefined) msg.dst = dst if (dst !== undefined) msg.dst = dst
const control = connect(controlUrl, { const control = connect(controlUrl, {
message(ev: MessageEvent) { message(ev: WebSocmetMessageEvent) {
const res = JSON.parse(ev.data) const res = JSON.parse(ev.data)
if ('error' in res) { if ('error' in res) {
console.error('Control socket error', msg, res.error) 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> path: Array<string>
}) })
type CloudFile = {
file: File
cloudName: string
cloudPos: number
}
function uploadHandler(event: Event) { function uploadHandler(event: Event) {
event.preventDefault() event.preventDefault()
event.stopPropagation() event.stopPropagation()
// @ts-ignore // @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 if (!infiles.length) return
const loc = props.path!.join('/') const loc = props.path!.join('/')
let files = [] for (const f of infiles) {
for (const file of infiles) { f.cloudName = loc + '/' + (f.webkitRelativePath || f.name)
files.push({ f.cloudPos = 0
file,
cloudName: loc + '/' + (file.webkitRelativePath || file.name),
cloudPos: 0,
})
} }
const dotfiles = files.filter(f => f.cloudName.includes('/.')) const dotfiles = infiles.filter(f => f.cloudName.includes('/.'))
if (dotfiles.length) { if (dotfiles.length) {
documentStore.error = "Won't upload dotfiles" documentStore.error = "Won't upload dotfiles"
console.log("Dotfiles omitted", dotfiles) console.log("Dotfiles omitted", dotfiles)
files = files.filter(f => !f.cloudName.includes('/.')) infiles = infiles.filter(f => !f.cloudName.includes('/.'))
} }
if (!files.length) return if (!infiles.length) return
files.sort((a, b) => collator.compare(a.cloudName, b.cloudName)) infiles.sort((a, b) => collator.compare(a.cloudName, b.cloudName))
// @ts-ignore // @ts-ignore
upqueue = [...upqueue, ...files] upqueue = upqueue.concat(infiles)
statsAdd(files) statsAdd(infiles)
startWorker() startWorker()
} }
@ -58,14 +49,13 @@ const uprogress_init = {
tlast: 0, tlast: 0,
statbytes: 0, statbytes: 0,
statdur: 0, statdur: 0,
files: [] as CloudFile[], files: [],
filestart: 0, filestart: 0,
fileidx: 0, fileidx: 0,
filecount: 0, filecount: 0,
filename: '', filename: '',
filesize: 0, filesize: 0,
filepos: 0, filepos: 0,
status: 'idle',
} }
const uprogress = reactive({...uprogress_init}) const uprogress = reactive({...uprogress_init})
const percent = computed(() => uprogress.uploaded / uprogress.total * 100) const percent = computed(() => uprogress.uploaded / uprogress.total * 100)
@ -88,7 +78,7 @@ setInterval(() => {
uprogress.statdur *= .9 uprogress.statdur *= .9
} }
}, 100) }, 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 if (name !== uprogress.filename) return // If stats have been reset
const now = Date.now() const now = Date.now()
uprogress.uploaded = uprogress.filestart + end uprogress.uploaded = uprogress.filestart + end
@ -107,7 +97,7 @@ const statNextFile = () => {
const f = uprogress.files.shift() const f = uprogress.files.shift()
if (!f) return statReset() if (!f) return statReset()
uprogress.filepos = 0 uprogress.filepos = 0
uprogress.filesize = f.file.size uprogress.filesize = f.size
uprogress.filename = f.cloudName uprogress.filename = f.cloudName
} }
const statReset = () => { const statReset = () => {
@ -115,14 +105,14 @@ const statReset = () => {
uprogress.t0 = Date.now() uprogress.t0 = Date.now()
uprogress.tlast = uprogress.t0 + 1 uprogress.tlast = uprogress.t0 + 1
} }
const statsAdd = (f: CloudFile[]) => { const statsAdd = (f: Array<File>) => {
if (uprogress.files.length === 0) statReset() 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.filecount += f.length
uprogress.files = [...uprogress.files, ...f] uprogress.files = uprogress.files.concat(f)
statNextFile() statNextFile()
} }
let upqueue = [] as CloudFile[] let upqueue = [] as File[]
// TODO: Rewrite as WebSocket class // TODO: Rewrite as WebSocket class
const WSCreate = async () => await new Promise<WebSocket>(resolve => { const WSCreate = async () => await new Promise<WebSocket>(resolve => {
@ -165,19 +155,17 @@ const worker = async () => {
const ws = await WSCreate() const ws = await WSCreate()
while (upqueue.length) { while (upqueue.length) {
const f = upqueue[0] const f = upqueue[0]
if (f.cloudPos === f.file.size) { if (f.cloudPos === f.size) {
upqueue.shift() upqueue.shift()
continue continue
} }
const start = f.cloudPos const start = f.cloudPos
const end = Math.min(f.file.size, start + (1<<20)) const end = Math.min(f.size, start + (1<<20))
const control = { name: f.cloudName, size: f.file.size, start, end } const control = { name: f.cloudName, size: f.size, start, end }
const data = f.file.slice(start, end) const data = f.slice(start, end)
f.cloudPos = end f.cloudPos = end
// Note: files may get modified during I/O // Note: files may get modified during I/O
// @ts-ignore FIXME proper WebSocket class, avoid attaching functions to WebSocket object
ws.sendMsg(control) ws.sendMsg(control)
// @ts-ignore
await ws.sendData(data) await ws.sendData(data)
} }
if (upqueue.length) startWorker() 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() const store = useDocumentStore()
console.log('Watch root', root) console.log('Watch root', root)
store.updateRoot(root) store.updateRoot(root)

View File

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