Git Product home page Git Product logo

filament-tree's Introduction

Important

Please note that we will only be updating to version 2.x, excluding any bug fixes.

Filament Tree

Filament Tree is a plugin for Filament Admin that creates a model management page with a heritage tree structure view. This plugin can be used to create menus and more.

Latest Version on Packagist Total Downloads

This plugin creates model management page with heritage tree structure view for Filament Admin. It could be used to create menu, etc.

Demo site : https://filament-cms-website-demo.solutionforest.net/admin

Demo username : [email protected]

Demo password : 12345678 Auto Reset every hour.

Installation

To install the package, run the following command:

composer require solution-forest/filament-tree

Important: Need to publish assets after version 2.x

php artisan filament:assets

Note: Add plugin Blade files to your custom theme tailwind.config.js for dark mode.

To set up your own custom theme, you can visit the official instruction page on the Filament website.

Add the plugin's views to your tailwind.config.js file.

content: [
    '<path-to-vendor>/solution-forest/filament-tree/resources/**/*.blade.php',
]

Then, publish the config file using:

php artisan vendor:publish --tag="filament-tree-config"

You can set your preferred options by adding the following code to your config/filament-tree.php file:

<?php

return [
    /**
     * Tree model fields
     */
    'column_name' => [
        'order' => 'order',
        'parent' => 'parent_id',
        'title' => 'title',
    ],
    /**
     * Tree model default parent key
     */
    'default_parent_id' => -1,
    /**
     * Tree model default children key name
     */
    'default_children_key_name' => 'children',
];

Screenshot

Usage

Prepare the database and model

To use Filament Tree, follow these table structure conventions:

Tip: The parent_id field must always default to -1!!!

Schema::create('product_categories', function (Blueprint $table) {
    $table->id();
    $table->integer('parent_id')->default(-1);
    $table->integer('order')->default(0)->index();
    $table->string('title');
    $table->timestamps();
});

This plugin provides a convenient method called treeColumns() that you can use to add the required columns for the tree structure to your table more easily. Here's an example:

Schema::create('product_categories', function (Blueprint $table) {
    $table->id();
    $table->treeColumns();
    $table->timestamps();
});

This will automatically add the required columns for the tree structure to your table.

The above table structure contains three required fields: parent_id, order, title, and other fields do not have any requirements.

The corresponding model is app/Models/ProductCategory.php:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use SolutionForest\FilamentTree\Concern\ModelTree;

class ProductCategory extends Model
{
    use ModelTree;

    protected $fillable = ["parent_id", "title", "order"];

    protected $table = 'product_categories';
}

The field names of the three fields parent_id, order, and title in the table structure can also be modified:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use SolutionForest\FilamentTree\Concern\ModelTree;

class ProductCategory extends Model
{
    use ModelTree;

    protected $fillable = ["parent_id", "title", "order"];

    protected $table = 'product_categories';

    // Default if you need to override

    // public function determineOrderColumnName(): string
    // {
    //     return "order";
    // }

    // public function determineParentColumnName(): string
    // {
    //     return "parent_id";
    // }

    // public function determineTitleColumnName(): string
    // {
    //     return 'title';
    // }

    // public static function defaultParentKey()
    // {
    //     return -1;
    // }

    // public static function defaultChildrenKeyName(): string
    // {
    //     return "children";
    // }

}

Widget

Filament provides a powerful feature that allows you to display widgets inside pages, below the header and above the footer. This can be useful for adding additional functionality to your resource pages.

To create a Tree Widget and apply it to a resource page, you can follow these steps:

1. Creating a Filament Resource Page

To create a resources page, run the following command:

php artisan make:filament-resource ProductCategory

2. Create Tree Widget

Prepare the filament-tree Widget and show it in Resource page.

php artisan make:filament-tree-widget ProductCategoryWidget

Now you can see the Widget in Filament Folder

<?php

namespace App\Filament\Widgets;

use App\Models\ProductCategory as ModelsProductCategory;
use App\Filament\Widgets;
use Filament\Forms\Components\TextInput;
use SolutionForest\FilamentTree\Widgets\Tree as BaseWidget;

class ProductCategoryWidget extends BaseWidget
{
    protected static string $model = ModelsProductCategory::class;

    // you can customize the maximum depth of your tree
    protected static int $maxDepth = 2;

    protected ?string $treeTitle = 'ProductCategory';

    protected bool $enableTreeTitle = true;

    protected function getFormSchema(): array
    {
        return [
            TextInput::make('title'),
        ];
    }
}

