Skip to content

Commit f680155

Browse files
Add Nova Metrics for Backups, Issues, Kegiatan, Outdated Packages, and System Info
- Implemented BackupsTable metric to display the latest 3 backups with download links. - Created IssuesTable metric to show unresolved issues from Sentry with appropriate icons. - Developed Kegiatan metric to list upcoming activities based on type (Rapat, Deadline, Libur). - Added OutdatedTable metric to list outdated Composer packages with installed and latest versions. - Introduced SystemInfo metric to provide system and application information including OS, PHP version, and database details.
1 parent 1212733 commit f680155

File tree

13 files changed

+375
-115
lines changed

13 files changed

+375
-115
lines changed

app/Helpers/Api.php

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,6 @@ public static function getComposerOutdatedPackages($flag = '--no-dev')
5252
$process = Process::fromShellCommandline($composer.' clear-cache', base_path(), ['COMPOSER_HOME' => $home]);
5353
$process->run();
5454

55-
return array_map(fn ($package) => [
56-
'title' => $package['name'],
57-
'description' => 'Installed: '.$package['version'].' | Latest: '.$package['latest'],
58-
], $data['installed'] ?? []);
55+
return $data['installed'] ?? [];
5956
}
6057
}

app/Nova/Dashboards/Main.php

Lines changed: 13 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,9 @@
44

55
use App\Helpers\Helper;
66
use App\Models\Announcement;
7-
use App\Models\DaftarKegiatan;
7+
use App\Nova\Metrics\Kegiatan;
88
use Illuminate\Support\Facades\Storage;
99
use Laravel\Nova\Dashboards\Main as Dashboard;
10-
use Laravelwebdev\ListCard\ListCard;
1110
use Laravelwebdev\NewsCard\NewsCard;
1211
use Laravelwebdev\NovaQuotes\NovaQuotes;
1312
use Richardkeep\NovaTimenow\NovaTimenow;
@@ -36,40 +35,6 @@ public function cards()
3635
}, session('role'));
3736

3837
$cards = [];
39-
40-
$items = DaftarKegiatan::whereIn('jenis', ['Libur', 'Deadline', 'Rapat'])
41-
->where(function ($query) {
42-
$query->where('jenis', 'Libur')
43-
->orWhere(function ($q) {
44-
$q->whereIn('jenis', ['Deadline', 'Rapat'])
45-
->whereDate('awal', '>=', now()->toDateString());
46-
});
47-
})
48-
->orderBy('awal')
49-
->get()
50-
->groupBy('jenis');
51-
52-
$kegiatan = ($items['Libur'] ?? collect())->map(function ($item) {
53-
return [
54-
'title' => Helper::terbilangHari($item->awal).', '.Helper::terbilangTanggal($item->awal),
55-
'description' => $item->kegiatan,
56-
];
57-
})->values()->toArray();
58-
59-
$deadline = ($items['Deadline'] ?? collect())->map(function ($item) {
60-
return [
61-
'title' => Helper::terbilangHari($item->awal).', '.Helper::terbilangTanggal($item->awal),
62-
'description' => $item->kegiatan,
63-
];
64-
})->values()->toArray();
65-
66-
$rapat = ($items['Rapat'] ?? collect())->map(function ($item) {
67-
return [
68-
'title' => Helper::terbilangHari($item->awal).', '.Helper::terbilangTanggal($item->awal),
69-
'description' => $item->kegiatan,
70-
];
71-
})->values()->toArray();
72-
7338
$pengumuman = Announcement::cache()->get('latest');
7439

7540
$cards[] = NovaQuotes::make()
@@ -97,20 +62,20 @@ public function cards()
9762
);
9863
}
9964

100-
$cards[] = ListCard::make()
101-
->title('Deadline Mendatang')
102-
->items($deadline)
103-
->emptyText('Tidak ada Deadline');
65+
$cards[] = Kegiatan::make('Deadline')
66+
->emptyText('Tidak ada deadline')
67+
->scrollable()
68+
->width('1/3');
10469

