1
0
mirror of https://github.com/nicoverbruggen/phpmon.git synced 2025-08-07 03:50:08 +02:00

♻️ Rework how the user's PATH is loaded

This commit is contained in:
2022-08-15 01:47:55 +02:00
parent bbbdce6b44
commit a9f9c38e0d
12 changed files with 154 additions and 102 deletions

View File

@ -98,6 +98,8 @@
C42CFB1627DFDE7900862737 /* nginx-site.test in Resources */ = {isa = PBXBuildFile; fileRef = C42CFB1527DFDE7900862737 /* nginx-site.test */; }; C42CFB1627DFDE7900862737 /* nginx-site.test in Resources */ = {isa = PBXBuildFile; fileRef = C42CFB1527DFDE7900862737 /* nginx-site.test */; };
C42CFB1827DFDFDC00862737 /* nginx-site-isolated.test in Resources */ = {isa = PBXBuildFile; fileRef = C42CFB1727DFDFDC00862737 /* nginx-site-isolated.test */; }; C42CFB1827DFDFDC00862737 /* nginx-site-isolated.test in Resources */ = {isa = PBXBuildFile; fileRef = C42CFB1727DFDFDC00862737 /* nginx-site-isolated.test */; };
C42CFB1A27DFE8BD00862737 /* NginxConfigurationTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42CFB1927DFE8BD00862737 /* NginxConfigurationTest.swift */; }; C42CFB1A27DFE8BD00862737 /* NginxConfigurationTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42CFB1927DFE8BD00862737 /* NginxConfigurationTest.swift */; };
C42E3BF428A9BF5100AFECFC /* Shell+PATH.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42E3BF328A9BF5100AFECFC /* Shell+PATH.swift */; };
C42E3BF528A9BF5100AFECFC /* Shell+PATH.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42E3BF328A9BF5100AFECFC /* Shell+PATH.swift */; };
C42F26732805B4B400938AC7 /* DomainListable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42F26722805B4B400938AC7 /* DomainListable.swift */; }; C42F26732805B4B400938AC7 /* DomainListable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42F26722805B4B400938AC7 /* DomainListable.swift */; };
C42F26742805B4B400938AC7 /* DomainListable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42F26722805B4B400938AC7 /* DomainListable.swift */; }; C42F26742805B4B400938AC7 /* DomainListable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42F26722805B4B400938AC7 /* DomainListable.swift */; };
C42F26762805FEE200938AC7 /* nginx-secure-proxy.test in Resources */ = {isa = PBXBuildFile; fileRef = C42F26752805FEE200938AC7 /* nginx-secure-proxy.test */; }; C42F26762805FEE200938AC7 /* nginx-secure-proxy.test in Resources */ = {isa = PBXBuildFile; fileRef = C42F26752805FEE200938AC7 /* nginx-secure-proxy.test */; };
@ -356,6 +358,7 @@
C42CFB1527DFDE7900862737 /* nginx-site.test */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "nginx-site.test"; sourceTree = "<group>"; }; C42CFB1527DFDE7900862737 /* nginx-site.test */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "nginx-site.test"; sourceTree = "<group>"; };
C42CFB1727DFDFDC00862737 /* nginx-site-isolated.test */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "nginx-site-isolated.test"; sourceTree = "<group>"; }; C42CFB1727DFDFDC00862737 /* nginx-site-isolated.test */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "nginx-site-isolated.test"; sourceTree = "<group>"; };
C42CFB1927DFE8BD00862737 /* NginxConfigurationTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NginxConfigurationTest.swift; sourceTree = "<group>"; }; C42CFB1927DFE8BD00862737 /* NginxConfigurationTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NginxConfigurationTest.swift; sourceTree = "<group>"; };
C42E3BF328A9BF5100AFECFC /* Shell+PATH.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Shell+PATH.swift"; sourceTree = "<group>"; };
C42F26722805B4B400938AC7 /* DomainListable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomainListable.swift; sourceTree = "<group>"; }; C42F26722805B4B400938AC7 /* DomainListable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomainListable.swift; sourceTree = "<group>"; };
C42F26752805FEE200938AC7 /* nginx-secure-proxy.test */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "nginx-secure-proxy.test"; sourceTree = "<group>"; }; C42F26752805FEE200938AC7 /* nginx-secure-proxy.test */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "nginx-secure-proxy.test"; sourceTree = "<group>"; };
C436039F275E67610028EFC6 /* AppDelegate+Notifications.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppDelegate+Notifications.swift"; sourceTree = "<group>"; }; C436039F275E67610028EFC6 /* AppDelegate+Notifications.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppDelegate+Notifications.swift"; sourceTree = "<group>"; };
@ -608,6 +611,7 @@
C4B5853D2770FE3900DA4FBE /* Command.swift */, C4B5853D2770FE3900DA4FBE /* Command.swift */,
C4B5853B2770FE3900DA4FBE /* Paths.swift */, C4B5853B2770FE3900DA4FBE /* Paths.swift */,
C4B5853C2770FE3900DA4FBE /* Shell.swift */, C4B5853C2770FE3900DA4FBE /* Shell.swift */,
C42E3BF328A9BF5100AFECFC /* Shell+PATH.swift */,
C4C1019A27C65C6F001FACC2 /* Process.swift */, C4C1019A27C65C6F001FACC2 /* Process.swift */,
C40C7F2F27722E8D00DDDCDC /* Logger.swift */, C40C7F2F27722E8D00DDDCDC /* Logger.swift */,
C417DC73277614690015E6EE /* Helpers.swift */, C417DC73277614690015E6EE /* Helpers.swift */,
@ -1386,6 +1390,7 @@
C4C3ED412783497000AB15D8 /* MainMenu+Startup.swift in Sources */, C4C3ED412783497000AB15D8 /* MainMenu+Startup.swift in Sources */,
C4D89BC62783C99400A02B68 /* ComposerJson.swift in Sources */, C4D89BC62783C99400A02B68 /* ComposerJson.swift in Sources */,
C46FA23F246C358E00944F05 /* StringExtension.swift in Sources */, C46FA23F246C358E00944F05 /* StringExtension.swift in Sources */,
C42E3BF428A9BF5100AFECFC /* Shell+PATH.swift in Sources */,
C42337A3281F19F000459A48 /* Xdebug.swift in Sources */, C42337A3281F19F000459A48 /* Xdebug.swift in Sources */,
C4B97B75275CF08C003F3378 /* AppDelegate+MenuOutlets.swift in Sources */, C4B97B75275CF08C003F3378 /* AppDelegate+MenuOutlets.swift in Sources */,
C41C02A627E60D7A009F26CB /* SiteScanner.swift in Sources */, C41C02A627E60D7A009F26CB /* SiteScanner.swift in Sources */,
@ -1430,6 +1435,7 @@
C449B4F027EE7FB800C47E8A /* DomainListTLSCell.swift in Sources */, C449B4F027EE7FB800C47E8A /* DomainListTLSCell.swift in Sources */,
C4FBFC532616485F00CDB8E1 /* PhpVersionDetectionTest.swift in Sources */, C4FBFC532616485F00CDB8E1 /* PhpVersionDetectionTest.swift in Sources */,
C43A8A2425D9D20D00591B77 /* HomebrewPackageTest.swift in Sources */, C43A8A2425D9D20D00591B77 /* HomebrewPackageTest.swift in Sources */,
C42E3BF528A9BF5100AFECFC /* Shell+PATH.swift in Sources */,
C4F780CA25D80B75000DBC97 /* HomebrewPackage.swift in Sources */, C4F780CA25D80B75000DBC97 /* HomebrewPackage.swift in Sources */,
C4C8E81C276F54E5003AC782 /* PhpConfigWatcher.swift in Sources */, C4C8E81C276F54E5003AC782 /* PhpConfigWatcher.swift in Sources */,
C4F319C927B034A500AFF46F /* Stats.swift in Sources */, C4F319C927B034A500AFF46F /* Stats.swift in Sources */,

