zauberzeug / nicegui

Create web-based user interfaces with Python. The nice way.
https://nicegui.io
MIT License
8.93k stars 542 forks source link

Integration of Quasar's table component #370

Closed rbeeli closed 1 year ago

rbeeli commented 1 year ago

Currently, there is a Table component wrapping AG Grid. Given that nicegui mostly relies on Quasar components, it's surprising that AG Grid was integrated instead of Quasar's Table component.

What are the strong advantages of AG Grid over Quasar's Table?

I see many possible issues regarding this choice:

Are there any plans to integrate Quasar's table?

falkoschindler commented 1 year ago

Thanks for bringing this up, @rbeeli! That's an interesting point.

Originally, NiceGUI was built on top of JustPy, which in turn has a pretty strong AG Grid integration. Once we needed something for displaying tabular information, this was an easy choice. Especially its API, simply putting everything into a dictionary and sending it to the client, was very convenient as we wouldn't need to re-implement a large and complicated interface. Quasar's QTable on the other hand - although with a very nice look and feel - seemed to be a bit more complicated to integrate. At least that's what I thought back then, with my limited understanding of JustPy, Quasar, and Vue at that time.

But maybe we should re-evaluate this decision. It looks like one can also pass data as rows and columns to the table and configure it with a huge collection of props. I could imagine spiking a ui.qtable element and eventually renaming ui.table to ui.aggrid and ui.qtable to ui.table (something we did with ui.plot, splitting it into ui.pyplot and ui.plotly).

Of course one could argue to ditch AG Grid altogether. But this would be a huge break and there seem to be quite some people using it. And NiceGUI has always been not only an engine, but also a collection of useful components ("batteries included"). So I think it's worth keeping it around for now.

Diegiwg commented 1 year ago

@rbeeli, your question is valid indeed.

Your could, if you want, open a PR, starting the implementation, so other people can continue, and maybe create the second table widget, as suggested by @falkoschindler.

rbeeli commented 1 year ago

Maybe some kind of plugin system with additional packages could be the way to go? Meaning most components, if sufficient, are based on Quasar, which is the base UI library anyways. If users want Tailwind, Plotly, High Charts, AG Grid, etc., some kind of additional plugins to load would be nice. This would also help with community contributions, if people want to make their own plugin without directly commiting into the core repository. I think there are advantages in having a stable, streamlined and lean core based on Quasar, which in my experience is an excellent UI library covering most needs.

Not sure how/what you are doing elsewhere regarding plugins and optional components. If you package all possible 3rd party components by default, the library will quickly have 100 MB+, today's JavaScript libraries have gotten quite large.

Quasar's table definition is mostly declarative, i.e. simple JavaScript objects which look like JSON, apart from some selection and formatting functions. The challenge would be how to model the JavaScript properties and functions in Python in a neat way, e.g. just a special Python string, which is eval'ed on component rendering?

@falkoschindler I like your naming suggestion, exactly how I would do it.

Diegiwg commented 1 year ago

I was testing an early implementation of Table from Quasar.

I managed to get the part of defining the columns to work, and the 'lines of information'.

However, I can't get the selection system to work. The checkboxes are enabled, however, there is no point in clicking, as the click does not count.

Current element code link: https://gist.github.com/Diegiwg/f85e007d243c96c9576016bb903ced93

Example of use:

from nicegui import ui
from requests import get

from quasar import *

table = table()
table.selection.type("single")

table.columns.add("title", "Title", "title")
table.columns.add("completed", "Completed", "completed")

ui.button("Add ID column", on_click=lambda: table.columns.add("id", "id", "id"))

req = get("https://jsonplaceholder.typicode.com/todos")
todos = req.json()

for todo in todos:
    table.rows.add(todo)
falkoschindler commented 1 year ago

@Diegiwg We probably need to handle selection events and send the modified list of selected rows back to the client. That's how we do it for QTree. Have a look at tree.py. Maybe you can transfer the pattern to QTable.

falkoschindler commented 1 year ago

@Diegiwg, @dclause I'm a bit behind with reviewing/thinking about your PR's #434, #500 and related issues like #501. But I'm planning to look into it next week.