105-
$cards[] = ListCard::make()
106-
->title('Rapat Mendatang')
107-
->items($rapat)
108-
->emptyText('Tidak ada Rapat');
70+
$cards[] = Kegiatan::make('Rapat')
71+
->emptyText('Tidak ada Rapat')
72+
->scrollable()
73+
->width('1/3');
10974

110-
$cards[] = ListCard::make()
111-
->title('Hari Libur Nasional')
112-
->items($kegiatan)
113-
->emptyText('Tidak ada hari libur nasional');
75+
$cards[] = Kegiatan::make('Libur')
76+
->emptyText('Tidak ada hari libur nasional')
77+
->scrollable()
78+
->width('1/3');
11479

11580
return $cards;
11681
}

app/Nova/Dashboards/SystemHealth.php

Lines changed: 15 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,12 @@
22

33
namespace App\Nova\Dashboards;
44

5-
use App\Helpers\Api;
6-
use App\Nova\Metrics\ServerResource;
7-
use Illuminate\Support\Facades\Cache;
85
use Laravel\Nova\Dashboard;
9-
use Laravelwebdev\ListCard\ListCard;
10-
use Laravelwebdev\SystemInfo\SystemInfo;
11-
use Spatie\Backup\BackupDestination\Backup;
12-
use Spatie\Backup\BackupDestination\BackupDestination;
13-
use Spatie\Backup\Helpers\Format;
6+
use App\Nova\Metrics\SystemInfo;
7+
use App\Nova\Metrics\IssuesTable;
8+
use App\Nova\Metrics\BackupsTable;
9+
use App\Nova\Metrics\OutdatedTable;
10+
use App\Nova\Metrics\ServerResource;
1411

