Browse Source

feat(gui-v2): integrate attachment cell

Signed-off-by: Pranav C <pranavxc@gmail.com>
pull/3188/head
Pranav C 2 years ago
parent
commit
85f4be117b
  1. 14
      packages/nc-gui-v2/components/cell/attachment/index.vue
  2. 52
      packages/nc-gui-v2/components/cell/attachment/utils.ts
  3. 2
      packages/nc-gui-v2/components/shared-view/Form.vue

14
packages/nc-gui-v2/components/cell/attachment/index.vue

@ -4,7 +4,7 @@ import { useProvideAttachmentCell } from './utils'
import { useSortable } from './sort'
import Modal from './Modal.vue'
import Carousel from './Carousel.vue'
import { computed, isImage, openLink, ref, useDropZone, useSmartsheetStoreOrThrow, watch } from '#imports'
import { computed, isImage, openLink, ref, useDropZone, useSmartsheetStoreOrThrow, watch, useSmartsheetRowStoreOrThrow } from '#imports'
interface Props {
modelValue: string | Record<string, any>[] | null
@ -23,13 +23,15 @@ const sortableRef = ref<HTMLDivElement>()
const { cellRefs } = useSmartsheetStoreOrThrow()!
const { column, modalVisible, attachments, visibleItems, onDrop, isLoading, open, FileIcon, selectedImage, isReadonly } =
const { column, modalVisible, attachments, visibleItems, onDrop, isLoading, open, FileIcon, selectedImage, isReadonly, storedFilesRefs, } =
useProvideAttachmentCell(updateModelValue)
const currentCellRef = computed(() => cellRefs.value.find((cell) => cell.dataset.key === `${rowIndex}${column.value.id}`))
const { dragging } = useSortable(sortableRef, visibleItems, updateModelValue, isReadonly)
const { state: rowState } = useSmartsheetRowStoreOrThrow()
const { isOverDropZone } = useDropZone(currentCellRef, onDrop)
/** on new value, reparse our stored attachments */
@ -53,6 +55,14 @@ onKeyDown('Escape', () => {
modalVisible.value = false
isOverDropZone.value = false
})
/** sync storedFilesRefs state with row state */
watch(
() => storedFilesRefs?.value?.length || 0,
() => {
rowState.value[column.value.title!] = storedFilesRefs?.value
},
)
</script>
<template>

52
packages/nc-gui-v2/components/cell/attachment/utils.ts

@ -1,7 +1,7 @@
import { message } from 'ant-design-vue'
import FileSaver from 'file-saver'
import { computed, inject, ref, useApi, useFileDialog, useInjectionState, useProject, watch } from '#imports'
import { ColumnInj, EditModeInj, MetaInj, ReadonlyInj } from '~/context'
import { ColumnInj, EditModeInj, IsPublicInj, MetaInj, ReadonlyInj } from '~/context'
import { isImage } from '~/utils'
import { NOCO } from '~/lib'
import MdiPdfBox from '~icons/mdi/pdf-box'
@ -10,11 +10,18 @@ import MdiFilePowerpointBox from '~icons/mdi/file-powerpoint-box'
import MdiFileExcelOutline from '~icons/mdi/file-excel-outline'
import IcOutlineInsertDriveFile from '~icons/ic/outline-insert-drive-file'
interface AttachmentProps {
data?: any
file: File
title: string
}
export const [useProvideAttachmentCell, useAttachmentCell] = useInjectionState(
(updateModelValue: (data: string | Record<string, any>[]) => void) => {
const isReadonly = inject(ReadonlyInj, false)
const isPublicForm = inject('isPublicForm', false)
const isPublic = inject(IsPublicInj, ref(false))
const isForm = inject('isForm', false)
@ -27,8 +34,11 @@ export const [useProvideAttachmentCell, useAttachmentCell] = useInjectionState(
const editEnabled = inject(EditModeInj, ref(false))
// todo: refactor name
const storedFiles = ref<{ title: string; file: File }[]>([])
const storedFilesRefs = ref<File[]>([])
const attachments = ref<File[]>([])
const modalVisible = ref(false)
@ -43,8 +53,9 @@ export const [useProvideAttachmentCell, useAttachmentCell] = useInjectionState(
/** remove a file from our stored attachments (either locally stored or saved ones) */
function removeFile(i: number) {
if (isPublicForm) {
if (isPublic.value) {
storedFiles.value.splice(i, 1)
storedFilesRefs.value.splice(i, 1)
updateModelValue(storedFiles.value.map((storedFile) => storedFile.file))
} else {
@ -57,16 +68,28 @@ export const [useProvideAttachmentCell, useAttachmentCell] = useInjectionState(
async function onFileSelect(selectedFiles: FileList | File[]) {
if (!selectedFiles.length || isPublicGrid) return
if (isPublicForm) {
if (isPublic.value) {
storedFilesRefs.value.push(...selectedFiles)
storedFiles.value.push(
...Array.from(selectedFiles).map((file) => {
const res = { file, title: file.name }
if (isImage(file.name, (file as any).mimetype)) {
const reader = new FileReader()
reader.readAsDataURL(file)
}
return res
}),
...(await Promise.all<AttachmentProps>(
Array.from(selectedFiles).map(
(file) =>
new Promise<AttachmentProps>((resolve) => {
const res: AttachmentProps = { file, title: file.name }
if (isImage(file.name, (file as any).mimetype)) {
const reader = new FileReader()
reader.onload = (e: any) => {
res.data = e.target?.result
resolve(res)
}
reader.onerror = () => {
resolve(res)
}
reader.readAsDataURL(file)
}
}),
),
)),
)
return updateModelValue(storedFiles.value.map((storedFile) => storedFile.file))
@ -124,7 +147,7 @@ export const [useProvideAttachmentCell, useAttachmentCell] = useInjectionState(
}
/** our currently visible items, either the locally stored or the ones from db, depending on isPublicForm status */
const visibleItems = computed<any[]>(() => (isPublicForm ? storedFiles.value : attachments.value) || ([] as any[]))
const visibleItems = computed<any[]>(() => (isPublic.value ? storedFiles.value : attachments.value) || ([] as any[]))
watch(files, (nextFiles) => nextFiles && onFileSelect(nextFiles))
@ -132,7 +155,7 @@ export const [useProvideAttachmentCell, useAttachmentCell] = useInjectionState(
attachments,
storedFiles,
visibleItems,
isPublicForm,
isPublic,
isForm,
isPublicGrid,
isReadonly,
@ -149,6 +172,7 @@ export const [useProvideAttachmentCell, useAttachmentCell] = useInjectionState(
downloadFile,
updateModelValue,
selectedImage,
storedFilesRefs
}
},
'useAttachmentCell',

2
packages/nc-gui-v2/components/shared-view/Form.vue

@ -96,7 +96,7 @@ const { state: additionalState } = useProvideSmartsheetRowStore(
/>
</div>
<div v-if="isVirtualCol(field)" class="mt-0">
<SmartsheetVirtualCell v-model="formState[field.title]" class="mt-0 nc-input" :column="field" />
<SmartsheetVirtualCell class="mt-0 nc-input" :column="field" />
<div
v-if="
v$.virtual?.$dirty && (!v$.virtual?.[col.title]?.required || !v$.virtual?.[col.title]?.minLength)

Loading…
Cancel
Save