Skip to content

Release v0.23.1 - #297

Merged
jakub-przepiora merged 18 commits into
mainfrom
release/v0.23.1
Sep 14, 2026
Merged

jakub-przepiora merged 18 commits into
mainfrom
release/v0.23.1

Conversation

@jakub-przepiora

Copy link
Copy Markdown
Contributor

Cuts the Unreleased section to v0.23.1 and bumps config/version.php.

PATCH — fixes only.

The headline: Admin → Modules → Install now works end to end

v0.23.0 shipped the module system and told operators to install the Enterprise module. Both halves of that path were broken, and each hid behind the other:

  • The upload never opened its own archive. Stored on the local disk (storage/app/private) but handed a storage/app/… path, so every attempt failed with "Could not open ZIP file" whatever the archive held — and leaked the file.
  • Enabling a module never created the tables it ships. Enabling ran migrate, but a module's migrations are registered by its service provider, providers are registered at boot, and the process doing the enabling booted with the module switched off. migrate only ever saw the application's own paths. Every screen the module contributes then answered 500 with "relation … does not exist".

Fixing only the first made it worse in practice: the install reported success and then failed on first use.

Also in this release

  • Install accepts a dropped ZIP, validates through a Form Request and shows progress.
  • Operator Workstation view follows the selected workstation; the "All" chip actually clears the selection.
  • Live lists kept updating after a create or delete — two collections sharing a channel no longer unsubscribe each other.
  • No more phantom rows from a rolled-back write: collection deltas are sent after commit.
  • Sidebar groups highlight on pages a module added to them.
  • Uploads over PHP's post_max_size report a flash error instead of a bare exception page.

See CHANGELOG.md for the full list.

Upgrade

Nothing beyond the usual: deploy and run migrations. No schema change of its own.

An installation that already had the Enterprise module working is unaffected — its tables exist. This matters for installations that have not installed it yet, and for every new one.

Verification

Backend 2607, frontend 134, build green.

Exercised against a running PostgreSQL instance rather than only the suite: from a database with none of the module's tables, ZIP upload → enable → all twelve tables created with their soft-delete columns → all twelve module screens 200, nothing in the log. The same sequence on develop before this branch left the tables uncreated and the screens at 500.

The new test asserts the table exists after enabling, not that migrate was called — a call is exactly what the broken version also made, which is how this stayed green. It fails without the fix.

Svannte and others added 18 commits September 14, 2026 17:51
- Workstation view follows the workstation selected in the Queue: only
  orders whose current step runs there, plus not-yet-started orders whose
  routing starts there, and only that station's machine state, with an
  "All workstations" link back. A workstation account's assignment alone
  doesn't filter it; per_line tracking keeps the whole-line view.
- Queue lists those not-yet-started orders as "To start at …" cards, its
  polling count includes them, and the "All" chip now clears the selection.
- Workstation view: machine-state picker uses the shared Dropdown, and
  structured extra-data renders as text instead of [object Object].
- Live lists: collection channels are reference-counted, so a remounted
  list (e.g. the redirect after a create) no longer loses its subscription
  when the old collection shuts down.
- Collection deltas are broadcast after the transaction commits, so a
  rolled-back write can't leave a phantom row in open lists.
A group lights up and auto-expands from its static `match` list in
adminNav.js. Links a module injects into a core group were never on that
list, and a module's own group had no list at all, so on exactly the
pages a module contributes the group stayed dark and shut — the child
link was highlighted, inside a collapsed group nobody could see.

