Skip to content

Commit

Permalink
wip: Refactor documents related components #904
Browse files Browse the repository at this point in the history
  • Loading branch information
cnouguier committed Dec 18, 2024
1 parent 216d228 commit 3455b06
Show file tree
Hide file tree
Showing 6 changed files with 259 additions and 23 deletions.
10 changes: 10 additions & 0 deletions core/client/components/KDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@
:is="computedComponent"
v-model="computedModel"
v-bind="computedAttrs"
v-on="computedHandlers"
/>
<!-- component without v-model -->
<component
v-else
ref="componentRef"
:is="computedComponent"
v-bind="computedAttrs"
v-on="computedHandlers"
/>
</Suspense>
</KModal>
Expand Down Expand Up @@ -49,6 +51,10 @@ const props = defineProps({
type: String,
default: null
},
handlers: {
type: Object,
default: null
},
okAction: {
type: [String, Object],
default: 'OK'
Expand Down Expand Up @@ -132,6 +138,10 @@ const computedButtons = computed(() => {
const computedComponent = computed(() => {
return loadComponent(props.component)
})
const computedHandlers = computed(() => {
if (_.isEmpty(props.handlers)) return {}
return props.handlers
})
const computedModel = computed({
get: function () {
return model.value
Expand Down
127 changes: 106 additions & 21 deletions core/client/components/document/KBrowser.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,24 @@
-->
<div class="full-width row justify-between items-center">
<div
v-if="document"
id="browser-title"
class="text-subtitle1"
>
{{ document.name }}
{{ title }}
</div>
<KPanel
id="browser-toolbar"
:content="toolbar"
:content="tools"
:class="{ 'q-gutter-x-sm' : $q.screen.gt.xs, 'q-gutter-x-xs': $q.screen.lt.sm }"
/>
</div>
<!--
Content
-->
<div class="full-width col row justify-between items-center">
<div
v-if="files && file"
class="full-width col row justify-between items-center"
>
<div
v-if="hasPrevious"
class="full-height column justify-center"
Expand All @@ -35,10 +37,16 @@
</div>
<div class="full-height col column justify-center items-center">
<KDocument
v-bind="document"
v-if="hasDocumentViewer(file)"
v-bind="file"
:localize="false"
class="fit"
/>
<q-icon
v-else
name="las la-eye-slash"
size="3rem"
/>
</div>
<div
v-if="hasNext"
Expand All @@ -60,11 +68,16 @@
import _ from 'lodash'
import { ref, computed, watch } from 'vue'
import { Storage } from '../../storage.js'
import { Document } from '../../document.js'
import KDocument from './KDocument.vue'
import KAction from '../action/KAction.vue'
// Props
const props = defineProps({
path: {
type: String,
default: ''
},
documents: {
type: Array,
default: () => null
Expand All @@ -81,47 +94,119 @@ const props = defineProps({
// Data
const index = ref(null)
const document = ref(null)
const files = ref([])
const file = ref(null)
// Computed
const title = computed(() => {
return file.value ? file.value.name : ''
})
const hasPrevious = computed(() => {
return _.size(props.documents) > 1
return _.size(files.value) > 1
})
const hasNext = computed(() => {
return _.size(props.documents) > 1
return _.size(files.value) > 1
})
const tools = computed(() => {
if (_.isEmpty(props.toolbar)) return []
let components = []
if (props.toolbar.includes('download')) {
components.push({
id: 'download-file',
icon: 'las la-download',
color: 'white',
tooltip: 'KBrowser.DOWNLOAD_FILE',
handler: downloadFile
})
}
if (props.toolbar.includes('upload')) {
components.push({
id: 'upload-file',
icon: 'las la-upload',
color: 'white',
tooltip: 'KBrowser.UPLOAD_FILES',
dialog: {
component: 'document/KUploader',
'component.path': props.path,
handlers: { 'files-uploaded': onFilesUploaded },
cancelAction: 'CANCEL',
okAction: { id: 'upload-button', label: 'KBrowser.UPLOAD', handler: 'upload' }
}
})
}
if (props.toolbar.includes('delete')) {
components.push({
id: 'delete-file',
icon: 'las la-trash',
color: 'white',
tooltip: 'KBrowser.DELETE_FILE',
handler: deleteFile
})
}
return components
})
// Watch
watch(() => [props.documents, props.default], async () => {
index.value = _.findIndex(props.documents, { name: props.default })
if (_.size(props.document) > 0) {
files.value = props.documents
index.value = _.findIndex(files.value, { name: props.default })
if (index.value < 0) index.value = 0
await refresh()
} else {
files.value = []
file.value = null
index.value = -1
}
files.value = props.documents
index.value = _.findIndex(files.value, { name: props.default })
if (index.value > -1) await refresh()
console.log(files.value)
}, { immediate: true })
// Functions
function hasDocumentViewer (file) {
return Document.hasViewer(file.type)
}
function getDocumentKey (name) {
return _.isEmpty(props.path) ? name : `${props.path}/${name}`
}
async function previous () {
if (index.value === 0) index.value = _.size(props.documents) - 1
if (index.value === 0) index.value = _.size(files.value) - 1
else index.value = index.value - 1
await refresh()
}
async function next () {
if (index.value === _.size(props.documents) - 1) index.value = 0
if (index.value === _.size(files.value) - 1) index.value = 0
else index.value = index.value + 1
await refresh()
}
async function refresh () {
document.value = props.documents[index.value]
document.value.url = await Storage.getPresignedUrl({
key: document.value.key,
context: document.value.contextId,
file.value = files.value[index.value]
file.value.url = await Storage.getPresignedUrl({
key: getDocumentKey(file.value.name),
expiresIn: 60
})
}
/* TODO
function download (document) {
function downloadFile () {
Storage.export({
file: document.value.name,
key: document.value.key,
context: document.value.contextId
file: file.value.name,
key: getDocumentKey(file.value.name)
})
}*/
}
function deleteFile () {
/*Storage.export({
file: file.value.name,
key: getDocumentKey(file.value.name)
})*/
}
function onFilesUploaded (uploadedFiles) {
files.value = _.concat(files.value, _.map(uploadedFiles, file => {
return {
name: file.name,
type: file.type
}
}))
console.log(uploadedFiles, files.value)
}
</script>
4 changes: 2 additions & 2 deletions core/client/components/document/KImage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<img
:src="url"
:onload="onLoaded"
class="full-width"
style="max-width: 100%;"
/>
</pinch-zoom>
<div
Expand All @@ -28,7 +28,7 @@
<img
:src="url"
:onload="onLoaded"
class="full-width"
style="max-width: 100%;"
/>
</div>
<q-spinner
Expand Down
115 changes: 115 additions & 0 deletions core/client/components/document/KUploader.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
<template>
<q-file
v-model="files"
:filter="checkFilesSize"
:label="$t('KUploader.ADD_FILES')"
:disable="uploading"
rounded
outlined
use-chips
multiple
append
clearable
dense
@update:model-value="onUpdated"
/>
</template>

<script setup>
import _ from 'lodash'
import logger from 'loglevel'
import { ref } from 'vue'
import { Notify } from 'quasar'
import { Storage } from '../../storage.js'
import { i18n } from '../../i18n.js'
// Props
const props = defineProps({
path: {
type: String,
default: undefined
},
fileTypes: {
type: String,
default: undefined
},
maxFileSize: {
type: Number,
default: 52428800
}
})
// Emits
const emit = defineEmits(['files-updated', 'files-uploaded'])
// Data
const files = ref([])
const uploading = ref(false)
const bToMb = 0.00000095367432
// Functions
function checkFilesSize (files) {
return _.filter(files, file => {
if (file.size === 0) {
Notify.create({ type: 'negative', message: i18n.t('KUploader.EMPTY_FILE', { file: file.name })})
return false
}
if (file.size > props.maxFileSize) {
Notify.create({ type: 'negative', message: i18n.t('KUploader.FILE_TOO_LARGE', { file: file.name, size: Math.trunc(props.maxFileSize * bToMb) }) })
return false
}
return true
})
}
async function upload (path) {
uploading.value = true
// compute the path: first use path argument, second use path prop
if (!path) path = _.isEmpty(props.path) ? '' : `${props.path}`
// upload the files
for (const file of files.value) {
const key = _.isEmpty(path) ? file.name : `${path}/${file.name}`
logger.debug(`[KDK] Uploading file ${file.name} with key ${key}`)
Storage.upload({
file: file.name,
type: file.type,
key,
blob: file
})
.then(() => {
Notify.create({
type: 'positive',
message: i18n.t('KUploader.UPLOAD_FILE_SUCCEEDED',
{ file: file.name })
})
})
.catch(error => {
logger.error('[KDK] Uploading file ${file.name} failed:', error)
Notify.create({
type: 'negative',
message: i18n.t('KUploader.UPLOAD_FILE_ERRORED',
{ file: file.name })
})
})
}
uploading.value = false
emit('files-uploaded', files.value)
// clear the files
files.value = []
onUpdated([])
return true
}
function onUpdated (value) {
const files = _.map(value, file => {
return {
name: file.name,
type: file.type
}
})
emit('files-updated', files)
}
// Expose
defineExpose({
upload
})
</script>
13 changes: 13 additions & 0 deletions core/client/i18n/core_en.json
Original file line number Diff line number Diff line change
Expand Up @@ -928,6 +928,19 @@
},
"KImage": {
"RESET": "Reset"
},
"KBrowser": {
"UPLOAD_FILES": "Upload files",
"DOWNLOAD_FILE": "Download file",
"DELETE_FILE": "Delete file",
"UPLOAD": "Upload"
},
"KUploader": {
"ADD_FILES": "Add files...",
"EMPTY_FILE": "File {file] is empty or corrupted !",
"FILE_TOO_LARGE": "File {file} is too large. The size must be less than {size}Mb",
"UPLOAD_FILE_SUCCEEDED": "File {file} has been successfully uploaded",
"UPLOAD_FILE_ERRORED": "Cannot upload file {file} !"
}
}

Loading

0 comments on commit 3455b06

Please sign in to comment.