feat: display vaults (monicahq/chandler#2)
This commit is contained in:
@@ -3,12 +3,10 @@
|
||||
namespace App\Features\Account\ManageAccount\Services;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Models\Vault;
|
||||
use App\Models\Account;
|
||||
use App\Jobs\SetupAccount;
|
||||
use App\Jobs\CreateAuditLog;
|
||||
use App\Services\BaseService;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Interfaces\ServiceInterface;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
|
||||
@@ -17,7 +15,6 @@ class CreateAccount extends BaseService implements ServiceInterface
|
||||
private User $user;
|
||||
private Account $account;
|
||||
private array $data;
|
||||
public Vault $vault;
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the service.
|
||||
@@ -47,7 +44,6 @@ class CreateAccount extends BaseService implements ServiceInterface
|
||||
|
||||
$this->account = Account::create();
|
||||
$this->addFirstUser();
|
||||
$this->createFirstVault();
|
||||
$this->addLogs();
|
||||
|
||||
SetupAccount::dispatch($this->user)->onQueue('low');
|
||||
@@ -67,21 +63,6 @@ class CreateAccount extends BaseService implements ServiceInterface
|
||||
]);
|
||||
}
|
||||
|
||||
private function createFirstVault(): void
|
||||
{
|
||||
$this->vault = Vault::create([
|
||||
'account_id' => $this->account->id,
|
||||
'type' => Vault::TYPE_PERSONAL,
|
||||
'name' => trans('account.default_vault_name'),
|
||||
]);
|
||||
|
||||
DB::table('user_vault')->insert([
|
||||
'vault_id' => $this->vault->id,
|
||||
'user_id' => $this->user->id,
|
||||
'permission' => Vault::PERMISSION_MANAGE,
|
||||
]);
|
||||
}
|
||||
|
||||
private function addLogs(): void
|
||||
{
|
||||
CreateAuditLog::dispatch([
|
||||
@@ -91,16 +72,5 @@ class CreateAccount extends BaseService implements ServiceInterface
|
||||
'action_name' => 'account_created',
|
||||
'objects' => json_encode([]),
|
||||
]);
|
||||
|
||||
CreateAuditLog::dispatch([
|
||||
'account_id' => $this->account->id,
|
||||
'author_id' => $this->user->id,
|
||||
'author_name' => $this->user->name,
|
||||
'action_name' => 'vault_created',
|
||||
'objects' => json_encode([
|
||||
'vault_id' => $this->vault->id,
|
||||
'vault_name' => $this->vault->name,
|
||||
]),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace App\Features\Vault\ManageVault\ViewHelpers;
|
||||
|
||||
class VaultCreateViewHelper
|
||||
{
|
||||
/**
|
||||
* Get all the data needed for the page.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function data(): array
|
||||
{
|
||||
return [
|
||||
'url' => [
|
||||
'store' => route('vault.store'),
|
||||
'back' => route('vault.index'),
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace App\Features\Vault\ManageVault\ViewHelpers;
|
||||
|
||||
use App\Models\Vault;
|
||||
use App\Models\Account;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class VaultIndexViewHelper
|
||||
{
|
||||
/**
|
||||
* Get all the data needed for the general layout page.
|
||||
*
|
||||
* @param Vault $vault
|
||||
* @return array
|
||||
*/
|
||||
public static function layoutData(Vault $vault = null): array
|
||||
{
|
||||
return [
|
||||
'user' => [
|
||||
'name' => Auth::user()->name,
|
||||
],
|
||||
'vault' => $vault ? [
|
||||
'id' => $vault->id,
|
||||
'name' => $vault->name,
|
||||
] : null,
|
||||
'url' => [
|
||||
'vaults' => route('vault.index'),
|
||||
'logout' => route('logout'),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the data needed for the general layout page.
|
||||
*
|
||||
* @param Account $account
|
||||
* @return array
|
||||
*/
|
||||
public static function data(Account $account): array
|
||||
{
|
||||
$vaults = Vault::where('account_id', $account->id)
|
||||
->orderBy('name', 'asc')
|
||||
->get();
|
||||
|
||||
$vaultCollection = collect();
|
||||
foreach ($vaults as $vault) {
|
||||
$vaultCollection->push([
|
||||
'id' => $vault->id,
|
||||
'name' => $vault->name,
|
||||
'description' => $vault->description,
|
||||
'url' => [
|
||||
'show' => route('vault.show', [
|
||||
'vault' => $vault,
|
||||
]),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
return [
|
||||
'vaults' => $vaultCollection,
|
||||
'url' => [
|
||||
'vault' => [
|
||||
'new' => route('vault.new'),
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Vault;
|
||||
|
||||
use Inertia\Inertia;
|
||||
use App\Models\Vault;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use App\Features\Vault\ManageVault\Services\CreateVault;
|
||||
use App\Features\Vault\ManageVault\ViewHelpers\VaultIndexViewHelper;
|
||||
use App\Features\Vault\ManageVault\ViewHelpers\VaultCreateViewHelper;
|
||||
|
||||
class VaultController extends Controller
|
||||
{
|
||||
/**
|
||||
* Show all the vaults of the user.
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return Inertia::render('Vault/Index', [
|
||||
'layoutData' => VaultIndexViewHelper::layoutData(),
|
||||
'data' => VaultIndexViewHelper::data(Auth::user()->account),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the create vault page.
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function new()
|
||||
{
|
||||
return Inertia::render('Vault/Create', [
|
||||
'layoutData' => VaultIndexViewHelper::layoutData(),
|
||||
'data' => VaultCreateViewHelper::data(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the vault.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$data = [
|
||||
'account_id' => Auth::user()->account_id,
|
||||
'author_id' => Auth::user()->id,
|
||||
'type' => Vault::TYPE_PERSONAL,
|
||||
'name' => $request->input('name'),
|
||||
'description' => $request->input('description'),
|
||||
];
|
||||
|
||||
(new CreateVault)->execute($data);
|
||||
|
||||
return response()->json([
|
||||
'data' => route('vault.index'),
|
||||
], 201);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the vault.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $vaultId
|
||||
* @return Response
|
||||
*/
|
||||
public function show(Request $request, int $vaultId)
|
||||
{
|
||||
$vault = Vault::find($vaultId);
|
||||
|
||||
return Inertia::render('Vault/Show', [
|
||||
'layoutData' => VaultIndexViewHelper::layoutData($vault),
|
||||
'data' => VaultCreateViewHelper::data(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Http;
|
||||
|
||||
use App\Http\Middleware\CheckVaultAccess;
|
||||
use Illuminate\Foundation\Http\Kernel as HttpKernel;
|
||||
|
||||
class Kernel extends HttpKernel
|
||||
@@ -64,5 +65,6 @@ class Kernel extends HttpKernel
|
||||
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
|
||||
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
||||
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
|
||||
'vault' => CheckVaultAccess::class,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class CheckVaultAccess
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
$requestedVaultId = $request->route()->parameter('vault');
|
||||
|
||||
$exists = DB::table('user_vault')->where('user_id', Auth::user()->id)
|
||||
->where('vault_id', $requestedVaultId)
|
||||
->count() > 0;
|
||||
|
||||
if ($exists) {
|
||||
return $next($request);
|
||||
} else {
|
||||
abort(401);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -35,7 +35,6 @@ class HandleInertiaRequests extends Middleware
|
||||
{
|
||||
return array_merge(parent::share($request), [
|
||||
'auth' => [
|
||||
'user' => $request->user(),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
+3
-3
@@ -3,17 +3,17 @@
|
||||
namespace App\Models;
|
||||
|
||||
use Laravel\Sanctum\HasApiTokens;
|
||||
use Illuminate\Auth\MustVerifyEmail;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
|
||||
class User extends Authenticatable
|
||||
class User extends Authenticatable implements MustVerifyEmail
|
||||
{
|
||||
use Notifiable, HasFactory, HasApiTokens, MustVerifyEmail;
|
||||
use Notifiable, HasFactory, HasApiTokens;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
|
||||
@@ -17,7 +17,7 @@ class RouteServiceProvider extends ServiceProvider
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public const HOME = '/dashboard';
|
||||
public const HOME = '/vaults';
|
||||
|
||||
/**
|
||||
* The controller namespace for the application.
|
||||
|
||||
@@ -9,12 +9,14 @@
|
||||
"fruitcake/laravel-cors": "^2.0",
|
||||
"guzzlehttp/guzzle": "^7.0.1",
|
||||
"inertiajs/inertia-laravel": "^0.4.3",
|
||||
"itsgoingd/clockwork": "^5.1",
|
||||
"laravel/framework": "^8.65",
|
||||
"laravel/sanctum": "^2.6",
|
||||
"laravel/tinker": "^2.5",
|
||||
"tightenco/ziggy": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"brianium/paratest": "^6.4",
|
||||
"facade/ignition": "^2.5",
|
||||
"fakerphp/faker": "^1.9.1",
|
||||
"laravel/breeze": "^1.4",
|
||||
|
||||
Generated
+165
-1
@@ -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": "0de4f12469e5a4cc90c2736af9f7cb17",
|
||||
"content-hash": "c20f904fa356640d9b6acf9396b6bd4a",
|
||||
"packages": [
|
||||
{
|
||||
"name": "asm89/stack-cors",
|
||||
@@ -1027,6 +1027,75 @@
|
||||
],
|
||||
"time": "2021-10-27T09:37:59+00:00"
|
||||
},
|
||||
{
|
||||
"name": "itsgoingd/clockwork",
|
||||
"version": "v5.1.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/itsgoingd/clockwork.git",
|
||||
"reference": "2daf30fa6dfc5a1ccfdb2142df59243a72c473d8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/itsgoingd/clockwork/zipball/2daf30fa6dfc5a1ccfdb2142df59243a72c473d8",
|
||||
"reference": "2daf30fa6dfc5a1ccfdb2142df59243a72c473d8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-json": "*",
|
||||
"php": ">=5.6",
|
||||
"psr/log": "1.* || ^2.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Clockwork\\Support\\Laravel\\ClockworkServiceProvider"
|
||||
],
|
||||
"aliases": {
|
||||
"Clockwork": "Clockwork\\Support\\Laravel\\Facade"
|
||||
}
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Clockwork\\": "Clockwork/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "itsgoingd",
|
||||
"email": "itsgoingd@luzer.sk",
|
||||
"homepage": "https://twitter.com/itsgoingd"
|
||||
}
|
||||
],
|
||||
"description": "php dev tools in your browser",
|
||||
"homepage": "https://underground.works/clockwork",
|
||||
"keywords": [
|
||||
"Devtools",
|
||||
"debugging",
|
||||
"laravel",
|
||||
"logging",
|
||||
"lumen",
|
||||
"profiling",
|
||||
"slim"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/itsgoingd/clockwork/issues",
|
||||
"source": "https://github.com/itsgoingd/clockwork/tree/v5.1.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/itsgoingd",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2021-11-01T17:38:35+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/framework",
|
||||
"version": "v8.74.0",
|
||||
@@ -5823,6 +5892,101 @@
|
||||
},
|
||||
"time": "2018-12-13T10:34:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "brianium/paratest",
|
||||
"version": "v6.4.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/paratestphp/paratest.git",
|
||||
"reference": "c32a5c4fc2ff339202437d25d19a5f496f880d61"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/paratestphp/paratest/zipball/c32a5c4fc2ff339202437d25d19a5f496f880d61",
|
||||
"reference": "c32a5c4fc2ff339202437d25d19a5f496f880d61",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-dom": "*",
|
||||
"ext-pcre": "*",
|
||||
"ext-reflection": "*",
|
||||
"ext-simplexml": "*",
|
||||
"php": "^7.3 || ^8.0",
|
||||
"phpunit/php-code-coverage": "^9.2.9",
|
||||
"phpunit/php-file-iterator": "^3.0.5",
|
||||
"phpunit/php-timer": "^5.0.3",
|
||||
"phpunit/phpunit": "^9.5.10",
|
||||
"sebastian/environment": "^5.1.3",
|
||||
"symfony/console": "^5.4.0 || ^6.0.0",
|
||||
"symfony/process": "^5.4.0 || ^6.0.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/coding-standard": "^9.0.0",
|
||||
"ekino/phpstan-banned-code": "^0.5.0",
|
||||
"ergebnis/phpstan-rules": "^0.15.3",
|
||||
"ext-posix": "*",
|
||||
"infection/infection": "^0.25.3",
|
||||
"malukenho/mcbumpface": "^1.1.5",
|
||||
"phpstan/phpstan": "^0.12.99",
|
||||
"phpstan/phpstan-deprecation-rules": "^0.12.6",
|
||||
"phpstan/phpstan-phpunit": "^0.12.22",
|
||||
"phpstan/phpstan-strict-rules": "^0.12.11",
|
||||
"squizlabs/php_codesniffer": "^3.6.1",
|
||||
"symfony/filesystem": "^v5.4.0",
|
||||
"thecodingmachine/phpstan-strict-rules": "^v0.12.2",
|
||||
"vimeo/psalm": "^4.13.1"
|
||||
},
|
||||
"bin": [
|
||||
"bin/paratest"
|
||||
],
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"ParaTest\\": [
|
||||
"src/"
|
||||
]
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Brian Scaturro",
|
||||
"email": "scaturrob@gmail.com",
|
||||
"role": "Developer"
|
||||
},
|
||||
{
|
||||
"name": "Filippo Tessarotto",
|
||||
"email": "zoeslam@gmail.com",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "Parallel testing for PHP",
|
||||
"homepage": "https://github.com/paratestphp/paratest",
|
||||
"keywords": [
|
||||
"concurrent",
|
||||
"parallel",
|
||||
"phpunit",
|
||||
"testing"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/paratestphp/paratest/issues",
|
||||
"source": "https://github.com/paratestphp/paratest/tree/v6.4.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/sponsors/Slamdunk",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://paypal.me/filippotessarotto",
|
||||
"type": "paypal"
|
||||
}
|
||||
],
|
||||
"time": "2021-12-02T09:12:23+00:00"
|
||||
},
|
||||
{
|
||||
"name": "composer/ca-bundle",
|
||||
"version": "1.3.1",
|
||||
|
||||
@@ -0,0 +1,416 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|------------------------------------------------------------------------------------------------------------------
|
||||
| Enable Clockwork
|
||||
|------------------------------------------------------------------------------------------------------------------
|
||||
|
|
||||
| Clockwork is enabled by default only when your application is in debug mode. Here you can explicitly enable or
|
||||
| disable Clockwork. When disabled, no data is collected and the api and web ui are inactive.
|
||||
|
|
||||
*/
|
||||
|
||||
'enable' => env('CLOCKWORK_ENABLE', null),
|
||||
|
||||
/*
|
||||
|------------------------------------------------------------------------------------------------------------------
|
||||
| Features
|
||||
|------------------------------------------------------------------------------------------------------------------
|
||||
|
|
||||
| You can enable or disable various Clockwork features here. Some features have additional settings (eg. slow query
|
||||
| threshold for database queries).
|
||||
|
|
||||
*/
|
||||
|
||||
'features' => [
|
||||
|
||||
// Cache usage stats and cache queries including results
|
||||
'cache' => [
|
||||
'enabled' => env('CLOCKWORK_CACHE_ENABLED', true),
|
||||
|
||||
// Collect cache queries
|
||||
'collect_queries' => env('CLOCKWORK_CACHE_QUERIES', true),
|
||||
|
||||
// Collect values from cache queries (high performance impact with a very high number of queries)
|
||||
'collect_values' => env('CLOCKWORK_CACHE_COLLECT_VALUES', false),
|
||||
],
|
||||
|
||||
// Database usage stats and queries
|
||||
'database' => [
|
||||
'enabled' => env('CLOCKWORK_DATABASE_ENABLED', true),
|
||||
|
||||
// Collect database queries (high performance impact with a very high number of queries)
|
||||
'collect_queries' => env('CLOCKWORK_DATABASE_COLLECT_QUERIES', true),
|
||||
|
||||
// Collect details of models updates (high performance impact with a lot of model updates)
|
||||
'collect_models_actions' => env('CLOCKWORK_DATABASE_COLLECT_MODELS_ACTIONS', true),
|
||||
|
||||
// Collect details of retrieved models (very high performance impact with a lot of models retrieved)
|
||||
'collect_models_retrieved' => env('CLOCKWORK_DATABASE_COLLECT_MODELS_RETRIEVED', false),
|
||||
|
||||
// Query execution time threshold in milliseconds after which the query will be marked as slow
|
||||
'slow_threshold' => env('CLOCKWORK_DATABASE_SLOW_THRESHOLD'),
|
||||
|
||||
// Collect only slow database queries
|
||||
'slow_only' => env('CLOCKWORK_DATABASE_SLOW_ONLY', false),
|
||||
|
||||
// Detect and report duplicate queries
|
||||
'detect_duplicate_queries' => env('CLOCKWORK_DATABASE_DETECT_DUPLICATE_QUERIES', false),
|
||||
],
|
||||
|
||||
// Dispatched events
|
||||
'events' => [
|
||||
'enabled' => env('CLOCKWORK_EVENTS_ENABLED', true),
|
||||
|
||||
// Ignored events (framework events are ignored by default)
|
||||
'ignored_events' => [
|
||||
// App\Events\UserRegistered::class,
|
||||
// 'user.registered'
|
||||
],
|
||||
],
|
||||
|
||||
// Laravel log (you can still log directly to Clockwork with laravel log disabled)
|
||||
'log' => [
|
||||
'enabled' => env('CLOCKWORK_LOG_ENABLED', true),
|
||||
],
|
||||
|
||||
// Sent notifications
|
||||
'notifications' => [
|
||||
'enabled' => env('CLOCKWORK_NOTIFICATIONS_ENABLED', true),
|
||||
],
|
||||
|
||||
// Performance metrics
|
||||
'performance' => [
|
||||
// Allow collecting of client metrics. Requires separate clockwork-browser npm package.
|
||||
'client_metrics' => env('CLOCKWORK_PERFORMANCE_CLIENT_METRICS', true),
|
||||
],
|
||||
|
||||
// Dispatched queue jobs
|
||||
'queue' => [
|
||||
'enabled' => env('CLOCKWORK_QUEUE_ENABLED', true),
|
||||
],
|
||||
|
||||
// Redis commands
|
||||
'redis' => [
|
||||
'enabled' => env('CLOCKWORK_REDIS_ENABLED', true),
|
||||
],
|
||||
|
||||
// Routes list
|
||||
'routes' => [
|
||||
'enabled' => env('CLOCKWORK_ROUTES_ENABLED', false),
|
||||
|
||||
// Collect only routes from particular namespaces (only application routes by default)
|
||||
'only_namespaces' => ['App'],
|
||||
],
|
||||
|
||||
// Rendered views
|
||||
'views' => [
|
||||
'enabled' => env('CLOCKWORK_VIEWS_ENABLED', true),
|
||||
|
||||
// Collect views including view data (high performance impact with a high number of views)
|
||||
'collect_data' => env('CLOCKWORK_VIEWS_COLLECT_DATA', false),
|
||||
|
||||
// Use Twig profiler instead of Laravel events for apps using laravel-twigbridge (more precise, but does
|
||||
// not support collecting view data)
|
||||
'use_twig_profiler' => env('CLOCKWORK_VIEWS_USE_TWIG_PROFILER', false),
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
/*
|
||||
|------------------------------------------------------------------------------------------------------------------
|
||||
| Enable web UI
|
||||
|------------------------------------------------------------------------------------------------------------------
|
||||
|
|
||||
| Clockwork comes with a web UI accessible via http://your.app/clockwork. Here you can enable or disable this
|
||||
| feature. You can also set a custom path for the web UI.
|
||||
|
|
||||
*/
|
||||
|
||||
'web' => env('CLOCKWORK_WEB', true),
|
||||
|
||||
/*
|
||||
|------------------------------------------------------------------------------------------------------------------
|
||||
| Enable toolbar
|
||||
|------------------------------------------------------------------------------------------------------------------
|
||||
|
|
||||
| Clockwork can show a toolbar with basic metrics on all responses. Here you can enable or disable this feature.
|
||||
| Requires a separate clockwork-browser npm library.
|
||||
| For installation instructions see https://underground.works/clockwork/#docs-viewing-data
|
||||
|
|
||||
*/
|
||||
|
||||
'toolbar' => env('CLOCKWORK_TOOLBAR', true),
|
||||
|
||||
/*
|
||||
|------------------------------------------------------------------------------------------------------------------
|
||||
| HTTP requests collection
|
||||
|------------------------------------------------------------------------------------------------------------------
|
||||
|
|
||||
| Clockwork collects data about HTTP requests to your app. Here you can choose which requests should be collected.
|
||||
|
|
||||
*/
|
||||
|
||||
'requests' => [
|
||||
// With on-demand mode enabled, Clockwork will only profile requests when the browser extension is open or you
|
||||
// manually pass a "clockwork-profile" cookie or get/post data key.
|
||||
// Optionally you can specify a "secret" that has to be passed as the value to enable profiling.
|
||||
'on_demand' => env('CLOCKWORK_REQUESTS_ON_DEMAND', false),
|
||||
|
||||
// Collect only errors (requests with HTTP 4xx and 5xx responses)
|
||||
'errors_only' => env('CLOCKWORK_REQUESTS_ERRORS_ONLY', false),
|
||||
|
||||
// Response time threshold in milliseconds after which the request will be marked as slow
|
||||
'slow_threshold' => env('CLOCKWORK_REQUESTS_SLOW_THRESHOLD'),
|
||||
|
||||
// Collect only slow requests
|
||||
'slow_only' => env('CLOCKWORK_REQUESTS_SLOW_ONLY', false),
|
||||
|
||||
// Sample the collected requests (e.g. set to 100 to collect only 1 in 100 requests)
|
||||
'sample' => env('CLOCKWORK_REQUESTS_SAMPLE', false),
|
||||
|
||||
// List of URIs that should not be collected
|
||||
'except' => [
|
||||
'/horizon/.*', // Laravel Horizon requests
|
||||
'/telescope/.*', // Laravel Telescope requests
|
||||
'/_debugbar/.*', // Laravel DebugBar requests
|
||||
],
|
||||
|
||||
// List of URIs that should be collected, any other URI will not be collected if not empty
|
||||
'only' => [
|
||||
// '/api/.*'
|
||||
],
|
||||
|
||||
// Don't collect OPTIONS requests, mostly used in the CSRF pre-flight requests and are rarely of interest
|
||||
'except_preflight' => env('CLOCKWORK_REQUESTS_EXCEPT_PREFLIGHT', true),
|
||||
],
|
||||
|
||||
/*
|
||||
|------------------------------------------------------------------------------------------------------------------
|
||||
| Artisan commands collection
|
||||
|------------------------------------------------------------------------------------------------------------------
|
||||
|
|
||||
| Clockwork can collect data about executed artisan commands. Here you can enable and configure which commands
|
||||
| should be collected.
|
||||
|
|
||||
*/
|
||||
|
||||
'artisan' => [
|
||||
// Enable or disable collection of executed Artisan commands
|
||||
'collect' => env('CLOCKWORK_ARTISAN_COLLECT', false),
|
||||
|
||||
// List of commands that should not be collected (built-in commands are not collected by default)
|
||||
'except' => [
|
||||
// 'inspire'
|
||||
],
|
||||
|
||||
// List of commands that should be collected, any other command will not be collected if not empty
|
||||
'only' => [
|
||||
// 'inspire'
|
||||
],
|
||||
|
||||
// Enable or disable collection of command output
|
||||
'collect_output' => env('CLOCKWORK_ARTISAN_COLLECT_OUTPUT', false),
|
||||
|
||||
// Enable or disable collection of built-in Laravel commands
|
||||
'except_laravel_commands' => env('CLOCKWORK_ARTISAN_EXCEPT_LARAVEL_COMMANDS', true),
|
||||
],
|
||||
|
||||
/*
|
||||
|------------------------------------------------------------------------------------------------------------------
|
||||
| Queue jobs collection
|
||||
|------------------------------------------------------------------------------------------------------------------
|
||||
|
|
||||
| Clockwork can collect data about executed queue jobs. Here you can enable and configure which queue jobs should
|
||||
| be collected.
|
||||
|
|
||||
*/
|
||||
|
||||
'queue' => [
|
||||
// Enable or disable collection of executed queue jobs
|
||||
'collect' => env('CLOCKWORK_QUEUE_COLLECT', false),
|
||||
|
||||
// List of queue jobs that should not be collected
|
||||
'except' => [
|
||||
// App\Jobs\ExpensiveJob::class
|
||||
],
|
||||
|
||||
// List of queue jobs that should be collected, any other queue job will not be collected if not empty
|
||||
'only' => [
|
||||
// App\Jobs\BuggyJob::class
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
|------------------------------------------------------------------------------------------------------------------
|
||||
| Tests collection
|
||||
|------------------------------------------------------------------------------------------------------------------
|
||||
|
|
||||
| Clockwork can collect data about executed tests. Here you can enable and configure which tests should be
|
||||
| collected.
|
||||
|
|
||||
*/
|
||||
|
||||
'tests' => [
|
||||
// Enable or disable collection of ran tests
|
||||
'collect' => env('CLOCKWORK_TESTS_COLLECT', false),
|
||||
|
||||
// List of tests that should not be collected
|
||||
'except' => [
|
||||
// Tests\Unit\ExampleTest::class
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
|------------------------------------------------------------------------------------------------------------------
|
||||
| Enable data collection when Clockwork is disabled
|
||||
|------------------------------------------------------------------------------------------------------------------
|
||||
|
|
||||
| You can enable this setting to collect data even when Clockwork is disabled, e.g. for future analysis.
|
||||
|
|
||||
*/
|
||||
|
||||
'collect_data_always' => env('CLOCKWORK_COLLECT_DATA_ALWAYS', false),
|
||||
|
||||
/*
|
||||
|------------------------------------------------------------------------------------------------------------------
|
||||
| Metadata storage
|
||||
|------------------------------------------------------------------------------------------------------------------
|
||||
|
|
||||
| Configure how is the metadata collected by Clockwork stored. Two options are available:
|
||||
| - files - A simple fast storage implementation storing data in one-per-request files.
|
||||
| - sql - Stores requests in a sql database. Supports MySQL, PostgreSQL and SQLite. Requires PDO.
|
||||
|
|
||||
*/
|
||||
|
||||
'storage' => env('CLOCKWORK_STORAGE', 'files'),
|
||||
|
||||
// Path where the Clockwork metadata is stored
|
||||
'storage_files_path' => env('CLOCKWORK_STORAGE_FILES_PATH', storage_path('clockwork')),
|
||||
|
||||
// Compress the metadata files using gzip, trading a little bit of performance for lower disk usage
|
||||
'storage_files_compress' => env('CLOCKWORK_STORAGE_FILES_COMPRESS', false),
|
||||
|
||||
// SQL database to use, can be a name of database configured in database.php or a path to a SQLite file
|
||||
'storage_sql_database' => env('CLOCKWORK_STORAGE_SQL_DATABASE', storage_path('clockwork.sqlite')),
|
||||
|
||||
// SQL table name to use, the table is automatically created and udpated when needed
|
||||
'storage_sql_table' => env('CLOCKWORK_STORAGE_SQL_TABLE', 'clockwork'),
|
||||
|
||||
// Maximum lifetime of collected metadata in minutes, older requests will automatically be deleted, false to disable
|
||||
'storage_expiration' => env('CLOCKWORK_STORAGE_EXPIRATION', 60 * 24 * 7),
|
||||
|
||||
/*
|
||||
|------------------------------------------------------------------------------------------------------------------
|
||||
| Authentication
|
||||
|------------------------------------------------------------------------------------------------------------------
|
||||
|
|
||||
| Clockwork can be configured to require authentication before allowing access to the collected data. This might be
|
||||
| useful when the application is publicly accessible. Setting to true will enable a simple authentication with a
|
||||
| pre-configured password. You can also pass a class name of a custom implementation.
|
||||
|
|
||||
*/
|
||||
|
||||
'authentication' => env('CLOCKWORK_AUTHENTICATION', false),
|
||||
|
||||
// Password for the simple authentication
|
||||
'authentication_password' => env('CLOCKWORK_AUTHENTICATION_PASSWORD', 'VerySecretPassword'),
|
||||
|
||||
/*
|
||||
|------------------------------------------------------------------------------------------------------------------
|
||||
| Stack traces collection
|
||||
|------------------------------------------------------------------------------------------------------------------
|
||||
|
|
||||
| Clockwork can collect stack traces for log messages and certain data like database queries. Here you can set
|
||||
| whether to collect stack traces, limit the number of collected frames and set further configuration. Collecting
|
||||
| long stack traces considerably increases metadata size.
|
||||
|
|
||||
*/
|
||||
|
||||
'stack_traces' => [
|
||||
// Enable or disable collecting of stack traces
|
||||
'enabled' => env('CLOCKWORK_STACK_TRACES_ENABLED', true),
|
||||
|
||||
// Limit the number of frames to be collected
|
||||
'limit' => env('CLOCKWORK_STACK_TRACES_LIMIT', 10),
|
||||
|
||||
// List of vendor names to skip when determining caller, common vendors are automatically added
|
||||
'skip_vendors' => [
|
||||
// 'phpunit'
|
||||
],
|
||||
|
||||
// List of namespaces to skip when determining caller
|
||||
'skip_namespaces' => [
|
||||
// 'Laravel'
|
||||
],
|
||||
|
||||
// List of class names to skip when determining caller
|
||||
'skip_classes' => [
|
||||
// App\CustomLog::class
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
/*
|
||||
|------------------------------------------------------------------------------------------------------------------
|
||||
| Serialization
|
||||
|------------------------------------------------------------------------------------------------------------------
|
||||
|
|
||||
| Clockwork serializes the collected data to json for storage and transfer. Here you can configure certain aspects
|
||||
| of serialization. Serialization has a large effect on the cpu time and memory usage.
|
||||
|
|
||||
*/
|
||||
|
||||
// Maximum depth of serialized multi-level arrays and objects
|
||||
'serialization_depth' => env('CLOCKWORK_SERIALIZATION_DEPTH', 10),
|
||||
|
||||
// A list of classes that will never be serialized (e.g. a common service container class)
|
||||
'serialization_blackbox' => [
|
||||
\Illuminate\Container\Container::class,
|
||||
\Illuminate\Foundation\Application::class,
|
||||
\Laravel\Lumen\Application::class,
|
||||
],
|
||||
|
||||
/*
|
||||
|------------------------------------------------------------------------------------------------------------------
|
||||
| Register helpers
|
||||
|------------------------------------------------------------------------------------------------------------------
|
||||
|
|
||||
| Clockwork comes with a "clock" global helper function. You can use this helper to quickly log something and to
|
||||
| access the Clockwork instance.
|
||||
|
|
||||
*/
|
||||
|
||||
'register_helpers' => env('CLOCKWORK_REGISTER_HELPERS', true),
|
||||
|
||||
/*
|
||||
|------------------------------------------------------------------------------------------------------------------
|
||||
| Send headers for AJAX request
|
||||
|------------------------------------------------------------------------------------------------------------------
|
||||
|
|
||||
| When trying to collect data, the AJAX method can sometimes fail if it is missing required headers. For example, an
|
||||
| API might require a version number using Accept headers to route the HTTP request to the correct codebase.
|
||||
|
|
||||
*/
|
||||
|
||||
'headers' => [
|
||||
// 'Accept' => 'application/vnd.com.whatever.v1+json',
|
||||
],
|
||||
|
||||
/*
|
||||
|------------------------------------------------------------------------------------------------------------------
|
||||
| Server timing
|
||||
|------------------------------------------------------------------------------------------------------------------
|
||||
|
|
||||
| Clockwork supports the W3C Server Timing specification, which allows for collecting a simple performance metrics
|
||||
| in a cross-browser way. E.g. in Chrome, your app, database and timeline event timings will be shown in the Dev
|
||||
| Tools network tab. This setting specifies the max number of timeline events that will be sent. Setting to false
|
||||
| will disable the feature.
|
||||
|
|
||||
*/
|
||||
|
||||
'server_timing' => env('CLOCKWORK_SERVER_TIMING', 10),
|
||||
|
||||
];
|
||||
@@ -24,7 +24,10 @@
|
||||
"lodash": "^4.17.19",
|
||||
"postcss": "^8.2.13",
|
||||
"postcss-import": "^14.0.1",
|
||||
"sass": "^1.15.2",
|
||||
"sass-loader": "^7.1.0",
|
||||
"tailwindcss": "^2.1.2",
|
||||
"tiny-emitter": "^2.1.0",
|
||||
"vue": "^3.0.5",
|
||||
"vue-loader": "^16.1.2"
|
||||
}
|
||||
|
||||
Vendored
-188579
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Vendored
-47332
File diff suppressed because one or more lines are too long
Vendored
+4
@@ -1,3 +1,7 @@
|
||||
@import 'tailwindcss/base';
|
||||
@import 'tailwindcss/components';
|
||||
@import 'tailwindcss/utilities';
|
||||
|
||||
body {
|
||||
color: #343a4b;
|
||||
}
|
||||
|
||||
@@ -1,124 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="min-h-screen bg-gray-100">
|
||||
<nav class="bg-white border-b border-gray-100">
|
||||
<!-- Primary Navigation Menu -->
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between h-16">
|
||||
<div class="flex">
|
||||
<!-- Logo -->
|
||||
<div class="flex-shrink-0 flex items-center">
|
||||
<Link :href="route('dashboard')">
|
||||
<BreezeApplicationLogo class="block h-9 w-auto" />
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<!-- Navigation Links -->
|
||||
<div class="hidden space-x-8 sm:-my-px sm:ml-10 sm:flex">
|
||||
<BreezeNavLink :href="route('dashboard')" :active="route().current('dashboard')">
|
||||
Dashboard
|
||||
</BreezeNavLink>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hidden sm:flex sm:items-center sm:ml-6">
|
||||
<!-- Settings Dropdown -->
|
||||
<div class="ml-3 relative">
|
||||
<BreezeDropdown align="right" width="48">
|
||||
<template #trigger>
|
||||
<span class="inline-flex rounded-md">
|
||||
<button type="button" class="inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md text-gray-500 bg-white hover:text-gray-700 focus:outline-none transition ease-in-out duration-150">
|
||||
{{ $page.props.auth.user.name }}
|
||||
|
||||
<svg class="ml-2 -mr-0.5 h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
</button>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<template #content>
|
||||
<BreezeDropdownLink :href="route('logout')" method="post" as="button">
|
||||
Log Out
|
||||
</BreezeDropdownLink>
|
||||
</template>
|
||||
</BreezeDropdown>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Hamburger -->
|
||||
<div class="-mr-2 flex items-center sm:hidden">
|
||||
<button @click="showingNavigationDropdown = ! showingNavigationDropdown" class="inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:bg-gray-100 focus:text-gray-500 transition duration-150 ease-in-out">
|
||||
<svg class="h-6 w-6" stroke="currentColor" fill="none" viewBox="0 0 24 24">
|
||||
<path :class="{'hidden': showingNavigationDropdown, 'inline-flex': ! showingNavigationDropdown }" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
|
||||
<path :class="{'hidden': ! showingNavigationDropdown, 'inline-flex': showingNavigationDropdown }" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Responsive Navigation Menu -->
|
||||
<div :class="{'block': showingNavigationDropdown, 'hidden': ! showingNavigationDropdown}" class="sm:hidden">
|
||||
<div class="pt-2 pb-3 space-y-1">
|
||||
<BreezeResponsiveNavLink :href="route('dashboard')" :active="route().current('dashboard')">
|
||||
Dashboard
|
||||
</BreezeResponsiveNavLink>
|
||||
</div>
|
||||
|
||||
<!-- Responsive Settings Options -->
|
||||
<div class="pt-4 pb-1 border-t border-gray-200">
|
||||
<div class="px-4">
|
||||
<div class="font-medium text-base text-gray-800">{{ $page.props.auth.user.name }}</div>
|
||||
<div class="font-medium text-sm text-gray-500">{{ $page.props.auth.user.email }}</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-3 space-y-1">
|
||||
<BreezeResponsiveNavLink :href="route('logout')" method="post" as="button">
|
||||
Log Out
|
||||
</BreezeResponsiveNavLink>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- Page Heading -->
|
||||
<header class="bg-white shadow" v-if="$slots.header">
|
||||
<div class="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
|
||||
<slot name="header" />
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Page Content -->
|
||||
<main>
|
||||
<slot />
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import BreezeApplicationLogo from '@/Components/ApplicationLogo.vue'
|
||||
import BreezeDropdown from '@/Components/Dropdown.vue'
|
||||
import BreezeDropdownLink from '@/Components/DropdownLink.vue'
|
||||
import BreezeNavLink from '@/Components/NavLink.vue'
|
||||
import BreezeResponsiveNavLink from '@/Components/ResponsiveNavLink.vue'
|
||||
import { Link } from '@inertiajs/inertia-vue3';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
BreezeApplicationLogo,
|
||||
BreezeDropdown,
|
||||
BreezeDropdownLink,
|
||||
BreezeNavLink,
|
||||
BreezeResponsiveNavLink,
|
||||
Link,
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
showingNavigationDropdown: false,
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
<script>
|
||||
import BreezeButton from '@/Components/Button.vue'
|
||||
import BreezeGuestLayout from '@/Layouts/Guest.vue'
|
||||
import BreezeGuestLayout from '@/Shared/Guest.vue'
|
||||
import BreezeInput from '@/Components/Input.vue'
|
||||
import BreezeLabel from '@/Components/Label.vue'
|
||||
import BreezeValidationErrors from '@/Components/ValidationErrors.vue'
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
<script>
|
||||
import BreezeButton from '@/Components/Button.vue'
|
||||
import BreezeGuestLayout from '@/Layouts/Guest.vue'
|
||||
import BreezeGuestLayout from '@/Shared/Guest.vue'
|
||||
import BreezeInput from '@/Components/Input.vue'
|
||||
import BreezeLabel from '@/Components/Label.vue'
|
||||
import BreezeValidationErrors from '@/Components/ValidationErrors.vue'
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
<script>
|
||||
import BreezeButton from '@/Components/Button.vue'
|
||||
import BreezeCheckbox from '@/Components/Checkbox.vue'
|
||||
import BreezeGuestLayout from '@/Layouts/Guest.vue'
|
||||
import BreezeGuestLayout from '@/Shared/Guest.vue'
|
||||
import BreezeInput from '@/Components/Input.vue'
|
||||
import BreezeLabel from '@/Components/Label.vue'
|
||||
import BreezeValidationErrors from '@/Components/ValidationErrors.vue'
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
|
||||
<script>
|
||||
import BreezeButton from '@/Components/Button.vue'
|
||||
import BreezeGuestLayout from '@/Layouts/Guest.vue'
|
||||
import BreezeGuestLayout from '@/Shared/Guest.vue'
|
||||
import BreezeInput from '@/Components/Input.vue'
|
||||
import BreezeLabel from '@/Components/Label.vue'
|
||||
import BreezeValidationErrors from '@/Components/ValidationErrors.vue'
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
<script>
|
||||
import BreezeButton from '@/Components/Button.vue'
|
||||
import BreezeGuestLayout from '@/Layouts/Guest.vue'
|
||||
import BreezeGuestLayout from '@/Shared/Guest.vue'
|
||||
import BreezeInput from '@/Components/Input.vue'
|
||||
import BreezeLabel from '@/Components/Label.vue'
|
||||
import BreezeValidationErrors from '@/Components/ValidationErrors.vue'
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
<script>
|
||||
import BreezeButton from '@/Components/Button.vue'
|
||||
import BreezeGuestLayout from '@/Layouts/Guest.vue'
|
||||
import BreezeGuestLayout from '@/Shared/Guest.vue'
|
||||
import { Head, Link } from '@inertiajs/inertia-vue3';
|
||||
|
||||
export default {
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
<template>
|
||||
<Head title="Dashboard" />
|
||||
|
||||
<BreezeAuthenticatedLayout>
|
||||
<template #header>
|
||||
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
|
||||
Dashboard
|
||||
</h2>
|
||||
</template>
|
||||
|
||||
<div class="py-12">
|
||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
||||
<div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
|
||||
<div class="p-6 bg-white border-b border-gray-200">
|
||||
You're logged in!
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</BreezeAuthenticatedLayout>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import BreezeAuthenticatedLayout from '@/Layouts/Authenticated.vue'
|
||||
import { Head } from '@inertiajs/inertia-vue3';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
BreezeAuthenticatedLayout,
|
||||
Head,
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,93 @@
|
||||
<style lang="scss" scoped>
|
||||
.section-head {
|
||||
border-top-left-radius: 7px;
|
||||
border-top-right-radius: 7px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<template>
|
||||
<Layout :layoutData="layoutData">
|
||||
<main class="sm:mt-24 relative">
|
||||
<div class="max-w-lg mx-auto px-2 py-2 sm:py-6 sm:px-6 lg:px-8">
|
||||
|
||||
<form @submit.prevent="submit()" class="bg-white border border-gray-200 rounded-lg mb-6">
|
||||
<div class="p-5 border-b border-gray-200 bg-blue-50 section-head">
|
||||
<h1 class="text-center text-2xl mb-1 font-medium">Create a new vault</h1>
|
||||
<p class="text-center">Vaults contain all your contacts data.</p>
|
||||
</div>
|
||||
<div class="p-5 border-b border-gray-200">
|
||||
<text-input v-model="form.name" :autofocus="true" :div-outer-class="'mb-5'" :input-class="'block w-full'" :required="true" :maxlength="255" :label="'Vault name'" />
|
||||
<text-area v-model="form.description" :label="'Description'" :maxlength="255" :textarea-class="'block w-full'" />
|
||||
</div>
|
||||
|
||||
<div class="p-5 flex justify-between">
|
||||
<pretty-link :href="data.url.back" :text="'Cancel'" :classes="'mr-3'" />
|
||||
<pretty-button :href="'data.url.vault.new'" :text="'Create a vault'" :state="loadingState" :icon="'check'" :classes="'save'" />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</main>
|
||||
</Layout>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Layout from '@/Shared/Layout';
|
||||
import PrettyLink from '@/Shared/PrettyLink';
|
||||
import PrettyButton from '@/Shared/PrettyButton';
|
||||
import TextInput from '@/Shared/TextInput';
|
||||
import TextArea from '@/Shared/TextArea';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Layout,
|
||||
PrettyLink,
|
||||
PrettyButton,
|
||||
TextInput,
|
||||
TextArea,
|
||||
},
|
||||
|
||||
props: {
|
||||
layoutData: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
data: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
addMode: false,
|
||||
loadingState: '',
|
||||
form: {
|
||||
name: '',
|
||||
description: '',
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
methods: {
|
||||
showAddModal(type) {
|
||||
if (type == 'lifeEvent') {
|
||||
this.addMode = true;
|
||||
}
|
||||
},
|
||||
|
||||
submit() {
|
||||
this.loadingState = 'loading';
|
||||
|
||||
axios.post(this.data.url.store, this.form)
|
||||
.then(response => {
|
||||
localStorage.success = 'The vault has been created';
|
||||
this.$inertia.visit(response.data.data);
|
||||
})
|
||||
.catch(error => {
|
||||
this.loadingState = null;
|
||||
//this.form.errors = error.response.data;
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,120 @@
|
||||
<style lang="scss" scoped>
|
||||
.vault-list {
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.vault-detail {
|
||||
height: 250px;
|
||||
grid-template-columns: 1fr;
|
||||
grid-template-rows: auto 1fr auto;
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.vault-list {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.icon-sidebar {
|
||||
color: #737e8d;
|
||||
top: -2px;
|
||||
}
|
||||
|
||||
input[type=checkbox] {
|
||||
top: 3px;
|
||||
width: 12px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<template>
|
||||
<Layout title="Dashboard" :layoutData="layoutData">
|
||||
<main class="sm:mt-24 relative">
|
||||
<!-- blank state -->
|
||||
<div v-if="data.vaults.length == 0" class="max-w-md mx-auto px-2 py-2 sm:py-6 sm:px-6 lg:px-8">
|
||||
<div class="bg-white border border-gray-200 rounded-lg mb-6 p-5">
|
||||
<h2 class="text-lg text-center mb-6">Thanks for trying out Monica 👋</h2>
|
||||
<p class="mb-3">Monica is there to help you build better relationships.</p>
|
||||
<p class="mb-3">Contacts in Monica are stored in vaults. You can have as many vaults as you want: one vault for your personal life, one for your professional life, and/or one vault shared with your spouse.</p>
|
||||
<div class="text-center">
|
||||
<pretty-link :href="data.url.vault.new" :text="'Create a vault'" :icon="'plus'" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="data.vaults.length > 0" class="max-w-4xl mx-auto px-2 py-2 sm:py-6 sm:px-6 lg:px-8">
|
||||
<div class="flex items-center justify-between mb-6">
|
||||
<h3>All the vaults in the account</h3>
|
||||
<pretty-link :href="data.url.vault.new" :text="'Create a vault'" :icon="'plus'" />
|
||||
</div>
|
||||
|
||||
<div class="vault-list grid grid-cols-1 sm:grid-cols-3 gap-6">
|
||||
<div v-for="vault in data.vaults" :key="vault.id" class="bg-white border border-gray-200 rounded-lg">
|
||||
<div class="grid vault-detail">
|
||||
<Link :href="vault.url.show" class="border-b border-gray-200 text-lg px-3 py-1 font-medium">
|
||||
{{ vault.name }}
|
||||
</Link>
|
||||
|
||||
<!-- description -->
|
||||
<p v-if="vault.description" class="border-b border-gray-200 p-3">
|
||||
{{ vault.description }}
|
||||
</p>
|
||||
<p v-else class="border-b border-gray-200 p-3">
|
||||
No description yet.
|
||||
</p>
|
||||
|
||||
<!-- actions -->
|
||||
<div class="flex items-center justify-between px-3 py-2">
|
||||
<Link :href="'href'">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-gray-400 hover:text-gray-900 pointer" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||
</svg>
|
||||
</Link>
|
||||
|
||||
<Link :href="vault.url.show">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-gray-400 hover:text-gray-900 pointer" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 7l5 5m0 0l-5 5m5-5H6" />
|
||||
</svg>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</Layout>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Layout from '@/Shared/Layout';
|
||||
import { Link } from '@inertiajs/inertia-vue3';
|
||||
import PrettyLink from '@/Shared/PrettyLink';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Layout,
|
||||
Link,
|
||||
PrettyLink,
|
||||
},
|
||||
|
||||
props: {
|
||||
layoutData: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
data: {
|
||||
type: Array,
|
||||
default: [],
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
addMode: false,
|
||||
};
|
||||
},
|
||||
|
||||
methods: {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,45 @@
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
||||
|
||||
<template>
|
||||
<Layout title="Dashboard" :inside-vault="true" :layoutData="layoutData">
|
||||
<main class="sm:mt-24 relative">
|
||||
d
|
||||
</main>
|
||||
</Layout>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Layout from '@/Shared/Layout';
|
||||
import { Link } from '@inertiajs/inertia-vue3';
|
||||
import PrettyLink from '@/Shared/PrettyLink';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Layout,
|
||||
Link,
|
||||
PrettyLink,
|
||||
},
|
||||
|
||||
props: {
|
||||
layoutData: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
data: {
|
||||
type: Array,
|
||||
default: [],
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
addMode: false,
|
||||
};
|
||||
},
|
||||
|
||||
methods: {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,134 @@
|
||||
<style lang="scss" scoped>
|
||||
main {
|
||||
color: #343a4b;
|
||||
}
|
||||
</style>
|
||||
|
||||
<template>
|
||||
<main>
|
||||
<div class="min-h-full">
|
||||
<div class="fixed w-full z-10 top-0">
|
||||
|
||||
<!-- main nav -->
|
||||
<nav class="bg-gray-50 border-b max-w-8xl mx-auto px-3 sm:px-6 flex items-center justify-between h-10">
|
||||
<div class="border border-gray-200 rounded-lg bg-white items-center sm:flex px-3">
|
||||
<Link :href="layoutData.url.vaults" class="flex-shrink-0">
|
||||
{{ layoutData.user.name }}
|
||||
</Link>
|
||||
<div v-if="layoutData.vault"><span class="mr-1 ml-1">></span> {{ layoutData.vault.name }}</div>
|
||||
</div>
|
||||
|
||||
<!-- search box -->
|
||||
<div v-if="insideVault" class="flew-grow">
|
||||
<input type="text" class="focus:ring-indigo-500 focus:border-indigo-500 block w-full sm:text-sm border-gray-300 rounded-md border border-gray-300 w-64 px-2 py-1" placeholder="Search a contact" />
|
||||
</div>
|
||||
|
||||
<!-- icons -->
|
||||
<div class="flew-grow">
|
||||
<ul>
|
||||
<li class="inline mr-4">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="inline text-gray-600 h-4 w-4 sm:h-5 sm:w-5 cursor-pointer" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"
|
||||
/>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||
</svg>
|
||||
</li>
|
||||
<li class="inline">
|
||||
<svg @click="logout()" xmlns="http://www.w3.org/2000/svg" class="inline text-gray-600 h-4 w-4 sm:h-5 sm:w-5 cursor-pointer" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1"
|
||||
/>
|
||||
</svg>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- sub menu -->
|
||||
<nav v-if="insideVault" class="sm:border-b bg-white">
|
||||
<div class="max-w-8xl mx-auto px-4 sm:px-6">
|
||||
<div class="py-2">
|
||||
<div class="">
|
||||
<div class="hidden md:block">
|
||||
<div class="flex items-baseline justify-between space-x-6">
|
||||
<div>
|
||||
<Link href="" class="bg-blue-700 text-white px-2 py-1 mr-2 rounded-md text-sm font-medium">
|
||||
Dashboard
|
||||
</Link>
|
||||
|
||||
<Link href="" class="hover:bg-gray-700 hover:text-white px-2 py-1 mr-2 rounded-md text-sm font-medium">
|
||||
Reports
|
||||
</Link>
|
||||
|
||||
<Link href="contacts'" class="hover:bg-gray-700 hover:text-white px-2 py-1 mr-2 rounded-md text-sm font-medium">
|
||||
Contacts
|
||||
</Link>
|
||||
|
||||
<Link href="" class="hover:bg-gray-700 hover:text-white px-2 py-1 mr-2 rounded-md text-sm font-medium">
|
||||
Gift center
|
||||
</Link>
|
||||
|
||||
<Link href="" class="hover:bg-gray-700 hover:text-white px-2 py-1 mr-2 rounded-md text-sm font-medium">
|
||||
Loans & debts center
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<Link href="" class="hover:bg-gray-700 hover:text-white px-2 py-1 rounded-md text-sm font-medium">
|
||||
Settings
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
<main class="mt-10 sm:mt-20 relative">
|
||||
<slot></slot>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<toaster />
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Link } from '@inertiajs/inertia-vue3';
|
||||
import Toaster from '@/Shared/Toaster';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Link,
|
||||
Toaster,
|
||||
},
|
||||
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
insideVault: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
layoutData: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
|
||||
created() {
|
||||
if (localStorage.success) {
|
||||
this.flash(localStorage.success, 'success');
|
||||
localStorage.removeItem('success');
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
logout() {
|
||||
window.open(this.user.url.logout);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,82 @@
|
||||
<style lang="scss" scoped>
|
||||
.icon {
|
||||
top: -1px;
|
||||
}
|
||||
|
||||
.save {
|
||||
background-color: #fcf27e;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: .25rem !important;
|
||||
border-color: #191a1b;
|
||||
border-width: 1px !important;
|
||||
box-shadow: 2px 2px 0 #191a1b;
|
||||
display: inline-block !important;
|
||||
position: relative !important;
|
||||
text-decoration: none !important;
|
||||
transition-duration: .15s !important;
|
||||
transition-property: background-color,border-color,color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter !important;
|
||||
transition-timing-function: cubic-bezier(.4,0,.2,1) !important;
|
||||
font-size: .875rem !important;
|
||||
line-height: 1.25rem !important;
|
||||
padding-left: 9px;
|
||||
padding-right: 9px;
|
||||
|
||||
&:hover {
|
||||
box-shadow: none !important;
|
||||
transform: translate(2px,2px);
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
box-shadow: none;
|
||||
transform: translate(0,0);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<template>
|
||||
<button :class="classes" :disabled="state == 'loading'" class="relative text-sm" name="save" type="submit">
|
||||
|
||||
<span v-if="state == 'loading'">Loading…</span>
|
||||
|
||||
<!-- + icon -->
|
||||
<svg v-if="icon === 'plus' && state != 'loading'" xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 inline relative icon" fill="none" viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6" />
|
||||
</svg>
|
||||
|
||||
<!-- check icon -->
|
||||
<svg v-if="icon === 'check' && state != 'loading'" xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 inline relative icon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
|
||||
<span v-if="state != 'loading'">
|
||||
{{ text }}
|
||||
</span>
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
text: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
icon: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
state: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
classes: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,77 @@
|
||||
<style lang="scss" scoped>
|
||||
.icon {
|
||||
top: -1px;
|
||||
}
|
||||
|
||||
a {
|
||||
--tw-shadow: 2px 2px 0 #191a1b !important;
|
||||
border-radius: .25rem !important;
|
||||
border-color: #191a1b;
|
||||
border-width: 1px !important;
|
||||
box-shadow: var(--tw-ring-offset-shadow,0 0 transparent),var(--tw-ring-shadow,0 0 transparent),var(--tw-shadow) !important;
|
||||
display: inline-block !important;
|
||||
position: relative !important;
|
||||
text-decoration: none !important;
|
||||
transition-duration: .15s !important;
|
||||
transition-property: background-color,border-color,color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter !important;
|
||||
transition-timing-function: cubic-bezier(.4,0,.2,1) !important;
|
||||
font-size: .875rem !important;
|
||||
line-height: 1.25rem !important;
|
||||
padding-left: 9px;
|
||||
padding-right: 9px;
|
||||
|
||||
&:hover {
|
||||
box-shadow: none !important;
|
||||
transform: translate(2px,2px);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<template>
|
||||
<Link :class="classes" class="relative text-sm" :href="href">
|
||||
<!-- + icon -->
|
||||
<svg v-if="icon === 'plus' && state != 'loading'" xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 inline relative icon" fill="none" viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6" />
|
||||
</svg>
|
||||
|
||||
<!-- check icon -->
|
||||
<svg v-if="icon === 'check' && state != 'loading'" xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 inline relative icon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
|
||||
<span>
|
||||
{{ text }}
|
||||
</span>
|
||||
</Link>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Link } from '@inertiajs/inertia-vue3';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Link,
|
||||
},
|
||||
|
||||
props: {
|
||||
text: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
icon: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
href: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
classes: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,137 @@
|
||||
<style lang="scss" scoped>
|
||||
.optional-badge {
|
||||
border-radius: 4px;
|
||||
color: #283e59;
|
||||
background-color: #edf2f9;
|
||||
padding: 1px 3px;
|
||||
}
|
||||
|
||||
.length {
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
background-color: #e5eeff;
|
||||
padding: 3px 4px;
|
||||
}
|
||||
|
||||
.counter {
|
||||
padding-right: 64px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<template>
|
||||
<div class="mb3">
|
||||
<label v-if="label" class="block text-sm mb-2" :for="id">
|
||||
{{ label }}
|
||||
<span v-if="!required" class="optional-badge text-xs">
|
||||
optional
|
||||
</span>
|
||||
</label>
|
||||
|
||||
<div class="relative">
|
||||
<textarea @input="$emit('update:modelValue', $event.target.value)"
|
||||
v-model="modelValue"
|
||||
:id="id"
|
||||
:class="localTextAreaClasses"
|
||||
:required="required"
|
||||
:type="type"
|
||||
:rows="rows"
|
||||
:maxlength="maxlength"
|
||||
@keydown.esc="sendEscKey"
|
||||
@focus="showMaxLength"
|
||||
@blur="displayMaxLength = false"
|
||||
></textarea>
|
||||
<span v-if="maxlength && displayMaxLength" class="length absolute text-xs rounded">
|
||||
{{ charactersLeft }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<p v-if="help" class="f7 mb3 lh-title">
|
||||
{{ help }}
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
inheritAttrs: false,
|
||||
|
||||
model: {
|
||||
prop: 'modelValue',
|
||||
event: 'update:modelValue'
|
||||
},
|
||||
|
||||
props: {
|
||||
id: {
|
||||
type: String,
|
||||
default: 'text-area-',
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: 'text',
|
||||
},
|
||||
textareaClass: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
modelValue: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
help: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
required: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
rows: {
|
||||
type: Number,
|
||||
default: 3,
|
||||
},
|
||||
maxlength: {
|
||||
type: Number,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
|
||||
emits: [
|
||||
'esc-key-pressed', 'update:modelValue'
|
||||
],
|
||||
|
||||
data() {
|
||||
return {
|
||||
displayMaxLength: false,
|
||||
};
|
||||
},
|
||||
|
||||
created() {
|
||||
this.localTextAreaClasses = 'border-gray-300 focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50 rounded-md shadow-sm ' + this.textareaClass;
|
||||
},
|
||||
|
||||
computed: {
|
||||
charactersLeft() {
|
||||
var char = 0;
|
||||
if (this.modelValue) {
|
||||
char = this.modelValue.length;
|
||||
}
|
||||
|
||||
return `${this.maxlength - char} / ${this.maxlength}`;
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
sendEscKey() {
|
||||
this.$emit('esc-key-pressed');
|
||||
},
|
||||
|
||||
showMaxLength() {
|
||||
this.displayMaxLength = true;
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,142 @@
|
||||
<style lang="scss" scoped>
|
||||
.optional-badge {
|
||||
border-radius: 4px;
|
||||
color: #283e59;
|
||||
background-color: #edf2f9;
|
||||
padding: 1px 3px;
|
||||
}
|
||||
|
||||
.length {
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
background-color: #e5eeff;
|
||||
padding: 3px 4px;
|
||||
}
|
||||
|
||||
.counter {
|
||||
padding-right: 64px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<template>
|
||||
<div :class="divOuterClass">
|
||||
<label v-if="label" class="block text-sm mb-2" :for="id">
|
||||
{{ label }}
|
||||
<span v-if="!required" class="optional-badge text-xs">
|
||||
optional
|
||||
</span>
|
||||
</label>
|
||||
|
||||
<div class="relative component">
|
||||
<input
|
||||
:class="localInputClasses"
|
||||
:value="modelValue"
|
||||
@input="$emit('update:modelValue', $event.target.value)"
|
||||
ref="input"
|
||||
:type="type"
|
||||
:maxlength="maxlength"
|
||||
:id="id"
|
||||
:required="required"
|
||||
:autofocus="autofocus"
|
||||
@focus="showMaxLength"
|
||||
@blur="displayMaxLength = false"
|
||||
>
|
||||
<span v-if="maxlength && displayMaxLength" class="length absolute text-xs rounded">
|
||||
{{ charactersLeft }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<p v-if="help" class="text-sm mb-3">
|
||||
{{ help }}
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
emits: ['update:modelValue'],
|
||||
|
||||
props: {
|
||||
id: {
|
||||
type: String,
|
||||
default: 'text-input-',
|
||||
},
|
||||
inputClass: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
divOuterClass: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
modelValue: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: 'text',
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
default: 'input',
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
help: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
required: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
autofocus: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
maxlength: {
|
||||
type: Number,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
localInputClasses: '',
|
||||
displayMaxLength: false,
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
charactersLeft() {
|
||||
var char = 0;
|
||||
if (this.modelValue) {
|
||||
char = this.modelValue.length;
|
||||
}
|
||||
|
||||
return `${this.maxlength - char} / ${this.maxlength}`;
|
||||
},
|
||||
},
|
||||
|
||||
created() {
|
||||
this.localInputClasses = 'border-gray-300 focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50 rounded-md shadow-sm ' + this.inputClass;
|
||||
},
|
||||
|
||||
methods: {
|
||||
focus() {
|
||||
this.$refs.input.focus()
|
||||
},
|
||||
|
||||
showMaxLength() {
|
||||
this.displayMaxLength = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,94 @@
|
||||
<style lang="scss" scoped>
|
||||
.flash.notification {
|
||||
z-index: 99999999999;
|
||||
bottom: 30px;
|
||||
right: 0px;
|
||||
transform: translate(100%);
|
||||
transition: all 0.8s ease-in-out;
|
||||
background-color: #fff;
|
||||
border: 1px solid #e7e7e7;
|
||||
border-radius: 6px;
|
||||
box-shadow: 1px 1px 2px rgba(122, 122, 122, 0.17);
|
||||
padding: 10px 20px;
|
||||
|
||||
&.is-visible {
|
||||
transform: translate(0);
|
||||
opacity: 1;
|
||||
right: 30px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<template>
|
||||
<div class="flash notification fixed" :class="[
|
||||
levelClass, isOpen ? isVisibleClass : ''
|
||||
]"
|
||||
>
|
||||
<span class="mr-1">👋</span> {{ messageText }}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
|
||||
props: {
|
||||
level: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
message: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
isOpen: false,
|
||||
isVisibleClass: 'is-visible',
|
||||
closeAfter: 5000, // 10 seconds, you can change that
|
||||
levelClass: null,
|
||||
messageText: null
|
||||
};
|
||||
},
|
||||
|
||||
created() {
|
||||
if (this.level) {
|
||||
this.levelClass = 'is-' + this.level;
|
||||
}
|
||||
|
||||
if (this.message) {
|
||||
this.messageText = this.message;
|
||||
this.show();
|
||||
}
|
||||
|
||||
const self = this;
|
||||
|
||||
this.$on('flash', data => self.show(data));
|
||||
},
|
||||
|
||||
methods: {
|
||||
show(data) {
|
||||
if (data) {
|
||||
this.messageText = data.message;
|
||||
this.levelClass = 'is-' + data.level;
|
||||
}
|
||||
|
||||
this.act(true, 100);
|
||||
this.hide();
|
||||
},
|
||||
|
||||
hide() {
|
||||
this.act(false, this.closeAfter);
|
||||
},
|
||||
|
||||
act(action, timeout) {
|
||||
const self = this;
|
||||
|
||||
setTimeout(() => {
|
||||
self.isOpen = action;
|
||||
}, timeout);
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
Vendored
+1
-1
@@ -12,7 +12,7 @@ createInertiaApp({
|
||||
setup({ el, app, props, plugin }) {
|
||||
return createApp({ render: () => h(app, props) })
|
||||
.use(plugin)
|
||||
.mixin({ methods: { route } })
|
||||
.mixin({ methods: _.assign({ route }, require('./methods').default) })
|
||||
.mount(el);
|
||||
},
|
||||
});
|
||||
|
||||
Vendored
+19
@@ -0,0 +1,19 @@
|
||||
import Emitter from 'tiny-emitter';
|
||||
const emitter = new Emitter();
|
||||
|
||||
export default {
|
||||
/**
|
||||
* Flash a message.
|
||||
*
|
||||
* @param {string} message
|
||||
* @param {string} level
|
||||
*/
|
||||
flash(message, level = 'success') {
|
||||
this.$emitt('flash', { message, level });
|
||||
},
|
||||
|
||||
$on: (...args) => emitter.on(...args),
|
||||
$once: (...args) => emitter.once(...args),
|
||||
$off: (...args) => emitter.off(...args),
|
||||
$emitt: (...args) => emitter.emit(...args),
|
||||
};
|
||||
@@ -1,27 +1,28 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||
|
||||
<title inertia>{{ config('app.name', 'Laravel') }}</title>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||
|
||||
<!-- Fonts -->
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Nunito:wght@400;600;700&display=swap">
|
||||
<title inertia>{{ config('app.name', 'Laravel') }}</title>
|
||||
|
||||
<!-- Styles -->
|
||||
<link rel="stylesheet" href="{{ mix('css/app.css') }}">
|
||||
<!-- Styles -->
|
||||
<link rel="stylesheet" href="{{ mix('css/app.css') }}">
|
||||
|
||||
<!-- Scripts -->
|
||||
@routes
|
||||
<script src="{{ mix('js/app.js') }}" defer></script>
|
||||
</head>
|
||||
<body class="font-sans antialiased">
|
||||
@inertia
|
||||
<!-- Scripts -->
|
||||
@routes
|
||||
<script src="{{ mix('js/app.js') }}" defer></script>
|
||||
</head>
|
||||
|
||||
<body class="font-sans antialiased">
|
||||
@inertia
|
||||
|
||||
@env ('local')
|
||||
<script src="http://localhost:8080/js/bundle.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/gh/underground-works/clockwork-browser@1/dist/toolbar.js"></script>
|
||||
@endenv
|
||||
</body>
|
||||
|
||||
@env ('local')
|
||||
<script src="http://localhost:8080/js/bundle.js"></script>
|
||||
@endenv
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+1
-1
@@ -59,6 +59,6 @@ Route::get('/confirm-password', [ConfirmablePasswordController::class, 'show'])
|
||||
Route::post('/confirm-password', [ConfirmablePasswordController::class, 'store'])
|
||||
->middleware('auth');
|
||||
|
||||
Route::post('/logout', [AuthenticatedSessionController::class, 'destroy'])
|
||||
Route::get('/logout', [AuthenticatedSessionController::class, 'destroy'])
|
||||
->middleware('auth')
|
||||
->name('logout');
|
||||
|
||||
+10
-4
@@ -3,6 +3,7 @@
|
||||
use Inertia\Inertia;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Illuminate\Foundation\Application;
|
||||
use App\Http\Controllers\Vault\VaultController;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
@@ -29,15 +30,20 @@ require __DIR__.'/auth.php';
|
||||
Route::middleware(['auth', 'verified'])->group(function () {
|
||||
Route::get('dashboard', 'Dashboard\\DashboardController@index')->name('dashboard');
|
||||
|
||||
Route::get('home', 'HomeController@index')->name('home');
|
||||
// vaults
|
||||
Route::get('vaults', [VaultController::class, 'index'])->name('vault.index');
|
||||
Route::get('vaults/new', [VaultController::class, 'new'])->name('vault.new');
|
||||
Route::post('vaults', [VaultController::class, 'store'])->name('vault.store');
|
||||
|
||||
Route::middleware(['vault'])->prefix('vaults/{vault}')->group(function () {
|
||||
Route::get('', [VaultController::class, 'show'])->name('vault.show');
|
||||
});
|
||||
|
||||
Route::get('contacts', 'ContactController@index');
|
||||
|
||||
Route::get('settings', 'Settings\\SettingsController@index')->name('settings.index');
|
||||
Route::resource('settings/information', 'Settings\\InformationController');
|
||||
|
||||
// vaults
|
||||
Route::get('vaults/{vault}', 'HomeController@index')->name('vault.show');
|
||||
|
||||
// contacts
|
||||
Route::get('vaults/{vault}/contacts/{contact}', 'HomeController@index')->name('contact.show');
|
||||
});
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
*.json
|
||||
*.json.gz
|
||||
index
|
||||
@@ -58,10 +58,6 @@ class CreateAccountTest extends TestCase
|
||||
'is_account_administrator' => true,
|
||||
]);
|
||||
|
||||
$this->assertDatabaseHas('user_vault', [
|
||||
'user_id' => $user->id,
|
||||
]);
|
||||
|
||||
$this->assertInstanceOf(
|
||||
User::class,
|
||||
$user
|
||||
@@ -74,9 +70,5 @@ class CreateAccountTest extends TestCase
|
||||
Queue::assertPushed(CreateAuditLog::class, function ($job) {
|
||||
return $job->auditLog['action_name'] === 'account_created';
|
||||
});
|
||||
|
||||
Queue::assertPushed(CreateAuditLog::class, function ($job) {
|
||||
return $job->auditLog['action_name'] === 'vault_created';
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Features\Vault\ManageVault\ViewHelpers;
|
||||
|
||||
use Tests\TestCase;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
use App\Features\Vault\ManageVault\ViewHelpers\VaultCreateViewHelper;
|
||||
|
||||
class VaultCreateViewHelperTest extends TestCase
|
||||
{
|
||||
use DatabaseTransactions;
|
||||
|
||||
/** @test */
|
||||
public function it_gets_the_data_needed_for_the_view(): void
|
||||
{
|
||||
$array = VaultCreateViewHelper::data();
|
||||
$this->assertEquals(
|
||||
[
|
||||
'url' => [
|
||||
'store' => env('APP_URL').'/vaults',
|
||||
'back' => env('APP_URL').'/vaults',
|
||||
],
|
||||
],
|
||||
$array
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Features\Vault\ManageVault\ViewHelpers;
|
||||
|
||||
use Tests\TestCase;
|
||||
use App\Models\User;
|
||||
use App\Models\Vault;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
use App\Features\Vault\ManageVault\ViewHelpers\VaultIndexViewHelper;
|
||||
|
||||
class VaultIndexViewHelperTest extends TestCase
|
||||
{
|
||||
use DatabaseTransactions;
|
||||
|
||||
/** @test */
|
||||
public function it_gets_general_layout_information(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
$vault = Vault::factory()->create();
|
||||
|
||||
$this->be($user);
|
||||
|
||||
$array = VaultIndexViewHelper::layoutData($vault);
|
||||
$this->assertEquals(
|
||||
[
|
||||
'user' => [
|
||||
'name' => $user->name,
|
||||
],
|
||||
'vault' => [
|
||||
'id' => $vault->id,
|
||||
'name' => $vault->name,
|
||||
],
|
||||
'url' => [
|
||||
'vaults' => env('APP_URL').'/vaults',
|
||||
'logout' => env('APP_URL').'/logout',
|
||||
],
|
||||
],
|
||||
$array
|
||||
);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_gets_the_data_needed_for_the_view(): void
|
||||
{
|
||||
$vault = Vault::factory()->create();
|
||||
|
||||
$array = VaultIndexViewHelper::data($vault->account);
|
||||
|
||||
$this->assertEquals(2, count($array));
|
||||
|
||||
$this->assertEquals(
|
||||
[
|
||||
0 => [
|
||||
'id' => $vault->id,
|
||||
'name' => $vault->name,
|
||||
'description' => $vault->description,
|
||||
'url' => [
|
||||
'show' => env('APP_URL').'/vaults/'.$vault->id,
|
||||
],
|
||||
],
|
||||
],
|
||||
$array['vaults']->toArray()
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
[
|
||||
'vault' => [
|
||||
'new' => env('APP_URL').'/vaults/new',
|
||||
],
|
||||
],
|
||||
$array['url']
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1829,7 +1829,7 @@ charenc@0.0.2:
|
||||
resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667"
|
||||
integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=
|
||||
|
||||
chokidar@^3.5.2:
|
||||
"chokidar@>=3.0.0 <4.0.0", chokidar@^3.5.2:
|
||||
version "3.5.2"
|
||||
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75"
|
||||
integrity sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==
|
||||
@@ -3178,6 +3178,11 @@ img-loader@^4.0.0:
|
||||
dependencies:
|
||||
loader-utils "^1.1.0"
|
||||
|
||||
immutable@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.0.0.tgz#b86f78de6adef3608395efb269a91462797e2c23"
|
||||
integrity sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw==
|
||||
|
||||
import-cwd@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-3.0.0.tgz#20845547718015126ea9b3676b7592fb8bd4cf92"
|
||||
@@ -3581,7 +3586,7 @@ loader-runner@^4.2.0:
|
||||
resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.2.0.tgz#d7022380d66d14c5fb1d496b89864ebcfd478384"
|
||||
integrity sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==
|
||||
|
||||
loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.4.0:
|
||||
loader-utils@^1.0.1, loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613"
|
||||
integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==
|
||||
@@ -3853,7 +3858,7 @@ negotiator@0.6.2:
|
||||
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb"
|
||||
integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==
|
||||
|
||||
neo-async@^2.6.2:
|
||||
neo-async@^2.5.0, neo-async@^2.6.2:
|
||||
version "2.6.2"
|
||||
resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f"
|
||||
integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==
|
||||
@@ -4214,6 +4219,11 @@ pify@^2.3.0:
|
||||
resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
|
||||
integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw=
|
||||
|
||||
pify@^4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231"
|
||||
integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==
|
||||
|
||||
pkg-dir@^4.1.0, pkg-dir@^4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3"
|
||||
@@ -4872,6 +4882,25 @@ safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1,
|
||||
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
|
||||
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
|
||||
|
||||
sass-loader@^7.1.0:
|
||||
version "7.3.1"
|
||||
resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-7.3.1.tgz#a5bf68a04bcea1c13ff842d747150f7ab7d0d23f"
|
||||
integrity sha512-tuU7+zm0pTCynKYHpdqaPpe+MMTQ76I9TPZ7i4/5dZsigE350shQWe5EZNl5dBidM49TPET75tNqRbcsUZWeNA==
|
||||
dependencies:
|
||||
clone-deep "^4.0.1"
|
||||
loader-utils "^1.0.1"
|
||||
neo-async "^2.5.0"
|
||||
pify "^4.0.1"
|
||||
semver "^6.3.0"
|
||||
|
||||
sass@^1.15.2:
|
||||
version "1.44.0"
|
||||
resolved "https://registry.yarnpkg.com/sass/-/sass-1.44.0.tgz#619aa0a2275c097f9af5e6b8fe8a95e3056430fb"
|
||||
integrity sha512-0hLREbHFXGQqls/K8X+koeP+ogFRPF4ZqetVB19b7Cst9Er8cOR0rc6RU7MaI4W1JmUShd1BPgPoeqmmgMMYFw==
|
||||
dependencies:
|
||||
chokidar ">=3.0.0 <4.0.0"
|
||||
immutable "^4.0.0"
|
||||
|
||||
schema-utils@^2.6.5:
|
||||
version "2.7.1"
|
||||
resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.7.1.tgz#1ca4f32d1b24c590c203b8e7a50bf0ea4cd394d7"
|
||||
@@ -5336,6 +5365,11 @@ timsort@^0.3.0:
|
||||
resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4"
|
||||
integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=
|
||||
|
||||
tiny-emitter@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-2.1.0.tgz#1d1a56edfc51c43e863cbb5382a72330e3555423"
|
||||
integrity sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==
|
||||
|
||||
tmp@^0.2.1:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14"
|
||||
|
||||
Reference in New Issue
Block a user