@@ -28,21 +28,24 @@ import {
2828 usePersonalView ,
2929 getHttpErrorMessage ,
3030 LARGE_QUERY_THRESHOLD ,
31+ useRowCount ,
3132} from '@teable/sdk' ;
33+ import { useConfirm } from '@teable/ui-lib/base' ;
3234import { toast } from '@teable/ui-lib/shadcn/ui/sonner' ;
3335import type { AxiosResponse } from 'axios' ;
3436import { useTranslation } from 'next-i18next' ;
3537import { useCallback } from 'react' ;
3638import { isHTTPS , isLocalhost } from '@/features/app/utils' ;
3739import { serializerCellValueHtml , serializerHtml } from '@/features/app/utils/clipboard' ;
3840import { tableConfig } from '@/features/i18n/table.config' ;
39- import { selectionCoverAttachments } from '../utils' ;
41+ import { getEffectCellCount , getEffectRows , selectionCoverAttachments } from '../utils' ;
4042import {
4143 ClipboardTypes ,
4244 copyHandler ,
4345 filePasteHandler ,
46+ getCellPasteInfo ,
4447 rangeTypes ,
45- textPasteHandler ,
48+ textPasteHandlerWithData ,
4649} from '../utils/copyAndPaste' ;
4750import { getSyncCopyData } from '../utils/getSyncCopyData' ;
4851import { useSyncSelectionStore } from './useSelectionStore' ;
@@ -62,6 +65,7 @@ export const useSelectionOperation = (props?: {
6265 const view = useView ( ) ;
6366 const { searchQuery : search } = useSearch ( ) ;
6467 const { personalViewCommonQuery } = usePersonalView ( ) ;
68+ const rowCount = useRowCount ( ) ;
6569
6670 // Parameters for retrieving selected records in plugins
6771 useSyncSelectionStore ( {
@@ -213,21 +217,7 @@ export const useSelectionOperation = (props?: {
213217 [ checkCopyAndPasteEnvironment , viewId , tableId , copyRequest , t ]
214218 ) ;
215219
216- // const getPasteDescription = useCallback(
217- // (cellCount: number, selectionRows: number, expandRowCount: number, expandColCount: number) => {
218- // const isExpandRow = expandRowCount > 0;
219- // const isExpandCol = expandColCount > 0;
220- // const isExpand = isExpandRow || isExpandCol;
221- // return isExpand
222- // ? `${t('table:table.actionTips.expandCommonDescription')} ${isExpandRow ? t('table:table.actionTips.expandRowDescription', { count: expandRowCount }) : ''} ${isExpandRow && isExpandCol ? t('table:table.actionTips.conjunction') : ''} ${isExpandCol ? t('table:table.actionTips.expandColDescription', { count: expandColCount }) : ''}`
223- // : `
224- // ${t('table:table.actionTips.pasteConfirmDescription', {
225- // cellCount: cellCount,
226- // recordCount: selectionRows,
227- // }) }`;
228- // },
229- // [t]
230- // );
220+ const { confirm } = useConfirm ( ) ;
231221
232222 const doPaste = useCallback (
233223 async (
@@ -238,60 +228,42 @@ export const useSelectionOperation = (props?: {
238228 ) => {
239229 if ( ! viewId || ! tableId ) return ;
240230
241- // const [startRange, endRange] = selection.ranges;
242- // const [startCol, startRow] = startRange;
243- // const [, endRow] = endRange;
244- // const selectionRows = endRow - startRow + 1;
245- // const cellCount = getEffectCellCount(selection, fields);
246- // const { cellValues } = getCellPasteInfo(e);
247-
248- // const computedFieldIndexes = [] as number[];
249- // fields.forEach((field, index) => {
250- // if (field.isComputed && index >= startCol) {
251- // computedFieldIndexes.push(index);
252- // }
253- // });
254-
255- // const pasteRecordLength = cellValues?.length ?? 0;
256-
257- // const { isExpand, expandRowCount, expandColCount } = getExpandInfo(
258- // rowCount,
259- // startRow,
260- // startCol,
261- // fields,
262- // computedFieldIndexes,
263- // cellValues
264- // );
265-
266- // if (isExpand || pasteRecordLength >= 10) {
267- // const description = getPasteDescription(
268- // cellCount,
269- // selectionRows,
270- // expandRowCount,
271- // expandColCount
272- // );
273- // const confirmed = await confirm({
274- // title: t('table:table.actionTips.pasteConfirmTitle'),
275- // description,
276- // confirmText: t('table:table.actionTips.paste'),
277- // cancelText: t('common:actions.cancel'),
278- // confirmButtonVariant: 'destructive',
279- // });
280- // if (!confirmed) return;
281- // }
282-
283231 const { files, types } = e . clipboardData ;
232+ const hasHtml = types . includes ( ClipboardTypes . html ) ;
233+ const html = hasHtml ? e . clipboardData . getData ( ClipboardTypes . html ) : '' ;
234+ const text = types . includes ( ClipboardTypes . text )
235+ ? e . clipboardData . getData ( ClipboardTypes . text )
236+ : '' ;
237+ const fileArray = Array . from ( files ) as unknown as FileList ;
238+
239+ const { cellValues } = getCellPasteInfo ( e ) ;
240+
241+ const pasteRecordLength = cellValues ?. length ?? 0 ;
242+
243+ if ( pasteRecordLength >= 10 ) {
244+ const confirmed = await confirm ( {
245+ title : t ( 'table:table.actionTips.pasteConfirmTitle' ) ,
246+ description : t ( 'table:table.actionTips.pasteConfirmDescription' , {
247+ recordCount : pasteRecordLength ,
248+ } ) ,
249+ confirmText : t ( 'table:table.actionTips.paste' ) ,
250+ cancelText : t ( 'common:actions.cancel' ) ,
251+ confirmButtonVariant : 'destructive' ,
252+ } ) ;
253+ if ( ! confirmed ) return ;
254+ }
255+
284256 const toastId = toast . loading ( t ( 'table:table.actionTips.pasting' ) ) ;
285257
286258 try {
287- if ( files . length > 0 && ! types . includes ( ClipboardTypes . text ) ) {
259+ if ( fileArray . length > 0 && ! types . includes ( ClipboardTypes . text ) ) {
288260 const isSelectionCoverAttachments = selectionCoverAttachments ( selection , fields ) ;
289261 if ( ! isSelectionCoverAttachments ) {
290262 toast . error ( t ( 'table:table.actionTips.pasteFileFailed' ) , { id : toastId } ) ;
291263 return ;
292264 }
293265 await filePasteHandler ( {
294- files,
266+ files : fileArray ,
295267 fields,
296268 selection,
297269 recordMap,
@@ -313,17 +285,21 @@ export const useSelectionOperation = (props?: {
313285 } ,
314286 } ) ;
315287 } else {
316- await textPasteHandler ( e , selection , async ( content , type , ranges , header ) => {
317- if ( ! content ) {
318- return ;
319- }
320- if ( updateTemporaryData ) {
321- const res = await temporaryPasteReq ( { content, ranges, header } ) ;
322- updateTemporaryData ( res . data ) ;
323- } else {
324- await pasteReq ( { content, type, ranges, header } ) ;
288+ await textPasteHandlerWithData (
289+ { html, text, hasHtml } ,
290+ selection ,
291+ async ( content , type , ranges , header ) => {
292+ if ( ! content ) {
293+ return ;
294+ }
295+ if ( updateTemporaryData ) {
296+ const res = await temporaryPasteReq ( { content, ranges, header } ) ;
297+ updateTemporaryData ( res . data ) ;
298+ } else {
299+ await pasteReq ( { content, type, ranges, header } ) ;
300+ }
325301 }
326- } ) ;
302+ ) ;
327303 }
328304 toast . success ( t ( 'table:table.actionTips.pasteSuccessful' ) , { id : toastId } ) ;
329305 } catch ( e ) {
@@ -336,41 +312,29 @@ export const useSelectionOperation = (props?: {
336312 console . error ( 'Paste error: ' , error ) ;
337313 }
338314 } ,
339- [ viewId , tableId , fields , t , baseId , temporaryPasteReq , pasteReq ]
315+ [ viewId , tableId , fields , t , confirm , baseId , temporaryPasteReq , pasteReq ]
340316 ) ;
341317
342318 const doClear = useCallback (
343319 async ( selection : CombinedSelection ) => {
344320 if ( ! viewId || ! tableId ) return ;
345- // const calFieldsIndex = [] as number[];
346- // fields.forEach((field, index) => {
347- // if (field.isComputed) {
348- // calFieldsIndex.push(index);
349- // }
350- // });
351- // const [startRange, endRange] = selection.ranges;
352-
353- // if (startRange && endRange) {
354- // const [, startRow] = startRange;
355- // const [, endRow] = endRange;
356- // const deleteRows = endRow - startRow + 1;
357-
358- // const cellCount = getEffectCellCount(selection, fields);
359-
360- // if (deleteRows >= 10 && cellCount) {
361- // const confirmed = await confirm({
362- // title: t('table:table.actionTips.clearConfirmTitle'),
363- // description: t('table:table.actionTips.clearConfirmDescription', {
364- // cellCount: cellCount,
365- // rowCount: deleteRows,
366- // }),
367- // confirmText: t('table:table.actionTips.clear'),
368- // cancelText: t('common:actions.cancel'),
369- // confirmButtonVariant: 'destructive',
370- // });
371- // if (!confirmed) return;
372- // }
373- // }
321+
322+ const effectRows = getEffectRows ( selection ) ;
323+ const effectCells = getEffectCellCount ( selection , fields , rowCount ) ;
324+
325+ if ( effectRows >= 10 && effectCells ) {
326+ const confirmed = await confirm ( {
327+ title : t ( 'table:table.actionTips.clearConfirmTitle' ) ,
328+ description : t ( 'table:table.actionTips.clearConfirmDescription' , {
329+ cellCount : effectCells ,
330+ rowCount : effectRows ,
331+ } ) ,
332+ confirmText : t ( 'table:table.actionTips.clear' ) ,
333+ cancelText : t ( 'common:actions.cancel' ) ,
334+ confirmButtonVariant : 'destructive' ,
335+ } ) ;
336+ if ( ! confirmed ) return ;
337+ }
374338
375339 const toastId = toast . loading ( t ( 'table:table.actionTips.clearing' ) , { id : clearToastId } ) ;
376340 const ranges = selection . serialize ( ) ;
@@ -383,7 +347,7 @@ export const useSelectionOperation = (props?: {
383347
384348 toast . success ( t ( 'table:table.actionTips.clearSuccessful' ) , { id : toastId } ) ;
385349 } ,
386- [ viewId , tableId , t , clearReq ]
350+ [ viewId , tableId , fields , rowCount , t , clearReq , confirm ]
387351 ) ;
388352
389353 const doDelete = useCallback (
0 commit comments