kirschbaum-development/nova-inline-select
Nova Inline Select lets you edit select fields directly from Laravel Nova's index and detail views, no extra clicks or forms. Add inline dropdown editing to any resource for faster, smoother workflows with a simple field configuration.
Architecture fit. This is a presentation-layer extension inside an already-licensed Laravel Nova admin app — one PHP field class plus one compiled Vue component. No schema change, no migration, no new service, no new on-call surface, no config file or service provider. It rides Nova's existing API, auth, and update path. Fit is high only when three conditions hold: Nova is already the admin layer, the dominant ops workflow is editing one scalar field directly on a resource index, and the option set is small. Outside that envelope (cascading fields, multi-selects, confirmation dialogs, reason codes) it is the wrong shape and you will end up writing a Nova field anyway.
Integration feasibility. Genuinely cheap. It is a drop-in replacement for Laravel\Nova\Fields\Select; options(), displayUsing(), and label configuration carry over. Adoption is a composer require, a version pin, and swapping one field class in one fields() method. Estimate hours for a pilot, not sprints — and the rollback (delete the line, composer remove) is a single commit, so this can be approved at team level rather than escalated as a platform bet.
Technical risk. Concentrated and mostly knowable:
| Risk | Why it matters to a TPM |
|---|---|
| Nova major coupling | 3.0.0's changelog is a single line — "Nova v5 Support" — a semver-major break with no stated behavior change and no evidence Nova 4 is supported on 3.x. A loose constraint plus a Nova bump can silently swap tracks. Pin ^3.0 (Nova 5) or ^2.0 (Nova 4) and commit it. |
| Validation bypass | Field ->rules() are exercised on Nova's form submission path; an inline index PATCH may not take it. Treat UI rules as an affordance, not a guard. Real guard belongs in a model observer or DB constraint. |
| Authorization surface shift | The index becomes a write surface. Read-only users must not see a clickable cell; per-row canSee/policy checks are mandatory, not polish. |
| Side-effect integrity | updated observers (audit rows, webhooks, search reindex) may double-fire or silently skip on inline saves. Must be verified per model with a real click. |
| Concurrency | Last-write-wins and no live refresh; two ops staff on one queue will clobber each other. |
| Asset drift | dist/js/field.js must be published/built; Nova 5 changed asset conventions. "Works locally, plain text in prod" is the canonical failure. |
| Maintenance depth | 93 stars, 0 dependents, thin contributor base. Mitigated by the tiny surface and MIT license — forking under your own namespace is realistic and cheap. |
Key questions to answer before green-lighting.
Stack fit. Laravel + Nova, PHP 8.x, Composer, one locked dependency. It inherits Nova's session, policy, and API stack — no new infrastructure, no new secrets, no new deployment target. It slots into existing CI/CD as a normal versioned package and is invisible to the rest of the application.
Migration path — this is adoption, not migration. Sequence it deliberately:
^3.0 for Nova 5, ^2.0 for Nova 4. Commit the constraint in composer.json; don't let composer require pick while the nova constraint is also loose.KirschbaumDevelopment\NovaInlineSelect\NovaInlineSelect, but read the header in vendor/.->onlyOnIndex().updated_at actually moved (if it didn't, the write never landed and the UI is lying) → read-only user cannot click.Compatibility patterns. Bind options to a domain enum (->options(Status::class)) so the dropdown can't drift from the source of truth. Split the field by context: NovaInlineSelect on the index as a fast path with a small option set, plain Select ->onlyOnForms() with full required|in: rules for deliberate edits. Add an explicit blank entry ('' => '—') on nullable columns, otherwise users can never clear the value. Keep option sets to 3–8; a 200-row owner dropdown in a table cell is a searchable BelongsTo or an action.
Sequencing against the roadmap. Treat this as a pre-upgrade checklist line item, not a discovery: confirm the Nova major and its upgrade window before adoption, pilot on one operational queue, harden the write path (observer/DB constraint) before expanding, then schedule any Nova major bump as its own deliberate change. Run the Nova 5 upgrade and the package bump together, never as an incidental composer update. If the roadmap contemplates queue views, triage, or fulfilment dashboards, this is the cheapest possible way to validate the interaction pattern with real operators before committing to a bespoke console.
Maintenance. Code maintenance is near-zero; upgrade maintenance is the real line item and it is calendar cost, not sprint cost. Budget an explicit checkpoint at every Nova upgrade: re-confirm the package constraint, run php artisan nova:publish, rebuild assets, and test against a production build. If the package goes stale, fork it — the surface is one class and one Vue component, and MIT permits it. Record the chosen version track in the repo README so the next engineer doesn't reverse-engineer it.
Support. Triage is genuinely fast and should be written down as a runbook so the ops lead, not an engineer, handles first line: renders as plain text → asset not published/built; click does nothing → Network tab, the PATCH /nova-api/... status; 403 → policy/canSee; 422 → server validation; 200 but value reverts → $fillable, cast, or an observer rewriting it; wrong label → options shape or missing displayUsingLabels(). That table is the whole support surface.
Scaling. It scales with the Nova app, not separately — but three constraints bite at volume. (1) Option-set cardinality: stay at 3–8 values or the cell becomes unusable. (2) Observer cost: once an index is a rapid-fire editing surface, expensive observers (webhooks, reindexing, audit writes) need debouncing or rate limiting, or every keystroke of ops activity becomes backend load. (3) Concurrency: no realtime refresh means conflicting edits silently overwrite; mitigate cheaply by surfacing updated_at on the index, marking stale rows readonly, or simply keeping the field off resources where a clobbered edit is expensive.
Failure modes. All are contained to a column, not a workflow — that's the argument for adopting it. The realistic set: silent no-op that looks saved (verify updated_at); plain-text render in production only; validation bypass admitting an invalid state; double-fired or skipped side effects; unauthorized inline edit; mutually clobbered concurrent edits; field stops rendering after a Nova upgrade due to asset/API drift. The last is the most likely and the least alarming — it degrades to plain text, not data loss.
Ramp-up. Engineers: effectively zero — the API is Nova's Select with familiar methods. Operators: small but non-trivial, because an editable cell with no Save button invites accidental changes. Ship it with a one-line internal release note ("these cells now save immediately"), a short demo, and a week of watching for accidental-edit reports. TPM enablement is a demo plus the runbook, not a training program.
Success measures for the pilot. Share of target edits completed inline versus opening the record; time-to-complete on the pilot queue; 403/422 rates on the inline PATCH endpoint; observer latency after rollout; count of accidental-change or conflict reports. If inline edits absorb the bulk of the demand for custom admin tooling, that is evidence against a heavier internal-tooling bet — and worth putting in the same conversation as any proposal to build a dedicated ops console.
How can I help you explore Laravel packages today?