versione 2.0.0

This commit is contained in:
2026-06-09 11:02:01 +02:00
parent 6f106e3130
commit d82b123bfd
38 changed files with 1552 additions and 83 deletions
+9
View File
@@ -117,6 +117,15 @@
</div>
</div>
<div class="card mt-3">
<div class="card-header">
<h3 class="card-title"><i class="fas fa-tags mr-2"></i>Tag</h3>
</div>
<div class="card-body">
@include('partials._tag-selector', ['selectedTags' => [], 'label' => 'Etichette'])
</div>
</div>
<div class="mt-3">
<button type="submit" class="btn btn-success">
<i class="fas fa-save mr-1"></i> Salva
+9
View File
@@ -270,6 +270,15 @@
</div>
</div>
<div class="card mt-3">
<div class="card-header">
<h3 class="card-title"><i class="fas fa-tags mr-2"></i>Tag</h3>
</div>
<div class="card-body">
@include('partials._tag-selector', ['selectedTags' => $selectedTags ?? [], 'label' => 'Etichette'])
</div>
</div>
<div class="mt-3">
<button type="submit" class="btn btn-success">
<i class="fas fa-save mr-1"></i> Salva Modifiche
+147
View File
@@ -17,6 +17,7 @@ $columnLabels = [
'citta' => 'Città',
'telefono' => 'Telefono',
'email' => 'Email',
'tag' => 'Tag',
];
$vistaDefaultJson = $vista ? $vista->toJson() : 'null';
$allColumnsJson = json_encode($allColumns);
@@ -51,6 +52,22 @@ $visibleColumnsJson = json_encode($visibleColumns);
<i class="fas fa-sitemap mr-1"></i> Albero
</button>
</div>
<div class="btn-group mr-1">
<button type="button" class="btn btn-sm btn-secondary dropdown-toggle" data-toggle="dropdown">
<i class="fas fa-cog mr-1"></i> Azioni
</button>
<div class="dropdown-menu">
@if($canWriteGruppi)
<a class="dropdown-item" href="#" onclick="showMassTagModal(); return false;">
<i class="fas fa-tags mr-2"></i>Assegna Tag
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-danger" href="#" onclick="deleteSelected(); return false;">
<i class="fas fa-trash mr-2"></i>Elimina Selezionati
</a>
@endif
</div>
</div>
<button type="button" class="btn btn-primary btn-sm mr-1" onclick="showSaveVistaModal()">
<i class="fas fa-save mr-1"></i> Salva Vista
</button>
@@ -65,11 +82,19 @@ $visibleColumnsJson = json_encode($visibleColumns);
</div>
</div>
@include('partials._tag-filter-bar', ['filterTags' => $allTags])
@if($viewMode === 'table')
<div class="card-body p-0">
<table class="table table-bordered table-hover table-striped mb-0" id="gruppi-table">
<thead class="thead-light">
<tr>
<th style="width: 40px;">
<div class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input" id="select-all" onchange="toggleSelectAll(this)">
<label class="custom-control-label" for="select-all"></label>
</div>
</th>
@if(in_array('nome', $visibleColumns))
<th data-sortable="true" onclick="sortTable('nome')" style="cursor:pointer;">Nome <i class="fas fa-sort float-right text-muted"></i></th>
@endif
@@ -103,12 +128,21 @@ $visibleColumnsJson = json_encode($visibleColumns);
@if(in_array('email', $visibleColumns))
<th>Email</th>
@endif
@if(in_array('tag', $visibleColumns))
<th>Tag</th>
@endif
<th style="width: 120px;">Azioni</th>
</tr>
</thead>
<tbody id="table-body">
@foreach($gruppi as $gruppo)
<tr data-id="{{ $gruppo->id }}">
<td>
<div class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input row-checkbox" id="select-{{ $gruppo->id }}" value="{{ $gruppo->id }}">
<label class="custom-control-label" for="select-{{ $gruppo->id }}"></label>
</div>
</td>
@if(in_array('nome', $visibleColumns))
<td>
<span style="padding-left: {{ ($gruppo->depth ?? 0) * 20 }}px;">
@@ -154,6 +188,13 @@ $visibleColumnsJson = json_encode($visibleColumns);
@if(in_array('email', $visibleColumns))
<td>-</td>
@endif
@if(in_array('tag', $visibleColumns))
<td>
@foreach($gruppo->tags as $tag)
<a href="{{ route('gruppi.index', ['tag[]' => $tag->slug]) }}" class="badge" style="background-color: {{ $tag->color ?? '#6c757d' }}; color: #fff;">{{ $tag->name }}</a>
@endforeach
</td>
@endif
<td>
<a href="{{ route('gruppi.show', $gruppo->id) }}" class="btn btn-xs btn-info" title="Visualizza">
<i class="fas fa-eye"></i>
@@ -309,6 +350,68 @@ $visibleColumnsJson = json_encode($visibleColumns);
</div>
</div>
</div>
{{-- MODAL: Gestione Tag massiva --}}
<div class="modal fade" id="massTagModal" tabindex="-1" role="dialog">
<div class="modal-dialog modal-dialog-scrollable" role="document">
<div class="modal-content">
<div class="modal-header bg-info">
<h5 class="modal-title text-white"><i class="fas fa-tags mr-2"></i>Gestione Tag</h5>
<button type="button" class="close text-white" data-dismiss="modal"><span>&times;</span></button>
</div>
<form id="massTagForm" method="POST" action="/gruppi/mass-tag">
@csrf
<div class="modal-body">
<p class="mb-2">Operazione su <strong id="massTagCount">0</strong> gruppi selezionati.</p>
<div class="form-group mb-3">
<label class="font-weight-bold">Azione</label>
<div class="d-flex" style="gap:1.5rem;">
<div class="form-check">
<input class="form-check-input" type="radio" name="mode" id="grMtModeAssign" value="assign" checked>
<label class="form-check-label" for="grMtModeAssign">Assegna tag</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="mode" id="grMtModeRemove" value="remove">
<label class="form-check-label" for="grMtModeRemove">Rimuovi tag</label>
</div>
</div>
</div>
@include('partials._tag-selector', ['label' => 'Seleziona tag'])
<input type="hidden" name="ids" id="massTagIds" value="">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Annulla</button>
<button type="submit" class="btn btn-primary"><i class="fas fa-tags mr-1"></i> Applica</button>
</div>
</form>
</div>
</div>
</div>
{{-- MODAL: Conferma Eliminazione massiva --}}
<div class="modal fade" id="deleteModal" tabindex="-1" role="dialog">
@if($canDeleteGruppi)
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header bg-danger">
<h5 class="modal-title text-white"><i class="fas fa-trash-alt mr-2"></i>Conferma Eliminazione</h5>
<button type="button" class="close text-white" data-dismiss="modal"><span>&times;</span></button>
</div>
<div class="modal-body">
<p>Stai per eliminare <strong id="delete-count">0</strong> gruppi.</p>
<div class="alert alert-warning mt-3 mb-0">
<small><i class="fas fa-info-circle mr-1"></i>I membri verranno scollegati ma non eliminati.</small>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Annulla</button>
<button type="button" class="btn btn-danger" id="confirm-delete-btn"><i class="fas fa-trash mr-1"></i> Elimina</button>
</div>
</div>
</div>
@endif
</div>
@endsection
@section('scripts')
@@ -317,6 +420,50 @@ function switchView(mode) {
window.location.href = '?view=' + mode;
}
function toggleSelectAll(source) {
document.querySelectorAll('.row-checkbox').forEach(function(cb) {
cb.checked = source.checked;
});
}
function getSelectedIds() {
return Array.from(document.querySelectorAll('.row-checkbox:checked')).map(cb => cb.value);
}
function showMassTagModal() {
const ids = getSelectedIds();
if (ids.length === 0) {
alert('Seleziona almeno un gruppo');
return;
}
document.getElementById('massTagIds').value = ids.join(',');
document.getElementById('massTagCount').textContent = ids.length;
$('#massTagModal').modal('show');
}
function deleteSelected() {
const ids = getSelectedIds();
if (ids.length === 0) {
alert('Seleziona almeno un gruppo');
return;
}
document.getElementById('delete-count').textContent = ids.length;
document.getElementById('confirm-delete-btn').onclick = function() {
const form = document.createElement('form');
form.method = 'POST';
form.action = '/gruppi/mass-elimina';
const csrfToken = document.querySelector('meta[name="csrf-token"]')?.content || '{{ csrf_token() }}';
let html = '<input type="hidden" name="_token" value="' + csrfToken + '">';
ids.forEach(function(id) {
html += '<input type="hidden" name="ids[]" value="' + id + '">';
});
form.innerHTML = html;
document.body.appendChild(form);
form.submit();
};
$('#deleteModal').modal('show');
}
function toggleItem(id) {
const el = document.getElementById('group-' + id);
const icon = document.getElementById('icon-' + id);
+11
View File
@@ -247,6 +247,17 @@ $canDeleteGruppi = Auth::user()->canDelete('gruppi');
</div>
@endif
<div class="card mt-3">
<div class="card-header"><h3 class="card-title"><i class="fas fa-tags mr-2"></i>Tag</h3></div>
<div class="card-body">
@forelse($gruppo->tags as $tag)
<span class="badge" style="background-color:{{ $tag->color ?? '#6c757d' }};color:#fff;padding:4px 10px;border-radius:12px;font-size:0.85rem;">{{ $tag->name }}</span>
@empty
<p class="text-muted mb-0"><i class="fas fa-info-circle mr-1"></i>Nessun tag assegnato.</p>
@endforelse
</div>
</div>
<div class="card mt-3">
<div class="card-header">
<h3 class="card-title">