Frontend created and rewritten a few times, with some backend fixes #1

Merged
leo merged 110 commits from plaintable into main 2023-11-08 20:38:40 +00:00
8 changed files with 198 additions and 185 deletions
Showing only changes of commit 0d186726b5 - Show all commits

View File

@ -26,7 +26,8 @@
pathList pathList
} }
}) })
// Update human-readable x seconds ago messages from mtimes
setInterval(documentStore.updateModified, 1000)
watchEffect(() => { watchEffect(() => {
const documentHandler = new DocumentHandler() const documentHandler = new DocumentHandler()
const documentUploadHandler = new DocumentUploadHandler() const documentUploadHandler = new DocumentUploadHandler()

View File

@ -15,13 +15,14 @@
<template #headerCell="{column}"></template> <template #headerCell="{column}"></template>
<template #bodyCell="{ column, record }"> <template #bodyCell="{ column, record }">
<template v-if="column.key === 'name'"> <template v-if="column.key === 'name'">
<div class="editable-cell"> <div class="editable-cell" :class="record.type === 'folder' ? 'folder' : 'file'">
<div v-if="editableData[record.key]" class="action-container editable-cell-input-wrapper"> <div v-if="editableData[record.key]" class="action-container editable-cell-input-wrapper">
<a-input class="name" v-model:value="editableData[record.key].name" @pressEnter="save(record.key)" /> <a-input class="name" v-model:value="editableData[record.key].name" @pressEnter="save(record.key)" />
<CheckOutlined class="edit-action editable-cell-icon-check" @click="save(record.key)" /> <CheckOutlined class="edit-action editable-cell-icon-check" @click="save(record.key)" />
</div> </div>
<div v-else class="action-container editable-cell-text-wrapper"> <div v-else class="action-container editable-cell-text-wrapper">
<a class="name" :href="`#${linkBasePath}/${record.name}`">{{record.name}}</a> <a v-if="record.type === 'folder'" class="name" :href="`#${linkBasePath}/${record.name}`">{{record.name}}</a>
<a v-else class="name" :href="`${filesBasePath}/${record.name}`">{{record.name}}</a>
<edit-outlined class="edit-action editable-cell-icon" @click="edit(record.key)" /> <edit-outlined class="edit-action editable-cell-icon" @click="edit(record.key)" />
</div> </div>
</div> </div>
@ -84,9 +85,10 @@
}); });
const linkBasePath = computed(()=>{ const linkBasePath = computed(()=>{
if(Router.currentRoute.value.path === '/') return '' const path = Router.currentRoute.value.path
return Router.currentRoute.value.path return path === '/' ? '' : path
}) })
const filesBasePath = computed(() => `/files${linkBasePath.value}`)
const columns = ref<TableColumnsType>([ const columns = ref<TableColumnsType>([
{ {
@ -95,34 +97,26 @@
width: '70%', width: '70%',
key: 'name', key: 'name',
sortDirections: ['ascend', 'descend'], sortDirections: ['ascend', 'descend'],
sorter: (a: Document, b: Document, sortOrder) => { sorter: (a: Document, b: Document) => a.name.localeCompare(b.name),
return b.name.localeCompare(a.name)
}
}, },
{ {
title: 'Modified', title: 'Modified',
dataIndex: 'modified', dataIndex: 'modified',
className: 'column-date',
responsive: ['lg'], responsive: ['lg'],
sortDirections: ['ascend', 'descend'], sortDirections: ['ascend', 'descend'],
defaultSortOrder: 'descend', defaultSortOrder: 'descend',
sorter: (a: FolderDocument, b: FolderDocument) => { sorter: (a: FolderDocument, b: FolderDocument) => a.mtime - b.mtime,
const dateA = new Date(a.modified),
dateB = new Date(b.modified);
if (dateA < dateB) return -1
if (dateA > dateB) return 1
return 0
},
key: 'modified', key: 'modified',
}, },
{ {
// TODO BETTER SORT FOR MULTPLE SIZE OR CUSTOM PIPE TO kB to MB / GB // TODO BETTER SORT FOR MULTPLE SIZE OR CUSTOM PIPE TO kB to MB / GB
title: 'Size', title: 'Size',
dataIndex: 'size', dataIndex: 'size',
className: 'column-size',
responsive: ['lg'], responsive: ['lg'],
sortDirections: ['ascend', 'descend'], sortDirections: ['ascend', 'descend'],
sorter: (a: FolderDocument, b: FolderDocument) => { sorter: (a: FolderDocument, b: FolderDocument) => a.size - b.size,
return a.size - b.size
},
key: 'size', key: 'size',
}, },
{ {
@ -152,7 +146,10 @@
</script> </script>
<style scoped> <style>
.column-date, .column-size {
text-align: right;
}
main { main {
padding: 5px; padding: 5px;
height: 100%; height: 100%;
@ -175,11 +172,19 @@
.carousel-container{ .carousel-container{
height: inherit; height: inherit;
} }
.file .name::before {
content: '📄 ';
font-size: 1.5em;
}
.folder .name::before {
content: '📁 ';
font-size: 1.5em;
}
.editable-cell-text-wrapper .editable-cell-icon { .editable-cell-text-wrapper .editable-cell-icon {
visibility: hidden; /* Oculta el ícono de manera predeterminada */ visibility: hidden; /* Oculta el ícono de manera predeterminada */
} }
.editable-cell-text-wrapper:hover .editable-cell-icon { .editable-cell-text-wrapper:hover .editable-cell-icon {
visibility: visible; /* Muestra el ícono al hacer hover en el contenedor */ visibility: visible; /* Muestra el ícono al hacer hover en el contenedor */
} }
</style> </style>

View File

@ -6,13 +6,14 @@ import Client from '@/repositories/Client'
type BaseDocument = { type BaseDocument = {
name: string; name: string;
key?: number; key?: number | string;
}; };
export type FolderDocument = BaseDocument & { export type FolderDocument = BaseDocument & {
type: 'folder' | 'folder-file';
size: number; size: number;
mtime: number;
modified: string; modified: string;
type: 'folder';
}; };
export type FileDocument = BaseDocument & { export type FileDocument = BaseDocument & {

View File

@ -1,15 +1,15 @@
import type { Document } from '@/repositories/Document'; import type { Document, FolderDocument } from '@/repositories/Document';
import type { ISimpleError } from '@/repositories/Client'; import type { ISimpleError } from '@/repositories/Client';
import { fetchFile } from '@/repositories/Document' import { fetchFile } from '@/repositories/Document'
import { formatUnixDate } from '@/utils'; import { formatUnixDate } from '@/utils';
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
type FileData = { mtime: number, size: number, dir: DirectoryData}; type FileData = { id: string, mtime: number, size: number, dir: DirectoryData};
type DirectoryData = { type DirectoryData = {
[filename: string]: FileData; [filename: string]: FileData;
}; };
export type FileStructure = {mtime: number, size: number, dir: DirectoryData}; export type FileStructure = {id: string, mtime: number, size: number, dir: DirectoryData};
export type DocumentStore = { export type DocumentStore = {
root: FileStructure, root: FileStructure,
@ -54,18 +54,20 @@ export const useDocumentStore = defineStore({
}) })
// Transform data // Transform data
let count = 0 for (const [name, attr] of Object.entries(data.dir)) {
for (const key in data.dir) { const {id, size, mtime, dir} = attr
const element: Document = { const element: Document = {
name: key, name,
key: count, key: id,
size: data.dir[key].size, size,
modified: formatUnixDate(data.dir[key].mtime), mtime,
type: 'folder', modified: formatUnixDate(mtime),
type: dir === undefined ? 'folder-file' : 'folder',
} }
count++
dataMapped.push(element) dataMapped.push(element)
} }
// Pre sort directory entries folders first then files, names in natural ordering
dataMapped.sort((a, b) => a.type === b.type ? a.name.localeCompare(b.name) : a.type === "folder" ? -1 : 1)
this.document = dataMapped this.document = dataMapped
this.loading = false; this.loading = false;
}, },
@ -83,11 +85,9 @@ export const useDocumentStore = defineStore({
this.selectedDocuments = this.selectedDocuments.filter(e => document.key !== e.key) this.selectedDocuments = this.selectedDocuments.filter(e => document.key !== e.key)
}, },
updateUploadingDocuments(key: number, progress: number){ updateUploadingDocuments(key: number, progress: number){
this.uploadingDocuments.forEach((document) => { for (const d of this.uploadingDocuments) {
if(document.key === key) { if(d.key === key) d.progress = progress
document.progress = progress }
}
})
}, },
pushUploadingDocuments(name: string){ pushUploadingDocuments(name: string){
this.uploadCount++; this.uploadCount++;
@ -134,9 +134,13 @@ export const useDocumentStore = defineStore({
index = index + direction index = index + direction
} }
return actualDirArr[index].name return actualDirArr[index].name
},
updateModified() {
for (const d of this.document) {
if ("mtime" in d) d.modified = formatUnixDate(d.mtime)
}
} }
}, },
getters: { getters: {
mainDocument(): Document[] { mainDocument(): Document[] {
return this.document; return this.document;

View File

@ -12,7 +12,9 @@ export function formatUnixDate(t: number) {
const diff = date.getTime() - now.getTime() const diff = date.getTime() - now.getTime()
const formatter = new Intl.RelativeTimeFormat('en', { numeric: const formatter = new Intl.RelativeTimeFormat('en', { numeric:
'auto' }) 'auto' })
if (Math.abs(diff) <= 5000) {
return 'now'
}
if (Math.abs(diff) <= 60000) { if (Math.abs(diff) <= 60000) {
return formatter.format(Math.round(diff / 1000), 'second') return formatter.format(Math.round(diff / 1000), 'second')
} }
@ -29,7 +31,7 @@ export function formatUnixDate(t: number) {
return formatter.format(Math.round(diff / 86400000), 'day') return formatter.format(Math.round(diff / 86400000), 'day')
} }
return date.toLocaleDateString() return date.toLocaleDateString(undefined, { weekday: 'short', year: 'numeric', month: 'short', day: 'numeric' })
} }
export function getFileExtension(filename: string) { export function getFileExtension(filename: string) {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -5,8 +5,8 @@
<link rel="icon" href="/favicon.ico"> <link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Vite Vasanko</title> <title>Vite Vasanko</title>
<script type="module" crossorigin src="/assets/index-1dc06db1.js"></script> <script type="module" crossorigin src="/assets/index-dfc6f58a.js"></script>
<link rel="stylesheet" href="/assets/index-09b10238.css"> <link rel="stylesheet" href="/assets/index-ee545ab1.css">
</head> </head>
<body> <body>
<div id="app"></div> <div id="app"></div>