diff --git a/README.md b/README.md index c355e3d..02c1346 100644 --- a/README.md +++ b/README.md @@ -325,6 +325,29 @@ The main configuration file `config/buildora.php` contains: ### Navigation Structure ```php 'navigation' => [ + // Link to a Buildora resource + [ + 'label' => 'Users', + 'icon' => 'fas fa-user', + 'route' => 'buildora.index', + 'params' => ['resource' => 'user'], + ], + + // Link to an external URL + [ + 'label' => 'Documentation', + 'icon' => 'fas fa-book', + 'url' => 'https://docs.example.com', + ], + + // Link to a custom Laravel route + [ + 'label' => 'Back to site', + 'icon' => 'fas fa-home', + 'url' => '/', + ], + + // Nested navigation with children [ 'label' => 'Settings', 'icon' => 'fas fa-cog', @@ -335,12 +358,24 @@ The main configuration file `config/buildora.php` contains: 'route' => 'buildora.index', 'params' => ['resource' => 'user'], ], + [ + 'label' => 'Permissions', + 'icon' => 'fas fa-lock', + 'route' => 'buildora.index', + 'params' => ['resource' => 'permission'], + ], ], ], - 'include_resources' => true, // Auto-include all resources + + 'include_resources' => true, // Auto-include all resources not manually defined ], ``` +Navigation items support: +- `route` + `params`: Link to a named Laravel route +- `url`: Direct URL (internal or external) +- `children`: Nested dropdown menu + --- ## 14. All Available Commands diff --git a/composer.json b/composer.json index 164c2fe..fe7f5fa 100644 --- a/composer.json +++ b/composer.json @@ -21,10 +21,11 @@ "livewire/livewire": "^3.0", "maatwebsite/excel": "^3.1", "pragmarx/google2fa": "^8.0", - "spatie/laravel-permission": "^6.16" + "spatie/laravel-permission": "^6.16", + "binarytorch/larecipe": "^2.0" }, "extra": { - "buildora-version": "1.0.36", + "buildora-version": "1.0.37", "laravel": { "providers": [ "Ginkelsoft\\Buildora\\Providers\\BuildoraServiceProvider" diff --git a/config/buildora.php b/config/buildora.php index 74f3c9b..cd99fc2 100644 --- a/config/buildora.php +++ b/config/buildora.php @@ -125,6 +125,18 @@ ], 'include_resources' => true, + + [ + 'label' => 'Buildora', + 'icon' => 'fas fa-cog', + 'children' => [ + [ + 'label' => 'Settings', + 'icon' => 'fas fa-sliders', + 'route' => 'buildora.settings', + ], + ], + ], ], /* diff --git a/config/larecipe.php b/config/larecipe.php new file mode 100644 index 0000000..37565d2 --- /dev/null +++ b/config/larecipe.php @@ -0,0 +1,98 @@ + [ + 'route' => '/buildora/docs', + 'path' => '/resources/docs', + 'landing' => 'index', + 'middleware' => ['web'], + ], + + /* + |-------------------------------------------------------------------------- + | Documentation Versions + |-------------------------------------------------------------------------- + | + | Here you can define the available documentation versions. + | + */ + + 'versions' => [ + 'default' => '1.0', + 'published' => [ + '1.0', + ], + ], + + /* + |-------------------------------------------------------------------------- + | Documentation Settings + |-------------------------------------------------------------------------- + | + | Configure documentation behavior. + | + */ + + 'settings' => [ + 'auth' => false, + 'ga_id' => '', + 'middleware' => [], + 'edit_on_github' => [ + 'enabled' => true, + 'repo' => 'https://github.com/ginkelsoft/buildora', + 'branch' => 'main', + ], + ], + + /* + |-------------------------------------------------------------------------- + | Appearance + |-------------------------------------------------------------------------- + | + | Configure the appearance of the documentation. + | + */ + + 'ui' => [ + 'code_theme' => 'dark', + 'fav' => '', + 'fa_v4_shims' => true, + 'show_side_bar' => true, + 'colors' => [ + 'primary' => '#667eea', + 'secondary' => '#e8f4f8', + ], + 'theme_order' => null, + ], + + /* + |-------------------------------------------------------------------------- + | SEO + |-------------------------------------------------------------------------- + | + | Configure SEO settings. + | + */ + + 'seo' => [ + 'author' => 'Ginkelsoft', + 'description' => 'Buildora - Laravel Admin Panel Package Documentation', + 'keywords' => 'laravel, admin panel, crud, buildora, datatables', + 'og' => [ + 'title' => 'Buildora Documentation', + 'type' => 'website', + 'url' => '', + 'image' => '', + 'description' => 'Buildora - Laravel Admin Panel Package Documentation', + ], + ], +]; diff --git a/package.json b/package.json index 5228a3f..c1c5add 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "buildora", - "version": "1.0.36", + "version": "1.0.37", "description": "Buildora resource engine", "main": "index.js", "scripts": { diff --git a/resources/docs/1.0/actions.md b/resources/docs/1.0/actions.md new file mode 100644 index 0000000..2f64b39 --- /dev/null +++ b/resources/docs/1.0/actions.md @@ -0,0 +1,271 @@ +# Actions + +--- + +- [Introduction](#introduction) +- [Row Actions](#row-actions) +- [Bulk Actions](#bulk-actions) +- [Page Actions](#page-actions) +- [Full Example](#example) + + +## Introduction + +Actions allow users to perform operations on records. Buildora supports three types: Row Actions, Bulk Actions, and Page Actions. + + +## Row Actions + +Row actions appear in the actions column of the datatable and operate on individual records. + +### Creating Row Actions + +```php +use Ginkelsoft\Buildora\Actions\RowAction; + +public function defineRowActions(): array +{ + return [ + RowAction::make('View Details', 'fas fa-eye', 'route', 'products.show') + ->params(['id' => 'id']), + + RowAction::make('Edit', 'fas fa-edit', 'route', 'buildora.edit') + ->params(['resource' => 'products', 'id' => 'id']), + + RowAction::make('Delete', 'fas fa-trash', 'route', 'buildora.destroy') + ->method('DELETE') + ->confirm('Are you sure you want to delete this product?'), + ]; +} +``` + +### RowAction Methods + +#### make() + +Factory method to create a new action: + +```php +RowAction::make( + string $label, // Button label + string $icon, // FontAwesome icon class + string $type, // 'route' or 'url' + string $action // Route name or URL +): RowAction +``` + +#### method() + +Set the HTTP method: + +```php +->method('GET') // Default +->method('POST') +->method('PUT') +->method('DELETE') +``` + +#### params() + +Define route parameters. Use the field name as the value to substitute: + +```php +->params(['id' => 'id']) // Substitutes record's 'id' field +->params([ + 'resource' => 'products', // Static value + 'id' => 'id', // Dynamic from record +]) +``` + +#### confirm() + +Show a confirmation dialog before executing: + +```php +->confirm('Are you sure you want to delete this item?') +``` + +#### permission() + +Require a permission to see/use this action: + +```php +->permission('product.delete') +``` + + +## Bulk Actions + +Bulk actions operate on multiple selected records from the datatable. + +### Creating Bulk Actions + +```php +use Ginkelsoft\Buildora\Actions\BulkAction; + +public function defineBulkActions(): array +{ + return [ + BulkAction::make('Delete Selected', 'products.bulk-delete') + ->method('DELETE') + ->permission('product.delete'), + + BulkAction::make('Export Selected', 'products.bulk-export') + ->method('POST') + ->permission('product.export'), + ]; +} +``` + +### BulkAction Methods + +#### make() + +```php +BulkAction::make( + string $label, // Button label + string $route, // Route name + array $parameters = [] // Additional route parameters +): BulkAction +``` + +#### method() + +```php +->method('POST') // Default +->method('DELETE') +``` + +#### permission() + +```php +->permission('product.bulk-delete') +``` + +### Handling Bulk Actions + +In your controller, receive the selected IDs: + +```php +// routes/web.php +Route::post('products/bulk-publish', [ProductController::class, 'bulkPublish']) + ->name('products.bulk-publish'); + +// ProductController.php +public function bulkPublish(Request $request) +{ + $ids = $request->input('ids', []); + Product::whereIn('id', $ids)->update(['status' => 'published']); + return back()->with('success', count($ids) . ' products published.'); +} +``` + +> {info} Buildora automatically includes export actions (XLSX, CSV) for bulk operations. + + +## Page Actions + +Page actions appear in the header of the index page. + +```php +use Ginkelsoft\Buildora\Actions\PageAction; + +public function definePageActions(): array +{ + return [ + PageAction::make('Import Products', 'products.import') + ->icon('fas fa-upload') + ->permission('product.import'), + ]; +} +``` + + +## Full Example + +```php +params(['resource' => 'products', 'id' => 'id']) + ->permission('product.view'), + + RowAction::make('Edit', 'fas fa-edit', 'route', 'buildora.edit') + ->params(['resource' => 'products', 'id' => 'id']) + ->permission('product.edit'), + + RowAction::make('Duplicate', 'fas fa-copy', 'route', 'products.duplicate') + ->method('POST') + ->params(['id' => 'id']) + ->confirm('Create a copy of this product?') + ->permission('product.create'), + + RowAction::make('Delete', 'fas fa-trash', 'route', 'buildora.destroy') + ->method('DELETE') + ->params(['resource' => 'products', 'id' => 'id']) + ->confirm('Delete this product?') + ->permission('product.delete'), + ]; + } + + public function defineBulkActions(): array + { + return [ + BulkAction::make('Publish Selected', 'products.bulk-publish') + ->method('POST') + ->permission('product.publish'), + + BulkAction::make('Delete Selected', 'products.bulk-delete') + ->method('DELETE') + ->permission('product.delete'), + ]; + } + + public function definePageActions(): array + { + return [ + PageAction::make('Import', 'products.import') + ->icon('fas fa-upload') + ->permission('product.import'), + + PageAction::make('Export All', 'products.export-all') + ->icon('fas fa-download') + ->permission('product.export'), + ]; + } +} +``` + +## Action Icons + +Common FontAwesome icons: + +| Action | Icon | +|--------|------| +| View | `fas fa-eye` | +| Edit | `fas fa-edit` | +| Delete | `fas fa-trash` | +| Duplicate | `fas fa-copy` | +| Download | `fas fa-download` | +| Upload | `fas fa-upload` | +| Print | `fas fa-print` | +| Email | `fas fa-envelope` | diff --git a/resources/docs/1.0/commands.md b/resources/docs/1.0/commands.md new file mode 100644 index 0000000..f801eca --- /dev/null +++ b/resources/docs/1.0/commands.md @@ -0,0 +1,148 @@ +# Artisan Commands + +--- + +- [Resource Commands](#resource) +- [Widget Commands](#widget) +- [Permission Commands](#permission) +- [User Commands](#user) +- [Installation Commands](#installation) + + +## Resource Commands + +### buildora:resource + +Generate a new Buildora resource for an Eloquent model. + +```bash +php artisan buildora:resource {ModelName} +``` + +**Example:** +```bash +php artisan buildora:resource Product +``` + +Creates `app/Buildora/Resources/ProductBuildora.php` with auto-detected fields from database schema. + +### buildora:make-permission-resource + +Generate the Permission resource for managing permissions. + +```bash +php artisan buildora:make-permission-resource +``` + + +## Widget Commands + +### buildora:widget + +Interactive command to generate a widget. + +```bash +php artisan buildora:widget +``` + +Creates: +- Widget class: `app/Buildora/Widgets/{Name}Widget.php` +- Blade view: `resources/views/buildora/widgets/{name}.blade.php` + + +## Permission Commands + +### buildora:generate-permissions + +Generate permissions for all Buildora resources. + +```bash +php artisan buildora:generate-permissions +``` + +Creates permissions: `{resource}.view`, `{resource}.create`, `{resource}.edit`, `{resource}.delete` + +### buildora:sync-permissions + +Synchronize permissions with the database. + +```bash +php artisan buildora:sync-permissions +``` + +### buildora:grant-permissions + +Grant all Buildora permissions to a user. + +```bash +php artisan buildora:grant-permissions {user_id} +``` + +### buildora:permission:grant-resource + +Grant all permissions for a specific resource to a user. + +```bash +php artisan buildora:permission:grant-resource {user_id} {resource} +``` + +**Example:** +```bash +php artisan buildora:permission:grant-resource 1 product +``` + + +## User Commands + +### buildora:user:create + +Interactive command to create a new admin user. + +```bash +php artisan buildora:user:create +``` + + +## Installation Commands + +### buildora:install + +Run the Buildora installation wizard. + +```bash +php artisan buildora:install +``` + +### buildora:upgrade + +Upgrade an existing Buildora installation. + +```bash +php artisan buildora:upgrade +``` + +## Publishing Assets + +```bash +# Publish configuration +php artisan vendor:publish --tag=buildora-config + +# Publish views +php artisan vendor:publish --tag=buildora-views + +# Publish theme +php artisan vendor:publish --tag=buildora-theme +``` + +## Quick Reference + +| Command | Description | +|---------|-------------| +| `buildora:install` | Initial installation | +| `buildora:upgrade` | Upgrade installation | +| `buildora:resource {Model}` | Generate resource | +| `buildora:widget` | Generate widget | +| `buildora:generate-permissions` | Generate all permissions | +| `buildora:sync-permissions` | Sync permissions | +| `buildora:grant-permissions {id}` | Grant all permissions | +| `buildora:user:create` | Create admin user | diff --git a/resources/docs/1.0/configuration.md b/resources/docs/1.0/configuration.md new file mode 100644 index 0000000..dac4046 --- /dev/null +++ b/resources/docs/1.0/configuration.md @@ -0,0 +1,251 @@ +# Configuration + +--- + +- [Publishing Configuration](#publishing) +- [Route Settings](#routes) +- [Datatable Settings](#datatable) +- [File Upload Settings](#files) +- [Dashboard Configuration](#dashboard) +- [Navigation](#navigation) +- [Default Resources](#resources) + + +## Publishing Configuration + +```bash +php artisan vendor:publish --tag=buildora-config +``` + +This creates `config/buildora.php` in your application. + + +## Route Settings + +### Route Prefix + +The URL prefix for all Buildora routes: + +```php +'route_prefix' => 'buildora', +``` + +Your admin panel will be accessible at `/buildora/...` + +Change to `'admin'` for URLs like `/admin/resource/users`. + +### Middleware + +Middleware applied to all Buildora routes: + +```php +'middleware' => [ + 'web', + 'buildora.auth', + 'buildora.ensure-user-resource', +], +``` + +Add your own middleware: + +```php +'middleware' => [ + 'web', + 'buildora.auth', + 'buildora.ensure-user-resource', + 'verified', // Require email verification +], +``` + + +## Datatable Settings + +Pagination options for datatables: + +```php +'datatable' => [ + 'pagination' => [10, 25, 50, 100, 250], + 'default_per_page' => 25, +], +``` + + +## File Upload Settings + +Configure file upload behavior: + +```php +'files' => [ + 'default_disk' => 'public', + 'default_path' => 'uploads', + 'max_upload_size_kb' => 2048, + 'previewable' => ['jpg', 'jpeg', 'png', 'pdf'], +], +``` + +| Option | Description | +|--------|-------------| +| `default_disk` | Laravel filesystem disk | +| `default_path` | Default upload path | +| `max_upload_size_kb` | Maximum file size in KB | +| `previewable` | File types that show inline preview | + + +## Dashboard Configuration + +```php +'dashboards' => [ + 'enabled' => true, + 'label' => 'Dashboard', + 'icon' => 'fa fa-gauge', + 'route' => 'buildora.dashboard', + 'permission' => 'dashboard.view', + 'widgets' => [ + \App\Buildora\Widgets\StatsWidget::class, + \App\Buildora\Widgets\RecentActivityWidget::class, + ], +], +``` + +| Option | Description | +|--------|-------------| +| `enabled` | Show dashboard in navigation | +| `label` | Navigation label | +| `icon` | FontAwesome icon class | +| `route` | Dashboard route name | +| `permission` | Required permission | +| `widgets` | Array of widget classes | + + +## Navigation + +Define custom navigation structure: + +```php +'navigation' => [ + [ + 'label' => 'Dashboard', + 'icon' => 'fas fa-gauge', + 'route' => 'buildora.dashboard', + ], + [ + 'label' => 'Products', + 'icon' => 'fas fa-box', + 'route' => 'buildora.index', + 'route_params' => ['resource' => 'products'], + ], + [ + 'label' => 'Settings', + 'icon' => 'fas fa-cog', + 'children' => [ + [ + 'label' => 'Users', + 'route' => 'buildora.index', + 'route_params' => ['resource' => 'users'], + ], + [ + 'label' => 'Permissions', + 'route' => 'buildora.index', + 'route_params' => ['resource' => 'permissions'], + ], + ], + ], + 'include_resources' => true, // Auto-include all resources +], +``` + +### Navigation Item Options + +| Option | Description | +|--------|-------------| +| `label` | Display text | +| `icon` | FontAwesome icon | +| `route` | Route name | +| `route_params` | Route parameters | +| `url` | External URL (instead of route) | +| `children` | Nested navigation items | +| `permission` | Required permission | + + +## Default Resources + +Configure built-in resources: + +```php +'resources' => [ + 'defaults' => [ + 'user' => [ + 'enabled' => true, + 'class' => \Ginkelsoft\Buildora\Resources\Defaults\UserBuildora::class, + ], + 'permission' => [ + 'enabled' => true, + 'class' => \Ginkelsoft\Buildora\Resources\Defaults\PermissionBuildora::class, + ], + ], +], +``` + +Disable a default resource: + +```php +'user' => [ + 'enabled' => false, +], +``` + +Use a custom class: + +```php +'user' => [ + 'enabled' => true, + 'class' => \App\Buildora\Resources\CustomUserBuildora::class, +], +``` + +## Full Example + +```php + 'admin', + + 'middleware' => [ + 'web', + 'buildora.auth', + 'buildora.ensure-user-resource', + ], + + 'models_namespace' => 'App\\Models\\', + + 'datatable' => [ + 'pagination' => [10, 25, 50, 100], + 'default_per_page' => 25, + ], + + 'files' => [ + 'default_disk' => 'public', + 'default_path' => 'uploads', + 'max_upload_size_kb' => 5120, + 'previewable' => ['jpg', 'jpeg', 'png', 'gif', 'webp', 'pdf'], + ], + + 'dashboards' => [ + 'enabled' => true, + 'label' => 'Dashboard', + 'icon' => 'fa fa-gauge', + 'permission' => 'dashboard.view', + 'widgets' => [ + \App\Buildora\Widgets\StatsWidget::class, + ], + ], + + 'resources' => [ + 'defaults' => [ + 'user' => ['enabled' => true], + 'permission' => ['enabled' => true], + ], + ], +]; +``` diff --git a/resources/docs/1.0/fields.md b/resources/docs/1.0/fields.md new file mode 100644 index 0000000..8e9a1ae --- /dev/null +++ b/resources/docs/1.0/fields.md @@ -0,0 +1,391 @@ +# Fields + +--- + +- [Introduction](#introduction) +- [Common Methods](#common-methods) +- [Text Input Fields](#text-fields) +- [Date & Time Fields](#date-fields) +- [Selection Fields](#selection-fields) +- [Relationship Fields](#relationship-fields) +- [Content Fields](#content-fields) +- [File Upload Field](#file-field) + + +## Introduction + +Fields are the building blocks that define how model attributes are displayed and edited. Buildora provides 20+ field types out of the box. + +All fields follow a fluent API pattern: + +```php +TextField::make('name', 'Display Label') + ->searchable() + ->sortable() + ->validation(['required', 'max:255']) + ->columnSpan(6); +``` + + +## Common Methods + +These methods are available on all field types: + +### Display + +```php +->label('Custom Label') // Override the display label +->help('Help text here') // Show help text below the field +->readonly() // Make the field read-only +->readonly(fn($model) => $model->is_locked) // Conditional readonly +``` + +### Table & Search + +```php +->sortable() // Enable sorting in datatable +->searchable() // Enable searching on this field +->searchable('custom_column') // Search on a different column +->notSearchable() // Explicitly disable search +``` + +### Visibility + +Control where the field appears: + +```php +->hideFromTable() // Hide from index/list view +->hideFromCreate() // Hide from create form +->hideFromEdit() // Hide from edit form +->hideFromDetail() // Hide from detail/show page +->hideFromExport() // Hide from exports +->hideOnForms() // Hide from both create and edit +``` + +### Layout + +Control form layout using a 12-column grid: + +```php +->columnSpan(6) // 50% width (6 of 12 columns) +->columnSpan(12) // Full width +->columnSpan(4) // 33% width + +// Responsive column spans +->columnSpan([ + 'default' => 12, // Full width on mobile + 'md' => 6, // 50% on medium screens + 'lg' => 4, // 33% on large screens +]) + +->startNewRow() // Force this field to start a new row +``` + +--- + + +## Text Input Fields + +### TextField + +Basic text input for strings. + +```php +use Ginkelsoft\Buildora\Fields\Types\TextField; + +TextField::make('name', 'Full Name') + ->searchable() + ->sortable() + ->validation(['required', 'max:255']); +``` + +### EmailField + +Email input with automatic validation. + +```php +use Ginkelsoft\Buildora\Fields\Types\EmailField; + +EmailField::make('email', 'Email Address') + ->searchable() + ->sortable(); +``` + +### PasswordField + +Password input with automatic hashing. + +```php +use Ginkelsoft\Buildora\Fields\Types\PasswordField; + +PasswordField::make('password', 'Password') + ->hideFromTable() + ->help('Leave empty to keep current password'); +``` + +> {info} Empty passwords are ignored on update, and values are automatically hashed with `bcrypt()`. + +### NumberField + +Numeric input. + +```php +use Ginkelsoft\Buildora\Fields\Types\NumberField; + +NumberField::make('quantity', 'Quantity') + ->sortable() + ->validation(['required', 'integer', 'min:0']); +``` + +### CurrencyField + +Formatted currency display. + +```php +use Ginkelsoft\Buildora\Fields\Types\CurrencyField; + +CurrencyField::make('price', 'Price') + ->sortable(); +``` + +--- + + +## Date & Time Fields + +### DateField + +Date input with customizable format. + +```php +use Ginkelsoft\Buildora\Fields\Types\DateField; + +DateField::make('birth_date', 'Birth Date') + ->format('d-m-Y') // Display format + ->sortable(); +``` + +### DateTimeField + +Date and time input. + +```php +use Ginkelsoft\Buildora\Fields\Types\DateTimeField; + +DateTimeField::make('published_at', 'Published At') + ->format('d-m-Y H:i') + ->sortable(); +``` + +--- + + +## Selection Fields + +### BooleanField + +Toggle/checkbox for boolean values. + +```php +use Ginkelsoft\Buildora\Fields\Types\BooleanField; + +BooleanField::make('is_active', 'Active') + ->options([ + true => 'Enabled', + false => 'Disabled', + ]); +``` + +### SelectField + +Dropdown select with static or dynamic options. + +```php +use Ginkelsoft\Buildora\Fields\Types\SelectField; + +// Static options +SelectField::make('status', 'Status') + ->options([ + 'draft' => 'Draft', + 'published' => 'Published', + 'archived' => 'Archived', + ]); + +// Dynamic options via closure +SelectField::make('category_id', 'Category') + ->options(fn() => Category::pluck('name', 'id')->toArray()); + +// From PHP Enum +SelectField::make('status', 'Status') + ->options(OrderStatus::class); +``` + +### CheckboxListField + +Multiple checkbox selection (extends BelongsToManyField). + +```php +use Ginkelsoft\Buildora\Fields\Types\CheckboxListField; + +CheckboxListField::make('permissions', 'Permissions') + ->groupByPrefix(true, '.') // Group by dot prefix + ->hideFromTable(); +``` + +--- + + +## Relationship Fields + +### BelongsToField + +Select for BelongsTo relationships. + +```php +use Ginkelsoft\Buildora\Fields\Types\BelongsToField; + +BelongsToField::make('category') + ->relatedTo(\App\Models\Category::class) + ->pluck('id', 'name') // (valueColumn, displayColumn) + ->searchable(); +``` + +### AsyncBelongsToField + +AJAX-powered select for large datasets. + +```php +use Ginkelsoft\Buildora\Fields\Types\AsyncBelongsToField; + +AsyncBelongsToField::make('customer') + ->relatedTo(\App\Models\Customer::class) + ->pluck('id', 'name') + ->searchColumns(['name', 'email', 'phone']) // Columns to search + ->displayUsing('name'); +``` + +### BelongsToManyField + +Multi-select for many-to-many relationships. + +```php +use Ginkelsoft\Buildora\Fields\Types\BelongsToManyField; + +BelongsToManyField::make('tags') + ->pluck('id', 'name') + ->hideFromTable(); +``` + +### RelationLinkField + +Displays a clickable link to a related record. + +```php +use Ginkelsoft\Buildora\Fields\Types\RelationLinkField; + +// Basic usage - link to related record +RelationLinkField::make('category', 'Category') + ->displayUsing('name'); + +// With explicit model and resource +RelationLinkField::make('author', 'Author') + ->relatedTo(\App\Models\User::class) + ->resource(\App\Buildora\Resources\UserBuildora::class) + ->displayUsing('name'); + +// Open in new tab +RelationLinkField::make('company') + ->displayUsing('company_name') + ->openInNewTab(); +``` + +**Methods:** +- `relatedTo(string $model)` - Set the related model class +- `resource(string $resourceClass)` - Set the Buildora resource for URL generation +- `displayUsing(string $column)` - Column to display as link text (default: 'name') +- `openInNewTab(bool $value)` - Open the link in a new browser tab + +> {info} RelationLinkField automatically hides from create/edit forms. It's designed for table and detail views only. + +--- + + +## Content Fields + +### EditorField + +WYSIWYG editor for editing rich content. + +```php +use Ginkelsoft\Buildora\Fields\Types\EditorField; + +EditorField::make('body', 'Article Body') + ->hideFromTable() + ->columnSpan(12); +``` + +### JsonField + +JSON editor for structured data. + +```php +use Ginkelsoft\Buildora\Fields\Types\JsonField; + +JsonField::make('metadata', 'Metadata') + ->hideFromTable() + ->hideFromExport(); +``` + +### DisplayField + +Custom computed content. + +```php +use Ginkelsoft\Buildora\Fields\Types\DisplayField; + +DisplayField::make('full_address', 'Address') + ->content(fn($model) => "{$model->street}, {$model->city}"); +``` + +### ViewField + +Render a custom Blade view. + +```php +use Ginkelsoft\Buildora\Fields\Types\ViewField; + +ViewField::make('custom_display') + ->view('components.order-summary') + ->closure(fn($model) => [ + 'total' => $model->calculateTotal(), + 'items' => $model->items, + ]); +``` + +--- + + +## File Upload Field + +### FileField + +File upload with preview support. + +```php +use Ginkelsoft\Buildora\Fields\Types\FileField; + +FileField::make('document', 'Document') + ->disk('public') // Storage disk + ->path('documents') // Upload path + ->accept('.pdf,.doc,.docx') // Allowed extensions + ->maxSize(2048) // Max size in KB + ->showPreview(true); // Show inline preview + +// For images with dimension limits +FileField::make('avatar', 'Profile Picture') + ->disk('public') + ->path('avatars') + ->accept('.jpg,.jpeg,.png,.webp') + ->imageDimensions(800, 800) // Max width, height + ->showPreview(true); +``` diff --git a/resources/docs/1.0/index.json b/resources/docs/1.0/index.json new file mode 100644 index 0000000..a17c024 --- /dev/null +++ b/resources/docs/1.0/index.json @@ -0,0 +1,24 @@ +{ + "Get Started": { + "Introduction": "index", + "Installation": "installation" + }, + "Core Concepts": { + "Resources": "resources", + "Fields": "fields", + "Validation": "validation" + }, + "Advanced Features": { + "Panels & Relations": "panels", + "Actions": "actions", + "Widgets": "widgets" + }, + "Configuration": { + "Configuration": "configuration", + "Permissions": "permissions", + "Artisan Commands": "commands" + }, + "Customization": { + "Theming": "theming" + } +} diff --git a/resources/docs/1.0/index.md b/resources/docs/1.0/index.md new file mode 100644 index 0000000..ea57966 --- /dev/null +++ b/resources/docs/1.0/index.md @@ -0,0 +1,35 @@ +# Introduction + +--- + +- [What is Buildora?](#what-is-buildora) +- [Features](#features) +- [Requirements](#requirements) + + +## What is Buildora? + +Buildora is a powerful Laravel package for building admin panels, resources, forms, datatables, widgets, and actions based on your Eloquent models with minimal configuration. + +It's a comprehensive CRUD engine that automatically generates beautiful, functional admin interfaces from your Laravel models. + + +## Features + +- **Automatic CRUD Operations** - Create, Read, Update, Delete out of the box +- **Powerful Datatables** - Sortable, searchable, exportable tables +- **Flexible Field System** - 20+ field types with full customization +- **Relation Management** - Panels for HasMany, BelongsToMany relations +- **Widget System** - Dashboard widgets and custom components +- **Built-in Permissions** - Spatie Laravel Permission integration +- **Modern UI** - Tailwind CSS with dark mode support +- **Two-Factor Authentication** - Built-in 2FA support + + +## Requirements + +- PHP 8.1 or higher +- Laravel 10, 11, or 12 +- Spatie Laravel Permission package + +> {info} Buildora works seamlessly with existing Laravel applications. No need to start from scratch! diff --git a/resources/docs/1.0/installation.md b/resources/docs/1.0/installation.md new file mode 100644 index 0000000..822b00e --- /dev/null +++ b/resources/docs/1.0/installation.md @@ -0,0 +1,44 @@ +# Installation + +--- + +- [Install via Composer](#composer) +- [Run the Installer](#installer) +- [Create Admin User](#admin-user) +- [Access the Panel](#access) + + +## Install via Composer + +```bash +composer require ginkelsoft/buildora +``` + + +## Run the Installer + +```bash +php artisan buildora:install +``` + +The installer will: +- Publish configuration files +- Publish assets +- Run necessary migrations +- Optionally create an admin user + + +## Create Admin User + +If you didn't create one during installation: + +```bash +php artisan buildora:user:create +``` + + +## Access the Panel + +Visit `/buildora/dashboard` in your browser and log in with your admin credentials. + +> {primary} Congratulations! Buildora is now installed and ready to use. diff --git a/resources/docs/1.0/panels.md b/resources/docs/1.0/panels.md new file mode 100644 index 0000000..a6d81b3 --- /dev/null +++ b/resources/docs/1.0/panels.md @@ -0,0 +1,183 @@ +# Panels & Relations + +--- + +- [Introduction](#introduction) +- [Creating Panels](#creating) +- [Inline Editing](#inline-editing) +- [Supported Relationships](#relationships) +- [Full Example](#example) + + +## Introduction + +Panels allow you to display and manage related data on the detail page of a resource. They integrate with Laravel's Eloquent relationships. + + +## Creating Panels + +Define panels in the `definePanels()` method of your resource: + +```php +use Ginkelsoft\Buildora\Layouts\Panel; + +public function definePanels(): array +{ + return [ + Panel::relation('orders', OrderBuildora::class) + ->label('Customer Orders'), + + Panel::relation('addresses', AddressBuildora::class) + ->label('Addresses'), + ]; +} +``` + +### Panel::relation() + +The primary method to create a panel: + +```php +Panel::relation(string $relationMethod, string $resourceClass): Panel +``` + +**Parameters:** +- `$relationMethod` - The name of the relationship method on your model +- `$resourceClass` - The Buildora resource class for the related model + +### label() + +Set a custom display label: + +```php +Panel::relation('orders', OrderBuildora::class) + ->label('Purchase History') +``` + + +## Inline Editing + +Enable inline CRUD operations without leaving the page: + +```php +Panel::relation('items', OrderItemBuildora::class) + ->label('Order Items') + ->inlineEditing() // Enable create, edit, and delete +``` + +Control which operations are allowed: + +```php +// Only allow create and edit, no delete +->inlineEditing(create: true, delete: false) + +// Only allow editing existing records +->inlineEditing(create: false, delete: false) + +// Full control +->inlineEditing(create: true, delete: true) +``` + +When `inlineEditing()` is enabled, users can: + +1. **Create** new related records via a modal +2. **Edit** existing records in a modal +3. **Delete** records with confirmation + + +## Supported Relationships + +Panels work with these Eloquent relationship types: + +### HasMany + +```php +// Model: App\Models\Customer +public function orders(): HasMany +{ + return $this->hasMany(Order::class); +} + +// Resource: CustomerBuildora +public function definePanels(): array +{ + return [ + Panel::relation('orders', OrderBuildora::class) + ->label('Orders'), + ]; +} +``` + +### BelongsToMany + +```php +// Model: App\Models\Product +public function tags(): BelongsToMany +{ + return $this->belongsToMany(Tag::class); +} + +// Resource: ProductBuildora +public function definePanels(): array +{ + return [ + Panel::relation('tags', TagBuildora::class) + ->label('Tags') + ->inlineEditing(), + ]; +} +``` + +> {info} Relations defined in `definePanels()` are automatically eager-loaded to prevent N+1 query problems. + + +## Full Example + +```php +searchable() + ->sortable() + ->columnSpan(6), + + EmailField::make('email', 'Email') + ->searchable() + ->columnSpan(6), + ]; + } + + public function definePanels(): array + { + return [ + // Read-only panel for orders + Panel::relation('orders', OrderBuildora::class) + ->label('Order History'), + + // Inline editable addresses + Panel::relation('addresses', AddressBuildora::class) + ->label('Addresses') + ->inlineEditing(create: true, delete: true), + + // Inline notes without delete option + Panel::relation('notes', NoteBuildora::class) + ->label('Customer Notes') + ->inlineEditing(create: true, delete: false), + ]; + } +} +``` diff --git a/resources/docs/1.0/permissions.md b/resources/docs/1.0/permissions.md new file mode 100644 index 0000000..696cda6 --- /dev/null +++ b/resources/docs/1.0/permissions.md @@ -0,0 +1,152 @@ +# Permissions + +--- + +- [Introduction](#introduction) +- [Permission Format](#format) +- [Generating Permissions](#generating) +- [Using Permissions](#using) +- [Super Admin](#super-admin) + + +## Introduction + +Buildora integrates with [Spatie Laravel Permission](https://spatie.be/docs/laravel-permission) to provide role-based access control. + + +## Permission Format + +Permissions follow the format: `{resource}.{action}` + +| Permission | Description | +|------------|-------------| +| `product.view` | View product list and details | +| `product.create` | Create new products | +| `product.edit` | Edit existing products | +| `product.delete` | Delete products | + + +## Generating Permissions + +### Generate All Permissions + +```bash +php artisan buildora:generate-permissions +``` + +This scans all Buildora resources and creates permissions for each. + +### Sync Permissions + +```bash +php artisan buildora:sync-permissions +``` + +Synchronizes permissions, adding new ones and optionally removing unused ones. + +### Grant All to a User + +```bash +php artisan buildora:grant-permissions {user_id} +``` + +### Grant Resource Permissions + +```bash +php artisan buildora:permission:grant-resource {user_id} {resource} +``` + +Example: +```bash +php artisan buildora:permission:grant-resource 1 product +``` + +This grants `product.view`, `product.create`, `product.edit`, `product.delete` to user 1. + + +## Using Permissions + +### In Row Actions + +```php +RowAction::make('Edit', 'fas fa-edit', 'route', 'buildora.edit') + ->params(['resource' => 'products', 'id' => 'id']) + ->permission('product.edit'); +``` + +### In Bulk Actions + +```php +BulkAction::make('Delete Selected', 'products.bulk-delete') + ->method('DELETE') + ->permission('product.delete'); +``` + +### In Navigation + +```php +'navigation' => [ + [ + 'label' => 'Products', + 'icon' => 'fas fa-box', + 'route' => 'buildora.index', + 'route_params' => ['resource' => 'products'], + 'permission' => 'product.view', + ], +], +``` + +### Custom Permission Prefix + +Override the default permission prefix in your resource: + +```php +protected function permissionPrefix(): string +{ + return 'inventory'; // Uses inventory.view, inventory.create, etc. +} +``` + +### In Blade Views + +```html +@can('product.create') + + Create Product + +@endcan +``` + + +## Super Admin + +For users who should bypass all permission checks, add this to your User model: + +```php +public function hasPermissionTo($permission, $guardName = null): bool +{ + if ($this->hasRole('super-admin')) { + return true; + } + + return parent::hasPermissionTo($permission, $guardName); +} +``` + +## Setting Up Roles + +```php +use Spatie\Permission\Models\Role; +use Spatie\Permission\Models\Permission; + +// Create roles +$admin = Role::create(['name' => 'admin']); +$editor = Role::create(['name' => 'editor']); + +// Assign permissions to roles +$admin->givePermissionTo('product.view', 'product.create', 'product.edit', 'product.delete'); +$editor->givePermissionTo('product.view', 'product.edit'); + +// Assign role to user +$user->assignRole('editor'); +``` diff --git a/resources/docs/1.0/resources.md b/resources/docs/1.0/resources.md new file mode 100644 index 0000000..6709f12 --- /dev/null +++ b/resources/docs/1.0/resources.md @@ -0,0 +1,302 @@ +# Resources + +--- + +- [Introduction](#introduction) +- [Creating a Resource](#creating) +- [Resource Properties](#properties) +- [Defining Fields](#fields) +- [Optional Methods](#optional-methods) +- [Query Customization](#query) +- [Full Example](#example) + + +## Introduction + +Resources are the core building blocks of Buildora. Each resource represents a single Eloquent model and defines how it should be displayed and managed in the admin panel. + + +## Creating a Resource + +Use the Artisan command to generate a new resource: + +```bash +php artisan buildora:resource Product +``` + +This creates `app/Buildora/Resources/ProductBuildora.php`: + +```php + +## Resource Properties + +### Model Class + +Every resource must define which Eloquent model it represents: + +```php +protected string $modelClass = \App\Models\Product::class; +``` + +### Title + +Override the display title (shown in navigation and headers): + +```php +public function title(): string +{ + return 'Products'; // Default: class basename +} +``` + +### URI Key + +The URL segment used for this resource: + +```php +public function uriKey(): string +{ + return 'products'; // Default: lowercase model name +} +``` + +### Navigation + +Control whether this resource appears in the sidebar: + +```php +public function showInNavigation(): bool +{ + return true; // Default: true +} +``` + + +## Defining Fields + +The `defineFields()` method is required. Returns an array of Field objects: + +```php +public function defineFields(): array +{ + return [ + TextField::make('name', 'Product Name') + ->searchable() + ->sortable() + ->validation(['required', 'max:255']), + + NumberField::make('price', 'Price') + ->sortable(), + + SelectField::make('status', 'Status') + ->options([ + 'draft' => 'Draft', + 'published' => 'Published', + ]), + + TextField::make('description', 'Description') + ->hideFromTable() + ->columnSpan(12), + ]; +} +``` + + +## Optional Methods + +### definePanels() + +Define relation panels for the detail page: + +```php +public function definePanels(): array +{ + return [ + Panel::relation('orders', OrderBuildora::class) + ->label('Orders'), + + Panel::relation('reviews', ReviewBuildora::class) + ->label('Customer Reviews') + ->inlineEditing(), + ]; +} +``` + +### defineRowActions() + +Add custom actions for individual records: + +```php +public function defineRowActions(): array +{ + return [ + RowAction::make('Duplicate', 'fas fa-copy', 'route', 'products.duplicate') + ->method('POST') + ->confirm('Are you sure you want to duplicate this product?'), + ]; +} +``` + +### defineBulkActions() + +Add actions for multiple selected records: + +```php +public function defineBulkActions(): array +{ + return [ + BulkAction::make('Publish Selected', 'products.bulk-publish') + ->method('POST') + ->permission('product.publish'), + ]; +} +``` + +### defineWidgets() + +Add widgets to the resource index page: + +```php +public function defineWidgets(): array +{ + return [ + ProductStatsWidget::make() + ->colSpan(6), + ]; +} +``` + +### searchResultConfig() + +Configure how this resource appears in global search: + +```php +public function searchResultConfig(): array +{ + return [ + 'label' => 'name', // Field(s) for the result label + 'columns' => ['name', 'sku', 'price'], // Columns to display + ]; +} +``` + + +## Query Customization + +Override the base query for all resource operations: + +```php +public static function query(): BuildoraQueryBuilder +{ + return parent::query() + ->where('active', true) + ->orderBy('created_at', 'desc'); +} +``` + + +## Full Example + +```php +searchable() + ->sortable() + ->validation(['required', 'max:255']) + ->columnSpan(6), + + TextField::make('sku', 'SKU') + ->searchable() + ->columnSpan(6), + + BelongsToField::make('category') + ->relatedTo(\App\Models\Category::class) + ->pluck('id', 'name') + ->columnSpan(6), + + NumberField::make('price', 'Price') + ->sortable() + ->validation(['required', 'numeric', 'min:0']) + ->columnSpan(6), + + SelectField::make('status', 'Status') + ->options([ + 'draft' => 'Draft', + 'published' => 'Published', + 'archived' => 'Archived', + ]) + ->columnSpan(6), + + BooleanField::make('featured', 'Featured Product') + ->columnSpan(6), + + FileField::make('image', 'Product Image') + ->disk('public') + ->path('products') + ->columnSpan(12), + ]; + } + + public function definePanels(): array + { + return [ + Panel::relation('variants', ProductVariantBuildora::class) + ->label('Variants') + ->inlineEditing(), + ]; + } + + public function searchResultConfig(): array + { + return [ + 'label' => 'name', + 'columns' => ['sku', 'price'], + ]; + } +} +``` diff --git a/resources/docs/1.0/theming.md b/resources/docs/1.0/theming.md new file mode 100644 index 0000000..476b8da --- /dev/null +++ b/resources/docs/1.0/theming.md @@ -0,0 +1,154 @@ +# Theming + +--- + +- [Publishing the Theme](#publishing) +- [CSS Variables](#variables) +- [Dark Mode](#dark-mode) +- [Theme Presets](#presets) + + +## Publishing the Theme + +```bash +php artisan vendor:publish --tag=buildora-theme +``` + +This creates `resources/buildora/buildora-theme.css` in your Laravel application. + + +## CSS Variables + +### Colors + +```css +:root { + /* Primary/Accent Colors */ + --accent-color: #667eea; + --accent-hover: #5a6fd6; + + /* Background Colors */ + --bg-primary: #f8fafc; + --bg-secondary: #ffffff; + --bg-card: #ffffff; + --bg-dropdown: #ffffff; + --bg-input: #ffffff; + --bg-sidebar: #1e293b; + + /* Text Colors */ + --text-primary: #1e293b; + --text-secondary: #475569; + --text-muted: #94a3b8; + --text-sidebar: #e2e8f0; + + /* Border Colors */ + --border-color: #e2e8f0; + + /* Status Colors */ + --success: #10b981; + --warning: #f59e0b; + --danger: #ef4444; + --info: #3b82f6; +} +``` + + +## Dark Mode + +Dark mode is automatically applied based on the `dark` class on the HTML element: + +```css +.dark { + --bg-primary: #0f172a; + --bg-secondary: #1e293b; + --bg-card: #1e293b; + --bg-dropdown: #334155; + --bg-input: #334155; + + --text-primary: #f1f5f9; + --text-secondary: #cbd5e1; + --text-muted: #64748b; + + --border-color: #334155; +} +``` + +Buildora includes a theme switcher with three options: +- **Light** - Force light mode +- **Dark** - Force dark mode +- **System** - Follow OS preference + + +## Theme Presets + +### Blue Theme (Default) + +```css +:root { + --accent-color: #667eea; + --accent-hover: #5a6fd6; +} +``` + +### Green Theme + +```css +:root { + --accent-color: #10b981; + --accent-hover: #059669; +} +``` + +### Purple Theme + +```css +:root { + --accent-color: #8b5cf6; + --accent-hover: #7c3aed; +} +``` + +### Orange Theme + +```css +:root { + --accent-color: #f97316; + --accent-hover: #ea580c; +} +``` + +## Custom Example + +Edit `resources/buildora/buildora-theme.css`: + +```css +:root { + /* Custom brand color */ + --accent-color: #0ea5e9; + --accent-hover: #0284c7; + + /* Custom sidebar */ + --bg-sidebar: #0c4a6e; + --text-sidebar: #e0f2fe; +} + +.dark { + --accent-color: #38bdf8; +} +``` + +## Using Custom Fonts + +```css +@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap'); + +:root { + --font-family: 'Inter', sans-serif; +} + +body { + font-family: var(--font-family); +} +``` + +> {primary} Using CSS variables ensures consistent styling across light and dark modes. diff --git a/resources/docs/1.0/validation.md b/resources/docs/1.0/validation.md new file mode 100644 index 0000000..917e789 --- /dev/null +++ b/resources/docs/1.0/validation.md @@ -0,0 +1,155 @@ +# Validation + +--- + +- [Basic Validation](#basic) +- [Dynamic Validation](#dynamic) +- [Common Patterns](#patterns) +- [Password Validation](#password) + + +## Basic Validation + +Use the `validation()` method with an array of Laravel validation rules: + +```php +TextField::make('name', 'Name') + ->validation(['required', 'max:255']); + +EmailField::make('email', 'Email') + ->validation(['required', 'email', 'unique:users,email']); + +NumberField::make('price', 'Price') + ->validation(['required', 'numeric', 'min:0', 'max:99999.99']); +``` + + +## Dynamic Validation + +Use a closure for context-aware validation rules: + +```php +TextField::make('name', 'Name') + ->validation(function ($model) { + $rules = ['required', 'max:255']; + + // Add unique rule, ignoring current record on edit + if ($model->exists) { + $rules[] = 'unique:products,name,' . $model->id; + } else { + $rules[] = 'unique:products,name'; + } + + return $rules; + }); +``` + +### Conditional Validation + +Apply different rules based on model state: + +```php +NumberField::make('discount_percentage', 'Discount %') + ->validation(function ($model) { + if ($model->has_discount) { + return ['required', 'numeric', 'min:1', 'max:100']; + } + return ['nullable', 'numeric', 'min:0', 'max:100']; + }); +``` + + +## Common Patterns + +### Required Fields + +```php +TextField::make('title', 'Title') + ->validation(['required']); +``` + +### String Length + +```php +TextField::make('name', 'Name') + ->validation(['required', 'min:2', 'max:255']); +``` + +### Numeric Values + +```php +NumberField::make('quantity', 'Quantity') + ->validation(['required', 'integer', 'min:0']); + +NumberField::make('price', 'Price') + ->validation(['required', 'numeric', 'min:0', 'max:99999.99']); +``` + +### Unique Values + +```php +// Simple unique +TextField::make('slug', 'Slug') + ->validation(['required', 'unique:products,slug']); + +// Unique with exception for current record +TextField::make('email', 'Email') + ->validation(fn($model) => [ + 'required', + 'email', + $model->exists + ? 'unique:users,email,' . $model->id + : 'unique:users,email' + ]); +``` + +### Date Validation + +```php +DateField::make('start_date', 'Start Date') + ->validation(['required', 'date', 'after:today']); + +DateField::make('end_date', 'End Date') + ->validation(['required', 'date', 'after:start_date']); +``` + +### File Validation + +```php +FileField::make('document', 'Document') + ->validation(['nullable', 'file', 'mimes:pdf,doc,docx', 'max:5120']); + +FileField::make('image', 'Image') + ->validation(['nullable', 'image', 'mimes:jpg,jpeg,png', 'max:2048']); +``` + +### Enum/In Validation + +```php +SelectField::make('status', 'Status') + ->options(['draft', 'published', 'archived']) + ->validation(['required', 'in:draft,published,archived']); +``` + +### Relationship Validation + +```php +BelongsToField::make('category') + ->validation(['required', 'exists:categories,id']); +``` + + +## Password Validation + +Buildora handles passwords specially: + +```php +PasswordField::make('password', 'Password') + ->validation(fn($model) => $model->exists + ? ['nullable', 'min:8', 'confirmed'] // Optional on edit + : ['required', 'min:8', 'confirmed'] // Required on create + ) + ->help('Leave empty to keep current password'); +``` + +> {info} Empty password fields are automatically ignored during updates. diff --git a/resources/docs/1.0/widgets.md b/resources/docs/1.0/widgets.md new file mode 100644 index 0000000..fdbd633 --- /dev/null +++ b/resources/docs/1.0/widgets.md @@ -0,0 +1,244 @@ +# Widgets + +--- + +- [Introduction](#introduction) +- [Creating a Widget](#creating) +- [Widget Configuration](#configuration) +- [Using Widgets](#using) +- [Examples](#examples) + + +## Introduction + +Widgets are reusable components that display information on dashboards and resource pages. They're perfect for statistics, charts, quick actions, and custom content. + + +## Creating a Widget + +Use the Artisan command to generate a widget: + +```bash +php artisan buildora:widget +``` + +This interactive command will: +1. Ask for the widget name +2. Generate the widget class +3. Create the Blade view + +### Manual Creation + +Create a widget class in `app/Buildora/Widgets/`: + +```php + $totalSales, + 'orderCount' => $orderCount, + ]); + } +} +``` + +Create the Blade view at `resources/views/buildora/widgets/sales-overview.blade.php`: + +```html +
Total Sales
++ € {{ number_format($totalSales, 2, ',', '.') }} +
+Orders
++ {{ $orderCount }} +
+{{ $title }}
++ {{ number_format($value) }} +
++ {{ __buildora('Manage your Buildora installation and system settings.') }} +
++ {{ __buildora('Synchronize permissions for all Buildora resources.') }} +
++ {{ __buildora('This will scan all Buildora resources and create the necessary permissions (view, create, edit, delete) for each resource.') }} +
++ {{ __buildora('Clear application caches to refresh data.') }} +
+{{ $stats['cache_driver'] ?? 'file' }}
+{{ $stats['session_driver'] ?? 'file' }}
+{{ $stats['queue_driver'] ?? 'sync' }}
++ {{ __buildora('Overview of registered Buildora resources.') }} +
+ ++ {{ __buildora('Generate a new resource using:') }} +
+
+ php artisan buildora:resource ModelName
+
+ {{ $stats['user_count'] ?? 0 }}
+{{ __buildora('Users') }}
+{{ $stats['resource_count'] ?? 0 }}
+{{ __buildora('Resources') }}
+{{ $stats['permission_count'] ?? 0 }}
+{{ __buildora('Permissions') }}
++ {{ __buildora('Learn how to use Buildora effectively.') }} +
+ + + {{ __buildora('View Documentation') }} + +