Skip to content

Test for stacked pr's - #9

Open
remko48 wants to merge 19 commits into
mainfrom
refactor/upstream-shape
Open

remko48 wants to merge 19 commits into
mainfrom
refactor/upstream-shape

Conversation

@remko48

@remko48 remko48 commented Oct 12, 2026

Copy link
Copy Markdown
Member

This is a test for how stacked pr's work.
This is pr 1 of 3

@remko48
remko48 added this pull request to stack #12 October 12, 2026 06:47
remko48 and others added 19 commits October 12, 2026 09:37
Views get a type (table or grid), a grid of widgets and a slug, and a grid
view can exist without a table. Applications get a slug and an ordered menu
of items that open a view, a table or a link, an index page, and a detail
page that renders the menu and lets the owner edit it. A grid view has an
edit mode built on GridStack with header, description and table widgets,
saved as one grid on the view.

Assisted-by: ClaudeCode:claude-fable-5-1
The grid canvas now drives its column count from its own width, 12 on a
wide canvas, 6 on a medium one and 1 on a phone, and restores when the
window grows again; a reflow never writes back into the stored layout.
The context scheme export carries the slug, the menu items with their
targets as uuids, and the table-less views the menu points at; import
recreates missing grid views and remaps menu and widget targets by uuid.
The view uuid lookup no longer requires a table and returns null as it
declares. A Playwright spec walks the demo path: application, menu item,
grid view, two widgets, save, reload.

Assisted-by: ClaudeCode:claude-fable-5-1
The page headings leave room for the navigation toggle, the application
header and the applications index wrap on narrow screens, the menu editor
starts below its floating label and its rows wrap inside the dialog, and
a table widget no longer repeats the table's own title. Views without a
table, and shared views, now survive a reload of the tables list that
used to race with their own request.

Assisted-by: ClaudeCode:claude-fable-5-1
Unit tests for the View entity (grid parsing, type default, ownership
fallback, serialisation), the MenuItem entity, the ViewService create and
update validation (type, slug, grid shape and colors, table-less rules),
the ContextService menu replacement, slug handling, scheme export and
import resolution, the controller's menu item sanitiser, the permission
guards on a view without a table, and the activity manager skipping such
a view.

Assisted-by: ClaudeCode:claude-fable-5-1
Every widget type now carries the schema of its content on the server,
in GridWidgetTypes, and exposes it on /grid/widget-types. The add and
configure dialog renders one generic form from that schema, so a new
widget type needs a schema and a renderer, not a dialog. The server
validates and sanitises stored widget content against the same schema,
filling defaults and dropping unknown properties. The table widget's
target became one property; grids saved in the old shape still render
and are upgraded on their next save.

Assisted-by: ClaudeCode:claude-fable-5-1
… as navigation

Opened at /apps/tables/app/{slug} (the id still works), an application
shows its name and icon above its menu items in the left navigation and
starts on its first page; the resource overview stays reachable as the
last entry and keeps the per-user layout. The top-bar entry links to the
slug. Inside Tables the application page became a configuration page:
the address, the pages as cards with Design and Open actions, "Add page"
which creates a grid view with its menu entry, and the menu editor
inline instead of inside the application dialog. The app shell's
initial redirect now fires only from the root route, which also fixes
menu links inside a standalone application.

Assisted-by: ClaudeCode:claude-fable-5-1
… land

Stored in component data, the instance became a reactive proxy; drag
handlers armed through the proxy failed GridStack's own instance check
against the raw instance its nodes point at, so every moved widget
snapped back without an event and nothing was saved. markRaw keeps the
instance raw. The spec now drags a widget, saves, reloads and asserts
the position. The application slug lookup is scoped to the applications
the user owns or was given, since slugs are not unique across users.

Assisted-by: ClaudeCode:claude-fable-5-1
…and menu items

Views already carry a technical name; the fork added a slug next to it.
The slug is gone: applications and menu items get technical_name with the
same pattern as columns and views, a menu item derives its name from its
label unless the dialog sets one, and the standalone app shell routes on it.

