Skip to content

Commit 626ea98

Browse files
authored
fix: paste relative (#1953)
* fix: add link list exceed tips * perf: add more selection type for clear、paste * chore: delete unnecessary code
1 parent e412ab2 commit 626ea98

9 files changed

Lines changed: 223 additions & 149 deletions

File tree

apps/nextjs-app/src/features/app/blocks/view/grid/GridViewBaseInner.tsx

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ import {
7878
useRecordOperations,
7979
useButtonClickStatus,
8080
} from '@teable/sdk/hooks';
81-
import { ConfirmDialog, useToast } from '@teable/ui-lib';
81+
import { ConfirmDialog, useConfirm, useToast } from '@teable/ui-lib';
8282
import { toast as sonnerToast } from '@teable/ui-lib/shadcn/ui/sonner';
8383
import { isEqual, keyBy, uniqueId, groupBy } from 'lodash';
8484
import { useRouter } from 'next/router';
@@ -102,6 +102,7 @@ import { DomBox } from './DomBox';
102102
import { useCollaborate, useSelectionOperation } from './hooks';
103103
import { useIsSelectionLoaded } from './hooks/useIsSelectionLoaded';
104104
import { useGridSearchStore } from './useGridSearchStore';
105+
import { getEffectRows } from './utils';
105106

106107
interface IGridViewBaseInnerProps {
107108
groupPointsServerData?: IGroupPointsVo;
@@ -392,7 +393,7 @@ export const GridViewBaseInner: React.FC<IGridViewBaseInnerProps> = (
392393
[recordMap, columns, t]
393394
);
394395

395-
// const { confirm } = useConfirm();
396+
const { confirm } = useConfirm();
396397

397398
// eslint-disable-next-line sonarjs/cognitive-complexity
398399
const onContextMenu = (selection: CombinedSelection, position: IPosition) => {
@@ -419,26 +420,20 @@ export const GridViewBaseInner: React.FC<IGridViewBaseInnerProps> = (
419420
position,
420421
isMultipleSelected,
421422
deleteRecords: async () => {
422-
// const [startRange, endRange] = selection.ranges;
423-
424-
// if (startRange && endRange) {
425-
// const [, startRow] = startRange;
426-
// const [, endRow] = endRange;
427-
// const deleteRows = endRow - startRow + 1;
428-
429-
// if (deleteRows >= 10) {
430-
// const confirmed = await confirm({
431-
// title: t('table:table.actionTips.deleteRecordConfirmTitle'),
432-
// description: t('table:table.actionTips.deleteRecordConfirmDescription', {
433-
// recordCount: deleteRows,
434-
// }),
435-
// confirmText: t('table:table.actionTips.deleteRecord'),
436-
// cancelText: t('common:actions.cancel'),
437-
// confirmButtonVariant: 'destructive',
438-
// });
439-
// if (!confirmed) return;
440-
// }
441-
// }
423+
const deleteRows = getEffectRows(selection);
424+
425+
if (deleteRows >= 10) {
426+
const confirmed = await confirm({
427+
title: t('table:table.actionTips.deleteRecordConfirmTitle'),
428+
description: t('table:table.actionTips.deleteRecordConfirmDescription', {
429+
recordCount: deleteRows,
430+
}),
431+
confirmText: t('table:table.actionTips.deleteRecord'),
432+
cancelText: t('common:actions.cancel'),
433+
confirmButtonVariant: 'destructive',
434+
});
435+
if (!confirmed) return;
436+
}
442437

443438
deleteRecords(selection);
444439
gridRef.current?.setSelection(emptySelection);

apps/nextjs-app/src/features/app/blocks/view/grid/hooks/useSelectionOperation.ts

Lines changed: 66 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -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';
3234
import { toast } from '@teable/ui-lib/shadcn/ui/sonner';
3335
import type { AxiosResponse } from 'axios';
3436
import { useTranslation } from 'next-i18next';
3537
import { useCallback } from 'react';
3638
import { isHTTPS, isLocalhost } from '@/features/app/utils';
3739
import { serializerCellValueHtml, serializerHtml } from '@/features/app/utils/clipboard';
3840
import { tableConfig } from '@/features/i18n/table.config';
39-
import { selectionCoverAttachments } from '../utils';
41+
import { getEffectCellCount, getEffectRows, selectionCoverAttachments } from '../utils';
4042
import {
4143
ClipboardTypes,
4244
copyHandler,
4345
filePasteHandler,
46+
getCellPasteInfo,
4447
rangeTypes,
45-
textPasteHandler,
48+
textPasteHandlerWithData,
4649
} from '../utils/copyAndPaste';
4750
import { getSyncCopyData } from '../utils/getSyncCopyData';
4851
import { 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

Comments
 (0)