Skip to content

Refactor DynamicDataTable - #1914

Open
BenjaminCharmes wants to merge 12 commits into
mainfrom
bc/refactor-dynamicdatatable
Open

Refactor DynamicDataTable#1914
BenjaminCharmes wants to merge 12 commits into
mainfrom
bc/refactor-dynamicdatatable

Conversation

@BenjaminCharmes

Copy link
Copy Markdown
Contributor

Closes #1712

Summary

  • DynamicDataTable is now a thin, generic wrapper over PrimeVue DataTable — no more hardcoded field names, v-else-if filter chains, or central getComponentProps registry
  • Column descriptors own their body component, filter component, match function, and options provider; adding a new item type only requires editing the consumer
  • Extracted reusable filter components (TextFilter, MultiSelectFilter, SingleSelectFilter, DateRangeFilter, CreatorsAndGroupsFilter) and shared match/options helpers into utils/filterMatchers.js
  • Dynamic FilterService matcher registration from descriptors, scoped per dataType to avoid global collisions
  • Cleanup: allUsers passed as an explicit prop, body events forwarded generically via column.body.events, filterOptionsCache receives store.state rather than the full store

@codecov

codecov Bot commented Jul 13, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 80.27%. Comparing base (cd0b699) to head (7fd5426).

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #1914   +/-   ##
=======================================
  Coverage   80.27%   80.27%           
=======================================
  Files          83       83           
  Lines        7616     7616           
=======================================
  Hits         6114     6114           
  Misses       1502     1502           
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@cypress

cypress Bot commented Jul 13, 2026

Copy link
Copy Markdown

datalab    Run #5304

Run Properties:  status check passed Passed #5304  •  git commit 3a2178649f ℹ️: Merge 7fd5426635916e3640d339c33fa7947da093c00d into cd0b699a322e311dc99febc8945d...
Project datalab
Branch Review bc/refactor-dynamicdatatable
Run status status check passed Passed #5304
Run duration 22m 24s
Commit git commit 3a2178649f ℹ️: Merge 7fd5426635916e3640d339c33fa7947da093c00d into cd0b699a322e311dc99febc8945d...
Committer Ben Charmes
View all properties for this run ↗︎

Test results
Tests that failed  Failures 0
Tests that were flaky  Flaky 0
Tests that did not run due to a developer annotating a test with .skip  Pending 0
Tests that did not run due to a failure in a mocha hook  Skipped 0
Tests that passed  Passing 548
View all changes introduced in this branch ↗︎

@BenjaminCharmes
BenjaminCharmes marked this pull request as ready for review July 18, 2026 17:31
@BenjaminCharmes
BenjaminCharmes requested a review from ml-evs July 27, 2026 14:26
@BenjaminCharmes

Copy link
Copy Markdown
Contributor Author

@ml-evs I forgot to ping you for a review!

@ml-evs ml-evs added this to the v0.8.x milestone Aug 9, 2026
@ml-evs

ml-evs commented Aug 9, 2026

Copy link
Copy Markdown
Member

Also pining @DianaAliabieva and @davidwaroquiers for review here as they have been working on this component and will likely need to base their changes on this!

@ml-evs ml-evs left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this @BenjaminCharmes, looks great! Would you mind incorporating the changes from #1910 before we merge this? I had a look and not entirely sure how I would do it with the current conflicts. Thanks!

@BenjaminCharmes

Copy link
Copy Markdown
Contributor Author

Thanks for this @BenjaminCharmes, looks great! Would you mind incorporating the changes from #1910 before we merge this? I had a look and not entirely sure how I would do it with the current conflicts. Thanks!

Yes, I'll have a look !

ml-evs and others added 8 commits August 10, 2026 12:27
… API response

Only bump item last_modified when a version is actually minted

Add some testing and handling of millisecond edge cases when rehydrating date from db

Refactor UTC handler into separate function

Update relevant table tests to include new column

Tidy up comments

Remove misleading comment

(cherry picked from commit e9c7f6b)
Reintroduce chemform

(cherry picked from commit d236324)
…e preferences so new columns default to shown

(cherry picked from commit 2b8f5aa)
…tatable

# Conflicts:
#	pydatalab/src/pydatalab/routes/v0_1/items.py
#	webapp/src/components/CollectionInformation.vue
#	webapp/src/components/DynamicDataTable.vue
@BenjaminCharmes
BenjaminCharmes requested a review from ml-evs August 11, 2026 14:39
@BenjaminCharmes

Copy link
Copy Markdown
Contributor Author

