Integrazione dashboard laravel pulse con laravel nova  

Oggi vi propongo una modifica che ho fatto sul backend di un mio cliente in modo da avere la dashboard di laravel pulse direttamente nel pannello principale di laravel nova.
Pubblicato il 22/10/2024 alle 11:20

Anche se Laravel Pulse mette a disposizione un endpoint da raggiungere tramite un semplice link ed utilizzare la dashboard di pulse come applicazione standalone ho avuto l'esigenza di integrare la visualizzazione direttamente nella dashboard di laravel per creare una migliore esperienza utente.

Obiettivo

Qui vi indico il risultato che otterremo con questa integrazione, nella versione standard ho riscontrato questi problemi, la versione dark se attivata su Laravel Nova bisognava anche selezionarla su pulse o il contrario, avendo a disposizione un menu per laravel nova sullo stato di diverse applicazioni quando veniva richiamata la dashboard di pulse bisognava sempre tornare indietro per scegliere altra opzione.

L'idea è quella di creare una "custom route" in laravel nova che crei un elemento iframe ad una versione modificata della dashboard pulse, quindi senza usare l'endpoint originale, in questo modo possiamo personalizzare il layout originale e integrare un solo stato di tema dark/light e personalizzare il CSS.

Creazione delle "custom route"

Per prima cosa creiamo un file per la definizione delle "route" o modifichiamo quello esistente se già avete delle "route" personalizzate. Io ho creato un file in app/Nova/Routes/tools.php.

Route::get('status/pulse')
    ->uses('App\Nova\Controllers\Tools\Status\PulseController@index')
    ->name('tools.status.pulse');

Route::get('status/pulse/iframe')
    ->uses('App\Nova\Controllers\Tools\Status\PulseController@iframe')
    ->name('tools.status.pulse.iframe');

Ho creato una "route" per la pagina laravel nova principale e una per eseguire "embed" tramite "iframe" di una copia della dashboard di laravel pulse modificata in base alle nostre necessità. In seguito andremmo anche a definire il controller per l'esecuzione di queste due funzioni. Ovviamente potete cambiare il valore del "path" come desiderate in base alle vostre preferenze.

Creazione del controller

Personalmente preferisco avere tutto l'ambiente Nova nella directory app\Nova e lasciare le directory standard per le funzione dell'applicazione operativa, quindi creo il controller necessario nella directory app/Nova/Controllers/Tools/Status come indicato nella definizione delle "route".

namespace App\Nova\Controllers\Tools\Status;

use App\Http\Controllers\Controller;

class PulseController extends Controller
{
    /**
     * Application nova function
     */
    public function index()
    {
        return inertia('StatusPulse');
    }

    /**
     * Application nova function
     */
    public function iframe()
    {
        return view('admin::tools.status.pulse.index');
    }
}

Il primo metodo è usato per richiamare la pagina principale tramite un componente Vue, dato che Nova esegue il rendering iniziale lato client, mentre il metodo "iframe" sarà elaborato lato server e quindi elaborerà una vista blade con la copia originale della dashboard di laravel pulse però modificata.

Creazione componente Vue

Per rendere funzionante il path /status/pulse relativo al path di laravel nova dobbiamo creare un componente Vue quindi dobbiamo implementare uno javascript e caricarlo durante l'inizializzazione di laravel nova, io ad esempio uso questa tecnica anche per caricare livewire che uso insieme a Nova.

import StatusPulse from './pages/Status/Pulse.vue'

Nova.booting((app, store) => {
    Nova.inertia('StatusPulse', StatusPulse)
})

Creiamo un file nova.js dove avete l'ambiente per la creazione degli assets, io uso ViteJS però sono sicuro che potete implementarlo anche con altri strumenti. Nella stessa directory di nova.js creiamo una directory con il template "vue" ./pages/Status/Pulse.vue indicando questo codice.

<template>
  <div>
    <iframe src="/nova/status/pulse/iframe?period=24_hours"
            width="100%" style="min-height:100vw"></iframe>
  </div>
</template>

Creazione vista Blade

Adesso l'ambiente dovrebbe essere pronto per visualizzare una pagina che esegue il rendering della vista blade associata al controller definito in precedenza tramite il metodo "iframe". Quindi basta copiare al momento solo per testare il funzionamento (dopo faremo le personalizzazioni) il file presente nel pacchetto di laravel pulse. app\vendor\laravel\pulse\resources nella nostra vista blade.

