Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Nova Field Sortable Laravel Package

naxon/nova-field-sortable

naxon/nova-field-sortable is a Laravel Nova field for drag-and-drop sorting of resource records in index views. It lets editors reorder menus, categories, and other lists directly in Nova, with simple setup and an order column to store manual positions. Useful for any model that needs a custom displ...

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit. The package is a thin Nova field: a PHP Field subclass (src/Sortable.php), a compiled Vue 2 index component, and an AJAX reorder route. It bolts onto the existing Resource::fields() / indexQuery() contract with no new infrastructure, no queue, no service provider of consequence. That is the right shape for the problem — but the scope is strictly one flat list per table. There is no parent/child awareness, no nesting, no per-category scoping. If the requirement is "chapters within a course" or "items within a menu," the field is only the drag handle; the hierarchy, validation, and reindex logic are ours to write.

Integration feasibility. Feasibility is entirely gated on the Nova major version, and that is a one-command check (composer show laravel/nova) before any planning happens.

  • Nova 1.x–2.x: genuine drop-in, roughly a day including column migration, backfill, and one smoke test.
  • Nova 3: may work; treat as a half-day spike with a hard stop.
  • Nova 4/5: not an install. The Vue 2 + Laravel Mix component will not mount and must be ported to Vue 3/Vite and re-registered through the current Nova.booting signature. Budget 1–2 days of frontend work, treat exceeding two days as the signal to write a bespoke field instead — the underlying logic is genuinely shallow.

Technical risk. High, and concentrated in ownership rather than complexity.

  • Last release October 2018, 58 stars, zero Packagist dependents, no security contact, no issue triage. Every future Nova upgrade is our problem, not theirs.
  • The AJAX reorder endpoint is the entire security surface and arrives with no authorization. A list-of-IDs endpoint is a classic IDOR; a user who can see a resource is not automatically permitted to reorder it. Policy checks, payload validation (expected ID set, not arbitrary IDs), a transaction, and lockForUpdate() are all ours.
  • Compiled JS ships into public/vendor/, so asset publication becomes a release-pipeline concern, not a one-time install step.
  • Silent failure is the characteristic mode: after a Nova upgrade the field mounts, renders nothing, throws nothing, and the index looks normal minus the handle.

Key questions to close before committing.

  1. Which Nova major are we on, and is an upgrade within 12 months?
  2. Does ->sortable() plus $defaultSort already satisfy the requirement? If the order is derivable (name, date, score), this initiative dies here — and that should be the first check, not the last.
  3. How many rows, and how many concurrent editors? Tens of rows with one editor is a different design than hundreds with five.
  4. Flat list or hierarchical? If hierarchical, we are building, not adopting.
  5. Who is the named internal owner of the forked source, and where does the divergence note live?
  6. Has the reorder route had a security review, or is that part of the estimate?

Integration Approach

Stack fit. Laravel + Nova + Eloquent, no frontend build step on our side for Nova 1/2. The one hard dependency friction is that laravel/nova resolves from a private repo — CI needs Nova credentials configured as secrets (not committed auth.json) before this resolves at all.

Migration path.

  • Vendor the source into a repo we control at a pinned commit (VCS or path repository entry), rather than depending on Packagist. Add the laravel/nova constraint edit as an explicit, reviewed change.
  • Add an indexed unsignedInteger order column with a sane default, backfill from current display order, and set new rows to max(order) + 1 in a booted() creating hook so drags stay meaningful.
  • Register the field ->onlyOnIndex() — it is a handle, not an editable input — and override indexQuery() to orderBy('order') so the visible list matches stored order.
  • Prefer the field's own column-configuration method over renaming schema to fit a 2018 package's assumptions; check src/Sortable.php for hardcoded order/position first.

Compatibility constraints to verify, not assume. Nova major; PHP version against the 2018 constraint; whether a composite unique index (parent_id, order) is needed; and whether any existing sorting mechanism (notably spatie/eloquent-sortable) already owns the order column. Two mechanisms writing the same integer will double-write and drift — pick one.

Sequencing.

  1. Version check and native-sorting check (hours, and either can end the effort).
  2. Spike on one low-risk, editorially-owned flat list — FAQs, footer links, pricing tiers — with realistic seed data. Drag one row, refresh, confirm the column changed.
  3. Harden: authorize the route, validate the payload, wrap in a transaction, add a feature test for the happy path, one for a 403, and one render smoke test asserting the handle HTML — that last one is the canary for a Nova upgrade silently blanking the field.
  4. Decide: expand to more lists, port for Nova 4/5, or hand the reference implementation to a bespoke build. Record the decision and the kill criteria in the log.

Operational Impact

Maintenance. This is an adoption of source, not a dependency. Name an owner, pin the commit, and write a short README note describing how our fork diverges — otherwise the next developer assumes it is maintained and attempts an upgrade. Add "verify drag handle renders" to the Nova-major upgrade checklist permanently.

Support. There is none upstream. No issue triage, no security disclosure channel, no peers who will surface breakage before we do. All defects, ports, and vulnerability responses are internal work with no external SLA to point at.

Scaling. The default strategy rewrites N rows per drop, which is correct at tens of rows and wrong past a few hundred. If a list can plausibly grow, plan the fractional-rank design (float or lexicographic) up front so we are not migrating mid-flight; a single-row update per drag also removes most of the lost-update problem for free. Two specific traps: pagination and active filters (a drag on page 2 with a search applied will renumber against visible indices and scramble hidden rows — either disable the handle or send and reindex the full ordered ID set inside the transaction), and multi-parent tables (without the parent in the payload and a composite uniqueness constraint, a drag will renumber across parents).

Failure modes and the debugging playbook.

  • Handle missing after a Nova upgrade: silent, no error — check the network tab for a 404 on the compiled asset, then Nova::script() registration.
  • Stale assets after deploy: the JS lives in public/vendor/, so nova:publish must be in the release pipeline or we ship backend changes against last week's frontend.
  • XHR fires with a 200 but order does not stick: $fillable/mass-assignment or a model saving hook overriding the column.
  • 419 on drop: CSRF against the Nova route.
  • Gaps after deletion: harmless and cheaper than a full reindex; compact on demand only, and query withTrashed() if we ever do.

Ramp-up. Low. A few hundred lines across three places — the field class, the Vue component, the route/controller — and a day to be productive. The cost is not learning it; it is owning it indefinitely and remembering that when the next Nova upgrade lands.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator