First commit
This commit is contained in:
474
resources/views/admin/chunks/show.blade.php
Normal file
474
resources/views/admin/chunks/show.blade.php
Normal file
@@ -0,0 +1,474 @@
|
||||
@extends('layouts.admin')
|
||||
|
||||
@section('title', 'Chunk #' . ($chunk->chunk_index + 1) . ' — ' . Str::limit($chunk->document->title, 30))
|
||||
|
||||
@section('breadcrumb')
|
||||
<li class="breadcrumb-item"><a href="{{ route('admin.documents.index') }}">Dokumen</a></li>
|
||||
<li class="breadcrumb-item">
|
||||
<a href="{{ route('admin.documents.show', $chunk->document) }}">{{ Str::limit($chunk->document->title, 25) }}</a>
|
||||
</li>
|
||||
<li class="breadcrumb-item">
|
||||
<a href="{{ route('admin.documents.chunks', ['document' => $chunk->document, 'version' => $chunk->documentVersion]) }}">
|
||||
Chunks v{{ $chunk->documentVersion->version_number }}
|
||||
</a>
|
||||
</li>
|
||||
<li class="breadcrumb-item active">Chunk #{{ $chunk->chunk_index + 1 }}</li>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
|
||||
{{-- Flash Messages --}}
|
||||
@if(session('success'))
|
||||
<div class="alert alert-success alert-dismissible fade show py-2">
|
||||
<i class="bi bi-check-circle me-1"></i>{{ session('success') }}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||
</div>
|
||||
@endif
|
||||
@if(session('error'))
|
||||
<div class="alert alert-danger alert-dismissible fade show py-2">
|
||||
<i class="bi bi-exclamation-triangle me-1"></i>{{ session('error') }}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- Header Row --}}
|
||||
<div class="d-flex align-items-start justify-content-between mb-3 flex-wrap gap-2">
|
||||
<div>
|
||||
<div class="d-flex align-items-center gap-2 flex-wrap mb-1">
|
||||
<h4 class="mb-0 fw-bold">Chunk #{{ $chunk->chunk_index + 1 }}</h4>
|
||||
<span class="badge {{ $chunk->getStatusBadgeClass() }}">{{ $chunk->getStatusLabel() }}</span>
|
||||
@if($chunk->is_edited)
|
||||
<span class="badge bg-primary-subtle text-primary border border-primary">
|
||||
<i class="bi bi-pencil me-1"></i>Telah Diedit
|
||||
</span>
|
||||
@endif
|
||||
@if($chunk->parent_chunk_id)
|
||||
<span class="badge bg-warning-subtle text-warning border border-warning">
|
||||
<i class="bi bi-scissors me-1"></i>Hasil Split
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
<p class="text-muted small mb-0">
|
||||
{{ $chunk->document->title }} — v{{ $chunk->documentVersion->version_number }}
|
||||
@if($chunk->page_number) · ms. {{ $chunk->page_number }} @endif
|
||||
@if($chunk->section_heading) · {{ $chunk->section_heading }} @endif
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{{-- Action buttons --}}
|
||||
<div class="d-flex gap-2 flex-wrap">
|
||||
<a href="{{ route('admin.documents.chunks', ['document' => $chunk->document, 'version' => $chunk->documentVersion]) }}"
|
||||
class="btn btn-sm btn-outline-secondary">
|
||||
<i class="bi bi-arrow-left me-1"></i>Senarai Chunk
|
||||
</a>
|
||||
|
||||
@if(!$chunk->isSuperseded())
|
||||
<a href="{{ route('admin.chunks.split', $chunk) }}"
|
||||
class="btn btn-sm btn-warning">
|
||||
<i class="bi bi-scissors me-1"></i>Split Chunk
|
||||
</a>
|
||||
|
||||
@if($chunk->exclude_from_index)
|
||||
<form method="POST" action="{{ route('admin.chunks.include', $chunk) }}" class="d-inline">
|
||||
@csrf
|
||||
<button type="submit" class="btn btn-sm btn-success"
|
||||
onclick="return confirm('Kembalikan chunk ini ke indexing?')">
|
||||
<i class="bi bi-check-circle me-1"></i>Include
|
||||
</button>
|
||||
</form>
|
||||
@else
|
||||
<form method="POST" action="{{ route('admin.chunks.exclude', $chunk) }}" class="d-inline">
|
||||
@csrf
|
||||
<button type="submit" class="btn btn-sm btn-outline-secondary"
|
||||
onclick="return confirm('Kecualikan chunk ini dari indexing?')">
|
||||
<i class="bi bi-slash-circle me-1"></i>Exclude
|
||||
</button>
|
||||
</form>
|
||||
@endif
|
||||
|
||||
@if($chunk->isIndexable())
|
||||
<form method="POST" action="{{ route('admin.chunks.reindex', $chunk) }}" class="d-inline">
|
||||
@csrf
|
||||
<button type="submit" class="btn btn-sm btn-outline-info"
|
||||
onclick="return confirm('Trigger reindex untuk chunk ini?')">
|
||||
<i class="bi bi-arrow-repeat me-1"></i>Reindex
|
||||
</button>
|
||||
</form>
|
||||
@endif
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Metadata Cards --}}
|
||||
<div class="row g-2 mb-3">
|
||||
<div class="col-sm-6 col-lg-3">
|
||||
<div class="card border-0 bg-light h-100">
|
||||
<div class="card-body py-2 px-3">
|
||||
<p class="text-muted mb-0" style="font-size:.7rem">CHUNK INDEX</p>
|
||||
<p class="mb-0 fw-bold">#{{ $chunk->chunk_index + 1 }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-6 col-lg-3">
|
||||
<div class="card border-0 bg-light h-100">
|
||||
<div class="card-body py-2 px-3">
|
||||
<p class="text-muted mb-0" style="font-size:.7rem">QDRANT POINT ID</p>
|
||||
<p class="mb-0 fw-bold" style="font-size:.75rem;word-break:break-all">
|
||||
{{ $chunk->qdrant_point_id ?? '—' }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-6 col-lg-3">
|
||||
<div class="card border-0 bg-light h-100">
|
||||
<div class="card-body py-2 px-3">
|
||||
<p class="text-muted mb-0" style="font-size:.7rem">LAST EMBEDDED</p>
|
||||
<p class="mb-0 fw-bold" style="font-size:.82rem">
|
||||
{{ $chunk->last_embedded_at?->format('d/m/Y H:i') ?? '—' }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-6 col-lg-3">
|
||||
<div class="card border-0 bg-light h-100">
|
||||
<div class="card-body py-2 px-3">
|
||||
<p class="text-muted mb-0" style="font-size:.7rem">DIEDIT OLEH</p>
|
||||
<p class="mb-0 fw-bold" style="font-size:.82rem">
|
||||
{{ $chunk->editor?->name ?? '—' }}
|
||||
@if($chunk->edited_at)
|
||||
<br><span class="text-muted fw-normal" style="font-size:.7rem">{{ $chunk->edited_at->format('d/m/Y H:i') }}</span>
|
||||
@endif
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Parent Chunk Info (jika ini adalah hasil split) --}}
|
||||
@if($chunk->parentChunk)
|
||||
<div class="alert alert-warning py-2 mb-3">
|
||||
<i class="bi bi-scissors me-1"></i>
|
||||
Chunk ini adalah hasil split daripada
|
||||
<a href="{{ route('admin.chunks.show', $chunk->parentChunk) }}" class="alert-link">
|
||||
Chunk #{{ $chunk->parentChunk->chunk_index + 1 }}
|
||||
</a>
|
||||
({{ $chunk->parentChunk->getStatusLabel() }}).
|
||||
Urutan dalam split: {{ $chunk->split_order + 1 }} / dalam kumpulan yang sama.
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- Superseded Warning --}}
|
||||
@if($chunk->isSuperseded())
|
||||
<div class="alert alert-dark py-2 mb-3">
|
||||
<i class="bi bi-exclamation-triangle me-1"></i>
|
||||
Chunk ini telah <strong>digantikan</strong> oleh chunk-chunk baharu hasil split. Ia tidak lagi digunakan dalam Qdrant.
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- ===================================================================== --}}
|
||||
{{-- TEXT PREVIEW — 3 Panel --}}
|
||||
{{-- ===================================================================== --}}
|
||||
|
||||
<div class="card border-0 shadow-sm mb-3">
|
||||
<div class="card-header bg-white border-bottom">
|
||||
<ul class="nav nav-tabs card-header-tabs" id="textTabs" role="tablist">
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link {{ !$chunk->final_text && !$chunk->cleaned_text ? 'active' : '' }}"
|
||||
id="raw-tab" data-bs-toggle="tab" data-bs-target="#raw-panel"
|
||||
type="button" role="tab">
|
||||
<i class="bi bi-file-earmark-text me-1"></i>
|
||||
raw_text
|
||||
<span class="badge bg-light text-dark border ms-1" style="font-size:.65rem">
|
||||
{{ number_format(str_word_count($chunk->content)) }} patah
|
||||
</span>
|
||||
</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link {{ $chunk->cleaned_text && !$chunk->final_text ? 'active' : '' }}"
|
||||
id="cleaned-tab" data-bs-toggle="tab" data-bs-target="#cleaned-panel"
|
||||
type="button" role="tab">
|
||||
<i class="bi bi-magic me-1"></i>
|
||||
cleaned_text
|
||||
@if(!$chunk->cleaned_text)
|
||||
<span class="badge bg-light text-muted border ms-1" style="font-size:.65rem">null</span>
|
||||
@endif
|
||||
</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link {{ $chunk->final_text ? 'active' : '' }}"
|
||||
id="final-tab" data-bs-toggle="tab" data-bs-target="#final-panel"
|
||||
type="button" role="tab">
|
||||
<i class="bi bi-check-circle me-1"></i>
|
||||
final_text
|
||||
@if($chunk->final_text)
|
||||
<span class="badge bg-primary-subtle text-primary border border-primary ms-1" style="font-size:.65rem">
|
||||
Aktif
|
||||
</span>
|
||||
@else
|
||||
<span class="badge bg-light text-muted border ms-1" style="font-size:.65rem">null</span>
|
||||
@endif
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
<div class="tab-content" id="textTabsContent">
|
||||
|
||||
{{-- raw_text --}}
|
||||
<div class="tab-pane fade {{ !$chunk->final_text && !$chunk->cleaned_text ? 'show active' : '' }}"
|
||||
id="raw-panel" role="tabpanel">
|
||||
<div class="p-3">
|
||||
<p class="text-muted small mb-2">
|
||||
Teks asal hasil extraction PDF. <strong>Tidak boleh diubah.</strong>
|
||||
Ini adalah source of truth untuk chunk ini.
|
||||
</p>
|
||||
<pre class="mb-0 p-3 bg-light rounded" style="white-space:pre-wrap;max-height:300px;overflow-y:auto;font-family:inherit;font-size:.82rem">{{ $chunk->content }}</pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- cleaned_text --}}
|
||||
<div class="tab-pane fade {{ $chunk->cleaned_text && !$chunk->final_text ? 'show active' : '' }}"
|
||||
id="cleaned-panel" role="tabpanel">
|
||||
<div class="p-3">
|
||||
@if($chunk->cleaned_text)
|
||||
<p class="text-muted small mb-2">
|
||||
Teks selepas auto cleanup. Jika final_text tidak ditetapkan, ini digunakan untuk embedding.
|
||||
</p>
|
||||
<pre class="mb-0 p-3 bg-light rounded" style="white-space:pre-wrap;max-height:300px;overflow-y:auto;font-family:inherit;font-size:.82rem">{{ $chunk->cleaned_text }}</pre>
|
||||
@else
|
||||
<div class="text-center py-4 text-muted">
|
||||
<i class="bi bi-dash-circle display-6 d-block mb-2"></i>
|
||||
<p class="mb-0">cleaned_text tidak ditetapkan.</p>
|
||||
<p class="small">raw_text (content) digunakan untuk embedding.</p>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- final_text --}}
|
||||
<div class="tab-pane fade {{ $chunk->final_text ? 'show active' : '' }}"
|
||||
id="final-panel" role="tabpanel">
|
||||
<div class="p-3">
|
||||
@if($chunk->final_text)
|
||||
<p class="text-muted small mb-2">
|
||||
Teks yang <strong>sebenarnya dihantar ke Qdrant</strong> untuk embedding.
|
||||
Diedit oleh admin.
|
||||
</p>
|
||||
<pre class="mb-0 p-3 bg-success-subtle rounded" style="white-space:pre-wrap;max-height:300px;overflow-y:auto;font-family:inherit;font-size:.82rem">{{ $chunk->final_text }}</pre>
|
||||
@else
|
||||
<div class="text-center py-4 text-muted">
|
||||
<i class="bi bi-dash-circle display-6 d-block mb-2"></i>
|
||||
<p class="mb-0">final_text tidak ditetapkan.</p>
|
||||
<p class="small">Sistem menggunakan cleaned_text atau raw_text untuk embedding.</p>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- ===================================================================== --}}
|
||||
{{-- EDIT FINAL TEXT FORM --}}
|
||||
{{-- ===================================================================== --}}
|
||||
|
||||
@if(!$chunk->isSuperseded())
|
||||
<div class="card border-0 shadow-sm mb-3">
|
||||
<div class="card-header bg-white border-bottom py-2">
|
||||
<h6 class="mb-0">
|
||||
<i class="bi bi-pencil-square me-2"></i>Edit final_text
|
||||
</h6>
|
||||
<p class="text-muted small mb-0 mt-1">
|
||||
Edit teks yang akan dihantar untuk embedding. raw_text tidak akan diubah.
|
||||
Selepas simpan, reindex akan diantrikan secara automatik.
|
||||
</p>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="POST" action="{{ route('admin.chunks.update', $chunk) }}" id="editForm">
|
||||
@csrf
|
||||
@method('PATCH')
|
||||
|
||||
@error('final_text')
|
||||
<div class="alert alert-danger py-2 mb-3">{{ $message }}</div>
|
||||
@enderror
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="final_text" class="form-label fw-semibold">
|
||||
final_text
|
||||
<small class="text-muted fw-normal">
|
||||
(kosong = guna {{ $chunk->cleaned_text ? 'cleaned_text' : 'raw_text' }})
|
||||
</small>
|
||||
</label>
|
||||
<textarea name="final_text" id="final_text" rows="10"
|
||||
class="form-control font-monospace @error('final_text') is-invalid @enderror"
|
||||
style="font-size:.82rem;line-height:1.5"
|
||||
placeholder="Masukkan final_text yang telah dibersihkan...">{{ old('final_text', $chunk->final_text ?? $chunk->getEmbeddableText()) }}</textarea>
|
||||
<div class="d-flex justify-content-between mt-1">
|
||||
<small class="text-muted">Minimum 20 aksara, maksimum 10,000 aksara.</small>
|
||||
<small class="text-muted" id="charCount">0 aksara</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Quick-fill dari raw_text --}}
|
||||
<div class="mb-3">
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary" id="btnFillRaw">
|
||||
<i class="bi bi-arrow-down me-1"></i>Isi dari raw_text
|
||||
</button>
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary ms-1" id="btnClearFinal">
|
||||
<i class="bi bi-x me-1"></i>Kosongkan
|
||||
</button>
|
||||
<span class="text-muted ms-2" style="font-size:.75rem">
|
||||
raw_text: {{ number_format(mb_strlen($chunk->content)) }} aksara,
|
||||
{{ number_format(str_word_count($chunk->content)) }} patah
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="notes" class="form-label">Nota perubahan <span class="text-muted fw-normal">(optional)</span></label>
|
||||
<input type="text" name="notes" id="notes" class="form-control"
|
||||
value="{{ old('notes') }}"
|
||||
placeholder="Contoh: Buang header halaman, nombor muka surat...">
|
||||
</div>
|
||||
|
||||
<div class="d-flex gap-2">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="bi bi-save me-1"></i>Simpan & Queue Reindex
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-secondary" onclick="history.back()">
|
||||
Batal
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- ===================================================================== --}}
|
||||
{{-- CHILD CHUNKS (jika chunk ini pernah di-split) --}}
|
||||
{{-- ===================================================================== --}}
|
||||
|
||||
@if($chunk->childChunks->count() > 0)
|
||||
<div class="card border-0 shadow-sm mb-3">
|
||||
<div class="card-header bg-white border-bottom py-2">
|
||||
<h6 class="mb-0">
|
||||
<i class="bi bi-diagram-2 me-2"></i>
|
||||
Chunk Baharu Hasil Split
|
||||
<span class="badge bg-secondary ms-1">{{ $chunk->childChunks->count() }}</span>
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
@foreach($chunk->childChunks as $child)
|
||||
<div class="d-flex align-items-center gap-3 px-3 py-2 border-bottom">
|
||||
<span class="badge {{ $child->getStatusBadgeClass() }}" style="font-size:.7rem">
|
||||
{{ $child->getStatusLabel() }}
|
||||
</span>
|
||||
<span class="text-muted" style="font-size:.75rem">#{{ $child->chunk_index + 1 }}</span>
|
||||
<p class="mb-0 text-truncate flex-grow-1" style="font-size:.82rem">
|
||||
{{ Str::limit($child->getEmbeddableText(), 100) }}
|
||||
</p>
|
||||
<a href="{{ route('admin.chunks.show', $child) }}"
|
||||
class="btn btn-sm btn-outline-primary flex-shrink-0">
|
||||
Lihat
|
||||
</a>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- ===================================================================== --}}
|
||||
{{-- AUDIT TRAIL --}}
|
||||
{{-- ===================================================================== --}}
|
||||
|
||||
@if($chunk->audits->count() > 0)
|
||||
<div class="card border-0 shadow-sm mb-3">
|
||||
<div class="card-header bg-white border-bottom py-2">
|
||||
<h6 class="mb-0">
|
||||
<i class="bi bi-clock-history me-2"></i>Audit Trail
|
||||
<span class="badge bg-light text-dark border ms-1">{{ $chunk->audits->count() }} rekod</span>
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
@foreach($chunk->audits as $audit)
|
||||
<div class="px-3 py-2 border-bottom">
|
||||
<div class="d-flex align-items-center gap-2 flex-wrap mb-1">
|
||||
<span class="badge {{ $audit->getOperationBadgeClass() }}" style="font-size:.7rem">
|
||||
{{ $audit->getOperationLabel() }}
|
||||
</span>
|
||||
@if($audit->old_status && $audit->new_status)
|
||||
<span class="text-muted" style="font-size:.75rem">
|
||||
{{ $audit->old_status ?? '—' }} → {{ $audit->new_status }}
|
||||
</span>
|
||||
@endif
|
||||
<span class="ms-auto text-muted" style="font-size:.72rem">
|
||||
{{ $audit->user?->name ?? 'System' }}
|
||||
· {{ $audit->created_at->format('d/m/Y H:i') }}
|
||||
</span>
|
||||
</div>
|
||||
@if($audit->notes)
|
||||
<p class="mb-0 text-muted" style="font-size:.75rem">
|
||||
<i class="bi bi-chat-left-text me-1"></i>{{ $audit->notes }}
|
||||
</p>
|
||||
@endif
|
||||
@if($audit->operation === \App\Models\ChunkAudit::OP_EDIT_FINAL_TEXT && $audit->old_final_text)
|
||||
<details class="mt-1">
|
||||
<summary class="text-muted" style="font-size:.72rem;cursor:pointer">
|
||||
Lihat perubahan teks
|
||||
</summary>
|
||||
<div class="row g-2 mt-1">
|
||||
<div class="col-6">
|
||||
<p class="text-muted mb-1" style="font-size:.68rem">SEBELUM</p>
|
||||
<pre class="bg-danger-subtle p-2 rounded mb-0" style="font-size:.72rem;white-space:pre-wrap;max-height:100px;overflow-y:auto">{{ Str::limit($audit->old_final_text, 300) }}</pre>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<p class="text-muted mb-1" style="font-size:.68rem">SELEPAS</p>
|
||||
<pre class="bg-success-subtle p-2 rounded mb-0" style="font-size:.72rem;white-space:pre-wrap;max-height:100px;overflow-y:auto">{{ Str::limit($audit->new_final_text, 300) }}</pre>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
@endif
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
// ── Char counter ──────────────────────────────────────────────────────────────
|
||||
const textarea = document.getElementById('final_text');
|
||||
const charCount = document.getElementById('charCount');
|
||||
|
||||
function updateCount() {
|
||||
if (textarea && charCount) {
|
||||
charCount.textContent = textarea.value.length.toLocaleString() + ' aksara';
|
||||
}
|
||||
}
|
||||
|
||||
if (textarea) {
|
||||
textarea.addEventListener('input', updateCount);
|
||||
updateCount();
|
||||
}
|
||||
|
||||
// ── Quick-fill dari raw_text ──────────────────────────────────────────────────
|
||||
const rawText = @json($chunk->content);
|
||||
|
||||
document.getElementById('btnFillRaw')?.addEventListener('click', function() {
|
||||
if (textarea.value.trim() !== '' && !confirm('Gantikan teks sedia ada dengan raw_text?')) {
|
||||
return;
|
||||
}
|
||||
textarea.value = rawText;
|
||||
updateCount();
|
||||
textarea.focus();
|
||||
});
|
||||
|
||||
document.getElementById('btnClearFinal')?.addEventListener('click', function() {
|
||||
if (!confirm('Kosongkan final_text? Sistem akan guna raw_text untuk embedding.')) return;
|
||||
textarea.value = '';
|
||||
updateCount();
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
Reference in New Issue
Block a user