Module contributions now extend the group's match list (groupMatch in
navMerge.js), which also lets the breadcrumb trail find the group.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ADDtUtMzoXfPD7sC5RZXWm
- docker-compose.dev.yml: mount backend/modules into the Vite watcher.
  app.jsx globs modules/*/resources/js/Pages, and without the mount every
  module page was missing from the dev bundle and rendered _MissingPage.
- ResourceTable: `toolbarActions` prop for extra controls left of the
  "new" button (the Enterprise module's "Transfer stock" uses it).
- lang: keys for the Enterprise stock-transfer screens and the upload
  size error (module UI strings live here — the frontend loader reads
  only core's lang/*.json).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ADDtUtMzoXfPD7sC5RZXWm
…Large

The image allowed 32 MB while UploadBackupRequest accepts a 500 MB
archive, so restoring a backup died on a bare PostTooLargeException page
before validation could say anything. post_max_size/upload_max_filesize
are now 512M, and an oversized body is reported as a flash error on the
page it came from (413 for JSON clients).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ADDtUtMzoXfPD7sC5RZXWm
- Batch::currentStep() reads the loaded steps relation when present
  (same answer as the query), and the workstation filter eager-loads
  batches.steps, so the queue and workstation views no longer run up to
  two queries per batch.
- queue/check resolves the workstation and its order source like the
  queue: cross-line when workstation routing is enabled.
- "All workstations" keeps the week and search filters.
- A "To start at" card whose first step has alternatives shows the
  alternative at the selected workstation.
…hrows

ValidatePostSize is global middleware, so it throws before the web group
has started a session; back()->with('error') flashed into a store nothing
would save, and the browser landed on the referrer with no message
(CodeRabbit, #294). The handler now decrypts the cookies and runs
StartSession itself around the redirect, so the user's own session is
resumed and the flash written.

The test now sends an oversized Content-Length through the real stack
and reads the flash back through the session driver, which is what the
next request sees — assertSessionHas alone passes even when nothing
was persisted.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ADDtUtMzoXfPD7sC5RZXWm
The upload was stored on the `local` disk, which is rooted at
storage/app/private since Laravel 11, but the installer was handed a
hand-built storage/app/… path. The file was never there, so every
upload ended in "Could not open ZIP file" — and the finally-unlink
missed too, leaking an archive per attempt. Ask the disk for the path.

Adds ModuleUploadTest, which pushes a real archive through the endpoint
(install lands in the modules dir, upload is cleaned up, a broken zip
reports why, non-admins are refused) — the three install cases fail on
the old code.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ADDtUtMzoXfPD7sC5RZXWm
- Admin → Modules → Install uses the shared FileDropZone (drag and drop
  as well as browse) and posts through Inertia, so a rejected file shows
  its error under the zone and the upload shows progress.
- Upload validation moves from the controller into InstallModuleRequest.
- The stored ZIP is resolved through the local disk: its root is
  storage/app/private, so the hand-built storage_path("app/…") pointed at
  a missing file — every upload failed with "Could not open ZIP file" and
  the ZIP was left behind.
- Feature tests for the upload: success hands the manager a readable ZIP
  and removes it, rejected ZIP, required / not-a-zip / over 20 MB, guest,
  operator.
Resolve the CHANGELOG conflict under Unreleased → Fixed: keep develop's sidebar and upload-size entries alongside the module ZIP upload entry.
fix(modules): installing a module from a ZIP upload always failed
tempnam() creates the file before the .zip suffix is appended, and tearDown() only removed the suffixed path, so each ZIP upload left an empty file in the temp directory. Rename the created file to the .zip name instead.
Resolve ModulesController::upload against #296, which fixed the same storage path: keep the InstallModuleRequest form request (no inline validate()) with the disk-resolved path. Keep one CHANGELOG entry for that fix (develop's), and drop the two cases from Web/Admin/ModuleUploadTest that develop's real-install tests/Feature/ModuleUploadTest.php now covers.
fix: module upload drag-and-drop, form request and storage path
Every screen a module contributes answered 500 with "relation ... does not
exist" the moment it was opened, on any installation that did not already have
the tables from before the code was extracted into a module — which is every new
installation.

enable() called migrate() plainly, on the stated theory that enabling the module
is the first moment its migrations can run. It is not. Migrations are registered
by the module's service provider, providers are registered at boot, and the
process doing the enabling booted with the module switched off. So migrate saw
only the application's own paths and the module's tables were never created.
Point it at the module's own directory instead.

The test asserts the table exists afterwards, not that migrate was called: a
call is exactly what the broken version also made, which is why nothing caught
this. It fails without the fix.

Pairs with the ZIP upload fix already on develop. Separately they each leave the
install path broken; together Admin → Modules → Install works end to end.
Cut the Unreleased section to 0.23.1 and bump config/version.php.

PATCH: fixes only. The headline is that Admin → Modules → Install works end to
end — v0.23.0 shipped the module system and told operators to install the
Enterprise module, while both halves of that path were broken: the upload never
opened its own archive, and enabling a module never created the tables it ships.
Each was fixed separately; neither alone made the path usable.
@coderabbitai

coderabbitai Bot commented Sep 14, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are limited based on label configuration.

🏷️ Required labels (at least one) (1)
  • cla-signed

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: 28bc68c3-1acf-4e3e-87e0-2f8e94015e10

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@jakub-przepiora
jakub-przepiora merged commit 4b43b01 into main Sep 14, 2026
1 check passed
@jakub-przepiora
jakub-przepiora deleted the release/v0.23.1 branch September 14, 2026 19:50
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.

3 participants