Skip to content

feat(grid): render grid widgets on a gridstack canvas - #17

Open
remko48 wants to merge 5 commits into
stack/g3-views-api-v2from
stack/g4-grid-widgets
Open

remko48 wants to merge 5 commits into
stack/g3-views-api-v2from
stack/g4-grid-widgets

Conversation

@remko48

@remko48 remko48 commented Oct 12, 2026 •

Copy link
Copy Markdown
Member

Frontend building blocks to show a grid view: a canvas that places widgets on a grid, the card around each widget, and the first two widget types (header and text). Nothing uses them yet; the grid view page comes in a later PR of this stack.

What changes

  • New dependency gridstack for the grid layout (drag, resize, reflow). It does the hard part of a dashboard grid; writing that ourselves would be a lot more code to maintain.
  • GridCanvas: 12 columns on a wide screen, 6 on a medium one, 1 on a phone, based on the canvas width. A narrower layout is only how the page is shown; the stored layout always stays the 12-column one. Widgets can therefore only be arranged at full width: on a narrow screen edit mode shows a hint instead.
  • GridWidget: the card with an optional title and, in edit mode, a menu to configure, remove, move and resize the widget, so the grid can be arranged with the keyboard as well as by dragging. In edit mode the card always shows a heading, the widget's title or else its type name.
  • Widgets: HeaderWidget (heading, subheading, alignment, colors) and TextWidget (paragraphs, split on empty lines). Colors are only applied when they are hex, the same rule as the backend.
  • Widget types are loaded from GET /api/2/views/widget-types the first time a widget is shown, with one shared request; the frontend only maps each type to the component that renders it.
  • Tests: a Cypress component test covers the layout helpers and the hex color check.

🖼️ Screenshots

No visible change yet, since nothing renders the canvas until the grid view page PR.

🏁 Checklist

  • ⛑️ Tests (unit and/or integration) are included or not needed
  • 🔙 Backport requests are created or not needed: /backport to stableX.X
  • 📅 Milestone is set
  • 🌸 PR title is meaningful (if it should be in the changelog: is it meaningful to users?)

🤖 AI (if applicable)

  • The content of this PR was partly or fully generated using AI

@remko48
remko48 added this pull request to stack #15 October 12, 2026 08:33
@remko48
remko48 force-pushed the stack/g4-grid-widgets branch 2 times, most recently from 10a5016 to c682c13 Compare October 12, 2026 11:46
Adds the building blocks of a grid view: a canvas that places widgets on
a 12 column grid with gridstack, the card around each widget, and the
header and text widgets. The widget types are loaded from the server.

- the grid reflows to 6 and 1 columns on narrower screens, while the
  stored layout keeps the 12 column positions
- in edit mode widgets can be dragged and resized, or moved and resized
  from the widget menu with the keyboard
- colors from widget content are applied only when they are hex values

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
remko48 force-pushed the stack/g4-grid-widgets branch from c682c13 to 929306d Compare October 12, 2026 11:56

@remko48 remko48 left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Review (Thorough, round 2)

