Pano Widget'ı Ekleme

2.3k görüntülenme Markdown

Admin panosuna bir kart eklemek için tek bir kayıt kancasından tanım dizisi döndürürsünüz.

Genel Bakış

Pano widget'ları bir modül tipi değildir: widget modülü ve genişletilecek bir taban sınıf yoktur. get_widgets() onları yetki kontrollerinden kurar, tek bir şablon gösterir, kancalar genişletir.

register:admin.dashboard_widgets kancasından bir dizi döndürürsünüz. Çekirdek ona bir sıra atar, operatörün kayıtlı düzenini uygular ve paylaşılan kart kabuğuna verir. Panonun geri kalanına dört kanca daha ulaşır.

Ön Koşullar

  • Çalışan bir hooks.php dosyası olan bir modül; bkz. Modülden Kanca Kaydetme.
  • İçeriğiniz bir HTML dizesi olarak; gövde olduğu gibi görünür.
  • Kart kısıtlanacaksa bir yetki anahtarı.

Yapı

controllers/admin/index.php get_widgets() listeyi kurar ve kancanızın dönüşünü birleştirir; get_statistics() rakam şeridini kurar.
templates/admin/index.php Pano kabuğu: enjeksiyon kancalarını ve widget filtresini tetikler, sonra listeyi kartlara döker.
inc/template-widget-item.php Kart kabuğu. Bilinmeyen bir ad sizin içeriğinize düşer.
operations/AdminIndex.php get_widget_content, yenile butonunun arkasındaki operation.
js/home.js Izgarayı Packery ile yerleştirir: rank HTML'deki sıradır, kartın yeri burada belirlenir.

Adım Adım

Kartı Kaydedin

  1. hooks.php dosyanızdan register:admin.dashboard_widgets kancasını dinleyin ve tek bir tanım dizisi döndürün.
  2. En azından name, title ve content verin; kalan her şeyin varsayılanı vardır.
  3. Yetki kontrolünü dinleyicinin içinde yapın: düşerse false döndürün ya da allowed anahtarına sonucu yazın.

Gövdeyi Kurun

  1. HTML'i heredoc ile üretin ve metinlerinizi modülün dil dosyasından okuyun.
  2. Dosya gövdesinde değil dinleyicinin içinde kurun; kartınızın gösterilmediği bir pano maliyet doğurmaz.
  3. Sonradan dolan her şeyin yüksekliğini rezerve edin.

Konum ve Boyutu Belirleyin

  1. İşaretlemedeki sıra için rank verin; yazmazsanız çekirdek sizinkini sona ekler.
  2. Tam genişlikte bir kart için size değerini wide yapın; başka her değer standart yarım genişliği verir.
  3. Şerit, çevresindeki işaretleme ya da başkasının kartları için aşağıdaki diğer dört kancayı kullanın.

Referans

Beş Pano Kancası

KancaÇağrı yeriDönüşünüz
register:admin.dashboard_widgetsHook::run, argümansızbir tanım bir kart olur; false hiçbir şey kaydetmez
filter:admin.dashboard.widgetsHook::runRefs, $widgets referanslayerinde düzenler: sıralama, çıkarma, başlık değiştirme
filter:admin.dashboard.statisticsHook::run, $resultboş olmayan dönüş dizinin tamamını değiştirir
ui:admin.dashboard.topHook::run, argümansızrakam şeridinin üstünde bir dize
ui:admin.dashboard.statistics.after ve ui:admin.dashboard.bottomaynısı, argümansızşeritten ve ızgaradan sonra bir dize
İstatistik filtresi değiştirir, birleştirmez

Çağrı yeri, boş olmayan son dinleyici dönüşünü tutar ve dizinin tamamına atar. İlgilendiğiniz anahtarı değiştirip dizinin tamamını döndürün; kendi anahtarınızı tek başına döndürmek şeridi siler ve boş şerit yine makul görünür.

Tanım Dizisi

