make:panel-page
Menghasilkan standalone panel page — sebuah screen yang menjadi bagian dari Panel, tetapi bukan salah satu CRUD page milik Resource.
Gunakan command ini untuk membuat:
- halaman Settings;
- dashboard tambahan;
- report;
- atau screen lain yang membutuhkan URL, navigation entry, dan props sendiri.
php artisan make:panel-page Reports --panel=AdminOutput:
INFO Created [app/Panels/Admin/Pages/Reports.php]Path discoverPages() pada Panel sudah mencakup app/Panels/Admin/Pages, sehingga pada request berikutnya /admin/reports langsung tersedia dan entry Reports muncul di sidebar.
Signature
make:panel-page
{name : The page class name}
{--panel= : The panel it belongs to}
{--component : Also generate a Vue component for the page}
{--force}2
3
4
5
| Argument / option | Default | Efek |
|---|---|---|
name | required | Diubah menjadi StudlyCase. reports, Reports, dan report-summary semuanya menjadi nama class yang valid. |
--panel= | required | Panel tujuan generate, juga diubah menjadi StudlyCase. Jika tidak diberikan, command gagal. |
--component | off | Mengatur $component agar menunjuk ke file Vue milik page ini dan sekaligus membuat file tersebut. |
--force | off | Menimpa file yang sudah ada. |
php artisan make:panel-page Reports --panel=Admin
php artisan make:panel-page Settings --panel=Admin --component
php artisan make:panel-page Settings --panel=Admin --component --force2
3
Page yang Dihasilkan
<?php
declare(strict_types=1);
namespace App\Panels\Admin\Pages;
use PandaPanel\Pages\Page;
final class Reports extends Page
{
protected static ?string $navigationIcon = 'file-text';
protected static int $navigationSort = 0;
protected static string $component = 'panel/Page';
/**
* @return array<string, mixed>
*/
public function props(): array
{
return [];
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Behavior lainnya diwarisi dan diturunkan secara otomatis:
| Behavior | Sumber | Hasil untuk Reports |
|---|---|---|
| URL slug | Page::slug(), class basename dalam kebab-case | reports |
| Route path | Page::routePath(), slug di bawah cluster prefix jika ada | reports |
| Route name | Page::routeName() | panel.admin.pages.reports — baca dengan Reports::routeName() |
| Title | Page::title(), Str::headline() dari class basename | Reports |
| Heading | Page::heading(), default sama dengan title | Reports |
| Access | Page::canAccess() | true — override bila perlu dibatasi |
use App\Panels\Admin\Pages\Reports;
Reports::slug(); // 'reports'
Reports::url(); // '/admin/reports'
Reports::routeName(); // 'panel.admin.pages.reports'2
3
4
5
Tanpa --component: Generic Renderer
$component = 'panel/Page' menunjuk ke component bawaan package yang dipublish ke:
resources/js/pages/panel/Page.vueComponent tersebut merender:
- page heading;
- subheading;
- header actions;
- widgets;
di dalam PanelLayout, yang juga menggambar breadcrumbs dari page metadata yang sama.
Satu hal yang tidak dirender oleh generic component ini adalah page filter bar. Control dari filterSchema() dirender oleh dashboard component. Jadi standalone page yang ingin menampilkan filter di screen harus memiliki component sendiri melalui --component.
Page yang tidak memiliki UI khusus tidak memerlukan file Vue. Karena itu default generator memang tidak membuat Vue component. Banyak standalone page hanya membutuhkan heading dan widgets:
use App\Panels\Admin\Widgets\UserStats;
use PandaPanel\Pages\Page;
final class Reports extends Page
{
protected static ?string $navigationIcon = 'chart-line';
protected static string $component = 'panel/Page';
/**
* @return list<class-string<\PandaPanel\Widgets\Widget>>
*/
public function widgets(): array
{
return [UserStats::class];
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Dengan --component: Vue File Sendiri
php artisan make:panel-page Settings --panel=Admin --componentOutput:
INFO Created [app/Panels/Admin/Pages/Settings.php]
INFO Created [resources/js/pages/Panels/Admin/Pages/Settings.vue]2
Pada sisi PHP hanya ada satu perubahan:
protected static string $component = 'Panels/Admin/Pages/Settings';File Vue yang dihasilkan sudah menjadi starting point yang dapat langsung dikembangkan:
<script setup lang="ts">
import { Head } from '@inertiajs/vue3';
import PageHeader from '@/panel/components/PageHeader.vue';
import type { PageMetadata } from '@/panel/types/page';
defineProps<{
page: PageMetadata;
}>();
</script>
<template>
<Head :title="page.title" />
<div class="flex flex-col gap-6">
<PageHeader :heading="page.heading" :subheading="page.subheading" />
</div>
</template>2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Nama component adalah path relatif di bawah resources/js/pages/, tanpa extension.
Jadi:
Panels/Admin/Pages/Settingsberarti:
resources/js/pages/Panels/Admin/Pages/Settings.vueInilah cara Inertia me-resolve page component.
Mengirim Props Sendiri
Return dari props() digabung ke Inertia response bersama key framework:
page
widgets
widgetData
filters2
3
4
Contoh:
use App\Models\User;
use PandaPanel\Pages\Page;
final class Settings extends Page
{
protected static string $component = 'Panels/Admin/Pages/Settings';
/**
* @return array<string, mixed>
*/
public function props(): array
{
return [
'userCount' => User::query()->count(),
];
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Frontend:
<script setup lang="ts">
import type { PageMetadata } from '@/panel/types/page';
defineProps<{
page: PageMetadata;
userCount: number;
}>();
</script>2
3
4
5
6
7
8
Hanya kirim value yang dapat diserialisasi, karena props menyeberang ke browser sebagai JSON.
Lokasi Vue File
Default:
resources/js/pages/Panels/{Panel}/Pages/{Class}.vueSegment Panels dapat dikonfigurasi:
// config/panda-panel.php
'frontend' => [
'panel_path' => 'js/panel',
'pages_path' => 'js/pages/Panels',
],2
3
4
5
6
pages_path dibaca melalui:
PandaPanel\Support\FrontendPaths::pages()Helper ini digunakan oleh generator ini dan make:panel-widget.
Path tersebut juga menjadi root untuk import.meta.glob allowlist yang digunakan frontend untuk me-resolve component name. Jika Anda memindahkannya, glob terkait juga harus ikut disesuaikan.
Custom Stubs
php artisan vendor:publish --tag=panda-panel-stubs| Stub | Ditulis ke | Placeholder |
|---|---|---|
stubs/panel/page.stub | app/Panels/{Panel}/Pages/{Class}.php | panel, class, component |
stubs/panel/page-component.stub | resources/js/pages/Panels/{Panel}/Pages/{Class}.vue | tidak ada |
page-component.stub tidak memiliki placeholder dan disalin apa adanya.
Exit Codes
| Hasil | Code |
|---|---|
| Minimal satu file dibuat | 0 |
| Semua file sudah ada dan dilewati | 1 |
--panel tidak diberikan | 1, dengan pesan The --panel option is required. |
Hal yang Perlu Diperhatikan
- Page ditemukan melalui discovery, bukan registration eksplisit. File harus berada di directory yang tercakup oleh
discoverPages(). Jika dipindah ke luar path tersebut, page menghilang tanpa error. - Cached manifest dapat menyembunyikan page baru. Tidak ada route, navigation entry, atau error. Jalankan
php artisan panel:clear. --componenttidak otomatis rebuild frontend. Setelah file.vuedibuat, jalankannpm run devataunpm run build.- Menghapus Vue file tidak otomatis mengembalikan generic renderer. Jika
$componentmasih menunjuk ke component custom yang sudah dihapus, page tidak dapat di-resolve. Ubah$componentsecara manual. - Navigation icon harus terdaftar di icon registry. Stub menggunakan
file-text. Icon lain perlu didaftarkan lewatphp artisan panel:icons. - Dua Page dalam satu Panel tidak boleh memiliki slug yang sama. Cluster hanya mem-prefix route path dan tidak mengubah
slug(). Collision tetap menyebabkanPageRegistrymelemparduplicatePageSlug()saat boot.