mirror of
https://github.com/nicoverbruggen/phpmon.git
synced 2025-08-07 20:10:08 +02:00
👌 Improve UI and warn about spaces in folder names
This commit is contained in:
@ -34,6 +34,8 @@
|
||||
C41C1B4922B00A9800E7CF16 /* MenuBarImageGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41C1B4822B00A9800E7CF16 /* MenuBarImageGenerator.swift */; };
|
||||
C41C1B4B22B019FF00E7CF16 /* ActivePhpInstallation.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41C1B4A22B019FF00E7CF16 /* ActivePhpInstallation.swift */; };
|
||||
C41C1B4D22B0215A00E7CF16 /* Actions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41C1B4C22B0215A00E7CF16 /* Actions.swift */; };
|
||||
C41CA5ED2774F8EE00A2C80E /* SiteListVC+Actions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41CA5EC2774F8EE00A2C80E /* SiteListVC+Actions.swift */; };
|
||||
C41CA5EE2774F8EE00A2C80E /* SiteListVC+Actions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41CA5EC2774F8EE00A2C80E /* SiteListVC+Actions.swift */; };
|
||||
C41CD0292628D8EE0065BBED /* GlobalKeybindPreference.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41CD0282628D8EE0065BBED /* GlobalKeybindPreference.swift */; };
|
||||
C41E871A2763D42300161EE0 /* SiteListVC+ContextMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41E87192763D42300161EE0 /* SiteListVC+ContextMenu.swift */; };
|
||||
C41E871B2763D42300161EE0 /* SiteListVC+ContextMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41E87192763D42300161EE0 /* SiteListVC+ContextMenu.swift */; };
|
||||
@ -155,6 +157,7 @@
|
||||
C41C1B4822B00A9800E7CF16 /* MenuBarImageGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuBarImageGenerator.swift; sourceTree = "<group>"; };
|
||||
C41C1B4A22B019FF00E7CF16 /* ActivePhpInstallation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivePhpInstallation.swift; sourceTree = "<group>"; };
|
||||
C41C1B4C22B0215A00E7CF16 /* Actions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Actions.swift; sourceTree = "<group>"; };
|
||||
C41CA5EC2774F8EE00A2C80E /* SiteListVC+Actions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SiteListVC+Actions.swift"; sourceTree = "<group>"; };
|
||||
C41CD0282628D8EE0065BBED /* GlobalKeybindPreference.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlobalKeybindPreference.swift; sourceTree = "<group>"; };
|
||||
C41E87192763D42300161EE0 /* SiteListVC+ContextMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SiteListVC+ContextMenu.swift"; sourceTree = "<group>"; };
|
||||
C42295DC2358D02000E263B2 /* Command.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Command.swift; sourceTree = "<group>"; };
|
||||
@ -337,6 +340,7 @@
|
||||
C464ADAB275A7A3F003FCD53 /* SiteListWC.swift */,
|
||||
C464ADAE275A7A69003FCD53 /* SiteListVC.swift */,
|
||||
C41E87192763D42300161EE0 /* SiteListVC+ContextMenu.swift */,
|
||||
C41CA5EC2774F8EE00A2C80E /* SiteListVC+Actions.swift */,
|
||||
C464ADB1275A87CA003FCD53 /* SiteListCell.swift */,
|
||||
);
|
||||
path = SiteList;
|
||||
@ -597,6 +601,7 @@
|
||||
C48D0C9325CC804200CC7490 /* XibLoadable.swift in Sources */,
|
||||
54FCFD2A276C8AA4004CE748 /* CheckboxPreferenceView.swift in Sources */,
|
||||
C4811D2A22D70F9A00B5F6B3 /* MainMenu.swift in Sources */,
|
||||
C41CA5ED2774F8EE00A2C80E /* SiteListVC+Actions.swift in Sources */,
|
||||
C412E5FC25700D5300A1FB67 /* HomebrewPackage.swift in Sources */,
|
||||
54AB03262763858F00A29D5F /* Timer.swift in Sources */,
|
||||
C41C1B3722B0097F00E7CF16 /* AppDelegate.swift in Sources */,
|
||||
@ -624,6 +629,7 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
54EAC806262F212B0092D14E /* GlobalKeybindPreference.swift in Sources */,
|
||||
C41CA5EE2774F8EE00A2C80E /* SiteListVC+Actions.swift in Sources */,
|
||||
C4F780C425D80B75000DBC97 /* MainMenu.swift in Sources */,
|
||||
54AB03272763858F00A29D5F /* Timer.swift in Sources */,
|
||||
54FCFD2B276C8AA4004CE748 /* CheckboxPreferenceView.swift in Sources */,
|
||||
|
@ -497,13 +497,35 @@
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="IconLinked" id="2ng-pK-kvv"/>
|
||||
<color key="contentTintColor" name="tertiaryLabelColor" catalog="System" colorSpace="catalog"/>
|
||||
</imageView>
|
||||
<button translatesAutoresizingMaskIntoConstraints="NO" id="ypa-iv-wLD">
|
||||
<rect key="frame" x="211" y="18" width="18" height="18"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="18" id="jKJ-Xn-BPA"/>
|
||||
<constraint firstAttribute="height" constant="18" id="lSH-of-WzD"/>
|
||||
</constraints>
|
||||
<buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" image="NSCaution" imagePosition="only" alignment="center" imageScaling="proportionallyUpOrDown" inset="2" id="9XB-KO-aSI">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
</button>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="150" translatesAutoresizingMaskIntoConstraints="NO" id="MD8-ef-Ht8">
|
||||
<rect key="frame" x="235" y="16" width="182" height="22"/>
|
||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Warning: This is a warning message. Please take this into account." id="iub-KH-clf">
|
||||
<font key="font" metaFont="system" size="9"/>
|
||||
<color key="textColor" name="secondaryLabelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="0NQ-ZD-CqD" firstAttribute="leading" secondItem="MD8-ef-Ht8" secondAttribute="trailing" constant="20" id="1Rb-Or-Nnn"/>
|
||||
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="TbX-e2-3QL" secondAttribute="trailing" constant="20" symbolic="YES" id="3vE-LR-S7N"/>
|
||||
<constraint firstItem="TbX-e2-3QL" firstAttribute="leading" secondItem="0NQ-ZD-CqD" secondAttribute="trailing" constant="8" symbolic="YES" id="4cb-D9-8d1"/>
|
||||
<constraint firstItem="XJL-Uw-frD" firstAttribute="leading" secondItem="QPX-eu-eV8" secondAttribute="trailing" constant="10" id="55y-3V-RYt"/>
|
||||
<constraint firstItem="syz-LF-l6P" firstAttribute="leading" secondItem="5GY-nN-BWd" secondAttribute="leading" id="8QK-nf-Fiw"/>
|
||||
<constraint firstItem="QPX-eu-eV8" firstAttribute="top" secondItem="XJL-Uw-frD" secondAttribute="top" id="9QB-jZ-k1V"/>
|
||||
<constraint firstItem="ypa-iv-wLD" firstAttribute="centerY" secondItem="5GY-nN-BWd" secondAttribute="centerY" id="9d8-P2-iSk"/>
|
||||
<constraint firstItem="MD8-ef-Ht8" firstAttribute="leading" secondItem="ypa-iv-wLD" secondAttribute="trailing" constant="8" symbolic="YES" id="C90-wQ-3Gf"/>
|
||||
<constraint firstItem="QPX-eu-eV8" firstAttribute="leading" secondItem="5GY-nN-BWd" secondAttribute="leading" constant="10" id="GOj-sw-ZlZ"/>
|
||||
<constraint firstItem="TbX-e2-3QL" firstAttribute="top" secondItem="jKi-Ls-7FZ" secondAttribute="bottom" constant="-1" id="J29-wT-Uex"/>
|
||||
<constraint firstItem="CXK-Q9-CpO" firstAttribute="leading" secondItem="XJL-Uw-frD" secondAttribute="leading" id="Ojw-VZ-3EG"/>
|
||||
@ -515,15 +537,19 @@
|
||||
<constraint firstItem="TbX-e2-3QL" firstAttribute="centerY" secondItem="5GY-nN-BWd" secondAttribute="centerY" constant="5" id="cN8-zO-fnc"/>
|
||||
<constraint firstAttribute="bottom" secondItem="syz-LF-l6P" secondAttribute="bottom" id="gj7-cJ-Lle"/>
|
||||
<constraint firstItem="0NQ-ZD-CqD" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="CXK-Q9-CpO" secondAttribute="trailing" constant="8" symbolic="YES" id="iEd-Y3-zhp"/>
|
||||
<constraint firstItem="ypa-iv-wLD" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="XJL-Uw-frD" secondAttribute="trailing" constant="30" id="koV-Sj-tO8"/>
|
||||
<constraint firstItem="MD8-ef-Ht8" firstAttribute="centerY" secondItem="ypa-iv-wLD" secondAttribute="centerY" id="lIN-pm-mCo"/>
|
||||
<constraint firstItem="0NQ-ZD-CqD" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="XJL-Uw-frD" secondAttribute="trailing" constant="8" symbolic="YES" id="lLA-Jx-Q4W"/>
|
||||
<constraint firstItem="jKi-Ls-7FZ" firstAttribute="leading" secondItem="TbX-e2-3QL" secondAttribute="leading" id="zjN-s3-2Ww"/>
|
||||
</constraints>
|
||||
<connections>
|
||||
<outlet property="buttonWarning" destination="ypa-iv-wLD" id="NwX-H3-8um"/>
|
||||
<outlet property="imageViewLock" destination="QPX-eu-eV8" id="Nnh-kB-adG"/>
|
||||
<outlet property="imageViewType" destination="0NQ-ZD-CqD" id="Cph-FN-LaY"/>
|
||||
<outlet property="labelDriver" destination="TbX-e2-3QL" id="qJh-Ak-Dge"/>
|
||||
<outlet property="labelPathName" destination="CXK-Q9-CpO" id="iVZ-cL-azB"/>
|
||||
<outlet property="labelSiteName" destination="XJL-Uw-frD" id="f0t-vd-W68"/>
|
||||
<outlet property="labelWarning" destination="MD8-ef-Ht8" id="Faw-CY-9R5"/>
|
||||
</connections>
|
||||
</tableCellView>
|
||||
</prototypeCellViews>
|
||||
@ -573,12 +599,13 @@
|
||||
</viewController>
|
||||
<customObject id="HgD-aB-bQb" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="288" y="765"/>
|
||||
<point key="canvasLocation" x="288" y="764.5"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="IconLinked" width="512" height="512"/>
|
||||
<image name="Lock" width="30" height="30"/>
|
||||
<image name="NSCaution" width="32" height="32"/>
|
||||
<image name="arrow.clockwise" catalog="system" width="14" height="16"/>
|
||||
</resources>
|
||||
</document>
|
||||
|
@ -68,6 +68,9 @@ class Valet {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Returns a count of how many sites are linked and parked.
|
||||
*/
|
||||
private func countPaths() -> Int {
|
||||
var count = 0
|
||||
for path in config.paths {
|
||||
@ -81,6 +84,9 @@ class Valet {
|
||||
return count
|
||||
}
|
||||
|
||||
/**
|
||||
Resolves all paths and creates linked or parked site instances that can be referenced later.
|
||||
*/
|
||||
private func resolvePaths(tld: String) {
|
||||
sites = []
|
||||
|
||||
@ -92,6 +98,10 @@ class Valet {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Determines whether the site can be resolved as a symbolic link or as a directory.
|
||||
Regular files are ignored. Returns true if the path can be parsed.
|
||||
*/
|
||||
private func resolveSite(_ entry: String, forPath path: String) -> Bool {
|
||||
let siteDir = path + "/" + entry
|
||||
|
||||
@ -106,6 +116,10 @@ class Valet {
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
Determines whether the site can be resolved as a symbolic link or as a directory.
|
||||
Regular files are ignored, and the site is added to Valet's list of sites.
|
||||
*/
|
||||
private func resolvePath(_ entry: String, forPath path: String, tld: String) {
|
||||
let siteDir = path + "/" + entry
|
||||
|
||||
@ -167,12 +181,11 @@ class Valet {
|
||||
}
|
||||
|
||||
public func determineSecured(_ tld: String) {
|
||||
let name = self.name!.replacingOccurrences(of: " ", with: "\\ ")
|
||||
secured = Shell.fileExists("~/.config/valet/Certificates/\(name).\(tld).key")
|
||||
secured = Shell.fileExists("~/.config/valet/Certificates/\(self.name!).\(tld).key")
|
||||
}
|
||||
|
||||
public func determineDriver() {
|
||||
let driver = Shell.pipe("cd \"\(absolutePath!)\" && valet which", requiresPath: true)
|
||||
let driver = Shell.pipe("cd '\(absolutePath!)' && valet which", requiresPath: true)
|
||||
if driver.contains("This site is served by") {
|
||||
self.driver = driver
|
||||
// TODO: Use a regular expression to retrieve the driver instead?
|
||||
|
@ -19,6 +19,9 @@ class SiteListCell: NSTableCellView
|
||||
|
||||
@IBOutlet weak var labelDriver: NSTextField!
|
||||
|
||||
@IBOutlet weak var buttonWarning: NSButton!
|
||||
@IBOutlet weak var labelWarning: NSTextField!
|
||||
|
||||
override func draw(_ dirtyRect: NSRect) {
|
||||
super.draw(dirtyRect)
|
||||
}
|
||||
@ -27,6 +30,11 @@ class SiteListCell: NSTableCellView
|
||||
// Make sure to show the TLD
|
||||
labelSiteName.stringValue = "\(site.name!).\(Valet.shared.config.tld)"
|
||||
|
||||
let isProblematic = site.name.contains(" ")
|
||||
buttonWarning.isHidden = !isProblematic
|
||||
labelWarning.isHidden = !isProblematic
|
||||
labelWarning.stringValue = "site_list.warning.spaces".localized
|
||||
|
||||
// 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: "~")
|
||||
|
97
phpmon/Domain/SiteList/SiteListVC+Actions.swift
Normal file
97
phpmon/Domain/SiteList/SiteListVC+Actions.swift
Normal file
@ -0,0 +1,97 @@
|
||||
//
|
||||
// SiteListVC+Actions.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 23/12/2021.
|
||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Cocoa
|
||||
|
||||
extension SiteListVC {
|
||||
|
||||
@objc 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_not_changed.title".localized,
|
||||
info: "site_list.alerts_status_not_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(
|
||||
"\(selectedSite.name!).\(Valet.shared.config.tld)",
|
||||
newState
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
tableView.reloadData(forRowIndexes: [rowToReload], columnIndexes: [0])
|
||||
tableView.deselectRow(rowToReload)
|
||||
tableView.selectRowIndexes([rowToReload], byExtendingSelection: true)
|
||||
}
|
||||
}
|
||||
|
||||
@objc func openInBrowser() {
|
||||
let prefix = selectedSite!.secured ? "https://" : "http://"
|
||||
let url = URL(string: "\(prefix)\(selectedSite!.name!).\(Valet.shared.config.tld)")
|
||||
if url != nil {
|
||||
NSWorkspace.shared.open(url!)
|
||||
} else {
|
||||
_ = Alert.present(
|
||||
messageText: "site_list.alert.invalid_folder_name".localized,
|
||||
informativeText: "site_list.alert.invalid_folder_name_desc".localized
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@objc func openInFinder() {
|
||||
Shell.run("open '\(selectedSite!.absolutePath!)'")
|
||||
}
|
||||
|
||||
@objc func openInTerminal() {
|
||||
Shell.run("open -b com.apple.terminal '\(selectedSite!.absolutePath!)'")
|
||||
}
|
||||
|
||||
@objc func openWithEditor(sender: EditorMenuItem) {
|
||||
guard let editor = sender.editor else { return }
|
||||
editor.openDirectory(file: selectedSite!.absolutePath!)
|
||||
}
|
||||
|
||||
@objc func unlinkSite() {
|
||||
guard let site = selectedSite else {
|
||||
return
|
||||
}
|
||||
|
||||
if site.aliasPath == nil {
|
||||
return
|
||||
}
|
||||
|
||||
Alert.confirm(
|
||||
onWindow: view.window!,
|
||||
messageText: "site_list.confirm_unlink".localized(site.name),
|
||||
informativeText: "site_link.confirm_link".localized,
|
||||
buttonTitle: "site_list.unlink".localized,
|
||||
secondButtonTitle: "Cancel",
|
||||
style: .critical,
|
||||
onFirstButtonPressed: {
|
||||
Shell.run("valet unlink '\(site.name!)'", requiresPath: true)
|
||||
self.reloadSites()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
}
|
@ -112,12 +112,11 @@ class SiteListVC: NSViewController, NSTableViewDelegate, NSTableViewDataSource {
|
||||
- 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 = {})
|
||||
internal 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()
|
||||
@ -164,92 +163,6 @@ class SiteListVC: NSViewController, NSTableViewDelegate, NSTableViewDataSource {
|
||||
self.openInBrowser()
|
||||
}
|
||||
|
||||
// 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_not_changed.title".localized,
|
||||
info: "site_list.alerts_status_not_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(
|
||||
"\(selectedSite.name!).\(Valet.shared.config.tld)",
|
||||
newState
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
tableView.reloadData(forRowIndexes: [rowToReload], columnIndexes: [0])
|
||||
tableView.deselectRow(rowToReload)
|
||||
tableView.selectRowIndexes([rowToReload], byExtendingSelection: true)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Open in Browser & Finder
|
||||
|
||||
@objc public func openInBrowser() {
|
||||
let prefix = selectedSite!.secured ? "https://" : "http://"
|
||||
let url = URL(string: "\(prefix)\(selectedSite!.name!).\(Valet.shared.config.tld)")
|
||||
if url != nil {
|
||||
NSWorkspace.shared.open(url!)
|
||||
} else {
|
||||
warnAboutInvalidFolderAction()
|
||||
}
|
||||
}
|
||||
|
||||
@objc public func openInFinder() {
|
||||
Shell.run("open '\(selectedSite!.absolutePath!)'")
|
||||
}
|
||||
|
||||
@objc public func openInTerminal() {
|
||||
Shell.run("open -b com.apple.terminal '\(selectedSite!.absolutePath!)'")
|
||||
}
|
||||
|
||||
@objc public func unlinkSite() {
|
||||
guard let site = selectedSite else {
|
||||
return
|
||||
}
|
||||
|
||||
if site.aliasPath == nil {
|
||||
return
|
||||
}
|
||||
|
||||
Alert.confirm(
|
||||
onWindow: view.window!,
|
||||
messageText: "site_list.confirm_unlink".localized(site.name),
|
||||
informativeText: "site_link.confirm_link".localized,
|
||||
buttonTitle: "site_list.unlink".localized,
|
||||
secondButtonTitle: "Cancel",
|
||||
style: .critical,
|
||||
onFirstButtonPressed: {
|
||||
Shell.run("valet unlink \(site.name!)", requiresPath: true)
|
||||
self.reloadSites()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private func warnAboutInvalidFolderAction() {
|
||||
_ = Alert.present(
|
||||
messageText: "site_list.alert.invalid_folder_name".localized,
|
||||
informativeText: "site_list.alert.invalid_folder_name_desc".localized
|
||||
)
|
||||
}
|
||||
|
||||
// MARK: - (Search) Text Field Delegate
|
||||
|
||||
func searchedFor(text: String) {
|
||||
@ -269,13 +182,7 @@ class SiteListVC: NSViewController, NSTableViewDelegate, NSTableViewDataSource {
|
||||
|
||||
tableView.reloadData()
|
||||
}
|
||||
|
||||
// MARK: - Context Menu
|
||||
|
||||
@objc func openWithEditor(sender: EditorMenuItem) {
|
||||
guard let editor = sender.editor else { return }
|
||||
editor.openDirectory(file: selectedSite!.absolutePath!)
|
||||
}
|
||||
|
||||
// MARK: - Deinitialization
|
||||
|
||||
deinit {
|
||||
|
@ -116,7 +116,8 @@ class Shell {
|
||||
Uses `/bin/echo` instead of the `builtin` (which does not support `-n`).
|
||||
*/
|
||||
public static func fileExists(_ path: String) -> Bool {
|
||||
return Shell.pipe("if [ -f \(path) ]; then /bin/echo -n \"0\"; fi") == "0"
|
||||
let escapedPath = path.replacingOccurrences(of: " ", with: "\\ ")
|
||||
return Shell.pipe("if [ -f \(escapedPath) ]; then /bin/echo -n \"0\"; fi") == "0"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -74,6 +74,8 @@
|
||||
"site_list.detected_apps" = "Detected Applications";
|
||||
"site_list.system_apps" = "System Applications";
|
||||
|
||||
"site_list.warning.spaces" = "Warning! This site has a space in its folder.\nThe site will not be reachable via the browser.";
|
||||
|
||||
"site_list.alert.invalid_folder_name" = "Invalid folder name";
|
||||
"site_list.alert.invalid_folder_name_desc" = "This folder could not be resolved to a valid URL. This is usually because there’s a space in the folder name. Please rename the folder, reload the list of sites, and try again.";
|
||||
|
||||
|
Reference in New Issue
Block a user