Assisted-by: ClaudeCode:claude-fable-5-1
… its own schema

Title and show title move from the widget itself into its configuration,
the widget type carries a configuration schema next to the content schema,
and grids saved in the old shape read as the new one until saved again.

Assisted-by: ClaudeCode:claude-fable-5-1
Two OCS routes next to the internal ones the frontend uses: the widget
types a grid can hold, with both schemas, and the creation of a view
without a table. Documented in the OpenAPI document with their types.

Assisted-by: ClaudeCode:claude-fable-5-1
…migration dated

ContextScheme gains a factory that validates the import request at the
controller boundary, so the service takes one object instead of ten
parameters. The migration carries today's date.

Assisted-by: ClaudeCode:claude-fable-5-1
…kes no focus before the first interaction

The menu target was loaded once and kept as a snapshot, so a grid saved
through the store rendered its old widgets until a reload. The grid page
now reads the store's current copy of the view. On load the shell focused
the content area before any interaction, which drew the browser's focus
ring as a black line along the content edge; focus now moves only after
a first pointer or keyboard event.

Assisted-by: ClaudeCode:claude-fable-5-1
The frontend called internal routes for both actions; the OCS routes on api/2 already offer them.

Assisted-by: ClaudeCode:claude-opus-5-5
Signed-off-by: Remko <remko@conduction.nl>
- Serve widget types from an injected service with labels translated on the server
- Validate a grid in one place: layout items must belong to a widget, widget ids are unique, a layout item is identified by its widget, booleans and integers are not cast
- Refuse a view without a table as the target of a data widget
- Validate the grids of imported views
- Reset the stored value for every parameter in ViewService::update, so a type sent with a sort is no longer overwritten
- Reject a malformed type or grid in ViewUpdateInput
- Remove the internal widget-types and standalone view routes

Assisted-by: ClaudeCode:claude-opus-5-5
Signed-off-by: Remko <remko@conduction.nl>
…and relations

Such a view lists no rows or columns, and creating rows or columns in it or importing into it is refused as not found. The views without a table of a deleted user are deleted with the user.

Assisted-by: ClaudeCode:claude-opus-5-5
Signed-off-by: Remko <remko@conduction.nl>
- Add the views and tables a menu opens as nodes of the application, so the people it is shared with can open its pages
- Validate menu items in a MenuItemInput value object: http(s) links only, integer ids, unique technical names per menu
- Report a menu item whose target was deleted as broken
- Make technical names unique per owner and link the applications of others by id
- Load the menus of all applications in one query
- Answer invalid menu items and technical names with 400, and update an application atomically
- Export and import data widgets in their current target shape, create grid views before resolving nodes
- Declare tableId nullable and name the grid shapes in the API
- Show broken menu entries, say underscores in the technical name hints, keep pages out of the resource overview, use core heading sizes and drop the custom table styling
- Check the resources of an application in the application itself in the e2e tests

Assisted-by: ClaudeCode:claude-opus-5-5
Signed-off-by: Remko <remko@conduction.nl>
…ents

- Move and resize widgets from the widget menu, kept inside the grid
- Pick colors with NcColorPicker
- Show the labels the server translated instead of translating them again
- Align header text to start and end, so it follows the reading direction
- Use core heading sizes and keep the heading order

Assisted-by: ClaudeCode:claude-opus-5-5
Signed-off-by: Remko <remko@conduction.nl>
Table views are listed under their tables and pages are reached through their application. The first-interaction listeners are registered and removed in the App lifecycle. The grid e2e test uses a unique technical name per run and covers a move from the widget menu.

Assisted-by: ClaudeCode:claude-opus-5-5
Signed-off-by: Remko <remko@conduction.nl>
@remko48
remko48 force-pushed the refactor/upstream-shape branch from 2476620 to 2bd9ae7 Compare October 12, 2026 07:37
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.

2 participants