1512
class SystemHealth extends Dashboard
1613
{
@@ -21,58 +18,21 @@ class SystemHealth extends Dashboard
2118
*/
2219
public function cards(): array
2320
{
24-
$disk = config('backup.backup.destination.disks')[0] ?? 'local';
25-
$backupDestination = BackupDestination::create($disk, config('backup.backup.name'));
26-
$backups = Cache::remember("backups-{$disk}", now()->addSeconds(4), function () use ($backupDestination) {
27-
return $backupDestination
28-
->backups()
29-
->map(function (Backup $backup) {
30-
$size = method_exists($backup, 'sizeInBytes') ? $backup->sizeInBytes() : $backup->size();
31-
32-
return [
33-
'path' => $backup->path(),
34-
'date' => $backup->date()->format('j F Y H:i:s'),
35-
'size' => Format::humanReadableSize($size),
36-
];
37-
})
38-
->toArray();
39-
});
40-
41-
$backuplist = array_map(function ($backup) {
42-
return [
43-
'title' => $backup['path'],
44-
'description' => 'Created: '.$backup['date'].', Size: '.$backup['size'],
45-
'icon' => 'arrow-down',
46-
'url' => config('app.url').config('nova.path').'/backup/download/'.basename($backup['path']),
47-
];
48-
}, $backups);
49-
50-
$issues = array_map(function ($issue) {
51-
return [
52-
'title' => ucwords($issue['type']).' ('.$issue['count'].')',
53-
'description' => $issue['title'],
54-
];
55-
}, Api::getSentryUnresolvedIssues());
56-
5721
return [
5822
ServerResource::make()->refreshIntervalSeconds(60),
5923
ServerResource::make('inode')->refreshIntervalSeconds(60),
6024
ServerResource::make('backup')->help('')->refreshIntervalSeconds(60),
61-
SystemInfo::make()->versions()->width('1/2'),
62-
ListCard::make()
63-
->width('1/2')
64-
->title('Backups')
65-
->items($backuplist)
66-
->emptyText('No Backup Found'),
67-
ListCard::make()
68-
->width('1/2')
69-
->title('Outdated Packages')
70-
->items(Api::getComposerOutdatedPackages())
25+
SystemInfo::make()->width('1/2')->refreshIntervalSeconds(60)->scrollable(),
26+
BackupsTable::make()->width('1/2')
27+
->emptyText('No backups found.')
28+
->scrollable()
29+
->refreshIntervalSeconds(60),
30+
OutdatedTable::make()->width('1/2')
31+
->scrollable()
7132
->emptyText('All packages are already up to date.'),
72-
ListCard::make()
73-
->width('1/2')
74-
->title('Unresolved Issues')
75-
->items($issues)
33+
IssuesTable::make()->width('1/2')
34+
->refreshIntervalSeconds(60)
35+
->scrollable()
7636
->emptyText('No issues found.'),
7737
];
7838
}

app/Nova/Metrics/BackupsTable.php

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
<?php
2+
3+
namespace App\Nova\Metrics;
4+
5+
use DateTimeInterface;
6+
use Fidum\LaravelNovaMetricsPolling\Concerns\SupportsPolling;
7+
use Illuminate\Support\Facades\Cache;
8+
use Laravel\Nova\Http\Requests\NovaRequest;
9+
use Laravel\Nova\Menu\MenuItem;
10+
use Laravel\Nova\Metrics\MetricTableRow;
11+
use Laravel\Nova\Metrics\Table;
12+
use Spatie\Backup\BackupDestination\Backup;
13+
use Spatie\Backup\BackupDestination\BackupDestination;
14+
use Spatie\Backup\Helpers\Format;
15+
16+
class BackupsTable extends Table
17+
{
18+
use SupportsPolling;
19+
20+
public function name(): string
21+
{
22+
return 'Latest 3 Backups';
23+
}
24+
25+
/**
26+
* Calculate the value of the metric.
27+
*
28+
* @return array<int, \Laravel\Nova\Metrics\MetricTableRow>
29+
*/
30+
public function calculate(NovaRequest $request): array
31+
{
32+
$disk = config('backup.backup.destination.disks')[0] ?? 'local';
33+
$backupDestination = BackupDestination::create($disk, config('backup.backup.name'));
34+
$backups = Cache::remember("backups-{$disk}", now()->addSeconds(4), function () use ($backupDestination) {
35+
return $backupDestination
36+
->backups()
37+
->map(function (Backup $backup) {
38+
$size = method_exists($backup, 'sizeInBytes') ? $backup->sizeInBytes() : $backup->size();
39+
40+
return [
41+
'path' => $backup->path(),
42+
'date' => $backup->date()->format('j F Y H:i:s'),
43+
'size' => Format::humanReadableSize($size),
44+
];
45+
})
46+
->toArray();
47+
});
48+
49+
$rows = [];
50+
// Ambil 4 backup terbaru saja
51+
$latestBackups = array_slice($backups, 0, 3);
52+
foreach ($latestBackups as $backup) {
53+
$rows[] = MetricTableRow::make()
54+
->icon('inbox')
55+
->iconClass('text-green-500')
56+
->title($backup['path'])
57+
->subtitle('Created: '.$backup['date'].', Size: '.$backup['size'])
58+
->actions(fn () => [
59+
MenuItem::externalLink('Download', config('app.url').config('nova.path').'/backup/download/'.basename($backup['path'])),
60+
61+
]);
62+
}
63+
64+
return $rows;
65+
}
66+
67+
/**
68+
* Determine the amount of time the results of the metric should be cached.
69+
*/
70+
public function cacheFor(): ?DateTimeInterface
71+
{
72+
// return now()->addMinutes(5);
73+
74+
return null;
75+
}
76+
}

app/Nova/Metrics/IssuesTable.php

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php
2+
3+
namespace App\Nova\Metrics;
4+
5+
use App\Helpers\Api;
6+
use DateTimeInterface;
7+
use Fidum\LaravelNovaMetricsPolling\Concerns\SupportsPolling;
8+
use Laravel\Nova\Http\Requests\NovaRequest;
9+
use Laravel\Nova\Metrics\MetricTableRow;
10+
use Laravel\Nova\Metrics\Table;
11+
12+
class IssuesTable extends Table
13+
{
14+
use SupportsPolling;
15+
16+
public $name = 'Bugs & Issues';
17+
18+
/**
19+
* Calculate the value of the metric.
20+
*
21+
* @return array<int, \Laravel\Nova\Metrics\MetricTableRow>
22+
*/
23+
public function calculate(NovaRequest $request): array
24+
{
25+
$rows = [];
26+
foreach (Api::getSentryUnresolvedIssues() as $issue) {
27+
$rows[] = MetricTableRow::make()
28+
->icon($issue['level'] === 'error' ? 'x-circle' : 'exclamation-circle')
29+
->iconClass($issue['level'] === 'error' ? 'text-red-500' : 'text-yellow-500')
30+
->title(ucwords($issue['type']).' ('.$issue['count'].')')
31+
->subtitle($issue['title']);
32+
}
33+
34+
return $rows;
35+
}
36+
37+
/**
38+
* Determine the amount of time the results of the metric should be cached.
39+
*/
40+
public function cacheFor(): ?DateTimeInterface
41+
{
42+
// return now()->addMinutes(5);
43+
44+
return null;
45+
}
46+
}

app/Nova/Metrics/Kegiatan.php

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<?php
2+
3+
namespace App\Nova\Metrics;
4+
5+
use App\Helpers\Helper;
6+
use App\Models\DaftarKegiatan;
7+
use DateTimeInterface;
8+
use Laravel\Nova\Http\Requests\NovaRequest;
9+
use Laravel\Nova\Metrics\MetricTableRow;
10+
use Laravel\Nova\Metrics\Table;
11+
12+
class Kegiatan extends Table
13+
{
14+
protected $jenis = 'Rapat';
15+
16+
public function __construct($jenis)
17+
{
18+
$this->jenis = $jenis;
19+
}
20+
21+
public function name()
22+
{
23+
switch ($this->jenis) {
24+
case 'Rapat':
25+
return 'Rapat Mendatang';
26+
case 'Deadline':
27+
return 'Deadline Mendatang';
28+
case 'Libur':
29+
return 'Hari Libur Nasional';
30+
default:
31+
return 'Kegiatan ' . ucfirst($this->jenis);
32+
}
33+
}
34+
35+
/**
36+
* Calculate the value of the metric.
37+
*
38+
* @return array<int, \Laravel\Nova\Metrics\MetricTableRow>
39+
*/
40+
public function calculate(NovaRequest $request): array
41+
{
42+
$rows = [];
43+
$deadlines = DaftarKegiatan::where('jenis', $this->jenis)
44+
->when($this->jenis !== 'Libur', function ($query) {
45+
$query->whereDate('awal', '>=', now()->toDateString());
46+
})
47+
->orderBy('awal', 'asc')
48+
->get();
49+
foreach ($deadlines as $deadline) {
50+
$rows[] = MetricTableRow::make()
51+
->icon(
52+
$this->jenis === 'Libur' ? 'calendar' :
53+
($this->jenis === 'Deadline' ? 'exclamation-triangle' : 'user-group')
54+
)
55+
->iconClass(
56+
$this->jenis === 'Rapat' ? 'text-green-500' :
57+
($this->jenis === 'Deadline' ? 'text-red-500' : 'text-blue-500')
58+
)
59+
->subtitle($deadline->kegiatan)
60+
->title(Helper::terbilangHari($deadline->awal).', '.Helper::terbilangTanggal($deadline->awal));
61+
}
62+
63+
return $rows;
64+
}
65+
66+
/**
67+
* Determine the amount of time the results of the metric should be cached.
68+
*/
69+
public function cacheFor(): ?DateTimeInterface
70+
{
71+
// return now()->addMinutes(5);
72+
73+
return null;
74+
}
75+
}

0 commit comments

Comments
 (0)