feat(06.2-03): frontend — CloudDeleteWarningModal + remove_only path in DocumentView
- api/client.js: deleteDocument gains removeOnly param; deleteDocumentRemoveOnly wrapper added - DocumentView.vue: confirmDelete inspects response.cloud_delete_failed, shows modal on failure - DocumentView.vue: inline CloudDeleteWarningModal (C-3 contract) with Remove from app / Cancel - confirmRemoveOnly() calls DELETE ?remove_only=true and navigates to / Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -72,8 +72,13 @@ export function getDocument(id) {
|
|||||||
return request(`/api/documents/${id}`)
|
return request(`/api/documents/${id}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function deleteDocument(id) {
|
export function deleteDocument(id, removeOnly = false) {
|
||||||
return request(`/api/documents/${id}`, { method: 'DELETE' })
|
const url = removeOnly ? `/api/documents/${id}?remove_only=true` : `/api/documents/${id}`
|
||||||
|
return request(url, { method: 'DELETE' })
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deleteDocumentRemoveOnly(id) {
|
||||||
|
return deleteDocument(id, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function classifyDocument(id, topics = null) {
|
export function classifyDocument(id, topics = null) {
|
||||||
|
|||||||
@@ -108,6 +108,40 @@
|
|||||||
:doc="doc"
|
:doc="doc"
|
||||||
@close="showPreviewModal = false"
|
@close="showPreviewModal = false"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<!-- Cloud delete warning modal -->
|
||||||
|
<div
|
||||||
|
v-if="showCloudDeleteWarning"
|
||||||
|
class="fixed inset-0 bg-black/40 flex items-center justify-center z-50"
|
||||||
|
@click.self="cancelCloudDeleteWarning"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
role="dialog"
|
||||||
|
aria-modal="true"
|
||||||
|
aria-labelledby="cloud-delete-modal-title"
|
||||||
|
class="bg-white rounded-2xl shadow-xl p-6 max-w-sm w-full mx-4"
|
||||||
|
>
|
||||||
|
<div class="flex items-center gap-2 mb-2">
|
||||||
|
<svg class="w-5 h-5 text-amber-500 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
|
||||||
|
</svg>
|
||||||
|
<h2 id="cloud-delete-modal-title" class="text-lg font-semibold text-gray-900">Cloud delete failed</h2>
|
||||||
|
</div>
|
||||||
|
<p class="text-sm text-gray-600 mb-4">
|
||||||
|
The file could not be deleted from {{ cloudProviderName }}. Remove it from DocuVault anyway? The file will remain on {{ cloudProviderName }}.
|
||||||
|
</p>
|
||||||
|
<div class="flex gap-2 justify-end">
|
||||||
|
<button
|
||||||
|
@click="cancelCloudDeleteWarning"
|
||||||
|
class="border border-gray-300 text-gray-700 text-sm px-4 py-2 rounded-lg hover:bg-gray-50 transition-colors"
|
||||||
|
>Cancel</button>
|
||||||
|
<button
|
||||||
|
@click="confirmRemoveOnly"
|
||||||
|
class="bg-red-600 hover:bg-red-700 text-white text-sm px-4 py-2 rounded-lg transition-colors"
|
||||||
|
>Remove from app</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -135,6 +169,8 @@ const suggestions = ref([])
|
|||||||
const selectedSuggestions = ref([])
|
const selectedSuggestions = ref([])
|
||||||
const showPreviewModal = ref(false)
|
const showPreviewModal = ref(false)
|
||||||
const pdfOpenMode = ref('new_tab')
|
const pdfOpenMode = ref('new_tab')
|
||||||
|
const showCloudDeleteWarning = ref(false)
|
||||||
|
const cloudProviderName = ref('your cloud storage')
|
||||||
|
|
||||||
const isPdf = computed(() => {
|
const isPdf = computed(() => {
|
||||||
if (!doc.value) return false
|
if (!doc.value) return false
|
||||||
@@ -229,12 +265,33 @@ async function createSelectedTopics() {
|
|||||||
await reclassify()
|
await reclassify()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const _PROVIDER_NAMES = { google_drive: 'Google Drive', onedrive: 'OneDrive', nextcloud: 'Nextcloud', webdav: 'WebDAV' }
|
||||||
|
|
||||||
async function confirmDelete() {
|
async function confirmDelete() {
|
||||||
if (!confirm(`Delete "${doc.value.original_name}"?`)) return
|
if (!confirm(`Delete "${doc.value.original_name}"?`)) return
|
||||||
await docsStore.remove(doc.value.id)
|
const resp = await api.deleteDocument(doc.value.id)
|
||||||
|
if (resp && resp.cloud_delete_failed) {
|
||||||
|
cloudProviderName.value = _PROVIDER_NAMES[doc.value.storage_backend] || 'your cloud storage'
|
||||||
|
showCloudDeleteWarning.value = true
|
||||||
|
return
|
||||||
|
}
|
||||||
router.push('/')
|
router.push('/')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function confirmRemoveOnly() {
|
||||||
|
try {
|
||||||
|
await api.deleteDocumentRemoveOnly(doc.value.id)
|
||||||
|
showCloudDeleteWarning.value = false
|
||||||
|
router.push('/')
|
||||||
|
} catch (e) {
|
||||||
|
// error shown inline if needed — modal stays open
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function cancelCloudDeleteWarning() {
|
||||||
|
showCloudDeleteWarning.value = false
|
||||||
|
}
|
||||||
|
|
||||||
function formatDate(iso) {
|
function formatDate(iso) {
|
||||||
if (!iso) return ''
|
if (!iso) return ''
|
||||||
return new Date(iso).toLocaleDateString(undefined, { month: 'short', day: 'numeric', year: 'numeric' })
|
return new Date(iso).toLocaleDateString(undefined, { month: 'short', day: 'numeric', year: 'numeric' })
|
||||||
|
|||||||
Reference in New Issue
Block a user