Skip to content

Commit

Permalink
Show latest news in dashboard
Browse files Browse the repository at this point in the history
  • Loading branch information
jbrooksuk committed Feb 24, 2025
1 parent 6280995 commit 8743d2e
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 0 deletions.
2 changes: 2 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@
},
"require": {
"php": "^8.2",
"ext-simplexml": "*",
"doctrine/dbal": "^3.6",
"filament/filament": "^3.2.57",
"filament/spatie-laravel-settings-plugin": "^3.2",
"guzzlehttp/guzzle": "^7.8",
"illuminate/cache": "^11.23.0",
"illuminate/console": "^11.23.0",
"illuminate/database": "^11.23.0",
"illuminate/events": "^11.23.0",
Expand Down
5 changes: 5 additions & 0 deletions config/cachet.php
Original file line number Diff line number Diff line change
Expand Up @@ -160,4 +160,9 @@
*/
'demo_mode' => env('CACHET_DEMO_MODE', false),

'feed' => [
'uri' => env('CACHET_FEED_URI', 'https://blog.cachethq.io/rss'),
'cache' => env('CACHET_FEED_CACHE', 3600),
],

];
5 changes: 5 additions & 0 deletions resources/lang/en/cachet.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@
'keep_up_to_date' => 'Keep up to date with the latest news and releases by following the *Cachet blog*.',
'work_in_progress_text' => 'Cachet is under active development. Things are still subject to change.',
],
'feed' => [
'section_heading' => 'Latest Blog Posts',
'empty' => 'No blog posts were found. Check *the blog* for further information.',
'posted_at' => 'Posted :date'
],
'powered_by' => 'Powered by',
'open_source_status_page' => 'The open-source status page.',
'all_times_shown_in' => 'All times are shown in *:timezone*.',
Expand Down
29 changes: 29 additions & 0 deletions resources/views/filament/widgets/feed.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<x-filament::widget>
<x-filament::section :heading="__('cachet::cachet.feed.section_heading')">
<div class="relative">
<ul role="list" class="gap-4 flex flex-col">
@forelse ($items as $post)
<li>
<a class="flex items-center justify-between text-sm" href="{{ $post['link'] }}" target="_blank">
<div class="overflow-hidden text-sm leading-6 text-gray-500 dark:text-gray-400">
<h3 class="text-base font-medium text-gray-950 dark:text-white">{{ $post['title'] }}</h3>
<time class="text-muted text-xs" datetime="{{ $post['date']->toW3cString() }}" title="{{ $post['date']->toDateTimeString() }}">
{{ __('cachet::cachet.feed.posted_at', ['date' => $post['date']->diffForHumans()]) }}
</time>
<p class="break-words truncate">{{ $post['description'] }}</p>
</div>
<div class="">
<x-heroicon-o-chevron-right class="w-5 h-5 text-gray-400" />
</div>
</a>
</li>
@empty
<li class="text-center filament-tables-text-column">
<p class="text-sm text-gray-500">{!! $noItems !!}</p>
</li>
@endforelse
</ul>
</div>
</x-filament::section>
</x-filament::widget>

92 changes: 92 additions & 0 deletions src/Filament/Widgets/Feed.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<?php

namespace Cachet\Filament\Widgets;

use Filament\Widgets\Concerns\CanPoll;
use Filament\Widgets\Widget;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Str;
use Illuminate\Support\Uri;
use Throwable;

class Feed extends Widget
{
use CanPoll;

protected int|string|array $columnSpan = 'full';

protected static string $view = 'cachet::filament.widgets.feed';

protected static ?int $sort = 10;

protected function getViewData(): array
{
return [
'items' => $this->getFeed(),
'noItems' => Blade::render($this->getEmptyBlock()),
];
}

/**
* Get the generated empty block text.
*/
public function getEmptyBlock(): string
{
return preg_replace(
'/\*(.*?)\*/',
'<x-filament::link href="'.config('cachet.feed.uri').'" target="_blank" rel="nofollow noopener">$1</x-filament::link>',
__('cachet::cachet.feed.empty')
);
}

/**
* Get the feed from the cache or fetch it fresh.
*/
protected function getFeed(): array
{
return Cache::flexible('cachet-feed', [

Check failure on line 49 in src/Filament/Widgets/Feed.php

View workflow job for this annotation

GitHub Actions / Static Analysis - P8.4 - L11.x - prefer-lowest

Parameter #2 $ttl of static method Illuminate\Support\Facades\Cache::flexible() expects void, array<int, int> given.

Check failure on line 49 in src/Filament/Widgets/Feed.php

View workflow job for this annotation

GitHub Actions / Static Analysis - P8.3 - L11.x - prefer-lowest

Parameter #2 $ttl of static method Illuminate\Support\Facades\Cache::flexible() expects void, array<int, int> given.

Check failure on line 49 in src/Filament/Widgets/Feed.php

View workflow job for this annotation

GitHub Actions / Static Analysis - P8.2 - L11.x - prefer-lowest

Parameter #2 $ttl of static method Illuminate\Support\Facades\Cache::flexible() expects void, array<int, int> given.
60 * 15,
60 * 60,
], fn () => $this->fetchFeed(
config('cachet.feed.uri')
));
}

/**
* Fetch the data from the given RSS feed.
*/
protected function fetchFeed(string $uri, int $maxPosts = 5): array
{
try {
$xml = simplexml_load_string(file_get_contents($uri));

$posts = [];

$feedItems = $xml->channel->item ?? $xml->entry ?? [];
$feedIndex = 0;

foreach ($feedItems as $item) {
if ($feedIndex >= $maxPosts) {
break;
}

$posts[] = [
'title' => (string)($item->title ?? ''),
'link' => Uri::of((string)($item->link ?? ''))->withQuery([

Check failure on line 77 in src/Filament/Widgets/Feed.php

View workflow job for this annotation

GitHub Actions / Static Analysis - P8.4 - L11.x - prefer-lowest

Call to static method of() on an unknown class Illuminate\Support\Uri.

Check failure on line 77 in src/Filament/Widgets/Feed.php

View workflow job for this annotation

GitHub Actions / Static Analysis - P8.3 - L11.x - prefer-lowest

Call to static method of() on an unknown class Illuminate\Support\Uri.

Check failure on line 77 in src/Filament/Widgets/Feed.php

View workflow job for this annotation

GitHub Actions / Static Analysis - P8.2 - L11.x - prefer-lowest

Call to static method of() on an unknown class Illuminate\Support\Uri.
'ref' => 'cachet-dashboard',
]),
'description' => Str::of($item->description ?? $item->summary ?? '')->limit(preserveWords: true),
'date' => Carbon::parse((string)($item->pubDate ?? $item->updated ?? '')),
];

$feedIndex++;
}

return $posts;
} catch (Throwable $e) {
return [];
}
}
}

0 comments on commit 8743d2e

Please sign in to comment.