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:
@ -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 */,
|
||||||
|
@ -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"
|
||||||
}
|
}
|
||||||
|
27
phpmon/Common/Core/Shell+PATH.swift
Normal file
27
phpmon/Common/Core/Shell+PATH.swift
Normal 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) ?? ""
|
||||||
|
}
|
||||||
|
}
|
@ -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/")
|
||||||
|
@ -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>
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
|
@ -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() {
|
||||||
|
@ -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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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 Monitor’s helpers are currently unavailable.";
|
"warnings.helper_permissions.title" = "PHP Monitor’s 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";
|
||||||
|
Reference in New Issue
Block a user