mirror of
https://github.com/nicoverbruggen/phpmon.git
synced 2025-08-08 04:20:07 +02:00
👌 Polish for v5.0
This commit is contained in:
@ -27,11 +27,11 @@ extension App {
|
||||
// Make sure we can parse the JSON into the desired format
|
||||
guard let keybindPref = GlobalKeybindPreference.fromJson(hotkey) else {
|
||||
print("No global hotkey loaded, could not be parsed!")
|
||||
self.shortcutHotkey = nil
|
||||
shortcutHotkey = nil
|
||||
return
|
||||
}
|
||||
|
||||
self.shortcutHotkey = HotKey(keyCombo: KeyCombo(
|
||||
shortcutHotkey = HotKey(keyCombo: KeyCombo(
|
||||
carbonKeyCode: keybindPref.keyCode,
|
||||
carbonModifiers: keybindPref.carbonFlags
|
||||
))
|
||||
@ -42,7 +42,7 @@ extension App {
|
||||
(opens the menu).
|
||||
*/
|
||||
func setupGlobalHotkeyListener() {
|
||||
guard let hotkey = self.shortcutHotkey else {
|
||||
guard let hotkey = shortcutHotkey else {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -90,7 +90,7 @@ class App {
|
||||
*/
|
||||
var shortcutHotkey: HotKey? = nil {
|
||||
didSet {
|
||||
self.setupGlobalHotkeyListener()
|
||||
setupGlobalHotkeyListener()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,7 @@ class Startup {
|
||||
performEnvironmentCheck(
|
||||
!Shell.fileExists("\(Paths.binPath)/php"),
|
||||
messageText: "startup.errors.php_binary.title".localized,
|
||||
informativeText: "startup.errors.php_binary_desc".localized,
|
||||
informativeText: "startup.errors.php_binary.desc".localized,
|
||||
breaking: true
|
||||
)
|
||||
|
||||
|
@ -28,7 +28,13 @@ class Alert {
|
||||
}
|
||||
|
||||
public static func notify(message: String, info: String, style: NSAlert.Style = .informational) {
|
||||
_ = self.present(messageText: message, informativeText: info, buttonTitle: "OK", secondButtonTitle: "", style: style)
|
||||
_ = present(
|
||||
messageText: message,
|
||||
informativeText: info,
|
||||
buttonTitle: "OK",
|
||||
secondButtonTitle: "",
|
||||
style: style
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -22,11 +22,11 @@ class PMWindowController: NSWindowController, NSWindowDelegate {
|
||||
|
||||
override func showWindow(_ sender: Any?) {
|
||||
super.showWindow(sender)
|
||||
App.shared.register(window: self.windowName)
|
||||
App.shared.register(window: windowName)
|
||||
}
|
||||
|
||||
func windowWillClose(_ notification: Notification) {
|
||||
App.shared.remove(window: self.windowName)
|
||||
App.shared.remove(window: windowName)
|
||||
}
|
||||
|
||||
deinit {
|
||||
|
@ -18,8 +18,8 @@ class HomebrewDiagnostics {
|
||||
var errors: [HomebrewDiagnostics.Errors] = []
|
||||
|
||||
init() {
|
||||
if self.determineAliasConflicts() {
|
||||
self.errors.append(.aliasConflict)
|
||||
if determineAliasConflicts() {
|
||||
errors.append(.aliasConflict)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,35 +18,35 @@ class Valet {
|
||||
var sites: [Site] = []
|
||||
|
||||
init() {
|
||||
self.version = Actions.valet("--version")
|
||||
version = Actions.valet("--version")
|
||||
.replacingOccurrences(of: "Laravel Valet ", with: "")
|
||||
.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
|
||||
let file = FileManager.default.homeDirectoryForCurrentUser
|
||||
.appendingPathComponent(".config/valet/config.json")
|
||||
|
||||
self.config = try! JSONDecoder().decode(
|
||||
config = try! JSONDecoder().decode(
|
||||
Valet.Configuration.self,
|
||||
from: try! String(contentsOf: file, encoding: .utf8).data(using: .utf8)!
|
||||
)
|
||||
|
||||
print("PHP Monitor should scan the following paths:")
|
||||
print(self.config.paths)
|
||||
print(config.paths)
|
||||
|
||||
resolvePaths(tld: self.config.tld)
|
||||
resolvePaths(tld: config.tld)
|
||||
}
|
||||
|
||||
public func reloadSites() {
|
||||
resolvePaths(tld: self.config.tld)
|
||||
resolvePaths(tld: config.tld)
|
||||
}
|
||||
|
||||
private func resolvePaths(tld: String) {
|
||||
self.sites = []
|
||||
sites = []
|
||||
|
||||
for path in self.config.paths {
|
||||
for path in config.paths {
|
||||
let entries = try! FileManager.default.contentsOfDirectory(atPath: path)
|
||||
for entry in entries {
|
||||
self.resolvePath(entry, forPath: path, tld: tld)
|
||||
resolvePath(entry, forPath: path, tld: tld)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -61,9 +61,9 @@ class Valet {
|
||||
let type = attrs[FileAttributeKey.type] as! FileAttributeType
|
||||
|
||||
if type == FileAttributeType.typeSymbolicLink {
|
||||
self.sites.append(Site(aliasPath: siteDir, tld: tld))
|
||||
sites.append(Site(aliasPath: siteDir, tld: tld))
|
||||
} else if type == FileAttributeType.typeDirectory {
|
||||
self.sites.append(Site(absolutePath: siteDir, tld: tld))
|
||||
sites.append(Site(absolutePath: siteDir, tld: tld))
|
||||
}
|
||||
}
|
||||
|
||||
@ -99,7 +99,7 @@ class Valet {
|
||||
}
|
||||
|
||||
public func determineSecured(_ tld: String) {
|
||||
self.secured = Shell.fileExists("~/.config/valet/Certificates/\(self.name!).\(tld).key")
|
||||
secured = Shell.fileExists("~/.config/valet/Certificates/\(self.name!).\(tld).key")
|
||||
}
|
||||
|
||||
public func determineDriver() {
|
||||
|
@ -32,7 +32,7 @@ class ActivePhpInstallation {
|
||||
|
||||
init() {
|
||||
// Show information about the current version
|
||||
self.getVersion()
|
||||
getVersion()
|
||||
|
||||
// If an error occurred, exit early
|
||||
if (version.error) {
|
||||
@ -47,9 +47,9 @@ class ActivePhpInstallation {
|
||||
|
||||
// Get configuration values
|
||||
configuration = Configuration(
|
||||
memory_limit: self.getByteCount(key: "memory_limit"),
|
||||
upload_max_filesize: self.getByteCount(key: "upload_max_filesize"),
|
||||
post_max_size: self.getByteCount(key: "post_max_size")
|
||||
memory_limit: getByteCount(key: "memory_limit"),
|
||||
upload_max_filesize: getByteCount(key: "upload_max_filesize"),
|
||||
post_max_size: getByteCount(key: "post_max_size")
|
||||
)
|
||||
|
||||
// Return a list of .ini files parsed after php.ini
|
||||
@ -60,9 +60,9 @@ class ActivePhpInstallation {
|
||||
|
||||
// See if any extensions are present in said .ini files
|
||||
paths.forEach { (iniFilePath) in
|
||||
let extensions = PhpExtension.load(from: URL(fileURLWithPath: iniFilePath))
|
||||
if extensions.count > 0 {
|
||||
self.extensions.append(contentsOf: extensions)
|
||||
let exts = PhpExtension.load(from: URL(fileURLWithPath: iniFilePath))
|
||||
if exts.count > 0 {
|
||||
extensions.append(contentsOf: exts)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ class Preferences {
|
||||
|
||||
public init() {
|
||||
Preferences.handleFirstTimeLaunch()
|
||||
self.cachedPreferences = Self.cache()
|
||||
cachedPreferences = Self.cache()
|
||||
}
|
||||
|
||||
// MARK: - First Time Run
|
||||
|
@ -75,7 +75,7 @@ class PrefsVC: NSViewController {
|
||||
}
|
||||
|
||||
override func viewWillDisappear() {
|
||||
if self.listeningForGlobalHotkey {
|
||||
if listeningForGlobalHotkey {
|
||||
listeningForGlobalHotkey = false
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ class PrefsWC: PMWindowController {
|
||||
override func keyDown(with event: NSEvent) {
|
||||
super.keyDown(with: event)
|
||||
|
||||
if let vc = self.contentViewController as? PrefsVC {
|
||||
if let vc = contentViewController as? PrefsVC {
|
||||
if vc.listeningForGlobalHotkey {
|
||||
if event.keyCode == Keys.Escape || event.keyCode == Keys.Space {
|
||||
print("A blacklisted key was pressed, canceling listen")
|
||||
|
@ -22,4 +22,28 @@ class SiteListCell: NSTableCellView
|
||||
override func draw(_ dirtyRect: NSRect) {
|
||||
super.draw(dirtyRect)
|
||||
}
|
||||
|
||||
func populateCell(with site: Valet.Site) {
|
||||
// Make sure to show the TLD
|
||||
labelSiteName.stringValue = "\(site.name!).\(Valet.shared.config.tld)"
|
||||
|
||||
// Show the absolute path, except make sure to replace the /Users/username segment with ~ for readability
|
||||
labelPathName.stringValue = site.absolutePath
|
||||
.replacingOccurrences(of: "/Users/\(Paths.whoami)", with: "~")
|
||||
|
||||
// If the `aliasPath` is nil, we're dealing with a parked site (otherwise: linked).
|
||||
imageViewType.image = NSImage(
|
||||
named: site.aliasPath == nil
|
||||
? "IconParked"
|
||||
: "IconLinked"
|
||||
)
|
||||
imageViewType.contentTintColor = NSColor.tertiaryLabelColor
|
||||
|
||||
// Show the green or red lock based on whether the site was secured
|
||||
imageViewLock.contentTintColor = site.secured ? NSColor.systemGreen
|
||||
: NSColor.red
|
||||
|
||||
// Show the current driver
|
||||
labelDriver.stringValue = site.driver
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,15 @@ class SiteListVC: NSViewController, NSTableViewDelegate, NSTableViewDataSource {
|
||||
var editorAvailability: [String] = []
|
||||
var lastSearchedFor = ""
|
||||
|
||||
// MARK: - Helper Variables
|
||||
|
||||
var selectedSite: Valet.Site? {
|
||||
if tableView.selectedRow == -1 {
|
||||
return nil
|
||||
}
|
||||
return sites[tableView.selectedRow]
|
||||
}
|
||||
|
||||
// MARK: - Display
|
||||
|
||||
public static func create(delegate: NSWindowDelegate?) {
|
||||
@ -56,103 +65,196 @@ class SiteListVC: NSViewController, NSTableViewDelegate, NSTableViewDataSource {
|
||||
// MARK: - Lifecycle
|
||||
|
||||
override func viewDidLoad() {
|
||||
if (Shell.fileExists("/usr/local/bin/code")) {
|
||||
self.editorAvailability.append("vscode")
|
||||
determineEditorAvailability()
|
||||
sites = Valet.shared.sites
|
||||
setUINotBusy()
|
||||
}
|
||||
|
||||
// MARK: - Async Operations
|
||||
|
||||
/**
|
||||
Disables the UI so the user cannot interact with it.
|
||||
Also shows a spinner to indicate that we're busy.
|
||||
*/
|
||||
private func setUIBusy() {
|
||||
progressIndicator.startAnimation(nil)
|
||||
tableView.alphaValue = 0.3
|
||||
tableView.isEnabled = false
|
||||
}
|
||||
|
||||
/**
|
||||
Re-enables the UI so the user can interact with it.
|
||||
*/
|
||||
private func setUINotBusy() {
|
||||
progressIndicator.stopAnimation(nil)
|
||||
tableView.alphaValue = 1.0
|
||||
tableView.isEnabled = true
|
||||
}
|
||||
|
||||
/**
|
||||
Executes a specific callback and fires the completion callback,
|
||||
while updating the UI as required. As long as the completion callback
|
||||
does not fire, the app is presumed to be busy and the UI reflects this.
|
||||
|
||||
- Parameter execute: Callback of the work that needs to happen.
|
||||
- Parameter completion: Callback that is fired when the work is done.
|
||||
*/
|
||||
private func waitAndExecute(_ execute: @escaping () -> Void, completion: @escaping () -> Void = {})
|
||||
{
|
||||
setUIBusy()
|
||||
DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
|
||||
execute()
|
||||
|
||||
DispatchQueue.main.async { [self] in
|
||||
completion()
|
||||
setUINotBusy()
|
||||
}
|
||||
}
|
||||
|
||||
if (Shell.fileExists("/Applications/PhpStorm.app/Contents/Info.plist")) {
|
||||
self.editorAvailability.append("phpstorm")
|
||||
}
|
||||
|
||||
self.sites = Valet.shared.sites
|
||||
self.progressIndicator.stopAnimation(nil)
|
||||
}
|
||||
|
||||
// MARK: - Site Data Loading
|
||||
|
||||
func reloadSites() {
|
||||
// Start spinner and reset view (no items)
|
||||
self.progressIndicator.startAnimation(nil)
|
||||
self.tableView.alphaValue = 0.3
|
||||
self.tableView.isEnabled = false
|
||||
|
||||
DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
|
||||
// Reload site information
|
||||
waitAndExecute {
|
||||
Valet.shared.reloadSites()
|
||||
|
||||
DispatchQueue.main.async { [self] in
|
||||
// Update the site list
|
||||
self.sites = Valet.shared.sites
|
||||
|
||||
// Stop spinner
|
||||
self.progressIndicator.stopAnimation(nil)
|
||||
self.tableView.alphaValue = 1.0
|
||||
self.tableView.isEnabled = true
|
||||
|
||||
// Re-apply any existing search
|
||||
self.searchedFor(text: lastSearchedFor)
|
||||
}
|
||||
} completion: { [self] in
|
||||
sites = Valet.shared.sites
|
||||
searchedFor(text: lastSearchedFor)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Table View
|
||||
// MARK: - Table View Delegate
|
||||
|
||||
func numberOfRows(in tableView: NSTableView) -> Int {
|
||||
return self.sites.count
|
||||
return sites.count
|
||||
}
|
||||
|
||||
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
|
||||
guard let userCell = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "siteItem"), owner: self) as? SiteListCell else { return nil }
|
||||
guard let userCell = tableView.makeView(
|
||||
withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "siteItem"), owner: self
|
||||
) as? SiteListCell else { return nil }
|
||||
|
||||
let item = self.sites[row]
|
||||
|
||||
/// Make sure to show the TLD
|
||||
userCell.labelSiteName.stringValue = "\(item.name!).\(Valet.shared.config.tld)"
|
||||
|
||||
/// Show the absolute path, except make sure to replace the /Users/username segment with ~ for readability
|
||||
userCell.labelPathName.stringValue = item.absolutePath
|
||||
.replacingOccurrences(of: "/Users/\(Paths.whoami)", with: "~")
|
||||
|
||||
/// If the `aliasPath` is nil, we're dealing with a parked site. Otherwise, it's a link that was explicitly created.
|
||||
userCell.imageViewType.image = NSImage(
|
||||
named: item.aliasPath == nil
|
||||
? "IconParked"
|
||||
: "IconLinked"
|
||||
)
|
||||
userCell.imageViewType.contentTintColor = NSColor.tertiaryLabelColor
|
||||
|
||||
/// Show the green or red lock based on whether the site was secured
|
||||
userCell.imageViewLock.contentTintColor = item.secured ? NSColor.systemGreen
|
||||
: NSColor.red
|
||||
|
||||
/// Show the current driver
|
||||
userCell.labelDriver.stringValue = item.driver
|
||||
userCell.populateCell(with: sites[row])
|
||||
|
||||
return userCell
|
||||
}
|
||||
|
||||
func tableViewSelectionDidChange(_ notification: Notification) {
|
||||
reloadContextMenu()
|
||||
}
|
||||
|
||||
// MARK: Secure & Unsecure
|
||||
|
||||
@objc public func toggleSecure() {
|
||||
let rowToReload = tableView.selectedRow
|
||||
let originalSecureStatus = selectedSite!.secured
|
||||
let action = selectedSite!.secured ? "unsecure" : "secure"
|
||||
let selectedSite = selectedSite!
|
||||
let command = "cd \(selectedSite.absolutePath!) && sudo \(Paths.valet) \(action) && exit;"
|
||||
|
||||
waitAndExecute {
|
||||
Shell.run(command, requiresPath: true)
|
||||
} completion: { [self] in
|
||||
selectedSite.determineSecured(Valet.shared.config.tld)
|
||||
if selectedSite.secured == originalSecureStatus {
|
||||
Alert.notify(
|
||||
message: "site_list.alerts_status_changed.title".localized,
|
||||
info: "\("site_list.alerts_status_changed.desc".localized) `\(command)`")
|
||||
} else {
|
||||
let newState = selectedSite.secured ? "secured" : "unsecured"
|
||||
LocalNotification.send(
|
||||
title: "site_list.alerts_status_changed.title".localized,
|
||||
subtitle: "site_list.alerts_status_changed.desc"
|
||||
.localized
|
||||
.replacingOccurrences(of: "{@1}", with: "\(selectedSite.name!).\(Valet.shared.config.tld)")
|
||||
.replacingOccurrences(of: "{@2}", with: newState)
|
||||
)
|
||||
}
|
||||
|
||||
tableView.reloadData(forRowIndexes: [rowToReload], columnIndexes: [0])
|
||||
tableView.deselectRow(rowToReload)
|
||||
tableView.selectRowIndexes([rowToReload], byExtendingSelection: true)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Open with IDE / Editor
|
||||
|
||||
/**
|
||||
Find out which editors are available on the user’s system.
|
||||
Currently only PHPStorm and Visual Studio Code are detected.
|
||||
*/
|
||||
private func determineEditorAvailability() {
|
||||
if (Shell.fileExists("/usr/local/bin/code")) {
|
||||
editorAvailability.append("vscode")
|
||||
}
|
||||
|
||||
if (Shell.fileExists("/Applications/PhpStorm.app/Contents/Info.plist")) {
|
||||
editorAvailability.append("phpstorm")
|
||||
}
|
||||
}
|
||||
|
||||
@objc public func openWithPhpStorm() {
|
||||
Shell.run("open -a /Applications/PhpStorm.app \(selectedSite!.absolutePath!)")
|
||||
}
|
||||
|
||||
@objc public func openWithVSCode() {
|
||||
Shell.run("/usr/local/bin/code \(selectedSite!.absolutePath!)")
|
||||
}
|
||||
|
||||
// MARK: Open in Browser & Finder
|
||||
|
||||
@objc public func openInBrowser() {
|
||||
let prefix = selectedSite!.secured ? "https://" : "http://"
|
||||
let url = "\(prefix)\(selectedSite!.name!).\(Valet.shared.config.tld)"
|
||||
NSWorkspace.shared.open(URL(string: url)!)
|
||||
}
|
||||
|
||||
@objc public func openInFinder() {
|
||||
Shell.run("open \(selectedSite!.absolutePath!)")
|
||||
}
|
||||
|
||||
// MARK: - (Search) Text Field Delegate
|
||||
|
||||
func searchedFor(text: String) {
|
||||
lastSearchedFor = text
|
||||
|
||||
let searchString = text.lowercased()
|
||||
|
||||
if searchString.isEmpty {
|
||||
sites = Valet.shared.sites
|
||||
tableView.reloadData()
|
||||
return
|
||||
}
|
||||
|
||||
sites = Valet.shared.sites.filter({ site in
|
||||
return site.name.lowercased().contains(searchString)
|
||||
})
|
||||
|
||||
tableView.reloadData()
|
||||
}
|
||||
|
||||
// MARK: - Context Menu
|
||||
|
||||
private func reloadContextMenu() {
|
||||
let menu = NSMenu()
|
||||
|
||||
if self.tableView.selectedRow == -1 {
|
||||
guard let site = selectedSite else {
|
||||
tableView.menu = nil
|
||||
return
|
||||
}
|
||||
|
||||
let site = self.sites[self.tableView.selectedRow]
|
||||
|
||||
menu.addItem(
|
||||
withTitle: site.secured
|
||||
? "site_list.unsecure".localized
|
||||
: "site_list.secure".localized,
|
||||
? "site_list.unsecure".localized
|
||||
: "site_list.secure".localized,
|
||||
action: #selector(toggleSecure),
|
||||
keyEquivalent: "L"
|
||||
)
|
||||
|
||||
if (self.editorAvailability.count > 0) {
|
||||
if (editorAvailability.count > 0) {
|
||||
menu.addItem(NSMenuItem.separator())
|
||||
|
||||
if self.editorAvailability.contains("vscode") {
|
||||
if editorAvailability.contains("vscode") {
|
||||
menu.addItem(
|
||||
withTitle: "site_list.open_with_vs_code".localized,
|
||||
action: #selector(self.openWithVSCode),
|
||||
@ -181,96 +283,9 @@ class SiteListVC: NSViewController, NSTableViewDelegate, NSTableViewDataSource {
|
||||
action: #selector(self.openInBrowser),
|
||||
keyEquivalent: "O"
|
||||
)
|
||||
|
||||
tableView.menu = menu
|
||||
}
|
||||
|
||||
// MARK: Secure / unsecure
|
||||
|
||||
@objc public func toggleSecure() {
|
||||
let rowToReload = self.tableView.selectedRow
|
||||
let site = self.sites[self.tableView.selectedRow]
|
||||
let previous = site.secured
|
||||
let action = site.secured ? "unsecure" : "secure"
|
||||
|
||||
self.progressIndicator.startAnimation(nil)
|
||||
self.tableView.alphaValue = 0.3
|
||||
self.tableView.isEnabled = false
|
||||
|
||||
DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
|
||||
let command = "cd \(site.absolutePath!) && sudo \(Paths.valet) \(action) && exit;"
|
||||
let _ = Shell.pipe(command, requiresPath: true)
|
||||
|
||||
site.determineSecured(Valet.shared.config.tld)
|
||||
|
||||
DispatchQueue.main.async { [self] in
|
||||
if site.secured == previous {
|
||||
Alert.notify(
|
||||
message: "SSL status not changed",
|
||||
info: "Something went wrong. Try running the command in your terminal manually: `\(command)`")
|
||||
} else {
|
||||
let newState = site.secured ? "secured" : "unsecured"
|
||||
LocalNotification.send(
|
||||
title: "SSL status changed",
|
||||
subtitle: "The domain '\(site.name!).\(Valet.shared.config.tld)' is now \(newState)."
|
||||
)
|
||||
}
|
||||
|
||||
progressIndicator.stopAnimation(nil)
|
||||
self.tableView.alphaValue = 1
|
||||
self.tableView.isEnabled = true
|
||||
|
||||
tableView.reloadData(forRowIndexes: [rowToReload], columnIndexes: [0])
|
||||
tableView.deselectRow(rowToReload)
|
||||
tableView.selectRowIndexes([rowToReload], byExtendingSelection: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Open with IDE / Editor
|
||||
|
||||
@objc public func openWithPhpStorm() {
|
||||
let site = self.sites[self.tableView.selectedRow]
|
||||
Shell.run("open -a /Applications/PhpStorm.app \(site.absolutePath!)")
|
||||
}
|
||||
|
||||
@objc public func openWithVSCode() {
|
||||
let site = self.sites[self.tableView.selectedRow]
|
||||
Shell.run("/usr/local/bin/code \(site.absolutePath!)")
|
||||
}
|
||||
|
||||
// MARK: Open in Browser & Finder
|
||||
|
||||
@objc public func openInBrowser() {
|
||||
let site = self.sites[self.tableView.selectedRow]
|
||||
let prefix = site.secured ? "https://" : "http://"
|
||||
let url = "\(prefix)\(site.name!).\(Valet.shared.config.tld)"
|
||||
NSWorkspace.shared.open(URL(string: url)!)
|
||||
}
|
||||
|
||||
@objc public func openInFinder() {
|
||||
let site = self.sites[self.tableView.selectedRow]
|
||||
Shell.run("open \(site.absolutePath!)")
|
||||
}
|
||||
|
||||
// MARK: - (Search) Text Field Delegate
|
||||
|
||||
func searchedFor(text: String) {
|
||||
self.lastSearchedFor = text
|
||||
|
||||
let searchString = text.lowercased()
|
||||
|
||||
if searchString.isEmpty {
|
||||
self.sites = Valet.shared.sites
|
||||
tableView.reloadData()
|
||||
return
|
||||
}
|
||||
|
||||
self.sites = Valet.shared.sites.filter({ site in
|
||||
return site.name.lowercased().contains(searchString)
|
||||
})
|
||||
|
||||
tableView.reloadData()
|
||||
}
|
||||
|
||||
// MARK: - Deinitialization
|
||||
|
||||
|
@ -15,7 +15,7 @@ class Shell {
|
||||
_ command: String,
|
||||
requiresPath: Bool = false
|
||||
) {
|
||||
Shell.user.run(command)
|
||||
Shell.user.run(command, requiresPath: requiresPath)
|
||||
}
|
||||
|
||||
public static func pipe(
|
||||
@ -27,23 +27,10 @@ class Shell {
|
||||
|
||||
// MARK: - Singleton
|
||||
|
||||
var shell: String
|
||||
|
||||
init() {
|
||||
// Determine if we're using macOS Catalina or newer (that support /bin/zsh as default shell)
|
||||
let at_least_10_15 = ProcessInfo.processInfo.isOperatingSystemAtLeast(
|
||||
.init(majorVersion: 10, minorVersion: 15, patchVersion: 0))
|
||||
|
||||
// If macOS Mojave is being used, we'll default to /bin/bash
|
||||
shell = at_least_10_15
|
||||
? "/bin/sh"
|
||||
: "/bin/bash"
|
||||
|
||||
print(at_least_10_15
|
||||
? "Detected recent macOS (> 10.15): defaulting to /bin/sh"
|
||||
: "Detected older macOS (< 10.15): defaulting to /bin/bash"
|
||||
)
|
||||
}
|
||||
/**
|
||||
We now require macOS 11, so no need to detect which terminal to use.
|
||||
*/
|
||||
var shell: String = "/bin/sh"
|
||||
|
||||
/**
|
||||
Singleton to access a user shell (with --login)
|
||||
|
@ -53,6 +53,12 @@
|
||||
"site_list.title" = "Domains";
|
||||
"site_list.subtitle" = "Linked & Parked";
|
||||
|
||||
"site_list.alerts_status_changed.title" = "SSL Status Not Changed";
|
||||
"site_list.alerts_status_changed.desc" = "Something went wrong. Try running the command in your terminal manually:";
|
||||
|
||||
"site_list.alerts_status_changed.title" = "SSL Status Changed";
|
||||
"site_list.alerts_status_changed.desc" = "The domain '{@1}' is now {@2}.";
|
||||
|
||||
// SITE LIST ACTIONS
|
||||
|
||||
"site_list.secure" = "Secure";
|
||||
@ -127,7 +133,7 @@
|
||||
|
||||
/// 1. PHP binary not found
|
||||
"startup.errors.php_binary.title" = "PHP is not correctly installed";
|
||||
"startup.errors.php_binary_desc" = "You must install PHP via brew. Try running `which php` in Terminal, it should return `/usr/local/bin/php` (or `/opt/homebrew/bin/php`). The app will not work correctly until you resolve this issue. (Usually `brew link php` resolves this issue.)";
|
||||
"startup.errors.php_binary.desc" = "You must install PHP via brew. Try running `which php` in Terminal, it should return `/usr/local/bin/php` (or `/opt/homebrew/bin/php`). The app will not work correctly until you resolve this issue. (Usually `brew link php` resolves this issue.)";
|
||||
|
||||
/// 2. PHP not found in /usr/local/opt or /opt/homebrew/opt
|
||||
"startup.errors.php_opt.title" = "PHP is not correctly installed";
|
||||
|
Reference in New Issue
Block a user