995 lines
68 KiB
PHP
995 lines
68 KiB
PHP
<div class="fi-page">
|
|
@php
|
|
$supportUpdateAuthUser = auth()->user();
|
|
$supportCanRunUpdate = $supportUpdateAuthUser && method_exists($supportUpdateAuthUser, 'hasAnyRole') && $supportUpdateAuthUser->hasAnyRole(['super-admin', 'admin', 'amministratore']);
|
|
@endphp
|
|
<div class="mx-auto max-w-7xl space-y-3 text-xs">
|
|
<x-filament.components.page-breadcrumbs
|
|
:breadcrumbs="[
|
|
['label' => 'Supporto', 'url' => null],
|
|
['label' => 'Modifiche', 'url' => null],
|
|
]"
|
|
/>
|
|
|
|
<x-filament::section class="!p-4">
|
|
<div class="flex flex-wrap items-start justify-between gap-3">
|
|
<div class="space-y-1">
|
|
<div class="text-base font-semibold">NetGescon - Modifiche e Aggiornamenti</div>
|
|
<div class="text-xs text-gray-600">
|
|
Versione corrente: <span class="font-mono font-semibold">{{ $this->currentVersion }}</span>
|
|
<span class="ml-2 rounded bg-gray-100 px-1.5 py-0.5 text-[10px] uppercase">fonte {{ $this->versionSource }}</span>
|
|
</div>
|
|
<div class="pt-1 text-[11px] text-sky-700">
|
|
Per sync Git e update piu sicuri usa il launcher esterno:
|
|
<a href="{{ \App\Filament\Pages\Supporto\AggiornamentoLauncher::getUrl(panel: 'admin-filament') }}" class="font-semibold text-sky-900 underline underline-offset-2 hover:text-sky-700">
|
|
Apri Aggiornamento Nodo
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="space-y-1 text-xs text-gray-600">
|
|
<div class="font-medium text-gray-700">Legenda rapida</div>
|
|
<div class="flex flex-wrap gap-3">
|
|
<span class="inline-flex items-center gap-2"><span class="inline-block h-2.5 w-2.5 rounded-sm bg-success-500"></span>U utenti finali</span>
|
|
<span class="inline-flex items-center gap-2"><span class="inline-block h-2.5 w-2.5 rounded-sm bg-primary-500"></span>P assistenza/sviluppo</span>
|
|
<span class="inline-flex items-center gap-2"><span class="inline-block h-2.5 w-2.5 rounded-sm bg-warning-500"></span>E non bloccante</span>
|
|
<span class="inline-flex items-center gap-2"><span class="inline-block h-2.5 w-2.5 rounded-sm bg-danger-500"></span>E! bloccante</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-3 flex flex-wrap gap-2">
|
|
<button
|
|
type="button"
|
|
wire:click="setActiveTab('manuale')"
|
|
class="inline-flex items-center rounded-md px-3 py-1.5 text-xs font-medium {{ $this->activeTab === 'manuale' ? 'bg-slate-800 text-white' : 'bg-slate-100 text-slate-700 hover:bg-slate-200' }}"
|
|
>
|
|
Manuale
|
|
</button>
|
|
<button
|
|
type="button"
|
|
wire:click="setActiveTab('errori')"
|
|
class="inline-flex items-center rounded-md px-3 py-1.5 text-xs font-medium {{ $this->activeTab === 'errori' ? 'bg-slate-800 text-white' : 'bg-slate-100 text-slate-700 hover:bg-slate-200' }}"
|
|
>
|
|
Aggiornamenti + Bug
|
|
</button>
|
|
<button
|
|
type="button"
|
|
wire:click="setActiveTab('commit')"
|
|
class="inline-flex items-center rounded-md px-3 py-1.5 text-xs font-medium {{ $this->activeTab === 'commit' ? 'bg-slate-800 text-white' : 'bg-slate-100 text-slate-700 hover:bg-slate-200' }}"
|
|
>
|
|
Commit + Note
|
|
</button>
|
|
<button
|
|
type="button"
|
|
wire:click="setActiveTab('migliorie')"
|
|
class="inline-flex items-center rounded-md px-3 py-1.5 text-xs font-medium {{ $this->activeTab === 'migliorie' ? 'bg-slate-800 text-white' : 'bg-slate-100 text-slate-700 hover:bg-slate-200' }}"
|
|
>
|
|
Migliorie
|
|
</button>
|
|
</div>
|
|
</x-filament::section>
|
|
|
|
@if($this->activeTab === 'manuale')
|
|
<x-filament::section class="!p-4">
|
|
<div class="grid gap-3 lg:grid-cols-[1.35fr_0.65fr]">
|
|
<div class="rounded-lg border bg-slate-50 p-3">
|
|
<div class="text-xs font-semibold text-slate-800">Manuale operativo integrato nel progetto</div>
|
|
<div class="mt-2 text-[11px] leading-relaxed text-slate-700">
|
|
Questa sezione diventa il punto di continuita tra sviluppo, Git e aggiornamenti applicativi. I contenuti sotto arrivano da file Markdown versionati nel repository, quindi restano leggibili sia dalla UI sia durante le prossime sessioni di sviluppo con agent e strumenti locali.
|
|
</div>
|
|
<div class="mt-3 flex flex-wrap gap-2">
|
|
<x-filament::button size="sm" color="gray" wire:click="reloadDashboardData">
|
|
Ricarica manuale e dati pagina
|
|
</x-filament::button>
|
|
<x-filament::button size="sm" color="info" wire:click="setActiveTab('commit')">
|
|
Vai a Commit + Note
|
|
</x-filament::button>
|
|
<x-filament::button size="sm" color="warning" wire:click="setActiveTab('errori')">
|
|
Vai a Aggiornamenti + Bug
|
|
</x-filament::button>
|
|
<x-filament::button size="sm" wire:click="runUpdate" :disabled="!$supportCanRunUpdate">
|
|
Lancia aggiornamento
|
|
</x-filament::button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="rounded-lg border bg-white p-3">
|
|
<div class="text-xs font-semibold text-slate-800">Flusso minimo dopo ogni Git</div>
|
|
<ol class="mt-2 list-decimal space-y-1 pl-4 text-[11px] text-slate-700">
|
|
<li>aggiorna il documento della sezione corretta nel repository</li>
|
|
<li>salva una nota operativa sul commit se serve contesto extra</li>
|
|
<li>spingi il codice su Gitea</li>
|
|
<li>usa il pulsante di sync da Gitea da questa pagina per allineare staging</li>
|
|
<li>se c e un problema applicativo, registralo o segnalo come risolto nel tab BUG</li>
|
|
</ol>
|
|
</div>
|
|
</div>
|
|
</x-filament::section>
|
|
|
|
<x-filament::section class="!p-4">
|
|
<div class="mb-2 flex flex-wrap items-start justify-between gap-2">
|
|
<div>
|
|
<div class="text-xs font-semibold text-gray-700">Snapshot continuita sviluppo</div>
|
|
<div class="mt-1 text-[11px] text-gray-500">
|
|
Riepilogo automatico per ripartire senza ricostruire ogni volta ragionamenti, file chiave, stato PBX e punti ancora aperti.
|
|
</div>
|
|
</div>
|
|
<div class="flex flex-wrap gap-2">
|
|
<div class="rounded bg-slate-100 px-2 py-1 font-mono text-[10px] text-slate-600">{{ $this->developmentSnapshotPath ?? '-' }}</div>
|
|
<x-filament::button size="sm" color="gray" wire:click="generateDevelopmentSnapshot" :disabled="!$supportCanRunUpdate">
|
|
Rigenera snapshot sviluppo
|
|
</x-filament::button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mb-3 rounded-lg border bg-gray-50 p-3 text-[11px] text-gray-700">
|
|
Generata il: <span class="font-medium">{{ $this->developmentSnapshotGeneratedAt ?? '-' }}</span>
|
|
</div>
|
|
|
|
<div class="prose prose-sm max-w-none text-[11px] leading-relaxed">
|
|
{!! $this->developmentSnapshotHtml !!}
|
|
</div>
|
|
</x-filament::section>
|
|
|
|
@foreach($this->manualSections as $section)
|
|
<x-filament::section class="!p-4">
|
|
<div class="mb-2 flex flex-wrap items-start justify-between gap-2">
|
|
<div>
|
|
<div class="text-xs font-semibold text-gray-700">{{ $section['title'] }}</div>
|
|
<div class="mt-1 text-[11px] text-gray-500">{{ $section['description'] }}</div>
|
|
</div>
|
|
<div class="rounded bg-slate-100 px-2 py-1 font-mono text-[10px] text-slate-600">{{ $section['path'] }}</div>
|
|
</div>
|
|
|
|
@if(! $section['exists'])
|
|
<div class="mb-3 rounded border border-amber-300 bg-amber-50 px-3 py-2 text-[11px] text-amber-900">
|
|
Documento non ancora presente nel repository. La sezione e predisposta per essere popolata progressivamente.
|
|
</div>
|
|
@endif
|
|
|
|
<div class="prose prose-sm max-w-none text-[11px] leading-relaxed">
|
|
{!! $section['html'] !!}
|
|
</div>
|
|
</x-filament::section>
|
|
@endforeach
|
|
@endif
|
|
|
|
@if($this->activeTab === 'errori')
|
|
<x-filament::section class="!p-4">
|
|
<div class="mb-3 rounded-lg border border-amber-300 bg-amber-50 p-3 text-[11px] text-amber-900">
|
|
<div class="font-semibold">Uso corretto di questa sezione</div>
|
|
<div class="mt-1">
|
|
Per il nodo staging, il percorso operativo principale e la sync Git da Gitea disponibile in questa tab. I pulsanti piu sotto servono invece al canale <span class="font-semibold">distribution</span>, che al momento non e ancora il flusso update attivo principale e puo restituire errore manifest 404.
|
|
</div>
|
|
</div>
|
|
|
|
<div class="grid gap-3 lg:grid-cols-2">
|
|
<div class="rounded-lg border bg-slate-50 p-3">
|
|
<div class="text-xs font-semibold text-slate-800">Cosa aggiorna il flusso Git di staging</div>
|
|
<div class="mt-2 text-[11px] leading-relaxed text-slate-700">
|
|
Il pulsante <span class="font-semibold">Aggiorna staging da Gitea</span> lancia il comando applicativo <span class="font-mono">netgescon:git-sync</span>. Il nodo si riallinea dal repository Git pubblicato su Gitea, rigenera il changelog automatico e aggiorna questa pagina senza usare deploy manuali fuori Git.
|
|
</div>
|
|
<ol class="mt-3 list-decimal space-y-1 pl-4 text-[11px] text-slate-700">
|
|
<li>fetch e allineamento del branch richiesto da Gitea</li>
|
|
<li>aggiornamento del codice sul nodo staging</li>
|
|
<li>rigenerazione changelog Git per Supporto > Modifiche</li>
|
|
<li>salvataggio esito, log e diagnostica del job</li>
|
|
</ol>
|
|
</div>
|
|
|
|
<div class="rounded-lg border bg-white p-3">
|
|
<div class="flex flex-wrap items-start justify-between gap-2">
|
|
<div>
|
|
<div class="text-xs font-semibold text-gray-700">Anteprima prima della sync Git</div>
|
|
<div class="mt-1 text-[11px] text-gray-500">Conteggio commit remoti, aree toccate e registro persistente delle modifiche gia strutturate.</div>
|
|
</div>
|
|
<x-filament::button size="sm" color="gray" wire:click="reloadDashboardData">
|
|
Ricalcola anteprima
|
|
</x-filament::button>
|
|
</div>
|
|
|
|
<div class="mt-2 grid gap-2 sm:grid-cols-4">
|
|
<div class="rounded-lg border bg-slate-50 p-2">
|
|
<div class="text-[10px] uppercase tracking-wide text-slate-500">Commit in arrivo</div>
|
|
<div class="mt-1 text-lg font-semibold text-slate-800">{{ (int) $this->pendingGitCommitCount }}</div>
|
|
</div>
|
|
<div class="rounded-lg border bg-slate-50 p-2">
|
|
<div class="text-[10px] uppercase tracking-wide text-slate-500">Registro DB visibile</div>
|
|
<div class="mt-1 text-lg font-semibold text-slate-800">{{ (int) $this->supportUpdateVisibleCount }}</div>
|
|
</div>
|
|
<div class="rounded-lg border bg-slate-50 p-2">
|
|
<div class="text-[10px] uppercase tracking-wide text-slate-500">Implementazioni</div>
|
|
<div class="mt-1 text-lg font-semibold text-emerald-700">{{ (int) $this->supportImplementationCount }}</div>
|
|
</div>
|
|
<div class="rounded-lg border bg-slate-50 p-2">
|
|
<div class="text-[10px] uppercase tracking-wide text-slate-500">Fix + debug</div>
|
|
<div class="mt-1 text-lg font-semibold text-amber-700">{{ (int) ($this->supportBugfixCount + $this->supportDebugCount) }}</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-2 grid gap-3 lg:grid-cols-2">
|
|
<div>
|
|
<div class="mb-1 text-[11px] font-semibold text-slate-700">Commit remoti non ancora allineati</div>
|
|
@if(filled($this->pendingGitPreviewIssue))
|
|
<div class="mb-2 rounded border border-amber-300 bg-amber-50 px-2 py-1 text-[10px] text-amber-900">{{ $this->pendingGitPreviewIssue }}</div>
|
|
@endif
|
|
<ul class="space-y-1 text-[11px] text-gray-700">
|
|
@forelse($this->pendingGitCommits as $commit)
|
|
<li class="rounded border bg-slate-50 px-2 py-1">
|
|
<span class="font-mono text-[10px] text-slate-500">{{ $commit['short_hash'] }}</span>
|
|
<span class="ml-1">{{ $commit['message'] }}</span>
|
|
<div class="mt-0.5 text-[10px] text-slate-500">{{ $commit['date'] }} · {{ $commit['author'] }}</div>
|
|
</li>
|
|
@empty
|
|
<li class="rounded border border-emerald-200 bg-emerald-50 px-2 py-1 text-emerald-800">Il nodo risulta gia allineato al branch remoto.</li>
|
|
@endforelse
|
|
</ul>
|
|
</div>
|
|
<div>
|
|
<div class="mb-1 text-[11px] font-semibold text-slate-700">Pagine e aree toccate dai commit in arrivo</div>
|
|
<ul class="space-y-1 text-[11px] text-gray-700">
|
|
@forelse($this->pendingGitChangedAreas as $item)
|
|
<li class="rounded border bg-slate-50 px-2 py-1">
|
|
<div class="font-medium text-slate-800">{{ $item['label'] }}</div>
|
|
<div class="text-[10px] text-slate-500">{{ $item['area'] }} · {{ $item['path'] }}</div>
|
|
</li>
|
|
@empty
|
|
<li class="text-gray-500">Nessuna area Filament/supporto modificata nei commit remoti in attesa.</li>
|
|
@endforelse
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-3 rounded-lg border bg-white p-3">
|
|
<div class="mb-2 flex flex-wrap items-start justify-between gap-2">
|
|
<div>
|
|
<div class="text-xs font-semibold text-gray-700">Registro aggiornamenti persistente in DB</div>
|
|
<div class="mt-1 text-[11px] text-gray-500">Implementazioni, fix e debug registrati in tabella applicativa con pagina impattata e commit di riferimento.</div>
|
|
</div>
|
|
<div class="rounded bg-slate-100 px-2 py-1 text-[10px] font-semibold text-slate-700">
|
|
{{ (int) $this->supportUpdateVisibleCount }} voci visibili
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mb-3 grid gap-3 lg:grid-cols-[0.85fr_1.15fr]">
|
|
<div class="rounded-lg border bg-slate-50 p-3">
|
|
<div class="mb-2 flex flex-wrap items-center justify-between gap-2">
|
|
<div class="text-[11px] font-semibold text-slate-800">Editor voci aggiornamento</div>
|
|
<x-filament::button size="sm" color="gray" wire:click="resetSupportUpdateForm">
|
|
Nuova voce
|
|
</x-filament::button>
|
|
</div>
|
|
|
|
<div class="grid gap-2 sm:grid-cols-2">
|
|
<label class="block">
|
|
<span class="mb-1 block text-[11px] font-medium">Categoria</span>
|
|
<select wire:model="supportUpdateFormCategory" class="w-full rounded-md border-gray-300 text-xs">
|
|
<option value="implementazione">implementazione</option>
|
|
<option value="bugfix">bugfix</option>
|
|
<option value="debug">debug</option>
|
|
</select>
|
|
</label>
|
|
<label class="block">
|
|
<span class="mb-1 block text-[11px] font-medium">Audience</span>
|
|
<select wire:model="supportUpdateFormAudience" class="w-full rounded-md border-gray-300 text-xs">
|
|
<option value="utenti">utenti</option>
|
|
<option value="supporto">supporto</option>
|
|
</select>
|
|
</label>
|
|
</div>
|
|
|
|
<label class="mt-2 block">
|
|
<span class="mb-1 block text-[11px] font-medium">Titolo</span>
|
|
<input type="text" wire:model.defer="supportUpdateFormTitle" class="w-full rounded-md border-gray-300 text-xs" placeholder="Es: Lavagna chiamate con archivio chiusi" />
|
|
</label>
|
|
|
|
<label class="mt-2 block">
|
|
<span class="mb-1 block text-[11px] font-medium">Riepilogo</span>
|
|
<textarea wire:model.defer="supportUpdateFormSummary" rows="3" class="w-full rounded-md border-gray-300 text-xs" placeholder="Cosa cambia davvero per chi aggiorna o usa la funzione"></textarea>
|
|
</label>
|
|
|
|
<label class="mt-2 block">
|
|
<span class="mb-1 block text-[11px] font-medium">Impatto operativo</span>
|
|
<textarea wire:model.defer="supportUpdateFormImpact" rows="2" class="w-full rounded-md border-gray-300 text-xs" placeholder="Perche e importante prima della sync staging"></textarea>
|
|
</label>
|
|
|
|
<div class="mt-2 grid gap-2 sm:grid-cols-2">
|
|
<label class="block">
|
|
<span class="mb-1 block text-[11px] font-medium">Pagina UI</span>
|
|
<input type="text" wire:model.defer="supportUpdateFormPageLabel" class="w-full rounded-md border-gray-300 text-xs" placeholder="Es: Strumenti > Post-it Gestione" />
|
|
</label>
|
|
<label class="block">
|
|
<span class="mb-1 block text-[11px] font-medium">Quando registrata</span>
|
|
<input type="text" wire:model.defer="supportUpdateFormRecordedAt" class="w-full rounded-md border-gray-300 text-xs" placeholder="2026-04-04 11:00" />
|
|
</label>
|
|
</div>
|
|
|
|
<div class="mt-2 grid gap-2 sm:grid-cols-2">
|
|
<label class="block">
|
|
<span class="mb-1 block text-[11px] font-medium">Classe pagina</span>
|
|
<input type="text" wire:model.defer="supportUpdateFormPageClass" class="w-full rounded-md border-gray-300 text-xs" placeholder="App\Filament\Pages\..." />
|
|
</label>
|
|
<label class="block">
|
|
<span class="mb-1 block text-[11px] font-medium">Path collegato</span>
|
|
<input type="text" wire:model.defer="supportUpdateFormRelatedPath" class="w-full rounded-md border-gray-300 text-xs" placeholder="app/Filament/Pages/..." />
|
|
</label>
|
|
</div>
|
|
|
|
<label class="mt-2 block">
|
|
<span class="mb-1 block text-[11px] font-medium">Commit collegato</span>
|
|
<input type="text" wire:model.defer="supportUpdateFormRelatedCommit" class="w-full rounded-md border-gray-300 text-xs" placeholder="short hash o commit completo" />
|
|
</label>
|
|
|
|
<div class="mt-2 flex flex-wrap gap-3 text-[11px]">
|
|
<label class="inline-flex items-center gap-2 rounded-md border bg-white px-2 py-1.5">
|
|
<input type="checkbox" wire:model="supportUpdateFormVisible" class="rounded border-gray-300" />
|
|
Visibile in elenco
|
|
</label>
|
|
<label class="inline-flex items-center gap-2 rounded-md border bg-white px-2 py-1.5">
|
|
<input type="checkbox" wire:model="supportUpdateFormHighlighted" class="rounded border-gray-300" />
|
|
Metti in evidenza
|
|
</label>
|
|
</div>
|
|
|
|
<div class="mt-3 flex flex-wrap gap-2">
|
|
<x-filament::button size="sm" wire:click="saveSupportUpdateEntry">
|
|
Salva voce registro
|
|
</x-filament::button>
|
|
<x-filament::button size="sm" color="gray" wire:click="resetSupportUpdateForm">
|
|
Reset form
|
|
</x-filament::button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="rounded-lg border bg-slate-50 p-3">
|
|
<div class="text-[11px] font-semibold text-slate-800">Come usarlo prima di Git e staging</div>
|
|
<ol class="mt-2 list-decimal space-y-1 pl-4 text-[11px] text-slate-700">
|
|
<li>registra qui implementazioni, fix o debug dell ultimo blocco di lavoro</li>
|
|
<li>collega, se la conosci, la pagina UI e il commit previsto o gia creato</li>
|
|
<li>usa il conteggio commit remoti per controllare se lo staging e davvero indietro</li>
|
|
<li>poi fai il push Git e usa questa stessa tab per la sync da Gitea</li>
|
|
</ol>
|
|
|
|
@if($this->supportUpdateFormId)
|
|
<div class="mt-3 rounded border border-amber-300 bg-amber-50 px-3 py-2 text-[11px] text-amber-900">
|
|
Stai modificando la voce ID {{ $this->supportUpdateFormId }}. Se vuoi inserirne una nuova, premi “Nuova voce”.
|
|
</div>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
|
|
<div class="grid gap-2 lg:grid-cols-2">
|
|
@forelse(array_slice($this->supportUpdateEntries, 0, 8) as $entry)
|
|
<div class="rounded-lg border {{ $entry['is_highlighted'] ? 'border-amber-300 bg-amber-50' : 'bg-slate-50' }} p-3">
|
|
<div class="flex flex-wrap items-start justify-between gap-2">
|
|
<div class="font-semibold text-slate-800">{{ $entry['title'] }}</div>
|
|
<span class="rounded px-1.5 py-0.5 text-[10px] font-semibold uppercase {{ $entry['category'] === 'implementazione' ? 'bg-emerald-100 text-emerald-800' : ($entry['category'] === 'bugfix' ? 'bg-amber-100 text-amber-900' : 'bg-sky-100 text-sky-800') }}">{{ $entry['category'] }}</span>
|
|
</div>
|
|
<div class="mt-1 text-[11px] text-slate-700">{{ $entry['summary'] }}</div>
|
|
@if($entry['impact'] !== '')
|
|
<div class="mt-2 rounded border border-slate-200 bg-white px-2 py-1 text-[10px] text-slate-700">{{ $entry['impact'] }}</div>
|
|
@endif
|
|
<div class="mt-2 flex flex-wrap gap-x-3 gap-y-1 text-[10px] text-slate-500">
|
|
@if($entry['page_label'] !== '')
|
|
<span>Pagina: {{ $entry['page_label'] }}</span>
|
|
@endif
|
|
@if($entry['related_commit'] !== '')
|
|
<span>Commit: <span class="font-mono">{{ $entry['related_commit'] }}</span></span>
|
|
@endif
|
|
@if($entry['recorded_at'] !== '')
|
|
<span>Registrato: {{ $entry['recorded_at'] }}</span>
|
|
@endif
|
|
</div>
|
|
@if($entry['related_path'] !== '' || $entry['page_url'])
|
|
<div class="mt-2 flex flex-wrap gap-2 text-[10px]">
|
|
@if($entry['page_url'])
|
|
<a href="{{ $entry['page_url'] }}" class="text-primary-600 hover:underline">Apri pagina</a>
|
|
@endif
|
|
@if($entry['related_path'] !== '')
|
|
<span class="rounded bg-white px-1.5 py-0.5 font-mono text-slate-600">{{ $entry['related_path'] }}</span>
|
|
@endif
|
|
</div>
|
|
@endif
|
|
<div class="mt-2 flex flex-wrap gap-2">
|
|
<x-filament::button size="xs" color="gray" wire:click="editSupportUpdateEntry({{ (int) $entry['id'] }})">
|
|
Modifica
|
|
</x-filament::button>
|
|
<x-filament::button size="xs" color="{{ $entry['is_visible'] ? 'warning' : 'success' }}" wire:click="toggleSupportUpdateVisibility({{ (int) $entry['id'] }})">
|
|
{{ $entry['is_visible'] ? 'Nascondi' : 'Mostra' }}
|
|
</x-filament::button>
|
|
</div>
|
|
</div>
|
|
@empty
|
|
<div class="rounded border border-dashed px-3 py-4 text-[11px] text-gray-500 lg:col-span-2">Registro DB non ancora disponibile: esegui le migration del nuovo support registry su questo nodo.</div>
|
|
@endforelse
|
|
</div>
|
|
</div>
|
|
|
|
<div class="grid gap-3 lg:grid-cols-[1.15fr_0.85fr]">
|
|
<div class="rounded-lg border bg-gray-50 p-3 lg:col-span-2">
|
|
<div class="mb-2 text-xs font-semibold text-gray-700">Aggiornamento staging da Gitea</div>
|
|
<div class="mb-3 text-[11px] text-gray-600">
|
|
Questo e il flusso principale da usare sui nodi interni: pull da Gitea, rigenerazione changelog Git per la pagina supporto e pulizia cache applicativa. Non richiede terminale.
|
|
</div>
|
|
<div class="mb-3 rounded border border-slate-200 bg-white px-3 py-2 text-[11px] text-slate-700">
|
|
Comando predisposto usato dalla UI: <span class="font-mono">php artisan netgescon:git-sync --remote={{ $this->gitRemote }} --branch={{ $this->gitBranch }}</span>
|
|
</div>
|
|
|
|
<div class="grid gap-2 sm:grid-cols-4">
|
|
<label class="block">
|
|
<span class="mb-1 block text-[11px] font-medium">Remote</span>
|
|
<input type="text" wire:model="gitRemote" class="w-full rounded-md border-gray-300 text-xs" />
|
|
</label>
|
|
<label class="block">
|
|
<span class="mb-1 block text-[11px] font-medium">Branch</span>
|
|
<input type="text" wire:model="gitBranch" class="w-full rounded-md border-gray-300 text-xs" />
|
|
</label>
|
|
<label class="inline-flex items-center gap-2 rounded-md border bg-white px-2 py-1.5 text-[11px] sm:mt-6">
|
|
<input type="checkbox" wire:model="gitForce" class="rounded border-gray-300" />
|
|
Force con working tree sporco
|
|
</label>
|
|
</div>
|
|
|
|
<div class="mt-3 flex flex-wrap gap-2">
|
|
<x-filament::button size="sm" wire:click="runGitSync" :disabled="!$supportCanRunUpdate">
|
|
Aggiorna staging da Gitea
|
|
</x-filament::button>
|
|
<x-filament::button size="sm" color="info" wire:click="refreshGitSyncProgress" :disabled="!$this->gitSyncInProgress">
|
|
Aggiorna avanzamento Git
|
|
</x-filament::button>
|
|
<x-filament::button size="sm" color="gray" wire:click="reloadDashboardData">
|
|
Rileggi stato Git
|
|
</x-filament::button>
|
|
</div>
|
|
|
|
@if($this->gitSyncInProgress)
|
|
<div class="mt-3 rounded-lg border bg-white p-3" wire:poll.2s="refreshGitSyncProgress">
|
|
@else
|
|
<div class="mt-3 rounded-lg border bg-white p-3">
|
|
@endif
|
|
<div class="mb-1 flex items-center justify-between text-[11px] text-gray-600">
|
|
<span class="font-semibold">Avanzamento sync Git</span>
|
|
<span class="font-mono">{{ (int) $this->gitSyncProgressPercent }}%</span>
|
|
</div>
|
|
<div class="h-2 w-full overflow-hidden rounded bg-gray-200">
|
|
<div class="h-2 {{ $this->gitSyncProgressStatus === 'failed' ? 'bg-rose-500' : 'bg-emerald-500' }}" style="width: {{ max(0, min(100, (int) $this->gitSyncProgressPercent)) }}%"></div>
|
|
</div>
|
|
<div class="mt-1 text-[11px] text-gray-600">{{ $this->gitSyncProgressMessage }}</div>
|
|
<div class="mt-1 text-[10px] text-gray-500">
|
|
Job: <span class="font-mono">{{ $this->gitSyncJobId ?? '-' }}</span>
|
|
· Stato: <span class="font-semibold">{{ $this->gitSyncProgressStatus }}</span>
|
|
@if($this->gitSyncInProgress)
|
|
· in esecuzione
|
|
@endif
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="rounded-lg border bg-white p-3">
|
|
<div class="text-xs font-semibold text-gray-700">Stato repository nodo</div>
|
|
<div class="mt-2 space-y-1 text-[11px] text-gray-600">
|
|
<div>Branch locale: <span class="font-mono font-medium">{{ $this->gitCurrentBranch ?? '-' }}</span></div>
|
|
<div>Commit locale: <span class="font-mono font-medium">{{ $this->gitCurrentCommit ?? '-' }}</span></div>
|
|
<div>Commit remoto: <span class="font-mono font-medium">{{ $this->gitRemoteCommit ?? '-' }}</span></div>
|
|
<div>Stato tracking: <span class="font-medium">{{ $this->gitAheadBehind }}</span></div>
|
|
<div>
|
|
Working tree:
|
|
<span class="font-medium {{ $this->gitWorkingTreeDirty ? 'text-rose-700' : 'text-emerald-700' }}">{{ $this->gitWorkingTreeDirty ? 'sporco' : 'pulito' }}</span>
|
|
</div>
|
|
<div>Ultima sync Git: <span class="font-medium">{{ $this->lastGitSyncAt ?? '-' }}</span></div>
|
|
<div>Rigenerazione changelog locale: <span class="font-medium">{{ $this->lastGitDocsSyncAt ?? '-' }}</span></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="rounded-lg border bg-white p-3">
|
|
<div class="text-xs font-semibold text-gray-700">Esito ultima sync Git</div>
|
|
<div class="mt-2 space-y-1 text-[11px] text-gray-600">
|
|
<div>Comando: <span class="font-mono font-medium">netgescon:git-sync</span></div>
|
|
<div>
|
|
Exit code:
|
|
@if($this->lastGitSyncExitCode === null)
|
|
<span class="font-medium">-</span>
|
|
@elseif($this->lastGitSyncExitCode === 0)
|
|
<span class="rounded bg-emerald-100 px-1.5 py-0.5 font-semibold text-emerald-800">0 OK</span>
|
|
@else
|
|
<span class="rounded bg-rose-100 px-1.5 py-0.5 font-semibold text-rose-800">{{ $this->lastGitSyncExitCode }} ERRORE</span>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
@if(filled($this->lastGitSyncIssue))
|
|
<div class="mt-3 rounded border border-amber-300 bg-amber-50 px-2 py-2 text-[11px] text-amber-900">
|
|
{{ $this->lastGitSyncIssue }}
|
|
</div>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
|
|
@if(filled($this->lastGitSyncOutput))
|
|
<div class="mt-3 rounded-lg border bg-slate-950 p-3">
|
|
<div class="mb-1 text-[11px] font-semibold text-slate-200">Output tecnico sync Git</div>
|
|
<pre class="max-h-64 overflow-auto whitespace-pre-wrap text-[11px] leading-relaxed text-slate-100">{{ $this->lastGitSyncOutput }}</pre>
|
|
</div>
|
|
@endif
|
|
|
|
<div class="grid gap-3 lg:grid-cols-3">
|
|
<div class="rounded-lg border bg-gray-50 p-3 lg:col-span-2">
|
|
<div class="mb-2 text-xs font-semibold text-gray-700">Aggiornamento da server distribution</div>
|
|
<div class="mb-3 text-[11px] text-gray-500">
|
|
Usare questi pulsanti solo quando il server <span class="font-mono">updates.netgescon.it</span> espone correttamente il manifest update. Per staging standard usare il flusso Git/Gitea mostrato sopra in questa stessa tab.
|
|
</div>
|
|
<div class="grid gap-2 sm:grid-cols-3">
|
|
<label class="block">
|
|
<span class="mb-1 block text-[11px] font-medium">Canale</span>
|
|
<select wire:model="updateChannel" class="w-full rounded-md border-gray-300 text-xs">
|
|
<option value="free">free</option>
|
|
<option value="licensed">licensed</option>
|
|
</select>
|
|
</label>
|
|
<label class="inline-flex items-center gap-2 rounded-md border bg-white px-2 py-1.5 text-[11px]">
|
|
<input type="checkbox" wire:model="updateDryRun" class="rounded border-gray-300" />
|
|
Dry run
|
|
</label>
|
|
<label class="inline-flex items-center gap-2 rounded-md border bg-white px-2 py-1.5 text-[11px]">
|
|
<input type="checkbox" wire:model="updateForce" class="rounded border-gray-300" />
|
|
Force
|
|
</label>
|
|
</div>
|
|
|
|
<div class="mt-2">
|
|
<label class="inline-flex items-center gap-2 rounded-md border border-amber-300 bg-amber-50 px-2 py-1.5 text-[11px] text-amber-900">
|
|
<input type="checkbox" wire:model="updateSkipBackup" class="rounded border-gray-300" />
|
|
Salta backup pre-update solo per test/debug su staging
|
|
</label>
|
|
</div>
|
|
|
|
<div class="mt-3 flex flex-wrap gap-2">
|
|
<x-filament::button size="sm" wire:click="runUpdate" :disabled="!$supportCanRunUpdate">
|
|
Lancia aggiornamento
|
|
</x-filament::button>
|
|
<x-filament::button size="sm" color="warning" wire:click="runUpdateFallback" :disabled="!$supportCanRunUpdate">
|
|
Lancia aggiornamento (riserva)
|
|
</x-filament::button>
|
|
<x-filament::button size="sm" color="info" wire:click="runUpdateConnectivityCheck">
|
|
Check connettivita update
|
|
</x-filament::button>
|
|
<x-filament::button size="sm" color="gray" wire:click="reloadDashboardData">
|
|
Aggiorna dati pagina
|
|
</x-filament::button>
|
|
<x-filament::button size="sm" color="gray" wire:click="runMaintenanceOptimizeClear" :disabled="!$supportCanRunUpdate">
|
|
Pulisci cache remoto
|
|
</x-filament::button>
|
|
<x-filament::button size="sm" color="gray" wire:click="runMaintenanceViewRebuild" :disabled="!$supportCanRunUpdate">
|
|
Ricompila view remoto
|
|
</x-filament::button>
|
|
<x-filament::button size="sm" color="gray" wire:click="refreshUpdateProgress" :disabled="!$this->updateInProgress">
|
|
Aggiorna avanzamento
|
|
</x-filament::button>
|
|
</div>
|
|
|
|
@if($this->updateInProgress)
|
|
<div class="mt-3 rounded-lg border bg-white p-3" wire:poll.2s="refreshUpdateProgress">
|
|
@else
|
|
<div class="mt-3 rounded-lg border bg-white p-3">
|
|
@endif
|
|
<div class="mb-1 flex items-center justify-between text-[11px] text-gray-600">
|
|
<span class="font-semibold">Avanzamento aggiornamento</span>
|
|
<span class="font-mono">{{ (int) $this->updateProgressPercent }}%</span>
|
|
</div>
|
|
<div class="h-2 w-full overflow-hidden rounded bg-gray-200">
|
|
<div class="h-2 {{ $this->updateProgressStatus === 'failed' ? 'bg-rose-500' : 'bg-emerald-500' }}" style="width: {{ max(0, min(100, (int) $this->updateProgressPercent)) }}%"></div>
|
|
</div>
|
|
<div class="mt-1 text-[11px] text-gray-600">{{ $this->updateProgressMessage }}</div>
|
|
<div class="mt-1 text-[10px] text-gray-500">
|
|
Job: <span class="font-mono">{{ $this->updateJobId ?? '-' }}</span>
|
|
· Stato: <span class="font-semibold">{{ $this->updateProgressStatus }}</span>
|
|
@if($this->updateInProgress)
|
|
· in esecuzione
|
|
@endif
|
|
</div>
|
|
</div>
|
|
|
|
@if(! $supportCanRunUpdate)
|
|
<div class="mt-2 text-[11px] text-amber-700">Permesso update non disponibile per il tuo ruolo.</div>
|
|
@endif
|
|
</div>
|
|
|
|
<div class="rounded-lg border bg-white p-3">
|
|
<div class="text-xs font-semibold text-gray-700">Esito ultimo update</div>
|
|
<div class="mt-2 space-y-1 text-[11px] text-gray-600">
|
|
<div>Ultima esecuzione: <span class="font-medium">{{ $this->lastUpdateAt ?? '-' }}</span></div>
|
|
<div>
|
|
Exit code:
|
|
@if($this->lastUpdateExitCode === null)
|
|
<span class="font-medium">-</span>
|
|
@elseif($this->lastUpdateExitCode === 0)
|
|
<span class="rounded bg-emerald-100 px-1.5 py-0.5 font-semibold text-emerald-800">0 OK</span>
|
|
@else
|
|
<span class="rounded bg-rose-100 px-1.5 py-0.5 font-semibold text-rose-800">{{ $this->lastUpdateExitCode }} ERRORE</span>
|
|
@endif
|
|
</div>
|
|
@if(filled($this->lastPlannedUpdateSummary))
|
|
<div class="rounded bg-slate-50 px-2 py-1 text-[10px] text-slate-600">
|
|
Piano usato: {{ $this->lastPlannedUpdateSummary }}
|
|
</div>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-3 grid gap-3 lg:grid-cols-2">
|
|
<div class="rounded-lg border bg-white p-3">
|
|
<div class="text-xs font-semibold text-gray-700">Ultimo backup pronto per update</div>
|
|
@if($this->latestBackupSummary)
|
|
<div class="mt-2 space-y-1 text-[11px] text-gray-600">
|
|
<div>Snapshot: <span class="font-mono">{{ $this->latestBackupSummary['snapshot_id'] }}</span></div>
|
|
<div>Creato: <span class="font-medium">{{ $this->latestBackupSummary['created_at'] }}</span></div>
|
|
<div>Copia locale: <span class="font-medium {{ $this->latestBackupSummary['zip_exists'] ? 'text-emerald-700' : 'text-rose-700' }}">{{ $this->latestBackupSummary['zip_exists'] ? 'OK' : 'mancante' }}</span></div>
|
|
<div>ZIP: <span class="break-all font-mono">{{ $this->latestBackupSummary['zip_path'] ?: '-' }}</span></div>
|
|
<div>Dimensione: <span class="font-medium">{{ $this->latestBackupSummary['zip_size_mb'] !== null ? number_format((float) $this->latestBackupSummary['zip_size_mb'], 2, ',', '.') . ' MB' : '-' }}</span></div>
|
|
<div>File copiati: <span class="font-medium">{{ (int) $this->latestBackupSummary['copied_files'] }}</span> · Tabelle indicizzate: <span class="font-medium">{{ (int) $this->latestBackupSummary['tables_count'] }}</span></div>
|
|
<div>
|
|
Copia Google Drive:
|
|
@if(is_array($this->latestBackupSummary['drive'] ?? null))
|
|
<span class="font-medium text-emerald-700">OK</span>
|
|
@if(!empty($this->latestBackupSummary['drive']['webViewLink']))
|
|
<a href="{{ $this->latestBackupSummary['drive']['webViewLink'] }}" target="_blank" class="ml-1 text-primary-600 hover:underline">Apri su Drive</a>
|
|
@endif
|
|
@else
|
|
<span class="font-medium text-rose-700">non disponibile</span>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
@else
|
|
<div class="mt-2 text-[11px] text-gray-500">Nessun backup pre-update registrato.</div>
|
|
@endif
|
|
</div>
|
|
|
|
<div class="rounded-lg border bg-white p-3">
|
|
<div class="text-xs font-semibold text-gray-700">Anteprima pacchetto in arrivo</div>
|
|
@if($this->lastManifestPreview)
|
|
<div class="mt-2 space-y-1 text-[11px] text-gray-600">
|
|
<div>Versione remota: <span class="font-semibold">{{ $this->lastManifestPreview['version'] }}</span></div>
|
|
<div>Migration richieste: <span class="font-medium {{ $this->lastManifestPreview['migrate_required'] ? 'text-amber-700' : 'text-emerald-700' }}">{{ $this->lastManifestPreview['migrate_required'] ? 'si' : 'no' }}</span></div>
|
|
<div>Pacchetto: <span class="break-all font-mono">{{ $this->lastManifestPreview['package_url'] }}</span></div>
|
|
<div>SHA256: <span class="break-all font-mono">{{ $this->lastManifestPreview['sha256'] }}</span></div>
|
|
@if(filled($this->lastManifestPreview['release_notes'] ?? null))
|
|
<div class="rounded bg-slate-50 px-2 py-1 text-[10px] text-slate-700">{{ $this->lastManifestPreview['release_notes'] }}</div>
|
|
@endif
|
|
@if(!empty($this->lastManifestPreview['security']))
|
|
<div class="rounded border border-amber-300 bg-amber-50 px-2 py-1 text-[10px] text-amber-900">
|
|
Aggiornamenti sicurezza: {{ is_array($this->lastManifestPreview['security']) ? json_encode($this->lastManifestPreview['security'], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) : $this->lastManifestPreview['security'] }}
|
|
</div>
|
|
@endif
|
|
</div>
|
|
@else
|
|
<div class="mt-2 text-[11px] text-gray-500">Esegui “Check connettivita update” per leggere manifest e contenuto dell aggiornamento prima del lancio.</div>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-3 rounded-lg border bg-blue-50 p-3">
|
|
<div class="mb-1 text-[11px] font-semibold text-blue-900">Aggiornamenti pianificati (prima del lancio)</div>
|
|
<ul class="list-disc space-y-1 pl-4 text-[11px] text-blue-900">
|
|
@foreach($this->updatePlannedSteps as $step)
|
|
<li>{{ $step }}</li>
|
|
@endforeach
|
|
</ul>
|
|
|
|
<div class="mt-3 rounded border border-blue-200 bg-white p-2 text-[11px] text-blue-900">
|
|
<div class="font-semibold">Ripristino differenziale disponibile</div>
|
|
<div class="mt-1">Ripristino singola scrittura:</div>
|
|
<pre class="mt-1 overflow-auto whitespace-pre-wrap rounded bg-slate-950 p-2 text-[10px] text-slate-100">php artisan netgescon:restore-record <tabella> <pk> --apply</pre>
|
|
<div class="mt-1">Preview senza scrivere:</div>
|
|
<pre class="mt-1 overflow-auto whitespace-pre-wrap rounded bg-slate-950 p-2 text-[10px] text-slate-100">php artisan netgescon:restore-record <tabella> <pk></pre>
|
|
</div>
|
|
</div>
|
|
|
|
@if(filled($this->lastUpdateOutput))
|
|
<div class="mt-3 rounded-lg border bg-slate-950 p-3">
|
|
<div class="mb-1 text-[11px] font-semibold text-slate-200">Output tecnico</div>
|
|
<pre class="max-h-64 overflow-auto whitespace-pre-wrap text-[11px] leading-relaxed text-slate-100">{{ $this->lastUpdateOutput }}</pre>
|
|
</div>
|
|
@endif
|
|
|
|
@if(filled($this->lastUpdateIssue))
|
|
<div class="mt-3 rounded-lg border border-amber-300 bg-amber-50 p-3 text-[11px] text-amber-900">
|
|
<div class="font-semibold">Diagnostica automatica ultimo errore</div>
|
|
<div class="mt-1">{{ $this->lastUpdateIssue }}</div>
|
|
</div>
|
|
@endif
|
|
|
|
@if(filled($this->lastConnectivityCheckOutput))
|
|
<div class="mt-3 rounded-lg border bg-slate-100 p-3">
|
|
<div class="mb-1 text-[11px] font-semibold text-slate-700">Output check connettivita endpoint update</div>
|
|
<pre class="max-h-52 overflow-auto whitespace-pre-wrap text-[11px] text-slate-700">{{ $this->lastConnectivityCheckOutput }}</pre>
|
|
</div>
|
|
@endif
|
|
</x-filament::section>
|
|
|
|
<x-filament::section class="!p-4">
|
|
<div class="mb-2 text-xs font-semibold text-gray-700">Errori runtime, supporto e pregressi (laravel.log)</div>
|
|
<div class="mb-2 text-[11px] text-gray-500">Raccolta unificata da: <code>runtime-errors.ndjson</code>, <code>support-events.ndjson</code>, <code>laravel.log</code>, <code>docs/support/online-runtime-errors.ndjson</code> (feed Git da online).</div>
|
|
|
|
<div class="mb-2 flex flex-wrap items-center gap-2 text-[11px]">
|
|
<span class="rounded bg-rose-100 px-2 py-1 font-semibold text-rose-800">Aperti: {{ (int) $this->openBugCount }}</span>
|
|
<span class="rounded bg-emerald-100 px-2 py-1 font-semibold text-emerald-800">Risolti: {{ (int) $this->resolvedBugCount }}</span>
|
|
<span class="ml-2 text-gray-500">Filtro:</span>
|
|
<button type="button" wire:click="setBugFilterStatus('all')" class="rounded px-2 py-1 {{ $this->bugFilterStatus === 'all' ? 'bg-slate-800 text-white' : 'bg-slate-100 text-slate-700' }}">Tutti</button>
|
|
<button type="button" wire:click="setBugFilterStatus('open')" class="rounded px-2 py-1 {{ $this->bugFilterStatus === 'open' ? 'bg-slate-800 text-white' : 'bg-slate-100 text-slate-700' }}">Aperti</button>
|
|
<button type="button" wire:click="setBugFilterStatus('resolved')" class="rounded px-2 py-1 {{ $this->bugFilterStatus === 'resolved' ? 'bg-slate-800 text-white' : 'bg-slate-100 text-slate-700' }}">Risolti</button>
|
|
</div>
|
|
|
|
<div class="mb-3 grid gap-3 lg:grid-cols-2">
|
|
<div class="rounded-lg border bg-gray-50 p-3">
|
|
<div class="mb-2 text-[11px] font-semibold text-gray-700">Aggiungi BUG manuale</div>
|
|
<label class="mb-2 block">
|
|
<span class="mb-1 block text-[11px] font-medium">Titolo</span>
|
|
<input type="text" wire:model.defer="manualBugTitle" class="w-full rounded-md border-gray-300 text-xs" placeholder="Es: Duplicati ricerca rubrica universale" />
|
|
</label>
|
|
<label class="block">
|
|
<span class="mb-1 block text-[11px] font-medium">Dettagli</span>
|
|
<textarea wire:model.defer="manualBugDetails" rows="3" class="w-full rounded-md border-gray-300 text-xs" placeholder="URL, cosa succede, risultato atteso, eventuale stabile/codice"></textarea>
|
|
</label>
|
|
<div class="mt-2">
|
|
<x-filament::button size="sm" wire:click="createManualBug">Crea BUG manuale</x-filament::button>
|
|
</div>
|
|
</div>
|
|
|
|
@if($this->highlightedBug)
|
|
<div class="rounded-lg border border-amber-300 bg-amber-50 p-3">
|
|
<div class="flex flex-wrap items-start justify-between gap-2">
|
|
<div>
|
|
<div class="text-[11px] font-semibold text-amber-900">BUG in evidenza</div>
|
|
<div class="mt-1 text-lg font-semibold text-slate-900">{{ $this->highlightedBug['bug_code'] }}</div>
|
|
</div>
|
|
<div class="flex flex-wrap gap-2 text-[10px]">
|
|
<span class="rounded bg-white px-2 py-1 font-semibold text-slate-700">Occorrenze {{ (int) ($this->highlightedBug['occurrences'] ?? 1) }}</span>
|
|
<span class="rounded px-2 py-1 font-semibold {{ ($this->highlightedBug['bug_status'] ?? 'open') === 'resolved' ? 'bg-emerald-100 text-emerald-800' : 'bg-rose-100 text-rose-800' }}">{{ ($this->highlightedBug['bug_status'] ?? 'open') === 'resolved' ? 'risolto' : 'aperto' }}</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-2 rounded border border-amber-200 bg-white px-3 py-2">
|
|
<div class="text-[11px] font-semibold text-slate-700">Messaggio</div>
|
|
<div class="mt-1 text-[11px] text-slate-800">{{ $this->highlightedBug['message'] }}</div>
|
|
</div>
|
|
|
|
<div class="mt-2 grid gap-2 lg:grid-cols-2">
|
|
<div class="rounded border border-amber-200 bg-white px-3 py-2">
|
|
<div class="text-[11px] font-semibold text-slate-700">Contesto</div>
|
|
<div class="mt-1 whitespace-pre-wrap break-words text-[10px] text-slate-700">{{ $this->highlightedBug['context'] !== '' ? $this->highlightedBug['context'] : '-' }}</div>
|
|
</div>
|
|
<div class="rounded border border-amber-200 bg-white px-3 py-2">
|
|
<div class="text-[11px] font-semibold text-slate-700">Nota risoluzione</div>
|
|
<label class="mt-1 block">
|
|
<textarea wire:model.defer="bugResolutionNote" rows="5" class="w-full rounded-md border-gray-300 text-xs" placeholder="Es: risolto con fix parser X, migration Y, deploy Z"></textarea>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
@if(filled($this->highlightedBugHint))
|
|
<div class="mt-2 rounded border border-sky-200 bg-sky-50 px-3 py-2 text-[11px] text-sky-900">{{ $this->highlightedBugHint }}</div>
|
|
@endif
|
|
|
|
@if($this->lastNotificationSanitization)
|
|
<div class="mt-2 rounded border border-slate-200 bg-white px-3 py-2 text-[11px] text-slate-700">
|
|
Ultima sanificazione notifiche Filament: <span class="font-semibold">{{ $this->lastNotificationSanitization['timestamp'] ?? '-' }}</span>
|
|
· rimossi <span class="font-semibold">{{ (int) ($this->lastNotificationSanitization['removed_items'] ?? 0) }}</span>
|
|
· rimasti <span class="font-semibold">{{ (int) ($this->lastNotificationSanitization['remaining_items'] ?? 0) }}</span>
|
|
</div>
|
|
@endif
|
|
|
|
<div class="mt-3 flex flex-wrap gap-2">
|
|
<x-filament::button size="sm" color="gray" wire:click="selectBugForResolution('{{ $this->highlightedBug['fingerprint'] }}')">Seleziona BUG</x-filament::button>
|
|
<x-filament::button size="sm" color="primary" wire:click="saveBugResolutionNote">Salva nota risoluzione</x-filament::button>
|
|
@if(($this->highlightedBug['bug_status'] ?? 'open') === 'resolved')
|
|
<x-filament::button size="sm" color="warning" wire:click="reopenBug('{{ $this->highlightedBug['fingerprint'] }}')">Riapri</x-filament::button>
|
|
@else
|
|
<x-filament::button size="sm" color="success" wire:click="markBugResolved('{{ $this->highlightedBug['fingerprint'] }}')">Segna risolto</x-filament::button>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
@else
|
|
<div class="rounded-lg border border-dashed bg-gray-50 p-3 text-[11px] text-gray-500">
|
|
Nessun BUG da mettere in evidenza.
|
|
</div>
|
|
@endif
|
|
</div>
|
|
|
|
<div class="overflow-x-auto">
|
|
<table class="min-w-full border-collapse border text-[11px]">
|
|
<thead>
|
|
<tr class="bg-slate-100 text-slate-700">
|
|
<th class="border px-2 py-1.5 text-left">BUG #</th>
|
|
<th class="border px-2 py-1.5 text-left">Stato</th>
|
|
<th class="border px-2 py-1.5 text-left">Timestamp</th>
|
|
<th class="border px-2 py-1.5 text-left">Origine</th>
|
|
<th class="border px-2 py-1.5 text-left">Tipo</th>
|
|
<th class="border px-2 py-1.5 text-left">Occorrenze</th>
|
|
<th class="border px-2 py-1.5 text-left">Messaggio</th>
|
|
<th class="border px-2 py-1.5 text-left">Contesto</th>
|
|
<th class="border px-2 py-1.5 text-left">Nota risoluzione</th>
|
|
<th class="border px-2 py-1.5 text-left">Azioni</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@forelse($this->runtimeErrors as $row)
|
|
<tr class="hover:bg-slate-50 {{ ($row['bug_code'] ?? '') === 'BUG-0033' ? 'bg-amber-50' : '' }} {{ ($row['fingerprint'] ?? '') === ($this->selectedBugFingerprint ?? '') ? 'ring-1 ring-primary-300' : '' }}">
|
|
<td class="border px-2 py-1.5 font-mono font-semibold">{{ $row['bug_code'] }}</td>
|
|
<td class="border px-2 py-1.5">
|
|
@if(($row['bug_status'] ?? 'open') === 'resolved')
|
|
<span class="rounded bg-emerald-100 px-1.5 py-0.5 font-semibold text-emerald-800">risolto</span>
|
|
@else
|
|
<span class="rounded bg-rose-100 px-1.5 py-0.5 font-semibold text-rose-800">aperto</span>
|
|
@endif
|
|
</td>
|
|
<td class="border px-2 py-1.5 whitespace-nowrap">{{ $row['timestamp'] }}</td>
|
|
<td class="border px-2 py-1.5">{{ $row['source'] ?? '-' }}</td>
|
|
<td class="border px-2 py-1.5">{{ $row['type'] }}</td>
|
|
<td class="border px-2 py-1.5">
|
|
<span class="rounded {{ (int) ($row['occurrences'] ?? 1) >= 20 ? 'bg-amber-100 text-amber-900' : 'bg-slate-100 text-slate-700' }} px-1.5 py-0.5 font-semibold">{{ (int) ($row['occurrences'] ?? 1) }}</span>
|
|
</td>
|
|
<td class="border px-2 py-1.5">{{ $row['message'] }}</td>
|
|
<td class="border px-2 py-1.5">
|
|
<div class="max-w-[420px] break-words text-[10px] text-gray-700">{{ $row['context'] !== '' ? \Illuminate\Support\Str::limit($row['context'], 220) : '-' }}</div>
|
|
</td>
|
|
<td class="border px-2 py-1.5">
|
|
<div class="max-w-[260px] break-words text-[10px] text-gray-700">{{ $row['resolution_note'] !== '' ? \Illuminate\Support\Str::limit($row['resolution_note'], 160) : '-' }}</div>
|
|
@if(($row['bug_status'] ?? 'open') === 'resolved' && filled($row['resolved_at']))
|
|
<div class="mt-1 text-[10px] text-emerald-700">risolto: {{ $row['resolved_at'] }}</div>
|
|
@endif
|
|
</td>
|
|
<td class="border px-2 py-1.5">
|
|
<x-filament::button size="xs" color="gray" type="button" wire:click="selectBugForResolution('{{ $row['fingerprint'] }}')">Apri nota</x-filament::button>
|
|
@if(($row['bug_status'] ?? 'open') === 'resolved')
|
|
<x-filament::button size="xs" color="warning" type="button" wire:click="reopenBug('{{ $row['fingerprint'] }}')">Riapri</x-filament::button>
|
|
@else
|
|
<x-filament::button size="xs" color="success" type="button" wire:click="markBugResolved('{{ $row['fingerprint'] }}')">Segna risolto</x-filament::button>
|
|
@endif
|
|
</td>
|
|
</tr>
|
|
@empty
|
|
<tr>
|
|
<td colspan="10" class="border px-2 py-3 text-center text-gray-500">Nessun errore registrato negli ultimi eventi.</td>
|
|
</tr>
|
|
@endforelse
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</x-filament::section>
|
|
@endif
|
|
|
|
@if($this->activeTab === 'commit')
|
|
<x-filament::section class="!p-4">
|
|
<div class="mb-2 text-xs font-semibold text-gray-700">Ultimi commit (descrizioni)</div>
|
|
|
|
<div class="mb-3 rounded-lg border bg-gray-50 p-3">
|
|
<div class="mb-2 text-[11px] font-semibold text-gray-700">Aggiungi nota operativa a un commit</div>
|
|
<div class="grid gap-2 sm:grid-cols-2">
|
|
<label class="block">
|
|
<span class="mb-1 block text-[11px] font-medium">Commit</span>
|
|
<select wire:model="selectedCommitHash" wire:change="onSelectedCommitHashUpdated" class="w-full rounded-md border-gray-300 text-xs">
|
|
<option value="">Seleziona commit</option>
|
|
@foreach($this->latestCommits as $c)
|
|
<option value="{{ $c['hash'] }}">{{ $c['short_hash'] }} - {{ $c['message'] }}</option>
|
|
@endforeach
|
|
</select>
|
|
</label>
|
|
<label class="block sm:col-span-2">
|
|
<span class="mb-1 block text-[11px] font-medium">Nota aggiuntiva</span>
|
|
<textarea wire:model.defer="newCommitNote" rows="3" class="w-full rounded-md border-gray-300 text-xs" placeholder="Es: Fix runtime error page X, aggiunta diagnostica update timeout, ecc."></textarea>
|
|
</label>
|
|
</div>
|
|
<div class="mt-2">
|
|
<x-filament::button size="sm" wire:click="saveCommitNote">Salva nota commit</x-filament::button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="overflow-x-auto">
|
|
<table class="min-w-full border-collapse border text-[11px]">
|
|
<thead>
|
|
<tr class="bg-slate-100 text-slate-700">
|
|
<th class="border px-2 py-1.5 text-left">Data</th>
|
|
<th class="border px-2 py-1.5 text-left">Commit</th>
|
|
<th class="border px-2 py-1.5 text-left">Autore</th>
|
|
<th class="border px-2 py-1.5 text-left">Descrizione</th>
|
|
<th class="border px-2 py-1.5 text-left">Nota aggiuntiva</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@forelse($this->latestCommits as $commit)
|
|
<tr class="hover:bg-slate-50">
|
|
<td class="border px-2 py-1.5 whitespace-nowrap">{{ $commit['date'] }}</td>
|
|
<td class="border px-2 py-1.5 font-mono">{{ $commit['short_hash'] }}</td>
|
|
<td class="border px-2 py-1.5">{{ $commit['author'] }}</td>
|
|
<td class="border px-2 py-1.5">{{ $commit['message'] }}</td>
|
|
<td class="border px-2 py-1.5">
|
|
<div class="max-w-[380px] break-words text-[11px] {{ $this->getCommitNote($commit['hash']) !== '' ? 'text-slate-800' : 'text-gray-400' }}">{{ $this->getCommitNote($commit['hash']) !== '' ? $this->getCommitNote($commit['hash']) : '-' }}</div>
|
|
</td>
|
|
</tr>
|
|
@empty
|
|
<tr>
|
|
<td colspan="5" class="border px-2 py-3 text-center text-gray-500">Nessun commit disponibile.</td>
|
|
</tr>
|
|
@endforelse
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</x-filament::section>
|
|
@endif
|
|
|
|
@php
|
|
$path = base_path('docs/NETGESCON-MODIFICHE.md');
|
|
$raw = file_exists($path) ? file_get_contents($path) : "# Modifiche\n\nFile non trovato: {$path}\n";
|
|
|
|
$gitGeneratedPath = storage_path('app/support/generated/NETGESCON-GIT-AUTOCHANGELOG.md');
|
|
$gitPath = file_exists($gitGeneratedPath) ? $gitGeneratedPath : base_path('docs/NETGESCON-GIT-AUTOCHANGELOG.md');
|
|
$gitRaw = file_exists($gitPath) ? file_get_contents($gitPath) : "# Git Auto Changelog\n\nFile non trovato: {$gitPath}\nEsegui: `bash scripts/ops/netgescon-sync-git-changelog.sh`\n";
|
|
|
|
$rawHtml = $this->renderSupportMarkdown($raw);
|
|
$gitRawHtml = $this->renderSupportMarkdown($gitRaw);
|
|
@endphp
|
|
|
|
@if($this->activeTab === 'migliorie')
|
|
<x-filament::section class="!p-4">
|
|
<div class="mb-2 text-xs font-semibold text-gray-700">Pagine nuove o rese piu funzionali (ultimi commit)</div>
|
|
<div class="overflow-x-auto">
|
|
<table class="min-w-full border-collapse border text-[11px]">
|
|
<thead>
|
|
<tr class="bg-slate-100 text-slate-700">
|
|
<th class="border px-2 py-1.5 text-left">Pagina</th>
|
|
<th class="border px-2 py-1.5 text-left">Percorso</th>
|
|
<th class="border px-2 py-1.5 text-left">Commit</th>
|
|
<th class="border px-2 py-1.5 text-left">Descrizione</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@forelse($this->recentFilamentPages as $row)
|
|
<tr class="hover:bg-slate-50">
|
|
<td class="border px-2 py-1.5 font-medium">{{ $row['page'] }}</td>
|
|
<td class="border px-2 py-1.5 font-mono text-[10px]">{{ $row['path'] }}</td>
|
|
<td class="border px-2 py-1.5 font-mono">{{ $row['commit'] }}</td>
|
|
<td class="border px-2 py-1.5">{{ $row['message'] }}</td>
|
|
</tr>
|
|
@empty
|
|
<tr>
|
|
<td colspan="4" class="border px-2 py-3 text-center text-gray-500">Nessuna pagina recente rilevata dai commit.</td>
|
|
</tr>
|
|
@endforelse
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</x-filament::section>
|
|
|
|
<x-filament::section class="!p-4">
|
|
<div class="mb-2 text-xs font-semibold text-gray-700">Migliorie e funzionalita aggiunte (estratte dal registro)</div>
|
|
<div class="rounded-lg border bg-gray-50 p-3">
|
|
<ul class="list-disc space-y-1 pl-4 text-[11px] text-gray-700">
|
|
@forelse($this->functionalHighlights as $item)
|
|
<li>{{ $item }}</li>
|
|
@empty
|
|
<li>Nessuna miglioria rilevata automaticamente nel file modifiche.</li>
|
|
@endforelse
|
|
</ul>
|
|
</div>
|
|
</x-filament::section>
|
|
|
|
<x-filament::section class="!p-4">
|
|
<div class="mb-2 text-xs font-semibold text-gray-700">Registro funzionale (manuale)</div>
|
|
<div class="prose prose-sm max-w-none text-[11px] leading-relaxed">
|
|
{!! $rawHtml !!}
|
|
</div>
|
|
</x-filament::section>
|
|
|
|
<x-filament::section class="!p-4">
|
|
<div class="mb-2 text-xs font-semibold text-gray-700">Changelog automatico da script</div>
|
|
<div class="prose prose-sm max-w-none text-[11px] leading-relaxed">
|
|
{!! $gitRawHtml !!}
|
|
</div>
|
|
</x-filament::section>
|
|
@endif
|
|
</div>
|
|
</div>
|