Browse Source

fic(nc-gui): allow duplicate file name file to upload in atttachment

pull/7605/head
Ramesh Mane 9 months ago
parent
commit
c5e0a076a2
  1. 38
      packages/nc-gui/components/cell/attachment/utils.ts
  2. 19
      packages/nc-gui/composables/useMultiSelect/convertCellData.ts
  3. 36
      packages/nc-gui/composables/useMultiSelect/index.ts
  4. 8
      packages/nc-gui/utils/fileUtils.ts

38
packages/nc-gui/components/cell/attachment/utils.ts

@ -108,7 +108,7 @@ export const [useProvideAttachmentCell, useAttachmentCell] = useInjectionState(
...parseProp(column?.value?.meta), ...parseProp(column?.value?.meta),
} }
const newAttachments = [] const newAttachments: AttachmentType[] = []
const files: File[] = [] const files: File[] = []
@ -159,13 +159,12 @@ export const [useProvideAttachmentCell, useAttachmentCell] = useInjectionState(
if (selectedFiles.length) { if (selectedFiles.length) {
files.push(file as File) files.push(file as File)
} else { } else {
let fileName = (file as AttachmentReqType).fileName ?? '' const fileName = populateUniqueFileName((file as AttachmentReqType).fileName ?? '', [
let count = 1 ...attachments.value,
while ([...attachments.value, ...imageUrls].some((el) => el.title === fileName)) { ...imageUrls,
fileName = fileName.replace(/(.+?)(\.[^.]+)$/, `$1(${count})$2`) ])
count++
} imageUrls.push({ ...(file as AttachmentReqType), fileName, title: fileName })
imageUrls.push({ ...(file as AttachmentReqType), fileName })
} }
} }
@ -221,13 +220,10 @@ export const [useProvideAttachmentCell, useAttachmentCell] = useInjectionState(
) )
// add suffix in duplicate file title // add suffix in duplicate file title
for (const uploadedFile of data) { for (const uploadedFile of data) {
let fileName = uploadedFile?.title newAttachments.push({
let count = 1 ...uploadedFile,
while ([...attachments.value, ...newAttachments].some((el) => el.title === fileName)) { title: populateUniqueFileName(uploadedFile?.title, [...attachments.value, ...newAttachments]),
fileName = fileName.replace(/(.+?)(\.[^.]+)$/, `$1(${count})$2`) })
count++
}
newAttachments.push({ ...uploadedFile, title: fileName })
} }
} catch (e: any) { } catch (e: any) {
message.error(e.message || t('msg.error.internalError')) message.error(e.message || t('msg.error.internalError'))
@ -283,7 +279,17 @@ export const [useProvideAttachmentCell, useAttachmentCell] = useInjectionState(
const imageData = imageUrl ? await getImageDataFromUrl(imageUrl) : '' const imageData = imageUrl ? await getImageDataFromUrl(imageUrl) : ''
if (imageData) { if (imageData) {
await onFileSelect([], [{ ...imageData, url: imageUrl, fileName: `image.${imageData.mimetype?.split('/')[1]}` }]) await onFileSelect(
[],
[
{
...imageData,
url: imageUrl,
fileName: `image.${imageData.mimetype?.split('/')[1]}`,
title: `image.${imageData.mimetype?.split('/')[1]}`,
},
],
)
} }
} }
} }

19
packages/nc-gui/composables/useMultiSelect/convertCellData.ts

