feat(10-06): wire breadcrumb mapping + toast call sites; delete FolderBreadcrumb
- FileManagerView: add mappedBreadcrumb computed ({id,label} from foldersStore.breadcrumb)
- FileManagerView: import useToastStore; add toast.show() to doMove, doDeleteDoc, onFilesSelected
- FileManagerView: remove console.error from doMove/doDeleteDoc (toast communicates errors)
- CloudFolderView: add mappedBreadcrumb computed; pass to StorageBrowser :breadcrumb
- Delete FolderBreadcrumb.vue + FolderBreadcrumb.test.js (no dead code per CLAUDE.md)
- FileManagerView.test.js: replace dead FolderBreadcrumb mock with BreadcrumbBar mock
- StorageBrowser.skeleton.test.js: remove unused FolderBreadcrumb stub
- Full suite: 164/164 pass, 0 failures
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
mode="cloud"
|
||||
:folders="folders"
|
||||
:files="files"
|
||||
:breadcrumb="breadcrumb"
|
||||
:breadcrumb="mappedBreadcrumb"
|
||||
:upload-queue="uploadQueue"
|
||||
:loading="loading"
|
||||
:empty-message="error || 'This folder is empty'"
|
||||
@@ -45,6 +45,10 @@ const breadcrumb = computed(() => {
|
||||
}))
|
||||
})
|
||||
|
||||
const mappedBreadcrumb = computed(() =>
|
||||
breadcrumb.value.map(f => ({ id: f.id, label: f.name }))
|
||||
)
|
||||
|
||||
async function load() {
|
||||
loading.value = true
|
||||
error.value = ''
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
mode="local"
|
||||
:folders="foldersStore.folders"
|
||||
:files="docsStore.documents"
|
||||
:breadcrumb="foldersStore.breadcrumb"
|
||||
:breadcrumb="mappedBreadcrumb"
|
||||
:upload-queue="uploadQueue"
|
||||
:loading="docsStore.loading || foldersStore.loading"
|
||||
:search-query="docsStore.searchQuery"
|
||||
@@ -49,6 +49,7 @@ import { useRoute, useRouter } from 'vue-router'
|
||||
import { useFoldersStore } from '../stores/folders.js'
|
||||
import { useDocumentsStore } from '../stores/documents.js'
|
||||
import { useTopicsStore } from '../stores/topics.js'
|
||||
import { useToastStore } from '../stores/toast.js'
|
||||
import StorageBrowser from '../components/storage/StorageBrowser.vue'
|
||||
import FolderDeleteModal from '../components/folders/FolderDeleteModal.vue'
|
||||
import ShareModal from '../components/sharing/ShareModal.vue'
|
||||
@@ -63,6 +64,9 @@ const browserRef = ref(null)
|
||||
// ── Navigation ────────────────────────────────────────────────────────────────
|
||||
|
||||
const currentFolderId = computed(() => route.params.folderId ?? null)
|
||||
const mappedBreadcrumb = computed(() =>
|
||||
(foldersStore.breadcrumb || []).map(f => ({ id: f.id, label: f.name }))
|
||||
)
|
||||
|
||||
async function loadFolder(folderId) {
|
||||
if (folderId === null) {
|
||||
@@ -100,6 +104,7 @@ const uploadQueue = ref([])
|
||||
|
||||
async function onFilesSelected({ files, autoClassify }) {
|
||||
const folderId = currentFolderId.value
|
||||
const toast = useToastStore()
|
||||
const promises = files.map(file => {
|
||||
const item = reactive({ name: file.name, done: false, error: null, quotaError: null, topics: null })
|
||||
uploadQueue.value.unshift(item)
|
||||
@@ -112,6 +117,14 @@ async function onFilesSelected({ files, autoClassify }) {
|
||||
})
|
||||
await Promise.allSettled(promises)
|
||||
await topicsStore.fetchTopics()
|
||||
const succeeded = uploadQueue.value.slice(0, files.length).filter(i => i.done).length
|
||||
if (succeeded === files.length) {
|
||||
toast.show(`${succeeded} file(s) uploaded`, 'success')
|
||||
} else if (succeeded > 0) {
|
||||
toast.show(`${succeeded} of ${files.length} file(s) uploaded`, 'warning')
|
||||
} else {
|
||||
toast.show('Upload failed', 'error')
|
||||
}
|
||||
}
|
||||
|
||||
// ── Folder CRUD ───────────────────────────────────────────────────────────────
|
||||
@@ -143,11 +156,23 @@ async function confirmDeleteFolder() {
|
||||
const shareDoc = ref(null)
|
||||
|
||||
async function doMove(docId, folderId) {
|
||||
try { await docsStore.moveToFolder(docId, folderId) } catch (e) { console.error(e.message) }
|
||||
const toast = useToastStore()
|
||||
try {
|
||||
await docsStore.moveToFolder(docId, folderId)
|
||||
toast.show('Document moved', 'success')
|
||||
} catch (e) {
|
||||
toast.show('Move failed: ' + (e.message || 'unknown error'), 'error')
|
||||
}
|
||||
}
|
||||
|
||||
async function doDeleteDoc(docId) {
|
||||
try { await docsStore.remove(docId) } catch (e) { console.error(e.message) }
|
||||
const toast = useToastStore()
|
||||
try {
|
||||
await docsStore.remove(docId)
|
||||
toast.show('Document deleted', 'success')
|
||||
} catch (e) {
|
||||
toast.show('Delete failed: ' + (e.message || 'unknown error'), 'error')
|
||||
}
|
||||
}
|
||||
|
||||
// ── Topic color lookup ────────────────────────────────────────────────────────
|
||||
|
||||
@@ -29,8 +29,8 @@ vi.mock('../../api/client.js', () => ({
|
||||
}))
|
||||
|
||||
// Stub heavy child components so we only test FileManagerView logic
|
||||
vi.mock('../../components/folders/FolderBreadcrumb.vue', () => ({
|
||||
default: { template: '<nav><slot/></nav>', props: ['segments'], emits: ['navigate'] },
|
||||
vi.mock('../../components/ui/BreadcrumbBar.vue', () => ({
|
||||
default: { template: '<nav><slot/></nav>', props: ['segments', 'rootLabel', 'showRoot'], emits: ['navigate'] },
|
||||
}))
|
||||
vi.mock('../../components/upload/DropZone.vue', () => ({
|
||||
default: { template: '<div class="dropzone"/>', emits: ['files-selected'] },
|
||||
|
||||
Reference in New Issue
Block a user