refactor: split stores and use events
Signed-off-by: Sebastian <krupinski01@gmail.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { ref, computed, shallowRef, watch } from 'vue'
|
||||
import { ref, computed, shallowRef } from 'vue'
|
||||
import { defineStore } from 'pinia'
|
||||
import { useCollectionsStore } from '@MailManager/stores/collectionsStore'
|
||||
import { useEntitiesStore } from '@MailManager/stores/entitiesStore'
|
||||
@@ -6,7 +6,21 @@ import { useServicesStore } from '@MailManager/stores/servicesStore'
|
||||
import { useMailSync } from '@MailManager/composables/useMailSync'
|
||||
import { useSnackbar } from '@KTXC'
|
||||
import type { ServiceIdentifier, CollectionIdentifier, EntityIdentifier } from '@MailManager/types/common'
|
||||
import type { ServiceObject, CollectionObject, EntityObject } from '@MailManager/models'
|
||||
import type { EntityTransmitRequest } from '@MailManager/types/entity'
|
||||
import type { MessageAddressInterface, MessageInterface, MessagePartInterface } from '@MailManager/types/message'
|
||||
import { ServiceObject, type CollectionObject, type EntityObject } from '@MailManager/models'
|
||||
import { CollectionPropertiesObject } from '@MailManager/models/collection'
|
||||
|
||||
interface ComposerMessageInput {
|
||||
to: string[]
|
||||
cc: string[]
|
||||
bcc: string[]
|
||||
subject: string
|
||||
body: {
|
||||
html: string
|
||||
text: string
|
||||
}
|
||||
}
|
||||
|
||||
export const useMailStore = defineStore('mailStore', () => {
|
||||
const servicesStore = useServicesStore()
|
||||
@@ -31,27 +45,17 @@ export const useMailStore = defineStore('mailStore', () => {
|
||||
}
|
||||
|
||||
// ── General State ─────────────────-───────────────────────────────────────
|
||||
const sidebarVisible = ref(true)
|
||||
const settingsDialogVisible = ref(false)
|
||||
const loading = ref(false)
|
||||
const serviceFolderLoadingState = ref<Record<string, boolean>>({})
|
||||
const serviceFolderLoadedState = ref<Record<string, boolean>>({})
|
||||
const serviceFolderErrorState = ref<Record<string, string | null>>({})
|
||||
|
||||
// ── Selection State ───────────────────────────────────────────────────────
|
||||
const selectedFolder = shallowRef<CollectionObject | null>(null)
|
||||
const selectedMessage = shallowRef<EntityObject | null>(null)
|
||||
const selectionMode = ref(false)
|
||||
const selectionList = ref<EntityIdentifier[]>([])
|
||||
|
||||
// ── Compose State ─────────────────────────────────────────────────────────
|
||||
const composeMode = ref(false)
|
||||
const composeReplyTo = shallowRef<EntityObject | null>(null)
|
||||
|
||||
// ── Move State ────────────────────────────────────────────────────────────
|
||||
const moveDialogVisible = ref(false)
|
||||
const moveDialogService = ref<ServiceIdentifier | null>(null)
|
||||
const moveDialogCandidates = ref<EntityIdentifier[] | null>(null)
|
||||
const composerSaving = ref(false)
|
||||
const composerSending = ref(false)
|
||||
const composerLastSaved = ref<Date | null>(null)
|
||||
const composerDraftIdentifier = ref<EntityIdentifier | null>(null)
|
||||
|
||||
// ── Computed ──────────────────────────────────────────────────────────────
|
||||
const currentMessages = computed(() => {
|
||||
@@ -98,11 +102,7 @@ export const useMailStore = defineStore('mailStore', () => {
|
||||
|
||||
try {
|
||||
// retrieve folders for service
|
||||
const collections = await collectionsStore.list({
|
||||
[service.provider]: {
|
||||
[String(service.identifier)]: true,
|
||||
},
|
||||
})
|
||||
const collections = await collectionsStore.collectionsForService(service.provider, service.identifier, true)
|
||||
|
||||
_setServiceFolderLoaded(service.provider, service.identifier, true)
|
||||
|
||||
@@ -121,7 +121,6 @@ export const useMailStore = defineStore('mailStore', () => {
|
||||
}
|
||||
|
||||
_updateSyncSources()
|
||||
return collections
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : 'Failed to load folders'
|
||||
_setServiceFolderError(service.provider, service.identifier, message)
|
||||
@@ -139,15 +138,20 @@ export const useMailStore = defineStore('mailStore', () => {
|
||||
// ── Helpers ──────────────────────────────────────────────────────────
|
||||
|
||||
function _serviceIdentifier(item: ServiceObject | CollectionObject | EntityObject | { provider: string, service: string | number }): ServiceIdentifier {
|
||||
if (item instanceof ServiceObject) {
|
||||
return `${item.provider}:${String(item.identifier)}` as ServiceIdentifier
|
||||
}
|
||||
return `${item.provider}:${String(item.service)}` as ServiceIdentifier
|
||||
}
|
||||
|
||||
function _collectionIdentifier(item: CollectionObject | EntityObject): CollectionIdentifier {
|
||||
return `${item.provider}:${String(item.service)}:${String(item.identifier)}` as CollectionIdentifier
|
||||
}
|
||||
function _sameCollection(left: CollectionObject | null | undefined, right: CollectionObject | null | undefined): boolean {
|
||||
if (!left || !right) {
|
||||
return false
|
||||
}
|
||||
|
||||
function _entityIdentifier(item: EntityObject): EntityIdentifier {
|
||||
return `${item.provider}:${String(item.service)}:${String(item.collection)}:${String(item.identifier)}` as EntityIdentifier
|
||||
return left.provider === right.provider &&
|
||||
String(left.service) === String(right.service) &&
|
||||
String(left.identifier) === String(right.identifier)
|
||||
}
|
||||
|
||||
function _setServiceFolderLoading(provider: string, service: string | number, loadingState: boolean) {
|
||||
@@ -176,15 +180,18 @@ export const useMailStore = defineStore('mailStore', () => {
|
||||
|
||||
// Track the currently selected folder
|
||||
if (selectedFolder.value) {
|
||||
mailSyncController.addSource({
|
||||
provider: selectedFolder.value.provider,
|
||||
service: selectedFolder.value.service,
|
||||
collections: [selectedFolder.value.identifier],
|
||||
})
|
||||
//mailSyncController.addSource({
|
||||
// provider: selectedFolder.value.provider,
|
||||
// service: selectedFolder.value.service,
|
||||
// collections: [selectedFolder.value.identifier],
|
||||
//})
|
||||
}
|
||||
|
||||
// Always track inboxes for each account (for new-mail notifications)
|
||||
servicesStore.servicesEnabled.forEach(service => {
|
||||
if (service.identifier === null) {
|
||||
return
|
||||
}
|
||||
const inboxes = collectionsStore.collectionsForService(service.provider, service.identifier).filter(
|
||||
c =>
|
||||
String(c.service) === String(service.identifier) &&
|
||||
@@ -193,11 +200,11 @@ export const useMailStore = defineStore('mailStore', () => {
|
||||
)
|
||||
|
||||
if (inboxes.length > 0) {
|
||||
mailSyncController.addSource({
|
||||
provider: service.provider,
|
||||
service: service.identifier as string | number,
|
||||
collections: inboxes.map(inbox => inbox.identifier),
|
||||
})
|
||||
//mailSyncController.addSource({
|
||||
// provider: service.provider,
|
||||
// service: service.identifier as string | number,
|
||||
// collections: inboxes.map(inbox => inbox.identifier),
|
||||
//})
|
||||
}
|
||||
})
|
||||
|
||||
@@ -218,58 +225,113 @@ export const useMailStore = defineStore('mailStore', () => {
|
||||
return serviceFolderErrorState.value[_serviceIdentifier({ provider, service })] ?? null
|
||||
}
|
||||
|
||||
function _reloadFolderMessages(folder: CollectionObject) {
|
||||
return entitiesStore.list({
|
||||
[folder.provider]: {
|
||||
[String(folder.service)]: {
|
||||
[String(folder.identifier)]: true,
|
||||
},
|
||||
function _findDraftFolder(folder: CollectionObject): CollectionObject {
|
||||
return collectionsStore.collectionsForService(folder.provider, folder.service).find(
|
||||
candidate =>
|
||||
candidate.provider === folder.provider &&
|
||||
String(candidate.service) === String(folder.service) &&
|
||||
(candidate.properties.role === 'drafts' ||
|
||||
String(candidate.identifier).toLowerCase() === 'drafts' ||
|
||||
candidate.properties.label.toLowerCase() === 'drafts'),
|
||||
) ?? folder
|
||||
}
|
||||
|
||||
function _toMessageAddresses(addresses: string[]): MessageAddressInterface[] | undefined {
|
||||
const normalized = addresses
|
||||
.map(address => address.trim())
|
||||
.filter(address => address.length > 0)
|
||||
|
||||
if (normalized.length === 0) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
return normalized.map(address => ({ address }))
|
||||
}
|
||||
|
||||
function _toDraftBody(body: ComposerMessageInput['body']): MessagePartInterface | null {
|
||||
const parts: MessagePartInterface[] = []
|
||||
const text = body.text.trim()
|
||||
const html = body.html.trim()
|
||||
|
||||
if (text.length > 0) {
|
||||
parts.push({
|
||||
type: 'text/plain',
|
||||
content: text,
|
||||
})
|
||||
}
|
||||
|
||||
if (html.length > 0) {
|
||||
parts.push({
|
||||
type: 'text/html',
|
||||
content: html,
|
||||
})
|
||||
}
|
||||
|
||||
if (parts.length === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (parts.length === 1) {
|
||||
return parts[0]
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'multipart/alternative',
|
||||
subParts: parts,
|
||||
}
|
||||
}
|
||||
|
||||
function _toDraftProperties(message: ComposerMessageInput): MessageInterface {
|
||||
return {
|
||||
'@type': 'mail:message',
|
||||
to: _toMessageAddresses(message.to),
|
||||
cc: _toMessageAddresses(message.cc),
|
||||
bcc: _toMessageAddresses(message.bcc),
|
||||
subject: message.subject.trim() || null,
|
||||
body: _toDraftBody(message.body),
|
||||
flags: {
|
||||
draft: true,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
function _setSelectionList(nextIds: EntityIdentifier[]) {
|
||||
selectionList.value = Array.from(new Set(nextIds))
|
||||
|
||||
if (selectionList.value.length === 0) {
|
||||
selectionMode.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function _reconcileSelection() {
|
||||
if (!selectedFolder.value) {
|
||||
clearSelection()
|
||||
selectedMessage.value = null
|
||||
return
|
||||
}
|
||||
|
||||
const currentMessageIdentifiers = new Set(currentMessages.value.map(message => _entityIdentifier(message)))
|
||||
const nextSelectedIds = selectionList.value.filter(identifier => currentMessageIdentifiers.has(identifier))
|
||||
|
||||
if (nextSelectedIds.length !== selectionList.value.length) {
|
||||
_setSelectionList(nextSelectedIds)
|
||||
}
|
||||
|
||||
if (selectedMessage.value && !currentMessageIdentifiers.has(_entityIdentifier(selectedMessage.value))) {
|
||||
selectedMessage.value = null
|
||||
}
|
||||
function resetComposerState() {
|
||||
composerSaving.value = false
|
||||
composerSending.value = false
|
||||
composerLastSaved.value = null
|
||||
composerDraftIdentifier.value = null
|
||||
}
|
||||
|
||||
watch(currentMessages, () => {
|
||||
_reconcileSelection()
|
||||
})
|
||||
|
||||
// ── Actions ───────────────────────────────────────────────────────────────
|
||||
|
||||
async function retrieveService(identifier: ServiceIdentifier, force: boolean = false): Promise<ServiceObject | null> {
|
||||
let service = servicesStore.serviceByIdentifier(identifier)
|
||||
if (service && !force) {
|
||||
return service
|
||||
}
|
||||
|
||||
try {
|
||||
service = await servicesStore.serviceByIdentifier(identifier, true)
|
||||
} catch (error) {
|
||||
console.error(`[Mail] Failed to retrieve service ${identifier}:`, error)
|
||||
throw error
|
||||
}
|
||||
|
||||
if (!service) {
|
||||
const message = `Service ${identifier} not found`
|
||||
console.error(`[Mail] ${message}`)
|
||||
throw new Error(message)
|
||||
}
|
||||
|
||||
return service
|
||||
}
|
||||
|
||||
async function selectFolder(folder: CollectionObject) {
|
||||
selectedFolder.value = folder
|
||||
selectedMessage.value = null
|
||||
clearSelection()
|
||||
selectionMode.value = false
|
||||
composeMode.value = false
|
||||
|
||||
try {
|
||||
await _reloadFolderMessages(folder)
|
||||
await entitiesStore.list([folder.identifier])
|
||||
} catch (error) {
|
||||
console.error('[Mail] Failed to load messages:', error)
|
||||
}
|
||||
@@ -280,140 +342,216 @@ export const useMailStore = defineStore('mailStore', () => {
|
||||
function clearSelectedFolder() {
|
||||
selectedFolder.value = null
|
||||
selectedMessage.value = null
|
||||
clearSelection()
|
||||
selectionMode.value = false
|
||||
composeMode.value = false
|
||||
composeReplyTo.value = null
|
||||
|
||||
_updateSyncSources()
|
||||
}
|
||||
|
||||
function selectMessage(entity: EntityObject, closeSidebar = false) {
|
||||
function selectMessage(entity: EntityObject) {
|
||||
selectedMessage.value = entity
|
||||
composeMode.value = false
|
||||
|
||||
if (closeSidebar) {
|
||||
sidebarVisible.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function openCompose(replyTo?: EntityObject) {
|
||||
composeMode.value = true
|
||||
composeReplyTo.value = replyTo ?? null
|
||||
function clearSelectedMessage() {
|
||||
selectedMessage.value = null
|
||||
}
|
||||
|
||||
function closeCompose() {
|
||||
composeMode.value = false
|
||||
composeReplyTo.value = null
|
||||
}
|
||||
|
||||
async function afterSent() {
|
||||
composeMode.value = false
|
||||
composeReplyTo.value = null
|
||||
|
||||
async function reloadSelectedFolder() {
|
||||
// Reload the current folder so the sent message appears in Sent
|
||||
if (selectedFolder.value) {
|
||||
await selectFolder(selectedFolder.value)
|
||||
}
|
||||
}
|
||||
|
||||
function isMessageSelected(message: EntityObject) {
|
||||
return selectionList.value.includes(_entityIdentifier(message))
|
||||
async function saveComposerDraft(folder: CollectionObject, message: ComposerMessageInput) {
|
||||
composerSaving.value = true
|
||||
|
||||
try {
|
||||
const targetFolder = _findDraftFolder(folder)
|
||||
const properties = _toDraftProperties(message)
|
||||
const draft = composerDraftIdentifier.value
|
||||
? await entitiesStore.update(composerDraftIdentifier.value, properties)
|
||||
: await entitiesStore.create(targetFolder.identifier, properties)
|
||||
|
||||
composerDraftIdentifier.value = draft.identifier
|
||||
composerLastSaved.value = new Date()
|
||||
|
||||
return draft
|
||||
} catch (error) {
|
||||
console.error('[Mail] Failed to save draft:', error)
|
||||
throw error
|
||||
} finally {
|
||||
composerSaving.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function toggleMessageSelection(message: EntityObject) {
|
||||
const identifier = _entityIdentifier(message)
|
||||
async function sendComposerMessage(message: ComposerMessageInput) {
|
||||
composerSending.value = true
|
||||
|
||||
selectionMode.value = true
|
||||
|
||||
if (selectionList.value.includes(identifier)) {
|
||||
_setSelectionList(selectionList.value.filter(selectedId => selectedId !== identifier))
|
||||
|
||||
return
|
||||
const transmitRequest: EntityTransmitRequest = {
|
||||
message: {
|
||||
to: message.to.map(address => address.trim()).filter(address => address.length > 0),
|
||||
cc: message.cc.map(address => address.trim()).filter(address => address.length > 0),
|
||||
bcc: message.bcc.map(address => address.trim()).filter(address => address.length > 0),
|
||||
subject: message.subject,
|
||||
body: {
|
||||
html: message.body.html,
|
||||
text: message.body.text,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
_setSelectionList([...selectionList.value, identifier])
|
||||
}
|
||||
if (transmitRequest.message.cc?.length === 0) {
|
||||
delete transmitRequest.message.cc
|
||||
}
|
||||
|
||||
function selectAllCurrentMessages() {
|
||||
selectionMode.value = true
|
||||
_setSelectionList(currentMessages.value.map(message => _entityIdentifier(message)))
|
||||
}
|
||||
if (transmitRequest.message.bcc?.length === 0) {
|
||||
delete transmitRequest.message.bcc
|
||||
}
|
||||
|
||||
function activateSelectionMode(message?: EntityObject) {
|
||||
selectionMode.value = true
|
||||
try {
|
||||
const response = await entitiesStore.transmit(transmitRequest)
|
||||
|
||||
if (message) {
|
||||
const identifier = _entityIdentifier(message)
|
||||
|
||||
if (!selectionList.value.includes(identifier)) {
|
||||
_setSelectionList([...selectionList.value, identifier])
|
||||
if (composerDraftIdentifier.value) {
|
||||
try {
|
||||
await entitiesStore.delete([composerDraftIdentifier.value])
|
||||
} catch (error) {
|
||||
console.error('[Mail] Failed to delete draft after send:', error)
|
||||
}
|
||||
}
|
||||
|
||||
notify('Message sent', 'success')
|
||||
resetComposerState()
|
||||
return response
|
||||
} catch (error) {
|
||||
const messageText = error instanceof Error ? error.message : 'Failed to send message'
|
||||
console.error('[Mail] Failed to send message:', error)
|
||||
notify(messageText, 'error')
|
||||
throw error
|
||||
} finally {
|
||||
composerSending.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function deactivateSelectionMode() {
|
||||
selectionMode.value = false
|
||||
clearSelection()
|
||||
}
|
||||
|
||||
function clearSelection() {
|
||||
_setSelectionList([])
|
||||
}
|
||||
|
||||
function openMoveDialog(entities?: EntityObject | EntityObject[]) {
|
||||
|
||||
moveDialogCandidates.value = []
|
||||
|
||||
if (entities) {
|
||||
if (Array.isArray(entities)) {
|
||||
moveDialogCandidates.value = entities.map(entity => _entityIdentifier(entity))
|
||||
moveDialogService.value = _serviceIdentifier(entities[0])
|
||||
} else {
|
||||
moveDialogCandidates.value = [_entityIdentifier(entities)]
|
||||
moveDialogService.value = _serviceIdentifier(entities)
|
||||
}
|
||||
} else {
|
||||
moveDialogCandidates.value = selectionList.value
|
||||
moveDialogService.value = _serviceIdentifier(selectedFolder.value)
|
||||
async function createFolder(
|
||||
service: ServiceObject,
|
||||
label: string,
|
||||
parentFolder: CollectionObject | null = null,
|
||||
): Promise<CollectionObject> {
|
||||
if (service.identifier === null) {
|
||||
throw new Error('Cannot create folder for a service without an identifier')
|
||||
}
|
||||
|
||||
moveDialogVisible.value = true
|
||||
const properties = new CollectionPropertiesObject()
|
||||
properties.label = label.trim()
|
||||
properties.rank = 0
|
||||
properties.subscribed = true
|
||||
|
||||
const newFolder = await collectionsStore.create(
|
||||
service.provider,
|
||||
service.identifier,
|
||||
properties,
|
||||
parentFolder?.identifier,
|
||||
)
|
||||
|
||||
notify(
|
||||
`Folder "${newFolder.properties.label || properties.label}" created`,
|
||||
'success',
|
||||
)
|
||||
|
||||
return newFolder
|
||||
}
|
||||
|
||||
function closeMoveDialog() {
|
||||
moveDialogVisible.value = false
|
||||
moveDialogService.value = null
|
||||
moveDialogCandidates.value = null
|
||||
async function renameFolder(folder: CollectionObject, label: string): Promise<CollectionObject> {
|
||||
const properties = new CollectionPropertiesObject()
|
||||
properties.label = label.trim()
|
||||
properties.rank = folder.properties.rank ?? 0
|
||||
properties.subscribed = folder.properties.subscribed ?? true
|
||||
|
||||
const updatedFolder = await collectionsStore.update(folder.identifier, properties)
|
||||
|
||||
if (_sameCollection(selectedFolder.value, folder)) {
|
||||
selectedFolder.value = updatedFolder
|
||||
}
|
||||
|
||||
notify(
|
||||
`Folder "${folder.properties.label || String(folder.identifier)}" renamed to "${updatedFolder.properties.label || properties.label}"`,
|
||||
'success',
|
||||
)
|
||||
|
||||
return updatedFolder
|
||||
}
|
||||
|
||||
async function moveFolder(source: CollectionObject, target: CollectionObject): Promise<CollectionObject> {
|
||||
const movedFolder = await collectionsStore.move(target.identifier, source.identifier)
|
||||
|
||||
if (_sameCollection(selectedFolder.value, source)) {
|
||||
selectedFolder.value = movedFolder
|
||||
}
|
||||
|
||||
notify(
|
||||
`Folder "${source.properties.label || String(source.identifier)}" moved to "${target.properties.label || String(target.identifier)}"`,
|
||||
'success',
|
||||
)
|
||||
|
||||
return movedFolder
|
||||
}
|
||||
|
||||
async function deleteFolder(folder: CollectionObject): Promise<CollectionObject | boolean> {
|
||||
const deletedFolder = await collectionsStore.delete(folder.identifier)
|
||||
|
||||
if (_sameCollection(selectedFolder.value, folder)) {
|
||||
clearSelectedFolder()
|
||||
}
|
||||
|
||||
notify(
|
||||
`Folder "${folder.properties.label || String(folder.identifier)}" deleted`,
|
||||
'success',
|
||||
)
|
||||
|
||||
return deletedFolder
|
||||
}
|
||||
|
||||
async function moveMessages(target: CollectionObject, entityIdentifiers: EntityIdentifier[]) {
|
||||
const movableIdentifiers = entityIdentifiers.filter(identifier => {
|
||||
const entity = entitiesStore.entityByIdentifier(identifier)
|
||||
const { movableIdentifiers, sourceCollections } = entityIdentifiers.reduce(
|
||||
(accumulator, identifier) => {
|
||||
const entity = entitiesStore.entity(identifier)
|
||||
|
||||
if (!entity) {
|
||||
return false
|
||||
}
|
||||
if (!entity) {
|
||||
return accumulator
|
||||
}
|
||||
|
||||
// Only allow moving messages within the same service and disallow moving into the same folder
|
||||
return entity.provider === target.provider &&
|
||||
String(entity.service) === String(target.service) &&
|
||||
String(entity.collection) !== String(target.identifier)
|
||||
})
|
||||
// Only allow moving messages within the same service and disallow moving into the same folder
|
||||
const canMove = entity.provider === target.provider &&
|
||||
String(entity.service) === String(target.service) &&
|
||||
String(entity.collection) !== String(target.identifier)
|
||||
|
||||
if (!canMove) {
|
||||
return accumulator
|
||||
}
|
||||
|
||||
accumulator.movableIdentifiers.push(identifier)
|
||||
|
||||
if (!accumulator.sourceCollections.some(
|
||||
collection => String(collection) === String(entity.collection),
|
||||
)) {
|
||||
accumulator.sourceCollections.push(entity.collection)
|
||||
}
|
||||
|
||||
return accumulator
|
||||
},
|
||||
{
|
||||
movableIdentifiers: [] as EntityIdentifier[],
|
||||
sourceCollections: [] as CollectionIdentifier[],
|
||||
},
|
||||
)
|
||||
|
||||
if (movableIdentifiers.length === 0) {
|
||||
closeMoveDialog()
|
||||
return
|
||||
}
|
||||
|
||||
loading.value = true
|
||||
|
||||
try {
|
||||
const [successes, failures] = await entitiesStore.move(_collectionIdentifier(target), movableIdentifiers)
|
||||
|
||||
clearSelection()
|
||||
closeMoveDialog()
|
||||
const { successes, failures } = await entitiesStore.move(target.identifier, movableIdentifiers)
|
||||
|
||||
if (failures.length === 0) {
|
||||
notify(
|
||||
@@ -430,6 +568,10 @@ export const useMailStore = defineStore('mailStore', () => {
|
||||
successes.length === 0 ? 'error' : 'warning',
|
||||
)
|
||||
}
|
||||
|
||||
// update source collections to reflect moved messages
|
||||
sourceCollections.push(target.identifier)
|
||||
await collectionsStore.fetch(sourceCollections)
|
||||
} catch (error) {
|
||||
const messageText = error instanceof Error ? error.message : 'Failed to move messages'
|
||||
console.error('[Mail] Failed to move messages:', error)
|
||||
@@ -448,9 +590,7 @@ export const useMailStore = defineStore('mailStore', () => {
|
||||
loading.value = true
|
||||
|
||||
try {
|
||||
const [successes, failures] = await entitiesStore.delete(entityIdentifiers)
|
||||
|
||||
clearSelection()
|
||||
const { successes, failures } = await entitiesStore.delete(entityIdentifiers)
|
||||
|
||||
if (failures.length === 0) {
|
||||
notify(
|
||||
@@ -477,14 +617,6 @@ export const useMailStore = defineStore('mailStore', () => {
|
||||
}
|
||||
}
|
||||
|
||||
function toggleSidebar() {
|
||||
sidebarVisible.value = !sidebarVisible.value
|
||||
}
|
||||
|
||||
function openSettings() {
|
||||
settingsDialogVisible.value = true
|
||||
}
|
||||
|
||||
function notify(message: string, color: 'success' | 'error' | 'info' | 'warning' = 'success') {
|
||||
showSnackbar({ message, color })
|
||||
}
|
||||
@@ -499,18 +631,13 @@ export const useMailStore = defineStore('mailStore', () => {
|
||||
mailSync,
|
||||
|
||||
// State
|
||||
sidebarVisible,
|
||||
settingsDialogVisible,
|
||||
loading,
|
||||
selectedFolder,
|
||||
selectedMessage,
|
||||
selectionList,
|
||||
selectionMode,
|
||||
composeMode,
|
||||
composeReplyTo,
|
||||
moveDialogVisible,
|
||||
moveDialogService,
|
||||
moveDialogCandidates,
|
||||
composerSaving,
|
||||
composerSending,
|
||||
composerLastSaved,
|
||||
composerDraftIdentifier,
|
||||
serviceFolderLoadingState,
|
||||
serviceFolderLoadedState,
|
||||
serviceFolderErrorState,
|
||||
@@ -519,24 +646,21 @@ export const useMailStore = defineStore('mailStore', () => {
|
||||
currentMessages,
|
||||
|
||||
// Actions
|
||||
retrieveService,
|
||||
selectFolder,
|
||||
clearSelectedFolder,
|
||||
selectMessage,
|
||||
isMessageSelected,
|
||||
activateSelectionMode,
|
||||
deactivateSelectionMode,
|
||||
toggleMessageSelection,
|
||||
selectAllCurrentMessages,
|
||||
clearSelection,
|
||||
openCompose,
|
||||
openMoveDialog,
|
||||
closeMoveDialog,
|
||||
closeCompose,
|
||||
afterSent,
|
||||
clearSelectedMessage,
|
||||
createFolder,
|
||||
reloadSelectedFolder,
|
||||
saveComposerDraft,
|
||||
sendComposerMessage,
|
||||
resetComposerState,
|
||||
deleteMessages,
|
||||
deleteFolder,
|
||||
moveMessages,
|
||||
toggleSidebar,
|
||||
openSettings,
|
||||
moveFolder,
|
||||
renameFolder,
|
||||
notify,
|
||||
isServiceFolderLoading,
|
||||
hasServiceFoldersLoaded,
|
||||
|
||||
Reference in New Issue
Block a user