Repository navigation
Conversation
Grid views keep their widgets and layout in a new grid column. The widget types (header, text and data) and the schemas of their configuration and content are defined on the server, and every grid is validated against them before it is stored. - unknown properties are dropped and missing ones get their default - colors must be hex values - a data widget cannot point at another view without a table - grids are validated on update and on import Co-authored-by: Ruben van der Linde <ruben@conduction.nl> Assisted-by: ClaudeCode:claude-opus-5-5 Signed-off-by: Remko <remko@conduction.nl>
remko48
added this pull request to stack #15
October 12, 2026 08:26
rjzondervan
reviewed
Oct 12, 2026
3 of 5 tasks
- a data widget only shows a table or view that exists, holds rows and is readable for the user; every other target gets the same error - only a grid view stores a grid, also when the type changes in the same request; an import only takes the grid over for a grid view - a layout places every widget once and with a size of at least one cell - a grid that cannot be encoded is refused instead of being stored empty - widget values are typed in the API instead of mixed, and the shapes are defined once in ResponseDefinitions - the conversion of a grid shape that only prototype data had is gone Assisted-by: ClaudeCode:claude-opus-5-5 Signed-off-by: Remko <remko@conduction.nl>
rjzondervan
reviewed
Oct 12, 2026
A save now only checks targets that are new or changed against the user who saves. A target that was stored before is kept, so a save no longer depends on the saver's access to widgets they did not touch, and a target that no longer exists is marked broken instead of blocking every save; the mark clears once the widget is saved in a valid state again. Tests now cover the refusal of a view without a table on its own, and the import of a table view whose source carries a grid. Assisted-by: ClaudeCode:claude-opus-5-5 Signed-off-by: Remko <remko@conduction.nl>
…n cases A test now saves a grid through ViewService::update() with a stored target the saver cannot read, so dropping the stored grid from that call fails it. The input-rejection cases of GridWidgetTypesTest run as one data-provider test, each with its own name and expected message. Assisted-by: ClaudeCode:claude-opus-5-5 Signed-off-by: Remko <remko@conduction.nl>
This was referenced Oct 12, 2026
3 of 5 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Grid views get the content that makes them a page: a set of widgets and their position on a grid. Which widget types exist, and what each may contain, is defined on the server. Every saved grid is checked against those definitions, so the database only holds known widget types and properties.
What changes
Migration:
tables_viewsgets a nullablegridtext column (JSON).Widget types (
GridWidgetTypes):header,textanddata(shows a table or view). Each type has aconfigurationschema (title, show title) and apropertiesschema for what the widget shows, stored as the widget'scontent. These definitions are not exposed through the API yet.Only grid views hold a grid: sending a
gridfor atableview is rejected. A single request can change the type togridand fill the grid at the same time.Validation on save and import: the following are rejected with a 400:
Unknown properties are dropped and missing ones get their default.
Colors: only hex colors (
#plus 3 to 6 hex digits) or an empty value are accepted, so no CSS can be injected through a widget.Data widget: a new or changed target must exist, must not be a view without a table, and the user must be able to read its rows. Every failure gives the same error, so it reveals nothing about other people's views. A target that was already stored is kept as it is, so a save does not depend on the saver's access to widgets they did not touch. It is marked
broken: trueonce its table or view no longer exists.Import: only views of type
gridtake over agridfrom the import, and it goes through the same validation.API:
grid(widgets + layout) is added to the view response and can be sent through the existing view update. OpenAPI and TS types regenerated.🖼️ Screenshots
Backend only, no UI changes.
🏁 Checklist
/backport to stableX.X🤖 AI (if applicable)