@ -1,5 +1,5 @@
import dayjs from 'dayjs' import dayjs from 'dayjs'
import type { ColumnType, LinkToAnotherRecordType, SelectOptionsType } from 'nocodb-sdk' import type { AttachmentType, ColumnType, LinkToAnotherRecordType, SelectOptionsType } from 'nocodb-sdk'
import { UITypes } from 'nocodb-sdk' import { UITypes } from 'nocodb-sdk'
import type { AppInfo } from '~/composables/useGlobal' import type { AppInfo } from '~/composables/useGlobal'
import { isBt, isMm, parseProp } from '#imports' import { isBt, isMm, parseProp } from '#imports'
@ -191,16 +191,6 @@ export default function convertCellData(
continue continue
} }
} }
// this prevent file with same names
const isFileNameAlreadyExist = oldAttachments.some((el) => el.title === (attachment?.title || attachment?.name))
if (isFileNameAlreadyExist) {
if (isMultiple) {
message.error(`File with name ${attachment?.title || attachment?.name} already attached`)
continue
} else {
throw new Error(`File with name ${attachment?.title || attachment?.name} already attached`)
}
}
attachments.push(attachment) attachments.push(attachment)
} }
@ -208,7 +198,12 @@ export default function convertCellData(
if (oldAttachments.length && !attachments.length) { if (oldAttachments.length && !attachments.length) {
return undefined return undefined
} else if (value && attachments.length) { } else if (value && attachments.length) {
return JSON.stringify([...oldAttachments, ...attachments]) const newAttachments: AttachmentType[] = []
for (const att of attachments) {
newAttachments.push({ ...att, title: populateUniqueFileName(att?.title, [...oldAttachments, ...newAttachments]) })
}
return JSON.stringify([...oldAttachments, ...newAttachments])
} else if (files.length && attachments.length) { } else if (files.length && attachments.length) {
return attachments return attachments
} else { } else {

36
packages/nc-gui/composables/useMultiSelect/index.ts

@ -2,7 +2,7 @@ import type { Ref } from 'vue'
import { computed } from 'vue' import { computed } from 'vue'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import type { MaybeRef } from '@vueuse/core' import type { MaybeRef } from '@vueuse/core'
import type { ColumnType, LinkToAnotherRecordType, PaginatedType, TableType, UserFieldRecordType, ViewType } from 'nocodb-sdk' import type { AttachmentType, ColumnType, LinkToAnotherRecordType, PaginatedType, TableType, UserFieldRecordType, ViewType } from 'nocodb-sdk'
import { UITypes, dateFormats, isDateMonthFormat, isSystemColumn, isVirtualCol, timeFormats } from 'nocodb-sdk' import { UITypes, dateFormats, isDateMonthFormat, isSystemColumn, isVirtualCol, timeFormats } from 'nocodb-sdk'
import { parse } from 'papaparse' import { parse } from 'papaparse'
import type { Cell } from './cellRange' import type { Cell } from './cellRange'
@ -1115,12 +1115,9 @@ export function useMultiSelect(
) )
if (columnObj.uidt === UITypes.Attachment && e.clipboardData?.files?.length && pasteValue?.length) { if (columnObj.uidt === UITypes.Attachment && e.clipboardData?.files?.length && pasteValue?.length) {
const uploadedFiles = await handleFileUpload(pasteValue, columnObj.id!) const newAttachments = await handleFileUploadAndGetCellValue(pasteValue, columnObj.id!, rowObj.row[columnObj.title!])
rowObj.row[columnObj.title!] = rowObj.row[columnObj.title!] = newAttachments ? JSON.stringify(newAttachments) : null
Array.isArray(uploadedFiles) && uploadedFiles.length
? JSON.stringify([...handleParseAttachmentCellData(rowObj.row[columnObj.title!]), ...uploadedFiles])
: null
} else if (pasteValue !== undefined) { } else if (pasteValue !== undefined) {
rowObj.row[columnObj.title!] = pasteValue rowObj.row[columnObj.title!] = pasteValue
} }
@ -1177,12 +1174,9 @@ export function useMultiSelect(
) )
if (fileUploadPayload?.length) { if (fileUploadPayload?.length) {
const uploadedFiles = await handleFileUpload(fileUploadPayload, col.id!) const newAttachments = await handleFileUploadAndGetCellValue(fileUploadPayload, col.id!, row.row[col.title!])
pasteValue = pasteValue = newAttachments ? JSON.stringify(newAttachments) : null
Array.isArray(uploadedFiles) && uploadedFiles.length
? JSON.stringify([...handleParseAttachmentCellData(row.row[col.title]), ...uploadedFiles])
: null
} }
} }
} else { } else {
@ -1232,7 +1226,9 @@ export function useMultiSelect(
event.preventDefault() event.preventDefault()
} }
async function handleFileUpload(files: File[], columnId: string) { async function handleFileUploadAndGetCellValue(files: File[], columnId: string, oldValue: AttachmentType[]) {
const newAttachments: AttachmentType[] = []
try { try {
const data = await api.storage.upload( const data = await api.storage.upload(
{ {
@ -1242,19 +1238,27 @@ export function useMultiSelect(
files, files,
}, },
) )
return data
// add suffix in duplicate file title
for (const uploadedFile of data) {
newAttachments.push({
...uploadedFile,
title: populateUniqueFileName(uploadedFile?.title, [...handleParseAttachmentCellData(oldValue), ...newAttachments]),
})
}
return newAttachments
} catch (e: any) { } catch (e: any) {
message.error(e.message || t('msg.error.internalError')) message.error(e.message || t('msg.error.internalError'))
} }
} }
function handleParseAttachmentCellData(value: string | null) { function handleParseAttachmentCellData<T>(value: T): T {
const parsedVal = parseProp(value) const parsedVal = parseProp(value)
if (parsedVal && Array.isArray(parsedVal)) { if (parsedVal && Array.isArray(parsedVal)) {
return parsedVal return parsedVal as T
} else { } else {
return [] return [] as T
} }
} }

8
packages/nc-gui/utils/fileUtils.ts

@ -62,3 +62,11 @@ export function extractImageSrcFromRawHtml(rawText: string) {
return imgElement.getAttribute('src') return imgElement.getAttribute('src')
} }
} }
export function populateUniqueFileName(fn: string, attachments: any[]) {
let c = 1
while (attachments.some((att) => att?.title === fn || att?.fileName === fn)) {
fn = fn.replace(/(.+?)(\.[^.]+)$/, `$1(${c++})$2`)
}
return fn
}

Loading…
Cancel
Save