feat(phase-4-09): wire components into views — sidebar, cards, home, folder, shared, settings, admin

- AppSidebar: add 'Shared with me' entry (purple icon, count badge) and Folders section with New folder CTA
- DocumentCard: add group class, hover-reveal share button, ShareModal v-if, shared indicator pill
- HomeView: add SearchBar + SortControls above document list; fetchFolders on mount
- FolderView: new view with FolderBreadcrumb, FolderRow list, inline new-subfolder input, document list
- SharedView: new view fetching /api/shares/received with owner_handle display and empty state
- DocumentView: add PDF preview logic (in_app=DocumentPreviewModal, new_tab=window.open); load preferences on mount
- SettingsView: add Document Preferences card with pdf_open_mode radio buttons, auto-save on change
- AdminView: add Audit Log tab alongside Users/Quotas/AI Config tabs
This commit is contained in:
curo1305
2026-05-25 22:14:12 +02:00
parent 36721575a5
commit a3f5fc2e69
8 changed files with 578 additions and 14 deletions
+48 -6
View File
@@ -17,10 +17,20 @@
Uploaded {{ formatDate(doc.created_at) }} · {{ formatSize(doc.size_bytes) }} · {{ doc.mime_type }}
</p>
</div>
<button
@click="confirmDelete"
class="text-sm text-red-500 hover:text-red-700 shrink-0"
>Delete</button>
<div class="flex items-center gap-2 shrink-0">
<!-- Open/Preview button for PDFs -->
<button
v-if="isPdf"
@click="openPdf"
class="text-sm px-3 py-1.5 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 transition-colors"
>
{{ pdfOpenMode === 'in_app' ? 'Preview' : 'Open' }}
</button>
<button
@click="confirmDelete"
class="text-sm text-red-500 hover:text-red-700"
>Delete</button>
</div>
</div>
<!-- Topics -->
@@ -91,13 +101,21 @@
<pre class="text-xs text-gray-600 whitespace-pre-wrap font-mono bg-gray-50 rounded-lg p-4 max-h-96 overflow-y-auto">{{ doc.extracted_text || '(no text extracted)' }}</pre>
</div>
</template>
<!-- PDF in-app preview modal -->
<DocumentPreviewModal
v-if="showPreviewModal && doc"
:doc="doc"
@close="showPreviewModal = false"
/>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { ref, computed, onMounted } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import TopicBadge from '../components/topics/TopicBadge.vue'
import DocumentPreviewModal from '../components/documents/DocumentPreviewModal.vue'
import { useDocumentsStore } from '../stores/documents.js'
import { useTopicsStore } from '../stores/topics.js'
import * as api from '../api/client.js'
@@ -114,6 +132,15 @@ const suggesting = ref(false)
const classifyError = ref(null)
const suggestions = ref([])
const selectedSuggestions = ref([])
const showPreviewModal = ref(false)
const pdfOpenMode = ref('new_tab')
const isPdf = computed(() => {
if (!doc.value) return false
const mime = doc.value.mime_type || ''
const name = doc.value.original_name || ''
return mime === 'application/pdf' || name.toLowerCase().endsWith('.pdf')
})
onMounted(async () => {
try {
@@ -121,8 +148,23 @@ onMounted(async () => {
} finally {
loading.value = false
}
// Load user preferences for PDF open mode
try {
const prefs = await api.getMyPreferences()
pdfOpenMode.value = prefs.pdf_open_mode || 'new_tab'
} catch {
pdfOpenMode.value = 'new_tab'
}
})
function openPdf() {
if (pdfOpenMode.value === 'in_app') {
showPreviewModal.value = true
} else {
window.open(api.getDocumentContentUrl(doc.value.id), '_blank')
}
}
function topicColor(name) {
return topicsStore.topics.find(t => t.name === name)?.color ?? '#6366f1'
}
@@ -166,7 +208,7 @@ async function createSelectedTopics() {
async function confirmDelete() {
if (!confirm(`Delete "${doc.value.original_name}"?`)) return
await api.deleteDocument(doc.value.id)
await docsStore.remove(doc.value.id)
router.push('/')
}