3. Displaying a widget on a resource page

Once you have created the widget, modify the getHeaderWidgets() or getFooterWidgets() methods of the resource page to show the tree view:

<?php

namespace App\Filament\Resources\ProductCategoryResource\Pages;

use App\Filament\Resources\ProductCategoryResource;
use App\Filament\Widgets\ProductCategory;
use Filament\Pages\Actions;
use Filament\Resources\Pages\ListRecords;

class ListProductCategories extends ListRecords
{
    protected static string $resource = ProductCategoryResource::class;

    protected function getActions(): array
    {
        return [
            Actions\CreateAction::make(),
        ];
    }

    protected function getHeaderWidgets(): array
    {
        return [
            ProductCategory::class
        ];
    }
}

Resources

Filament allows you to create a custom pages for resources, you also can create a tree page that display hierarchical data.

Create a Page

To create a tree page for resource, you can use:

php artisan make:filament-tree-page ProductCategoryTree --resource=ProductCategory

Register a Page to the resource

You must register the tree page to a route in the static getPages() methods of your resource. For example:

public static function getPages(): array
{
    return [
        // ...
        'tree-list' => Pages\ProductCategoryTree::route('/tree-list'),
    ];
}

Actions

Define the available "actions" for the tree page using the getActions() and getTreeActions() methods of your page class.

The getActions() method defines actions that are displayed next to the page's heading:

    use Filament\Pages\Actions\CreateAction;

    protected function getActions(): array
    {
        return [
            CreateAction::make(),
            // SAMPLE CODE, CAN DELETE
            //\Filament\Pages\Actions\Action::make('sampleAction'),
        ];
    }

The getTreeActions() method defines the actions that are displayed for each record in the tree. For example:

use Filament\Pages\Actions\Action;

protected function getTreeActions(): array
{
    return [
        Actions\ViewAction::make(),
        Actions\EditAction::make(),
        Actions\DeleteAction::make(),
    ];
}

Alternatively, you can use the hasDeleteAction(), hasEditAction(), and hasViewAction() methods to customize each action individually.

protected function hasDeleteAction(): bool
{
    return false;
}

protected function hasEditAction(): bool
{
    return true;
}

protected function hasViewAction(): bool
{
    return false;
}

Record ICON

To customize the prefix icon for each record in a tree page, you can use the getTreeRecordIcon() method in your tree page class. This method should return a string that represents the name of the icon you want to use for the record. For example:

public function getTreeRecordIcon(?\Illuminate\Database\Eloquent\Model $record = null): ?string
{
    // default null
    return 'heroicon-o-cake';
}

tree-icon

Node collapsed state

You can customize a collapsed state of the node. If you would like to show your tree initially collapsed you can use:

public function getNodeCollapsedState(?\Illuminate\Database\Eloquent\Model $record = null): bool
{
    // All tree nodes will be collapsed by default.
    return true;
}

Pages

This plugin enables you to create tree pages in the admin panel. To create a tree page for a model, use the make:filament-tree-page command. For example, to create a tree page for the ProductCategory model, you can run:

Create a Page

Tip: Note that you should make sure the model contains the required columns or already uses the ModelTree trait

php artisan make:filament-tree-page ProductCategory --model=ProductCategory

Actions, Widgets and Icon for each record

Once you've created the tree page, you can customize the available actions, widgets, and icon for each record. You can use the same methods as for resource pages. See the Resource Page for more information on how to customize actions, widgets, and icons.

Publishing Views

To publish the views, use:

php artisan vendor:publish --tag="filament-tree-views"

Publishing Translations

To publish the translations, use:

php artisan vendor:publish --tag="filament-tree-translations"

Testing

To run the tests, run:

composer test

Changelog

See the CHANGELOG for more information on what has changed recently.

Contributing

See CONTRIBUTING for details.

Security Vulnerabilities

If you discover any security related issues, please email [email protected] instead of using the issue tracker.

Credits

License

Filament Tree is open-sourced software licensed under the MIT license.

About Solution Forest

Solution Forest Web development agency based in Hong Kong. We help customers to solve their problems. We Love Open Soruces.

We have built a collection of best-in-class products:

filament-tree's People

Contributors

aslanutku avatar aymanalareqi avatar celaraze avatar cklei-carly avatar dev avatar dev3k avatar kelseylws avatar lam0819 avatar mohamedsabil83 avatar nasimic avatar progresivjose avatar sfkelseylee avatar skoro avatar tomiaa1926 avatar vanhooff avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

filament-tree's Issues

How to make custom query?

