mirror of
https://github.com/nicoverbruggen/phpmon.git
synced 2025-08-07 20:10:08 +02:00
🏗 WIP: Tweaks to PHP Doctor
This commit is contained in:
@ -68,6 +68,11 @@
|
|||||||
</CommandLineArgument>
|
</CommandLineArgument>
|
||||||
</CommandLineArguments>
|
</CommandLineArguments>
|
||||||
<EnvironmentVariables>
|
<EnvironmentVariables>
|
||||||
|
<EnvironmentVariable
|
||||||
|
key = "EXTREME_DOCTOR_MODE"
|
||||||
|
value = ""
|
||||||
|
isEnabled = "YES">
|
||||||
|
</EnvironmentVariable>
|
||||||
<EnvironmentVariable
|
<EnvironmentVariable
|
||||||
key = "PAINT_PHPMON_SWIFTUI_VIEWS"
|
key = "PAINT_PHPMON_SWIFTUI_VIEWS"
|
||||||
value = ""
|
value = ""
|
||||||
|
@ -82,7 +82,7 @@ class StatusMenu: NSMenu {
|
|||||||
self.addItem(NSMenuItem.separator())
|
self.addItem(NSMenuItem.separator())
|
||||||
|
|
||||||
let count = WarningManager.shared.warnings.count
|
let count = WarningManager.shared.warnings.count
|
||||||
self.addItem(NSMenuItem(title: (count == 1 ? "mi_warning" : "mi_warnings").localized(count),
|
self.addItem(NSMenuItem(title: "mi_warnings".localized(count),
|
||||||
action: #selector(MainMenu.openWarnings), keyEquivalent: ""))
|
action: #selector(MainMenu.openWarnings), keyEquivalent: ""))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,26 +10,50 @@ import SwiftUI
|
|||||||
|
|
||||||
struct WarningListView: View {
|
struct WarningListView: View {
|
||||||
var body: some View {
|
var body: some View {
|
||||||
List {
|
VStack {
|
||||||
VStack(alignment: .leading) {
|
HStack(spacing: 15) {
|
||||||
ForEach(WarningManager.shared.warnings) { warning in
|
Image(systemName: "stethoscope.circle.fill")
|
||||||
WarningView(
|
.resizable()
|
||||||
title: warning.titleText,
|
.frame(width: 40, height: 40)
|
||||||
description: warning.descriptionText,
|
.foregroundColor(Color.red)
|
||||||
documentationUrl: warning.url
|
.padding(12)
|
||||||
)
|
VStack(alignment: .trailing, spacing: 5) {
|
||||||
Divider()
|
Text("warnings.description".localizedForSwiftUI)
|
||||||
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
|
Text("warnings.disclaimer".localizedForSwiftUI)
|
||||||
|
.font(.system(size: 12))
|
||||||
|
.foregroundColor(.gray)
|
||||||
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.padding(10)
|
||||||
|
|
||||||
|
List {
|
||||||
|
VStack(alignment: .leading, spacing: 0) {
|
||||||
|
ForEach(WarningManager.shared.warnings) { warning in
|
||||||
|
Group {
|
||||||
|
WarningView(
|
||||||
|
title: warning.title,
|
||||||
|
paragraphs: warning.paragraphs,
|
||||||
|
documentationUrl: warning.url
|
||||||
|
)
|
||||||
|
.fixedSize(horizontal: false, vertical: true)
|
||||||
|
|
||||||
|
Divider()
|
||||||
|
}.padding(5)
|
||||||
|
}
|
||||||
|
}.frame(minHeight: 0, maxHeight: .infinity).padding(5)
|
||||||
|
}
|
||||||
|
.listRowInsets(EdgeInsets())
|
||||||
|
.listStyle(.plain)
|
||||||
|
.frame(maxHeight: .infinity, alignment: .top)
|
||||||
}
|
}
|
||||||
.navigationTitle("Warnings")
|
|
||||||
.listStyle(.automatic)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct WarningListView_Previews: PreviewProvider {
|
struct WarningListView_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
WarningListView()
|
WarningListView()
|
||||||
|
.frame(width: 600, height: 480)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,27 +10,37 @@ import SwiftUI
|
|||||||
|
|
||||||
struct WarningView: View {
|
struct WarningView: View {
|
||||||
@State var title: String
|
@State var title: String
|
||||||
@State var description: String
|
@State var paragraphs: [String]
|
||||||
@State var documentationUrl: String?
|
@State var documentationUrl: String?
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
HStack(spacing: 10) {
|
HStack(alignment: .top, spacing: 10) {
|
||||||
Image(systemName: "exclamationmark.triangle.fill")
|
Image(systemName: "bandage.fill")
|
||||||
.resizable()
|
.resizable()
|
||||||
.frame(width: 18, height: 18)
|
.frame(width: 18, height: 18)
|
||||||
.foregroundColor(Color.orange)
|
.foregroundColor(Color.orange)
|
||||||
.padding()
|
.padding(.trailing, 5)
|
||||||
VStack(alignment: .leading, spacing: 5) {
|
VStack(alignment: .leading, spacing: 15) {
|
||||||
Text(title.localizedForSwiftUI)
|
VStack(alignment: .leading, spacing: 10) {
|
||||||
.fontWeight(.bold)
|
Text(title.localizedForSwiftUI)
|
||||||
Text(description.localizedForSwiftUI)
|
.fontWeight(.bold)
|
||||||
.font(.system(size: 12))
|
ForEach(paragraphs, id: \.self) { paragraph in
|
||||||
}
|
Text(paragraph.localizedForSwiftUI)
|
||||||
if documentationUrl != nil {
|
.font(.system(size: 13))
|
||||||
Button("Learn More") {
|
}
|
||||||
NSWorkspace.shared.open(URL(string: documentationUrl!)!)
|
}
|
||||||
}.padding()
|
.fixedSize(horizontal: false, vertical: false)
|
||||||
|
.frame(
|
||||||
|
minWidth: 0, maxWidth: .infinity,
|
||||||
|
minHeight: 0, maxHeight: .infinity,
|
||||||
|
alignment: .topLeading
|
||||||
|
)
|
||||||
|
if documentationUrl != nil {
|
||||||
|
Button("Learn More") {
|
||||||
|
NSWorkspace.shared.open(URL(string: documentationUrl!)!)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}.padding(5)
|
}.padding(5)
|
||||||
}
|
}
|
||||||
@ -39,15 +49,6 @@ struct WarningView: View {
|
|||||||
|
|
||||||
struct WarningView_Previews: PreviewProvider {
|
struct WarningView_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
WarningView(
|
WarningListView().frame(width: 600, height: 480)
|
||||||
title: "warnings.helper_permissions_title",
|
|
||||||
description: "warnings.helper_permissions.description",
|
|
||||||
documentationUrl: "https://nicoverbruggen.be"
|
|
||||||
)
|
|
||||||
WarningView(
|
|
||||||
title: "warnings.helper_permissions_title",
|
|
||||||
description: "warnings.helper_permissions.description"
|
|
||||||
)
|
|
||||||
.preferredColorScheme(.dark)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,21 +12,21 @@ struct Warning: Identifiable {
|
|||||||
var id = UUID()
|
var id = UUID()
|
||||||
let command: () async -> Bool
|
let command: () async -> Bool
|
||||||
let name: String
|
let name: String
|
||||||
let titleText: String
|
let title: String
|
||||||
let descriptionText: String
|
let paragraphs: [String]
|
||||||
let url: String?
|
let url: String?
|
||||||
|
|
||||||
init(
|
init(
|
||||||
command: @escaping () async -> Bool,
|
command: @escaping () async -> Bool,
|
||||||
name: String,
|
name: String,
|
||||||
titleText: String,
|
title: String,
|
||||||
descriptionText: String,
|
paragraphs: [String],
|
||||||
url: String?
|
url: String?
|
||||||
) {
|
) {
|
||||||
self.command = command
|
self.command = command
|
||||||
self.name = name
|
self.name = name
|
||||||
self.titleText = titleText
|
self.title = title
|
||||||
self.descriptionText = descriptionText
|
self.paragraphs = paragraphs
|
||||||
self.url = url
|
self.url = url
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,25 +13,31 @@ class WarningManager {
|
|||||||
|
|
||||||
static var shared = WarningManager()
|
static var shared = WarningManager()
|
||||||
|
|
||||||
|
init() {
|
||||||
|
if isRunningSwiftUIPreview {
|
||||||
|
self.warnings = self.evaluations
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public let evaluations: [Warning] = [
|
public let evaluations: [Warning] = [
|
||||||
Warning(
|
|
||||||
command: {
|
|
||||||
!FileManager.default.isWritableFile(atPath: "/usr/local/bin/")
|
|
||||||
},
|
|
||||||
name: "`/usr/local/bin` not writable",
|
|
||||||
titleText: "warnings.helper_permissions.title",
|
|
||||||
descriptionText: "warnings.helper_permissions.description",
|
|
||||||
url: nil
|
|
||||||
),
|
|
||||||
Warning(
|
Warning(
|
||||||
command: {
|
command: {
|
||||||
return Shell.pipe("sysctl -n sysctl.proc_translated")
|
return Shell.pipe("sysctl -n sysctl.proc_translated")
|
||||||
.trimmingCharacters(in: .whitespacesAndNewlines) == "1"
|
.trimmingCharacters(in: .whitespacesAndNewlines) == "1"
|
||||||
},
|
},
|
||||||
name: "Running PHP Monitor with Rosetta on M1",
|
name: "Running PHP Monitor with Rosetta on M1",
|
||||||
titleText: "warnings.arm_compatibility.title",
|
title: "warnings.arm_compatibility.title",
|
||||||
descriptionText: "warnings.arm_compatibility.description",
|
paragraphs: ["warnings.arm_compatibility.description"],
|
||||||
url: "https://github.com/nicoverbruggen/phpmon/wiki/PHP-Monitor-and-Apple-Silicon"
|
url: "https://github.com/nicoverbruggen/phpmon/wiki/PHP-Monitor-and-Apple-Silicon"
|
||||||
|
),
|
||||||
|
Warning(
|
||||||
|
command: {
|
||||||
|
!FileManager.default.isWritableFile(atPath: "/usr/local/bin/")
|
||||||
|
},
|
||||||
|
name: "`/usr/local/bin` not writable",
|
||||||
|
title: "warnings.helper_permissions.title",
|
||||||
|
paragraphs: ["warnings.helper_permissions.description", "warnings.helper_permissions.unavailable"],
|
||||||
|
url: "https://github.com/nicoverbruggen/phpmon/wiki/PHP-Monitor-helper-binaries"
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -50,6 +56,7 @@ class WarningManager {
|
|||||||
*/
|
*/
|
||||||
func checkEnvironment() async {
|
func checkEnvironment() async {
|
||||||
self.warnings = []
|
self.warnings = []
|
||||||
|
|
||||||
for check in self.evaluations {
|
for check in self.evaluations {
|
||||||
if await check.applies() {
|
if await check.applies() {
|
||||||
Log.info("[WARNING] \(check.name)")
|
Log.info("[WARNING] \(check.name)")
|
||||||
@ -57,6 +64,11 @@ class WarningManager {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For debugging purposes, we may wish to see all possible evaluations listed
|
||||||
|
if ProcessInfo.processInfo.environment["EXTREME_DOCTOR_MODE"] != nil {
|
||||||
|
self.warnings = self.evaluations
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -22,12 +22,12 @@ class WarningsWindowController: PMWindowController {
|
|||||||
windowController.window = NSWindow()
|
windowController.window = NSWindow()
|
||||||
|
|
||||||
guard let window = windowController.window else { return }
|
guard let window = windowController.window else { return }
|
||||||
window.title = "warnings.title".localized
|
window.title = ""
|
||||||
window.styleMask = [.titled, .closable, .miniaturizable]
|
window.styleMask = [.titled, .closable, .miniaturizable]
|
||||||
window.titlebarAppearsTransparent = true
|
window.titlebarAppearsTransparent = true
|
||||||
window.delegate = delegate ?? windowController
|
window.delegate = delegate ?? windowController
|
||||||
window.contentView = NSHostingView(rootView: WarningListView())
|
window.contentView = NSHostingView(rootView: WarningListView())
|
||||||
window.setContentSize(NSSize(width: 600, height: 300))
|
window.setContentSize(NSSize(width: 600, height: 480))
|
||||||
|
|
||||||
App.shared.warningsWindowController = windowController
|
App.shared.warningsWindowController = windowController
|
||||||
}
|
}
|
||||||
|
@ -55,8 +55,7 @@
|
|||||||
"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_warning" = "⚠️ %i Warning";
|
"mi_warnings" = "(%i) PHP Doctor...";
|
||||||
"mi_warnings" = "⚠️ %i Warnings...";
|
|
||||||
|
|
||||||
"mi_valet" = "Laravel Valet";
|
"mi_valet" = "Laravel Valet";
|
||||||
"mi_domain_list" = "View Domains List...";
|
"mi_domain_list" = "View Domains List...";
|
||||||
@ -509,12 +508,15 @@ If you are seeing this message but are confused why this folder has gone missing
|
|||||||
|
|
||||||
// WARNINGS
|
// WARNINGS
|
||||||
|
|
||||||
"warnings.title" = "Warnings";
|
"warnings.title" = "PHP Doctor";
|
||||||
|
"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.helper_permissions.title" = "Helpers could not be written!";
|
"warnings.helper_permissions.title" = "PHP Monitor’s helpers are currently unavailable.";
|
||||||
"warnings.helper_permissions.description" = "The helper files in `/usr/local/bin` could not be written because PHP Monitor does not have permission to write there.";
|
"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.unavailable" = "However, these helpers are currently *unavailable* because PHP Monitor could not create the required symlinks (alternatively, you could add PHP Monitor's helper directory to your `PATH` variable to make this warning go away as well).";
|
||||||
|
|
||||||
"warnings.arm_compatibility.title" = "You are running PHP Monitor using Rosetta";
|
"warnings.arm_compatibility.title" = "You are running PHP Monitor using Rosetta on Apple Silicon, which means your PHP environment is also running via Rosetta.";
|
||||||
"warnings.arm_compatibility.description" = "You appear to be running an ARM-compatible version of macOS, but you are currently running PHP Monitor using Rosetta. While this will work correctly, it is recommended that you use the native version of Homebrew.";
|
"warnings.arm_compatibility.description" = "You appear to be running an ARM-compatible version of macOS, but you are currently running PHP Monitor using Rosetta. While this will work correctly, it is recommended that you use the native version of Homebrew.";
|
||||||
|
|
||||||
// ONBOARDING
|
// ONBOARDING
|
||||||
|
Reference in New Issue
Block a user