diff --git a/docs/guide/crud/list.md b/docs/guide/crud/list.md
index 5b8cd6b2..8db80871 100644
--- a/docs/guide/crud/list.md
+++ b/docs/guide/crud/list.md
@@ -149,6 +149,7 @@ See all supported field properties :
| **source** | `string` | Resource property to display. |
| **type** | `string` | Type of [field](../components/fields.md) to use. |
| **label** | `string` | Column title header, use [localized property source](../i18n.md) by default. |
+| **labelKey** | `string` | Override default source as i18n key message |
| **sortable** | `boolean` | Activate server-side sort. |
| **align** | `string` | You can Use `left`, `right`, `center` for each cell `align` attribute. |
| **link** | `string` | Use any valid `show` or `edit` action if you want to wrap field inside resource action link. |
@@ -327,6 +328,7 @@ See all supported field properties :
| **source** | `string` | Resource property to display. |
| **type** | `string` | Type of [input](../components/inputs.md) to use. |
| **label** | `string` | Column title header, use [localized property source](../i18n.md) by default. |
+| **labelKey** | `string` | Override default source as i18n key message |
| **alwaysOn** | `boolean` | Keep filter always active and visible. Not removable. |
| **attributes** | `object` | All props or attributes to merge to the [input component](../components/inputs.md). |
diff --git a/examples/api-platform/vue.config.js b/examples/api-platform/vue.config.js
index 18b2d8de..ff604461 100644
--- a/examples/api-platform/vue.config.js
+++ b/examples/api-platform/vue.config.js
@@ -1,5 +1,5 @@
module.exports = {
- transpileDependencies: ["vuetify", "vtec-admin"],
+ transpileDependencies: ["vuetify"],
pluginOptions: {
i18n: {
locale: "en",
diff --git a/examples/demo-laravel/app/Book.php b/examples/demo-laravel/app/Book.php
index c564f0a1..189c5a8a 100644
--- a/examples/demo-laravel/app/Book.php
+++ b/examples/demo-laravel/app/Book.php
@@ -16,21 +16,25 @@
*
* @property int $id
* @property int $publisher_id
+ * @property int $category_id
* @property string|null $isbn
* @property string $title
* @property string $description
* @property string $summary
- * @property string $category
* @property array $formats
* @property float $price
* @property bool $commentable
* @property array $tags
* @property Carbon $publication_date
+ * @property-read Category $category
* @property-read \Illuminate\Database\Eloquent\Collection|\App\Review[] $reviews
* @property-read int|null $reviews_count
* @property-read \App\Publisher $publisher
* @property-read \Illuminate\Database\Eloquent\Collection|\App\Author[] $authors
* @property-read int|null $authors_count
+ * @property-read mixed $translations
+ * @property-read \Illuminate\Database\Eloquent\Collection|Media[] $media
+ * @property-read int|null $media_count
* @method static \Illuminate\Database\Eloquent\Builder|\App\Book newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|\App\Book newQuery()
* @method static \Illuminate\Database\Eloquent\Builder|\App\Book query()
@@ -40,9 +44,6 @@
* @method static \Illuminate\Database\Eloquent\Builder|\App\Book pricierThan($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\Book commentables()
* @mixin \Eloquent
- * @property-read mixed $translations
- * @property-read \Illuminate\Database\Eloquent\Collection|Media[] $media
- * @property-read int|null $media_count
*/
class Book extends Model implements HasMedia
{
@@ -58,7 +59,7 @@ class Book extends Model implements HasMedia
'description',
'summary',
'price',
- 'category',
+ 'category_id',
'formats',
'commentable',
'tags',
@@ -86,6 +87,11 @@ public function registerMediaCollections(): void
$this->addMediaCollection('extract')->singleFile();
}
+ public function category()
+ {
+ return $this->belongsTo(Category::class);
+ }
+
public function publisher()
{
return $this->belongsTo(Publisher::class);
diff --git a/examples/demo-laravel/app/Category.php b/examples/demo-laravel/app/Category.php
new file mode 100644
index 00000000..ecbed9c0
--- /dev/null
+++ b/examples/demo-laravel/app/Category.php
@@ -0,0 +1,69 @@
+header('locale') ?: app()->getLocale();
+ }
+
+ public function parent()
+ {
+ return $this->belongsTo(Category::class);
+ }
+
+ public function children()
+ {
+ return $this->hasMany(Category::class, 'parent_id');
+ }
+
+ public function buildSortQuery()
+ {
+ return static::query()
+ ->where('type', $this->type)
+ ->where('parent_id', $this->parent_id);
+ }
+
+ public function toArray()
+ {
+ return [
+ 'id' => $this->id,
+ 'name' => $this->name,
+ ];
+ }
+
+ public function __toString()
+ {
+ return $this->name;
+ }
+}
diff --git a/examples/demo-laravel/app/Http/Controllers/BookController.php b/examples/demo-laravel/app/Http/Controllers/BookController.php
index fbeab5fd..874e9eb9 100644
--- a/examples/demo-laravel/app/Http/Controllers/BookController.php
+++ b/examples/demo-laravel/app/Http/Controllers/BookController.php
@@ -49,7 +49,7 @@ public function index()
AllowedFilter::scope('published_after'),
])
->allowedSorts(['id', 'isbn', 'title', 'price', 'publication_date'])
- ->allowedIncludes(['publisher', 'authors', 'reviews', 'media'])
+ ->allowedIncludes(['category', 'publisher', 'authors', 'reviews', 'media'])
->paginate()
);
}
@@ -62,7 +62,7 @@ public function index()
*/
public function show(Book $book)
{
- return new BookResource($book->load(['publisher', 'authors', 'reviews', 'media']));
+ return new BookResource($book->load(['category', 'publisher', 'authors', 'reviews', 'media']));
}
/**
diff --git a/examples/demo-laravel/app/Http/Controllers/CategoryController.php b/examples/demo-laravel/app/Http/Controllers/CategoryController.php
new file mode 100644
index 00000000..eb3332e7
--- /dev/null
+++ b/examples/demo-laravel/app/Http/Controllers/CategoryController.php
@@ -0,0 +1,91 @@
+authorizeResource(Category::class);
+ }
+
+ /**
+ * Display a listing of the resource.
+ *
+ * @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection
+ */
+ public function index()
+ {
+ return CategoryResource::collection(
+ QueryBuilder::for(Category::class)
+ ->allowedFields(['id', 'name'])
+ ->allowedFilters([
+ AllowedFilter::exact('id'),
+ AllowedFilter::exact('type'),
+ 'name',
+ ])
+ ->ordered()
+ ->get()
+ );
+ }
+
+ /**
+ * Display the specified resource.
+ *
+ * @param \App\Category $category
+ * @return CategoryResource
+ */
+ public function show(Category $category)
+ {
+ return new CategoryResource($category);
+ }
+
+ /**
+ * Store a newly created resource in storage.
+ *
+ * @param Request $request
+ * @return CategoryResource
+ */
+ public function store(StoreCategory $request)
+ {
+ $category = Category::create($request->all());
+
+ return new CategoryResource($category);
+ }
+
+ /**
+ * Update the specified resource in storage.
+ *
+ * @param UpdateCategory $request
+ * @param \App\Category $category
+ * @return CategoryResource
+ */
+ public function update(UpdateCategory $request, Category $category)
+ {
+ $category->update($request->all());
+
+ return new CategoryResource($category);
+ }
+
+ /**
+ * Remove the specified resource from storage.
+ *
+ * @param \App\Category $category
+ * @return \Illuminate\Http\Response
+ * @throws \Exception
+ */
+ public function destroy(Category $category)
+ {
+ $category->delete();
+
+ return response()->noContent();
+ }
+}
diff --git a/examples/demo-laravel/app/Http/Requests/StoreBook.php b/examples/demo-laravel/app/Http/Requests/StoreBook.php
index d74ab36c..a4e3a6b4 100644
--- a/examples/demo-laravel/app/Http/Requests/StoreBook.php
+++ b/examples/demo-laravel/app/Http/Requests/StoreBook.php
@@ -31,7 +31,6 @@ public function rules()
'publisher_id' => 'required',
'isbn' => 'required|isbn',
'title' => 'required',
- 'category' => 'required|in:novel,comic,cook,economy,politics,history,fantasy,biography',
'description' => 'required',
'formats.*' => 'in:pocket,paperback,pdf,epub,kindle',
'price' => 'required|numeric',
diff --git a/examples/demo-laravel/app/Http/Requests/StoreCategory.php b/examples/demo-laravel/app/Http/Requests/StoreCategory.php
new file mode 100644
index 00000000..5df76788
--- /dev/null
+++ b/examples/demo-laravel/app/Http/Requests/StoreCategory.php
@@ -0,0 +1,31 @@
+ 'required',
+ 'type' => 'required|in:book',
+ ];
+ }
+}
diff --git a/examples/demo-laravel/app/Http/Requests/UpdateBook.php b/examples/demo-laravel/app/Http/Requests/UpdateBook.php
index 24cc4317..e04d57e7 100644
--- a/examples/demo-laravel/app/Http/Requests/UpdateBook.php
+++ b/examples/demo-laravel/app/Http/Requests/UpdateBook.php
@@ -31,7 +31,6 @@ public function rules()
'publisher_id' => 'sometimes|required',
'isbn' => 'sometimes|required|isbn',
'title' => 'sometimes|required',
- 'category' => 'sometimes|required|in:novel,comic,cook,economy,politics,history,fantasy,biography',
'description' => 'sometimes|required',
'formats.*' => 'sometimes|in:pocket,paperback,pdf,epub,kindle',
'price' => 'sometimes|required|numeric',
diff --git a/examples/demo-laravel/app/Http/Requests/UpdateCategory.php b/examples/demo-laravel/app/Http/Requests/UpdateCategory.php
new file mode 100644
index 00000000..c5b1603f
--- /dev/null
+++ b/examples/demo-laravel/app/Http/Requests/UpdateCategory.php
@@ -0,0 +1,31 @@
+ 'sometimes|required',
+ 'type' => 'sometimes|required|in:book',
+ ];
+ }
+}
diff --git a/examples/demo-laravel/app/Http/Resources/Book.php b/examples/demo-laravel/app/Http/Resources/Book.php
index 4a41f707..85e89bcc 100644
--- a/examples/demo-laravel/app/Http/Resources/Book.php
+++ b/examples/demo-laravel/app/Http/Resources/Book.php
@@ -16,6 +16,7 @@ public function toArray($request)
{
$attributes = parent::toArray($request);
+ $attributes['category'] = Category::make($this->whenLoaded('category'));
$attributes['publisher'] = Publisher::make($this->whenLoaded('publisher'));
$attributes['authors'] = Author::collection($this->whenLoaded('authors'));
$attributes['reviews'] = Review::collection($this->whenLoaded('reviews'));
diff --git a/examples/demo-laravel/app/Http/Resources/Category.php b/examples/demo-laravel/app/Http/Resources/Category.php
new file mode 100644
index 00000000..a96c9b03
--- /dev/null
+++ b/examples/demo-laravel/app/Http/Resources/Category.php
@@ -0,0 +1,19 @@
+hasRole('admin')) {
+ return false;
+ }
+ }
+
+ /**
+ * Determine whether the user can view any categories.
+ *
+ * @param \App\User $user
+ * @return mixed
+ */
+ public function viewAny(User $user)
+ {
+ return true;
+ }
+
+ /**
+ * Determine whether the user can view the category.
+ *
+ * @param \App\User $user
+ * @param \App\Category $category
+ * @return mixed
+ */
+ public function view(User $user, Category $category)
+ {
+ return true;
+ }
+
+ /**
+ * Determine whether the user can create categories.
+ *
+ * @param \App\User $user
+ * @return mixed
+ */
+ public function create(User $user)
+ {
+ return true;
+ }
+
+ /**
+ * Determine whether the user can update the category.
+ *
+ * @param \App\User $user
+ * @param \App\Category $category
+ * @return mixed
+ */
+ public function update(User $user, Category $category)
+ {
+ return true;
+ }
+
+ /**
+ * Determine whether the user can delete the category.
+ *
+ * @param \App\User $user
+ * @param \App\Category $category
+ * @return mixed
+ */
+ public function delete(User $user, Category $category)
+ {
+ return false;
+ }
+}
diff --git a/examples/demo-laravel/app/User.php b/examples/demo-laravel/app/User.php
index dc4ea6d3..69583034 100644
--- a/examples/demo-laravel/app/User.php
+++ b/examples/demo-laravel/app/User.php
@@ -22,15 +22,16 @@
* @property \Illuminate\Support\Carbon|null $updated_at
* @property-read \Illuminate\Notifications\DatabaseNotificationCollection|\Illuminate\Notifications\DatabaseNotification[] $notifications
* @property-read int|null $notifications_count
- * @method static \Illuminate\Database\Eloquent\Builder|\App\User newModelQuery()
- * @method static \Illuminate\Database\Eloquent\Builder|\App\User newQuery()
- * @method static \Illuminate\Database\Eloquent\Builder|\App\User query()
- * @mixin \Eloquent
* @property-read \Illuminate\Database\Eloquent\Collection|\App\Author[] $authors
* @property-read int|null $authors_count
* @property-read \Illuminate\Database\Eloquent\Collection|\App\Publisher[] $publishers
* @property-read int|null $publishers_count
+ * @property-read bool $impersonate
* @method static \Illuminate\Database\Eloquent\Builder|\App\User role($role)
+ * @method static \Illuminate\Database\Eloquent\Builder|\App\User newModelQuery()
+ * @method static \Illuminate\Database\Eloquent\Builder|\App\User newQuery()
+ * @method static \Illuminate\Database\Eloquent\Builder|\App\User query()
+ * @mixin \Eloquent
*/
class User extends Authenticatable implements JWTSubject
{
diff --git a/examples/demo-laravel/composer.json b/examples/demo-laravel/composer.json
index 977c317f..d9993fa0 100644
--- a/examples/demo-laravel/composer.json
+++ b/examples/demo-laravel/composer.json
@@ -18,6 +18,7 @@
"laravel/sanctum": "^2.0",
"laravel/tinker": "^2.1",
"laravel/ui": "^2.0",
+ "spatie/eloquent-sortable": "^3.8",
"symfony/yaml": "^5.0",
"tymon/jwt-auth": "^1.0",
"vtec/laravel-crud": "dev-master"
diff --git a/examples/demo-laravel/composer.lock b/examples/demo-laravel/composer.lock
index 3040166d..14c80fd2 100644
--- a/examples/demo-laravel/composer.lock
+++ b/examples/demo-laravel/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "8bacc94194282843f9b389635834513b",
+ "content-hash": "6716afc0f8fc9b761eb3f8b570ee7eb3",
"packages": [
{
"name": "asm89/stack-cors",
@@ -479,16 +479,16 @@
},
{
"name": "egulias/email-validator",
- "version": "2.1.19",
+ "version": "2.1.20",
"source": {
"type": "git",
"url": "https://github.com/egulias/EmailValidator.git",
- "reference": "840d5603eb84cc81a6a0382adac3293e57c1c64c"
+ "reference": "f46887bc48db66c7f38f668eb7d6ae54583617ff"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/840d5603eb84cc81a6a0382adac3293e57c1c64c",
- "reference": "840d5603eb84cc81a6a0382adac3293e57c1c64c",
+ "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/f46887bc48db66c7f38f668eb7d6ae54583617ff",
+ "reference": "f46887bc48db66c7f38f668eb7d6ae54583617ff",
"shasum": ""
},
"require": {
@@ -533,7 +533,7 @@
"validation",
"validator"
],
- "time": "2020-08-08T21:28:19+00:00"
+ "time": "2020-09-06T13:44:32+00:00"
},
{
"name": "fideloper/proxy",
@@ -808,16 +808,16 @@
},
{
"name": "intervention/validation",
- "version": "2.4.1",
+ "version": "2.4.2",
"source": {
"type": "git",
"url": "https://github.com/Intervention/validation.git",
- "reference": "1637e3c6a0f32fd3fcefaff56eff09831cd32bb5"
+ "reference": "f49e6d621edd801bcaf1a40899a5529f9f938823"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/Intervention/validation/zipball/1637e3c6a0f32fd3fcefaff56eff09831cd32bb5",
- "reference": "1637e3c6a0f32fd3fcefaff56eff09831cd32bb5",
+ "url": "https://api.github.com/repos/Intervention/validation/zipball/f49e6d621edd801bcaf1a40899a5529f9f938823",
+ "reference": "f49e6d621edd801bcaf1a40899a5529f9f938823",
"shasum": ""
},
"require": {
@@ -865,7 +865,7 @@
"validation",
"validator"
],
- "time": "2020-06-05T07:55:39+00:00"
+ "time": "2020-09-04T16:52:53+00:00"
},
{
"name": "itsgoingd/clockwork",
@@ -1942,16 +1942,16 @@
},
{
"name": "nesbot/carbon",
- "version": "2.39.0",
+ "version": "2.39.1",
"source": {
"type": "git",
"url": "https://github.com/briannesbitt/Carbon.git",
- "reference": "0a41ea7f7fedacf307b7a339800e10356a042918"
+ "reference": "7af467873250583cc967a59ee9df29fabab193c1"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/0a41ea7f7fedacf307b7a339800e10356a042918",
- "reference": "0a41ea7f7fedacf307b7a339800e10356a042918",
+ "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/7af467873250583cc967a59ee9df29fabab193c1",
+ "reference": "7af467873250583cc967a59ee9df29fabab193c1",
"shasum": ""
},
"require": {
@@ -1964,7 +1964,7 @@
"doctrine/orm": "^2.7",
"friendsofphp/php-cs-fixer": "^2.14 || ^3.0",
"kylekatarnls/multi-tester": "^2.0",
- "phpmd/phpmd": "^2.8",
+ "phpmd/phpmd": "^2.9",
"phpstan/extension-installer": "^1.0",
"phpstan/phpstan": "^0.12.35",
"phpunit/phpunit": "^7.5 || ^8.0",
@@ -2027,7 +2027,7 @@
"type": "tidelift"
}
],
- "time": "2020-08-24T12:35:58+00:00"
+ "time": "2020-09-04T13:11:37+00:00"
},
{
"name": "nikic/php-parser",
@@ -2083,16 +2083,16 @@
},
{
"name": "opis/closure",
- "version": "3.5.6",
+ "version": "3.5.7",
"source": {
"type": "git",
"url": "https://github.com/opis/closure.git",
- "reference": "e8d34df855b0a0549a300cb8cb4db472556e8aa9"
+ "reference": "4531e53afe2fc660403e76fb7644e95998bff7bf"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/opis/closure/zipball/e8d34df855b0a0549a300cb8cb4db472556e8aa9",
- "reference": "e8d34df855b0a0549a300cb8cb4db472556e8aa9",
+ "url": "https://api.github.com/repos/opis/closure/zipball/4531e53afe2fc660403e76fb7644e95998bff7bf",
+ "reference": "4531e53afe2fc660403e76fb7644e95998bff7bf",
"shasum": ""
},
"require": {
@@ -2140,7 +2140,7 @@
"serialization",
"serialize"
],
- "time": "2020-08-11T08:46:50+00:00"
+ "time": "2020-09-06T17:02:15+00:00"
},
{
"name": "org_heigl/ghostscript",
@@ -2844,6 +2844,63 @@
],
"time": "2020-08-18T17:17:46+00:00"
},
+ {
+ "name": "spatie/eloquent-sortable",
+ "version": "3.8.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/spatie/eloquent-sortable.git",
+ "reference": "18451ecf44b28a14ac0ed8803d0f5195a78a48a2"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/spatie/eloquent-sortable/zipball/18451ecf44b28a14ac0ed8803d0f5195a78a48a2",
+ "reference": "18451ecf44b28a14ac0ed8803d0f5195a78a48a2",
+ "shasum": ""
+ },
+ "require": {
+ "illuminate/database": "~5.8.0|^6.0|^7.0",
+ "illuminate/support": "~5.8.0|^6.0|^7.0",
+ "php": "^7.2"
+ },
+ "require-dev": {
+ "orchestra/testbench": "~3.8.0|^4.0|^5.0",
+ "phpunit/phpunit": "^8.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Spatie\\EloquentSortable\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Freek Van der Herten",
+ "email": "freek@spatie.be"
+ }
+ ],
+ "description": "Sortable behaviour for eloquent models",
+ "homepage": "https://github.com/spatie/eloquent-sortable",
+ "keywords": [
+ "behaviour",
+ "eloquent",
+ "laravel",
+ "model",
+ "sort",
+ "sortable"
+ ],
+ "funding": [
+ {
+ "url": "https://spatie.be/open-source/support-us",
+ "type": "custom"
+ }
+ ],
+ "time": "2020-07-08T00:05:43+00:00"
+ },
{
"name": "spatie/image",
"version": "1.7.6",
@@ -3106,26 +3163,26 @@
},
{
"name": "spatie/laravel-translatable",
- "version": "4.4.0",
+ "version": "4.4.1",
"source": {
"type": "git",
"url": "https://github.com/spatie/laravel-translatable.git",
- "reference": "7642b38df16a61e5738ed00c912ca522bb32b554"
+ "reference": "cc2ce05f2dc9c7eca1ca79613d7dd3026c31e418"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/spatie/laravel-translatable/zipball/7642b38df16a61e5738ed00c912ca522bb32b554",
- "reference": "7642b38df16a61e5738ed00c912ca522bb32b554",
+ "url": "https://api.github.com/repos/spatie/laravel-translatable/zipball/cc2ce05f2dc9c7eca1ca79613d7dd3026c31e418",
+ "reference": "cc2ce05f2dc9c7eca1ca79613d7dd3026c31e418",
"shasum": ""
},
"require": {
- "illuminate/database": "~5.8.0|^6.0|^7.0",
- "illuminate/support": "~5.8.0|^6.0|^7.0",
+ "illuminate/database": "~5.8.0|^6.0|^7.0|^8.0",
+ "illuminate/support": "~5.8.0|^6.0|^7.0|^8.0",
"php": "^7.2"
},
"require-dev": {
"mockery/mockery": "^1.3",
- "orchestra/testbench": "~3.8.0|^4.0|^5.0"
+ "orchestra/testbench": "~3.8.0|^4.0|^5.0|^6.0"
},
"type": "library",
"extra": {
@@ -3180,7 +3237,7 @@
"type": "custom"
}
],
- "time": "2020-07-09T07:05:40+00:00"
+ "time": "2020-09-06T19:02:11+00:00"
},
{
"name": "spatie/pdf-to-image",
@@ -8221,16 +8278,16 @@
},
{
"name": "phpunit/php-code-coverage",
- "version": "9.1.6",
+ "version": "9.1.7",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
- "reference": "d25b24b1cd14772bde4d75daeb393dc17db9f6e6"
+ "reference": "2ef92bec3186a827faf7362ff92ae4e8ec2e49d2"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/d25b24b1cd14772bde4d75daeb393dc17db9f6e6",
- "reference": "d25b24b1cd14772bde4d75daeb393dc17db9f6e6",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/2ef92bec3186a827faf7362ff92ae4e8ec2e49d2",
+ "reference": "2ef92bec3186a827faf7362ff92ae4e8ec2e49d2",
"shasum": ""
},
"require": {
@@ -8290,7 +8347,7 @@
"type": "github"
}
],
- "time": "2020-08-31T06:31:46+00:00"
+ "time": "2020-09-03T07:09:19+00:00"
},
{
"name": "phpunit/php-file-iterator",
diff --git a/examples/demo-laravel/config/elfinder.php b/examples/demo-laravel/config/elfinder.php
index 3dcdfd29..4941557b 100644
--- a/examples/demo-laravel/config/elfinder.php
+++ b/examples/demo-laravel/config/elfinder.php
@@ -10,7 +10,7 @@
| The dir where to store the images (relative from public)
|
*/
- 'dir' => ['storage/files'],
+ 'dir' => [],
/*
|--------------------------------------------------------------------------
@@ -26,7 +26,9 @@
| ]
*/
'disks' => [
-
+ 'files' => [
+ 'alias' => 'Local storage',
+ ],
],
/*
diff --git a/examples/demo-laravel/config/filesystems.php b/examples/demo-laravel/config/filesystems.php
index c4c20371..d3ee6aab 100644
--- a/examples/demo-laravel/config/filesystems.php
+++ b/examples/demo-laravel/config/filesystems.php
@@ -62,6 +62,13 @@
'visibility' => 'public',
],
+ 'files' => [
+ 'driver' => 'local',
+ 'root' => storage_path('app/public/files'),
+ 'url' => env('APP_URL').'/storage/files',
+ 'visibility' => 'public',
+ ],
+
's3' => [
'driver' => 's3',
'key' => env('AWS_ACCESS_KEY_ID'),
diff --git a/examples/demo-laravel/database/factories/BookFactory.php b/examples/demo-laravel/database/factories/BookFactory.php
index 8a95ee62..bf1ab536 100644
--- a/examples/demo-laravel/database/factories/BookFactory.php
+++ b/examples/demo-laravel/database/factories/BookFactory.php
@@ -15,7 +15,6 @@
'en' => ucfirst($faker->words($faker->numberBetween(1, 5), true)),
'fr' => ucfirst($faker->words($faker->numberBetween(1, 5), true)),
],
- 'category' => $faker->randomElement(['novel', 'comic', 'cook', 'economy', 'politics', 'history', 'fantasy', 'biography']),
'description' => [
'en' => $faker->paragraph(10),
'fr' => $faker->paragraph(10),
@@ -30,7 +29,7 @@
),
'price' => $faker->randomFloat(2, 10, 50),
'commentable' => $faker->boolean(80),
- 'tags' => $faker->unique()->words($faker->numberBetween(2, 5)),
+ 'tags' => collect($faker->words($faker->numberBetween(2, 5)))->unique(),
'publication_date' => $faker->dateTime,
];
});
diff --git a/examples/demo-laravel/database/migrations/2020_02_01_093550_create_categories_table.php b/examples/demo-laravel/database/migrations/2020_02_01_093550_create_categories_table.php
new file mode 100644
index 00000000..3085e5df
--- /dev/null
+++ b/examples/demo-laravel/database/migrations/2020_02_01_093550_create_categories_table.php
@@ -0,0 +1,37 @@
+id();
+ $table->json('name');
+ $table->string('type');
+ $table->unsignedBigInteger('parent_id')->nullable();
+ $table->unsignedInteger('order_column')->nullable();
+ $table->timestamps();
+
+ $table->foreign('parent_id')->references('id')->on('categories')->onDelete('cascade');
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::dropIfExists('categories');
+ }
+}
diff --git a/examples/demo-laravel/database/migrations/2020_02_26_153609_add_books_category_column.php b/examples/demo-laravel/database/migrations/2020_02_26_153609_add_books_category_column.php
index 3fa3f612..e3becafe 100644
--- a/examples/demo-laravel/database/migrations/2020_02_26_153609_add_books_category_column.php
+++ b/examples/demo-laravel/database/migrations/2020_02_26_153609_add_books_category_column.php
@@ -14,7 +14,9 @@ class AddBooksCategoryColumn extends Migration
public function up()
{
Schema::table('books', function (Blueprint $table) {
- $table->string('category')->after('title');
+ $table->unsignedBigInteger('category_id')->after('title')->nullable();
+
+ $table->foreign('category_id')->references('id')->on('categories')->nullOnDelete();
});
}
diff --git a/examples/demo-laravel/database/seeds/BookSeeder.php b/examples/demo-laravel/database/seeds/BookSeeder.php
index 19eda041..f88728ce 100644
--- a/examples/demo-laravel/database/seeds/BookSeeder.php
+++ b/examples/demo-laravel/database/seeds/BookSeeder.php
@@ -1,5 +1,8 @@
make()->each(function (\App\Book $book) use ($publishers, $authors, $faker) {
+ factory(Book::class, 500)->make()->each(function (Book $book) use ($categories, $publishers, $authors, $faker) {
+ $book->category()->associate($categories->random());
$book->publisher()->associate($publishers->random());
$book->save();
diff --git a/examples/demo-laravel/database/seeds/CategorySeeder.php b/examples/demo-laravel/database/seeds/CategorySeeder.php
new file mode 100644
index 00000000..6d061afe
--- /dev/null
+++ b/examples/demo-laravel/database/seeds/CategorySeeder.php
@@ -0,0 +1,258 @@
+ [
+ 'en' => 'Comics',
+ 'fr' => 'BD',
+ ],
+ 'children' => [
+ [
+ 'name' => [
+ 'en' => 'Marvel',
+ 'fr' => 'Marvel',
+ ],
+ ],
+ [
+ 'name' => [
+ 'en' => 'Detective Comics',
+ 'fr' => 'Detective Comics',
+ ],
+ ],
+ [
+ 'name' => [
+ 'en' => 'Manga',
+ 'fr' => 'Manga',
+ ],
+ ],
+ ],
+ ],
+ [
+ 'name' => [
+ 'en' => 'Novel',
+ 'fr' => 'Roman',
+ ],
+ 'children' => [
+ [
+ 'name' => [
+ 'en' => 'Thriller',
+ 'fr' => 'Thriller',
+ ],
+ ],
+ [
+ 'name' => [
+ 'en' => 'Adventure',
+ 'fr' => 'Aventure',
+ ],
+ ],
+ [
+ 'name' => [
+ 'en' => 'Fantasy',
+ 'fr' => 'Fantastique',
+ ],
+ ],
+ [
+ 'name' => [
+ 'en' => 'SF',
+ 'fr' => 'SF',
+ ],
+ ],
+ ],
+ ],
+ [
+ 'name' => [
+ 'en' => 'Culture',
+ 'fr' => 'Culture',
+ ],
+ 'children' => [
+ [
+ 'name' => [
+ 'en' => 'History',
+ 'fr' => 'Histoire',
+ ],
+ ],
+ [
+ 'name' => [
+ 'en' => 'Biography',
+ 'fr' => 'Biographie',
+ ],
+ ],
+ [
+ 'name' => [
+ 'en' => 'Cinema',
+ 'fr' => 'Cinéma',
+ ],
+ ],
+ [
+ 'name' => [
+ 'en' => 'Music',
+ 'fr' => 'Musique',
+ ],
+ ],
+ [
+ 'name' => [
+ 'en' => 'Politics',
+ 'fr' => 'Politique',
+ ],
+ ],
+ [
+ 'name' => [
+ 'en' => 'Economy',
+ 'fr' => 'Economie',
+ ],
+ ],
+ ],
+ ],
+ [
+ 'name' => [
+ 'en' => 'Life',
+ 'fr' => 'Vie',
+ ],
+ 'children' => [
+ [
+ 'name' => [
+ 'en' => 'Cook',
+ 'fr' => 'Cuisine',
+ ],
+ ],
+ [
+ 'name' => [
+ 'en' => 'Eroticism',
+ 'fr' => 'Eroticisme',
+ ],
+ ],
+ [
+ 'name' => [
+ 'en' => 'Health',
+ 'fr' => 'Santé',
+ ],
+ ],
+ [
+ 'name' => [
+ 'en' => 'DIY',
+ 'fr' => 'Bricolage',
+ ],
+ ],
+ [
+ 'name' => [
+ 'en' => 'Sports',
+ 'fr' => 'Sports',
+ ],
+ ],
+ [
+ 'name' => [
+ 'en' => 'Travel',
+ 'fr' => 'Voyage',
+ ],
+ ],
+ [
+ 'name' => [
+ 'en' => 'Animals',
+ 'fr' => 'Animaux',
+ ],
+ ],
+ ],
+ ],
+ [
+ 'name' => [
+ 'en' => 'Knowledge',
+ 'fr' => 'Savoir',
+ ],
+ 'children' => [
+ [
+ 'name' => [
+ 'en' => 'School',
+ 'fr' => 'Ecole',
+ ],
+ ],
+ [
+ 'name' => [
+ 'en' => 'Dictionary',
+ 'fr' => 'Dictionnaires',
+ ],
+ ],
+ [
+ 'name' => [
+ 'en' => 'Languages',
+ 'fr' => 'Langues',
+ ],
+ ],
+ [
+ 'name' => [
+ 'en' => 'Law',
+ 'fr' => 'Droit',
+ ],
+ ],
+ [
+ 'name' => [
+ 'en' => 'Science',
+ 'fr' => 'Science',
+ ],
+ ],
+ [
+ 'name' => [
+ 'en' => 'Computer science',
+ 'fr' => 'Informatique',
+ ],
+ 'children' => [
+ [
+ 'name' => [
+ 'en' => 'Hardware',
+ 'fr' => 'Matériel',
+ ],
+ ],
+ [
+ 'name' => [
+ 'en' => 'Software',
+ 'fr' => 'Logiciel',
+ ],
+ ],
+ ],
+ ],
+ [
+ 'name' => [
+ 'en' => 'Business',
+ 'fr' => 'Entreprise',
+ ],
+ ],
+ ],
+ ],
+ ];
+
+ foreach ($categories as $category) {
+ $parent = Category::create([
+ 'type' => 'book',
+ 'name' => $category['name'],
+ ]);
+
+ if (! empty($category['children'])) {
+ foreach ($category['children'] as $child) {
+ $subParent = $parent->children()->create([
+ 'type' => 'book',
+ 'name' => $child['name'],
+ ]);
+
+ if (! empty($child['children'])) {
+ $subParent->children()->createMany(
+ collect($child['children'])
+ ->map(function ($item) {
+ return [
+ 'type' => 'book',
+ 'name' => $item['name'],
+ ];
+ })
+ ->toArray()
+ );
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/examples/demo-laravel/database/seeds/DatabaseSeeder.php b/examples/demo-laravel/database/seeds/DatabaseSeeder.php
index 5306dd2c..f9ca9071 100644
--- a/examples/demo-laravel/database/seeds/DatabaseSeeder.php
+++ b/examples/demo-laravel/database/seeds/DatabaseSeeder.php
@@ -12,16 +12,12 @@ class DatabaseSeeder extends Seeder
*/
public function run()
{
- /**
- * Cleanup media
- */
- foreach (Storage::disk('public')->allDirectories('media') as $dir) {
- Storage::disk('public')->deleteDirectory($dir);
- }
+ Storage::disk('public')->deleteDirectory('media');
$this->call(UserSeeder::class);
$this->call(PublisherSeeder::class);
$this->call(AuthorSeeder::class);
+ $this->call(CategorySeeder::class);
$this->call(BookSeeder::class);
$this->call(ReviewSeeder::class);
}
diff --git a/examples/demo-laravel/routes/api.php b/examples/demo-laravel/routes/api.php
index 194724c1..56bbb2e6 100644
--- a/examples/demo-laravel/routes/api.php
+++ b/examples/demo-laravel/routes/api.php
@@ -34,5 +34,6 @@
'books' => 'BookController',
'reviews' => 'ReviewController',
'publishers' => 'PublisherController',
+ 'categories' => 'CategoryController',
]);
});
diff --git a/examples/demo-laravel/storage/app/public/.gitignore b/examples/demo-laravel/storage/app/public/.gitignore
index 040a7727..d6b7ef32 100644
--- a/examples/demo-laravel/storage/app/public/.gitignore
+++ b/examples/demo-laravel/storage/app/public/.gitignore
@@ -1,4 +1,2 @@
*
-!files
-!media
!.gitignore
diff --git a/examples/demo-laravel/storage/app/public/files/.gitignore b/examples/demo-laravel/storage/app/public/files/.gitignore
deleted file mode 100644
index d6b7ef32..00000000
--- a/examples/demo-laravel/storage/app/public/files/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-*
-!.gitignore
diff --git a/examples/demo-laravel/storage/app/public/media/.gitignore b/examples/demo-laravel/storage/app/public/media/.gitignore
deleted file mode 100644
index d6b7ef32..00000000
--- a/examples/demo-laravel/storage/app/public/media/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-*
-!.gitignore
diff --git a/examples/demo/src/locales/en.json b/examples/demo/src/locales/en.json
index b745829c..ef751348 100644
--- a/examples/demo/src/locales/en.json
+++ b/examples/demo/src/locales/en.json
@@ -77,16 +77,6 @@
},
"books": {
"enums": {
- "category": {
- "novel": "Novel",
- "comic": "Comic",
- "cook": "Cook",
- "economy": "Economy",
- "politics": "Politics",
- "history": "History",
- "fantasy": "Fantasy",
- "biography": "Biography"
- },
"formats": {
"pocket": "Pocket",
"paperback": "Paperback",
diff --git a/examples/demo/src/locales/fr.json b/examples/demo/src/locales/fr.json
index f3e43a34..f2afb8e9 100644
--- a/examples/demo/src/locales/fr.json
+++ b/examples/demo/src/locales/fr.json
@@ -156,16 +156,6 @@
"cheaper_than": "Moins cher que"
},
"enums": {
- "category": {
- "novel": "Roman",
- "comic": "BD",
- "cook": "Cuisine",
- "economy": "Economie",
- "politics": "Politique",
- "history": "Histoire",
- "fantasy": "Fantastique",
- "biography": "Biographie"
- },
"formats": {
"pocket": "Poche",
"paperback": "Broché",
diff --git a/examples/demo/src/resources/books/Form.vue b/examples/demo/src/resources/books/Form.vue
index c13d46f5..161d374f 100644
--- a/examples/demo/src/resources/books/Form.vue
+++ b/examples/demo/src/resources/books/Form.vue
@@ -17,7 +17,12 @@
reference="publishers"
>
-
+
-
+
{{ item.description }}
@@ -57,7 +60,7 @@ export default {
src: "thumbnails.small",
},
},
- { source: "category", type: "select", attributes: { chip: true } },
+ { source: "category.name", labelKey: "category", type: "chip" },
{
source: "publisher",
type: "reference",
diff --git a/examples/demo/src/resources/books/Show.vue b/examples/demo/src/resources/books/Show.vue
index f2456852..c7519e6d 100644
--- a/examples/demo/src/resources/books/Show.vue
+++ b/examples/demo/src/resources/books/Show.vue
@@ -26,7 +26,11 @@
color="orange"
>
-
+
diff --git a/examples/demo/src/resources/index.js b/examples/demo/src/resources/index.js
index fb2b72f4..402d5e01 100644
--- a/examples/demo/src/resources/index.js
+++ b/examples/demo/src/resources/index.js
@@ -14,6 +14,13 @@ export default [
permissions: ["admin", "editor", "author"],
autocompleteFields: ["id", "title", "isbn"],
},
+ {
+ name: "categories",
+ icon: "mdi-tag",
+ label: "name",
+ translatable: true,
+ permissions: ["admin"],
+ },
{
name: "authors",
icon: "mdi-account",
diff --git a/examples/demo/src/views/Settings.vue b/examples/demo/src/views/Settings.vue
index dd6a7dcd..df5b178c 100644
--- a/examples/demo/src/views/Settings.vue
+++ b/examples/demo/src/views/Settings.vue
@@ -1,5 +1,95 @@
-
This is settings page
+ {{ selected }}
+
+
+
diff --git a/examples/demo/vue.config.js b/examples/demo/vue.config.js
index 9ca4442f..825addaa 100644
--- a/examples/demo/vue.config.js
+++ b/examples/demo/vue.config.js
@@ -1,6 +1,6 @@
module.exports = {
publicPath: process.env.BASE_URL,
- transpileDependencies: ["vuetify", "vtec-admin"],
+ transpileDependencies: ["vuetify"],
pluginOptions: {
i18n: {
locale: "en",
diff --git a/examples/laravel/admin/vue.config.js b/examples/laravel/admin/vue.config.js
index 18b2d8de..ff604461 100644
--- a/examples/laravel/admin/vue.config.js
+++ b/examples/laravel/admin/vue.config.js
@@ -1,5 +1,5 @@
module.exports = {
- transpileDependencies: ["vuetify", "vtec-admin"],
+ transpileDependencies: ["vuetify"],
pluginOptions: {
i18n: {
locale: "en",
diff --git a/examples/tutorial/vue.config.js b/examples/tutorial/vue.config.js
index c1d0d64d..a4b35303 100644
--- a/examples/tutorial/vue.config.js
+++ b/examples/tutorial/vue.config.js
@@ -1,5 +1,5 @@
module.exports = {
- transpileDependencies: ["vuetify", "vtec-admin"],
+ transpileDependencies: ["vuetify"],
pluginOptions: {
i18n: {
locale: "en",
diff --git a/packages/admin/src/components/ui/index.js b/packages/admin/src/components/ui/index.js
index f2be06f0..36f3a47f 100644
--- a/packages/admin/src/components/ui/index.js
+++ b/packages/admin/src/components/ui/index.js
@@ -6,6 +6,7 @@ import Show from "./providers/Show";
import Form from "./providers/Form";
import DataTable from "./list/DataTable";
+import Treeview from "./list/Treeview";
import CreateLayout from "./layouts/CreateLayout";
import ShowLayout from "./layouts/ShowLayout";
@@ -63,6 +64,7 @@ export {
Form,
Show,
DataTable,
+ Treeview,
CreateLayout,
ShowLayout,
EditLayout,
diff --git a/packages/admin/src/components/ui/list/DataTable.vue b/packages/admin/src/components/ui/list/DataTable.vue
index 0b870392..cb204c6b 100644
--- a/packages/admin/src/components/ui/list/DataTable.vue
+++ b/packages/admin/src/components/ui/list/DataTable.vue
@@ -73,12 +73,12 @@
v-slot="props"
>
+ @slot Use for field cell templating.
+ @binding {string} resource Name of resource.
+ @binding {string} source Property source.
+ @binding {string} item Full object item.
+ @binding {string} value Value of property source.
+ -->
+ Triggered on successful deletetion of ressource item.
+ @event deleted
+ -->
+
+
+
+
+
+
diff --git a/packages/admin/src/components/ui/providers/List.vue b/packages/admin/src/components/ui/providers/List.vue
index ec48e87a..f1261958 100644
--- a/packages/admin/src/components/ui/providers/List.vue
+++ b/packages/admin/src/components/ui/providers/List.vue
@@ -316,7 +316,8 @@ export default {
...f,
type: f.type || "text",
label:
- f.label || this.$admin.getSourceLabel(this.resource, f.source),
+ f.label ||
+ this.$admin.getSourceLabel(this.resource, f.labelKey || f.source),
};
});
},
diff --git a/packages/admin/src/components/ui/wrappers/Field.vue b/packages/admin/src/components/ui/wrappers/Field.vue
index e029c8f4..f997d42a 100644
--- a/packages/admin/src/components/ui/wrappers/Field.vue
+++ b/packages/admin/src/components/ui/wrappers/Field.vue
@@ -1,5 +1,5 @@
-
+