name Kimlik: kartta data-id, kayıtlı düzende anahtar ve yenileme argümanı. Varsayılan wt{rank}, ona güvenmeyin.
title Başlık, ham HTML olarak görünür. Varsayılan Untitled Widget; link verirseniz bağlantıya sarılır.
content Kart gövdesi, olduğu gibi görünür. Boşsa widget adı görünür; unutmanın belirtisi budur.
icon Başlığın yanındaki disk için Bootstrap ikon sınıfı. Varsayılan bi bi-box.
allowed Boolean kapı, varsayılan true. False, kart görünmeden onu listeden çıkarır.
status open ya da close, varsayılan open. Kapalı kart yalnız başlığını gösterir.
rank İşaretlemedeki tam sayı sıra. Varsayılan: kaydedilen son widget'ın bir fazlası.
size wide tam genişlik sınıfını ekler; başka her değer standart genişliği bırakır.
hidden Boolean. Kart üretilir ama display none ile başlar; kapat butonu kendini böyle hatırlar.
link Başlığı bağlantıya çevirir. Bağlantı üreticisiyle kurun, düz yol yazmayın.
buttons Başlık butonları: ['create' => ['name' => …, 'link' => …, 'icon' => …]]. create artı ikonu alır; diğer anahtarlar icon kullanır, o da yoksa metin olarak ad.
header_buttons Yenile, daralt ve kapat butonlarından önce gelen ham HTML.

Çekirdeğin Doldurdukları

birleştirme
$hook = Hook::run("register:admin.dashboard_widgets");
if ($hook)
{
    $last = end($widgets);
    $rank = $last["rank"] ?? 10;

    foreach ($hook as $h)
    {
        $rank++;
        $wn = "wt" . $rank;

        if (isset($h["name"]) && $h["name"]) $wn = $h["name"];
        if (!isset($h["allowed"])) $h["allowed"] = true;
        if (!isset($h["status"])) $h["status"] = "open";
        if (!isset($h["rank"]))   $h["rank"]   = $rank;

        $widgets[$wn] = $h;                 // anahtar sizin adınızdır: yerleşik bir kartı DEĞİŞTİREBİLİR
    }
}

Yenile Butonu

imza
public function get_widget_content(Operation $operation): bool;
operation
// GET {dashboard}?operation=get_widget_content&name={adınız}
$widgets = $this->get_widgets();                 // kanca dahil listenin TAMAMI yeniden kurulur
if (!isset($widgets[$wn])) throw new Exception("Invalid widget");

// Aynı kabuktan yeniden basılan tek bir kart, HTML dizesi olarak döner.
return $operation->output($this->view->chose("admin")->render("inc" . DS . "template-widget-item", [
    'widget' => $widgets[$wn],
], true));

Karta Tablo Koymak

liste preset'ini kullanmak
$t = new \WISECP\Components\Table("myAddonWidget", [
    'preset'      => 'invoiceList',      // satır basımı ANA listeden gelir
    'hideActions' => true,
    'perPage'     => false,
    'search'      => false,
    'info'        => false,
    'pagination'  => false,
]);

foreach ($t->getColumns() as $k => $v) $t->setColumn($k, ['sortable' => false]);
$t->deleteColumn("selection");
$t->setRows($rows);

$html = $t->build();
Satırlar preset'in okuduğu her anahtarı taşımalı

Widget tablosu ana listenin satır basıcısını ödünç alır ve o basıcı, bıraktığınız kolonlardan çok daha fazla anahtar okur. Eksik anahtar hata vermez, boş hücre gösterir. Listeyi preset dosyasından çıkarın; oradaki bir değişiklik kartınıza da ulaşır.

Örnek

Bir modülün kendi kuyruğu: kaydedilmiş, kapılanmış, sıralanmış ve yenilenebilir.

MyAddon/hooks.php
<?php

Modules::Load('Addons', 'MyAddon', true);
$my_config = Modules::Config('Addons', 'MyAddon') ?: [];

if (!($my_config['status'] ?? false)) return;

/*
 * Panoda tek bir kart. Dinleyici argüman almaz ve TEK bir tanım döndürür; her pano
 * basımında ve bu kartın her yenilenmesinde koşar, bu yüzden ucuz kalır ve modül
 * örneğini ancak yetki kontrolü geçtikten sonra kurar.
 */
Hook::add('register:admin.dashboard_widgets', 10, function () {
    if (!Admin::isPrivilege('TOOLS_ADDONS')) return false;

    $module = Modules::getInstance('Addons', 'MyAddon');

    return [
        'name'    => 'myaddon_queue',
        'title'   => $module->lang['widget-title'] ?? 'My Addon Queue',
        'icon'    => 'bi bi-list-check',
        'rank'    => 6,
        'status'  => 'open',
        'link'    => LinkGenerator::admin('tools-2', ['addons', 'MyAddon']),
        'buttons' => [
            'create' => [
                'name' => Language::gc('admin/index/button-create-a-new'),
                'link' => LinkGenerator::wQS(LinkGenerator::admin('tools-2', ['addons', 'MyAddon']), ['trigger' => 'create']),
            ],
        ],
        'content' => $module->render_dashboard_widget(),
    ];
});

