From 5b3854b7724bd6249c21000ed9f7180741ad7504 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=8C=80=EC=97=B0?= Date: Wed, 20 Dec 2023 06:46:55 +0900 Subject: [PATCH] fix: cannot edit after sort (#2001) * test: add test * feat: forced make observable * fix: make viewport data and previously observable data to observable * fix: correct typo * chore: change params of makeObservable to object --- .../integration/combinedFeatureTest.spec.ts | 20 ++++++++++- packages/toast-ui.grid/src/dispatch/data.ts | 33 ++++++++++++------- packages/toast-ui.grid/src/dispatch/focus.ts | 4 +-- packages/toast-ui.grid/src/dispatch/sort.ts | 28 +++++++++++----- packages/toast-ui.grid/src/query/clipboard.ts | 2 +- packages/toast-ui.grid/src/query/data.ts | 4 +-- .../toast-ui.grid/src/query/validation.ts | 2 +- 7 files changed, 67 insertions(+), 26 deletions(-) diff --git a/packages/toast-ui.grid/cypress/integration/combinedFeatureTest.spec.ts b/packages/toast-ui.grid/cypress/integration/combinedFeatureTest.spec.ts index f308d7dec..910dea234 100644 --- a/packages/toast-ui.grid/cypress/integration/combinedFeatureTest.spec.ts +++ b/packages/toast-ui.grid/cypress/integration/combinedFeatureTest.spec.ts @@ -12,7 +12,7 @@ const PER_PAGE_COUNT = 10; const SCROLL_PER_PAGE_COUNT = 50; const columns = [ - { name: 'deliveryType', sortable: true, sortingType: 'desc', filter: 'text' }, + { name: 'deliveryType', sortable: true, sortingType: 'desc', filter: 'text', editor: 'text' }, { name: 'orderName', sortable: true }, ]; @@ -468,3 +468,21 @@ describe('pagination(infinite scroll) + filter + sort', () => { assertColumnData('deliveryType', 'Visit'); }); }); + +describe('editor + sort', () => { + beforeEach(() => { + createGrid(); + }); + + it('can editing cell after sort', () => { + cy.gridInstance().invoke('sort', 'orderName', true); + + cy.getCellByIdx(0, 0).should('not.have.text', 'Visit'); + + cy.gridInstance().invoke('startEditingAt', 0, 0); + cy.getByCls('content-text').type('Visit'); + cy.gridInstance().invoke('finishEditing'); + + cy.getCellByIdx(0, 0).should('have.text', 'Visit'); + }); +}); diff --git a/packages/toast-ui.grid/src/dispatch/data.ts b/packages/toast-ui.grid/src/dispatch/data.ts index 7f06304df..796248254 100644 --- a/packages/toast-ui.grid/src/dispatch/data.ts +++ b/packages/toast-ui.grid/src/dispatch/data.ts @@ -135,24 +135,33 @@ export function updateHeights(store: Store) { : filteredRawData.map((row) => getRowHeight(row, rowHeight)); } -export function makeObservable( - store: Store, - rowIndex: number, +export function makeObservable({ + store, + rowIndex, silent = false, - lazyObservable = false -) { + lazyObservable = false, + forced = false, +}: { + store: Store; + rowIndex: number; + silent?: boolean; + lazyObservable?: boolean; + forced?: boolean; +}) { const { data, column, id } = store; const { rawData, viewData } = data; const { treeColumnName } = column; const rawRow = rawData[rowIndex]; - if (isObservable(rawRow)) { + if (!forced && isObservable(rawRow)) { return; } if (treeColumnName) { const parentRow = findRowByRowKey(data, column, id, rawRow._attributes.tree!.parentRowKey); - rawData[rowIndex] = createTreeRawRow(id, rawRow, parentRow || null, column, { lazyObservable }); + rawData[rowIndex] = createTreeRawRow(id, rawRow, parentRow || null, column, { + lazyObservable, + }); } else { rawData[rowIndex] = createRawRow(id, rawRow, rowIndex, column, { lazyObservable }); } @@ -182,7 +191,7 @@ export function setValue( return; } if (checkCellState) { - makeObservable(store, rowIndex); + makeObservable({ store, rowIndex }); const { disabled, editable } = viewData[rowIndex].valueMap[columnName]; if (disabled || !editable) { @@ -607,7 +616,7 @@ export function appendRow(store: Store, row: OptRow, options: OptAppendRow) { silentSplice(rawData, at, 0, rawRow); silentSplice(viewData, at, 0, viewRow); - makeObservable(store, at); + makeObservable({ store, rowIndex: at }); updatePageOptions(store, { totalCount: pageOptions.totalCount! + 1 }); updateHeights(store); @@ -851,7 +860,7 @@ export function setRow(store: Store, rowIndex: number, row: OptRow) { silentSplice(rawData, rowIndex, 1, rawRow); silentSplice(viewData, rowIndex, 1, viewRow); - makeObservable(store, rowIndex); + makeObservable({ store, rowIndex }); sortByCurrentState(store); @@ -926,7 +935,9 @@ export function setRows(store: Store, rows: OptRow[]) { createdRowInfos .filter(({ rowIndex }) => isBetween(rowIndex, rowRange[0], rowRange[1])) - .forEach(({ rowIndex }) => makeObservable(store, rowIndex, false, true)); + .forEach(({ rowIndex }) => + makeObservable({ store, rowIndex, silent: false, lazyObservable: true }) + ); if (isRowSpanEnabled(sortState, column)) { createdRowInfos diff --git a/packages/toast-ui.grid/src/dispatch/focus.ts b/packages/toast-ui.grid/src/dispatch/focus.ts index 5441f42b1..3a027f5b7 100644 --- a/packages/toast-ui.grid/src/dispatch/focus.ts +++ b/packages/toast-ui.grid/src/dispatch/focus.ts @@ -24,7 +24,7 @@ export function startEditing(store: Store, rowKey: RowKey, columnName: string) { } // makes the data observable to judge editable, disable of the cell - makeObservable(store, findIndexByRowKey(data, column, id, rowKey, false)); + makeObservable({ store, rowIndex: findIndexByRowKey(data, column, id, rowKey, false) }); if (!isEditableCell(store, foundIndex, columnName)) { return; @@ -158,7 +158,7 @@ export function saveAndFinishEditing(store: Store, value?: string) { const { rowKey, columnName } = editingAddress; // makes the data observable to judge editable, disable of the cell. - makeObservable(store, findIndexByRowKey(data, column, id, rowKey, false)); + makeObservable({ store, rowIndex: findIndexByRowKey(data, column, id, rowKey, false) }); // if value is 'undefined', editing result is saved and finished. if (isUndefined(value)) { diff --git a/packages/toast-ui.grid/src/dispatch/sort.ts b/packages/toast-ui.grid/src/dispatch/sort.ts index 029f41627..ca1f7d27e 100644 --- a/packages/toast-ui.grid/src/dispatch/sort.ts +++ b/packages/toast-ui.grid/src/dispatch/sort.ts @@ -3,23 +3,23 @@ import { Data, ViewRow, Row } from '@t/store/data'; import { SortingType } from '@t/store/column'; import { SortStateResetOption } from '@t/options'; import { findPropIndex, isUndefined } from '../helper/common'; -import { notify, unobservable } from '../helper/observable'; +import { isObservable, notify } from '../helper/observable'; import { sortRawData } from '../helper/sort'; import { getEventBus } from '../event/eventBus'; -import { updateRowNumber, setCheckedAllRows } from './data'; +import { updateRowNumber, setCheckedAllRows, makeObservable } from './data'; import { isSortable, isInitialSortState, isScrollPagination, isSorted } from '../query/data'; import { isComplexHeader } from '../query/column'; import { isCancelSort, createSortEvent, EventType, EventParams } from '../query/sort'; import { updateRowSpan } from './rowSpan'; -function createSoretedViewData(rawData: Row[]) { +function createSortedViewData(rawData: Row[]) { return rawData.map( ({ rowKey, sortKey, uniqueKey }) => ({ rowKey, sortKey, uniqueKey } as ViewRow) ); } function sortData(store: Store) { - const { data, column } = store; + const { data, column, viewport } = store; const { sortState, rawData, viewData, pageRowRange } = data; const { columns } = sortState; const sortedColumns = columns.map((sortedColumn) => ({ @@ -33,17 +33,29 @@ function sortData(store: Store) { targetRawData.sort(sortRawData(sortedColumns)); - const targetViewData = createSoretedViewData(targetRawData); + const targetViewData = createSortedViewData(targetRawData); data.rawData = targetRawData.concat(rawData.slice(pageRowRange[1])); data.viewData = targetViewData.concat(viewData.slice(pageRowRange[1])); } else { rawData.sort(sortRawData(sortedColumns)); - data.viewData = createSoretedViewData(rawData); + data.viewData = createSortedViewData(rawData); } - data.rawData.forEach((rawRow) => { - unobservable(rawRow); + const rowKeysInViewport = viewport.rows.map(({ rowKey }) => rowKey); + + data.rawData.forEach((rawRow, index) => { + const { rowKey } = rawRow; + + if (isObservable(rawRow) || rowKeysInViewport.includes(rowKey)) { + makeObservable({ + store, + rowIndex: index, + silent: false, + lazyObservable: false, + forced: true, + }); + } }); } diff --git a/packages/toast-ui.grid/src/query/clipboard.ts b/packages/toast-ui.grid/src/query/clipboard.ts index 60656b048..528e4c3f6 100644 --- a/packages/toast-ui.grid/src/query/clipboard.ts +++ b/packages/toast-ui.grid/src/query/clipboard.ts @@ -63,7 +63,7 @@ function getObservableList(store: Store, filteredViewData: ViewRow[], start: num for (let i = start; i <= end; i += 1) { if (!isObservable(filteredViewData[i].valueMap)) { - makeObservable(store, i, true); + makeObservable({ store, rowIndex: i, silent: true }); if (i === end) { notify(store.data, 'rawData', 'filteredRawData', 'viewData', 'filteredViewData'); diff --git a/packages/toast-ui.grid/src/query/data.ts b/packages/toast-ui.grid/src/query/data.ts index 7d079999e..6cc0394b6 100644 --- a/packages/toast-ui.grid/src/query/data.ts +++ b/packages/toast-ui.grid/src/query/data.ts @@ -45,7 +45,7 @@ export function isEditableCell(store: Store, rowIndex: number, columnName: strin // get index based on whole data(not filtered data) const index = filteredIndex ? filteredIndex[rowIndex] : rowIndex; - makeObservable(store, index, true); + makeObservable({ store, rowIndex: index, silent: true }); const { disabled, editable } = filteredViewData[rowIndex].valueMap[columnName]; @@ -303,7 +303,7 @@ export function getFormattedValue(store: Store, rowKey: RowKey, columnName: stri const { viewData } = data; if (rowIndex !== -1) { - makeObservable(store, rowIndex); + makeObservable({ store, rowIndex }); const viewCell = viewData[rowIndex].valueMap[columnName]; return viewCell ? viewCell.formattedValue : null; } diff --git a/packages/toast-ui.grid/src/query/validation.ts b/packages/toast-ui.grid/src/query/validation.ts index 791ad95bc..f89096e11 100644 --- a/packages/toast-ui.grid/src/query/validation.ts +++ b/packages/toast-ui.grid/src/query/validation.ts @@ -11,7 +11,7 @@ export function getInvalidRows(store: Store, rowKeys?: RowKey[]) { const needToValidateRow = !rowKeys || rowKeys.includes(row.rowKey); if (!isObservable(row) && needToValidateRow) { - makeObservable(store, rowIndex, true); + makeObservable({ store, rowIndex, silent: true }); } });