Skip to content

Commit

Permalink
Ensure Tabulator selection is updated when indexes change (#7066)
Browse files Browse the repository at this point in the history
  • Loading branch information
philippjfr authored Aug 3, 2024
1 parent a93b609 commit 7adcf3d
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 16 deletions.
5 changes: 4 additions & 1 deletion panel/tests/ui/widgets/test_tabulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -1968,7 +1968,6 @@ def test_tabulator_header_filters_default(page, df_mixed, cols):
([0, 1], 'input[type="number"]'),
(np.array([0, 1], dtype=np.uint64), 'input[type="number"]'),
([0.1, 1.1], 'input[type="number"]'),
# ([True, False], 'input[type="checkbox"]'), # Pandas cannot have boolean indexes apparently
),
)
def test_tabulator_header_filters_default_index(page, index, expected_selector):
Expand Down Expand Up @@ -3506,6 +3505,8 @@ def test_range_selection_on_sorted_data_downward(page, pagination):

page.locator('.tabulator-col-title-holder').nth(2).click()

page.wait_for_timeout(100)

page.locator('.tabulator-row').nth(0).click()

page.keyboard.down('Shift')
Expand All @@ -3524,6 +3525,8 @@ def test_range_selection_on_sorted_data_upward(page, pagination):

page.locator('.tabulator-col-title-holder').nth(2).click()

page.wait_for_timeout(100)

page.locator('.tabulator-row').nth(1).click()

page.keyboard.down('Shift')
Expand Down
9 changes: 9 additions & 0 deletions panel/tests/widgets/test_tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,15 @@ def test_none_table(document, comm):
assert model.source.data == {}


def test_tabulator_selection_resets():
df = makeMixedDataFrame()
table = Tabulator(df, selection=list(range(len(df))))

for i in reversed(range(len(df))):
table.value = df.iloc[:i]
assert table.selection == list(range(i))


def test_tabulator_selected_dataframe():
df = makeMixedDataFrame()
table = Tabulator(df, selection=[0, 2])
Expand Down
45 changes: 30 additions & 15 deletions panel/widgets/tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,10 @@ def __init__(self, value=None, **params):
self._index_mapping = {}
self._edited_indexes = []
super().__init__(value=value, **params)
self.param.watch(self._setup_on_change, ['editors', 'formatters'])
self._internal_callbacks.extend([
self.param.watch(self._setup_on_change, ['editors', 'formatters']),
self.param._watch(self._reset_selection, ['value'], precedence=-1)
])
self.param.trigger('editors')
self.param.trigger('formatters')

Expand All @@ -129,6 +132,32 @@ def _compute_renamed_cols(self):
str(col) if str(col) != col else col: col for col in self._get_fields()
}

def _reset_selection(self, event):
if event.type == 'triggered' and self._updating:
return
if self._indexes_changed(event.old, event.new):
selection = []
for sel in self.selection:
idx = event.old.index[sel]
try:
new = event.new.index.get_loc(idx)
selection.append(new)
except KeyError:
pass
self.selection = selection

def _indexes_changed(self, old, new):
"""
Comparator that checks whether DataFrame indexes have changed.
If indexes and length are unchanged we assume we do not
have to reset various settings including expanded rows,
scroll position, pagination etc.
"""
if type(old) != type(new) or isinstance(new, dict) or len(old) != len(new):
return True
return (old.index != new.index).any()

@property
def _length(self):
return len(self._processed)
Expand Down Expand Up @@ -1495,20 +1524,6 @@ def _get_model_children(self, panels, doc, root, parent, comm=None):
models[i] = model
return models

def _indexes_changed(self, old, new):
"""
Comparator that checks whether DataFrame indexes have changed.
If indexes and length are unchanged we assume we do not
have to reset various settings including expanded rows,
scroll position, pagination etc.
"""
if type(old) != type(new) or isinstance(new, dict):
return True
elif len(old) != len(new):
return False
return (old.index != new.index).any()

def _update_children(self, *events):
cleanup, reuse = set(), set()
page_events = ('page', 'page_size', 'pagination')
Expand Down

0 comments on commit 7adcf3d

Please sign in to comment.