View File

@ -19,12 +19,9 @@ public class Paths {
private var userName: String private var userName: String
private var PATH: String
init() { init() {
baseDir = App.architecture != "x86_64" ? .opt : .usr baseDir = App.architecture != "x86_64" ? .opt : .usr
userName = String(Shell.pipe("whoami").split(separator: "\n")[0]) userName = String(Shell.pipe("whoami").split(separator: "\n")[0])
PATH = String(Shell.pipe("echo $PATH")).trimmingCharacters(in: .whitespacesAndNewlines)
} }
public func detectBinaryPaths() { public func detectBinaryPaths() {
@ -60,10 +57,6 @@ public class Paths {
return shared.userName return shared.userName
} }
public static var PATH: String {
return shared.PATH
}
public static var cellarPath: String { public static var cellarPath: String {
return "\(shared.baseDir.rawValue)/Cellar" return "\(shared.baseDir.rawValue)/Cellar"
} }

View File

@ -0,0 +1,27 @@
//
// Shell+PATH.swift
// PHP Monitor
//
// Created by Nico Verbruggen on 15/08/2022.
// Copyright © 2022 Nico Verbruggen. All rights reserved.
//
import Foundation
extension Shell {
var PATH: String {
let task = Process()
task.launchPath = "/bin/zsh"
// We need an interactive shell so the user's PATH is loaded in correctly
task.arguments = ["--login", "-ilc", "echo $PATH"]
let pipe = Pipe()
task.standardOutput = pipe
task.launch()
let data = pipe.fileHandleForReading.readDataToEndOfFile()
return String(data: data, encoding: String.Encoding.utf8) ?? ""
}
}

View File

@ -20,7 +20,7 @@ class PhpHelper {
let destination = "/Users/\(Paths.whoami)/.config/phpmon/bin/pm\(dotless)" let destination = "/Users/\(Paths.whoami)/.config/phpmon/bin/pm\(dotless)"
// Check if the ~/.config/phpmon/bin directory is in the PATH // Check if the ~/.config/phpmon/bin directory is in the PATH
let inPath = Paths.PATH.contains("/Users/\(Paths.whoami)/.config/phpmon/bin") let inPath = Shell.user.PATH.contains("/Users/\(Paths.whoami)/.config/phpmon/bin")
// Check if we can create symlinks (`/usr/local/bin` must be writable) // Check if we can create symlinks (`/usr/local/bin` must be writable)
let canWriteSymlinks = FileManager.default.isWritableFile(atPath: "/usr/local/bin/") let canWriteSymlinks = FileManager.default.isWritableFile(atPath: "/usr/local/bin/")

View File

@ -13,9 +13,9 @@
</head> </head>
<body> <body>
<br> <br>
<p><b>Want to spread the love?</b> Leave a <a href="https://github.com/nicoverbruggen/phpmon">star on GitHub</a>!</p> <p><b>Do you enjoy using the app?</b> Leave a <a href="https://github.com/nicoverbruggen/phpmon">star on GitHub</a>!</p>
<p><b>Having issues?</b> Consult the <a href="https://github.com/nicoverbruggen/phpmon#%EF%B8%8F-faq--troubleshooting">FAQ & Troubleshooting</a> section.</p> <p><b>Having issues?</b> Consult the <a href="https://github.com/nicoverbruggen/phpmon#%EF%B8%8F-faq--troubleshooting">FAQ</a> section, I did my best to ensure everything is documented.</p>
<p><b>Want to support me?</b> You can <a href="https://nicoverbruggen.be/sponsor">financially support</a> the continued development of this app.</p> <p><b>Want to support further development of PHP Monitor?</b> You can <a href="https://nicoverbruggen.be/sponsor">financially support</a> the continued development of this app.</p>
<p><b>Get the latest on Twitter</b> Give me a <a href="https://twitter.com/nicoverbruggen">follow on Twitter</a> to learn about the latest and greatest updates of this app.</p> <p><b>Get the latest on Twitter</b> Give me a <a href="https://twitter.com/nicoverbruggen">follow on Twitter</a> to learn about the latest and greatest updates of this app.</p>
<br> <br>
</body> </body>

View File

@ -64,7 +64,6 @@ class MainMenu: NSObject, NSWindowDelegate, NSMenuDelegate, PhpSwitcherDelegate
menu.addRemainingMenuItems() menu.addRemainingMenuItems()
menu.addItem(NSMenuItem.separator()) menu.addItem(NSMenuItem.separator())
menu.addWarningsMenuItem()
menu.addCoreMenuItems() menu.addCoreMenuItems()
menu.items.forEach({ (item) in menu.items.forEach({ (item) in

View File

@ -157,6 +157,7 @@ extension StatusMenu {
return return
} }
self.addItem(NSMenuItem.separator())
let xdebugSwitch = NSMenuItem( let xdebugSwitch = NSMenuItem(
title: "mi_xdebug_mode".localized, title: "mi_xdebug_mode".localized,
action: nil, action: nil,

View File

@ -66,25 +66,34 @@ class StatusMenu: NSMenu {
self.addExtensionsMenuItems() self.addExtensionsMenuItems()
self.addXdebugMenuItem()
self.addPhpDoctorMenuItem()
self.addItem(NSMenuItem.separator()) self.addItem(NSMenuItem.separator())
self.addXdebugMenuItem()
self.addPresetsMenuItem() self.addPresetsMenuItem()
self.addFirstAidAndServicesMenuItems() self.addFirstAidAndServicesMenuItems()
} }
func addWarningsMenuItem() { func addPhpDoctorMenuItem() {
if !Preferences.isEnabled(.showPhpDoctorSuggestions) || if !Preferences.isEnabled(.showPhpDoctorSuggestions) ||
!WarningManager.shared.hasWarnings() { !WarningManager.shared.hasWarnings() {
return return
} }
self.addItem(NSMenuItem.separator()) self.addItem(NSMenuItem.separator())
self.addItem(HeaderView.asMenuItem(text: "mi_php_doctor".localized))
let count = WarningManager.shared.warnings.count self.addItem(NSMenuItem(
self.addItem(NSMenuItem(title: "mi_warnings".localized(count), title: "mi_recommendations_count".localized(WarningManager.shared.warnings.count),
action: #selector(MainMenu.openWarnings), keyEquivalent: "")) action: nil,
keyEquivalent: ""
))
self.addItem(NSMenuItem(
title: "mi_view_recommendations".localized,
action: #selector(MainMenu.openWarnings),
keyEquivalent: ""
))
} }
func addCoreMenuItems() { func addCoreMenuItems() {

View File

@ -28,9 +28,9 @@ struct OnboardingTextItem: View {
Text(description.localizedForSwiftUI) Text(description.localizedForSwiftUI)
.foregroundColor(Color.secondary) .foregroundColor(Color.secondary)
.font(.system(size: 13)) .font(.system(size: 13))
.lineLimit(6) .lineLimit(4)
.fixedSize(horizontal: false, vertical: true) .fixedSize(horizontal: false, vertical: true)
.frame(minWidth: 0, maxWidth: .infinity, alignment: .leading) .frame(minWidth: 0, maxWidth: 800, alignment: .leading)
} }
} }
.padding() .padding()
@ -41,80 +41,79 @@ struct OnboardingTextItem: View {
struct OnboardingView: View { struct OnboardingView: View {
var body: some View { var body: some View {
VStack(spacing: 10) { VStack(alignment: .center, spacing: 5) {
VStack(alignment: .center) { HStack {
HStack { Image(nsImage: NSApp.applicationIconImage)
Image(nsImage: NSApp.applicationIconImage) .resizable()
.resizable() .frame(width: 80, height: 80)
.frame(width: 80, height: 80) .padding(.bottom, 5)
.padding(.trailing, 25)
VStack(alignment: .leading, spacing: 0) {
Text("onboarding.welcome".localized)
.font(.title)
.bold()
.padding(.bottom, 5) .padding(.bottom, 5)
.padding(.trailing, 25) Text("onboarding.explore".localized)
VStack(alignment: .leading, spacing: 0) { .padding(.bottom)
Text("onboarding.welcome".localized) .padding(.trailing)
.font(.title)
.bold()
.padding(.bottom, 5)
Text("onboarding.explore".localized)
.padding(.bottom)
.padding(.trailing)
}
.padding(.top, 10)
} }
.padding(.leading) .padding(.top, 10)
.padding(.trailing)
VStack {
VStack(alignment: .leading, spacing: 10) {
OnboardingTextItem(
icon: "bolt.circle.fill",
title: "onboarding.tour.menu_bar.title",
description: "onboarding.tour.menu_bar"
)
OnboardingTextItem(
icon: "checkmark.circle.fill",
title: "onboarding.tour.services.title",
description: "onboarding.tour.services"
)
OnboardingTextItem(
icon: "list.bullet.circle.fill",
title: "onboarding.tour.domains.title",
description: "onboarding.tour.domains"
)
OnboardingTextItem(
icon: "pin.circle.fill",
title: "onboarding.tour.isolation.title",
description: "onboarding.tour.isolation"
)
}
}.padding()
VStack(spacing: 20) {
HStack {
Image(systemName: "questionmark.circle.fill")
.resizable()
.frame(width: 24, height: 24)
.foregroundColor(Color.appSecondary)
.padding(.trailing, 10)
HStack {
Text("onboarding.tour.faq_hint".localizedForSwiftUI)
.lineLimit(5)
}.fixedSize(horizontal: false, vertical: true)
}
VStack {
Text("onboarding.tour.once".localized)
.font(.subheadline)
.foregroundColor(.gray)
.padding(.top, 5)
.padding(.bottom, 5)
.lineLimit(5)
Button("onboarding.tour.close".localized) {
App.shared.onboardingWindowController?.close()
}
}
}.padding()
} }
.padding(.leading)
.padding(.trailing)
VStack {
VStack(alignment: .leading, spacing: 10) {
OnboardingTextItem(
icon: "bolt.circle.fill",
title: "onboarding.tour.menu_bar.title",
description: "onboarding.tour.menu_bar"
)
OnboardingTextItem(
icon: "checkmark.circle.fill",
title: "onboarding.tour.services.title",
description: "onboarding.tour.services"
)
OnboardingTextItem(
icon: "list.bullet.circle.fill",
title: "onboarding.tour.domains.title",
description: "onboarding.tour.domains"
)
OnboardingTextItem(
icon: "pin.circle.fill",
title: "onboarding.tour.isolation.title",
description: "onboarding.tour.isolation"
)
}
}.padding()
VStack(spacing: 20) {
HStack {
Image(systemName: "questionmark.circle.fill")
.resizable()
.frame(width: 24, height: 24)
.foregroundColor(Color.appSecondary)
.padding(.trailing, 10)
HStack {
Text("onboarding.tour.faq_hint".localizedForSwiftUI)
.lineLimit(5)
}.fixedSize(horizontal: false, vertical: true)
}
VStack {
Text("onboarding.tour.once".localized)
.font(.subheadline)
.foregroundColor(.gray)
.padding(.top, 5)
.padding(.bottom, 5)
.lineLimit(5)
Button("onboarding.tour.close".localized) {
App.shared.onboardingWindowController?.close()
}
}
}
.padding(.leading)
.padding(.trailing)
} }
.padding(.top, 8)
} }
} }

View File

@ -11,23 +11,35 @@ import SwiftUI
struct WarningListView: View { struct WarningListView: View {
var body: some View { var body: some View {
VStack { VStack {
HStack(spacing: 15) { HStack(alignment: .center, spacing: 15) {
Image(systemName: "stethoscope.circle.fill") Image(systemName: "stethoscope.circle.fill")
.resizable() .resizable()
.frame(width: 40, height: 40) .frame(width: 40, height: 40)
.foregroundColor(Color.red) .foregroundColor(Color.red)
.padding(12) .padding(12)
VStack(alignment: .trailing, spacing: 5) { VStack(alignment: .leading, spacing: 5) {
Text("warnings.description".localizedForSwiftUI) Text("warnings.description".localizedForSwiftUI)
.font(.system(size: 12))
.frame(maxWidth: .infinity, alignment: .leading) .frame(maxWidth: .infinity, alignment: .leading)
Text("warnings.disclaimer".localizedForSwiftUI) Text("warnings.disclaimer".localizedForSwiftUI)
.font(.system(size: 12)) .font(.system(size: 12))
.foregroundColor(.gray)
.frame(maxWidth: .infinity, alignment: .leading) .frame(maxWidth: .infinity, alignment: .leading)
} }
} }
.padding(10) .padding(10)
Divider()
HStack(alignment: .center, spacing: 15) {
Button("warnings.refresh.button".localizedForSwiftUI) {
WarningManager.shared.evaluateWarnings()
}
Text("warnings.refresh.button.description".localizedForSwiftUI)
.foregroundColor(.gray)
.font(.system(size: 11))
}
.padding(10)
List { List {
VStack(alignment: .leading, spacing: 0) { VStack(alignment: .leading, spacing: 0) {
ForEach(WarningManager.shared.warnings) { warning in ForEach(WarningManager.shared.warnings) { warning in

View File

@ -32,8 +32,8 @@ class WarningManager {
), ),
Warning( Warning(
command: { command: {
!Paths.PATH.contains("/Users/\(Paths.whoami)/.config/phpmon/bin") && return !Shell.user.PATH.contains("/Users/\(Paths.whoami)/.config/phpmon/bin") &&
!FileManager.default.isWritableFile(atPath: "/usr/local/bin/") !FileManager.default.isWritableFile(atPath: "/usr/local/bin/")
}, },
name: "Helpers cannot be symlinked and not in PATH", name: "Helpers cannot be symlinked and not in PATH",
title: "warnings.helper_permissions.title", title: "warnings.helper_permissions.title",
@ -74,6 +74,8 @@ class WarningManager {
if ProcessInfo.processInfo.environment["EXTREME_DOCTOR_MODE"] != nil { if ProcessInfo.processInfo.environment["EXTREME_DOCTOR_MODE"] != nil {
self.warnings = self.evaluations self.warnings = self.evaluations
} }
MainMenu.shared.rebuild()
} }
} }

View File

@ -55,7 +55,9 @@
"mi_detected_extensions" = "Detected Extensions"; "mi_detected_extensions" = "Detected Extensions";
"mi_no_extensions_detected" = "No additional extensions detected."; "mi_no_extensions_detected" = "No additional extensions detected.";
"mi_warnings" = "(%i) PHP Doctor..."; "mi_php_doctor" = "PHP Doctor";
"mi_recommendations_count" = "%i Issue(s) Detected!";
"mi_view_recommendations" = "View Recommendations...";
"mi_valet" = "Laravel Valet"; "mi_valet" = "Laravel Valet";
"mi_domain_list" = "View Domains List..."; "mi_domain_list" = "View Domains List...";
@ -517,6 +519,8 @@ If you are seeing this message but are confused why this folder has gone missing
"warnings.title" = "PHP Doctor"; "warnings.title" = "PHP Doctor";
"warnings.description" = "**PHP Doctor** will suggest improvements to your active system configuration."; "warnings.description" = "**PHP Doctor** will suggest improvements to your active system configuration.";
"warnings.disclaimer" = "You may choose to hide all recommendations from the PHP Monitor menu in Preferences, but it is recommended that you deal with all actionable items."; "warnings.disclaimer" = "You may choose to hide all recommendations from the PHP Monitor menu in Preferences, but it is recommended that you deal with all actionable items.";
"warnings.refresh.button" = "Scan Again";
"warnings.refresh.button.description" = "Press this button once you've fixed an issue. This will cause PHP Monitor to re-evaluate your environment. If it's really fixed, the recommendation should disappear.";
"warnings.helper_permissions.title" = "PHP Monitors helpers are currently unavailable."; "warnings.helper_permissions.title" = "PHP Monitors helpers are currently unavailable.";
"warnings.helper_permissions.description" = "PHP Monitor comes with various helper binaries. Using these binaries allows you to easily invoke a specific version of PHP without switching the linked PHP version."; "warnings.helper_permissions.description" = "PHP Monitor comes with various helper binaries. Using these binaries allows you to easily invoke a specific version of PHP without switching the linked PHP version.";
@ -531,14 +535,14 @@ If you are seeing this message but are confused why this folder has gone missing
"onboarding.title" = "Welcome Tour"; "onboarding.title" = "Welcome Tour";
"onboarding.welcome" = "Welcome to PHP Monitor!"; "onboarding.welcome" = "Welcome to PHP Monitor!";
"onboarding.explore" = "Learn more about some of the features that PHP Monitor has to offer. You can find a more comprehensive list of features on GitHub."; "onboarding.explore" = "Learn more about some of the features that PHP Monitor has to offer. You can find a more comprehensive list of features on GitHub.";
"onboarding.tour.menu_bar.title" = "Get Started"; "onboarding.tour.menu_bar.title" = "Power In Your Menu Bar";
"onboarding.tour.menu_bar" = "PHP Monitor lives in your menu bar. From here, you can switch the globally linked PHP version, start or stop services, locate config files, and more."; "onboarding.tour.menu_bar" = "PHP Monitor lives in your menu bar. From this menu, you can access most of PHP Monitor's key functionality, including switching the globally linked PHP version, locating config files, and much more.";
"onboarding.tour.faq_hint" = "I recommend that you check out the [README](https://github.com/nicoverbruggen/phpmon/blob/main/README.md) on GitHub: it contains a comprehensive FAQ with various tips and common questions and answers."; "onboarding.tour.faq_hint" = "I recommend that you check out the [README](https://github.com/nicoverbruggen/phpmon/blob/main/README.md) on GitHub: it contains a comprehensive FAQ with various tips and common questions and answers.";
"onboarding.tour.services.title" = "Manage Services"; "onboarding.tour.services.title" = "Manage Homebrew Services";
"onboarding.tour.services" = "Once you click on the menu bar item, you can see at a glance based on the checkmarks or crosses if all of the Homebrew services are up and running. You can also click on a service to quickly toggle it. You can also add your own!"; "onboarding.tour.services" = "Once you click on the menu bar item, you can see at a glance based on the checkmarks or crosses if all of the Homebrew services are up and running. You can also click on a service to quickly toggle it.";
"onboarding.tour.domains.title" = "Manage Domains"; "onboarding.tour.domains.title" = "Manage Domains";
"onboarding.tour.domains" = "By opening the Domains window via the menu bar item, you can view which domains are linked and parked, as well as active nginx proxies."; "onboarding.tour.domains" = "By opening the Domains window via the menu bar item, you can view which domains are linked and parked, as well as active nginx proxies.";
"onboarding.tour.isolation.title" = "Isolate Domains"; "onboarding.tour.isolation.title" = "Isolate Domains";
"onboarding.tour.isolation" = "If you have Valet 3 installed, you can even use domain isolation by right-clicking on a given domain in the Domains window. This allows you to pick a specific version of PHP to use for that domain, and that domain only!"; "onboarding.tour.isolation" = "If you have Valet 3 installed, you can even use domain isolation by right-clicking on a given domain in the Domains window. This allows you to pick a specific version of PHP to use for that domain, and that domain only.";
"onboarding.tour.once" = "You will only see the Welcome Tour once. You can re-open the Welcome Tour later via the menu bar icon (under First Aid & Services)."; "onboarding.tour.once" = "You will only see the Welcome Tour once. You can re-open the Welcome Tour later via the menu bar icon (under First Aid & Services).";
"onboarding.tour.close" = "Close Tour"; "onboarding.tour.close" = "Close Tour";