I have to filter data before showing in the tree.

Are there any ways that achieve somethings similar to this ?

public static function getEloquentQuery(): Builder
{
  return parent::getEloquentQuery()->where('visible', true);
}

Tree does not show up in widget

Not sure what I'm doing wrong here. Trying to create a category tree widget. However, no tree items show up at all within the widget.

I've followed the documentation exactly. I have some 'categories' in the table below the widget. But absolutely no categories in the widget.

My category migration, which successfully creates the required columns:

    public function up(): void
    {
        Schema::create('categories', function (Blueprint $table) {
            $table->id();
            $table->treeColumns();
            $table->string('slug')->unique();
            $table->timestamps();
        });
    }

My category model

<?php

namespace App\Models\Catalog;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;

class Category extends Model
{
    use HasFactory;

    protected $fillable = [
        'title',
        'slug',
        'parent_id',
        'order',
    ];

    public function products(): BelongsToMany
    {
        return $this->belongsToMany( Product::class );
    }

    public function children(): HasMany
    {
        return $this->hasMany( self::class, 'parent_id', 'id' )->orderBy( 'order' );
    }

    public function parent(): HasOne
    {
        return $this->hasOne( self::class, 'id', 'parent_id' );
    }
}

config/filament-tree.php config file

return [
    /**
     * Tree model fields
     */
    'column_name' => [
        'order' => 'order',
        'parent' => 'parent_id',
        'title' => 'title',
    ],
    /**
     * Tree model default parent key
     */
    'default_parent_id' => -1,
    /**
     * Tree model default children key name
     */
    'default_children_key_name' => 'children',
];

And my CategoryWidget

<?php

namespace App\Filament\Resources\Catalog\CategoryResource\Widgets;

use App\Models\Catalog\Category;
use Filament\Forms\Components\TextInput;
use SolutionForest\FilamentTree\Widgets\Tree as BaseWidget;

class CategoryWidget extends BaseWidget
{
    protected static string $model = Category::class;

    protected static int $maxDepth = 2;

    protected ?string $treeTitle = 'CategoryWidget';

    protected bool $enableTreeTitle = true;

    protected function getFormSchema(): array
    {
        return [
            TextInput::make('title')
        ];
    }

    // INFOLIST, CAN DELETE
    public function getViewFormSchema(): array {
        return [
            TextInput::make('title')
        ];
    }
}

The widget shows up, and I have categories in the table below. But no tree items.
image

Duplicate Name and Slug Per Level

Description

Through a round-about manner, you are able to have duplicate category names and slugs on the same level.

Steps to Reproduce

  • Create a category with name "Test Category" and slug "test-category"
  • Attempt to create a category with name "Test Category" and slug "test-category" with no parent, notice that it is disallowed due to a duplicate name and slug on the hierarchy level
  • Create a sub-category with name "Test Category" and slug "test-category" with the previously created record as it's parent
  • Use the table interface to drag the child category to the top level and save the re-ordering, notice that this is allowed.

V3 upgrade?

Are there any plans to make this v3 compatible?

Should work with NULL parent_id

You lose foreign key constraints with the -1 thing which is kind of no bueno. Is there a reason it doesn't work with nulls?

How to load custom data fro filament-tree package?

On laravel 9 filamenphp site I need to show data in tree and I found this
https://github.com/solutionforest/filament-tree
plugin.

But source of this plugin is 1 table, not as in my case when I need to combine data from 3 sources and 2 of them are non related tables.
If there is a way to load my custom data into this plugin?

I suppose it looks some laravel feature...
Has it any

    "filament/filament": "^2.17.39",
    "filament/forms": "^2.17.39",
    "laravel/framework": "^9.52.7",

Thanks in advance!

SolutionForest\FilamentTree\Support\Utils::buildNestedArray returns empty array when using null as parentId

I know the documentation recommends using -1, but, I think it makes more sense to use use null as the value for the parentId field of root items. Using null allows for simple parent() relationship, cascade deletes, etc because the parent_id column can be nullable.

Anyway, the tree component actually DOES work when using null for this value. However, none of the functions in the ModelTree trait that rely on the Utils::buildNestedArray function work when using null. For example treeNodes, selectArray all return empty arrays.

I believe one fix for this issue would be to modify the condition on line 62 of SolutionForest\FilamentTree\Support\Utils to check for a null parentId. E.g changing the condtion to below, allows Utils::buildNestedArray to work with null.

