Skip to content

Grid pages in applications (frontend) #3099

Open

Description

@enjeck

We would like for a Tables application becomes a small app of its own. It has a menu, and the menu opens pages. Each page is a grid of widgets that you can arrange. Widgets can be headings, text, and live tables or views. A data widget can only show the application’s own tables and views. Sharing the application therefore shares its pages and the data on them.

Here's what this could look like in the end:

Image

Walkthrough

Orange marks what is new. Blue marks what exists today.


The application start page looks the same as today. The only addition is the page bar under the description: “Start page”, one tab per grid page, and “Add page”:

Image

A grid page. “Overview” has a header widget, a text widget and two live tables. Milestones sits next to the text, and Tasks spans the full width underneath:

Image

Edit mode. “Edit page” turns every widget into a card you can drag and resize, each with a menu to configure or remove it. “Save” stores the whole layout at once:

Image

The widget types: a header, a text block (shown as “Description” in the menu), and a table or view:

Image

The data widget only offers the application’s own tables. The admin also owns a “Salaries” table that isn’t in this application, and it doesn’t appear in the list:

Image

Adding a page asks for a title, an emoji and a description:

Image

A user the application is shared with read-only. Bob sees the same page with live data, but has no “Add page”, no “Edit page” and no “Create row”. He didn’t need any table shared with him directly.

Image ---

Behavior

  • Only people who manage the application can add, edit or delete pages.
  • The grid has 12 columns and changes to 6 and then 1 column on narrow screens.
  • A widget shows its title when it has one.
  • If a table or view leaves the application, its widget stays on the page and asks the editor to pick another one.
  • The page bar is for designing in the Tables interface. The application menu is the navigation in the standalone app.
  • New applications get a menu item for the start page. Users can rename, move or remove it.
  • Each widget type registers its component in one place. New types need no change to the grid or the dialogs.

Activity

  1. rubenvdlinde commented on Oct 16, 2026

    @rubenvdlinde

    Thanks @enjeck, this reads as a clean version of what we proposed in #3075. We've discussed it with the team and we'll build on it. There are three places where it differs from our proposal, and here's what we think of each:

    Widgets in their own tables. Better than our version. tables_contexts_page_content and node_rel_id stay as they are, so existing start pages are never touched, and the query that loads applications doesn't change. The source table makes the link to the application's node a real column. We also prefer your behaviour when a table leaves the application: the widget stays and asks for a new table.

    The start page stays a list. We had the start page become a grid, so an application's start page could be its dashboard. Your schema allows widgets on any page, since widget.page_id is just a page. From our experience, builders want to customise the start page / landing page for their application, and a quick look at the App Store confirms that. So we would suggest the start page always be a grid that we autofill with a tables overview widget, but that can then be fully customised by the app developers.

    One row per setting. We'd suggest one JSON column on the widget instead. A setting is never queried on its own (at least we're not seeing that right now), and the server validates the whole set against the type's schema on save either way. Views already store filter and sort as JSON. One row per setting also means many rows for a single page read. If you prefer rows, we'll do rows, but it feels a bit too fragmented compared to how the rest of Tables is set up, and it adds unnecessary database load.

    One thing we'd like to add: a technical_name on pages, unique within the application and generated from the title when none is given. Views and columns have one for the same reasons. A re-imported scheme then finds its existing pages instead of adding them again, and a menu item or an external handler can address a page by name.

    The rest matches: the page fields, the API, read access for reading and manage access for changes, and scheme import and export through the node mapping of importContext().

  2. enjeck commented on Oct 16, 2026

    @enjeck
    ContributorAuthor

    6. We'd suggest one JSON column on the widget instead. A setting is never queried on its own (at least we're not seeing that right now), and the server validates the whole set against the type's schema on save either way. Views already store filter and sort as JSON. One row per setting also means many rows for a single page read. If you prefer rows, we'll do rows, but it feels a bit too fragmented compared to how the rest of Tables is set up, and it adds unnecessary database load.

    @blizzz can probably talk more about this, but we've had regrets in the past with using JSON? We wouldn't want to keep adding JSON just because it's what's we currently use despite the issues it brings

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions