Compare commits

..

3 Commits

23 changed files with 610 additions and 14 deletions

View File

@ -10,7 +10,7 @@ A little project because I haven't made anything new in a while, I would like to
* [x] Bookmark permalink * [x] Bookmark permalink
* [x] Bookmark index * [x] Bookmark index
* [x] Bookmark pagination * [x] Bookmark pagination
* [ ] Editing * [x] Editing
* [ ] Tag cloud * [ ] Tag cloud
* [ ] Tag permalink * [ ] Tag permalink
* [ ] Multi-user support * [ ] Multi-user support

View File

@ -38,11 +38,11 @@ class BookmarkController extends Controller
/** /**
* Display the specified resource. * Display the specified resource.
*/ */
public function show(string $id) public function show(Bookmark $bookmark)
{ {
return view( return view(
'bookmarks.show', [ 'bookmarks.show', [
'bookmark' => $bookmark = Bookmark::findOrFail($id), 'bookmark' => $bookmark,
] ]
); );
} }
@ -50,17 +50,31 @@ class BookmarkController extends Controller
/** /**
* Show the form for editing the specified resource. * Show the form for editing the specified resource.
*/ */
public function edit(string $id) public function edit(Bookmark $bookmark)
{ {
// return view(
'bookmarks.edit', [
'edit' => true,
'bookmark' => $bookmark,
]
);
} }
/** /**
* Update the specified resource in storage. * Update the specified resource in storage.
*/ */
public function update(Request $request, string $id) public function update(Request $request, Bookmark $bookmark)
{ {
// $bookmark->title = $request->post('title');
$bookmark->description = $request->post('description', '');
$bookmark->href = $request->post('href');
$bookmark->save();
return redirect()->action(
[self::class, "show"], [
"bookmark" => $bookmark,
]
);
} }
/** /**

View File

@ -14,6 +14,11 @@ class AppServiceProvider extends ServiceProvider
{ {
Paginator::defaultView('pagination.default'); Paginator::defaultView('pagination.default');
Paginator::defaultSimpleView('pagination.simple-default'); Paginator::defaultSimpleView('pagination.simple-default');
if ($this->app->environment('local')) {
$this->app->register(\Laravel\Telescope\TelescopeServiceProvider::class);
$this->app->register(TelescopeServiceProvider::class);
}
} }
/** /**

View File

@ -0,0 +1,64 @@
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Gate;
use Laravel\Telescope\IncomingEntry;
use Laravel\Telescope\Telescope;
use Laravel\Telescope\TelescopeApplicationServiceProvider;
class TelescopeServiceProvider extends TelescopeApplicationServiceProvider
{
/**
* Register any application services.
*/
public function register(): void
{
// Telescope::night();
$this->hideSensitiveRequestDetails();
$isLocal = $this->app->environment('local');
Telescope::filter(function (IncomingEntry $entry) use ($isLocal) {
return $isLocal ||
$entry->isReportableException() ||
$entry->isFailedRequest() ||
$entry->isFailedJob() ||
$entry->isScheduledTask() ||
$entry->hasMonitoredTag();
});
}
/**
* Prevent sensitive request details from being logged by Telescope.
*/
protected function hideSensitiveRequestDetails(): void
{
if ($this->app->environment('local')) {
return;
}
Telescope::hideRequestParameters(['_token']);
Telescope::hideRequestHeaders([
'cookie',
'x-csrf-token',
'x-xsrf-token',
]);
}
/**
* Register the Telescope gate.
*
* This gate determines who can access Telescope in non-local environments.
*/
protected function gate(): void
{
Gate::define('viewTelescope', function ($user) {
return in_array($user->email, [
//
]);
});
}
}

View File

@ -3,5 +3,6 @@
return [ return [
App\Providers\AppServiceProvider::class, App\Providers\AppServiceProvider::class,
App\Providers\RouteServiceProvider::class, App\Providers\RouteServiceProvider::class,
App\Providers\TelescopeServiceProvider::class,
App\Providers\ViewServiceProvider::class, App\Providers\ViewServiceProvider::class,
]; ];

View File

@ -16,6 +16,7 @@
"fakerphp/faker": "^1.23", "fakerphp/faker": "^1.23",
"laravel/pint": "^1.13", "laravel/pint": "^1.13",
"laravel/sail": "^1.26", "laravel/sail": "^1.26",
"laravel/telescope": "^5.0",
"mockery/mockery": "^1.6", "mockery/mockery": "^1.6",
"nunomaduro/collision": "^8.0", "nunomaduro/collision": "^8.0",
"phpunit/phpunit": "^11.0.1", "phpunit/phpunit": "^11.0.1",
@ -52,7 +53,9 @@
}, },
"extra": { "extra": {
"laravel": { "laravel": {
"dont-discover": [] "dont-discover": [
"laravel/telescope"
]
} }
}, },
"config": { "config": {

71
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "2077c394f6aa7d63f49d97c8c4f2764c", "content-hash": "e9505cd866332b68cbe9d5c4e371723a",
"packages": [ "packages": [
{ {
"name": "brick/math", "name": "brick/math",
@ -5991,6 +5991,75 @@
}, },
"time": "2024-05-16T21:39:11+00:00" "time": "2024-05-16T21:39:11+00:00"
}, },
{
"name": "laravel/telescope",
"version": "v5.0.5",
"source": {
"type": "git",
"url": "https://github.com/laravel/telescope.git",
"reference": "ae5c28ca1e40a7a66bfc9b2557e7e1d84d95363c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/telescope/zipball/ae5c28ca1e40a7a66bfc9b2557e7e1d84d95363c",
"reference": "ae5c28ca1e40a7a66bfc9b2557e7e1d84d95363c",
"shasum": ""
},
"require": {
"ext-json": "*",
"laravel/framework": "^8.37|^9.0|^10.0|^11.0",
"php": "^8.0",
"symfony/console": "^5.3|^6.0|^7.0",
"symfony/var-dumper": "^5.0|^6.0|^7.0"
},
"require-dev": {
"ext-gd": "*",
"guzzlehttp/guzzle": "^6.0|^7.0",
"laravel/octane": "^1.4|^2.0|dev-develop",
"orchestra/testbench": "^6.40|^7.37|^8.17|^9.0",
"phpstan/phpstan": "^1.10",
"phpunit/phpunit": "^9.0|^10.5"
},
"type": "library",
"extra": {
"laravel": {
"providers": [
"Laravel\\Telescope\\TelescopeServiceProvider"
]
}
},
"autoload": {
"psr-4": {
"Laravel\\Telescope\\": "src/",
"Laravel\\Telescope\\Database\\Factories\\": "database/factories/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Taylor Otwell",
"email": "taylor@laravel.com"
},
{
"name": "Mohamed Said",
"email": "mohamed@laravel.com"
}
],
"description": "An elegant debug assistant for the Laravel framework.",
"keywords": [
"debugging",
"laravel",
"monitoring"
],
"support": {
"issues": "https://github.com/laravel/telescope/issues",
"source": "https://github.com/laravel/telescope/tree/v5.0.5"
},
"time": "2024-05-09T17:09:01+00:00"
},
{ {
"name": "mockery/mockery", "name": "mockery/mockery",
"version": "1.6.12", "version": "1.6.12",

205
config/telescope.php Normal file
View File

@ -0,0 +1,205 @@
<?php
use Laravel\Telescope\Http\Middleware\Authorize;
use Laravel\Telescope\Watchers;
return [
/*
|--------------------------------------------------------------------------
| Telescope Master Switch
|--------------------------------------------------------------------------
|
| This option may be used to disable all Telescope watchers regardless
| of their individual configuration, which simply provides a single
| and convenient way to enable or disable Telescope data storage.
|
*/
'enabled' => env('TELESCOPE_ENABLED', true),
/*
|--------------------------------------------------------------------------
| Telescope Domain
|--------------------------------------------------------------------------
|
| This is the subdomain where Telescope will be accessible from. If the
| setting is null, Telescope will reside under the same domain as the
| application. Otherwise, this value will be used as the subdomain.
|
*/
'domain' => env('TELESCOPE_DOMAIN'),
/*
|--------------------------------------------------------------------------
| Telescope Path
|--------------------------------------------------------------------------
|
| This is the URI path where Telescope will be accessible from. Feel free
| to change this path to anything you like. Note that the URI will not
| affect the paths of its internal API that aren't exposed to users.
|
*/
'path' => env('TELESCOPE_PATH', 'telescope'),
/*
|--------------------------------------------------------------------------
| Telescope Storage Driver
|--------------------------------------------------------------------------
|
| This configuration options determines the storage driver that will
| be used to store Telescope's data. In addition, you may set any
| custom options as needed by the particular driver you choose.
|
*/
'driver' => env('TELESCOPE_DRIVER', 'database'),
'storage' => [
'database' => [
'connection' => env('DB_CONNECTION', 'mysql'),
'chunk' => 1000,
],
],
/*
|--------------------------------------------------------------------------
| Telescope Queue
|--------------------------------------------------------------------------
|
| This configuration options determines the queue connection and queue
| which will be used to process ProcessPendingUpdate jobs. This can
| be changed if you would prefer to use a non-default connection.
|
*/
'queue' => [
'connection' => env('TELESCOPE_QUEUE_CONNECTION', null),
'queue' => env('TELESCOPE_QUEUE', null),
],
/*
|--------------------------------------------------------------------------
| Telescope Route Middleware
|--------------------------------------------------------------------------
|
| These middleware will be assigned to every Telescope route, giving you
| the chance to add your own middleware to this list or change any of
| the existing middleware. Or, you can simply stick with this list.
|
*/
'middleware' => [
'web',
Authorize::class,
],
/*
|--------------------------------------------------------------------------
| Allowed / Ignored Paths & Commands
|--------------------------------------------------------------------------
|
| The following array lists the URI paths and Artisan commands that will
| not be watched by Telescope. In addition to this list, some Laravel
| commands, like migrations and queue commands, are always ignored.
|
*/
'only_paths' => [
// 'api/*'
],
'ignore_paths' => [
'livewire*',
'nova-api*',
'pulse*',
],
'ignore_commands' => [
//
],
/*
|--------------------------------------------------------------------------
| Telescope Watchers
|--------------------------------------------------------------------------
|
| The following array lists the "watchers" that will be registered with
| Telescope. The watchers gather the application's profile data when
| a request or task is executed. Feel free to customize this list.
|
*/
'watchers' => [
Watchers\BatchWatcher::class => env('TELESCOPE_BATCH_WATCHER', true),
Watchers\CacheWatcher::class => [
'enabled' => env('TELESCOPE_CACHE_WATCHER', true),
'hidden' => [],
],
Watchers\ClientRequestWatcher::class => env('TELESCOPE_CLIENT_REQUEST_WATCHER', true),
Watchers\CommandWatcher::class => [
'enabled' => env('TELESCOPE_COMMAND_WATCHER', true),
'ignore' => [],
],
Watchers\DumpWatcher::class => [
'enabled' => env('TELESCOPE_DUMP_WATCHER', true),
'always' => env('TELESCOPE_DUMP_WATCHER_ALWAYS', false),
],
Watchers\EventWatcher::class => [
'enabled' => env('TELESCOPE_EVENT_WATCHER', true),
'ignore' => [],
],
Watchers\ExceptionWatcher::class => env('TELESCOPE_EXCEPTION_WATCHER', true),
Watchers\GateWatcher::class => [
'enabled' => env('TELESCOPE_GATE_WATCHER', true),
'ignore_abilities' => [],
'ignore_packages' => true,
'ignore_paths' => [],
],
Watchers\JobWatcher::class => env('TELESCOPE_JOB_WATCHER', true),
Watchers\LogWatcher::class => [
'enabled' => env('TELESCOPE_LOG_WATCHER', true),
'level' => 'error',
],
Watchers\MailWatcher::class => env('TELESCOPE_MAIL_WATCHER', true),
Watchers\ModelWatcher::class => [
'enabled' => env('TELESCOPE_MODEL_WATCHER', true),
'events' => ['eloquent.*'],
'hydrations' => true,
],
Watchers\NotificationWatcher::class => env('TELESCOPE_NOTIFICATION_WATCHER', true),
Watchers\QueryWatcher::class => [
'enabled' => env('TELESCOPE_QUERY_WATCHER', true),
'ignore_packages' => true,
'ignore_paths' => [],
'slow' => 100,
],
Watchers\RedisWatcher::class => env('TELESCOPE_REDIS_WATCHER', true),
Watchers\RequestWatcher::class => [
'enabled' => env('TELESCOPE_REQUEST_WATCHER', true),
'size_limit' => env('TELESCOPE_RESPONSE_SIZE_LIMIT', 64),
'ignore_http_methods' => [],
'ignore_status_codes' => [],
],
Watchers\ScheduleWatcher::class => env('TELESCOPE_SCHEDULE_WATCHER', true),
Watchers\ViewWatcher::class => env('TELESCOPE_VIEW_WATCHER', true),
],
];

View File

@ -0,0 +1,70 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Get the migration connection name.
*/
public function getConnection(): ?string
{
return config('telescope.storage.database.connection');
}
/**
* Run the migrations.
*/
public function up(): void
{
$schema = Schema::connection($this->getConnection());
$schema->create('telescope_entries', function (Blueprint $table) {
$table->bigIncrements('sequence');
$table->uuid('uuid');
$table->uuid('batch_id');
$table->string('family_hash')->nullable();
$table->boolean('should_display_on_index')->default(true);
$table->string('type', 20);
$table->longText('content');
$table->dateTime('created_at')->nullable();
$table->unique('uuid');
$table->index('batch_id');
$table->index('family_hash');
$table->index('created_at');
$table->index(['type', 'should_display_on_index']);
});
$schema->create('telescope_entries_tags', function (Blueprint $table) {
$table->uuid('entry_uuid');
$table->string('tag');
$table->primary(['entry_uuid', 'tag']);
$table->index('tag');
$table->foreign('entry_uuid')
->references('uuid')
->on('telescope_entries')
->onDelete('cascade');
});
$schema->create('telescope_monitoring', function (Blueprint $table) {
$table->string('tag')->primary();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
$schema = Schema::connection($this->getConnection());
$schema->dropIfExists('telescope_entries_tags');
$schema->dropIfExists('telescope_entries');
$schema->dropIfExists('telescope_monitoring');
}
};

View File

@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
$schema = Schema::connection($this->getConnection());
$schema->create(
'cache', function (Blueprint $table) {
$table->string('key');
$table->string('value');
$table->bigInteger('expiration');
}
);
}
/**
* Reverse the migrations.
*/
public function down(): void
{
$schema = Schema::connection($this->getConnection());
$schema->dropIfExists('cache');
}
};

8
public/vendor/telescope/app-dark.css vendored Normal file

File diff suppressed because one or more lines are too long

7
public/vendor/telescope/app.css vendored Normal file

File diff suppressed because one or more lines are too long

2
public/vendor/telescope/app.js vendored Normal file

File diff suppressed because one or more lines are too long

BIN
public/vendor/telescope/favicon.ico vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@ -0,0 +1,5 @@
{
"/app.js": "/app.js?id=7049e92a398e816f8cd53a915eaea592",
"/app-dark.css": "/app-dark.css?id=1ea407db56c5163ae29311f1f38eb7b9",
"/app.css": "/app.css?id=de4c978567bfd90b38d186937dee5ccf"
}

View File

@ -16,6 +16,7 @@ body {
@import 'components/bookmark'; @import 'components/bookmark';
@import 'components/pagination'; @import 'components/pagination';
@import 'components/forms';
a { a {
&, &,

View File

@ -6,7 +6,8 @@
"title title" "title title"
"description description" "description description"
"href href" "href href"
"date tags"; "date tags"
"actions actions";
margin-bottom: 1em; margin-bottom: 1em;
padding: 0; padding: 0;
@ -64,6 +65,10 @@
} }
} }
&-actions {
grid-area: actions;
}
&-date { &-date {
grid-area: date; grid-area: date;
} }

View File

@ -0,0 +1,58 @@
.form {
&-row {
display: flex;
align-items: center;
padding: 1ex;
column-gap: 1ex;
row-gap: 0;
&-stacked {
align-items: stretch;
flex-direction: column;
column-gap: 0;
row-gap: 1ex;
}
&.align-right {
justify-content: flex-end;
}
}
&-label {
flex: 0;
font-weight: bold;
}
&-input,
&-textarea {
padding: 1ex;
flex: 1;
border: 1px solid #888;
border-radius: 5px;
min-height: 2em;
}
&-textarea {
min-height: 10em;
}
&-button {
border: 1px solid #888;
padding: 1ex 2ex;
border-radius: 5px;
text-decoration: none;
font-size: 1em;
background-color: #fff;
color: #000 !important;
cursor: default;
&:visited,
&:hover,
&:active {
color: #000 !important;
}
}
}

View File

@ -0,0 +1,34 @@
@extends('layouts.app')
@section('content')
<p>
<a href="{{ action('BookmarkController@index') }}">&larr; Back</a>
</p>
<form method="post" class="form" action="{{ action('BookmarkController@update', ['bookmark' => $bookmark]) }}">
@csrf
<div class="bookmark">
<div class="bookmark-title form-row"g>
<label class="form-label" for="title">
Title:
</label>
<input type="text" class="form-input" name="title" value="{{ $bookmark->title }}">
</div>
<div class="bookmark-href form-row form-row-stacked">
<label class="form-label" for="href">
URL:
</label>
<input type="text" class="form-input" name="href" value="{{ $bookmark->href }}">
</div>
<div class="bookmark-description form-row form-row-stacked">
<label class="form-label" for="description">
Description:
</label>
<textarea name="description" class="form-textarea">{{ $bookmark->description }}</textarea>
</div>
<div class="form-row align-right bookmark-actions">
<a class="form-button" href="{{ action('BookmarkController@show', ['bookmark' => $bookmark]) }}">Cancel</a>
<input type="submit" class="form-button" value="Save">
</div>
</div>
</form>
@endsection

View File

@ -5,4 +5,7 @@
<a href="{{ action('BookmarkController@index') }}">&larr; Back</a> <a href="{{ action('BookmarkController@index') }}">&larr; Back</a>
</p> </p>
<x-bookmark :bookmark="$bookmark" /> <x-bookmark :bookmark="$bookmark" />
<p>
<a href="{{ action('BookmarkController@edit', ['bookmark' => $bookmark]) }}">edit</a>
</p>
@endsection @endsection

View File

@ -2,7 +2,8 @@
<p class="bookmark-title"> <p class="bookmark-title">
{{ $bookmark->title }} {{ $bookmark->title }}
@action('index') @action('index')
<a href="/bookmarks/{{ $bookmark->id }}">#</a> <a href="{{ action('BookmarkController@show', $bookmark) }}">#</a>
<a href="{{ action('BookmarkController@edit', $bookmark) }}">e</a>
@endaction @endaction
</p> </p>
<p class="bookmark-href"><a href="{{ $bookmark->href }}">{{ $bookmark->href }}</a></p> <p class="bookmark-href"><a href="{{ $bookmark->href }}">{{ $bookmark->href }}</a></p>

View File

@ -2,7 +2,12 @@
use Illuminate\Foundation\Inspiring; use Illuminate\Foundation\Inspiring;
use Illuminate\Support\Facades\Artisan; use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Schedule;
Artisan::command('inspire', function () { Artisan::command(
$this->comment(Inspiring::quote()); 'inspire', function () {
})->purpose('Display an inspiring quote')->hourly(); $this->comment(Inspiring::quote());
}
)->purpose('Display an inspiring quote')->hourly();
Schedule::command('telescope:prune')->daily();

View File

@ -8,4 +8,6 @@ Route::get(
return redirect()->action([BookmarkController::class, 'index']); return redirect()->action([BookmarkController::class, 'index']);
} }
); );
Route::resource('bookmarks', BookmarkController::class); Route::resource('bookmarks', BookmarkController::class);
Route::post('/bookmarks/{bookmark}', [BookmarkController::class, 'update']);