diff --git a/packages/nc-gui/composables/useMultiSelect/convertCellData.ts b/packages/nc-gui/composables/useMultiSelect/convertCellData.ts index a9893b2054..824418bd47 100644 --- a/packages/nc-gui/composables/useMultiSelect/convertCellData.ts +++ b/packages/nc-gui/composables/useMultiSelect/convertCellData.ts @@ -246,7 +246,8 @@ export default function convertCellData( return parsedVal || value } - case UITypes.LinkToAnotherRecord: { + case UITypes.LinkToAnotherRecord: + case UITypes.Links: { const parsedVal = typeof value === 'string' ? JSON.parse(value) : value if (!(parsedVal && typeof parsedVal === 'object' && !Array.isArray(parsedVal) && Object.keys(parsedVal))) { throw new Error('Invalid LTAR data') diff --git a/packages/nc-gui/composables/useMultiSelect/index.ts b/packages/nc-gui/composables/useMultiSelect/index.ts index 0064a1c2ee..c078938339 100644 --- a/packages/nc-gui/composables/useMultiSelect/index.ts +++ b/packages/nc-gui/composables/useMultiSelect/index.ts @@ -113,6 +113,8 @@ export function useMultiSelect( const valueToCopy = (rowObj: Row, columnObj: ColumnType) => { let textToCopy = (columnObj.title && rowObj.row[columnObj.title]) || '' + console.log('rowObj, columnObj', rowObj, columnObj) + if (columnObj.uidt === UITypes.Checkbox) { textToCopy = !!textToCopy } @@ -218,6 +220,18 @@ export function useMultiSelect( textToCopy = `"${textToCopy.replace(/"/g, '\\"')}"` } + if ( + columnObj.uidt === UITypes.Links && + (columnObj.colOptions as LinkToAnotherRecordType).type === RelationTypes.MANY_TO_MANY + ) { + return JSON.stringify({ + rowId: extractPkFromRow(rowObj.row, meta.value?.columns as ColumnType[]), + columnId: columnObj.id, + fk_related_model_id: (columnObj.colOptions as LinkToAnotherRecordType).fk_related_model_id, + value: !isNaN(+textToCopy) ? +textToCopy : 0, + }) + } + return textToCopy } @@ -879,6 +893,99 @@ export function useMultiSelect( return await syncCellData?.({ ...activeCell, updatedColumnTitle: foreignKeyColumn.title }) } + if ( + columnObj.uidt === UITypes.Links && + (columnObj.colOptions as LinkToAnotherRecordType)?.type === RelationTypes.MANY_TO_MANY + ) { + const clipboardContext = JSON.parse(clipboardData) + if (clipboardContext?.fk_related_model_id !== (columnObj.colOptions as LinkToAnotherRecordType).fk_related_model_id) { + throw new Error('Invalid paste data for MM LTAR cell') + return + } + + let pasteVal = convertCellData( + { + value: clipboardContext, + to: columnObj.uidt as UITypes, + column: columnObj, + appInfo: unref(appInfo), + }, + isMysql(meta.value?.source_id), + ) + + console.log('paste data', clipboardContext, pasteVal) + const relatedTableMeta = await getMeta((columnObj.colOptions as LinkToAnotherRecordType).fk_related_model_id!) + + const extractedPk = extractPkFromRow(rowObj.row, meta.value?.columns as ColumnType[]) + if (!extractedPk) return + + const [copiedCellchildrenList, pasteCellchildrenList] = await Promise.all([ + api.dbDataTableRow.nestedList( + meta.value?.id as string, + columnObj.id as string, + encodeURIComponent((clipboardContext.rowId as string) || ''), + ), + api.dbDataTableRow.nestedList( + meta.value?.id as string, + columnObj.id as string, + encodeURIComponent(extractPkFromRow(rowObj.row, meta.value?.columns as ColumnType[]) || ''), + ), + ]) + + const relatedTablePrimaryKeys = (extractPk(relatedTableMeta?.columns as ColumnType[]) || '').split('__') + + function filterAndMapRows( + sourceList: Record[], + targetList: Record[], + primaryKeys: string[] = relatedTablePrimaryKeys, + ): Record[] { + return sourceList + .filter( + (sourceRow: Record) => + !targetList.some((targetRow: Record) => + primaryKeys.every((key) => sourceRow[key] === targetRow[key]), + ), + ) + .map((item: Record) => + primaryKeys.reduce((acc, key) => { + acc[key] = item[key] + return acc + }, {} as Record), + ) + } + + const filteredRowsToLink = filterAndMapRows(copiedCellchildrenList.list, pasteCellchildrenList.list) + + const filteredRowsToUnlink = filterAndMapRows(pasteCellchildrenList.list, copiedCellchildrenList.list) + + console.log('copied cell child list', copiedCellchildrenList) + console.log('paste cell child list', pasteCellchildrenList) + console.log('filtered', filteredRowsToLink, filteredRowsToUnlink) + + rowObj.row[columnObj.title!] = clipboardContext.value + + const result = await Promise.all([ + filteredRowsToLink.length && + api.dbDataTableRow.nestedLink( + meta.value?.id as string, + columnObj.id as string, + encodeURIComponent(extractPkFromRow(rowObj.row, meta.value?.columns as ColumnType[]) || ''), + filteredRowsToLink, + ), + filteredRowsToUnlink.length && + api.dbDataTableRow.nestedUnlink( + meta.value?.id as string, + columnObj.id as string, + encodeURIComponent(extractPkFromRow(rowObj.row, meta.value?.columns as ColumnType[]) || ''), + filteredRowsToUnlink, + ), + ]) + + console.log('result', result) + await syncCellData?.(activeCell) + return + } + if (!isPasteable(rowObj, columnObj, true)) { return }