mirror of
https://github.com/nicoverbruggen/phpmon.git
synced 2025-08-08 04:20:07 +02:00
Compare commits
28 Commits
Author | SHA1 | Date | |
---|---|---|---|
b26fc3bc4b | |||
f758c5d63a | |||
c7510d778d | |||
70c5aadb7f | |||
a731f15cf7 | |||
ab4c436202 | |||
c0231690d4 | |||
988e9d3351 | |||
2f119d4332 | |||
d83c629a7b | |||
e7d98dbeae | |||
f3d5946743 | |||
7728a1125c | |||
3612351df7 | |||
8e912151fb | |||
3a2209e604 | |||
1f0b56cab6 | |||
e08d970edd | |||
32c757e711 | |||
480cdb94ae | |||
7fbcac5dc2 | |||
4edb5f5015 | |||
294f84ccb2 | |||
155b57eb9e | |||
ff61d8c52e | |||
da41673855 | |||
5bda727981 | |||
8790b30706 |
@ -145,6 +145,9 @@
|
|||||||
C42337A3281F19F000459A48 /* Xdebug.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42337A2281F19F000459A48 /* Xdebug.swift */; };
|
C42337A3281F19F000459A48 /* Xdebug.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42337A2281F19F000459A48 /* Xdebug.swift */; };
|
||||||
C42759672627662800093CAE /* NSMenuExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42759662627662800093CAE /* NSMenuExtension.swift */; };
|
C42759672627662800093CAE /* NSMenuExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42759662627662800093CAE /* NSMenuExtension.swift */; };
|
||||||
C42759682627662800093CAE /* NSMenuExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42759662627662800093CAE /* NSMenuExtension.swift */; };
|
C42759682627662800093CAE /* NSMenuExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42759662627662800093CAE /* NSMenuExtension.swift */; };
|
||||||
|
C428311E2B52AD6F0009F9F1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C41C1B3A22B0098000E7CF16 /* Assets.xcassets */; };
|
||||||
|
C428311F2B52AD6F0009F9F1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C41C1B3A22B0098000E7CF16 /* Assets.xcassets */; };
|
||||||
|
C42831202B52AD700009F9F1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C41C1B3A22B0098000E7CF16 /* Assets.xcassets */; };
|
||||||
C4292D542B023F61004F0D2A /* PhpExtensionManagerWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4292D532B023F61004F0D2A /* PhpExtensionManagerWindowController.swift */; };
|
C4292D542B023F61004F0D2A /* PhpExtensionManagerWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4292D532B023F61004F0D2A /* PhpExtensionManagerWindowController.swift */; };
|
||||||
C4292D562B024006004F0D2A /* PhpExtensionManagerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4292D552B024006004F0D2A /* PhpExtensionManagerView.swift */; };
|
C4292D562B024006004F0D2A /* PhpExtensionManagerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4292D552B024006004F0D2A /* PhpExtensionManagerView.swift */; };
|
||||||
C4297F7A28970D59004C4630 /* WarningView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4297F7928970D59004C4630 /* WarningView.swift */; };
|
C4297F7A28970D59004C4630 /* WarningView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4297F7928970D59004C4630 /* WarningView.swift */; };
|
||||||
@ -2327,7 +2330,7 @@
|
|||||||
attributes = {
|
attributes = {
|
||||||
BuildIndependentTargetsInParallel = YES;
|
BuildIndependentTargetsInParallel = YES;
|
||||||
LastSwiftUpdateCheck = 1420;
|
LastSwiftUpdateCheck = 1420;
|
||||||
LastUpgradeCheck = 1430;
|
LastUpgradeCheck = 1500;
|
||||||
ORGANIZATIONNAME = "Nico Verbruggen";
|
ORGANIZATIONNAME = "Nico Verbruggen";
|
||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
C406A5EF298AD2CE00B5B85A = {
|
C406A5EF298AD2CE00B5B85A = {
|
||||||
@ -2412,6 +2415,7 @@
|
|||||||
C4E2E85528FC256B003B070C /* brew-services-sudo.json in Resources */,
|
C4E2E85528FC256B003B070C /* brew-services-sudo.json in Resources */,
|
||||||
C4E2E85928FC256B003B070C /* brew-services-normal.json in Resources */,
|
C4E2E85928FC256B003B070C /* brew-services-normal.json in Resources */,
|
||||||
C40934A8298EEB8700D25014 /* phpmon-dev.rb in Resources */,
|
C40934A8298EEB8700D25014 /* phpmon-dev.rb in Resources */,
|
||||||
|
C428311F2B52AD6F0009F9F1 /* Assets.xcassets in Resources */,
|
||||||
C4E2E84F28FC22E4003B070C /* brew-formula.json in Resources */,
|
C4E2E84F28FC22E4003B070C /* brew-formula.json in Resources */,
|
||||||
C4E2E86228FC28A6003B070C /* brew-services.json in Resources */,
|
C4E2E86228FC28A6003B070C /* brew-services.json in Resources */,
|
||||||
);
|
);
|
||||||
@ -2425,6 +2429,7 @@
|
|||||||
C4E2E85628FC256B003B070C /* brew-services-sudo.json in Resources */,
|
C4E2E85628FC256B003B070C /* brew-services-sudo.json in Resources */,
|
||||||
C4E2E85A28FC256B003B070C /* brew-services-normal.json in Resources */,
|
C4E2E85A28FC256B003B070C /* brew-services-normal.json in Resources */,
|
||||||
C40934A9298EEB8700D25014 /* phpmon-dev.rb in Resources */,
|
C40934A9298EEB8700D25014 /* phpmon-dev.rb in Resources */,
|
||||||
|
C42831202B52AD700009F9F1 /* Assets.xcassets in Resources */,
|
||||||
C4E2E85028FC22E4003B070C /* brew-formula.json in Resources */,
|
C4E2E85028FC22E4003B070C /* brew-formula.json in Resources */,
|
||||||
C4E2E86128FC28A6003B070C /* brew-services.json in Resources */,
|
C4E2E86128FC28A6003B070C /* brew-services.json in Resources */,
|
||||||
);
|
);
|
||||||
@ -2436,6 +2441,7 @@
|
|||||||
files = (
|
files = (
|
||||||
C4551659297AED7D009B8466 /* valetrc.valid in Resources */,
|
C4551659297AED7D009B8466 /* valetrc.valid in Resources */,
|
||||||
C4FC8D3E2A49816300FBBD16 /* Localizable.strings in Resources */,
|
C4FC8D3E2A49816300FBBD16 /* Localizable.strings in Resources */,
|
||||||
|
C428311E2B52AD6F0009F9F1 /* Assets.xcassets in Resources */,
|
||||||
54FCFD27276C883F004CE748 /* SelectPreferenceView.xib in Resources */,
|
54FCFD27276C883F004CE748 /* SelectPreferenceView.xib in Resources */,
|
||||||
54FCFD2E276C8D67004CE748 /* HotkeyPreferenceView.xib in Resources */,
|
54FCFD2E276C8D67004CE748 /* HotkeyPreferenceView.xib in Resources */,
|
||||||
C42CFB1827DFDFDC00862737 /* nginx-site-isolated.test in Resources */,
|
C42CFB1827DFDFDC00862737 /* nginx-site-isolated.test in Resources */,
|
||||||
@ -3521,6 +3527,7 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||||
CLANG_ANALYZER_NONNULL = YES;
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
@ -3585,6 +3592,7 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||||
CLANG_ANALYZER_NONNULL = YES;
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
@ -3647,7 +3655,7 @@
|
|||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
CURRENT_PROJECT_VERSION = 1400;
|
CURRENT_PROJECT_VERSION = 1422;
|
||||||
DEAD_CODE_STRIPPING = YES;
|
DEAD_CODE_STRIPPING = YES;
|
||||||
DEBUG = YES;
|
DEBUG = YES;
|
||||||
DEVELOPMENT_TEAM = 8M54J5J787;
|
DEVELOPMENT_TEAM = 8M54J5J787;
|
||||||
@ -3678,7 +3686,7 @@
|
|||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
CURRENT_PROJECT_VERSION = 1400;
|
CURRENT_PROJECT_VERSION = 1422;
|
||||||
DEAD_CODE_STRIPPING = YES;
|
DEAD_CODE_STRIPPING = YES;
|
||||||
DEBUG = NO;
|
DEBUG = NO;
|
||||||
DEVELOPMENT_TEAM = 8M54J5J787;
|
DEVELOPMENT_TEAM = 8M54J5J787;
|
||||||
@ -3856,6 +3864,7 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||||
CLANG_ANALYZER_NONNULL = YES;
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
@ -3918,7 +3927,7 @@
|
|||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
CURRENT_PROJECT_VERSION = 1400;
|
CURRENT_PROJECT_VERSION = 1422;
|
||||||
DEAD_CODE_STRIPPING = YES;
|
DEAD_CODE_STRIPPING = YES;
|
||||||
DEBUG = NO;
|
DEBUG = NO;
|
||||||
DEVELOPMENT_TEAM = 8M54J5J787;
|
DEVELOPMENT_TEAM = 8M54J5J787;
|
||||||
@ -3965,6 +3974,7 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||||
CLANG_ANALYZER_NONNULL = YES;
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
@ -4034,7 +4044,7 @@
|
|||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
CURRENT_PROJECT_VERSION = 1400;
|
CURRENT_PROJECT_VERSION = 1422;
|
||||||
DEAD_CODE_STRIPPING = YES;
|
DEAD_CODE_STRIPPING = YES;
|
||||||
DEBUG = YES;
|
DEBUG = YES;
|
||||||
DEVELOPMENT_TEAM = 8M54J5J787;
|
DEVELOPMENT_TEAM = 8M54J5J787;
|
||||||
@ -4081,6 +4091,7 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||||
CLANG_ANALYZER_NONNULL = YES;
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
@ -4150,7 +4161,7 @@
|
|||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
CURRENT_PROJECT_VERSION = 1400;
|
CURRENT_PROJECT_VERSION = 1422;
|
||||||
DEAD_CODE_STRIPPING = YES;
|
DEAD_CODE_STRIPPING = YES;
|
||||||
DEBUG = YES;
|
DEBUG = YES;
|
||||||
DEVELOPMENT_TEAM = 8M54J5J787;
|
DEVELOPMENT_TEAM = 8M54J5J787;
|
||||||
@ -4269,6 +4280,7 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||||
CLANG_ANALYZER_NONNULL = YES;
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
@ -4331,7 +4343,7 @@
|
|||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
CURRENT_PROJECT_VERSION = 1400;
|
CURRENT_PROJECT_VERSION = 1422;
|
||||||
DEAD_CODE_STRIPPING = YES;
|
DEAD_CODE_STRIPPING = YES;
|
||||||
DEBUG = NO;
|
DEBUG = NO;
|
||||||
DEVELOPMENT_TEAM = 8M54J5J787;
|
DEVELOPMENT_TEAM = 8M54J5J787;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Scheme
|
<Scheme
|
||||||
LastUpgradeVersion = "1430"
|
LastUpgradeVersion = "1500"
|
||||||
version = "1.3">
|
version = "1.3">
|
||||||
<BuildAction
|
<BuildAction
|
||||||
parallelizeBuildables = "YES"
|
parallelizeBuildables = "YES"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Scheme
|
<Scheme
|
||||||
LastUpgradeVersion = "1430"
|
LastUpgradeVersion = "1500"
|
||||||
version = "1.3">
|
version = "1.3">
|
||||||
<BuildAction
|
<BuildAction
|
||||||
parallelizeBuildables = "YES"
|
parallelizeBuildables = "YES"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Scheme
|
<Scheme
|
||||||
LastUpgradeVersion = "1430"
|
LastUpgradeVersion = "1500"
|
||||||
version = "1.3">
|
version = "1.3">
|
||||||
<BuildAction
|
<BuildAction
|
||||||
parallelizeBuildables = "YES"
|
parallelizeBuildables = "YES"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Scheme
|
<Scheme
|
||||||
LastUpgradeVersion = "1430"
|
LastUpgradeVersion = "1500"
|
||||||
version = "1.7">
|
version = "1.7">
|
||||||
<BuildAction
|
<BuildAction
|
||||||
parallelizeBuildables = "YES"
|
parallelizeBuildables = "YES"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Scheme
|
<Scheme
|
||||||
LastUpgradeVersion = "1430"
|
LastUpgradeVersion = "1500"
|
||||||
version = "1.3">
|
version = "1.3">
|
||||||
<BuildAction
|
<BuildAction
|
||||||
parallelizeBuildables = "YES"
|
parallelizeBuildables = "YES"
|
||||||
|
@ -120,7 +120,7 @@ For maximum compatibility with older PHP versions, you may wish to keep using Va
|
|||||||
<details>
|
<details>
|
||||||
<summary><strong>How do I install additional versions of PHP, including legacy versions?</strong></summary>
|
<summary><strong>How do I install additional versions of PHP, including legacy versions?</strong></summary>
|
||||||
|
|
||||||
Assuming you have installed the `php` formula, the latest stable version of PHP is installed. At the time of writing, this is PHP 8.2.
|
Assuming you have installed the `php` formula, the latest stable version of PHP is installed. At the time of writing, this is PHP 8.3.
|
||||||
|
|
||||||
You can install other supported versions of PHP via PHP Monitor's **PHP Version Manager**. (You can manually install or upgrade PHP versions too, but this is not recommended.)
|
You can install other supported versions of PHP via PHP Monitor's **PHP Version Manager**. (You can manually install or upgrade PHP versions too, but this is not recommended.)
|
||||||
|
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 674 KiB After Width: | Height: | Size: 723 KiB |
@ -8,6 +8,18 @@ import Foundation
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct Localization {
|
struct Localization {
|
||||||
|
static var preferredLanguage: String? {
|
||||||
|
guard let language = Preferences.preferences[.languageOverride] as? String else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if language.isEmpty {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return language
|
||||||
|
}
|
||||||
|
|
||||||
static var bundle: Bundle = {
|
static var bundle: Bundle = {
|
||||||
if !isRunningTests {
|
if !isRunningTests {
|
||||||
return Bundle.main
|
return Bundle.main
|
||||||
@ -32,7 +44,15 @@ struct Localization {
|
|||||||
|
|
||||||
extension String {
|
extension String {
|
||||||
var localized: String {
|
var localized: String {
|
||||||
let string = NSLocalizedString(self, tableName: nil, bundle: Localization.bundle, value: "", comment: "")
|
var preferredBundle: Bundle = Localization.bundle
|
||||||
|
|
||||||
|
if let preferred = Localization.preferredLanguage,
|
||||||
|
let path = Localization.bundle.path(forResource: preferred, ofType: "lproj"),
|
||||||
|
let bundle = Bundle(path: path) {
|
||||||
|
preferredBundle = bundle
|
||||||
|
}
|
||||||
|
|
||||||
|
let string = NSLocalizedString(self, tableName: nil, bundle: preferredBundle, value: "", comment: "")
|
||||||
|
|
||||||
// Fallback to English translation if the localized value is equal to the key (should not happen)
|
// Fallback to English translation if the localized value is equal to the key (should not happen)
|
||||||
if string == self {
|
if string == self {
|
||||||
|
@ -75,7 +75,7 @@ class MenuBarImageGenerator {
|
|||||||
|
|
||||||
// Then we'll fetch the image we want on the left
|
// Then we'll fetch the image we want on the left
|
||||||
var iconType = Preferences.preferences[.iconTypeToDisplay] as? String
|
var iconType = Preferences.preferences[.iconTypeToDisplay] as? String
|
||||||
if iconType == nil {
|
if iconType == nil || !MenuBarIcon.allCases.map({ $0.rawValue }).contains(iconType) {
|
||||||
Log.warn("Invalid icon type found, using the default")
|
Log.warn("Invalid icon type found, using the default")
|
||||||
iconType = MenuBarIcon.iconPhp.rawValue
|
iconType = MenuBarIcon.iconPhp.rawValue
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,7 @@ class PhpEnvironments {
|
|||||||
from: brewPhpAlias.data(using: .utf8)!
|
from: brewPhpAlias.data(using: .utf8)!
|
||||||
).first!
|
).first!
|
||||||
|
|
||||||
|
PhpEnvironments.brewPhpAlias = self.homebrewPackage.version
|
||||||
Log.info("[BREW] On your system, the `php` formula means version \(homebrewPackage.version).")
|
Log.info("[BREW] On your system, the `php` formula means version \(homebrewPackage.version).")
|
||||||
|
|
||||||
// Check if that version actually corresponds to an older version
|
// Check if that version actually corresponds to an older version
|
||||||
|
@ -27,7 +27,7 @@ extension InternalSwitcher {
|
|||||||
return corrections.contains(true)
|
return corrections.contains(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - PHP FPM pool
|
// MARK: - Corrections
|
||||||
|
|
||||||
public func disableDefaultPhpFpmPool(_ version: String) async -> FixApplied {
|
public func disableDefaultPhpFpmPool(_ version: String) async -> FixApplied {
|
||||||
let pool = "\(Paths.etcPath)/php/\(version)/php-fpm.d/www.conf"
|
let pool = "\(Paths.etcPath)/php/\(version)/php-fpm.d/www.conf"
|
||||||
@ -54,37 +54,7 @@ extension InternalSwitcher {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func getExpectedConfigurationFiles(for version: String) -> [ExpectedConfigurationFile] {
|
public func ensureConfigurationFilesExist(_ version: String) async -> FixApplied {
|
||||||
return [
|
|
||||||
ExpectedConfigurationFile(
|
|
||||||
destination: "/php-fpm.d/valet-fpm.conf",
|
|
||||||
source: "/cli/stubs/etc-phpfpm-valet.conf",
|
|
||||||
replacements: [
|
|
||||||
"VALET_USER": Paths.whoami,
|
|
||||||
"VALET_HOME_PATH": "~/.config/valet".replacingTildeWithHomeDirectory,
|
|
||||||
"valet.sock": "valet\(version.replacingOccurrences(of: ".", with: "")).sock"
|
|
||||||
],
|
|
||||||
applies: { Valet.shared.version!.major > 2 }
|
|
||||||
),
|
|
||||||
ExpectedConfigurationFile(
|
|
||||||
destination: "/conf.d/error_log.ini",
|
|
||||||
source: "/cli/stubs/etc-phpfpm-error_log.ini",
|
|
||||||
replacements: [
|
|
||||||
"VALET_USER": Paths.whoami,
|
|
||||||
"VALET_HOME_PATH": "~/.config/valet".replacingTildeWithHomeDirectory
|
|
||||||
],
|
|
||||||
applies: { return true }
|
|
||||||
),
|
|
||||||
ExpectedConfigurationFile(
|
|
||||||
destination: "/conf.d/php-memory-limits.ini",
|
|
||||||
source: "/cli/stubs/php-memory-limits.ini",
|
|
||||||
replacements: [:],
|
|
||||||
applies: { return true }
|
|
||||||
)
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
func ensureConfigurationFilesExist(_ version: String) async -> FixApplied {
|
|
||||||
let files = self.getExpectedConfigurationFiles(for: version)
|
let files = self.getExpectedConfigurationFiles(for: version)
|
||||||
|
|
||||||
// For each of the files, attempt to fix anything that is wrong
|
// For each of the files, attempt to fix anything that is wrong
|
||||||
@ -124,6 +94,38 @@ extension InternalSwitcher {
|
|||||||
return outcomes.contains(true)
|
return outcomes.contains(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - Internals
|
||||||
|
|
||||||
|
private func getExpectedConfigurationFiles(for version: String) -> [ExpectedConfigurationFile] {
|
||||||
|
return [
|
||||||
|
ExpectedConfigurationFile(
|
||||||
|
destination: "/php-fpm.d/valet-fpm.conf",
|
||||||
|
source: "/cli/stubs/etc-phpfpm-valet.conf",
|
||||||
|
replacements: [
|
||||||
|
"VALET_USER": Paths.whoami,
|
||||||
|
"VALET_HOME_PATH": "~/.config/valet".replacingTildeWithHomeDirectory,
|
||||||
|
"valet.sock": "valet\(version.replacingOccurrences(of: ".", with: "")).sock"
|
||||||
|
],
|
||||||
|
applies: { Valet.shared.version!.major > 2 }
|
||||||
|
),
|
||||||
|
ExpectedConfigurationFile(
|
||||||
|
destination: "/conf.d/error_log.ini",
|
||||||
|
source: "/cli/stubs/etc-phpfpm-error_log.ini",
|
||||||
|
replacements: [
|
||||||
|
"VALET_USER": Paths.whoami,
|
||||||
|
"VALET_HOME_PATH": "~/.config/valet".replacingTildeWithHomeDirectory
|
||||||
|
],
|
||||||
|
applies: { return true }
|
||||||
|
),
|
||||||
|
ExpectedConfigurationFile(
|
||||||
|
destination: "/conf.d/php-memory-limits.ini",
|
||||||
|
source: "/cli/stubs/php-memory-limits.ini",
|
||||||
|
replacements: [:],
|
||||||
|
applies: { return true }
|
||||||
|
)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct ExpectedConfigurationFile {
|
public struct ExpectedConfigurationFile {
|
||||||
|
@ -73,12 +73,26 @@ public struct TestableConfiguration: Codable {
|
|||||||
: .fake(.text)
|
: .fake(.text)
|
||||||
]) { (_, new) in new }
|
]) { (_, new) in new }
|
||||||
|
|
||||||
self.commandOutput["/opt/homebrew/opt/php@\(version.short)/bin/php-config --version"]
|
// PHP configuration files
|
||||||
= version.long
|
self.shellOutput["/opt/homebrew/opt/php@\(version.short)/bin/php --ini | grep -E -o '(/[^ ]+\\.ini)'"] =
|
||||||
|
.instant("/opt/homebrew/etc/php/\(version.short)/conf.d/php-memory-limits.ini")
|
||||||
|
|
||||||
|
// PHP Homebrew operations
|
||||||
|
self.shellOutput["/opt/homebrew/bin/brew unlink php@\(version.short)"] = .delayed(0.2, "OK")
|
||||||
|
self.shellOutput["sudo /opt/homebrew/bin/brew services stop php@\(version.short)"] = .delayed(0.2, "OK")
|
||||||
|
self.shellOutput["sudo /opt/homebrew/bin/brew services start php@\(version.short)"] = .delayed(0.2, "OK")
|
||||||
|
self.shellOutput["/opt/homebrew/bin/brew link php@\(version.short) --overwrite --force"] = .delayed(0.2, "OK")
|
||||||
|
|
||||||
|
// PHP version output
|
||||||
|
self.commandOutput["/opt/homebrew/opt/php@\(version.short)/bin/php-config --version"] = version.long
|
||||||
|
self.commandOutput["/opt/homebrew/opt/php@\(version.short)/bin/php -v"] = "OK"
|
||||||
|
|
||||||
if primary {
|
if primary {
|
||||||
self.shellOutput["ls /opt/homebrew/opt | grep php"]
|
// Files expected to be present for currently linked PHP version
|
||||||
= .instant("php")
|
self.shellOutput["ls /opt/homebrew/opt | grep php"] =
|
||||||
|
.instant("php")
|
||||||
|
self.shellOutput["/opt/homebrew/bin/php --ini | grep -E -o '(/[^ ]+\\.ini)'"] =
|
||||||
|
.instant("/opt/homebrew/etc/php/\(version.short)/conf.d/php-memory-limits.ini")
|
||||||
self.filesystem["/opt/homebrew/opt/php"]
|
self.filesystem["/opt/homebrew/opt/php"]
|
||||||
= .fake(.symlink, "/opt/homebrew/Cellar/php/\(version.long)")
|
= .fake(.symlink, "/opt/homebrew/Cellar/php/\(version.long)")
|
||||||
self.filesystem["/opt/homebrew/opt/php/bin/php"]
|
self.filesystem["/opt/homebrew/opt/php/bin/php"]
|
||||||
@ -89,12 +103,8 @@ public struct TestableConfiguration: Codable {
|
|||||||
= .fake(.symlink, "/opt/homebrew/Cellar/php/\(version.short)/bin/php-config")
|
= .fake(.symlink, "/opt/homebrew/Cellar/php/\(version.short)/bin/php-config")
|
||||||
self.commandOutput["/opt/homebrew/bin/php-config --version"]
|
self.commandOutput["/opt/homebrew/bin/php-config --version"]
|
||||||
= version.long
|
= version.long
|
||||||
self.commandOutput["/opt/homebrew/bin/php -r echo php_ini_scanned_files();"] =
|
|
||||||
"""
|
|
||||||
/opt/homebrew/etc/php/\(version.short)/conf.d/php-memory-limits.ini,
|
|
||||||
"""
|
|
||||||
} else {
|
} else {
|
||||||
|
// Output expected to be present for non-linked PHP versions
|
||||||
self.shellOutput["ls /opt/homebrew/opt | grep php@"] =
|
self.shellOutput["ls /opt/homebrew/opt | grep php@"] =
|
||||||
BatchFakeShellOutput.instant(
|
BatchFakeShellOutput.instant(
|
||||||
self.secondaryPhpVersions
|
self.secondaryPhpVersions
|
||||||
|
@ -109,6 +109,9 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
|
|||||||
|
|
||||||
static func initializeTestingProfile(_ path: String) {
|
static func initializeTestingProfile(_ path: String) {
|
||||||
Log.info("The configuration with path `\(path)` is being requested...")
|
Log.info("The configuration with path `\(path)` is being requested...")
|
||||||
|
// Clear for PHP Guard
|
||||||
|
Stats.clearCurrentGlobalPhpVersion()
|
||||||
|
// Load the configuration file
|
||||||
TestableConfiguration.loadFrom(path: path).apply()
|
TestableConfiguration.loadFrom(path: path).apply()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,6 +27,21 @@ class BrewDiagnostics {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Logs a bunch of useful information during startup.
|
||||||
|
*/
|
||||||
|
public static func logBootInformation() {
|
||||||
|
Log.info(BrewDiagnostics.customCaskInstalled
|
||||||
|
? "[BREW] The app has been installed via Homebrew Cask."
|
||||||
|
: "[BREW] The app has been installed directly (optimal)."
|
||||||
|
)
|
||||||
|
|
||||||
|
Log.info(BrewDiagnostics.usesNginxFullFormula
|
||||||
|
? "[BREW] The app will be using the `nginx-full` formula."
|
||||||
|
: "[BREW] The app will be using the `nginx` formula."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Determines whether the PHP Monitor Cask is installed.
|
Determines whether the PHP Monitor Cask is installed.
|
||||||
*/
|
*/
|
||||||
@ -46,6 +61,43 @@ class BrewDiagnostics {
|
|||||||
return destination.contains("/nginx-full/")
|
return destination.contains("/nginx-full/")
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
/**
|
||||||
|
It is possible to have outdated symlinks for PHP installations. This can mean that certain PHP installations
|
||||||
|
are going to be reported incorrectly (e.g. `php@8.2` links to an installation in a `8.3` folder after an upgrade).
|
||||||
|
|
||||||
|
To ensure this does not cause issues, PHP Monitor will automatically remove all incorrect PHP symlinks.
|
||||||
|
*/
|
||||||
|
public static func checkForOutdatedPhpInstallationSymlinks() async {
|
||||||
|
// Set up a regular expression
|
||||||
|
let regex = try! NSRegularExpression(pattern: "^php@[0-9]+\\.[0-9]+$", options: .caseInsensitive)
|
||||||
|
|
||||||
|
// Check for incorrect versions
|
||||||
|
if let contents = try? FileSystem.getShallowContentsOfDirectory("\(Paths.optPath)")
|
||||||
|
.filter({
|
||||||
|
let range = NSRange($0.startIndex..., in: $0)
|
||||||
|
return regex.firstMatch(in: $0, options: [], range: range) != nil
|
||||||
|
}) {
|
||||||
|
|
||||||
|
for symlink in contents {
|
||||||
|
let version = symlink.replacingOccurrences(of: "php@", with: "")
|
||||||
|
if let destination = try? FileSystem.getDestinationOfSymlink("\(Paths.optPath)/\(symlink)") {
|
||||||
|
if !destination.contains("Cellar/php/\(version)")
|
||||||
|
&& !destination.contains("Cellar/php@\(version)") {
|
||||||
|
Log.err("Symlink for \(symlink) is incorrect. Removing...")
|
||||||
|
do {
|
||||||
|
try FileSystem.remove("\(Paths.optPath)/\(symlink)")
|
||||||
|
Log.info("Incorrect symlink for \(symlink) has been successfully removed.")
|
||||||
|
} catch {
|
||||||
|
Log.err("Symlink for \(symlink) was incorrect but could not be removed!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.warn("Could not read symlink at: \(Paths.optPath)/\(symlink)! Symlink check skipped.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
It is possible to have the `shivammathur/php` tap installed, and for the core homebrew information to be outdated.
|
It is possible to have the `shivammathur/php` tap installed, and for the core homebrew information to be outdated.
|
||||||
This will then result in two different aliases claiming to point to the same formula (`php`).
|
This will then result in two different aliases claiming to point to the same formula (`php`).
|
||||||
|
@ -43,11 +43,13 @@ struct BrewPhpExtension: Hashable, Comparable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var hasAlternativeInstall: Bool {
|
var hasAlternativeInstall: Bool {
|
||||||
// Extension must be active
|
guard let php = PhpEnvironments.shared.cachedPhpInstallations[self.phpVersion] else {
|
||||||
let isActive = PhpEnvironments.shared.currentInstall?.extensions
|
return false
|
||||||
.contains(where: { $0.name == self.name }) ?? false
|
}
|
||||||
|
|
||||||
return isActive && !isInstalled
|
let alreadyDiscovered = php.extensions.contains(where: { $0.name == self.name })
|
||||||
|
|
||||||
|
return alreadyDiscovered && !isInstalled
|
||||||
}
|
}
|
||||||
|
|
||||||
internal func firstDependent(in exts: [BrewPhpExtension]) -> BrewPhpExtension? {
|
internal func firstDependent(in exts: [BrewPhpExtension]) -> BrewPhpExtension? {
|
||||||
|
@ -167,6 +167,9 @@ class ModifyPhpVersionCommand: BrewCommand {
|
|||||||
// Reload and restart PHP versions
|
// Reload and restart PHP versions
|
||||||
onProgress(.create(value: 0.95, title: self.title, description: "phpman.steps.reloading".localized))
|
onProgress(.create(value: 0.95, title: self.title, description: "phpman.steps.reloading".localized))
|
||||||
|
|
||||||
|
// Ensure all symlinks are correctly linked
|
||||||
|
await BrewDiagnostics.checkForOutdatedPhpInstallationSymlinks()
|
||||||
|
|
||||||
// Check which version of PHP are now installed
|
// Check which version of PHP are now installed
|
||||||
await PhpEnvironments.detectPhpVersions()
|
await PhpEnvironments.detectPhpVersions()
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ extension MainMenu {
|
|||||||
func startup() async {
|
func startup() async {
|
||||||
// Start with the icon
|
// Start with the icon
|
||||||
Task { @MainActor in
|
Task { @MainActor in
|
||||||
self.setStatusBar(image: NSImage(named: NSImage.Name("StatusBarIcon"))!)
|
self.setStatusBar(image: NSImage.statusBarIcon)
|
||||||
}
|
}
|
||||||
|
|
||||||
if await Startup().checkEnvironment() {
|
if await Startup().checkEnvironment() {
|
||||||
@ -32,19 +32,14 @@ extension MainMenu {
|
|||||||
// Determine what the `php` formula is aliased to
|
// Determine what the `php` formula is aliased to
|
||||||
await PhpEnvironments.shared.determinePhpAlias()
|
await PhpEnvironments.shared.determinePhpAlias()
|
||||||
|
|
||||||
|
// Make sure that broken symlinks are removed ASAP
|
||||||
|
await BrewDiagnostics.checkForOutdatedPhpInstallationSymlinks()
|
||||||
|
|
||||||
// Initialize preferences
|
// Initialize preferences
|
||||||
_ = Preferences.shared
|
_ = Preferences.shared
|
||||||
|
|
||||||
// Determine install method
|
// Put some useful diagnostics information in log
|
||||||
Log.info(BrewDiagnostics.customCaskInstalled
|
BrewDiagnostics.logBootInformation()
|
||||||
? "[BREW] The app has been installed via Homebrew Cask."
|
|
||||||
: "[BREW] The app has been installed directly (optimal)."
|
|
||||||
)
|
|
||||||
|
|
||||||
Log.info(BrewDiagnostics.usesNginxFullFormula
|
|
||||||
? "[BREW] The app will be using the `nginx-full` formula."
|
|
||||||
: "[BREW] The app will be using the `nginx` formula."
|
|
||||||
)
|
|
||||||
|
|
||||||
// Attempt to find out more info about Valet
|
// Attempt to find out more info about Valet
|
||||||
if Valet.shared.version != nil {
|
if Valet.shared.version != nil {
|
||||||
@ -73,7 +68,6 @@ extension MainMenu {
|
|||||||
WarningManager.shared.evaluateWarnings()
|
WarningManager.shared.evaluateWarnings()
|
||||||
|
|
||||||
// Set up the config watchers on launch (updated automatically when switching)
|
// Set up the config watchers on launch (updated automatically when switching)
|
||||||
Log.info("Setting up watchers...")
|
|
||||||
App.shared.handlePhpConfigWatcher()
|
App.shared.handlePhpConfigWatcher()
|
||||||
|
|
||||||
// Detect built-in and custom applications
|
// Detect built-in and custom applications
|
||||||
@ -108,6 +102,27 @@ extension MainMenu {
|
|||||||
// Find out which services are active
|
// Find out which services are active
|
||||||
Log.info("The services manager knows about \(ServicesManager.shared.services.count) services.")
|
Log.info("The services manager knows about \(ServicesManager.shared.services.count) services.")
|
||||||
|
|
||||||
|
// Post-launch stats and update check, but only if not running tests
|
||||||
|
await performPostLaunchActions()
|
||||||
|
|
||||||
|
// Check if the linked version has changed between launches of phpmon
|
||||||
|
PhpGuard().compareToLastGlobalVersion()
|
||||||
|
|
||||||
|
// We are ready!
|
||||||
|
PhpEnvironments.shared.isBusy = false
|
||||||
|
|
||||||
|
// Finally!
|
||||||
|
Log.info("PHP Monitor is ready to serve!")
|
||||||
|
|
||||||
|
// Check if we upgraded from a previous version
|
||||||
|
AppUpdater.checkIfUpdateWasPerformed()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Performs a set of post-launch actions, like incrementing stats and checking for updates.
|
||||||
|
(This code is skipped when running SwiftUI previews.)
|
||||||
|
*/
|
||||||
|
private func performPostLaunchActions() async {
|
||||||
if !isRunningSwiftUIPreview {
|
if !isRunningSwiftUIPreview {
|
||||||
Stats.incrementSuccessfulLaunchCount()
|
Stats.incrementSuccessfulLaunchCount()
|
||||||
Stats.evaluateSponsorMessageShouldBeDisplayed()
|
Stats.evaluateSponsorMessageShouldBeDisplayed()
|
||||||
@ -121,16 +136,6 @@ extension MainMenu {
|
|||||||
await AppUpdater().checkForUpdates(userInitiated: false)
|
await AppUpdater().checkForUpdates(userInitiated: false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the linked version has changed between launches of phpmon
|
|
||||||
PhpGuard().compareToLastGlobalVersion()
|
|
||||||
|
|
||||||
// We are ready!
|
|
||||||
PhpEnvironments.shared.isBusy = false
|
|
||||||
Log.info("PHP Monitor is ready to serve!")
|
|
||||||
|
|
||||||
// Check if we upgraded just now
|
|
||||||
AppUpdater.checkIfUpdateWasPerformed()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -155,12 +155,12 @@ class MainMenu: NSObject, NSWindowDelegate, NSMenuDelegate, PhpSwitcherDelegate
|
|||||||
Task { @MainActor [self] in
|
Task { @MainActor [self] in
|
||||||
if PhpEnvironments.shared.isBusy {
|
if PhpEnvironments.shared.isBusy {
|
||||||
Log.perf("Refreshing icon: currently busy")
|
Log.perf("Refreshing icon: currently busy")
|
||||||
setStatusBar(image: NSImage(named: NSImage.Name("StatusBarIcon"))!)
|
setStatusBar(image: NSImage.statusBarIcon)
|
||||||
} else {
|
} else {
|
||||||
Log.perf("Refreshing icon: no longer busy")
|
Log.perf("Refreshing icon: no longer busy")
|
||||||
if Preferences.preferences[.shouldDisplayDynamicIcon] as! Bool == false {
|
if Preferences.preferences[.shouldDisplayDynamicIcon] as! Bool == false {
|
||||||
// Static icon has been requested
|
// Static icon has been requested
|
||||||
setStatusBar(image: NSImage(named: NSImage.Name("StatusBarIconStatic"))!)
|
setStatusBar(image: NSImage.statusBarIconStatic)
|
||||||
} else {
|
} else {
|
||||||
// The dynamic icon has been requested
|
// The dynamic icon has been requested
|
||||||
let long = Preferences.preferences[.fullPhpVersionDynamicIcon] as! Bool
|
let long = Preferences.preferences[.fullPhpVersionDynamicIcon] as! Bool
|
||||||
|
@ -20,6 +20,7 @@ enum PreferenceName: String, Codable {
|
|||||||
case globalHotkey = "global_hotkey"
|
case globalHotkey = "global_hotkey"
|
||||||
case automaticBackgroundUpdateCheck = "backgroundUpdateCheck"
|
case automaticBackgroundUpdateCheck = "backgroundUpdateCheck"
|
||||||
case showPhpDoctorSuggestions = "show_php_doctor_suggestions"
|
case showPhpDoctorSuggestions = "show_php_doctor_suggestions"
|
||||||
|
case languageOverride = "language_override"
|
||||||
|
|
||||||
// APPEARANCE
|
// APPEARANCE
|
||||||
case shouldDisplayDynamicIcon = "use_dynamic_icon"
|
case shouldDisplayDynamicIcon = "use_dynamic_icon"
|
||||||
@ -84,7 +85,8 @@ enum PreferenceName: String, Codable {
|
|||||||
],
|
],
|
||||||
.string: [
|
.string: [
|
||||||
.globalHotkey,
|
.globalHotkey,
|
||||||
.iconTypeToDisplay
|
.iconTypeToDisplay,
|
||||||
|
.languageOverride
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -51,6 +51,7 @@ class Preferences {
|
|||||||
PreferenceName.allowProtocolForIntegrations.rawValue: true,
|
PreferenceName.allowProtocolForIntegrations.rawValue: true,
|
||||||
PreferenceName.automaticBackgroundUpdateCheck.rawValue: true,
|
PreferenceName.automaticBackgroundUpdateCheck.rawValue: true,
|
||||||
PreferenceName.showPhpDoctorSuggestions.rawValue: true,
|
PreferenceName.showPhpDoctorSuggestions.rawValue: true,
|
||||||
|
PreferenceName.languageOverride.rawValue: "",
|
||||||
|
|
||||||
/// Preferences: Appearance
|
/// Preferences: Appearance
|
||||||
PreferenceName.shouldDisplayDynamicIcon.rawValue: true,
|
PreferenceName.shouldDisplayDynamicIcon.rawValue: true,
|
||||||
|
@ -17,7 +17,9 @@ class GeneralPreferencesVC: GenericPreferenceVC {
|
|||||||
let vc = NSStoryboard(name: "Main", bundle: nil)
|
let vc = NSStoryboard(name: "Main", bundle: nil)
|
||||||
.instantiateController(withIdentifier: "preferencesTemplateVC") as! GenericPreferenceVC
|
.instantiateController(withIdentifier: "preferencesTemplateVC") as! GenericPreferenceVC
|
||||||
|
|
||||||
_ = vc.addView(when: true, vc.getShowPhpDoctorSuggestionsPV())
|
_ = vc
|
||||||
|
.addView(when: true, vc.getLanguageOptionsPV())
|
||||||
|
.addView(when: true, vc.getShowPhpDoctorSuggestionsPV())
|
||||||
.addView(when: true, vc.getAutoRestartServicesPV())
|
.addView(when: true, vc.getAutoRestartServicesPV())
|
||||||
.addView(when: true, vc.getAutomaticComposerUpdatePV())
|
.addView(when: true, vc.getAutomaticComposerUpdatePV())
|
||||||
.addView(when: true, vc.getShortcutPV())
|
.addView(when: true, vc.getShortcutPV())
|
||||||
|
@ -48,11 +48,44 @@ class GenericPreferenceVC: NSViewController {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getLanguageOptionsPV() -> NSView {
|
||||||
|
var options = Bundle.main.localizations
|
||||||
|
.filter({ $0 != "Base"})
|
||||||
|
.map({ lang in
|
||||||
|
return PreferenceDropdownOption(
|
||||||
|
label: Locale.current.localizedString(forLanguageCode: lang)!,
|
||||||
|
value: lang
|
||||||
|
)
|
||||||
|
})
|
||||||
|
options.insert(PreferenceDropdownOption(label: "System Default", value: ""), at: 0)
|
||||||
|
|
||||||
|
return SelectPreferenceView.make(
|
||||||
|
sectionText: "prefs.language".localized,
|
||||||
|
descriptionText: "prefs.language_options_desc".localized,
|
||||||
|
options: options,
|
||||||
|
preference: .languageOverride,
|
||||||
|
action: {
|
||||||
|
MainMenu.shared.refreshIcon()
|
||||||
|
MainMenu.shared.rebuild()
|
||||||
|
|
||||||
|
if let window = App.shared.preferencesWindowController?.window {
|
||||||
|
let alert = NSAlert()
|
||||||
|
alert.messageText = "alert.language_changed.title".localized
|
||||||
|
alert.informativeText = "alert.language_changed.subtitle".localized
|
||||||
|
alert.alertStyle = .warning
|
||||||
|
alert.addButton(withTitle: "generic.ok".localized)
|
||||||
|
alert.beginSheetModal(for: window)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
func getIconOptionsPV() -> NSView {
|
func getIconOptionsPV() -> NSView {
|
||||||
return SelectPreferenceView.make(
|
return SelectPreferenceView.make(
|
||||||
sectionText: "",
|
sectionText: "",
|
||||||
descriptionText: "prefs.icon_options_desc".localized,
|
descriptionText: "prefs.icon_options_desc".localized,
|
||||||
options: MenuBarIcon.allCases.map({ return $0.rawValue }),
|
options: MenuBarIcon.allCases
|
||||||
|
.map({ return PreferenceDropdownOption(label: $0.rawValue, value: $0.rawValue) }),
|
||||||
localizationPrefix: "prefs.icon_options",
|
localizationPrefix: "prefs.icon_options",
|
||||||
preference: .iconTypeToDisplay,
|
preference: .iconTypeToDisplay,
|
||||||
action: {
|
action: {
|
||||||
|
@ -68,6 +68,8 @@ class PreferencesWindowController: PMWindowController {
|
|||||||
App.shared.preferencesWindowController?.positionWindowInTopRightCorner()
|
App.shared.preferencesWindowController?.positionWindowInTopRightCorner()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
App.shared.preferencesWindowController?.window?.orderFrontRegardless()
|
||||||
|
|
||||||
NSApp.activate(ignoringOtherApps: true)
|
NSApp.activate(ignoringOtherApps: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,6 +84,10 @@ class Stats {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static func clearCurrentGlobalPhpVersion() {
|
||||||
|
UserDefaults.standard.removeObject(forKey: InternalStats.lastGlobalPhpVersion.rawValue)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Determine if the sponsor message should be displayed.
|
Determine if the sponsor message should be displayed.
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="21507" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="22505" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="macosx"/>
|
<deployment identifier="macosx"/>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="21507"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="22505"/>
|
||||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<objects>
|
<objects>
|
||||||
@ -23,7 +23,7 @@
|
|||||||
<action selector="toggled:" target="c22-O7-iKe" id="c9y-JM-TdE"/>
|
<action selector="toggled:" target="c22-O7-iKe" id="c9y-JM-TdE"/>
|
||||||
</connections>
|
</connections>
|
||||||
</button>
|
</button>
|
||||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Bcg-X1-qca">
|
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Bcg-X1-qca">
|
||||||
<rect key="frame" x="168" y="5" width="410" height="14"/>
|
<rect key="frame" x="168" y="5" width="410" height="14"/>
|
||||||
<textFieldCell key="cell" title="DESCRIPTION" id="9fH-up-Sob">
|
<textFieldCell key="cell" title="DESCRIPTION" id="9fH-up-Sob">
|
||||||
<font key="font" metaFont="smallSystem"/>
|
<font key="font" metaFont="smallSystem"/>
|
||||||
@ -31,7 +31,7 @@
|
|||||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
</textField>
|
</textField>
|
||||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="B8f-nb-Y0A">
|
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="B8f-nb-Y0A">
|
||||||
<rect key="frame" x="-2" y="27" width="154" height="16"/>
|
<rect key="frame" x="-2" y="27" width="154" height="16"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstAttribute="width" constant="150" id="euj-t0-xv4"/>
|
<constraint firstAttribute="width" constant="150" id="euj-t0-xv4"/>
|
||||||
|
@ -9,30 +9,34 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
import Cocoa
|
import Cocoa
|
||||||
|
|
||||||
class SelectPreferenceView: NSView, XibLoadable {
|
struct PreferenceDropdownOption {
|
||||||
|
let label: String
|
||||||
|
let value: String
|
||||||
|
}
|
||||||
|
|
||||||
|
class SelectPreferenceView: NSView, XibLoadable {
|
||||||
@IBOutlet weak var labelSection: NSTextField!
|
@IBOutlet weak var labelSection: NSTextField!
|
||||||
@IBOutlet weak var labelDescription: NSTextField!
|
@IBOutlet weak var labelDescription: NSTextField!
|
||||||
@IBOutlet weak var popupButton: NSPopUpButton!
|
@IBOutlet weak var popupButton: NSPopUpButton!
|
||||||
|
|
||||||
var localizationPrefix: String = ""
|
var localizationPrefix: String?
|
||||||
var imagePrefix: String?
|
var imagePrefix: String?
|
||||||
|
|
||||||
var options: [String] = [] {
|
var options: [PreferenceDropdownOption] = [] {
|
||||||
didSet {
|
didSet {
|
||||||
self.popupButton.removeAllItems()
|
self.popupButton.removeAllItems()
|
||||||
self.options.forEach { value in
|
self.options.forEach { option in
|
||||||
self.popupButton.addItem(
|
if let prefix = localizationPrefix {
|
||||||
withTitle: "\(localizationPrefix).\(value)".localized
|
self.popupButton.addItem(withTitle: "\(prefix).\(option.label)".localized)
|
||||||
)
|
} else {
|
||||||
|
self.popupButton.addItem(withTitle: option.label)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if imagePrefix == nil {
|
if let prefix = imagePrefix {
|
||||||
return
|
self.popupButton.itemArray.enumerated().forEach { item in
|
||||||
}
|
item.element.image = NSImage(named: "\(prefix)_\(self.options[item.offset].value)")
|
||||||
|
}
|
||||||
self.popupButton.itemArray.enumerated().forEach { item in
|
|
||||||
item.element.image = NSImage(named: "\(imagePrefix!)_\(self.options[item.offset])")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -43,19 +47,18 @@ class SelectPreferenceView: NSView, XibLoadable {
|
|||||||
didSet {
|
didSet {
|
||||||
let value = Preferences.preferences[preference] as! String
|
let value = Preferences.preferences[preference] as! String
|
||||||
self.options.enumerated().forEach { option in
|
self.options.enumerated().forEach { option in
|
||||||
if option.element == value {
|
if option.element.value == value {
|
||||||
self.popupButton.selectItem(at: option.offset)
|
self.popupButton.selectItem(at: option.offset)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// swiftlint:disable function_parameter_count
|
|
||||||
static func make(
|
static func make(
|
||||||
sectionText: String,
|
sectionText: String,
|
||||||
descriptionText: String,
|
descriptionText: String,
|
||||||
options: [String],
|
options: [PreferenceDropdownOption],
|
||||||
localizationPrefix: String,
|
localizationPrefix: String? = nil,
|
||||||
imagePrefix: String? = nil,
|
imagePrefix: String? = nil,
|
||||||
preference: PreferenceName,
|
preference: PreferenceName,
|
||||||
action: @escaping () -> Void) -> NSView {
|
action: @escaping () -> Void) -> NSView {
|
||||||
@ -72,11 +75,10 @@ class SelectPreferenceView: NSView, XibLoadable {
|
|||||||
|
|
||||||
return view
|
return view
|
||||||
}
|
}
|
||||||
// swiftlint:enable function_parameter_count
|
|
||||||
|
|
||||||
@IBAction func valueChanged(_ sender: Any) {
|
@IBAction func valueChanged(_ sender: Any) {
|
||||||
let index = self.popupButton.indexOfSelectedItem
|
let index = self.popupButton.indexOfSelectedItem
|
||||||
Preferences.update(.iconTypeToDisplay, value: self.options[index])
|
Preferences.update(self.preference, value: self.options[index].value)
|
||||||
self.action()
|
self.action()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="21701" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="22505" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="macosx"/>
|
<deployment identifier="macosx"/>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="21701"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="22505"/>
|
||||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<objects>
|
<objects>
|
||||||
@ -13,16 +13,16 @@
|
|||||||
<rect key="frame" x="0.0" y="0.0" width="596" height="50"/>
|
<rect key="frame" x="0.0" y="0.0" width="596" height="50"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Bcg-X1-qca">
|
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Bcg-X1-qca">
|
||||||
<rect key="frame" x="183" y="5" width="395" height="14"/>
|
<rect key="frame" x="168" y="5" width="410" height="14"/>
|
||||||
<textFieldCell key="cell" title="DESCRIPTION" id="9fH-up-Sob">
|
<textFieldCell key="cell" title="DESCRIPTION" id="9fH-up-Sob">
|
||||||
<font key="font" metaFont="smallSystem"/>
|
<font key="font" metaFont="smallSystem"/>
|
||||||
<color key="textColor" name="secondaryLabelColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="secondaryLabelColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
</textField>
|
</textField>
|
||||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="B8f-nb-Y0A">
|
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="B8f-nb-Y0A">
|
||||||
<rect key="frame" x="13" y="29" width="154" height="16"/>
|
<rect key="frame" x="-2" y="29" width="154" height="16"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstAttribute="width" constant="150" id="euj-t0-xv4"/>
|
<constraint firstAttribute="width" constant="150" id="euj-t0-xv4"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
@ -33,7 +33,7 @@
|
|||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
</textField>
|
</textField>
|
||||||
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="YaB-Tg-Ir3">
|
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="YaB-Tg-Ir3">
|
||||||
<rect key="frame" x="182" y="23" width="110" height="25"/>
|
<rect key="frame" x="167" y="23" width="110" height="25"/>
|
||||||
<popUpButtonCell key="cell" type="push" title="Icon Option" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="SaA-mm-HBo" id="Su6-C4-aGo">
|
<popUpButtonCell key="cell" type="push" title="Icon Option" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="SaA-mm-HBo" id="Su6-C4-aGo">
|
||||||
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
|
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
|
||||||
<font key="font" metaFont="menu"/>
|
<font key="font" metaFont="menu"/>
|
||||||
@ -58,7 +58,7 @@
|
|||||||
<constraint firstItem="Bcg-X1-qca" firstAttribute="top" secondItem="YaB-Tg-Ir3" secondAttribute="bottom" constant="8" symbolic="YES" id="Mji-pe-CNl"/>
|
<constraint firstItem="Bcg-X1-qca" firstAttribute="top" secondItem="YaB-Tg-Ir3" secondAttribute="bottom" constant="8" symbolic="YES" id="Mji-pe-CNl"/>
|
||||||
<constraint firstAttribute="trailing" secondItem="Bcg-X1-qca" secondAttribute="trailing" constant="20" symbolic="YES" id="UPo-Il-l81"/>
|
<constraint firstAttribute="trailing" secondItem="Bcg-X1-qca" secondAttribute="trailing" constant="20" symbolic="YES" id="UPo-Il-l81"/>
|
||||||
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="YaB-Tg-Ir3" secondAttribute="trailing" constant="20" symbolic="YES" id="Zlg-jj-uKY"/>
|
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="YaB-Tg-Ir3" secondAttribute="trailing" constant="20" symbolic="YES" id="Zlg-jj-uKY"/>
|
||||||
<constraint firstItem="B8f-nb-Y0A" firstAttribute="leading" secondItem="c22-O7-iKe" secondAttribute="leading" constant="15" id="Ztd-uk-4aw"/>
|
<constraint firstItem="B8f-nb-Y0A" firstAttribute="leading" secondItem="c22-O7-iKe" secondAttribute="leading" id="aBU-J8-gRK"/>
|
||||||
<constraint firstAttribute="bottom" secondItem="Bcg-X1-qca" secondAttribute="bottom" constant="5" id="hNE-mU-jcu"/>
|
<constraint firstAttribute="bottom" secondItem="Bcg-X1-qca" secondAttribute="bottom" constant="5" id="hNE-mU-jcu"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
<connections>
|
<connections>
|
||||||
|
@ -27,7 +27,9 @@ var isRunningSwiftUIPreview: Bool {
|
|||||||
|
|
||||||
extension Color {
|
extension Color {
|
||||||
public static var appPrimary: Color = Color("AppColor")
|
public static var appPrimary: Color = Color("AppColor")
|
||||||
public static var appSecondary: Color = Color("AppSecondary")
|
|
||||||
|
// This next one is generated automatically via asset catalogs now
|
||||||
|
// public static var appSecondary: Color = Color("AppSecondary")
|
||||||
|
|
||||||
public static var debug: Color = {
|
public static var debug: Color = {
|
||||||
if ProcessInfo.processInfo.environment["PAINT_PHPMON_SWIFTUI_VIEWS"] != nil {
|
if ProcessInfo.processInfo.environment["PAINT_PHPMON_SWIFTUI_VIEWS"] != nil {
|
||||||
|
@ -16,21 +16,19 @@ class DomainListKindCell: NSTableCellView, DomainListCellProtocol {
|
|||||||
|
|
||||||
func populateCell(with site: ValetSite) {
|
func populateCell(with site: ValetSite) {
|
||||||
// If the `aliasPath` is nil, we're dealing with a parked site (otherwise: linked).
|
// If the `aliasPath` is nil, we're dealing with a parked site (otherwise: linked).
|
||||||
imageViewType.image = NSImage(
|
imageViewType.image = site.aliasPath == nil
|
||||||
named: site.aliasPath == nil
|
? NSImage.iconParked
|
||||||
? "IconParked"
|
: NSImage.iconLinked
|
||||||
: "IconLinked"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Unless, of course, this is a default site
|
// Unless, of course, this is a default site
|
||||||
if site.absolutePath == Valet.shared.config.defaultSite {
|
if site.absolutePath == Valet.shared.config.defaultSite {
|
||||||
imageViewType.image = NSImage(named: "IconDefault")
|
imageViewType.image = NSImage.iconDefault
|
||||||
}
|
}
|
||||||
|
|
||||||
imageViewType.contentTintColor = NSColor.tertiaryLabelColor
|
imageViewType.contentTintColor = NSColor.tertiaryLabelColor
|
||||||
}
|
}
|
||||||
|
|
||||||
func populateCell(with proxy: ValetProxy) {
|
func populateCell(with proxy: ValetProxy) {
|
||||||
imageViewType.image = NSImage(named: "IconProxy")
|
imageViewType.image = NSImage.iconProxy
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,14 +34,13 @@ class DomainListPhpCell: NSTableCellView, DomainListCellProtocol {
|
|||||||
|
|
||||||
if site.isolatedPhpVersion != nil {
|
if site.isolatedPhpVersion != nil {
|
||||||
imageViewPhpVersionOK.isHidden = false
|
imageViewPhpVersionOK.isHidden = false
|
||||||
imageViewPhpVersionOK.image = NSImage(named: "Isolated")
|
imageViewPhpVersionOK.image = NSImage.isolated
|
||||||
imageViewPhpVersionOK.toolTip = "domain_list.tooltips.isolated".localized(site.servingPhpVersion)
|
imageViewPhpVersionOK.toolTip = "domain_list.tooltips.isolated".localized(site.servingPhpVersion)
|
||||||
} else {
|
} else {
|
||||||
imageViewPhpVersionOK.isHidden = (site.preferredPhpVersion == "???"
|
imageViewPhpVersionOK.isHidden = (site.preferredPhpVersion == "???"
|
||||||
|| !site.isCompatibleWithPreferredPhpVersion)
|
|| !site.isCompatibleWithPreferredPhpVersion)
|
||||||
imageViewPhpVersionOK.image = NSImage(named: "Checkmark")
|
imageViewPhpVersionOK.image = NSImage.checkmark
|
||||||
imageViewPhpVersionOK.toolTip = "domain_list.tooltips.checkmark".localized(site.preferredPhpVersion)
|
imageViewPhpVersionOK.toolTip = "domain_list.tooltips.checkmark".localized(site.preferredPhpVersion)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,6 +110,22 @@ extension DomainListVC {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@objc func toggleExtension(sender: ExtensionMenuItem) {
|
||||||
|
Task {
|
||||||
|
self.setUIBusy()
|
||||||
|
|
||||||
|
await sender.phpExtension?.toggle()
|
||||||
|
|
||||||
|
if Preferences.isEnabled(.autoServiceRestartAfterExtensionToggle) {
|
||||||
|
await Actions.restartPhpFpm()
|
||||||
|
}
|
||||||
|
|
||||||
|
reloadContextMenu()
|
||||||
|
|
||||||
|
self.setUINotBusy()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@objc func isolateSite(sender: PhpMenuItem) {
|
@objc func isolateSite(sender: PhpMenuItem) {
|
||||||
guard let site = selectedSite else {
|
guard let site = selectedSite else {
|
||||||
return
|
return
|
||||||
|
@ -42,7 +42,20 @@ extension DomainListVC {
|
|||||||
addDisabledIsolation(to: menu)
|
addDisabledIsolation(to: menu)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addSeparator(to: menu)
|
||||||
|
|
||||||
|
if let extensions = site.isolatedPhpVersion?.extensions ?? PhpEnvironments.phpInstall?.extensions,
|
||||||
|
let version = site.isolatedPhpVersion?.versionNumber.short ?? PhpEnvironments.phpInstall?.version.short {
|
||||||
|
menu.addItem(HeaderView.asMenuItem(text: "mi_detected_extensions".localized))
|
||||||
|
addMenuItemsForExtensions(
|
||||||
|
to: menu,
|
||||||
|
for: extensions,
|
||||||
|
version: version
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
menu.addItem(HeaderView.asMenuItem(text: "domain_list.actions".localized))
|
menu.addItem(HeaderView.asMenuItem(text: "domain_list.actions".localized))
|
||||||
|
|
||||||
addToggleSecure(to: menu, secured: site.secured)
|
addToggleSecure(to: menu, secured: site.secured)
|
||||||
addUnlink(to: menu, with: site)
|
addUnlink(to: menu, with: site)
|
||||||
|
|
||||||
@ -150,6 +163,28 @@ extension DomainListVC {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func addMenuItemsForExtensions(to menu: NSMenu, for extensions: [PhpExtension], version: String) {
|
||||||
|
var items: [NSMenuItem] = [
|
||||||
|
NSMenuItem(title: "domain_list.applies_to".localized(version))
|
||||||
|
]
|
||||||
|
|
||||||
|
for phpExtension in extensions {
|
||||||
|
let item = ExtensionMenuItem(
|
||||||
|
title: "\(phpExtension.name) (\(phpExtension.fileNameOnly))",
|
||||||
|
action: #selector(self.toggleExtension),
|
||||||
|
keyEquivalent: ""
|
||||||
|
)
|
||||||
|
|
||||||
|
item.state = phpExtension.enabled ? .on : .off
|
||||||
|
item.phpExtension = phpExtension
|
||||||
|
|
||||||
|
items.append(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
menu.addItem(NSMenuItem(title: "domain_list.extensions".localized, submenu: items))
|
||||||
|
menu.addItem(NSMenuItem.separator())
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Menu Items for Proxy
|
// MARK: - Menu Items for Proxy
|
||||||
|
|
||||||
private func addMenuItemsForProxy(_ proxy: ValetProxy) {
|
private func addMenuItemsForProxy(_ proxy: ValetProxy) {
|
||||||
|
@ -60,6 +60,8 @@ extension PhpExtensionManagerView {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let phpVersionManaged = self.manager.phpVersion
|
||||||
|
|
||||||
do {
|
do {
|
||||||
self.status.busy = true
|
self.status.busy = true
|
||||||
try await command.execute { progress in
|
try await command.execute { progress in
|
||||||
@ -70,7 +72,7 @@ extension PhpExtensionManagerView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.manager.loadExtensionData(for: self.manager.phpVersion)
|
self.manager.phpVersion = phpVersionManaged
|
||||||
self.status.busy = false
|
self.status.busy = false
|
||||||
} catch let error {
|
} catch let error {
|
||||||
let error = error as! BrewCommandError
|
let error = error as! BrewCommandError
|
||||||
|
@ -102,7 +102,7 @@
|
|||||||
|
|
||||||
"phpextman.list.status.external" = "Diese Erweiterung ist bereits über eine andere Quelle installiert und kann nicht verwaltet werden.";
|
"phpextman.list.status.external" = "Diese Erweiterung ist bereits über eine andere Quelle installiert und kann nicht verwaltet werden.";
|
||||||
"phpextman.list.status.installable" = "Diese Erweiterung kann installiert werden.";
|
"phpextman.list.status.installable" = "Diese Erweiterung kann installiert werden.";
|
||||||
"phpextman.list.status.dependent" = "Sie können diese nicht deinstallieren, bevor Sie **%@** deinstallieren.";
|
"phpextman.list.status.dependent" = "Sie können diese nicht deinstallieren, bevor Sie %@ deinstallieren.";
|
||||||
"phpextman.list.status.can_manage" = "Diese Erweiterung ist installiert und kann von PHP Monitor verwaltet werden.";
|
"phpextman.list.status.can_manage" = "Diese Erweiterung ist installiert und kann von PHP Monitor verwaltet werden.";
|
||||||
|
|
||||||
|
|
||||||
@ -238,6 +238,9 @@ Möglicherweise werden Sie während des Deinstallationsvorgangs nach Ihrem Passw
|
|||||||
"domain_list.columns.kind" = "Art";
|
"domain_list.columns.kind" = "Art";
|
||||||
"domain_list.columns.project_type" = "Projekttyp";
|
"domain_list.columns.project_type" = "Projekttyp";
|
||||||
|
|
||||||
|
"domain_list.extensions" = "Erweiterungen umschalten";
|
||||||
|
"domain_list.applies_to" = "Gilt für PHP %@";
|
||||||
|
|
||||||
// CHOOSE WHAT TO ADD
|
// CHOOSE WHAT TO ADD
|
||||||
|
|
||||||
"selection.title" = "Welche Art von Domain möchten Sie einrichten?";
|
"selection.title" = "Welche Art von Domain möchten Sie einrichten?";
|
||||||
@ -814,3 +817,11 @@ Bitte beachten Sie, dass einige Funktionen (unten ausgegraut) derzeit nicht verf
|
|||||||
"onboarding.tour.feature_unavailable" = "Diese Funktion ist derzeit nicht verfügbar und erfordert die Installation von Laravel Valet.";
|
"onboarding.tour.feature_unavailable" = "Diese Funktion ist derzeit nicht verfügbar und erfordert die Installation von Laravel Valet.";
|
||||||
"onboarding.tour.once" = "Sie sehen die Willkommenstour nur einmal. Sie können die Willkommenstour später über das Symbol in der Menüleiste (im Menü unter Erste Hilfe & Dienste) erneut öffnen.";
|
"onboarding.tour.once" = "Sie sehen die Willkommenstour nur einmal. Sie können die Willkommenstour später über das Symbol in der Menüleiste (im Menü unter Erste Hilfe & Dienste) erneut öffnen.";
|
||||||
"onboarding.tour.close" = "Tour beenden";
|
"onboarding.tour.close" = "Tour beenden";
|
||||||
|
|
||||||
|
// LANGUAGE CHOICE
|
||||||
|
|
||||||
|
"prefs.language" = "Sprache:";
|
||||||
|
"prefs.language_options_desc" = "Wählen Sie eine andere Sprache für die Verwendung mit PHP Monitor. Um diese Änderung vollständig anzuwenden, müssen Sie die App neu starten.";
|
||||||
|
|
||||||
|
"alert.language_changed.title" = "Sie sollten PHP Monitor neu starten!";
|
||||||
|
"alert.language_changed.subtitle" = "Sie haben soeben die Anzeigesprache von PHP Monitor geändert. Das Menü wird sofort die korrekte Sprache verwenden, aber Sie müssen die App möglicherweise neu starten, damit alle Texte in der App Ihre neue Sprachwahl widerspiegeln.";
|
||||||
|
@ -117,7 +117,7 @@
|
|||||||
|
|
||||||
"phpextman.list.status.external" = "This extension is already installed via another source, and cannot be managed.";
|
"phpextman.list.status.external" = "This extension is already installed via another source, and cannot be managed.";
|
||||||
"phpextman.list.status.installable" = "This extension can be installed.";
|
"phpextman.list.status.installable" = "This extension can be installed.";
|
||||||
"phpextman.list.status.dependent" = "You cannot uninstall this before uninstalling **%@**.";
|
"phpextman.list.status.dependent" = "You cannot uninstall this before uninstalling %@.";
|
||||||
"phpextman.list.status.can_manage" = "This extension is installed and can be managed by PHP Monitor.";
|
"phpextman.list.status.can_manage" = "This extension is installed and can be managed by PHP Monitor.";
|
||||||
|
|
||||||
// PHPMAN
|
// PHPMAN
|
||||||
@ -264,6 +264,9 @@ You may be asked for your password during the uninstallation process if file per
|
|||||||
"domain_list.columns.kind" = "Kind";
|
"domain_list.columns.kind" = "Kind";
|
||||||
"domain_list.columns.project_type" = "Project Type";
|
"domain_list.columns.project_type" = "Project Type";
|
||||||
|
|
||||||
|
"domain_list.extensions" = "Toggle Extensions";
|
||||||
|
"domain_list.applies_to" = "Applies to PHP %@";
|
||||||
|
|
||||||
// CHOOSE WHAT TO ADD
|
// CHOOSE WHAT TO ADD
|
||||||
|
|
||||||
"selection.title" = "What kind of domain would you like to set up?";
|
"selection.title" = "What kind of domain would you like to set up?";
|
||||||
@ -840,3 +843,11 @@ Please note that some features (greyed out below) are currently unavailable beca
|
|||||||
"onboarding.tour.feature_unavailable" = "This feature is currently unavailable and requires Laravel Valet to be installed.";
|
"onboarding.tour.feature_unavailable" = "This feature is currently unavailable and requires Laravel Valet to be installed.";
|
||||||
"onboarding.tour.once" = "You will only see the Welcome Tour once. You can re-open the Welcome Tour later via the menu bar icon (available in the menu, 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 (available in the menu, under First Aid & Services).";
|
||||||
"onboarding.tour.close" = "Close Tour";
|
"onboarding.tour.close" = "Close Tour";
|
||||||
|
|
||||||
|
// LANGUAGE CHOICE
|
||||||
|
|
||||||
|
"prefs.language" = "Language:";
|
||||||
|
"prefs.language_options_desc" = "Choose a different language to use with PHP Monitor. To fully apply this change, you must restart the app.";
|
||||||
|
|
||||||
|
"alert.language_changed.title" = "You must restart PHP Monitor!";
|
||||||
|
"alert.language_changed.subtitle" = "You just changed the display language of PHP Monitor. The menu will immediately use the correct language, but you may need to restart the app for all text throughout the app to reflect your new language choice.";
|
||||||
|
@ -117,7 +117,7 @@
|
|||||||
|
|
||||||
"phpextman.list.status.external" = "Cette extension est déjà installée via une autre source et ne peut pas être gérée.";
|
"phpextman.list.status.external" = "Cette extension est déjà installée via une autre source et ne peut pas être gérée.";
|
||||||
"phpextman.list.status.installable" = "Cette extension peut être installée.";
|
"phpextman.list.status.installable" = "Cette extension peut être installée.";
|
||||||
"phpextman.list.status.dependent" = "Vous ne pouvez pas désinstaller ceci avant de désinstaller **%@**.";
|
"phpextman.list.status.dependent" = "Vous ne pouvez pas désinstaller ceci avant de désinstaller %@.";
|
||||||
"phpextman.list.status.can_manage" = "Cette extension est installée et peut être gérée par PHP Monitor.";
|
"phpextman.list.status.can_manage" = "Cette extension est installée et peut être gérée par PHP Monitor.";
|
||||||
|
|
||||||
// PHPMAN
|
// PHPMAN
|
||||||
@ -252,6 +252,9 @@ Il se peut que vous deviez saisir votre mot de passe pendant le processus de dé
|
|||||||
"domain_list.columns.kind" = "Sorte";
|
"domain_list.columns.kind" = "Sorte";
|
||||||
"domain_list.columns.project_type" = "Type de Projet";
|
"domain_list.columns.project_type" = "Type de Projet";
|
||||||
|
|
||||||
|
"domain_list.extensions" = "Activer/désactiver les extensions";
|
||||||
|
"domain_list.applies_to" = "S'applique à PHP %@";
|
||||||
|
|
||||||
// CHOOSE WHAT TO ADD
|
// CHOOSE WHAT TO ADD
|
||||||
|
|
||||||
"selection.title" = "Quel type de domaine souhaitez-vous configurer ?";
|
"selection.title" = "Quel type de domaine souhaitez-vous configurer ?";
|
||||||
@ -825,3 +828,11 @@ Veuillez noter que certaines fonctionnalités (grisées ci-dessous) sont actuell
|
|||||||
"onboarding.tour.feature_unavailable" = "Cette fonctionnalité n'est actuellement pas disponible et nécessite l'installation de Laravel Valet.";
|
"onboarding.tour.feature_unavailable" = "Cette fonctionnalité n'est actuellement pas disponible et nécessite l'installation de Laravel Valet.";
|
||||||
"onboarding.tour.once" = "Vous ne verrez la visite de bienvenue qu'une seule fois. Vous pouvez rouvrir la visite de bienvenue ultérieurement via l'icône de la barre de menu (disponible dans le menu, sous Premiers Secours et Services).";
|
"onboarding.tour.once" = "Vous ne verrez la visite de bienvenue qu'une seule fois. Vous pouvez rouvrir la visite de bienvenue ultérieurement via l'icône de la barre de menu (disponible dans le menu, sous Premiers Secours et Services).";
|
||||||
"onboarding.tour.close" = "Fermer la Visite d'Accueil";
|
"onboarding.tour.close" = "Fermer la Visite d'Accueil";
|
||||||
|
|
||||||
|
// LANGUAGE CHOICE
|
||||||
|
|
||||||
|
"prefs.language" = "Langue :";
|
||||||
|
"prefs.language_options_desc" = "Choisissez une autre langue à utiliser avec PHP Monitor. Pour appliquer pleinement ce changement, vous devez redémarrer l'application.";
|
||||||
|
|
||||||
|
"alert.language_changed.title" = "Vous devriez redémarrer PHP Monitor !";
|
||||||
|
"alert.language_changed.subtitle" = "Vous venez de changer la langue d'affichage de PHP Monitor. Le menu utilisera immédiatement la bonne langue, mais vous devrez peut-être redémarrer l'application pour que tout le texte dans l'application reflète votre nouveau choix de langue.";
|
||||||
|
@ -103,7 +103,7 @@
|
|||||||
|
|
||||||
"phpextman.list.status.external" = "Deze extensie is al geïnstalleerd via een andere bron en kan niet worden beheerd.";
|
"phpextman.list.status.external" = "Deze extensie is al geïnstalleerd via een andere bron en kan niet worden beheerd.";
|
||||||
"phpextman.list.status.installable" = "Deze extensie kan worden geïnstalleerd.";
|
"phpextman.list.status.installable" = "Deze extensie kan worden geïnstalleerd.";
|
||||||
"phpextman.list.status.dependent" = "U kunt dit niet deïnstalleren voordat u **%@** deïnstalleert.";
|
"phpextman.list.status.dependent" = "U kunt dit niet deïnstalleren voordat u %@ deïnstalleert.";
|
||||||
"phpextman.list.status.can_manage" = "Deze extensie is geïnstalleerd en kan worden beheerd door PHP Monitor.";
|
"phpextman.list.status.can_manage" = "Deze extensie is geïnstalleerd en kan worden beheerd door PHP Monitor.";
|
||||||
|
|
||||||
// PHPMAN
|
// PHPMAN
|
||||||
@ -238,6 +238,9 @@ Tijdens het verwijderingsproces kan u worden gevraagd om uw wachtwoord indien de
|
|||||||
"domain_list.columns.kind" = "Type";
|
"domain_list.columns.kind" = "Type";
|
||||||
"domain_list.columns.project_type" = "Projecttype";
|
"domain_list.columns.project_type" = "Projecttype";
|
||||||
|
|
||||||
|
"domain_list.extensions" = "Extensies in-/uitschakelen";
|
||||||
|
"domain_list.applies_to" = "Van toepassing op PHP %@";
|
||||||
|
|
||||||
// CHOOSE WHAT TO ADD
|
// CHOOSE WHAT TO ADD
|
||||||
|
|
||||||
"selection.title" = "Wat voor soort domein wilt u instellen?";
|
"selection.title" = "Wat voor soort domein wilt u instellen?";
|
||||||
@ -812,3 +815,11 @@ Houd er rekening mee dat sommige functies (hieronder grijs weergegeven) momentee
|
|||||||
"onboarding.tour.feature_unavailable" = "Deze functie is momenteel niet beschikbaar en vereist de installatie van Laravel Valet.";
|
"onboarding.tour.feature_unavailable" = "Deze functie is momenteel niet beschikbaar en vereist de installatie van Laravel Valet.";
|
||||||
"onboarding.tour.once" = "U zult de Welkomsttour slechts één keer zien. U kunt de Welkomsttour later opnieuw openen via het menubalkpictogram (beschikbaar in het menu onder First Aid & Services).";
|
"onboarding.tour.once" = "U zult de Welkomsttour slechts één keer zien. U kunt de Welkomsttour later opnieuw openen via het menubalkpictogram (beschikbaar in het menu onder First Aid & Services).";
|
||||||
"onboarding.tour.close" = "Tour sluiten";
|
"onboarding.tour.close" = "Tour sluiten";
|
||||||
|
|
||||||
|
// LANGUAGE CHOICE
|
||||||
|
|
||||||
|
"prefs.language" = "Taal:";
|
||||||
|
"prefs.language_options_desc" = "Kies een andere taal om te gebruiken met PHP Monitor. Om deze wijziging volledig toe te passen, moet u de app herstarten.";
|
||||||
|
|
||||||
|
"alert.language_changed.title" = "U moet PHP Monitor herstarten!";
|
||||||
|
"alert.language_changed.subtitle" = "U heeft zojuist de weergavetaal van PHP Monitor gewijzigd. Het menu zal onmiddellijk de juiste taal gebruiken, maar u moet mogelijk de app herstarten om overal de nieuwe taal te zien.";
|
||||||
|
@ -102,7 +102,7 @@
|
|||||||
|
|
||||||
"phpextman.list.status.external" = "Esta extensão já está instalada por outra fonte e não pode ser gerenciada.";
|
"phpextman.list.status.external" = "Esta extensão já está instalada por outra fonte e não pode ser gerenciada.";
|
||||||
"phpextman.list.status.installable" = "Esta extensão pode ser instalada.";
|
"phpextman.list.status.installable" = "Esta extensão pode ser instalada.";
|
||||||
"phpextman.list.status.dependent" = "Você não pode desinstalar isso antes de desinstalar **%@**.";
|
"phpextman.list.status.dependent" = "Você não pode desinstalar isso antes de desinstalar %@.";
|
||||||
"phpextman.list.status.can_manage" = "Esta extensão está instalada e pode ser gerenciada pelo PHP Monitor.";
|
"phpextman.list.status.can_manage" = "Esta extensão está instalada e pode ser gerenciada pelo PHP Monitor.";
|
||||||
|
|
||||||
// PHPMAN
|
// PHPMAN
|
||||||
@ -237,6 +237,10 @@ Poderá ser-lhe solicitada a sua palavra-passe durante o processo de desinstala
|
|||||||
"domain_list.columns.kind" = "Tipo";
|
"domain_list.columns.kind" = "Tipo";
|
||||||
"domain_list.columns.project_type" = "Tipo de projeto";
|
"domain_list.columns.project_type" = "Tipo de projeto";
|
||||||
|
|
||||||
|
"domain_list.extensions" = "Alternar Extensões";
|
||||||
|
"domain_list.applies_to" = "Aplica-se ao PHP %@";
|
||||||
|
|
||||||
|
|
||||||
// CHOOSE WHAT TO ADD
|
// CHOOSE WHAT TO ADD
|
||||||
|
|
||||||
"selection.title" = "Que tipo de domínio pretende configurar?";
|
"selection.title" = "Que tipo de domínio pretende configurar?";
|
||||||
@ -809,3 +813,11 @@ Tenha em conta que algumas funcionalidades (esmaecidos abaixo) estão indisponí
|
|||||||
"onboarding.tour.feature_unavailable" = "Esta funcionalidade não está disponível de momento e requer a instalação do Laravel Valet.";
|
"onboarding.tour.feature_unavailable" = "Esta funcionalidade não está disponível de momento e requer a instalação do Laravel Valet.";
|
||||||
"onboarding.tour.once" = "Apenas irá ver este 'Boas-vindas' uma vez. Pode visualiza-lo mais tarde através da barra de menum em 'Primeiros Socorros e Serviços'.";
|
"onboarding.tour.once" = "Apenas irá ver este 'Boas-vindas' uma vez. Pode visualiza-lo mais tarde através da barra de menum em 'Primeiros Socorros e Serviços'.";
|
||||||
"onboarding.tour.close" = "Fechar";
|
"onboarding.tour.close" = "Fechar";
|
||||||
|
|
||||||
|
// LANGUAGE CHOICE
|
||||||
|
|
||||||
|
"prefs.language" = "Idioma:";
|
||||||
|
"prefs.language_options_desc" = "Escolha um idioma diferente para usar com o PHP Monitor. Para aplicar completamente esta mudança, deve reiniciar a aplicação.";
|
||||||
|
|
||||||
|
"alert.language_changed.title" = "Deve reiniciar o PHP Monitor!";
|
||||||
|
"alert.language_changed.subtitle" = "Acabou de mudar o idioma de exibição do PHP Monitor. O menu usará imediatamente a língua correta, mas pode ser necessário reiniciar a aplicação para que todo o texto na aplicação reflita a sua nova escolha de idioma.";
|
||||||
|
@ -102,7 +102,7 @@
|
|||||||
|
|
||||||
"phpextman.list.status.external" = "Tiện ích mở rộng này đã được cài đặt thông qua một nguồn khác và không thể được quản lý.";
|
"phpextman.list.status.external" = "Tiện ích mở rộng này đã được cài đặt thông qua một nguồn khác và không thể được quản lý.";
|
||||||
"phpextman.list.status.installable" = "Tiện ích mở rộng này có thể được cài đặt.";
|
"phpextman.list.status.installable" = "Tiện ích mở rộng này có thể được cài đặt.";
|
||||||
"phpextman.list.status.dependent" = "Bạn không thể gỡ cài đặt điều này trước khi gỡ cài đặt **%@**.";
|
"phpextman.list.status.dependent" = "Bạn không thể gỡ cài đặt điều này trước khi gỡ cài đặt %@.";
|
||||||
"phpextman.list.status.can_manage" = "Tiện ích mở rộng này đã được cài đặt và có thể được quản lý bởi PHP Monitor.";
|
"phpextman.list.status.can_manage" = "Tiện ích mở rộng này đã được cài đặt và có thể được quản lý bởi PHP Monitor.";
|
||||||
|
|
||||||
// PHPMAN
|
// PHPMAN
|
||||||
@ -317,6 +317,9 @@ Bạn có thể được yêu cầu nhập mật khẩu của mình trong quá t
|
|||||||
"domain_list.columns.kind" = "Loại";
|
"domain_list.columns.kind" = "Loại";
|
||||||
"domain_list.columns.project_type" = "Loại dự án";
|
"domain_list.columns.project_type" = "Loại dự án";
|
||||||
|
|
||||||
|
"domain_list.extensions" = "Bật/tắt Tiện ích mở rộng";
|
||||||
|
"domain_list.applies_to" = "Áp dụng cho PHP %@";
|
||||||
|
|
||||||
// DRIVERS
|
// DRIVERS
|
||||||
|
|
||||||
"driver.not_detected" = "Khác";
|
"driver.not_detected" = "Khác";
|
||||||
@ -806,3 +809,11 @@ Vui lòng lưu ý rằng một số tính năng (xám bên dưới) hiện khôn
|
|||||||
"onboarding.tour.feature_unavailable" = "Tính năng này hiện không khả dụng và yêu cầu Laravel Valet được cài đặt.";
|
"onboarding.tour.feature_unavailable" = "Tính năng này hiện không khả dụng và yêu cầu Laravel Valet được cài đặt.";
|
||||||
"onboarding.tour.once" = "Bạn chỉ sẽ thấy Hướng Dẫn Chào Mừng một lần. Bạn có thể mở lại Hướng Dẫn Chào Mừng sau này qua biểu tượng thanh menu (có sẵn trong menu, ở dưới Cứu hộ và Các dịch vụ).";
|
"onboarding.tour.once" = "Bạn chỉ sẽ thấy Hướng Dẫn Chào Mừng một lần. Bạn có thể mở lại Hướng Dẫn Chào Mừng sau này qua biểu tượng thanh menu (có sẵn trong menu, ở dưới Cứu hộ và Các dịch vụ).";
|
||||||
"onboarding.tour.close" = "Đóng Tour";
|
"onboarding.tour.close" = "Đóng Tour";
|
||||||
|
|
||||||
|
// LANGUAGE CHOICE
|
||||||
|
|
||||||
|
"prefs.language" = "Ngôn ngữ:";
|
||||||
|
"prefs.language_options_desc" = "Chọn một ngôn ngữ khác để sử dụng với PHP Monitor. Để áp dụng hoàn toàn thay đổi này, bạn phải khởi động lại ứng dụng.";
|
||||||
|
|
||||||
|
"alert.language_changed.title" = "Bạn nên khởi động lại PHP Monitor!";
|
||||||
|
"alert.language_changed.subtitle" = "Bạn vừa thay đổi ngôn ngữ hiển thị của PHP Monitor. Menu sẽ ngay lập tức sử dụng ngôn ngữ đúng, nhưng bạn có thể cần phải khởi động lại ứng dụng để toàn bộ văn bản trong ứng dụng phản ánh sự lựa chọn ngôn ngữ mới của bạn.";
|
||||||
|
@ -181,9 +181,6 @@ class TestableConfigurations {
|
|||||||
"/opt/homebrew/bin/php -r echo ini_get('memory_limit');": "512M",
|
"/opt/homebrew/bin/php -r echo ini_get('memory_limit');": "512M",
|
||||||
"/opt/homebrew/bin/php -r echo ini_get('upload_max_filesize');": "512M",
|
"/opt/homebrew/bin/php -r echo ini_get('upload_max_filesize');": "512M",
|
||||||
"/opt/homebrew/bin/php -r echo ini_get('post_max_size');": "512M",
|
"/opt/homebrew/bin/php -r echo ini_get('post_max_size');": "512M",
|
||||||
"/opt/homebrew/opt/php@8.2/bin/php -v": "OK (no full output needed for testing)",
|
|
||||||
"/opt/homebrew/opt/php@8.1/bin/php -v": "OK (no full output needed for testing)",
|
|
||||||
"/opt/homebrew/opt/php@8.0/bin/php -v": "OK (no full output needed for testing)"
|
|
||||||
],
|
],
|
||||||
preferenceOverrides: [
|
preferenceOverrides: [
|
||||||
.automaticBackgroundUpdateCheck: false
|
.automaticBackgroundUpdateCheck: false
|
||||||
@ -191,7 +188,8 @@ class TestableConfigurations {
|
|||||||
phpVersions: [
|
phpVersions: [
|
||||||
VersionNumber(major: 8, minor: 2, patch: 6),
|
VersionNumber(major: 8, minor: 2, patch: 6),
|
||||||
VersionNumber(major: 8, minor: 1, patch: 0),
|
VersionNumber(major: 8, minor: 1, patch: 0),
|
||||||
VersionNumber(major: 8, minor: 0, patch: 0)
|
VersionNumber(major: 8, minor: 0, patch: 0),
|
||||||
|
VersionNumber(major: 7, minor: 4, patch: 33)
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -90,16 +90,17 @@ final class MainMenuTest: UITestCase {
|
|||||||
// Should display loader
|
// Should display loader
|
||||||
assertExists(app.staticTexts["phpman.busy.title".localized], 1)
|
assertExists(app.staticTexts["phpman.busy.title".localized], 1)
|
||||||
|
|
||||||
// After loading, should display PHP 8.2
|
// After loading, should display PHP 8.2 and PHP 8.3
|
||||||
assertExists(app.staticTexts["PHP 8.2"], 5)
|
assertExists(app.staticTexts["PHP 8.2"], 5)
|
||||||
|
assertExists(app.staticTexts["PHP 8.3"])
|
||||||
|
|
||||||
// Should also display pre-release version
|
// Should also display pre-release version
|
||||||
assertExists(app.staticTexts["PHP 8.3"])
|
assertExists(app.staticTexts["PHP 8.4"])
|
||||||
assertExists(app.staticTexts["phpman.version.prerelease".localized.uppercased()])
|
assertExists(app.staticTexts["phpman.version.prerelease".localized.uppercased()])
|
||||||
assertExists(app.staticTexts["phpman.version.available_for_installation".localized])
|
assertExists(app.staticTexts["phpman.version.available_for_installation".localized])
|
||||||
|
|
||||||
// But not PHP 8.4 (yet)
|
// But not PHP 8.5 (yet)
|
||||||
assertNotExists(app.staticTexts["PHP 8.4"])
|
assertNotExists(app.staticTexts["PHP 8.5"])
|
||||||
|
|
||||||
// Also, PHP 8.2 should have an update available
|
// Also, PHP 8.2 should have an update available
|
||||||
assertExists(app.staticTexts["phpman.version.has_update".localized(
|
assertExists(app.staticTexts["phpman.version.has_update".localized(
|
||||||
|
@ -32,10 +32,10 @@ final class ExtensionEnumeratorTest: XCTestCase {
|
|||||||
func testCanParseFormulaeBasedOnSyntax() throws {
|
func testCanParseFormulaeBasedOnSyntax() throws {
|
||||||
let formulae = BrewTapFormulae.from(tap: "shivammathur/homebrew-extensions")
|
let formulae = BrewTapFormulae.from(tap: "shivammathur/homebrew-extensions")
|
||||||
|
|
||||||
XCTAssertEqual(formulae["8.1"], [BrewPhpExtension(name: "xdebug", phpVersion: "8.1")])
|
XCTAssertEqual(formulae["8.1"], [BrewPhpExtension(path: "/", name: "xdebug", phpVersion: "8.1")])
|
||||||
XCTAssertEqual(formulae["8.2"], [BrewPhpExtension(name: "xdebug", phpVersion: "8.2")])
|
XCTAssertEqual(formulae["8.2"], [BrewPhpExtension(path: "/", name: "xdebug", phpVersion: "8.2")])
|
||||||
XCTAssertEqual(formulae["8.3"], [BrewPhpExtension(name: "xdebug", phpVersion: "8.3")])
|
XCTAssertEqual(formulae["8.3"], [BrewPhpExtension(path: "/", name: "xdebug", phpVersion: "8.3")])
|
||||||
XCTAssertEqual(formulae["8.4"], [BrewPhpExtension(name: "xdebug", phpVersion: "8.4")])
|
XCTAssertEqual(formulae["8.4"], [BrewPhpExtension(path: "/", name: "xdebug", phpVersion: "8.4")])
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,15 @@ class HomebrewUpgradableTest: XCTestCase {
|
|||||||
func test_upgradable_php_versions_can_be_parsed() async throws {
|
func test_upgradable_php_versions_can_be_parsed() async throws {
|
||||||
ActiveShell.useTestable([
|
ActiveShell.useTestable([
|
||||||
"/opt/homebrew/bin/brew update >/dev/null && /opt/homebrew/bin/brew outdated --json --formulae"
|
"/opt/homebrew/bin/brew update >/dev/null && /opt/homebrew/bin/brew outdated --json --formulae"
|
||||||
: .instant(try! String(contentsOf: Self.outdatedFileUrl))
|
: .instant(try! String(contentsOf: Self.outdatedFileUrl)),
|
||||||
|
"/opt/homebrew/bin/php --ini | grep -E -o '(/[^ ]+\\.ini)'"
|
||||||
|
: .instant("/opt/homebrew/etc/php/8.2/conf.d/php-memory-limits.ini"),
|
||||||
|
"/opt/homebrew/opt/php@8.1.16/bin/php --ini | grep -E -o '(/[^ ]+\\.ini)'"
|
||||||
|
: .instant("/opt/homebrew/etc/php/8.1/conf.d/php-memory-limits.ini"),
|
||||||
|
"/opt/homebrew/opt/php@8.2.3/bin/php --ini | grep -E -o '(/[^ ]+\\.ini)'"
|
||||||
|
: .instant("/opt/homebrew/etc/php/8.2/conf.d/php-memory-limits.ini"),
|
||||||
|
"/opt/homebrew/opt/php@7.4.11/bin/php --ini | grep -E -o '(/[^ ]+\\.ini)'"
|
||||||
|
: .instant("/opt/homebrew/etc/php/7.4/conf.d/php-memory-limits.ini")
|
||||||
])
|
])
|
||||||
|
|
||||||
let env = PhpEnvironments.shared
|
let env = PhpEnvironments.shared
|
||||||
|
Reference in New Issue
Block a user