7 Commits

4 changed files with 596 additions and 767 deletions

1254
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -23,13 +23,13 @@
"vue": "^3.4.0", "vue": "^3.4.0",
"vue-router": "^4.2.5", "vue-router": "^4.2.5",
"pinia": "^3.0.0", "pinia": "^3.0.0",
"vuetify": "^3.5.0" "vuetify": "^4.0.0"
}, },
"devDependencies": { "devDependencies": {
"@vitejs/plugin-vue": "^6.0.0", "@vitejs/plugin-vue": "^6.0.0",
"@vue/tsconfig": "^0.9.0", "@vue/tsconfig": "^0.9.0",
"typescript": "^6.0.0", "typescript": "^6.0.0",
"vite": "^5.0.0", "vite": "^8.0.0",
"vue-tsc": "^3.0.0" "vue-tsc": "^3.0.0"
} }
} }

View File

@@ -1,6 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed, ref, watch } from 'vue' import { computed, ref, watch } from 'vue'
import { useCollectionsStore } from '@MailManager/stores/collectionsStore' import { useCollectionsStore } from '@MailManager/stores/collectionsStore'
import { useServicesStore } from '@MailManager/stores/servicesStore'
import { useMailStore } from '@/stores/mailStore' import { useMailStore } from '@/stores/mailStore'
import type { ServiceObject, CollectionObject } from '@MailManager/models' import type { ServiceObject, CollectionObject } from '@MailManager/models'
import FolderSelectionTreeNode from './FolderSelectionTreeNode.vue' import FolderSelectionTreeNode from './FolderSelectionTreeNode.vue'
@@ -31,6 +32,7 @@ const emit = defineEmits<{
}>() }>()
const collectionsStore = useCollectionsStore() const collectionsStore = useCollectionsStore()
const servicesStore = useServicesStore()
const mailStore = useMailStore() const mailStore = useMailStore()
const selectedFolderKey = ref<string | null>(null) const selectedFolderKey = ref<string | null>(null)
@@ -52,7 +54,8 @@ interface ServiceGroup {
} }
const serviceGroups = computed<ServiceGroup[]>(() => { const serviceGroups = computed<ServiceGroup[]>(() => {
const service = props.service ?? mailStore.moveDialogService const service = props.service ??
(mailStore.moveDialogService ? servicesStore.serviceByIdentifier(mailStore.moveDialogService) : null)
if (!service) { if (!service) {
return [] return []

View File

@@ -255,26 +255,6 @@ export const useMailStore = defineStore('mailStore', () => {
} }
} }
function _formatMoveNotification(successCount: number, failureCount: number, targetFolder: CollectionObject) {
const folderLabel = targetFolder.properties.label || String(targetFolder.identifier)
if (failureCount === 0) {
return {
message: successCount === 1
? `Message moved to "${folderLabel}"`
: `${successCount} messages moved to "${folderLabel}"`,
color: 'success' as const,
}
}
return {
message: successCount === 0
? `Move failed for ${failureCount === 1 ? '1 message' : `${failureCount} messages`}`
: `Moved ${successCount} ${successCount === 1 ? 'message' : 'messages'} to "${folderLabel}". ${failureCount} failed.`,
color: successCount === 0 ? 'error' as const : 'warning' as const,
}
}
watch(currentMessages, () => { watch(currentMessages, () => {
_reconcileSelection() _reconcileSelection()
}) })
@@ -430,32 +410,26 @@ export const useMailStore = defineStore('mailStore', () => {
loading.value = true loading.value = true
try { try {
const response = await entitiesStore.move(_collectionIdentifier(target), movableIdentifiers) const [successes, failures] = await entitiesStore.move(_collectionIdentifier(target), movableIdentifiers)
const operationSucceeded: EntityIdentifier[] = []
const operationFailures: EntityIdentifier[] = []
Object.entries(response).forEach(([sourceIdentifier, result]) => {
if (result.success) {
operationSucceeded.push(sourceIdentifier as EntityIdentifier)
return
}
operationFailures.push(sourceIdentifier as EntityIdentifier)
})
if (operationSucceeded.length === 0) {
throw new Error(operationFailures[0] ?? 'Failed to move messages')
}
if (selectedMessage.value && operationSucceeded.includes(_entityIdentifier(selectedMessage.value))) {
selectedMessage.value = null
}
clearSelection() clearSelection()
closeMoveDialog() closeMoveDialog()
const notification = _formatMoveNotification(operationSucceeded.length, operationFailures.length, target) if (failures.length === 0) {
notify(notification.message, notification.color) notify(
successes.length === 1 ? 'Message moved' : `${successes.length} messages moved`,
'success',
)
}
if (failures.length > 0) {
notify(
successes.length === 0
? `Move failed for ${failures.length === 1 ? '1 message' : `${failures.length} messages`}`
: `Moved ${successes.length} ${successes.length === 1 ? 'message' : 'messages'}. ${failures.length} failed.`,
successes.length === 0 ? 'error' : 'warning',
)
}
} catch (error) { } catch (error) {
const messageText = error instanceof Error ? error.message : 'Failed to move messages' const messageText = error instanceof Error ? error.message : 'Failed to move messages'
console.error('[Mail] Failed to move messages:', error) console.error('[Mail] Failed to move messages:', error)
@@ -474,43 +448,23 @@ export const useMailStore = defineStore('mailStore', () => {
loading.value = true loading.value = true
try { try {
const response = await entitiesStore.delete(entityIdentifiers) const [successes, failures] = await entitiesStore.delete(entityIdentifiers)
const operationSucceeded: EntityIdentifier[] = []
const operationFailures: EntityIdentifier[] = []
Object.entries(response).forEach(([sourceIdentifier, result]) => {
if (result.success) {
operationSucceeded.push(sourceIdentifier as EntityIdentifier)
return
}
operationFailures.push(sourceIdentifier as EntityIdentifier)
})
if (operationSucceeded.length === 0) {
throw new Error(operationFailures[0] ?? 'Failed to delete messages')
}
if (selectedMessage.value && operationSucceeded.includes(_entityIdentifier(selectedMessage.value))) {
selectedMessage.value = null
}
clearSelection() clearSelection()
const successCount = operationSucceeded.length if (failures.length === 0) {
const failureCount = operationFailures.length
if (failureCount === 0) {
notify( notify(
successCount === 1 ? 'Message deleted' : `${successCount} messages deleted`, successes.length === 1 ? 'Message deleted' : `${successes.length} messages deleted`,
'success', 'success',
) )
} else { }
if (failures.length > 0) {
notify( notify(
successCount === 0 successes.length === 0
? `Delete failed for ${failureCount === 1 ? '1 message' : `${failureCount} messages`}` ? `Delete failed for ${failures.length === 1 ? '1 message' : `${failures.length} messages`}`
: `Deleted ${successCount} ${successCount === 1 ? 'message' : 'messages'}. ${failureCount} failed.`, : `Deleted ${successes.length} ${successes.length === 1 ? 'message' : 'messages'}. ${failures.length} failed.`,
successCount === 0 ? 'error' : 'warning', successes.length === 0 ? 'error' : 'warning',
) )
} }
} catch (error) { } catch (error) {