@ml-evs Everything should be good now, let me know if you need anything else!

DianaAliabieva added a commit to Matgenix/datalab that referenced this pull request Aug 11, 2026
…atalab-org#1914)

Adapts the clear-filters column/button to the new columns-driven filter
setup from datalab-org#1914: extracts default-filters construction into
getDefaultFilters() so it can be reused both on created() and when
clearing, adds hasActiveFilters, and updates the 4 component tests for
the extra header column.
@davidwaroquiers

davidwaroquiers commented Aug 12, 2026

Copy link
Copy Markdown
Member

Also pining @DianaAliabieva and @davidwaroquiers for review here as they have been working on this component and will likely need to base their changes on this!

Hi @ml-evs

Thank you for pinning us. I don't have time to make a thorough review right now (currently on holidays) but here is maybe my comment after a very quick look. This is a very nice work to make the Dynamic data table more generic and thanks @BenjaminCharmes for this. I was wondering if the associated table buttons could (or should) also be somehow described declaratively in the actual tables rather than being hardcoded in DynamicDataTable/DynamicDataTableButtons. Somehow the goal of the PR is to extract all references to actual tables from the DynamicDataTable component to the actual components (e.g. EquipmentTable, SampleTable, ...). What do you think ?

I can make a more thorough review when I'm back in the week of 24-28 August but if you'd prefer to get this merged sooner, please go ahead. Regarding PRs that are somehow related to this one (from me and/or @DianaAliabieva), we will refactor them based on these changes, I think the best is to get this through and rebase/refactor our own PRs.

@DianaAliabieva DianaAliabieva left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello! I tried to review this PR!
For me everything looks great, only one thing about lost filter values
Have a nice day!

}),
},
},
{

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this file got missed during the filter migration. On main, these three columns all had filter: true:

{ field: "date", header: "Date", label: "Date", filter: true },
{ field: "creatorsAndGroups", ..., filter: true },
{ field: "blocks", ..., filter: true },
In the refactored version they only kept getValue/body for rendering the filter key is just gone, and none of DateRangeFilter, CreatorsAndGroupsFilter, or matchBlocks/blocksOptions are imported at the top of the file (only TextFilter and MultiSelectFilter made it in, for the id/type/status columns).

So they are lost kinda, maybe we should return them? or it was a plan to do like that?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the filters should indeed stay the same unless this is intentional ?

@davidwaroquiers davidwaroquiers left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @BenjaminCharmes and @ml-evs

Thanks for the nice work, this was indeed a good idea to refactor this big chunk of code that was becoming more and more complex. I have a couple of small comments in the code, not directly related to this PR but that I believe are worth fixing here anyway (should be easy to fix, could even be in a separate PR if easier or want to completely separate concerns).

I already mentioned this in a comment, but a nice extension of this work would be to apply the same declarative approach to the toolbar buttons and bulk actions. The columns are now declared by each concrete table, while the toolbar and bulk actions are still centralized and selected through dataType-specific conditions. Each table could instead declare the actions it supports (including their label, visibility, disabled state, and handler) leaving the generic components responsible only for rendering them and managing shared UI. This could also be considered as a second phase or a separate PR if it feels too broad for this refactoring but I think it would make things even more clean and modular.

Happy to discuss if needed.

}

return visibleItems.every((currentItem) => {
const currentId = currentItem.item_id || currentItem.collection_id;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not directly related to this PR itself but I found out while reviewing. This seems like a bug. Identifying a specific row is based either on item_id or collection_id but for the other tables (users, groups, access tokens), e.g. those of the admin view, the key for identifying a row is different (immutable_id, group_id, _id). This leads to a bug when selecting users/groups/tokens.

To reproduce the bug, go for example in users and select one user:

Image

You get "1 selected" for the dropdown menu of bulk actions.

Then do select all (top left checkbox to select all):

Image

And only the previously selected user stays selected, others stay unselected (and the dropdown menu shows "1 selected").

The easiest fix would be to add a id_key string to specify which key is used to identify a row (user/item/group/...) uniquely.

Although this is not directly related to this refactoring I think it would be good to fix it here already.

}),
},
},
{

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the filters should indeed stay the same unless this is intentional ?

ref="datatable"
v-model:filters="filters"
v-model:selection="itemsSelected"
v-model:select-all="allSelected"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not directly related to this PR but probably easy to fix it here (or in another PR).

Currently if you select all rows (using the top left checkbox) then deselecting just one row keeps the selected all checkbox checked.

I think allSelected should be recomputed both upon row selection and deselection.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Refactoring the dynamic data table

4 participants