Each finding is an inline comment on the line it is about, marked 🔴 Blocker / 🟡 Concern / 🟢 Minor. This round takes the updated base stack into account (#13, #14 and #16 fixes, including 2ebf8c7, 2da6fa5 and 777c1b0); the diff of this PR itself is unchanged since it was rebased.

What was verified

  • Read the full diff against stack/g3-views-api-v2, and confirmed it is byte-identical to the round-1 patch (the branch was only rebased onto the updated #16).
  • Checked the backend widget schemas (lib/Service/GridWidgetTypes.php): all defaults are scalar or null, and the hex rule matches the one in AGENTS.md.
  • Confirmed t is a global in Tables (main.js plus the bare t already used in store.js).
  • Inspected the gridstack 13.3.0 package (column() defaults, gs-min-w handling).
  • Checked the commit carries Conventional Commit format, Assisted-by, Signed-off-by and a SPDX header.

Not run

eslint, stylelint, npm run dev/build, any tests, the app itself. The narrow-canvas finding is reasoned, not reproduced.

Comment thread src/modules/grid/GridCanvas.vue
Comment thread src/modules/grid/widgetRegistry.js Outdated
Comment thread src/modules/grid/GridWidget.vue
Comment thread src/App.vue Outdated
Comment thread src/modules/grid/GridWidget.vue Outdated
Comment thread src/modules/grid/GridCanvas.vue Outdated
Comment thread src/modules/grid/widgetRegistry.js Outdated
Comment thread src/modules/grid/widgets/HeaderWidget.vue Outdated
…azily

- on a canvas narrower than 12 columns drag, resize and the move actions are
  off with a hint, since that reflow is only shown and never stored
- widget types load the first time a widget needs them, in one request,
  instead of on every app start
- the column choice and the layout mapping are pure, named functions with
  component tests, together with the widget defaults, the grid copy and the
  hex color check
- one deep copy for defaults and grids, which also copies reactive data
- a header widget's heading sits below the card's own heading
- widgets no longer get an editable attribute they do not declare, and the
  grid baseline variable is used without a fallback

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

@remko48 remko48 left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Review (Thorough, round 3 — code guidelines and styling)

A strict pass on code guidelines and styling. Each finding is an inline comment, all 🟢 Minor. The 8 round-2 comments are still open: the diff is unchanged, so none of them is fixed yet.

CI

Most workflows never start in this fork: their jobs ask for runs-on: ubuntu-latest-low, a runner label that only exists in the Nextcloud org. I ran them locally at 929306dd3 (WSL, Node 24.20 / npm 11.19):

Workflow Result
Lint eslint ✅ pass, 0 warnings
Lint stylelint ✅ pass (also green here)
Build Javascript ✅ pass, and the build leaves the working tree clean
Cypress Component Tests ✅ 5/5 specs, headless Chrome 155
REUSE Compliance ✅ 1399/1399 files
AI Policy ✅ pass (adds the "AI assisted" label)
Block fixup and squash commits ✅ pass

Not run: PHPUnit (×4), Integration, Static analysis, Rector, Lint php, Lint info.xml and Playwright, which need PHP, Composer or Docker. This PR changes no PHP and no info.xml. Playwright does exercise it, through the loadWidgetTypes() call on every page.

What was verified

  • Re-read every file of the diff.
  • Measured Tables' conventions to compare against: data-cy casing, border tokens, comment casing, info.xml min-version 33.
  • Confirmed the arrow icons have no *Outline variant in vue-material-design-icons 5.3.1, so the outline-icon rule in AGENTS.md doesn't apply to them.

Comment thread src/modules/grid/GridCanvas.vue Outdated
Comment thread src/modules/grid/widgetRegistry.js
Comment thread src/modules/grid/GridCanvas.vue Outdated
Comment thread src/modules/grid/widgets/HeaderWidget.vue Outdated
Comment thread src/modules/grid/GridCanvas.vue Outdated
Comment thread src/modules/grid/GridCanvas.vue Outdated
Comment thread src/modules/grid/GridCanvas.vue
Comment thread src/modules/grid/GridWidget.vue Outdated
Comment thread src/modules/grid/GridWidget.vue Outdated
Comment thread src/modules/grid/widgets/TextWidget.vue
- the grid constants and pure helpers move to gridLayout.js, widgetRegistry.js
  only maps widget types to components
- move and resize steps are disabled when they cannot apply
- a widget card is labelled by its visible heading, and editor placeholders
  only show while the page is edited
- data-cy names are camelCase, the edit outline uses the max-contrast border
  and the header subtitle no longer lowers contrast with opacity
- GridStack and the resize observer are no longer reactive state, so they
  need no markRaw; the margin is a named constant
- one comment style, JSDoc on every method and one way to use icons

Assisted-by: ClaudeCode:claude-opus-5-5
Signed-off-by: Remko <remko@conduction.nl>
@remko48 remko48 closed this Oct 12, 2026
@remko48 remko48 reopened this Oct 12, 2026
@remko48 remko48 closed this Oct 12, 2026
@remko48 remko48 reopened this Oct 12, 2026
Signed-off-by: Remko <remko@conduction.nl>
@github-actions github-actions Bot added the AI assisted This PR contains AI-assisted commits label Oct 13, 2026
Signed-off-by: Remko <remko@conduction.nl>
Assisted-by: ClaudeCode:claude-opus-5-5
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AI assisted This PR contains AI-assisted commits

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant