@@ -454,12 +454,16 @@ final class VolumeManager {
454454 disableAutomount ( for: volume)
455455 guard let path = mountPaths [ volume. id] else { return }
456456
457- mountPaths. removeValue ( forKey: volume. id)
458457 busyVolumes. insert ( volume. id)
459458 log ( " Disconnecting \( volume. name) " )
460459
461460 Task {
462- await MountService . unmount ( path: path)
461+ guard await MountService . unmount ( path: path) else {
462+ self . reportUnmountFailure ( for: volume, action: " Disconnect " )
463+ await self . refreshState ( )
464+ return
465+ }
466+ self . mountPaths. removeValue ( forKey: volume. id)
463467 self . busyVolumes. remove ( volume. id)
464468 self . log ( " Disconnected: \( volume. name) " )
465469 await self . refreshState ( )
@@ -488,33 +492,67 @@ final class VolumeManager {
488492 }
489493
490494 func removeVolume( _ id: UUID ) {
491- if let v = volumes. first ( where: { $0. id == id } ) {
492- log ( " Removed volume: \( v. name) " )
495+ guard let volume = volumes. first ( where: { $0. id == id } ) else { return }
496+ guard let path = mountPaths [ id] else {
497+ removeVolumeConfiguration ( id: id, name: volume. name)
498+ Task { await refreshState ( ) }
499+ return
500+ }
501+
502+ busyVolumes. insert ( id)
503+ log ( " Removing volume: \( volume. name) " )
504+ Task {
505+ guard await MountService . unmount ( path: path) else {
506+ self . reportUnmountFailure ( for: volume, action: " Remove " )
507+ await self . refreshState ( )
508+ return
509+ }
510+ self . mountPaths. removeValue ( forKey: id)
511+ self . busyVolumes. remove ( id)
512+ self . removeVolumeConfiguration ( id: id, name: volume. name)
513+ await self . refreshState ( )
493514 }
494- volumes. removeAll { $0. id == id }
495- storage. saveVolumes ( volumes)
496- Task { await refreshState ( ) }
497515 }
498516
499517 func editVolume( id: UUID , name: String , serverAddress: String ) {
500518 guard let idx = volumes. firstIndex ( where: { $0. id == id } ) else { return }
501519 let old = volumes [ idx]
502520 let addressChanged = old. serverAddress != serverAddress
503521
504- volumes [ idx] . name = name
505- volumes [ idx] . serverAddress = serverAddress
506- storage. saveVolumes ( volumes)
507- log ( " Updated volume: \( name) " )
522+ if !addressChanged {
523+ volumes [ idx] . name = name
524+ storage. saveVolumes ( volumes)
525+ log ( " Updated volume: \( name) " )
526+ return
527+ }
508528
509- guard addressChanged, let oldPath = mountPaths [ id] else { return }
529+ guard let oldPath = mountPaths [ id] else {
530+ volumes [ idx] . name = name
531+ volumes [ idx] . serverAddress = serverAddress
532+ storage. saveVolumes ( volumes)
533+ log ( " Updated volume: \( name) " )
534+ return
535+ }
510536
511537 // Unmount the old connection by its recorded path, then remount at the new address.
512538 // Using oldPath (not the new address) ensures we disconnect the right kernel mount
513539 // even if the new address points to a different share entirely.
514- mountPaths. removeValue ( forKey: id)
515540 busyVolumes. insert ( id)
516541 Task {
517- await MountService . unmount ( path: oldPath)
542+ guard await MountService . unmount ( path: oldPath) else {
543+ self . reportUnmountFailure ( for: old, action: " Reconnect " )
544+ await self . refreshState ( )
545+ return
546+ }
547+ self . mountPaths. removeValue ( forKey: id)
548+ guard let currentIndex = self . volumes. firstIndex ( where: { $0. id == id } ) else {
549+ self . busyVolumes. remove ( id)
550+ return
551+ }
552+ self . volumes [ currentIndex] . name = name
553+ self . volumes [ currentIndex] . serverAddress = serverAddress
554+ self . storage. saveVolumes ( self . volumes)
555+ self . log ( " Updated volume: \( name) " )
518556 guard let url = URL ( string: serverAddress) else {
519557 self . busyVolumes. remove ( id)
520558 return
@@ -530,14 +568,50 @@ final class VolumeManager {
530568 self . showError = true
531569 }
532570 self . busyVolumes. remove ( id)
571+ await self . refreshState ( )
533572 }
534573 }
535574
536575 func clearAllVolumes( ) {
537- log ( " Cleared all volumes " )
538- volumes. removeAll ( )
576+ let configuredVolumes = volumes
577+ let mountedVolumes = configuredVolumes. compactMap { volume in
578+ mountPaths [ volume. id] . map { ( volume, $0) }
579+ }
580+ for (volume, _) in mountedVolumes { busyVolumes. insert ( volume. id) }
581+
582+ Task {
583+ var retainedIDs = Set < UUID > ( )
584+ for (volume, path) in mountedVolumes {
585+ guard await MountService . unmount ( path: path) else {
586+ retainedIDs. insert ( volume. id)
587+ self . reportUnmountFailure ( for: volume, action: " Clear " )
588+ continue
589+ }
590+ self . mountPaths. removeValue ( forKey: volume. id)
591+ self . busyVolumes. remove ( volume. id)
592+ }
593+ self . volumes. removeAll { !retainedIDs. contains ( $0. id) }
594+ self . storage. saveVolumes ( self . volumes)
595+ if retainedIDs. isEmpty {
596+ self . log ( " Cleared all volumes " )
597+ } else {
598+ self . log ( " Clear retained \( retainedIDs. count) mounted volume(s) " , level: . warning)
599+ }
600+ await self . refreshState ( )
601+ }
602+ }
603+
604+ private func removeVolumeConfiguration( id: UUID , name: String ) {
605+ volumes. removeAll { $0. id == id }
539606 storage. saveVolumes ( volumes)
540- Task { await refreshState ( ) }
607+ log ( " Removed volume: \( name) " )
608+ }
609+
610+ private func reportUnmountFailure( for volume: Volume , action: String ) {
611+ busyVolumes. remove ( volume. id)
612+ lastError = " Could not disconnect \( volume. name) . The share remains mounted. "
613+ showError = true
614+ log ( " \( action) failed; \( volume. name) remains mounted " , level: . error)
541615 }
542616
543617 func toggleAutomount( _ id: UUID ) {
0 commit comments