day4/tree-view
day4/tree-view is a Laravel package for turning nested, parent-child data into hierarchical tree views. It helps display categories, menus, and similar structures in Blade templates with simple, reusable rendering logic, so you can present recursive relationships cleanly without custom traversal cod...
Confirm the stack before anything else. Despite the description.md framing it as a general "Blade-friendly" tree renderer, the repository (u12206050/nova-treeview) is a Laravel Nova tool — a self-registering package that mounts a Vue panel inside Nova. It has no value outside Laravel + Nova. Check composer.json in the repo for its laravel/nova constraint; that line tells you which Nova major it was written against (expect ^3.0), and it is the single most important fact for the day-to-day experience.
Read the source first, not the README. With 9 stars and a 2020 release there is no guarantee the docs match the code. Open:
composer.json — the exact composer name, the Nova constraint, the PHP constraint, and the license. The repo slug (nova-treeview) and the composer name (day4/tree-view) differ; use the composer name in require.src/ — the tool class name and namespace (e.g. Day4\TreeView\TreeView), plus any ToolServiceProvider and whether it registers a route/menu entry.resources/js/ — Vue version (2 for a 2020 release) and whether the build tool is Mix or Vite. This is your compatibility verdict.sort/order column, and does it expect parent_id by a fixed name or a configurable key?Minimal install (Nova 3 environment only).
composer require day4/tree-view
php artisan nova:publish # or nova:publish --tag=tool-assets
// app/Providers/NovaServiceProvider.php
public function tools()
{
return [
new \Day4\TreeView\TreeView(), // verify class from src/
];
}
Then configure the model and its parent/title/order keys as the tool's constructor or config expects, and php artisan migrate if it ships a pivot/sort migration.
First use case to prove out: a Category model with parent_id and sort columns, browsed read-only in the Nova panel. Mount it, confirm the hierarchy renders correctly with a seeded three-level tree, and confirm Nova policies gate it. Only after that does drag-to-reorder matter. If the panel does not even mount, stop — you are in fork territory before you've written a line of business logic.
If you actually need the Blade side, that is not this package. The description.md text reads like a generic recursive-partial helper; the repo does not ship one. For Blade rendering use the standard Laravel pattern yourself:
// resources/views/partials/tree.blade.php
<ul>
@foreach ($nodes as $node)
<li>
{{ $node->title }}
@if ($node->childrenRecursive->isNotEmpty())
@include('partials.tree', ['nodes' => $node->childrenRecursive])
@endif
</li>
@endforeach
</ul>
// Controller — eager-load the whole path, avoid N+1
$tree = Category::with('childrenRecursive')->whereNull('parent_id')->get();
Gate the tool behind a policy or canSee. The tool is registered globally per Nova panel; if you register it in tools() unconditionally, every operator sees the hierarchy. Wrap it:
(new \Day4\TreeView\TreeView())->canSee(function ($request) {
return $request->user()->can('viewAny', Category::class);
}),
Confirm in the source that it routes through Nova's AuthorizedToSee contract and, more importantly, that any per-node action (move, delete) is checked — a 2020 tool may render the tree to anyone who can reach the panel regardless of node-level policy.
Register one tool instance per hierarchy. If you have categories, menus, and org units, do not try to make one instance serve three models. Register separate instances with distinct labels and model bindings in tools(). This keeps configuration explicit and makes it obvious in the Nova menu which tree you're looking at.
Reorder persistence — wrap it and validate. The most dangerous day-to-day pattern is drag-and-drop that writes an ordering column with no transaction and no sibling-scope check. In your fork, persist a move as:
DB::transaction(function () use ($node, $newParentId, $newIndex) {
$node->update(['parent_id' => $newParentId]);
$siblings = Category::where('parent_id', $newParentId)
->where('id', '!=', $node->id)
->orderBy('sort')
->lockForUpdate()
->pluck('id')
->splice($newIndex, 0, $node->id);
foreach ($siblings as $i => $id) {
Category::whereKey($id)->update(['sort' => $i]);
}
});
Add a unique index on (parent_id, sort) and a saving observer that rejects cycles (a node cannot become its own descendant). Assume upstream does neither.
Seed a realistic tree in tests before touching the component. You will be the only maintainer of the ordering logic. A Dusk/feature test that moves a node across parents and asserts the flat pluck('id') order is the highest-value test you can write, and it survives Nova upgrades if you keep the ordering logic in PHP rather than the Vue component.
Use withSum/withCount style eager loading, not lazy relations. If the component walks $node->children lazily, a 500-node tree is 500 queries. Define a recursive relation and eager-load it:
public function childrenRecursive()
{
return $this->hasMany(Category::class, 'parent_id')->orderBy('sort')
->with('childrenRecursive');
}
Category::with('childrenRecursive')->whereNull('parent_id')->get();
Vendoring pattern (recommended over composer require on Nova 4/5). Add the fork as a path repository so local edits compile:
"repositories": [{ "type": "path", "url": "packages/tree-view" }],
"require": { "day4/tree-view": "*" }
Then rename the namespace to your vendor, commit it, and pin the Nova major in your own composer.json. That converts an abandoned dependency into a named piece of internal code, which is the only sustainable day-to-day arrangement here.
Treat the Vue side as a shell. Put as much logic as possible in PHP (ordering, authorization, cycle rejection) and keep the component to rendering and emitting a move event. This is what makes future Nova upgrades a component swap rather than a rewrite.
Nova 4/5 will almost certainly not mount this unmodified. A September 2020 release predates the Inertia/Vue 3 rework, the Vite asset pipeline, and the reworked tool-bootstrapping contract. Symptoms: blank panel, Vue is not defined, or 404s on published assets. Budget a modernization fork; do not discover this mid-sprint. If you're on Nova 3, it may work near-out-of-the-box — verify that first.
The description and the code disagree. description.md sells a Blade-friendly hierarchical renderer; the repository is a Nova tool. Anyone evaluating from the description alone will expect @include-based tree partials and find none. State the Nova-only constraint in any decision record so it doesn't get re-litigated.
Package name ≠ repository name. day4/tree-view vs u12206050/nova-treeview. Requiring the wrong string fails at resolution; also check whether the vendor prefix on the fork is Day4 or something else before copying class references.
Asset publishing is the usual first failure. Mix-era packages publish into public/vendor/... with nova:publish; Nova 4+ expects Vite build output. If assets 404 after publish, check resources/js/ for webpack.mix.js vs vite.config.js — that tells you which pipeline it wants. Clear public/vendor and re-publish before debugging further.
Silent ordering corruption is the realistic production bug. Duplicate sort values, lost siblings, and orphaned children appear after concurrent edits, not after a single drag. Assume no transaction and no lock until you've read the save path. Add the DB unique index and lockForUpdate above; they are cheap insurance.
No cycle protection. Drag a parent into its own descendant and you can produce a detached subtree that no longer appears anywhere in the panel. Add a saving observer rejecting $node->isDescendantOf($newParent).
Authorization may be coarse. Verify whether the tool respects Nova policies or merely the tool-level canSee. If an operator can see the panel, can they see nodes their policy forbids? If not, add a scoped query in the fork — do not rely on upstream.
N+1 and eager loading hide until production. Test against your largest realistic tree (a few thousand nodes, not ten). If the component renders eagerly, add a depth cap or lazy expansion in the fork; do not wait for the admin panel to time out on a real category table.
There are no tests upstream and no upgrade path. Your regression suite around ordering persistence and authorization is the only thing between you and a Nova upgrade that silently breaks the panel. Write it before the first commit of the fork.
Pin the Nova version and name an owner. Put a line in your README/dependency register stating the pinned Nova major, the fork point, and who upgrades it. This package belongs in the same log as any other unmaintained dependency — with a recorded adopt/fork/build decision — or it will quietly become load-bearing six months from now with nobody accountable.
Debugging checklist when it fails to appear: tool registered in tools() for the right panel → nova:publish run and public/vendor cache cleared → correct Nova major → Vue/Mix vs Vite pipeline → browser console for mount errors → canSee closure returning true. That ordered list resolves most cases in minutes.
Have an exit criterion. If the fork estimate exceeds roughly a week of engineering, build the minimal sortable tree panel yourself. A Nova resource with an ordering action plus a small Vue tree component is not a hard feature, and it carries no abandoned-dependency tail — which is the whole point of evaluating this package before adopting it.
How can I help you explore Laravel packages today?