if ( ($pk === $parentId) || ($pk === '' && $parentId === 0) ) {

Max Depth not working - unable to make tree with more parents than 1

Hello,
I tried the package and it works pretty well but even though i have my maxDepth set to 4 - im unable to drag&drop elements deeper than 1 parent. Looks like its just the JS that wont allow me to snap an element to the one that already has a parent. If i manually change the parent_id - it build the tree correctly and then allows me to snap to the child node.

window.livewire.find is not a function

Hi,
I used this package as dependency with your Access-Management-Package.

But I can not save sorted states. If I click on save-button i get JS-Error:

window.livewire.find is not a function

This error located in filament-tree/resources/views/scripts.blade.php on Line 48.

(btw. there is a console.log, which should not be called in production)

`php artisan view:cache` Throws an Exception

Description

When running php artisan view:cache in a new application with Filament V3 and filament-tree. An exception is thrown and it fails to run.

Versions

OS: Mac OS Ventura v13.5.1
PHP v8.1.21
Laravel v10.25.2
Filament v3.0.62
Livewire v3.0.5

Exception

   InvalidArgumentException 

  Unable to locate a class or view for component [forms::icon-button].

  at vendor/laravel/framework/src/Illuminate/View/Compilers/ComponentTagCompiler.php:311
    307▕         if (Str::startsWith($component, 'mail::')) {
    308▕             return $component;
    309▕         }
    310▕ 
  ➜ 311▕         throw new InvalidArgumentException(
    312▕             "Unable to locate a class or view for component [{$component}]."
    313▕         );
    314▕     }
    315▕ 

      +2 vendor frames 
  3   [internal]:0
      Illuminate\View\Compilers\ComponentTagCompiler::Illuminate\View\Compilers\{closure}()

      +7 vendor frames 
  11  [internal]:0
      Illuminate\Foundation\Console\ViewCacheCommand::Illuminate\Foundation\Console\{closure}(Object(Symfony\Component\Finder\SplFileInfo), "/Users/nicole/Sites/package-testing/vendor/solution-forest/filament-tree/src/../resources/views/forms/tree.blade.php")

Cannot read properties of undefined (reading 'nestable')

Hi, I'm facing the following issue:

Alpine Expression Error: Cannot read properties of undefined (reading 'nestable')

Expression: "function () {

let nestedTree = $('#filament_tree_container_BxCAKyCkwLPukL2rHBKg').nestable
.
.
.

To be exact, it's happening in components/tree/index.php file. Looks like its not able to find the JQuery here. $('#{{ $containerKey }}') returns undefined while document.getElementById('{{ $containerKey }}') returns object.

Need SBS (step-by-step) documentation

  1. if I generate only a page (without resource) then "SolutionForest\FilamentTree\Pages\TreePage::getTreeRecordTitle(): Return value must be of type string, null returned" is appeared
  2. if I generate a page (with resource) then how do I access them with proper routing???
  3. what about migration for model that needs tree

Use table-actions

Hey,

is there a way to use native table actions (for creating and editing).
I am building very complex forms that do not work well in a modal action.

Create and edit pages instead of modal style.

Hello,

Is it possible to use the pages defined in the getPages() function of the resource to create and edit a tree item instead of using the modal functionality?

I hope my question isn't too silly.

Regards

class CreationResource extends Resource
{
    protected static ?string $model = Creation::class;
    
    public static function form(Form $form): Form
    {
        return $form
            ->schema([
                Forms\Components\Hidden::make('id')->dehydrated(),
                Forms\Components\TextInput::make('title'),
                // etc...

            ]);
    }

    public static function getPages(): array
    {
        return [
            'index' => Pages\CreationTree::route('/'),
            'create' => Pages\CreateCreation::route('/create'),
            'edit' => Pages\EditCreation::route('/{record}/edit'),
        ];
    }
}

Can't expand after using 'collapse all' button

You can't expand the tree parts after using 'collapse all' button.

Steps to reproduce:

  1. See your demo: https://filament-cms-website-demo.solutionforest.net/admin/product-categories
  2. Click button 'Collapse all'
  3. Click on the 'arrow up' on 't-shirt'.

You'll see the arrow change but the tree not expanding. If you click 'expand all' the toggle starts working again.

My browser is Chrome 113.0.5672.126 (Official Build) (x86_64) on MacOS Ventura 13.1 (22C65).

Drag-to-Reorder Handle Coloring in "Dark Mode"

Description

When Filament is running under "Dark Mode", the coloring looks out of place for the drag-to-reorder handles. It looks fine in light mode. There should probably also be some margin between the handle and the text next to it.

Screenshots

image

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.