Attenzione alla variabile {{slot}} che dovrà essere sostituita con la lista dei widgets di laravel pulse che vogliamo visualizzare nella nostra dashboard quindi modifichiamo il codice come segue:

<main class="py-4">
  <div {{ $attributes->merge(['class' => "mx-auto grid default:grid-cols-{$cols} default:gap-6"]) }}>
    <livewire:pulse.servers cols="full"/>
    <livewire:pulse.usage cols="4" rows="2" />
    <livewire:pulse.queues cols="4" />
    <livewire:pulse.cache cols="4" />
    <livewire:pulse.slow-queries cols="8" />
    <livewire:pulse.exceptions cols="6" />
    <livewire:pulse.slow-requests cols="6" />
    <livewire:pulse.slow-jobs cols="6" />
    <livewire:pulse.slow-outgoing-requests cols="6" />
  </div>
</main>

Adesso siamo pronti per fare una prova, se la dashboard viene visualizzata senza problemi possiamo passare alla fase di personalizzazione codice, altrimenti ripetere con attenzione i passi precedenti. In questa dimostrazione sto usando il codice originale con cui uso l'implementazione tutti i giorni quindi dovrebbe essere abbastanza affidabile dal punto di vista del funzionamento.

Personalizzazione Dashboard

Per rendere la pagina di pulse più coerente dobbiamo eseguire alcune modifiche, la prima è quella di eliminare il componete theme-switcher dal codice copiato e sostituire il cambio di tema basandosi su quello impostato in laravel nova. Quindi per prima cosa eliminiamo la riga dello switch.

Eliminare il componete indicato dal codice che abbiamo copiato precedentemente nella nostra vista blade e aggiungiamo un codice javascript nella sezione HEAD che attivi o disattivi il tema dark in base allo stato del tema di laravel nova che in questo caso esegue la funzione di contenitore.

@livewireScriptConfig

<script>

  function updateTheme() {
    if (window.parent.document.documentElement.classList.contains('dark')) {
      this.theme = 'dark'
      localStorage.theme = 'dark'
      document.documentElement.classList.add('dark')
    } else {
      this.theme = 'light'
      localStorage.theme = 'light'
      document.documentElement.classList.remove('dark')
    }
  }

  const observer = new MutationObserver(function(mutationsList) {
    for (let mutation of mutationsList) {
      if (mutation.attributeName === 'class') {
        updateTheme();
      }
    }
  });

  observer.observe(window.parent.document.documentElement, {
    attributes: true
  });

  updateTheme();

</script>

Inserite questo codice subito dopo l'istruzione @livewireScriptConfig che vi indico come riferimento, a questo punto dovremmo aver ottenuto lo switch del tema pulse usando lo switch di laravel nova. Oltre alla personalizzazione di javascript possiamo anche cambiare il CSS in modo da renderlo più idoneo al nostro ambiente o alle nostre personalizzazioni eseguite in ambiente di laravel nova.

<style>
  html.dark .dark\:bg-gray-900
  {
    background-color: #101521 !important;
  }
  *, :before, :after {
     --tw-gradient-to-position: 0;
  }
</style>

Io ad esempio ho cambiato il "background color" nella versione "dark-mode" per renderlo più visibile rispetto al background di default di laravel nova, ho anche eliminato dei background legati all sezione header per ottenere una sensazione di integrazione più diretta con il tema di laravel nova.

Risultato finale

Spero che questa esperienza vi torni utile per il vostro lavoro, ci vediamo nella prossima pubblicazione, qualsiasi miglioramento alla soluzione è ben accetto, usate i commenti per scrivermi. Grazie.

Commenti
Armando Simón León Kovaleff
Armando Simón León Kovaleff
Great article! It was incredibly helpful in understanding how to integrate Laravel Pulse with Laravel Nova. The step-by-step explanation, especially about customizing the theme and using the iframe, was very clear and insightful.
Emanuel Tomas Cruz Ñaupa
Emanuel Tomas Cruz Ñaupa
Complimenti per l'articolo! Mi è stato molto utile per comprendere meglio l'integrazione di Laravel Pulse con Laravel Nova. La spiegazione è chiara e dettagliata, soprattutto la parte riguardante la personalizzazione del tema e l'uso dell'iframe. Apprezzo anche i suggerimenti per migliorare l'esperienza utente e la coerenza visiva. Grazie per aver condiviso questa soluzione, non vedo l'ora di leggere le prossime pubblicazioni! Continuate così!