diff --git a/phpmon/Domain/App/Base.lproj/Main.storyboard b/phpmon/Domain/App/Base.lproj/Main.storyboard index 373b1c7..a4831dd 100644 --- a/phpmon/Domain/App/Base.lproj/Main.storyboard +++ b/phpmon/Domain/App/Base.lproj/Main.storyboard @@ -720,7 +720,7 @@ Gw - + @@ -788,24 +788,24 @@ Gw - + - - + + - - - + + + - - + + @@ -822,6 +822,7 @@ Gw + @@ -857,6 +858,7 @@ Gw + @@ -895,7 +897,7 @@ Gw - + @@ -905,14 +907,15 @@ Gw + - + - + @@ -950,7 +953,7 @@ Gw - + @@ -959,14 +962,15 @@ Gw + - + - + @@ -976,8 +980,8 @@ Gw - + @@ -995,10 +999,11 @@ Gw + - + @@ -1047,20 +1052,20 @@ Gw - + - + - + - + diff --git a/phpmon/Domain/Integrations/Valet/ValetSite.swift b/phpmon/Domain/Integrations/Valet/ValetSite.swift index 5538d8a..ed87be0 100644 --- a/phpmon/Domain/Integrations/Valet/ValetSite.swift +++ b/phpmon/Domain/Integrations/Valet/ValetSite.swift @@ -53,6 +53,12 @@ class ValetSite { /// How the PHP version was determined. var composerPhpSource: VersionSource = .unknown + /// Which version of PHP is actually used to serve this site. + var servingPhpVersion: String { + return self.isolatedPhpVersion?.versionNumber.homebrewVersion + ?? PhpEnv.phpInstall.version.short + } + enum VersionSource: String { case unknown = "unknown" case require = "require" diff --git a/phpmon/Domain/SiteList/Cells/SiteListKindCell.swift b/phpmon/Domain/SiteList/Cells/SiteListKindCell.swift index 9ca7346..6cdb823 100644 --- a/phpmon/Domain/SiteList/Cells/SiteListKindCell.swift +++ b/phpmon/Domain/SiteList/Cells/SiteListKindCell.swift @@ -11,12 +11,11 @@ import AppKit class SiteListKindCell: NSTableCellView, SiteListCellProtocol { + static let reusableName = "siteListKindCell" + @IBOutlet weak var imageViewType: NSImageView! func populateCell(with site: ValetSite) { - - - // If the `aliasPath` is nil, we're dealing with a parked site (otherwise: linked). imageViewType.image = NSImage( named: site.aliasPath == nil diff --git a/phpmon/Domain/SiteList/Cells/SiteListNameCell.swift b/phpmon/Domain/SiteList/Cells/SiteListNameCell.swift index f51d851..b444cd1 100644 --- a/phpmon/Domain/SiteList/Cells/SiteListNameCell.swift +++ b/phpmon/Domain/SiteList/Cells/SiteListNameCell.swift @@ -11,6 +11,8 @@ import AppKit class SiteListNameCell: NSTableCellView, SiteListCellProtocol { + static let reusableName = "siteListNameCell" + @IBOutlet weak var labelSiteName: NSTextField! @IBOutlet weak var labelPathName: NSTextField! diff --git a/phpmon/Domain/SiteList/Cells/SiteListPhpCell.swift b/phpmon/Domain/SiteList/Cells/SiteListPhpCell.swift index 06d7403..f7bca68 100644 --- a/phpmon/Domain/SiteList/Cells/SiteListPhpCell.swift +++ b/phpmon/Domain/SiteList/Cells/SiteListPhpCell.swift @@ -11,6 +11,8 @@ import AppKit class SiteListPhpCell: NSTableCellView, SiteListCellProtocol { + static let reusableName = "siteListPhpCell" + var site: ValetSite? = nil @IBOutlet weak var buttonPhpVersion: NSButton! @@ -19,8 +21,7 @@ class SiteListPhpCell: NSTableCellView, SiteListCellProtocol func populateCell(with site: ValetSite) { self.site = site - let versionInUse = site.isolatedPhpVersion?.versionNumber.homebrewVersion ?? PhpEnv.phpInstall.version.short - buttonPhpVersion.title = " PHP \(versionInUse)" + buttonPhpVersion.title = " PHP \(site.servingPhpVersion)" if site.isolatedPhpVersion != nil { imageViewPhpVersionOK.isHidden = false diff --git a/phpmon/Domain/SiteList/Cells/SiteListTLSCell.swift b/phpmon/Domain/SiteList/Cells/SiteListTLSCell.swift index fd2d2f5..466d165 100644 --- a/phpmon/Domain/SiteList/Cells/SiteListTLSCell.swift +++ b/phpmon/Domain/SiteList/Cells/SiteListTLSCell.swift @@ -11,6 +11,8 @@ import AppKit class SiteListTLSCell: NSTableCellView, SiteListCellProtocol { + static let reusableName = "siteListTLSCell" + @IBOutlet weak var imageViewLock: NSImageView! func populateCell(with site: ValetSite) { diff --git a/phpmon/Domain/SiteList/Cells/SiteListTypeCell.swift b/phpmon/Domain/SiteList/Cells/SiteListTypeCell.swift index 497bcb9..536d482 100644 --- a/phpmon/Domain/SiteList/Cells/SiteListTypeCell.swift +++ b/phpmon/Domain/SiteList/Cells/SiteListTypeCell.swift @@ -11,6 +11,8 @@ import AppKit class SiteListTypeCell: NSTableCellView, SiteListCellProtocol { + static let reusableName = "siteListTypeCell" + @IBOutlet weak var labelDriver: NSTextField! @IBOutlet weak var labelPhpVersion: NSTextField! diff --git a/phpmon/Domain/SiteList/SiteListVC.swift b/phpmon/Domain/SiteList/SiteListVC.swift index 64834f7..cb92769 100644 --- a/phpmon/Domain/SiteList/SiteListVC.swift +++ b/phpmon/Domain/SiteList/SiteListVC.swift @@ -26,6 +26,9 @@ class SiteListVC: NSViewController, NSTableViewDelegate, NSTableViewDataSource { return App.shared.detectedApplications } + /// The last sort descriptor used. + var sortDescriptor: NSSortDescriptor? = nil + /// String that was last searched for. Empty by default. var lastSearchedFor = "" @@ -144,6 +147,28 @@ class SiteListVC: NSViewController, NSTableViewDelegate, NSTableViewDataSource { } } + func applySortDescriptor(_ descriptor: NSSortDescriptor) { + sortDescriptor = descriptor + + var sorted = self.sites + + switch descriptor.key { + case "Secure": + sorted = self.sites.sorted { $0.secured && !$1.secured }; break + case "Domain": + sorted = self.sites.sorted { $0.absolutePath < $1.absolutePath }; break + case "PHP": + sorted = self.sites.sorted { $0.servingPhpVersion < $1.servingPhpVersion }; break + case "Kind": + sorted = self.sites.sorted { ($0.aliasPath == nil) && !($1.aliasPath == nil) }; break + case "Type": + sorted = self.sites.sorted { $0.driver ?? "QQQ" < $1.driver ?? "QQQ" }; break + default: break; + } + + self.sites = descriptor.ascending ? sorted.reversed() : sorted + } + func addedNewSite(name: String, secure: Bool) { waitAndExecute { Valet.shared.reloadSites() @@ -172,21 +197,28 @@ class SiteListVC: NSViewController, NSTableViewDelegate, NSTableViewDataSource { return sites.count } - func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { + func tableView(_ tableView: NSTableView, sortDescriptorsDidChange oldDescriptors: [NSSortDescriptor]) { + guard let sortDescriptor = tableView.sortDescriptors.first else { return } + // Kinda scuffed way of applying sort descriptors here, but it works. + Log.info("Applying sort descriptor for column: \(sortDescriptor.key ?? "Unknown")") + applySortDescriptor(sortDescriptor) + searchedFor(text: lastSearchedFor) + } + func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { let mapping: [String: String] = [ - "TLS": "siteListTLSCell", - "DOMAIN": "siteListNameCell", - "ENVIRONMENT": "siteListPhpCell", - "KIND": "siteListKindCell", - "TYPE": "siteListTypeCell", + "TLS": SiteListTLSCell.reusableName, + "DOMAIN": SiteListNameCell.reusableName, + "ENVIRONMENT": SiteListPhpCell.reusableName, + "KIND": SiteListKindCell.reusableName, + "TYPE": SiteListTypeCell.reusableName, ] let columnName = tableColumn!.identifier.rawValue + let identifier = NSUserInterfaceItemIdentifier(rawValue: mapping[columnName]!) - guard let userCell = tableView.makeView( - withIdentifier: NSUserInterfaceItemIdentifier(rawValue: mapping[columnName]!), owner: self - ) as? SiteListCellProtocol else { return nil } + guard let userCell = tableView.makeView(withIdentifier: identifier, owner: self) + as? SiteListCellProtocol else { return nil } userCell.populateCell(with: sites[row]) @@ -215,9 +247,14 @@ class SiteListVC: NSViewController, NSTableViewDelegate, NSTableViewDataSource { if searchString.isEmpty { sites = Valet.shared.sites + if let sortDescriptor = sortDescriptor { + self.applySortDescriptor(sortDescriptor) + } + DispatchQueue.main.async { self.tableView.reloadData() } + return } @@ -231,6 +268,10 @@ class SiteListVC: NSViewController, NSTableViewDelegate, NSTableViewDataSource { }.contains(false) }) + if let sortDescriptor = sortDescriptor { + self.applySortDescriptor(sortDescriptor) + } + DispatchQueue.main.async { self.tableView.reloadData() }