/* Şeritte bir rakam. Size verileni okuyun, bir anahtarı değiştirin, HEPSİNİ döndürün. */
Hook::add('filter:admin.dashboard.statistics', 10, function ($result) {
    if (!is_array($result)) return false;

    $result['static_blocks']['myaddon_pending'] = [
        'title' => 'Pending syncs',
        'value' => (int) WDB::select('COUNT(id) AS total')->from('MyAddon_queue')
            ->where('status', '=', 'pending')->build() ? (int) (WDB::getAssoc()['total'] ?? 0) : 0,
    ];

    return $result;
});
MyAddon.php, gövde
public function render_dashboard_widget(): string
{
    $rows = '';

    foreach ($this->queue_preview(5) as $row) {
        $label = htmlspecialchars((string) ($row['label'] ?? ''), ENT_QUOTES);
        $state = htmlspecialchars((string) ($row['status'] ?? ''), ENT_QUOTES);

        $rows .= <<<HTML
        <li class="list-group-item d-flex justify-content-between align-items-center px-0">
            <span class="text-truncate">{$label}</span>
            <span class="badge text-bg-light">{$state}</span>
        </li>
        HTML;
    }

    if ($rows === '')
        $rows = '<li class="list-group-item px-0 text-body-secondary">' . ($this->lang['widget-empty'] ?? 'Nothing queued.') . '</li>';

    // Rezerve edilen yüksekliği sınıf taşır (aşağıdaki stil dosyasına bakın); liste
    // dolduğunda tüm ızgaranın yeniden paketlenmesini engelleyen şey budur.
    return <<<HTML
    <ul class="list-group list-group-flush myaddon-queue">{$rows}</ul>
    HTML;
}
assets/style/admin.css
/* Nihai yükseklik, içerik var olmadan önce bildirilir. Kartı kaydeden aynı hooks.php
   dosyasından ui:admin.head.css üzerinden gönderin. */
.myaddon-queue { min-block-size: 220px; }

Okuma tarafı kart kabuğudur: content eksikken görünen yedek ve gövdenin neden kaçırılmadığı.

kart kabuğu
$w_name    = $widget["name"]  ?? "widget" . $w_rank;
$w_title   = ($widget["title"] ?? '') ?: 'Untitled Widget';
$w_icon    = ($widget["icon"]  ?? '') ?: 'bi bi-box';
$w_content = $widget["content"] ?? '';

if ($w_name == "orders_chart") {
    // ... yerleşik adlardan oluşan uzun bir zincir, her birine bir dal
}
else
    echo $w_content ?: $w_name;      // kaçırılmamış HTML'iniz, ya da unuttuysanız ad

Tuzaklar

İlk boyamadan sonra büyüyen kart ızgarayı yeniden paketler

Yerleşim masonry'dir ve her geçişte her kartı yeniden ölçer. Sonradan dolan bir gövde kartının yüksekliğini değiştirir, ilgisiz kartlar ekranda kayar. Ölçüldü: 54 piksel büyüyen bir grafik kutusu, başka iki kartı 733 piksel taşıdı.

Operatörün kayıtlı düzenlemesi tanımınızdan üstündür

Widget adınız için saklanmış bir rank, daraltılmış durum ya da gizli işaret tanımınızı yener ve çerezde taşınır: açık kaydettiğiniz kart bir yönetici için daralmış, meslektaşı için açık olabilir. Daraltılmış kartın içeriği sayfadadır, CSS ile gizlenir.

Dinleyiciniz her pano gösteriminde çalışır, bir kez değil

Herhangi bir kartın her yenilenmesinde de çalışır, çünkü o operation tüm listeyi yeniden kurar. Yenile butonunu sizin için çalıştıran şey budur; oradaki bir sorgu da her seferinde ödenir. Önce yetki kontrolünü yapın, pahalı olan her şeyi önbelleğe alın.

Var olan bir adla kayıt o kartı değiştirir

Birleştirme ada göre anahtarlanır, yani widget adınız notes ya da tasks ise yerleşik kartı devralır. Adın başına modülünüzü koyun.

Faydalı oldu mu?

Geri bildiriminiz için teşekkürler!

Hâlâ Yardıma mı İhtiyacınız Var?

Yukarıda bulamadığınız her şey için destek ekibimiz her zaman yanınızda.