From 4a8b6dd247e83dbd8ac7faa5e88a13bbbdfded46 Mon Sep 17 00:00:00 2001 From: Naffah Abdulla Rasheed Date: Thu, 1 Oct 2026 11:33:30 +0500 Subject: [PATCH] feat: Create role form and permission list component --- composer.json | 3 +- .../components/floating-submit.blade.php | 4 + .../material-admin-26/errors/_list.blade.php | 7 + .../material-admin-26/roles/_form.blade.php | 15 ++ .../roles/form/_general.blade.php | 32 ++++ .../roles/form/_permissions.blade.php | 170 ++++++++++++++++++ src/PermissionsServiceProvider.php | 8 + src/Views/Components/Component.php | 53 ++++++ src/Views/Components/PermissionList.php | 31 ++++ src/Views/Components/RoleForm.php | 35 ++++ tests/Feature/RoleFormTest.php | 92 ++++++++++ 11 files changed, 449 insertions(+), 1 deletion(-) create mode 100644 resources/views/material-admin-26/components/floating-submit.blade.php create mode 100644 resources/views/material-admin-26/errors/_list.blade.php create mode 100644 resources/views/material-admin-26/roles/_form.blade.php create mode 100644 resources/views/material-admin-26/roles/form/_general.blade.php create mode 100644 resources/views/material-admin-26/roles/form/_permissions.blade.php create mode 100644 src/Views/Components/Component.php create mode 100644 src/Views/Components/PermissionList.php create mode 100644 src/Views/Components/RoleForm.php create mode 100644 tests/Feature/RoleFormTest.php diff --git a/composer.json b/composer.json index 73c1a32..7429915 100644 --- a/composer.json +++ b/composer.json @@ -18,7 +18,8 @@ }, "require-dev": { "orchestra/testbench": "^10.0 || ^11.0", - "phpunit/phpunit": "^12.5.8 || ^13.0.3" + "phpunit/phpunit": "^12.5.8 || ^13.0.3", + "javaabu/forms": "^1.71" }, "autoload": { "psr-4": { diff --git a/resources/views/material-admin-26/components/floating-submit.blade.php b/resources/views/material-admin-26/components/floating-submit.blade.php new file mode 100644 index 0000000..c5c729c --- /dev/null +++ b/resources/views/material-admin-26/components/floating-submit.blade.php @@ -0,0 +1,4 @@ + diff --git a/resources/views/material-admin-26/errors/_list.blade.php b/resources/views/material-admin-26/errors/_list.blade.php new file mode 100644 index 0000000..b73422e --- /dev/null +++ b/resources/views/material-admin-26/errors/_list.blade.php @@ -0,0 +1,7 @@ +@unless(empty($error)) + +@endunless \ No newline at end of file diff --git a/resources/views/material-admin-26/roles/_form.blade.php b/resources/views/material-admin-26/roles/_form.blade.php new file mode 100644 index 0000000..2e346a1 --- /dev/null +++ b/resources/views/material-admin-26/roles/_form.blade.php @@ -0,0 +1,15 @@ +@include('permissions::material-admin-26.roles.form._general') + + + +
+ + + + {{ __('Cancel') }} + +
+ +@include('permissions::material-admin-26.components.floating-submit') diff --git a/resources/views/material-admin-26/roles/form/_general.blade.php b/resources/views/material-admin-26/roles/form/_general.blade.php new file mode 100644 index 0000000..2777b92 --- /dev/null +++ b/resources/views/material-admin-26/roles/form/_general.blade.php @@ -0,0 +1,32 @@ +
+
+
+
+ +
+ +
+ +
+
+
+
+ + +@push('scripts') + +@endpush diff --git a/resources/views/material-admin-26/roles/form/_permissions.blade.php b/resources/views/material-admin-26/roles/form/_permissions.blade.php new file mode 100644 index 0000000..13b07a7 --- /dev/null +++ b/resources/views/material-admin-26/roles/form/_permissions.blade.php @@ -0,0 +1,170 @@ +@php + use Illuminate\Support\Str; + $permissions = $permissions->groupBy('model'); +@endphp + +
+
+
+
+ + {{ __('All Permissions') }} + + +
+
+
+ +
+ + +
+
+
+ + @include('permissions::material-admin-26.errors._list', ['error' => $errors->get('permissions')]) +
+
+ +
+ @foreach($permissions as $model => $model_permissions) + @php + $model_slug = Str::slug($model); + @endphp + +
+
+ + +
+
+ @foreach($model_permissions as $permission) + @php + $checked = (isset($role) && $role->hasPermissionTo($permission)) || safe_in_array($permission->id, old('permissions')); + @endphp + + + {{ $permission->description }} + + @endforeach +
+
+
+
+ @endforeach +
+
+ +@push('scripts') + +@endpush diff --git a/src/PermissionsServiceProvider.php b/src/PermissionsServiceProvider.php index 212ccc1..8d8e657 100644 --- a/src/PermissionsServiceProvider.php +++ b/src/PermissionsServiceProvider.php @@ -24,8 +24,16 @@ public function boot(): void $this->publishes([ __DIR__ . '/../config/permission.php' => config_path('permission.php'), ], 'permissions-config'); + + $this->publishes([ + __DIR__ . '/../resources/views' => resource_path('views/vendor/permissions'), + ], 'permissions-views'); } + $this->loadViewsFrom(__DIR__ . '/../resources/views', 'permissions'); + + Blade::componentNamespace('Javaabu\\Permissions\\Views\\Components', 'permissions'); + /** * Returns true if the user has any of the permissions */ diff --git a/src/Views/Components/Component.php b/src/Views/Components/Component.php new file mode 100644 index 0000000..fb2fe05 --- /dev/null +++ b/src/Views/Components/Component.php @@ -0,0 +1,53 @@ +framework = $framework; + } + + public function getView(): string + { + return 'permissions::{framework}.' . $this->view; + } + + /** + * {@inheritDoc} + */ + public function render() + { + $view = $this->getView(); + + $framework = $this->framework; + + return str_replace('{framework}', $framework, $view); + } +} diff --git a/src/Views/Components/PermissionList.php b/src/Views/Components/PermissionList.php new file mode 100644 index 0000000..c04b747 --- /dev/null +++ b/src/Views/Components/PermissionList.php @@ -0,0 +1,31 @@ +role = $role; + $this->permissions = $permissions; + } +} diff --git a/src/Views/Components/RoleForm.php b/src/Views/Components/RoleForm.php new file mode 100644 index 0000000..f012f8e --- /dev/null +++ b/src/Views/Components/RoleForm.php @@ -0,0 +1,35 @@ +role = $role; + $this->permissions = $permissions; + $this->cancel_redirect_url = $cancelRedirectUrl ?: '#'; + } +} diff --git a/tests/Feature/RoleFormTest.php b/tests/Feature/RoleFormTest.php new file mode 100644 index 0000000..2ff5681 --- /dev/null +++ b/tests/Feature/RoleFormTest.php @@ -0,0 +1,92 @@ +runMigrations(); + + // Session is needed by forms package to retrieve old form valuues using old() helper + $this->app['request']->setLaravelSession($this->app['session']->driver()); + View::share('errors', new ViewErrorBag()); + } + + #[Test] + public function it_renders_a_role_form_with_permissions_and_an_cancel_redirect_link(): void + { + $permission = Permission::create([ + 'name' => 'edit-posts', + 'description' => 'Edit posts', + 'model' => 'posts', + 'guard_name' => 'web', + ]); + + $html = Blade::render( + '', + ['permissions' => Permission::all()] + ); + + $this->assertStringContainsString('name="description"', $html); + $this->assertStringContainsString('name="name"', $html); + $this->assertStringContainsString('name="permissions[]"', $html); + $this->assertStringContainsString('value="'.$permission->id.'"', $html); + $this->assertStringContainsString('Edit posts', $html); + $this->assertStringContainsString('href="/admin/roles"', $html); + } + + #[Test] + public function it_uses_the_default_framework_and_cancel_redirect_url(): void + { + Route::get('/admin/roles', fn () => '')->name('admin.roles.index'); + + $html = Blade::render( + '', + ['permissions' => collect()] + ); + + $this->assertStringContainsString('#', $html); + $this->assertStringContainsString('name="description"', $html); + } + + #[Test] + public function it_checks_permissions_assigned_to_the_role(): void + { + $permission = Permission::create([ + 'name' => 'edit-posts', + 'description' => 'Edit posts', + 'model' => 'posts', + 'guard_name' => 'web', + ]); + $role = Role::create(['name' => 'Editor', 'guard_name' => 'web']); + $role->givePermissionTo($permission); + + $html = Blade::render( + '', + ['permissions' => Permission::all(), 'role' => $role] + ); + + $this->assertMatchesRegularExpression('/]*id="permission-'.$permission->id.'"[^>]*checked/', $html); + } +}