chore: restructure views and add Livewire components for dashboard functionality
- remove flux dashboard - add DTOs for the connecter services Deps: - spatie/laravel-data - blade-icons (lucide-icons) - tailwind-merge
This commit is contained in:
parent
79c3751d5f
commit
4a5436a3b4
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Data\Ui\ConnectedServices;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* A collection of connected services.
|
||||
*
|
||||
* @extends Collection<int, ConnectedServiceData>
|
||||
*/
|
||||
final class ConnectedServiceCollectionData extends Collection {}
|
||||
24
app/Data/Ui/ConnectedServices/ConnectedServiceData.php
Normal file
24
app/Data/Ui/ConnectedServices/ConnectedServiceData.php
Normal file
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Data\Ui\ConnectedServices;
|
||||
|
||||
use App\Enums\ConnectionStatus;
|
||||
use App\Enums\ConnectionTechTypes;
|
||||
use Livewire\Wireable;
|
||||
use Spatie\LaravelData\Concerns\WireableData;
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
final class ConnectedServiceData extends Data implements Wireable
|
||||
{
|
||||
use WireableData;
|
||||
|
||||
public function __construct(
|
||||
public string $name,
|
||||
public string $icon,
|
||||
public ConnectionTechTypes $type,
|
||||
public string $connectionService,
|
||||
public ConnectionStatus $status,
|
||||
) {}
|
||||
}
|
||||
18
app/Data/Ui/ConnectedServices/ConnectedServicesData.php
Normal file
18
app/Data/Ui/ConnectedServices/ConnectedServicesData.php
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Data\Ui\ConnectedServices;
|
||||
|
||||
use Livewire\Wireable;
|
||||
use Spatie\LaravelData\Concerns\WireableData;
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
final class ConnectedServicesData extends Data implements Wireable
|
||||
{
|
||||
use WireableData;
|
||||
|
||||
public function __construct(
|
||||
public ConnectedServiceCollectionData $services,
|
||||
) {}
|
||||
}
|
||||
13
app/Enums/ConnectionStatus.php
Normal file
13
app/Enums/ConnectionStatus.php
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
enum ConnectionStatus: string
|
||||
{
|
||||
case Connected = 'connected';
|
||||
case Disconnected = 'disconnected';
|
||||
case Pending = 'pending';
|
||||
case Error = 'error';
|
||||
}
|
||||
11
app/Enums/ConnectionTechTypes.php
Normal file
11
app/Enums/ConnectionTechTypes.php
Normal file
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
enum ConnectionTechTypes: string
|
||||
{
|
||||
case OIDC = 'oidc';
|
||||
case SAML = 'saml';
|
||||
}
|
||||
@ -10,11 +10,14 @@
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"php": "^8.3",
|
||||
"gehrisandro/tailwind-merge-laravel": "^1.4",
|
||||
"laravel/fortify": "^1.34",
|
||||
"laravel/framework": "^13.7",
|
||||
"laravel/tinker": "^3.0",
|
||||
"livewire/flux": "^2.13.1",
|
||||
"livewire/livewire": "^4.1"
|
||||
"livewire/livewire": "^4.1",
|
||||
"mallardduck/blade-lucide-icons": "^1.26",
|
||||
"spatie/laravel-data": "^4.22"
|
||||
},
|
||||
"require-dev": {
|
||||
"fakerphp/faker": "^1.24",
|
||||
|
||||
686
composer.lock
generated
686
composer.lock
generated
@ -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": "d3f7e7c18d3f8f9bc93bbbe0115479c5",
|
||||
"content-hash": "2e46083521ccb7753e903364bb87f40b",
|
||||
"packages": [
|
||||
{
|
||||
"name": "bacon/bacon-qr-code",
|
||||
@ -61,6 +61,87 @@
|
||||
},
|
||||
"time": "2026-04-05T21:06:35+00:00"
|
||||
},
|
||||
{
|
||||
"name": "blade-ui-kit/blade-icons",
|
||||
"version": "1.10.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/driesvints/blade-icons.git",
|
||||
"reference": "74189a80bbaa4966aebaee54fec3a3c2ef0a5f3a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/driesvints/blade-icons/zipball/74189a80bbaa4966aebaee54fec3a3c2ef0a5f3a",
|
||||
"reference": "74189a80bbaa4966aebaee54fec3a3c2ef0a5f3a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"illuminate/contracts": "^8.0|^9.0|^10.0|^11.0|^12.0|^13.0",
|
||||
"illuminate/filesystem": "^8.0|^9.0|^10.0|^11.0|^12.0|^13.0",
|
||||
"illuminate/support": "^8.0|^9.0|^10.0|^11.0|^12.0|^13.0",
|
||||
"illuminate/view": "^8.0|^9.0|^10.0|^11.0|^12.0|^13.0",
|
||||
"php": "^7.4|^8.0",
|
||||
"symfony/console": "^5.3|^6.0|^7.0|^8.0",
|
||||
"symfony/finder": "^5.3|^6.0|^7.0|^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"mockery/mockery": "^1.5.1",
|
||||
"orchestra/testbench": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0",
|
||||
"phpunit/phpunit": "^9.0|^10.5|^11.0"
|
||||
},
|
||||
"bin": [
|
||||
"bin/blade-icons-generate"
|
||||
],
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"BladeUI\\Icons\\BladeIconsServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/helpers.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"BladeUI\\Icons\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Dries Vints",
|
||||
"homepage": "https://driesvints.com"
|
||||
}
|
||||
],
|
||||
"description": "A package to easily make use of icons in your Laravel Blade views.",
|
||||
"homepage": "https://github.com/driesvints/blade-icons",
|
||||
"keywords": [
|
||||
"blade",
|
||||
"icons",
|
||||
"laravel",
|
||||
"svg"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/driesvints/blade-icons/issues",
|
||||
"source": "https://github.com/driesvints/blade-icons"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/sponsors/driesvints",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://www.paypal.com/paypalme/driesvints",
|
||||
"type": "paypal"
|
||||
}
|
||||
],
|
||||
"time": "2026-04-23T19:03:45+00:00"
|
||||
},
|
||||
{
|
||||
"name": "brick/math",
|
||||
"version": "0.14.8",
|
||||
@ -732,6 +813,147 @@
|
||||
],
|
||||
"time": "2025-12-03T09:33:47+00:00"
|
||||
},
|
||||
{
|
||||
"name": "gehrisandro/tailwind-merge-laravel",
|
||||
"version": "v1.4.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/gehrisandro/tailwind-merge-laravel.git",
|
||||
"reference": "4dfc54d2f1c148b87a7f9803b3bae74c3437e7d9"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/gehrisandro/tailwind-merge-laravel/zipball/4dfc54d2f1c148b87a7f9803b3bae74c3437e7d9",
|
||||
"reference": "4dfc54d2f1c148b87a7f9803b3bae74c3437e7d9",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"gehrisandro/tailwind-merge-php": "^v1.1.0",
|
||||
"guzzlehttp/guzzle": "^7.5.1",
|
||||
"laravel/framework": "^12.0|^13.0",
|
||||
"php": "^8.2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"laravel/pint": "^1.13.8",
|
||||
"orchestra/testbench": "^10.0|^11.0",
|
||||
"pestphp/pest": "^3.7|^4.4",
|
||||
"pestphp/pest-plugin-arch": "^3.0|^4.0",
|
||||
"pestphp/pest-plugin-type-coverage": "^3.3|^4.0",
|
||||
"phpstan/phpstan": "^1.10.55|^2.1",
|
||||
"rector/rector": "^0.19|^2.0",
|
||||
"symfony/var-dumper": "^6.4.2|^7.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"TailwindMerge\\Laravel\\TailwindMergeServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/helpers.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"TailwindMerge\\Laravel\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Sandro Gehri",
|
||||
"email": "sandrogehri@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "TailwindMerge for Laravel merges multiple Tailwind CSS classes by automatically resolving conflicts between them",
|
||||
"keywords": [
|
||||
"classes",
|
||||
"laravel",
|
||||
"merge",
|
||||
"php",
|
||||
"tailwindcss"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/gehrisandro/tailwind-merge-laravel/issues",
|
||||
"source": "https://github.com/gehrisandro/tailwind-merge-laravel/tree/v1.4.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/gehrisandro",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2026-03-21T06:54:49+00:00"
|
||||
},
|
||||
{
|
||||
"name": "gehrisandro/tailwind-merge-php",
|
||||
"version": "v1.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/gehrisandro/tailwind-merge-php.git",
|
||||
"reference": "400040c89bc958ed130699ee4db0213f689cd498"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/gehrisandro/tailwind-merge-php/zipball/400040c89bc958ed130699ee4db0213f689cd498",
|
||||
"reference": "400040c89bc958ed130699ee4db0213f689cd498",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^8.2.0",
|
||||
"psr/simple-cache": "^3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"laravel/pint": "^1.13.8",
|
||||
"nunomaduro/collision": "^v8.9.1",
|
||||
"pestphp/pest": "^v4.4.2",
|
||||
"pestphp/pest-plugin-type-coverage": "^v4.0.3",
|
||||
"phpstan/phpstan": "^2.1.42",
|
||||
"rector/rector": "^2.3.9",
|
||||
"symfony/var-dumper": "^v7.4.6"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/TailwindMerge.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"TailwindMerge\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Sandro Gehri",
|
||||
"email": "sandrogehri@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "TailwindMerge for PHP merges multiple Tailwind CSS classes by automatically resolving conflicts between them",
|
||||
"keywords": [
|
||||
"classes",
|
||||
"merge",
|
||||
"php",
|
||||
"tailwindcss"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/gehrisandro/tailwind-merge-php/issues",
|
||||
"source": "https://github.com/gehrisandro/tailwind-merge-php/tree/v1.2.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/gehrisandro",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2026-03-21T06:39:15+00:00"
|
||||
},
|
||||
{
|
||||
"name": "graham-campbell/result-type",
|
||||
"version": "v1.1.4",
|
||||
@ -2452,6 +2674,66 @@
|
||||
],
|
||||
"time": "2026-05-01T00:46:07+00:00"
|
||||
},
|
||||
{
|
||||
"name": "mallardduck/blade-lucide-icons",
|
||||
"version": "1.26.19",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mallardduck/blade-lucide-icons.git",
|
||||
"reference": "a6e164dca10d29fd67ca332b9ef78bf2b35e0df8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/mallardduck/blade-lucide-icons/zipball/a6e164dca10d29fd67ca332b9ef78bf2b35e0df8",
|
||||
"reference": "a6e164dca10d29fd67ca332b9ef78bf2b35e0df8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"blade-ui-kit/blade-icons": "^1.8",
|
||||
"php": "^8.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-dom": "*",
|
||||
"ext-fileinfo": "*",
|
||||
"orchestra/testbench": "^6.0|^7.0|^8.0|^9.0|^10.0",
|
||||
"phpunit/phpunit": "^9.0|^10.0|^11.0",
|
||||
"spatie/phpunit-snapshot-assertions": "^4.2.14|^5.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"MallardDuck\\LucideIcons\\BladeLucideIconsServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"MallardDuck\\LucideIcons\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Dan Pock"
|
||||
}
|
||||
],
|
||||
"description": "A package to easily make use of Lucide icons in your Laravel Blade views.",
|
||||
"homepage": "https://github.com/mallardduck/blade-lucide-icons",
|
||||
"keywords": [
|
||||
"LucideIcons",
|
||||
"blade",
|
||||
"laravel"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/mallardduck/blade-lucide-icons/issues",
|
||||
"source": "https://github.com/mallardduck/blade-lucide-icons/tree/1.26.19"
|
||||
},
|
||||
"time": "2026-04-30T00:36:39+00:00"
|
||||
},
|
||||
{
|
||||
"name": "monolog/monolog",
|
||||
"version": "3.10.0",
|
||||
@ -3032,6 +3314,78 @@
|
||||
},
|
||||
"time": "2025-09-24T15:06:41+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpdocumentor/reflection",
|
||||
"version": "6.6.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpDocumentor/Reflection.git",
|
||||
"reference": "c8d36446027506a005103d57265ba5ea56beabfc"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpDocumentor/Reflection/zipball/c8d36446027506a005103d57265ba5ea56beabfc",
|
||||
"reference": "c8d36446027506a005103d57265ba5ea56beabfc",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"composer-runtime-api": "^2",
|
||||
"nikic/php-parser": "~4.18 || ^5.0",
|
||||
"php": "8.1.*|8.2.*|8.3.*|8.4.*|8.5.*",
|
||||
"phpdocumentor/reflection-common": "^2.1",
|
||||
"phpdocumentor/reflection-docblock": "^5",
|
||||
"phpdocumentor/type-resolver": "^1.4",
|
||||
"symfony/polyfill-php80": "^1.28",
|
||||
"webmozart/assert": "^1.7"
|
||||
},
|
||||
"require-dev": {
|
||||
"dealerdirect/phpcodesniffer-composer-installer": "^1.0",
|
||||
"doctrine/coding-standard": "^13.0",
|
||||
"eliashaeussler/phpunit-attributes": "^1.8",
|
||||
"mikey179/vfsstream": "~1.2",
|
||||
"mockery/mockery": "~1.6.0",
|
||||
"phpspec/prophecy-phpunit": "^2.4",
|
||||
"phpstan/extension-installer": "^1.1",
|
||||
"phpstan/phpstan": "^1.8",
|
||||
"phpstan/phpstan-webmozart-assert": "^1.2",
|
||||
"phpunit/phpunit": "^10.5.53",
|
||||
"psalm/phar": "^6.0",
|
||||
"rector/rector": "^1.0.0",
|
||||
"squizlabs/php_codesniffer": "^3.8"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-5.x": "5.3.x-dev",
|
||||
"dev-6.x": "6.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/php-parser/Modifiers.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"phpDocumentor\\": "src/phpDocumentor"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"description": "Reflection library to do Static Analysis for PHP Projects",
|
||||
"homepage": "http://www.phpdoc.org",
|
||||
"keywords": [
|
||||
"phpDocumentor",
|
||||
"phpdoc",
|
||||
"reflection",
|
||||
"static analysis"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/phpDocumentor/Reflection/issues",
|
||||
"source": "https://github.com/phpDocumentor/Reflection/tree/6.6.0"
|
||||
},
|
||||
"time": "2026-04-12T18:07:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpdocumentor/reflection-common",
|
||||
"version": "2.2.0",
|
||||
@ -4070,6 +4424,228 @@
|
||||
},
|
||||
"time": "2025-12-14T04:43:48+00:00"
|
||||
},
|
||||
{
|
||||
"name": "spatie/laravel-data",
|
||||
"version": "4.22.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/spatie/laravel-data.git",
|
||||
"reference": "ec254c0ebc3f3b37515cd7449e2dbb10588e606b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/spatie/laravel-data/zipball/ec254c0ebc3f3b37515cd7449e2dbb10588e606b",
|
||||
"reference": "ec254c0ebc3f3b37515cd7449e2dbb10588e606b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"illuminate/contracts": "^10.0|^11.0|^12.0|^13.0",
|
||||
"php": "^8.1",
|
||||
"phpdocumentor/reflection": "^6.0",
|
||||
"spatie/laravel-package-tools": "^1.9.0",
|
||||
"spatie/php-structure-discoverer": "^2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"fakerphp/faker": "^1.14",
|
||||
"friendsofphp/php-cs-fixer": "^3.0",
|
||||
"inertiajs/inertia-laravel": "^2.0|^3.0",
|
||||
"livewire/livewire": "^3.0|^4.0",
|
||||
"mockery/mockery": "^1.6",
|
||||
"nesbot/carbon": "^2.63|^3.0",
|
||||
"orchestra/testbench": "^8.37.0|^9.16|^10.9|^11.0",
|
||||
"pestphp/pest": "^2.36|^3.8|^4.3",
|
||||
"pestphp/pest-plugin-laravel": "^2.4|^3.0|^4.0",
|
||||
"pestphp/pest-plugin-livewire": "^2.1|^3.0|^4.0",
|
||||
"phpbench/phpbench": "^1.2",
|
||||
"phpstan/extension-installer": "^1.1",
|
||||
"spatie/invade": "^1.0",
|
||||
"spatie/laravel-typescript-transformer": "^2.5",
|
||||
"spatie/pest-plugin-snapshots": "^2.1",
|
||||
"spatie/test-time": "^1.2"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Spatie\\LaravelData\\LaravelDataServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Spatie\\LaravelData\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Ruben Van Assche",
|
||||
"email": "ruben@spatie.be",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "Create unified resources and data transfer objects",
|
||||
"homepage": "https://github.com/spatie/laravel-data",
|
||||
"keywords": [
|
||||
"laravel",
|
||||
"laravel-data",
|
||||
"spatie"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/spatie/laravel-data/issues",
|
||||
"source": "https://github.com/spatie/laravel-data/tree/4.22.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/spatie",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2026-04-27T07:30:53+00:00"
|
||||
},
|
||||
{
|
||||
"name": "spatie/laravel-package-tools",
|
||||
"version": "1.93.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/spatie/laravel-package-tools.git",
|
||||
"reference": "0d097bce95b2bf6802fb1d83e1e753b0f5a948e7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/spatie/laravel-package-tools/zipball/0d097bce95b2bf6802fb1d83e1e753b0f5a948e7",
|
||||
"reference": "0d097bce95b2bf6802fb1d83e1e753b0f5a948e7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"illuminate/contracts": "^10.0|^11.0|^12.0|^13.0",
|
||||
"php": "^8.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"mockery/mockery": "^1.5",
|
||||
"orchestra/testbench": "^8.0|^9.2|^10.0|^11.0",
|
||||
"pestphp/pest": "^2.1|^3.1|^4.0",
|
||||
"phpunit/php-code-coverage": "^10.0|^11.0|^12.0",
|
||||
"phpunit/phpunit": "^10.5|^11.5|^12.5",
|
||||
"spatie/pest-plugin-test-time": "^2.2|^3.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Spatie\\LaravelPackageTools\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Freek Van der Herten",
|
||||
"email": "freek@spatie.be",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "Tools for creating Laravel packages",
|
||||
"homepage": "https://github.com/spatie/laravel-package-tools",
|
||||
"keywords": [
|
||||
"laravel-package-tools",
|
||||
"spatie"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/spatie/laravel-package-tools/issues",
|
||||
"source": "https://github.com/spatie/laravel-package-tools/tree/1.93.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/spatie",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2026-02-21T12:49:54+00:00"
|
||||
},
|
||||
{
|
||||
"name": "spatie/php-structure-discoverer",
|
||||
"version": "2.4.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/spatie/php-structure-discoverer.git",
|
||||
"reference": "10cd4e0018450d23e2bd8f8472569ad0c445c0fc"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/spatie/php-structure-discoverer/zipball/10cd4e0018450d23e2bd8f8472569ad0c445c0fc",
|
||||
"reference": "10cd4e0018450d23e2bd8f8472569ad0c445c0fc",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"illuminate/collections": "^11.0|^12.0|^13.0",
|
||||
"php": "^8.3",
|
||||
"spatie/laravel-package-tools": "^1.92.7",
|
||||
"symfony/finder": "^6.0|^7.3.5|^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"amphp/parallel": "^2.3.2",
|
||||
"illuminate/console": "^11.0|^12.0|^13.0",
|
||||
"nunomaduro/collision": "^7.0|^8.8.3",
|
||||
"orchestra/testbench": "^9.5|^10.8|^11.0",
|
||||
"pestphp/pest": "^3.8|^4.0",
|
||||
"pestphp/pest-plugin-laravel": "^3.2|^4.0",
|
||||
"phpstan/extension-installer": "^1.4.3",
|
||||
"phpstan/phpstan-deprecation-rules": "^1.2.1",
|
||||
"phpstan/phpstan-phpunit": "^1.4.2",
|
||||
"spatie/laravel-ray": "^1.43.1"
|
||||
},
|
||||
"suggest": {
|
||||
"amphp/parallel": "When you want to use the Parallel discover worker"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Spatie\\StructureDiscoverer\\StructureDiscovererServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Spatie\\StructureDiscoverer\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Ruben Van Assche",
|
||||
"email": "ruben@spatie.be",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "Automatically discover structures within your PHP application",
|
||||
"homepage": "https://github.com/spatie/php-structure-discoverer",
|
||||
"keywords": [
|
||||
"discover",
|
||||
"laravel",
|
||||
"php",
|
||||
"php-structure-discoverer"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/spatie/php-structure-discoverer/issues",
|
||||
"source": "https://github.com/spatie/php-structure-discoverer/tree/2.4.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/LaravelAutoDiscoverer",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2026-04-28T06:26:02+00:00"
|
||||
},
|
||||
{
|
||||
"name": "spomky-labs/cbor-php",
|
||||
"version": "3.2.3",
|
||||
@ -4490,16 +5066,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/deprecation-contracts",
|
||||
"version": "v3.6.0",
|
||||
"version": "v3.7.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/deprecation-contracts.git",
|
||||
"reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62"
|
||||
"reference": "50f59d1f3ca46d41ac911f97a78626b6756af35b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62",
|
||||
"reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62",
|
||||
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/50f59d1f3ca46d41ac911f97a78626b6756af35b",
|
||||
"reference": "50f59d1f3ca46d41ac911f97a78626b6756af35b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -4512,7 +5088,7 @@
|
||||
"name": "symfony/contracts"
|
||||
},
|
||||
"branch-alias": {
|
||||
"dev-main": "3.6-dev"
|
||||
"dev-main": "3.7-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@ -4537,7 +5113,7 @@
|
||||
"description": "A generic function and convention to trigger deprecation notices",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0"
|
||||
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.7.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -4548,12 +5124,16 @@
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/nicolas-grekas",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-09-25T14:21:43+00:00"
|
||||
"time": "2026-04-13T15:52:40+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/error-handler",
|
||||
@ -4723,16 +5303,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/event-dispatcher-contracts",
|
||||
"version": "v3.6.0",
|
||||
"version": "v3.7.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/event-dispatcher-contracts.git",
|
||||
"reference": "59eb412e93815df44f05f342958efa9f46b1e586"
|
||||
"reference": "ccba7060602b7fed0b03c85bf025257f76d9ef32"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/59eb412e93815df44f05f342958efa9f46b1e586",
|
||||
"reference": "59eb412e93815df44f05f342958efa9f46b1e586",
|
||||
"url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/ccba7060602b7fed0b03c85bf025257f76d9ef32",
|
||||
"reference": "ccba7060602b7fed0b03c85bf025257f76d9ef32",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -4746,7 +5326,7 @@
|
||||
"name": "symfony/contracts"
|
||||
},
|
||||
"branch-alias": {
|
||||
"dev-main": "3.6-dev"
|
||||
"dev-main": "3.7-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@ -4779,7 +5359,7 @@
|
||||
"standards"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.6.0"
|
||||
"source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.7.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -4790,12 +5370,16 @@
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/nicolas-grekas",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-09-25T14:21:43+00:00"
|
||||
"time": "2026-01-05T13:30:16+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/finder",
|
||||
@ -4947,16 +5531,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/http-kernel",
|
||||
"version": "v8.0.8",
|
||||
"version": "v8.0.10",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/http-kernel.git",
|
||||
"reference": "1770f6818d83b2fddc12185025b93f39a90cb628"
|
||||
"reference": "fb3f65b3d4ca2dad31c80d323819a762ca31d6ac"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/1770f6818d83b2fddc12185025b93f39a90cb628",
|
||||
"reference": "1770f6818d83b2fddc12185025b93f39a90cb628",
|
||||
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/fb3f65b3d4ca2dad31c80d323819a762ca31d6ac",
|
||||
"reference": "fb3f65b3d4ca2dad31c80d323819a762ca31d6ac",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -5027,7 +5611,7 @@
|
||||
"description": "Provides a structured process for converting a Request into a Response",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/http-kernel/tree/v8.0.8"
|
||||
"source": "https://github.com/symfony/http-kernel/tree/v8.0.10"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -5047,7 +5631,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2026-03-31T21:14:05+00:00"
|
||||
"time": "2026-05-06T12:27:31+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/mailer",
|
||||
@ -6546,16 +7130,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/service-contracts",
|
||||
"version": "v3.6.1",
|
||||
"version": "v3.7.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/service-contracts.git",
|
||||
"reference": "45112560a3ba2d715666a509a0bc9521d10b6c43"
|
||||
"reference": "d25d82433a80eba6aa0e6c24b61d7370d99e444a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/45112560a3ba2d715666a509a0bc9521d10b6c43",
|
||||
"reference": "45112560a3ba2d715666a509a0bc9521d10b6c43",
|
||||
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/d25d82433a80eba6aa0e6c24b61d7370d99e444a",
|
||||
"reference": "d25d82433a80eba6aa0e6c24b61d7370d99e444a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -6573,7 +7157,7 @@
|
||||
"name": "symfony/contracts"
|
||||
},
|
||||
"branch-alias": {
|
||||
"dev-main": "3.6-dev"
|
||||
"dev-main": "3.7-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@ -6609,7 +7193,7 @@
|
||||
"standards"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/service-contracts/tree/v3.6.1"
|
||||
"source": "https://github.com/symfony/service-contracts/tree/v3.7.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -6629,7 +7213,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-07-15T11:30:57+00:00"
|
||||
"time": "2026-03-28T09:44:51+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/string",
|
||||
@ -6723,16 +7307,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/translation",
|
||||
"version": "v8.0.8",
|
||||
"version": "v8.0.10",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/translation.git",
|
||||
"reference": "27c03ae3940de24ba2f71cfdbac824f2aa1fdf2f"
|
||||
"reference": "f63e9342e12646a57c91ef8a366a4f9d8e557b67"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/translation/zipball/27c03ae3940de24ba2f71cfdbac824f2aa1fdf2f",
|
||||
"reference": "27c03ae3940de24ba2f71cfdbac824f2aa1fdf2f",
|
||||
"url": "https://api.github.com/repos/symfony/translation/zipball/f63e9342e12646a57c91ef8a366a4f9d8e557b67",
|
||||
"reference": "f63e9342e12646a57c91ef8a366a4f9d8e557b67",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -6792,7 +7376,7 @@
|
||||
"description": "Provides tools to internationalize your application",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/translation/tree/v8.0.8"
|
||||
"source": "https://github.com/symfony/translation/tree/v8.0.10"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -6812,20 +7396,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2026-03-30T15:14:47+00:00"
|
||||
"time": "2026-05-06T11:30:54+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/translation-contracts",
|
||||
"version": "v3.6.1",
|
||||
"version": "v3.7.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/translation-contracts.git",
|
||||
"reference": "65a8bc82080447fae78373aa10f8d13b38338977"
|
||||
"reference": "0ab302977a952b42fd51475c4ebac81f8da0a95d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/translation-contracts/zipball/65a8bc82080447fae78373aa10f8d13b38338977",
|
||||
"reference": "65a8bc82080447fae78373aa10f8d13b38338977",
|
||||
"url": "https://api.github.com/repos/symfony/translation-contracts/zipball/0ab302977a952b42fd51475c4ebac81f8da0a95d",
|
||||
"reference": "0ab302977a952b42fd51475c4ebac81f8da0a95d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -6838,7 +7422,7 @@
|
||||
"name": "symfony/contracts"
|
||||
},
|
||||
"branch-alias": {
|
||||
"dev-main": "3.6-dev"
|
||||
"dev-main": "3.7-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@ -6874,7 +7458,7 @@
|
||||
"standards"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/translation-contracts/tree/v3.6.1"
|
||||
"source": "https://github.com/symfony/translation-contracts/tree/v3.7.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -6894,7 +7478,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-07-15T13:41:35+00:00"
|
||||
"time": "2026-01-05T13:30:16+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/type-info",
|
||||
@ -7515,23 +8099,23 @@
|
||||
},
|
||||
{
|
||||
"name": "webmozart/assert",
|
||||
"version": "2.3.0",
|
||||
"version": "1.12.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/webmozarts/assert.git",
|
||||
"reference": "eb0d790f735ba6cff25c683a85a1da0eadeff9e4"
|
||||
"reference": "9be6926d8b485f55b9229203f962b51ed377ba68"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/webmozarts/assert/zipball/eb0d790f735ba6cff25c683a85a1da0eadeff9e4",
|
||||
"reference": "eb0d790f735ba6cff25c683a85a1da0eadeff9e4",
|
||||
"url": "https://api.github.com/repos/webmozarts/assert/zipball/9be6926d8b485f55b9229203f962b51ed377ba68",
|
||||
"reference": "9be6926d8b485f55b9229203f962b51ed377ba68",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-ctype": "*",
|
||||
"ext-date": "*",
|
||||
"ext-filter": "*",
|
||||
"php": "^8.2"
|
||||
"php": "^7.2 || ^8.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-intl": "",
|
||||
@ -7541,7 +8125,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-feature/2-0": "2.0-dev"
|
||||
"dev-master": "1.10-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@ -7557,10 +8141,6 @@
|
||||
{
|
||||
"name": "Bernhard Schussek",
|
||||
"email": "bschussek@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Woody Gilk",
|
||||
"email": "woody.gilk@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Assertions to validate method input/output with nice error messages.",
|
||||
@ -7571,9 +8151,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/webmozarts/assert/issues",
|
||||
"source": "https://github.com/webmozarts/assert/tree/2.3.0"
|
||||
"source": "https://github.com/webmozarts/assert/tree/1.12.1"
|
||||
},
|
||||
"time": "2026-04-11T10:33:05+00:00"
|
||||
"time": "2025-10-29T15:56:20+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [
|
||||
|
||||
217
config/data.php
Normal file
217
config/data.php
Normal file
@ -0,0 +1,217 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Illuminate\Contracts\Support\Arrayable;
|
||||
use Spatie\LaravelData\Casts\DateTimeInterfaceCast;
|
||||
use Spatie\LaravelData\Casts\EnumCast;
|
||||
use Spatie\LaravelData\Normalizers\ArrayableNormalizer;
|
||||
use Spatie\LaravelData\Normalizers\ArrayNormalizer;
|
||||
use Spatie\LaravelData\Normalizers\JsonNormalizer;
|
||||
use Spatie\LaravelData\Normalizers\ModelNormalizer;
|
||||
use Spatie\LaravelData\Normalizers\ObjectNormalizer;
|
||||
use Spatie\LaravelData\RuleInferrers\AttributesRuleInferrer;
|
||||
use Spatie\LaravelData\RuleInferrers\BuiltInTypesRuleInferrer;
|
||||
use Spatie\LaravelData\RuleInferrers\NullableRuleInferrer;
|
||||
use Spatie\LaravelData\RuleInferrers\RequiredRuleInferrer;
|
||||
use Spatie\LaravelData\RuleInferrers\SometimesRuleInferrer;
|
||||
use Spatie\LaravelData\Support\Creation\ValidationStrategy;
|
||||
use Spatie\LaravelData\Transformers\ArrayableTransformer;
|
||||
use Spatie\LaravelData\Transformers\DateTimeInterfaceTransformer;
|
||||
use Spatie\LaravelData\Transformers\EnumTransformer;
|
||||
|
||||
return [
|
||||
/*
|
||||
* The package will use this format when working with dates. If this option
|
||||
* is an array, it will try to convert from the first format that works,
|
||||
* and will serialize dates using the first format from the array.
|
||||
*/
|
||||
'date_format' => DATE_ATOM,
|
||||
|
||||
/*
|
||||
* When transforming or casting dates, the following timezone will be used to
|
||||
* convert the date to the correct timezone. If set to null no timezone will
|
||||
* be passed.
|
||||
*/
|
||||
'date_timezone' => null,
|
||||
|
||||
/*
|
||||
* It is possible to enable certain features of the package, these would otherwise
|
||||
* be breaking changes, and thus they are disabled by default. In the next major
|
||||
* version of the package, these features will be enabled by default.
|
||||
*/
|
||||
'features' => [
|
||||
'cast_and_transform_iterables' => false,
|
||||
|
||||
/*
|
||||
* When trying to set a computed property value, the package will throw an exception.
|
||||
* You can disable this behaviour by setting this option to true, which will then just
|
||||
* ignore the value being passed into the computed property and recalculate it.
|
||||
*/
|
||||
'ignore_exception_when_trying_to_set_computed_property_value' => false,
|
||||
],
|
||||
|
||||
/*
|
||||
* Global transformers will take complex types and transform them into simple
|
||||
* types.
|
||||
*/
|
||||
'transformers' => [
|
||||
DateTimeInterface::class => DateTimeInterfaceTransformer::class,
|
||||
Arrayable::class => ArrayableTransformer::class,
|
||||
BackedEnum::class => EnumTransformer::class,
|
||||
],
|
||||
|
||||
/*
|
||||
* Global casts will cast values into complex types when creating a data
|
||||
* object from simple types.
|
||||
*/
|
||||
'casts' => [
|
||||
DateTimeInterface::class => DateTimeInterfaceCast::class,
|
||||
BackedEnum::class => EnumCast::class,
|
||||
// Enumerable::class => Spatie\LaravelData\Casts\EnumerableCast::class,
|
||||
],
|
||||
|
||||
/*
|
||||
* Rule inferrers can be configured here. They will automatically add
|
||||
* validation rules to properties of a data object based upon
|
||||
* the type of the property.
|
||||
*/
|
||||
'rule_inferrers' => [
|
||||
SometimesRuleInferrer::class,
|
||||
NullableRuleInferrer::class,
|
||||
RequiredRuleInferrer::class,
|
||||
BuiltInTypesRuleInferrer::class,
|
||||
AttributesRuleInferrer::class,
|
||||
],
|
||||
|
||||
/*
|
||||
* Normalizers return an array representation of the payload, or null if
|
||||
* it cannot normalize the payload. The normalizers below are used for
|
||||
* every data object, unless overridden in a specific data object class.
|
||||
*/
|
||||
'normalizers' => [
|
||||
ModelNormalizer::class,
|
||||
// Spatie\LaravelData\Normalizers\FormRequestNormalizer::class,
|
||||
ArrayableNormalizer::class,
|
||||
ObjectNormalizer::class,
|
||||
ArrayNormalizer::class,
|
||||
JsonNormalizer::class,
|
||||
],
|
||||
|
||||
/*
|
||||
* Data objects can be wrapped into a key like 'data' when used as a resource,
|
||||
* this key can be set globally here for all data objects. You can pass in
|
||||
* `null` if you want to disable wrapping.
|
||||
*/
|
||||
'wrap' => null,
|
||||
|
||||
/*
|
||||
* Adds a specific caster to the Symphony VarDumper component which hides
|
||||
* some properties from data objects and collections when being dumped
|
||||
* by `dump` or `dd`. Can be 'enabled', 'disabled' or 'development'
|
||||
* which will only enable the caster locally.
|
||||
*/
|
||||
'var_dumper_caster_mode' => 'development',
|
||||
|
||||
/*
|
||||
* It is possible to skip the PHP reflection analysis of data objects
|
||||
* when running in production. This will speed up the package. You
|
||||
* can configure where data objects are stored and which cache
|
||||
* store should be used.
|
||||
*
|
||||
* Structures are cached forever as they'll become stale when your
|
||||
* application is deployed with changes. You can set a duration
|
||||
* in seconds if you want the cache to clear after a certain
|
||||
* timeframe.
|
||||
*/
|
||||
'structure_caching' => [
|
||||
'enabled' => true,
|
||||
'directories' => [app_path('Data')],
|
||||
'cache' => [
|
||||
'store' => env('CACHE_STORE', env('CACHE_DRIVER', 'file')),
|
||||
'prefix' => 'laravel-data',
|
||||
'duration' => null,
|
||||
],
|
||||
'reflection_discovery' => [
|
||||
'enabled' => true,
|
||||
'base_path' => base_path(),
|
||||
'root_namespace' => null,
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
* A data object can be validated when created using a factory or when calling the from
|
||||
* method. By default, only when a request is passed the data is being validated. This
|
||||
* behaviour can be changed to always validate or to completely disable validation.
|
||||
*/
|
||||
'validation_strategy' => ValidationStrategy::OnlyRequests->value,
|
||||
|
||||
/*
|
||||
* A data object can map the names of its properties when transforming (output) or when
|
||||
* creating (input). By default, the package will not map any names. You can set a
|
||||
* global strategy here, or override it on a specific data object.
|
||||
*/
|
||||
'name_mapping_strategy' => [
|
||||
'input' => null,
|
||||
'output' => null,
|
||||
],
|
||||
|
||||
/*
|
||||
* When using an invalid include, exclude, only or except partial, the package will
|
||||
* throw an exception. You can disable this behaviour by setting this option to true.
|
||||
*/
|
||||
'ignore_invalid_partials' => false,
|
||||
|
||||
/*
|
||||
* When transforming a nested chain of data objects, the package can end up in an infinite
|
||||
* loop when including a recursive relationship. The max transformation depth can be
|
||||
* set as a safety measure to prevent this from happening. When set to null, the
|
||||
* package will not enforce a maximum depth.
|
||||
*/
|
||||
'max_transformation_depth' => null,
|
||||
|
||||
/*
|
||||
* When the maximum transformation depth is reached, the package will throw an exception.
|
||||
* You can disable this behaviour by setting this option to true which will return an
|
||||
* empty array.
|
||||
*/
|
||||
'throw_when_max_transformation_depth_reached' => true,
|
||||
|
||||
/*
|
||||
* When using the `make:data` command, the package will use these settings to generate
|
||||
* the data classes. You can override these settings by passing options to the command.
|
||||
*/
|
||||
'commands' => [
|
||||
|
||||
/*
|
||||
* Provides default configuration for the `make:data` command. These settings can be overridden with options
|
||||
* passed directly to the `make:data` command for generating single Data classes, or if not set they will
|
||||
* automatically fall back to these defaults. See `php artisan make:data --help` for more information
|
||||
*/
|
||||
'make' => [
|
||||
|
||||
/*
|
||||
* The default namespace for generated Data classes. This exists under the application's root namespace,
|
||||
* so the default 'Data` will end up as '\App\Data', and generated Data classes will be placed in the
|
||||
* app/Data/ folder. Data classes can live anywhere, but this is where `make:data` will put them.
|
||||
*/
|
||||
'namespace' => 'Data',
|
||||
|
||||
/*
|
||||
* This suffix will be appended to all data classes generated by make:data, so that they are less likely
|
||||
* to conflict with other related classes, controllers or models with a similar name without resorting
|
||||
* to adding an alias for the Data object. Set to a blank string (not null) to disable.
|
||||
*/
|
||||
'suffix' => 'Data',
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
* When using Livewire, the package allows you to enable or disable the synths
|
||||
* these synths will automatically handle the data objects and their
|
||||
* properties when used in a Livewire component.
|
||||
*/
|
||||
'livewire' => [
|
||||
'enable_synths' => false,
|
||||
],
|
||||
];
|
||||
@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
use App\Data\Ui\ConnectedServices\ConnectedServiceCollectionData;
|
||||
use App\Data\Ui\ConnectedServices\ConnectedServiceData;
|
||||
use App\Data\Ui\ConnectedServices\ConnectedServicesData;
|
||||
use App\Enums\ConnectionStatus;
|
||||
use App\Enums\ConnectionTechTypes;
|
||||
use Illuminate\Support\Collection;
|
||||
use Livewire\Component;
|
||||
use Spatie\LaravelData\DataCollection;
|
||||
|
||||
new class extends Component {
|
||||
public ConnectedServicesData $connectedServices;
|
||||
|
||||
public function mount(): void
|
||||
{
|
||||
$this->connectedServices = new ConnectedServicesData(
|
||||
services: new ConnectedServiceCollectionData([
|
||||
new ConnectedServiceData(
|
||||
name: 'Microsoft Outlook',
|
||||
icon: 'home',
|
||||
type: ConnectionTechTypes::OIDC,
|
||||
connectionService: 'Azure AD',
|
||||
status: ConnectionStatus::Connected
|
||||
),
|
||||
new ConnectedServiceData(
|
||||
name: 'Microsoft Teams',
|
||||
icon: 'home',
|
||||
type: ConnectionTechTypes::OIDC,
|
||||
connectionService: 'Azure AD',
|
||||
status: ConnectionStatus::Pending
|
||||
),
|
||||
new ConnectedServiceData(
|
||||
name: 'Keka HR',
|
||||
icon: 'home',
|
||||
type: ConnectionTechTypes::SAML,
|
||||
connectionService: 'KeKA',
|
||||
status: ConnectionStatus::Disconnected
|
||||
),
|
||||
new ConnectedServiceData(
|
||||
name: 'Trutimer',
|
||||
icon: 'home',
|
||||
type: ConnectionTechTypes::SAML,
|
||||
connectionService: 'Redmine',
|
||||
status: ConnectionStatus::Error
|
||||
),
|
||||
])
|
||||
);
|
||||
}
|
||||
};
|
||||
?>
|
||||
|
||||
<div class="flex overflow-x-auto gap-x-4">
|
||||
@foreach ($connectedServices->services as $service)
|
||||
<x-shared.card class="min-w-60">
|
||||
<div class="flex space-x-4">
|
||||
<div class="bg-blue-200 p-4 rounded-lg flex items-center justify-center max-h-10">
|
||||
<svg role="img" class="w-4 h-4" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>
|
||||
Outline</title>
|
||||
<path
|
||||
d="M 15.081 21.857 L 15.081 22.459 C 15.081 23.636 13.812 24.378 12.785 23.8 L 3.543 18.602 C 3.058 18.329 2.758 17.816 2.758 17.26 L 2.758 6.742 C 2.758 6.185 3.058 5.672 3.543 5.399 L 12.785 0.201 C 13.812 -0.378 15.082 0.365 15.081 1.544 L 15.081 2.145 L 16.178 1.814 C 17.167 1.517 18.163 2.258 18.162 3.29 L 18.162 3.915 L 19.511 3.746 C 20.431 3.632 21.243 4.348 21.242 5.275 L 21.242 18.726 C 21.243 19.652 20.431 20.37 19.511 20.254 L 18.162 20.085 L 18.162 20.71 C 18.163 21.743 17.167 22.484 16.178 22.186 L 15.081 21.857 Z M 15.081 20.249 L 16.621 20.71 L 16.621 3.29 L 15.081 3.753 L 15.081 20.249 Z M 18.162 5.467 L 18.162 18.534 L 19.702 18.726 L 19.702 5.275 L 18.162 5.467 Z M 2.758 16.801 L 2.758 7.2 L 2.758 16.801 Z M 4.298 6.742 L 4.298 17.26 L 13.54 22.459 L 13.54 1.544 L 4.298 6.742 Z M 5.838 7.765 L 7.379 6.995 L 7.379 17.005 L 5.838 16.235 L 5.838 7.765 Z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<p class="font-medium">{{$service->name}}</p>
|
||||
<p class="text-sm text-gray-600">{{$service->type->name}} - {{$service->connectionService}}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-4 flex space-x-2.5 justify-between items-center">
|
||||
<div class="flex items-center space-x-1">
|
||||
<div
|
||||
@class([
|
||||
"w-2 h-2 rounded-full",
|
||||
'bg-green-400' => $service->status === ConnectionStatus::Connected,
|
||||
'bg-gray-400' => $service->status === ConnectionStatus::Disconnected,
|
||||
'bg-yellow-400' => $service->status === ConnectionStatus::Pending,
|
||||
'bg-red-400' => $service->status === ConnectionStatus::Error,
|
||||
])
|
||||
></div>
|
||||
<p class="text-sm">{{ucfirst($service->status->name)}}</p>
|
||||
</div>
|
||||
<x-shared.button>Revoke</x-shared.button>
|
||||
</div>
|
||||
</x-shared.card>
|
||||
@endforeach
|
||||
</div>
|
||||
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
use Livewire\Component;
|
||||
|
||||
new class extends Component
|
||||
{
|
||||
public string $selectedTab = 'all-tab';
|
||||
};
|
||||
?>
|
||||
|
||||
<div>
|
||||
<x-shared.card class="p-0">
|
||||
<div class="p-4 flex justify-between border-b border-gray-200">
|
||||
<h2 class="font-medium flex items-center gap-x-2">
|
||||
<x-lucide-grid-2x2-plus class="w-5 h-5"/>
|
||||
{{ __('Connected Services') }}
|
||||
</h2>
|
||||
<x-shared.button>
|
||||
<div class="flex items-center gap-x-2">
|
||||
<x-lucide-plus class="w-5 h-5"/>
|
||||
{{ __('Add service') }}
|
||||
</div>
|
||||
</x-shared.button>
|
||||
</div>
|
||||
<x-shared.tabs.tabs wire:model="selectedTab" class="px-4">
|
||||
<x-shared.tabs.tab name="all-tab" label="All" class="">
|
||||
<livewire:connected-services.all-connected-services />
|
||||
</x-shared.tabs.tab>
|
||||
<x-shared.tabs.tab name="oidc-tab" label="OIDC">
|
||||
<div>Tricks</div>
|
||||
</x-shared.tabs.tab>
|
||||
<x-shared.tabs.tab name="saml-tab" label="SAML">
|
||||
<div>Musics</div>
|
||||
</x-shared.tabs.tab>
|
||||
</x-shared.tabs.tabs>
|
||||
</x-shared.card>
|
||||
</div>
|
||||
192
resources/views/components/dashboard-sidebar.blade.php
Normal file
192
resources/views/components/dashboard-sidebar.blade.php
Normal file
@ -0,0 +1,192 @@
|
||||
<?php
|
||||
|
||||
use Livewire\Component;
|
||||
use Livewire\Attributes\On;
|
||||
|
||||
new class extends Component {
|
||||
/** Collapsed = icons-only mode */
|
||||
public bool $collapsed = false;
|
||||
|
||||
/** Active nav key — passed as a prop from the parent layout */
|
||||
public string $active = 'dashboard';
|
||||
|
||||
public function mount(string $active = 'dashboard'): void
|
||||
{
|
||||
$this->active = $active;
|
||||
$this->collapsed = session('sidebar_collapsed', false);
|
||||
}
|
||||
|
||||
public function toggle(): void
|
||||
{
|
||||
$this->collapsed = !$this->collapsed;
|
||||
session(['sidebar_collapsed' => $this->collapsed]);
|
||||
}
|
||||
|
||||
public function navItems(): array
|
||||
{
|
||||
return [
|
||||
[
|
||||
'key' => 'dashboard',
|
||||
'label' => 'Dashboard',
|
||||
'icon' => 'lucide-house',
|
||||
'route' => 'home',
|
||||
],
|
||||
[
|
||||
'key' => 'users',
|
||||
'label' => 'Users',
|
||||
'icon' => 'lucide-users',
|
||||
'route' => 'home',
|
||||
],
|
||||
];
|
||||
}
|
||||
};
|
||||
?>
|
||||
<aside
|
||||
x-data="{ collapsed: @entangle('collapsed') }"
|
||||
:class="collapsed ? 'w-12' : 'w-64'"
|
||||
class="relative flex flex-col h-screen bg-white border-r border-gray-100
|
||||
transition-[width] duration-300 ease-in-out shrink-0 overflow-hidden"
|
||||
:aria-expanded="String(!collapsed)"
|
||||
>
|
||||
|
||||
<div class="flex items-center h-20 px-2 border-b border-gray-100 shrink-0">
|
||||
|
||||
<a
|
||||
href="{{ route('dashboard') }}"
|
||||
wire:navigate
|
||||
class="shrink-0 flex items-center justify-center w-8 h-8
|
||||
rounded-lg bg-blue-600 text-gray-50
|
||||
shadow-sm focus-visible:outline-none
|
||||
focus-visible:ring-2 focus-visible:ring-cyan-400"
|
||||
aria-label="Go to dashboard"
|
||||
>
|
||||
<span class="w-4 h-4">
|
||||
@svg('lucide-shield-cog')
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<span
|
||||
x-cloak
|
||||
x-show="!collapsed"
|
||||
x-transition:enter="transition-all duration-200 delay-150 ease-out"
|
||||
x-transition:enter-start="opacity-0 -translate-x-2"
|
||||
x-transition:enter-end="opacity-100 translate-x-0"
|
||||
x-transition:leave="transition-opacity duration-100"
|
||||
x-transition:leave-start="opacity-100"
|
||||
x-transition:leave-end="opacity-0"
|
||||
class="ml-3 text-sm font-semibold text-gray-900 whitespace-nowrap tracking-tight"
|
||||
>
|
||||
<h1 class="text-lg">Company SSO</h1>
|
||||
<h2 class="text-sm font-light">Admin Panel</h2>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<nav
|
||||
class="flex-1 py-3 px-2 space-y-0.5 overflow-y-auto overflow-x-hidden"
|
||||
aria-label="Main navigation"
|
||||
>
|
||||
@foreach ($this->navItems() as $item)
|
||||
@php $isActive = $active === $item['key']; @endphp
|
||||
|
||||
<a
|
||||
href=""
|
||||
wire:navigate
|
||||
@class([
|
||||
'group relative flex items-center gap-3 px-2 py-2.5 rounded-lg',
|
||||
'text-sm font-medium transition-colors duration-150',
|
||||
'bg-gray-100 text-gray-900' => $isActive,
|
||||
'text-gray-500 hover:bg-gray-50 hover:text-gray-800' => ! $isActive,
|
||||
])
|
||||
aria-current="{{ $isActive ? 'page' : 'false' }}"
|
||||
>
|
||||
{{-- Active pill indicator --}}
|
||||
@if ($isActive)
|
||||
<span
|
||||
class="absolute left-0 inset-y-2 w-0.5 rounded-r-full bg-blue-600"
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
@endif
|
||||
|
||||
<span class="w-4 h-4">
|
||||
@svg($item['icon'])
|
||||
</span>
|
||||
|
||||
{{-- Label — hidden when collapsed --}}
|
||||
<span
|
||||
x-cloak
|
||||
x-show="!collapsed"
|
||||
x-transition:enter="transition-opacity duration-200 delay-100"
|
||||
x-transition:enter-start="opacity-0"
|
||||
x-transition:enter-end="opacity-100"
|
||||
x-transition:leave="transition-opacity duration-75"
|
||||
x-transition:leave-start="opacity-100"
|
||||
x-transition:leave-end="opacity-0"
|
||||
class="whitespace-nowrap overflow-hidden leading-none"
|
||||
>
|
||||
{{ $item['label'] }}
|
||||
</span>
|
||||
|
||||
{{-- Tooltip — only rendered & visible in collapsed mode --}}
|
||||
<span
|
||||
x-cloak
|
||||
x-show="collapsed"
|
||||
role="tooltip"
|
||||
class="pointer-events-none absolute left-full ml-3 z-50
|
||||
whitespace-nowrap rounded-md bg-gray-900 px-2.5 py-1.5
|
||||
text-xs font-medium text-white shadow-xl
|
||||
opacity-0 group-hover:opacity-100
|
||||
transition-opacity duration-150 delay-75"
|
||||
>
|
||||
{{ $item['label'] }}
|
||||
{{-- Arrow --}}
|
||||
<span
|
||||
class="absolute right-full top-1/2 -translate-y-1/2
|
||||
border-[5px] border-transparent border-r-gray-900"
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
</span>
|
||||
</a>
|
||||
@endforeach
|
||||
</nav>
|
||||
|
||||
<div class="border-t border-gray-100 px-2 py-3 shrink-0">
|
||||
<button
|
||||
wire:click="toggle"
|
||||
type="button"
|
||||
class="group w-full flex items-center gap-3 px-2 py-2.5 rounded-lg
|
||||
text-sm font-medium text-gray-400
|
||||
hover:bg-gray-50 hover:text-gray-700
|
||||
transition-colors duration-150
|
||||
focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-teal-400"
|
||||
:aria-label="collapsed ? 'Expand sidebar' : 'Collapse sidebar'"
|
||||
>
|
||||
<span class="flex-shrink-0 flex items-center justify-center w-5 h-5" aria-hidden="true">
|
||||
<svg
|
||||
:class="collapsed ? 'rotate-180' : 'rotate-0'"
|
||||
class="w-4 h-4 transition-transform duration-300 ease-in-out"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="2"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 19.5L8.25 12l7.5-7.5"/>
|
||||
</svg>
|
||||
</span>
|
||||
|
||||
<span
|
||||
x-cloak
|
||||
x-show="!collapsed"
|
||||
x-transition:enter="transition-opacity duration-200 delay-100"
|
||||
x-transition:enter-start="opacity-0"
|
||||
x-transition:enter-end="opacity-100"
|
||||
x-transition:leave="transition-opacity duration-75"
|
||||
x-transition:leave-start="opacity-100"
|
||||
x-transition:leave-end="opacity-0"
|
||||
class="whitespace-nowrap"
|
||||
>
|
||||
Collapse
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</aside>
|
||||
18
resources/views/components/dashboard-stats.blade.php
Normal file
18
resources/views/components/dashboard-stats.blade.php
Normal file
@ -0,0 +1,18 @@
|
||||
<grid class="grid grid-cols-4 gap-x-4">
|
||||
<x-shared.card >
|
||||
<p class="text-sm text-gray-400">Total Users</p>
|
||||
<p class="text-2xl">284</p>
|
||||
</x-shared.card>
|
||||
<x-shared.card >
|
||||
<p class="text-sm text-gray-400">Active Roles</p>
|
||||
<p class="text-2xl">4</p>
|
||||
</x-shared.card>
|
||||
<x-shared.card >
|
||||
<p class="text-sm text-gray-400">Services</p>
|
||||
<p class="text-2xl">8</p>
|
||||
</x-shared.card>
|
||||
<x-shared.card >
|
||||
<p class="text-sm text-gray-400">Revoked Today</p>
|
||||
<p class="text-2xl">7</p>
|
||||
</x-shared.card>
|
||||
</grid>
|
||||
12
resources/views/components/dashbord-topbar.blade.php
Normal file
12
resources/views/components/dashbord-topbar.blade.php
Normal file
@ -0,0 +1,12 @@
|
||||
<div class="w-full py-4 px-10 border-b border-gray-200 flex justify-center">
|
||||
<div class="flex-1 py-2">
|
||||
<p class="text-xl font-medium">Admin Panel</p>
|
||||
</div>
|
||||
<div class="flex space-x-4">
|
||||
<x-shared.button>
|
||||
<x-lucide-bell class="w-5 h-5" />
|
||||
</x-shared.button>
|
||||
<div class="rounded-full w-12 h-12 bg-blue-200">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -1,12 +0,0 @@
|
||||
@props([
|
||||
'id' => uniqid(),
|
||||
])
|
||||
|
||||
<svg {{ $attributes }} fill="none">
|
||||
<defs>
|
||||
<pattern id="pattern-{{ $id }}" x="0" y="0" width="8" height="8" patternUnits="userSpaceOnUse">
|
||||
<path d="M-1 5L5 -1M3 9L8.5 3.5" stroke-width="0.5"></path>
|
||||
</pattern>
|
||||
</defs>
|
||||
<rect stroke="none" fill="url(#pattern-{{ $id }})" width="100%" height="100%"></rect>
|
||||
</svg>
|
||||
3
resources/views/components/shared/button.blade.php
Normal file
3
resources/views/components/shared/button.blade.php
Normal file
@ -0,0 +1,3 @@
|
||||
<button class="rounded-lg border border-gray-300 px-6 py-2 text-gray-700">
|
||||
{{$slot}}
|
||||
</button>
|
||||
3
resources/views/components/shared/card.blade.php
Normal file
3
resources/views/components/shared/card.blade.php
Normal file
@ -0,0 +1,3 @@
|
||||
<div {{$attributes->twMerge('rounded-xl border border-gray-200 p-4 shadow-xs bg-white')}}>
|
||||
{{$slot}}
|
||||
</div>
|
||||
45
resources/views/components/shared/tabs/tab.blade.php
Normal file
45
resources/views/components/shared/tabs/tab.blade.php
Normal file
@ -0,0 +1,45 @@
|
||||
@php use Illuminate\Support\Facades\Blade; @endphp
|
||||
@props([
|
||||
'name',
|
||||
'label' => null,
|
||||
'disabled' => false,
|
||||
'hidden' => false,
|
||||
])
|
||||
|
||||
@php
|
||||
$fromLabel = $label ?? '';
|
||||
|
||||
$labelHtml = Blade::render("
|
||||
<div @class([
|
||||
'whitespace-nowrap',
|
||||
'text-base-content/30 cursor-not-allowed' => '{$disabled}'
|
||||
])>
|
||||
{$fromLabel}
|
||||
</div>
|
||||
");
|
||||
@endphp
|
||||
|
||||
<div
|
||||
data-name="{{ $name }}"
|
||||
x-init="
|
||||
const newItem = {
|
||||
name: '{{ $name }}',
|
||||
label: {{ json_encode($labelHtml) }},
|
||||
disabled: {{ $disabled ? 'true' : 'false' }},
|
||||
hidden: {{ $hidden ? 'true' : 'false' }}
|
||||
};
|
||||
const index = tabs.findIndex(item => item.name === '{{ $name }}');
|
||||
index !== -1 ? tabs[index] = newItem : tabs.push(newItem);
|
||||
|
||||
Livewire.hook('morph.removed', ({el}) => {
|
||||
if (el.getAttribute('data-name') == '{{ $name }}'){
|
||||
tabs = tabs.filter(i => i.name !== '{{ $name }}')
|
||||
}
|
||||
})
|
||||
"
|
||||
x-show="selected === '{{ $name }}'"
|
||||
role="tabpanel"
|
||||
{{ $attributes->class("tab-content py-5 px-1") }}
|
||||
>
|
||||
{{ $slot }}
|
||||
</div>
|
||||
37
resources/views/components/shared/tabs/tabs.blade.php
Normal file
37
resources/views/components/shared/tabs/tabs.blade.php
Normal file
@ -0,0 +1,37 @@
|
||||
@props([
|
||||
'selected' => null,
|
||||
'labelClass' => 'px-4 py-3 cursor-pointer',
|
||||
'activeClass' => 'font-medium border-b border-b-gray-400',
|
||||
'labelDivClass' => 'border-b border-b-base-content/10 flex overflow-x-auto',
|
||||
'tabsClass' => 'relative w-full',
|
||||
])
|
||||
|
||||
<div
|
||||
x-data="{
|
||||
tabs: [],
|
||||
selected:
|
||||
@if($selected)
|
||||
'{{ $selected }}'
|
||||
@else
|
||||
@entangle($attributes->wire('model'))
|
||||
@endif
|
||||
}"
|
||||
class="{{ $tabsClass }}"
|
||||
x-class="font-semibold pb-1 border-b-[length:var(--border)] border-b-base-content/50 border-b-base-content/10 flex overflow-x-auto scrollbar-hide relative w-full"
|
||||
>
|
||||
<div class="{{ $labelDivClass }}">
|
||||
<template x-for="tab in tabs" :key="tab.name">
|
||||
<a
|
||||
role="tab"
|
||||
x-init="if (typeof tab == 'undefined') $el.remove()"
|
||||
x-html="tab.label"
|
||||
@click="tab.disabled ? null: selected = tab.name"
|
||||
:class="{ '{{ $activeClass }} tab-active': selected === tab.name, 'hidden': tab.hidden }"
|
||||
class="{{ $labelClass }}"></a>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<div role="tablist" {{ $attributes->except(['wire:model', 'wire:model.live'])->class(['block']) }}>
|
||||
{{ $slot }}
|
||||
</div>
|
||||
</div>
|
||||
@ -1,18 +0,0 @@
|
||||
<x-layouts::app :title="__('Dashboard')">
|
||||
<div class="flex h-full w-full flex-1 flex-col gap-4 rounded-xl">
|
||||
<div class="grid auto-rows-min gap-4 md:grid-cols-3">
|
||||
<div class="relative aspect-video overflow-hidden rounded-xl border border-neutral-200 dark:border-neutral-700">
|
||||
<x-placeholder-pattern class="absolute inset-0 size-full stroke-gray-900/20 dark:stroke-neutral-100/20" />
|
||||
</div>
|
||||
<div class="relative aspect-video overflow-hidden rounded-xl border border-neutral-200 dark:border-neutral-700">
|
||||
<x-placeholder-pattern class="absolute inset-0 size-full stroke-gray-900/20 dark:stroke-neutral-100/20" />
|
||||
</div>
|
||||
<div class="relative aspect-video overflow-hidden rounded-xl border border-neutral-200 dark:border-neutral-700">
|
||||
<x-placeholder-pattern class="absolute inset-0 size-full stroke-gray-900/20 dark:stroke-neutral-100/20" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="relative h-full flex-1 overflow-hidden rounded-xl border border-neutral-200 dark:border-neutral-700">
|
||||
<x-placeholder-pattern class="absolute inset-0 size-full stroke-gray-900/20 dark:stroke-neutral-100/20" />
|
||||
</div>
|
||||
</div>
|
||||
</x-layouts::app>
|
||||
@ -3,99 +3,16 @@
|
||||
<head>
|
||||
@include('partials.head')
|
||||
</head>
|
||||
<body class="min-h-screen bg-white dark:bg-zinc-800">
|
||||
<flux:sidebar sticky collapsible="mobile" class="border-e border-zinc-200 bg-zinc-50 dark:border-zinc-700 dark:bg-zinc-900">
|
||||
<flux:sidebar.header>
|
||||
<x-app-logo :sidebar="true" href="{{ route('dashboard') }}" wire:navigate />
|
||||
<flux:sidebar.collapse class="lg:hidden" />
|
||||
</flux:sidebar.header>
|
||||
|
||||
<flux:sidebar.nav>
|
||||
<flux:sidebar.group :heading="__('Platform')" class="grid">
|
||||
<flux:sidebar.item icon="home" :href="route('dashboard')" :current="request()->routeIs('dashboard')" wire:navigate>
|
||||
{{ __('Dashboard') }}
|
||||
</flux:sidebar.item>
|
||||
</flux:sidebar.group>
|
||||
</flux:sidebar.nav>
|
||||
|
||||
<flux:spacer />
|
||||
|
||||
<flux:sidebar.nav>
|
||||
<flux:sidebar.item icon="folder-git-2" href="https://github.com/laravel/livewire-starter-kit" target="_blank">
|
||||
{{ __('Repository') }}
|
||||
</flux:sidebar.item>
|
||||
|
||||
<flux:sidebar.item icon="book-open-text" href="https://laravel.com/docs/starter-kits#livewire" target="_blank">
|
||||
{{ __('Documentation') }}
|
||||
</flux:sidebar.item>
|
||||
</flux:sidebar.nav>
|
||||
|
||||
<x-desktop-user-menu class="hidden lg:block" :name="auth()->user()->name" />
|
||||
</flux:sidebar>
|
||||
|
||||
<!-- Mobile User Menu -->
|
||||
<flux:header class="lg:hidden">
|
||||
<flux:sidebar.toggle class="lg:hidden" icon="bars-2" inset="left" />
|
||||
|
||||
<flux:spacer />
|
||||
|
||||
<flux:dropdown position="top" align="end">
|
||||
<flux:profile
|
||||
:initials="auth()->user()->initials()"
|
||||
icon-trailing="chevron-down"
|
||||
/>
|
||||
|
||||
<flux:menu>
|
||||
<flux:menu.radio.group>
|
||||
<div class="p-0 text-sm font-normal">
|
||||
<div class="flex items-center gap-2 px-1 py-1.5 text-start text-sm">
|
||||
<flux:avatar
|
||||
:name="auth()->user()->name"
|
||||
:initials="auth()->user()->initials()"
|
||||
/>
|
||||
|
||||
<div class="grid flex-1 text-start text-sm leading-tight">
|
||||
<flux:heading class="truncate">{{ auth()->user()->name }}</flux:heading>
|
||||
<flux:text class="truncate">{{ auth()->user()->email }}</flux:text>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</flux:menu.radio.group>
|
||||
|
||||
<flux:menu.separator />
|
||||
|
||||
<flux:menu.radio.group>
|
||||
<flux:menu.item :href="route('profile.edit')" icon="cog" wire:navigate>
|
||||
{{ __('Settings') }}
|
||||
</flux:menu.item>
|
||||
</flux:menu.radio.group>
|
||||
|
||||
<flux:menu.separator />
|
||||
|
||||
<form method="POST" action="{{ route('logout') }}" class="w-full">
|
||||
@csrf
|
||||
<flux:menu.item
|
||||
as="button"
|
||||
type="submit"
|
||||
icon="arrow-right-start-on-rectangle"
|
||||
class="w-full cursor-pointer"
|
||||
data-test="logout-button"
|
||||
>
|
||||
{{ __('Log out') }}
|
||||
</flux:menu.item>
|
||||
</form>
|
||||
</flux:menu>
|
||||
</flux:dropdown>
|
||||
</flux:header>
|
||||
|
||||
<body class="min-h-screen bg-gray-50 antialiased">
|
||||
<div class="flex h-full">
|
||||
<livewire:dashboard-sidebar :active="$activeNav ?? 'dashboard'"/>
|
||||
<div class="flex flex-col flex-1 min-w-0 overflow-hidden">
|
||||
<x-dashbord-topbar/>
|
||||
<main class="">
|
||||
{{ $slot }}
|
||||
|
||||
@persist('toast')
|
||||
<flux:toast.group>
|
||||
<flux:toast />
|
||||
</flux:toast.group>
|
||||
@endpersist
|
||||
|
||||
@fluxScripts
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
@livewireScripts
|
||||
</body>
|
||||
</html>
|
||||
|
||||
20
resources/views/pages/⚡dashboard.blade.php
Normal file
20
resources/views/pages/⚡dashboard.blade.php
Normal file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Routing\Attributes\Controllers\Middleware;
|
||||
use Livewire\Attributes\Layout;
|
||||
use Livewire\Attributes\Title;
|
||||
use Livewire\Component;
|
||||
|
||||
new
|
||||
#[Layout('layouts.app')]
|
||||
#[Title('Dashboard')]
|
||||
#[Middleware('auth,verified')]
|
||||
class extends Component {
|
||||
};
|
||||
?>
|
||||
|
||||
<div class="flex h-full w-full flex-1 flex-col gap-4 rounded-xl">
|
||||
<x-dashboard-stats />
|
||||
<livewire:connected-services />
|
||||
</div>
|
||||
|
||||
@ -12,4 +12,4 @@
|
||||
@fonts
|
||||
|
||||
@vite(['resources/css/app.css', 'resources/js/app.js'])
|
||||
@fluxAppearance
|
||||
@livewireStyles
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::view('/', 'welcome')->name('home');
|
||||
|
||||
Route::middleware(['auth', 'verified'])->group(function () {
|
||||
Route::view('dashboard', 'dashboard')->name('dashboard');
|
||||
});
|
||||
Route::livewire('dashboard', 'pages::dashboard')->name('dashboard');
|
||||
|
||||
require __DIR__ . '/settings.php';
|
||||
|
||||
@ -1,21 +1,23 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Auth\Notifications\ResetPassword;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
use Laravel\Fortify\Features;
|
||||
|
||||
beforeEach(function () {
|
||||
beforeEach(function (): void {
|
||||
$this->skipUnlessFortifyHas(Features::resetPasswords());
|
||||
});
|
||||
|
||||
test('reset password link screen can be rendered', function () {
|
||||
test('reset password link screen can be rendered', function (): void {
|
||||
$response = $this->get(route('password.request'));
|
||||
|
||||
$response->assertOk();
|
||||
});
|
||||
|
||||
test('reset password link can be requested', function () {
|
||||
test('reset password link can be requested', function (): void {
|
||||
Notification::fake();
|
||||
|
||||
$user = User::factory()->create();
|
||||
@ -25,7 +27,7 @@
|
||||
Notification::assertSentTo($user, ResetPassword::class);
|
||||
});
|
||||
|
||||
test('reset password screen can be rendered', function () {
|
||||
test('reset password screen can be rendered', function (): void {
|
||||
Notification::fake();
|
||||
|
||||
$user = User::factory()->create();
|
||||
@ -41,7 +43,7 @@
|
||||
});
|
||||
});
|
||||
|
||||
test('password can be reset with valid token', function () {
|
||||
test('password can be reset with valid token', function (): void {
|
||||
Notification::fake();
|
||||
|
||||
$user = User::factory()->create();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user