pre version 2

This commit is contained in:
2026-06-17 13:50:41 +02:00
parent c333bbce4e
commit 6909e21b67
26 changed files with 1213 additions and 136 deletions
-34
View File
@@ -105,40 +105,6 @@
</div>
@include('partials._tag-selector', ['selectedTags' => $selectedTags ?? [], 'label' => 'Etichette'])
</div>
<div class="card-body">
<table class="table table-sm table-borderless">
<tr>
<td style="width: 100px;"><strong>File:</strong></td>
<td>{{ $documento->file_path }}</td>
</tr>
<tr>
<td><strong>Tipo MIME:</strong></td>
<td>{{ $documento->mime_type ?? '-' }}</td>
</tr>
<tr>
<td><strong>Dimensione:</strong></td>
<td>{{ $documento->dimensione ? number_format($documento->dimensione / 1024, 1) . ' KB' : '-' }}</td>
</tr>
<tr>
<td><strong>Creato:</strong></td>
<td>{{ $documento->created_at->format('d/m/Y H:i') }}</td>
</tr>
@if($documento->user)
<tr>
<td><strong>Utente:</strong></td>
<td>{{ $documento->user->name }}</td>
</tr>
@endif
</table>
@if($documento->file_path)
<hr>
<a href="/documenti/{{ $documento->id }}/download" class="btn btn-primary btn-block">
<i class="fas fa-download mr-1"></i> Scarica
</a>
@endif
</div>
</div>
</div>
</div>
+63 -14
View File
@@ -18,6 +18,18 @@ $tableColumnsJson = json_encode($tableColumns ?? []);
@endsection
@section('content')
@if(session('success'))
<div class="alert alert-success alert-dismissible">
<button type="button" class="close" data-dismiss="alert">&times;</button>
{{ session('success') }}
</div>
@endif
@if(session('error'))
<div class="alert alert-danger alert-dismissible">
<button type="button" class="close" data-dismiss="alert">&times;</button>
{{ session('error') }}
</div>
@endif
<div class="row">
{{-- Sidebar cartelle --}}
<div class="col-md-3">
@@ -133,7 +145,7 @@ $tableColumnsJson = json_encode($tableColumns ?? []);
<form id="massForm" method="POST">
@csrf
<input type="hidden" name="_method" id="formMethod" value="POST">
@if($canDeleteDocumenti)
@if($canWriteDocumenti)
<div class="p-3 bg-light border-bottom d-flex align-items-center flex-wrap gap-2">
<span class="font-weight-bold mr-2">Azioni:</span>
<button type="button" class="btn btn-sm btn-danger" onclick="massAction('delete')">
@@ -149,7 +161,7 @@ $tableColumnsJson = json_encode($tableColumns ?? []);
<button type="button" class="btn btn-sm btn-secondary" onclick="$('#massMoveModal').modal('show')">
<i class="fas fa-folder-open mr-1"></i> Sposta selezionati in...
</button>
<button type="button" class="btn btn-sm btn-info" onclick="$('#massTagModal').modal('show')">
<button type="button" class="btn btn-sm btn-info" onclick="showMassTagModal()">
<i class="fas fa-tags mr-1"></i> Tag
</button>
<button type="button" class="btn btn-sm btn-success" onclick="massDownload()">
@@ -186,7 +198,7 @@ $tableColumnsJson = json_encode($tableColumns ?? []);
<i class="fas fa-folder-open"></i>
</button>
@endif
@if($canDeleteDocumenti)
@if($canWriteDocumenti)
<button type="button" class="btn btn-xs btn-danger" onclick='deleteFolder({{ $cartella->id }}, {{ json_encode($cartella->nome) }})' title="Elimina">
<i class="fas fa-times"></i>
</button>
@@ -213,13 +225,13 @@ $tableColumnsJson = json_encode($tableColumns ?? []);
<div class="col-md-4 col-sm-6 mb-3">
<div class="card card-outline card-secondary h-100">
<div class="card-body p-3">
@if($canDeleteDocumenti)
@if($canWriteDocumenti)
<div class="float-right">
<input type="checkbox" name="ids[]" value="{{ $documento->id }}" class="doc-checkbox" onchange="updateCount()">
</div>
@endif
<h6 class="card-title font-weight-bold text-truncate mb-2" title="{{ $documento->nome_file }}">
{{ $documento->nome_file }}
<a href="/documenti/{{ $documento->id }}/edit">{{ $documento->nome_file }}</a>
</h6>
<div class="text-center py-2" style="font-size: 2.5rem;">
<i class="fas {{ $icon }}"></i>
@@ -268,8 +280,11 @@ $tableColumnsJson = json_encode($tableColumns ?? []);
<button type="button" class="btn btn-xs btn-secondary" onclick="showUpdateModal({{ $documento->id }})" title="Cambia tipo/contesto">
<i class="fas fa-tag"></i>
</button>
<button type="button" class="btn btn-xs btn-info" onclick="openSingleTag({{ $documento->id }})" title="Assegna tag">
<i class="fas fa-tags"></i>
</button>
@endif
@if($canDeleteDocumenti)
@if($canWriteDocumenti)
<button type="button" class="btn btn-xs btn-danger" onclick="deleteDocumento({{ $documento->id }}, '{{ e($documento->nome_file) }}')" title="Elimina">
<i class="fas fa-trash"></i>
</button>
@@ -299,7 +314,7 @@ $tableColumnsJson = json_encode($tableColumns ?? []);
<table class="table table-bordered table-hover table-striped mb-0" id="documenti-table">
<thead class="thead-light">
<tr>
@if($canDeleteDocumenti)
@if($canWriteDocumenti)
<th style="width: 40px;" data-column="select">
<input type="checkbox" id="selectAll" onchange="toggleAll(this)">
</th>
@@ -316,7 +331,7 @@ $tableColumnsJson = json_encode($tableColumns ?? []);
<tbody>
@foreach($sottoCartelle as $cartella)
<tr class="table-warning">
@if($canDeleteDocumenti)
@if($canWriteDocumenti)
<td></td>
@endif
<td>
@@ -341,7 +356,7 @@ $tableColumnsJson = json_encode($tableColumns ?? []);
<i class="fas fa-folder-open"></i>
</button>
@endif
@if($canDeleteDocumenti)
@if($canWriteDocumenti)
<button type="button" class="btn btn-xs btn-danger" onclick='deleteFolder({{ $cartella->id }}, {{ json_encode($cartella->nome) }})' title="Elimina">
<i class="fas fa-times"></i>
</button>
@@ -362,7 +377,7 @@ $tableColumnsJson = json_encode($tableColumns ?? []);
};
@endphp
<tr>
@if($canDeleteDocumenti)
@if($canWriteDocumenti)
<td>
<input type="checkbox" name="ids[]" value="{{ $documento->id }}" class="doc-checkbox" onchange="updateCount()">
</td>
@@ -466,8 +481,11 @@ $tableColumnsJson = json_encode($tableColumns ?? []);
<button type="button" class="btn btn-xs btn-secondary" onclick="showUpdateModal({{ $documento->id }})" title="Cambia tipo/contesto">
<i class="fas fa-tag"></i>
</button>
<button type="button" class="btn btn-xs btn-info" onclick="openSingleTag({{ $documento->id }})" title="Assegna tag">
<i class="fas fa-tags"></i>
</button>
@endif
@if($canDeleteDocumenti)
@if($canWriteDocumenti)
<button type="button" class="btn btn-xs btn-danger" onclick="deleteDocumento({{ $documento->id }}, '{{ e($documento->nome_file) }}')" title="Elimina">
<i class="fas fa-trash"></i>
</button>
@@ -635,6 +653,10 @@ $tableColumnsJson = json_encode($tableColumns ?? []);
</button>
</div>
@if($currentRepo)
<div class="form-group">
<label>Tag (opzionale)</label>
@include("partials._tag-selector", ["selectedTags" => [], "label" => "Tag"])
</div>
<input type="hidden" name="repository_id" value="{{ $currentRepo->id }}">
<p class="text-muted small mb-0">Caricamento su repository remoto: <strong>{{ $currentRepo->nome }}</strong></p>
@endif
@@ -1287,11 +1309,38 @@ document.getElementById('massMoveModal')?.addEventListener('show.bs.modal', func
document.getElementById('massMoveCount').textContent = ids.length;
});
document.getElementById('massTagModal')?.addEventListener('show.bs.modal', function() {
const ids = getSelectedIds();
function showMassTagModal() {
var ids = getSelectedIds();
if (ids.length === 0) {
const preSelected = document.querySelector('.doc-checkbox[data-pre-selected="true"]');
if (preSelected) {
ids = [preSelected.value];
preSelected.removeAttribute('data-pre-selected');
}
}
if (ids.length === 0) {
alert('Seleziona almeno un documento');
return;
}
document.getElementById('massTagIds').value = ids.join(',');
document.getElementById('massTagCount').textContent = ids.length;
});
$('#massTagModal').modal('show');
}
function openSingleTag(docId) {
document.querySelectorAll('.doc-checkbox').forEach(cb => cb.checked = false);
let cb = document.querySelector('.doc-checkbox[value="' + docId + '"]');
if (cb) {
cb.checked = true;
cb.dispatchEvent(new Event('change'));
}
showMassTagModal();
}
document.getElementById('massMoveNewFolderBtn')?.addEventListener('click', function() {
Swal.fire({
+81 -8
View File
@@ -19,6 +19,12 @@ $entityType = $entityType ?? 'eventi';
{{ session('success') }}
</div>
@endif
@if(session('error'))
<div class="alert alert-danger alert-dismissible">
<button type="button" class="close" data-dismiss="alert">&times;</button>
{{ session('error') }}
</div>
@endif
<div class="card">
<div class="card-header">
@@ -33,12 +39,15 @@ $entityType = $entityType ?? 'eventi';
<button type="button" class="btn btn-sm btn-success mr-2" onclick="exportSelectedIcs()">
<i class="fas fa-calendar-plus mr-1"></i> Esporta ICS
</button>
@if($canWriteEventi)
<button type="button" class="btn btn-sm btn-info mr-2" onclick="showMassTagModal()">
<i class="fas fa-tags mr-1"></i> Tag
</button>
@endif
@if($canDeleteEventi)
<div class="btn-group mr-2">
<button type="button" class="btn btn-sm btn-danger" onclick="deleteSelected()">
<i class="fas fa-trash mr-1"></i> Elimina Selezionati
</button>
</div>
<button type="button" class="btn btn-sm btn-danger" onclick="deleteSelected()">
<i class="fas fa-trash mr-1"></i> Elimina Selezionati
</button>
@endif
@if($canWriteEventi)
<a href="/eventi/import" class="btn btn-sm btn-warning mr-2">
@@ -86,7 +95,7 @@ $entityType = $entityType ?? 'eventi';
<thead class="thead-light">
<tr>
<th style="width: 40px;" data-column="select">
@if($canDeleteEventi)
@if($canWriteEventi)
<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>
@@ -187,7 +196,7 @@ $entityType = $entityType ?? 'eventi';
@forelse($eventi as $evento)
<tr data-id="{{ $evento->id }}">
<td>
@if($canDeleteEventi)
@if($canWriteEventi)
<div class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input row-checkbox" id="row-checkbox-{{ $evento->id }}" value="{{ $evento->id }}">
<label class="custom-control-label" for="row-checkbox-{{ $evento->id }}"></label>
@@ -277,6 +286,9 @@ $entityType = $entityType ?? 'eventi';
<a href="{{ url('/eventi/' . $evento->id . '/edit') }}" class="btn btn-xs btn-warning" title="Modifica">
<i class="fas fa-edit"></i>
</a>
<button type="button" class="btn btn-xs btn-info" onclick="openSingleTag({{ $evento->id }})" title="Assegna tag">
<i class="fas fa-tags"></i>
</button>
<form action="{{ url('/eventi/' . $evento->id) }}" method="POST" class="d-inline">
@csrf @method('DELETE')
<button type="submit" class="btn btn-xs btn-danger" onclick="return confirm('Confermi l\'eliminazione?')" title="Elimina">
@@ -327,8 +339,51 @@ $entityType = $entityType ?? 'eventi';
<div id="vista-data" style="display:none;">{{ $vistaDefaultJson }}</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">
<h5 class="modal-title"><i class="fas fa-tags mr-2"></i>Gestione Tag</h5>
<button type="button" class="close" onclick="$('#massTagModal').modal('hide')">
<span>&times;</span>
</button>
</div>
<form id="massTagForm" method="POST" action="/eventi/mass-tag">
@csrf
<div class="modal-body">
<p class="mb-2">Operazione su <strong id="massTagCount">0</strong> eventi 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="mtModeAssign" value="assign" checked>
<label class="form-check-label" for="mtModeAssign">Assegna tag</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="mode" id="mtModeRemove" value="remove">
<label class="form-check-label" for="mtModeRemove">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" onclick="$('#massTagModal').modal('hide')">Annulla</button>
<button type="submit" class="btn btn-primary">
<i class="fas fa-tags mr-1"></i> Applica
</button>
</div>
</form>
</div>
</div>
</div>
<div class="modal fade" id="deleteModal" tabindex="-1" role="dialog">
@if($canDeleteEventi)
@if($canWriteEventi)
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header bg-danger">
@@ -358,10 +413,28 @@ function toggleSelectAll(source) {
document.querySelectorAll('.row-checkbox').forEach(cb => cb.checked = source.checked);
}
function showMassTagModal() {
const ids = getSelectedIds();
if (ids.length === 0) {
alert('Seleziona almeno un evento');
return;
}
document.getElementById('massTagIds').value = ids.join(',');
document.getElementById('massTagCount').textContent = ids.length;
$('#massTagModal').modal('show');
}
function getSelectedIds() {
return Array.from(document.querySelectorAll('.row-checkbox:checked')).map(cb => cb.value);
}
function openSingleTag(eventId) {
document.querySelectorAll('.row-checkbox').forEach(cb => cb.checked = false);
var cb = document.getElementById('row-checkbox-' + eventId);
if (cb) cb.checked = true;
showMassTagModal();
}
function deleteSelected() {
const selectedIds = getSelectedIds();
if (selectedIds.length === 0) {
@@ -0,0 +1,66 @@
<div class="card">
<div class="card-header">
<h3 class="card-title">Connessioni Google</h3>
<div class="card-tools">
<button type="button" class="btn btn-tool" data-card-widget="collapse">
<i class="fas fa-minus"></i>
</button>
</div>
</div>
<div class="card-body">
<p class="text-muted">
Connetti il tuo account Google per utilizzare i servizi di Gmail, Google Drive e Google Calendar.
</p>
@foreach ($googleStatus as $service => $status)
<div class="row mb-3 pb-3 border-bottom">
<div class="col-md-8">
<h5>
<i class="{{ $status['connection']?->service === 'email' ? 'fas fa-envelope' : ($status['connection']?->service === 'drive' ? 'fab fa-google-drive' : 'fas fa-calendar') }} text-primary me-2"></i>
{{ match($service) { 'email' => 'Gmail', 'drive' => 'Google Drive', 'calendar' => 'Google Calendar', default => ucfirst($service) } }}
</h5>
@if ($status['connected'])
<span class="badge bg-success">Connesso</span>
<small class="text-muted ms-2">{{ $status['email'] }}</small>
@if ($status['expired'])
<span class="badge bg-warning ms-2">Token in scadenza</span>
@endif
@else
<span class="badge bg-secondary">Non connesso</span>
@endif
</div>
<div class="col-md-4 text-end">
@if ($status['connected'])
<form action="{{ route('google-oauth.revoke', $status['connection']->id) }}"
method="POST"
class="d-inline"
onsubmit="return confirm('Disconnettere {{ $service === 'email' ? 'Gmail' : ($service === 'drive' ? 'Google Drive' : 'Google Calendar') }}?')">
@csrf
<button type="submit" class="btn btn-danger btn-sm">
<i class="fas fa-unlink me-1"></i> Disconnetti
</button>
</form>
@else
<a href="{{ route('google-oauth.redirect', $service) }}" class="btn btn-primary btn-sm">
<i class="fab fa-google me-1"></i> Connetti
</a>
@endif
</div>
</div>
@endforeach
</div>
</div>
@push('js')
<script>
document.addEventListener('DOMContentLoaded', function () {
const urlParams = new URLSearchParams(window.location.search);
if (urlParams.get('tab') === 'google') {
const tabTrigger = document.querySelector('[data-tab="google"]');
if (tabTrigger) {
tabTrigger.click();
}
}
});
</script>
@endpush
@@ -35,6 +35,9 @@
<a href="#calendario" class="list-group-item list-group-item-action" data-toggle="tab">
<i class="nav-icon fas fa-calendar-alt mr-2"></i> Calendario
</a>
<a href="#google" class="list-group-item list-group-item-action" data-toggle="tab">
<i class="nav-icon fab fa-google mr-2"></i> Google
</a>
<a href="#tipologie" class="list-group-item list-group-item-action" data-toggle="tab">
<i class="nav-icon fas fa-file mr-2"></i> Tipologie Documenti
</a>
@@ -740,6 +743,11 @@
</div>
</div>
{{-- === GOOGLE OAUTH === --}}
<div class="tab-pane" id="google">
@include("impostazioni._google-oauth")
</div>
{{-- === CALENDARIO === --}}
<div class="tab-pane" id="calendario">
<div class="card card-primary">