1
0
mirror of https://github.com/nicoverbruggen/phpmon.git synced 2025-12-22 19:40:06 +01:00

New Features

* Differentiate between services running as root and current user
* Support for custom services (via config.json)
* Renamed "Restart All Services" to "Restart Valet Services"
* Use SwiftUI for Stats, Services and Header view
* Added Color extension for debugging (PAINT_PHPMON_SWIFTUI_VIEWS)
This commit is contained in:
2022-06-11 23:18:27 +02:00
parent 090440abc8
commit 30059353fe
19 changed files with 252 additions and 167 deletions

View File

@@ -152,8 +152,6 @@
C484437B2804BB560041A78A /* ValetProxyScanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = C484437A2804BB560041A78A /* ValetProxyScanner.swift */; }; C484437B2804BB560041A78A /* ValetProxyScanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = C484437A2804BB560041A78A /* ValetProxyScanner.swift */; };
C484437C2804BB560041A78A /* ValetProxyScanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = C484437A2804BB560041A78A /* ValetProxyScanner.swift */; }; C484437C2804BB560041A78A /* ValetProxyScanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = C484437A2804BB560041A78A /* ValetProxyScanner.swift */; };
C48D0C9325CC804200CC7490 /* XibLoadable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C48D0C9225CC804200CC7490 /* XibLoadable.swift */; }; C48D0C9325CC804200CC7490 /* XibLoadable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C48D0C9225CC804200CC7490 /* XibLoadable.swift */; };
C48D0C9625CC80B100CC7490 /* HeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C48D0C9525CC80B100CC7490 /* HeaderView.swift */; };
C48D0C9A25CC888B00CC7490 /* HeaderView.xib in Resources */ = {isa = PBXBuildFile; fileRef = C48D0C9925CC888B00CC7490 /* HeaderView.xib */; };
C48D6C70279CD2AC00F26D7E /* PhpVersionNumber.swift in Sources */ = {isa = PBXBuildFile; fileRef = C48D6C6F279CD2AC00F26D7E /* PhpVersionNumber.swift */; }; C48D6C70279CD2AC00F26D7E /* PhpVersionNumber.swift in Sources */ = {isa = PBXBuildFile; fileRef = C48D6C6F279CD2AC00F26D7E /* PhpVersionNumber.swift */; };
C48D6C71279CD2AC00F26D7E /* PhpVersionNumber.swift in Sources */ = {isa = PBXBuildFile; fileRef = C48D6C6F279CD2AC00F26D7E /* PhpVersionNumber.swift */; }; C48D6C71279CD2AC00F26D7E /* PhpVersionNumber.swift in Sources */ = {isa = PBXBuildFile; fileRef = C48D6C6F279CD2AC00F26D7E /* PhpVersionNumber.swift */; };
C48D6C75279CD3E400F26D7E /* PhpVersionNumberTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C48D6C73279CD3E400F26D7E /* PhpVersionNumberTest.swift */; }; C48D6C75279CD3E400F26D7E /* PhpVersionNumberTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C48D6C73279CD3E400F26D7E /* PhpVersionNumberTest.swift */; };
@@ -180,7 +178,7 @@
C4B585422770FE3900DA4FBE /* Shell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B5853C2770FE3900DA4FBE /* Shell.swift */; }; C4B585422770FE3900DA4FBE /* Shell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B5853C2770FE3900DA4FBE /* Shell.swift */; };
C4B585442770FE3900DA4FBE /* Command.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B5853D2770FE3900DA4FBE /* Command.swift */; }; C4B585442770FE3900DA4FBE /* Command.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B5853D2770FE3900DA4FBE /* Command.swift */; };
C4B585452770FE3900DA4FBE /* Command.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B5853D2770FE3900DA4FBE /* Command.swift */; }; C4B585452770FE3900DA4FBE /* Command.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B5853D2770FE3900DA4FBE /* Command.swift */; };
C4B6091A2853AAD300C95265 /* MiniHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B609192853AAD300C95265 /* MiniHeaderView.swift */; }; C4B6091A2853AAD300C95265 /* SectionHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B609192853AAD300C95265 /* SectionHeaderView.swift */; };
C4B6091D2853AB9700C95265 /* ServicesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B6091C2853AB9700C95265 /* ServicesView.swift */; }; C4B6091D2853AB9700C95265 /* ServicesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B6091C2853AB9700C95265 /* ServicesView.swift */; };
C4B97B75275CF08C003F3378 /* AppDelegate+MenuOutlets.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B97B74275CF08C003F3378 /* AppDelegate+MenuOutlets.swift */; }; C4B97B75275CF08C003F3378 /* AppDelegate+MenuOutlets.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B97B74275CF08C003F3378 /* AppDelegate+MenuOutlets.swift */; };
C4B97B76275CF08C003F3378 /* AppDelegate+MenuOutlets.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B97B74275CF08C003F3378 /* AppDelegate+MenuOutlets.swift */; }; C4B97B76275CF08C003F3378 /* AppDelegate+MenuOutlets.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B97B74275CF08C003F3378 /* AppDelegate+MenuOutlets.swift */; };
@@ -229,6 +227,8 @@
C4E0F7EE27BEBDA9007475F2 /* NSWindowExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4E0F7EC27BEBDA9007475F2 /* NSWindowExtension.swift */; }; C4E0F7EE27BEBDA9007475F2 /* NSWindowExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4E0F7EC27BEBDA9007475F2 /* NSWindowExtension.swift */; };
C4E4404627C56F4700D225E1 /* ValetSite.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4E4404527C56F4700D225E1 /* ValetSite.swift */; }; C4E4404627C56F4700D225E1 /* ValetSite.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4E4404527C56F4700D225E1 /* ValetSite.swift */; };
C4E4404727C56F4700D225E1 /* ValetSite.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4E4404527C56F4700D225E1 /* ValetSite.swift */; }; C4E4404727C56F4700D225E1 /* ValetSite.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4E4404527C56F4700D225E1 /* ValetSite.swift */; };
C4EB53E528551F9B006F9937 /* HeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4EB53E428551F9B006F9937 /* HeaderView.swift */; };
C4EB53E728553117006F9937 /* ArrayExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4EB53E628553117006F9937 /* ArrayExtension.swift */; };
C4EC1E73279DFCF40010F296 /* Events.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4EC1E72279DFCF40010F296 /* Events.swift */; }; C4EC1E73279DFCF40010F296 /* Events.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4EC1E72279DFCF40010F296 /* Events.swift */; };
C4EE188422D3386B00E126E5 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4EE188322D3386B00E126E5 /* Constants.swift */; }; C4EE188422D3386B00E126E5 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4EE188322D3386B00E126E5 /* Constants.swift */; };
C4EED88927A48778006D7272 /* InterAppHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4EED88827A48778006D7272 /* InterAppHandler.swift */; }; C4EED88927A48778006D7272 /* InterAppHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4EED88827A48778006D7272 /* InterAppHandler.swift */; };
@@ -255,7 +255,6 @@
C4F780BA25D80B62000DBC97 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41C1B3622B0097F00E7CF16 /* AppDelegate.swift */; }; C4F780BA25D80B62000DBC97 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41C1B3622B0097F00E7CF16 /* AppDelegate.swift */; };
C4F780BD25D80B65000DBC97 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4EE188322D3386B00E126E5 /* Constants.swift */; }; C4F780BD25D80B65000DBC97 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4EE188322D3386B00E126E5 /* Constants.swift */; };
C4F780C025D80B6E000DBC97 /* Startup.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D8016522B1584700C6DA1B /* Startup.swift */; }; C4F780C025D80B6E000DBC97 /* Startup.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D8016522B1584700C6DA1B /* Startup.swift */; };
C4F780C325D80B75000DBC97 /* HeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C48D0C9525CC80B100CC7490 /* HeaderView.swift */; };
C4F780C425D80B75000DBC97 /* MainMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4811D2922D70F9A00B5F6B3 /* MainMenu.swift */; }; C4F780C425D80B75000DBC97 /* MainMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4811D2922D70F9A00B5F6B3 /* MainMenu.swift */; };
C4F780C525D80B75000DBC97 /* MenuBarImageGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41C1B4822B00A9800E7CF16 /* MenuBarImageGenerator.swift */; }; C4F780C525D80B75000DBC97 /* MenuBarImageGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41C1B4822B00A9800E7CF16 /* MenuBarImageGenerator.swift */; };
C4F780C625D80B75000DBC97 /* XibLoadable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C48D0C9225CC804200CC7490 /* XibLoadable.swift */; }; C4F780C625D80B75000DBC97 /* XibLoadable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C48D0C9225CC804200CC7490 /* XibLoadable.swift */; };
@@ -378,8 +377,6 @@
C4811D2922D70F9A00B5F6B3 /* MainMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainMenu.swift; sourceTree = "<group>"; }; C4811D2922D70F9A00B5F6B3 /* MainMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainMenu.swift; sourceTree = "<group>"; };
C484437A2804BB560041A78A /* ValetProxyScanner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValetProxyScanner.swift; sourceTree = "<group>"; }; C484437A2804BB560041A78A /* ValetProxyScanner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValetProxyScanner.swift; sourceTree = "<group>"; };
C48D0C9225CC804200CC7490 /* XibLoadable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XibLoadable.swift; sourceTree = "<group>"; }; C48D0C9225CC804200CC7490 /* XibLoadable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XibLoadable.swift; sourceTree = "<group>"; };
C48D0C9525CC80B100CC7490 /* HeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeaderView.swift; sourceTree = "<group>"; };
C48D0C9925CC888B00CC7490 /* HeaderView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = HeaderView.xib; sourceTree = "<group>"; };
C48D6C6F279CD2AC00F26D7E /* PhpVersionNumber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpVersionNumber.swift; sourceTree = "<group>"; }; C48D6C6F279CD2AC00F26D7E /* PhpVersionNumber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpVersionNumber.swift; sourceTree = "<group>"; };
C48D6C73279CD3E400F26D7E /* PhpVersionNumberTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhpVersionNumberTest.swift; sourceTree = "<group>"; }; C48D6C73279CD3E400F26D7E /* PhpVersionNumberTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhpVersionNumberTest.swift; sourceTree = "<group>"; };
C4927F0A27B2DFC200C55AFD /* Errors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Errors.swift; sourceTree = "<group>"; }; C4927F0A27B2DFC200C55AFD /* Errors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Errors.swift; sourceTree = "<group>"; };
@@ -396,7 +393,7 @@
C4B5853B2770FE3900DA4FBE /* Paths.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Paths.swift; sourceTree = "<group>"; }; C4B5853B2770FE3900DA4FBE /* Paths.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Paths.swift; sourceTree = "<group>"; };
C4B5853C2770FE3900DA4FBE /* Shell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Shell.swift; sourceTree = "<group>"; }; C4B5853C2770FE3900DA4FBE /* Shell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Shell.swift; sourceTree = "<group>"; };
C4B5853D2770FE3900DA4FBE /* Command.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Command.swift; sourceTree = "<group>"; }; C4B5853D2770FE3900DA4FBE /* Command.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Command.swift; sourceTree = "<group>"; };
C4B609192853AAD300C95265 /* MiniHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MiniHeaderView.swift; sourceTree = "<group>"; }; C4B609192853AAD300C95265 /* SectionHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectionHeaderView.swift; sourceTree = "<group>"; };
C4B6091C2853AB9700C95265 /* ServicesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServicesView.swift; sourceTree = "<group>"; }; C4B6091C2853AB9700C95265 /* ServicesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServicesView.swift; sourceTree = "<group>"; };
C4B97B74275CF08C003F3378 /* AppDelegate+MenuOutlets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppDelegate+MenuOutlets.swift"; sourceTree = "<group>"; }; C4B97B74275CF08C003F3378 /* AppDelegate+MenuOutlets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppDelegate+MenuOutlets.swift"; sourceTree = "<group>"; };
C4B97B77275CF1B5003F3378 /* App+ActivationPolicy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "App+ActivationPolicy.swift"; sourceTree = "<group>"; }; C4B97B77275CF1B5003F3378 /* App+ActivationPolicy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "App+ActivationPolicy.swift"; sourceTree = "<group>"; };
@@ -425,6 +422,8 @@
C4E4404527C56F4700D225E1 /* ValetSite.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValetSite.swift; sourceTree = "<group>"; }; C4E4404527C56F4700D225E1 /* ValetSite.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValetSite.swift; sourceTree = "<group>"; };
C4E713562570150F00007428 /* SECURITY.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = SECURITY.md; sourceTree = "<group>"; }; C4E713562570150F00007428 /* SECURITY.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = SECURITY.md; sourceTree = "<group>"; };
C4E713572570151400007428 /* docs */ = {isa = PBXFileReference; lastKnownFileType = folder; path = docs; sourceTree = "<group>"; }; C4E713572570151400007428 /* docs */ = {isa = PBXFileReference; lastKnownFileType = folder; path = docs; sourceTree = "<group>"; };
C4EB53E428551F9B006F9937 /* HeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeaderView.swift; sourceTree = "<group>"; };
C4EB53E628553117006F9937 /* ArrayExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArrayExtension.swift; sourceTree = "<group>"; };
C4EC1E72279DFCF40010F296 /* Events.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Events.swift; sourceTree = "<group>"; }; C4EC1E72279DFCF40010F296 /* Events.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Events.swift; sourceTree = "<group>"; };
C4EE188322D3386B00E126E5 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = "<group>"; }; C4EE188322D3386B00E126E5 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = "<group>"; };
C4EED88827A48778006D7272 /* InterAppHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InterAppHandler.swift; sourceTree = "<group>"; }; C4EED88827A48778006D7272 /* InterAppHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InterAppHandler.swift; sourceTree = "<group>"; };
@@ -767,8 +766,6 @@
C4F361602836BFD9003598CC /* MainMenu+Actions.swift */, C4F361602836BFD9003598CC /* MainMenu+Actions.swift */,
C47331A1247093B7009A0597 /* StatusMenu.swift */, C47331A1247093B7009A0597 /* StatusMenu.swift */,
C42800A928452AA10099C999 /* StatusMenu+Items.swift */, C42800A928452AA10099C999 /* StatusMenu+Items.swift */,
C48D0C9525CC80B100CC7490 /* HeaderView.swift */,
C48D0C9925CC888B00CC7490 /* HeaderView.xib */,
); );
path = Menu; path = Menu;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -873,7 +870,8 @@
children = ( children = (
C4B6091C2853AB9700C95265 /* ServicesView.swift */, C4B6091C2853AB9700C95265 /* ServicesView.swift */,
C4709CA128524B3400088BB8 /* StatsView.swift */, C4709CA128524B3400088BB8 /* StatsView.swift */,
C4B609192853AAD300C95265 /* MiniHeaderView.swift */, C4B609192853AAD300C95265 /* SectionHeaderView.swift */,
C4EB53E428551F9B006F9937 /* HeaderView.swift */,
); );
path = Menu; path = Menu;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -1049,6 +1047,7 @@
C48D0C9225CC804200CC7490 /* XibLoadable.swift */, C48D0C9225CC804200CC7490 /* XibLoadable.swift */,
C42759662627662800093CAE /* NSMenuExtension.swift */, C42759662627662800093CAE /* NSMenuExtension.swift */,
C4E0F7EC27BEBDA9007475F2 /* NSWindowExtension.swift */, C4E0F7EC27BEBDA9007475F2 /* NSWindowExtension.swift */,
C4EB53E628553117006F9937 /* ArrayExtension.swift */,
); );
path = Extensions; path = Extensions;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -1152,7 +1151,6 @@
C4068CA427B0780A00544CD5 /* CheckboxPreferenceView.xib in Resources */, C4068CA427B0780A00544CD5 /* CheckboxPreferenceView.xib in Resources */,
54FCFD2D276C8D67004CE748 /* HotkeyPreferenceView.xib in Resources */, 54FCFD2D276C8D67004CE748 /* HotkeyPreferenceView.xib in Resources */,
C405A4D024B9B9140062FAFA /* InternetAccessPolicy.strings in Resources */, C405A4D024B9B9140062FAFA /* InternetAccessPolicy.strings in Resources */,
C48D0C9A25CC888B00CC7490 /* HeaderView.xib in Resources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@@ -1215,6 +1213,7 @@
C4F8C0A422D4F12C002EFE61 /* DateExtension.swift in Sources */, C4F8C0A422D4F12C002EFE61 /* DateExtension.swift in Sources */,
C4AF9F7A2754499000D44ED0 /* Valet.swift in Sources */, C4AF9F7A2754499000D44ED0 /* Valet.swift in Sources */,
C4C0E8EA27F88B80002D32A9 /* ValetProxy+Fake.swift in Sources */, C4C0E8EA27F88B80002D32A9 /* ValetProxy+Fake.swift in Sources */,
C4EB53E728553117006F9937 /* ArrayExtension.swift in Sources */,
5420395926135DC100FB00FA /* PrefsVC.swift in Sources */, 5420395926135DC100FB00FA /* PrefsVC.swift in Sources */,
C43603A0275E67610028EFC6 /* AppDelegate+Notifications.swift in Sources */, C43603A0275E67610028EFC6 /* AppDelegate+Notifications.swift in Sources */,
5489625828312FAD004F647A /* CreatedFromFile.swift in Sources */, 5489625828312FAD004F647A /* CreatedFromFile.swift in Sources */,
@@ -1234,13 +1233,14 @@
C4C0E8DF27F88AEB002D32A9 /* FakeSiteScanner.swift in Sources */, C4C0E8DF27F88AEB002D32A9 /* FakeSiteScanner.swift in Sources */,
C44264BE2850B86C007400F1 /* SwiftUIHelper.swift in Sources */, C44264BE2850B86C007400F1 /* SwiftUIHelper.swift in Sources */,
C4F2E4372752F0870020E974 /* HomebrewDiagnostics.swift in Sources */, C4F2E4372752F0870020E974 /* HomebrewDiagnostics.swift in Sources */,
C4EB53E528551F9B006F9937 /* HeaderView.swift in Sources */,
C40FE737282ABA4F00A302C2 /* AppVersion.swift in Sources */, C40FE737282ABA4F00A302C2 /* AppVersion.swift in Sources */,
C4CCBA6C275C567B008C7055 /* PMWindowController.swift in Sources */, C4CCBA6C275C567B008C7055 /* PMWindowController.swift in Sources */,
C4B585442770FE3900DA4FBE /* Command.swift in Sources */, C4B585442770FE3900DA4FBE /* Command.swift in Sources */,
C44067F527E2582B0045BD4E /* DomainListNameCell.swift in Sources */, C44067F527E2582B0045BD4E /* DomainListNameCell.swift in Sources */,
C40C5C9C2846A40600E28255 /* Preset.swift in Sources */, C40C5C9C2846A40600E28255 /* Preset.swift in Sources */,
C41CD0292628D8EE0065BBED /* GlobalKeybindPreference.swift in Sources */, C41CD0292628D8EE0065BBED /* GlobalKeybindPreference.swift in Sources */,
C4B6091A2853AAD300C95265 /* MiniHeaderView.swift in Sources */, C4B6091A2853AAD300C95265 /* SectionHeaderView.swift in Sources */,
C44067F727E258410045BD4E /* DomainListPhpCell.swift in Sources */, C44067F727E258410045BD4E /* DomainListPhpCell.swift in Sources */,
C42800AA28452AA10099C999 /* StatusMenu+Items.swift in Sources */, C42800AA28452AA10099C999 /* StatusMenu+Items.swift in Sources */,
C415D3B72770F294005EF286 /* Actions.swift in Sources */, C415D3B72770F294005EF286 /* Actions.swift in Sources */,
@@ -1297,7 +1297,6 @@
C40C7F1E2772136000DDDCDC /* PhpEnv.swift in Sources */, C40C7F1E2772136000DDDCDC /* PhpEnv.swift in Sources */,
C476FF9822B0DD830098105B /* Alert.swift in Sources */, C476FF9822B0DD830098105B /* Alert.swift in Sources */,
C474B00624C0E98C00066A22 /* LocalNotification.swift in Sources */, C474B00624C0E98C00066A22 /* LocalNotification.swift in Sources */,
C48D0C9625CC80B100CC7490 /* HeaderView.swift in Sources */,
C4D5CFCA27E0F9CD00035329 /* NginxConfigurationFile.swift in Sources */, C4D5CFCA27E0F9CD00035329 /* NginxConfigurationFile.swift in Sources */,
C4CE3BBA27B31F670086CA49 /* ComposerWindow.swift in Sources */, C4CE3BBA27B31F670086CA49 /* ComposerWindow.swift in Sources */,
C4D9ADC8277611A0007277F4 /* InternalSwitcher.swift in Sources */, C4D9ADC8277611A0007277F4 /* InternalSwitcher.swift in Sources */,
@@ -1410,7 +1409,6 @@
C4998F0B2617633900B2526E /* PrefsWC.swift in Sources */, C4998F0B2617633900B2526E /* PrefsWC.swift in Sources */,
C4F2E43B27530F750020E974 /* PhpInstallation.swift in Sources */, C4F2E43B27530F750020E974 /* PhpInstallation.swift in Sources */,
C4F780BD25D80B65000DBC97 /* Constants.swift in Sources */, C4F780BD25D80B65000DBC97 /* Constants.swift in Sources */,
C4F780C325D80B75000DBC97 /* HeaderView.swift in Sources */,
C44C198E276E3A1C0072762D /* ProgressWindow.swift in Sources */, C44C198E276E3A1C0072762D /* ProgressWindow.swift in Sources */,
C415938027A1B54F00D2E1B7 /* PhpFrameworks.swift in Sources */, C415938027A1B54F00D2E1B7 /* PhpFrameworks.swift in Sources */,
C4D9ADC9277611A0007277F4 /* InternalSwitcher.swift in Sources */, C4D9ADC9277611A0007277F4 /* InternalSwitcher.swift in Sources */,
@@ -1599,7 +1597,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 = 810; CURRENT_PROJECT_VERSION = 900;
DEBUG = YES; DEBUG = YES;
DEVELOPMENT_TEAM = 8M54J5J787; DEVELOPMENT_TEAM = 8M54J5J787;
ENABLE_HARDENED_RUNTIME = YES; ENABLE_HARDENED_RUNTIME = YES;
@@ -1609,7 +1607,7 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 11.0; MACOSX_DEPLOYMENT_TARGET = 11.0;
MARKETING_VERSION = "5.4-dev"; MARKETING_VERSION = "5.5-dev";
PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon; PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
@@ -1626,7 +1624,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 = 810; CURRENT_PROJECT_VERSION = 900;
DEBUG = NO; DEBUG = NO;
DEVELOPMENT_TEAM = 8M54J5J787; DEVELOPMENT_TEAM = 8M54J5J787;
ENABLE_HARDENED_RUNTIME = YES; ENABLE_HARDENED_RUNTIME = YES;
@@ -1636,7 +1634,7 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 11.0; MACOSX_DEPLOYMENT_TARGET = 11.0;
MARKETING_VERSION = "5.4-dev"; MARKETING_VERSION = "5.5-dev";
PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon; PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";

View File

@@ -69,8 +69,8 @@
</CommandLineArguments> </CommandLineArguments>
<EnvironmentVariables> <EnvironmentVariables>
<EnvironmentVariable <EnvironmentVariable
key = "PHPMON_MARKETING_MODE" key = "PAINT_PHPMON_SWIFTUI_VIEWS"
value = "YES" value = ""
isEnabled = "NO"> isEnabled = "NO">
</EnvironmentVariable> </EnvironmentVariable>
</EnvironmentVariables> </EnvironmentVariables>

View File

@@ -24,7 +24,7 @@ class Actions {
brew("services restart dnsmasq", sudo: true) brew("services restart dnsmasq", sudo: true)
} }
public static func stopAllServices() { public static func stopValetServices() {
brew("services stop \(PhpEnv.phpInstall.formula)", sudo: true) brew("services stop \(PhpEnv.phpInstall.formula)", sudo: true)
brew("services stop nginx", sudo: true) brew("services stop nginx", sudo: true)
brew("services stop dnsmasq", sudo: true) brew("services stop dnsmasq", sudo: true)

View File

@@ -0,0 +1,24 @@
//
// ArrayExtension.swift
// PHP Monitor
//
// Created by Nico Verbruggen on 11/06/2022.
// Copyright © 2022 Nico Verbruggen. All rights reserved.
//
import Foundation
extension Array {
/**
Sourced from Stack Overflow
https://stackoverflow.com/a/33540708
*/
func chunked(by distance: Int) -> [[Element]] {
let indicesSequence = stride(from: startIndex, to: endIndex, by: distance)
let array: [[Element]] = indicesSequence.map {
let newIndex = $0.advanced(by: distance) > endIndex ? endIndex : $0.advanced(by: distance)
return Array(self[$0 ..< newIndex])
}
return array
}
}

View File

@@ -19,25 +19,6 @@ struct HomebrewService: Decodable, Equatable {
let log_path: String? let log_path: String?
let error_log_path: String? let error_log_path: String?
public static func loadAll(
filter: [String] = [PhpEnv.phpInstall.formula, "nginx", "dnsmasq"],
completion: @escaping ([HomebrewService]) -> Void
) {
DispatchQueue.global(qos: .background).async {
let data = Shell
.pipe("sudo \(Paths.brew) services info --all --json", requiresPath: true)
.data(using: .utf8)!
let services = try! JSONDecoder()
.decode([HomebrewService].self, from: data)
.filter({ return filter.contains($0.name) })
DispatchQueue.main.async {
completion(services)
}
}
}
/** /**
Dummy data for preview purposes. Dummy data for preview purposes.
*/ */

View File

@@ -26,10 +26,10 @@ class InterApp {
DomainListVC.show() DomainListVC.show()
}), }),
InterApp.Action(command: "services/stop", action: { _ in InterApp.Action(command: "services/stop", action: { _ in
MainMenu.shared.stopAllServices() MainMenu.shared.stopValetServices()
}), }),
InterApp.Action(command: "services/restart/all", action: { _ in InterApp.Action(command: "services/restart/all", action: { _ in
MainMenu.shared.restartAllServices() MainMenu.shared.restartValetServices()
}), }),
InterApp.Action(command: "services/restart/nginx", action: { _ in InterApp.Action(command: "services/restart/nginx", action: { _ in
MainMenu.shared.restartNginx() MainMenu.shared.restartNginx()

View File

@@ -13,14 +13,55 @@ class ServicesManager: ObservableObject {
static var shared = ServicesManager() static var shared = ServicesManager()
@Published var services: [String: HomebrewService] = [:] @Published var rootServices: [String: HomebrewService] = [:]
@Published var userServices: [String: HomebrewService] = [:]
public static func loadHomebrewServices() {
let rootServiceNames = [
PhpEnv.phpInstall.formula,
"nginx",
"dnsmasq"
]
DispatchQueue.global(qos: .background).async {
let data = Shell
.pipe("sudo \(Paths.brew) services info --all --json", requiresPath: true)
.data(using: .utf8)!
let services = try! JSONDecoder()
.decode([HomebrewService].self, from: data)
.filter({ return rootServiceNames.contains($0.name) })
DispatchQueue.main.async {
ServicesManager.shared.rootServices = Dictionary(
uniqueKeysWithValues: services.map { ($0.name, $0) }
)
}
}
guard let userServiceNames = Preferences.custom.services else {
return
}
DispatchQueue.global(qos: .background).async {
let data = Shell
.pipe("\(Paths.brew) services info --all --json", requiresPath: true)
.data(using: .utf8)!
let services = try! JSONDecoder()
.decode([HomebrewService].self, from: data)
.filter({ return userServiceNames.contains($0.name) })
DispatchQueue.main.async {
ServicesManager.shared.userServices = Dictionary(
uniqueKeysWithValues: services.map { ($0.name, $0) }
)
}
}
}
func loadData() { func loadData() {
HomebrewService.loadAll { services in Self.loadHomebrewServices()
self.services = Dictionary(
uniqueKeysWithValues: services.map { ($0.name, $0) }
)
}
} }
/** /**
@@ -29,7 +70,7 @@ class ServicesManager: ObservableObject {
func withDummyServices(_ services: [String: Bool]) -> Self { func withDummyServices(_ services: [String: Bool]) -> Self {
for (service, enabled) in services { for (service, enabled) in services {
let item = HomebrewService.dummy(named: service, enabled: enabled) let item = HomebrewService.dummy(named: service, enabled: enabled)
self.services[service] = item self.rootServices[service] = item
} }
return self return self

View File

@@ -1,36 +0,0 @@
//
// HeaderView.swift
// PHP Monitor
//
// Created by Nico Verbruggen on 04/02/2021.
// Copyright © 2022 Nico Verbruggen. All rights reserved.
//
import Foundation
import Cocoa
class HeaderView: NSView, XibLoadable {
@IBOutlet weak var textField: NSTextField!
static func asMenuItem(
text: String,
width: Int? = nil
) -> NSMenuItem {
let view = Self.createFromXib()!
view.autoresizingMask = [.width, .height]
view.textField.stringValue = text.uppercased()
view.textField.sizeToFit()
view.setFrameSize(CGSize(width: view.textField.frame.width + 40, height: view.frame.height))
let item = NSMenuItem()
item.view = view
item.target = self
return item
}
}

View File

@@ -1,35 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="19529" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="19529"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner"/>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<customView id="c22-O7-iKe" customClass="HeaderView" customModule="PHP_Monitor" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="270" height="24"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="ddg-VQ-cOT">
<rect key="frame" x="12" y="5" width="113" height="15"/>
<textFieldCell key="cell" lineBreakMode="clipping" alignment="left" title="ACTIVE SERVICES" id="NHz-MZ-8FK">
<font key="font" metaFont="systemBold" size="12"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<constraints>
<constraint firstItem="ddg-VQ-cOT" firstAttribute="centerY" secondItem="c22-O7-iKe" secondAttribute="centerY" id="n4Z-WN-RIh"/>
<constraint firstItem="ddg-VQ-cOT" firstAttribute="leading" secondItem="c22-O7-iKe" secondAttribute="leading" constant="14" id="yuW-pb-GQJ"/>
</constraints>
<connections>
<outlet property="textField" destination="ddg-VQ-cOT" id="aaQ-Xb-o2X"/>
</connections>
<point key="canvasLocation" x="177" y="105"/>
</customView>
</objects>
</document>

View File

@@ -47,7 +47,7 @@ extension MainMenu {
} }
} }
@objc func restartAllServices() { @objc func restartValetServices() {
asyncExecution { asyncExecution {
Actions.restartDnsMasq() Actions.restartDnsMasq()
Actions.restartPhpFpm() Actions.restartPhpFpm()
@@ -63,9 +63,9 @@ extension MainMenu {
} }
} }
@objc func stopAllServices() { @objc func stopValetServices() {
asyncExecution { asyncExecution {
Actions.stopAllServices() Actions.stopValetServices()
} success: { } success: {
DispatchQueue.main.async { DispatchQueue.main.async {
LocalNotification.send( LocalNotification.send(

View File

@@ -65,7 +65,12 @@ extension StatusMenu {
} }
func addPresetsMenuItem() { func addPresetsMenuItem() {
if Preferences.custom.presets.isEmpty { guard let presets = Preferences.custom.presets else {
addEmptyPresetHelp()
return
}
if presets.isEmpty {
addEmptyPresetHelp() addEmptyPresetHelp()
return return
} }
@@ -102,7 +107,7 @@ extension StatusMenu {
presetsMenu.addItem(NSMenuItem.separator()) presetsMenu.addItem(NSMenuItem.separator())
presetsMenu.addItem(HeaderView.asMenuItem(text: "mi_apply_presets_title".localized)) presetsMenu.addItem(HeaderView.asMenuItem(text: "mi_apply_presets_title".localized))
for preset in Preferences.custom.presets { for preset in Preferences.custom.presets! {
let presetMenuItem = PresetMenuItem( let presetMenuItem = PresetMenuItem(
title: preset.getMenuItemText(), title: preset.getMenuItemText(),
action: #selector(MainMenu.togglePreset(sender:)), action: #selector(MainMenu.togglePreset(sender:)),
@@ -132,7 +137,7 @@ extension StatusMenu {
presetsMenu.addItem(NSMenuItem.separator()) presetsMenu.addItem(NSMenuItem.separator())
presetsMenu.addItem(NSMenuItem( presetsMenu.addItem(NSMenuItem(
title: "mi_profiles_loaded".localized( title: "mi_profiles_loaded".localized(
Preferences.custom.presets.count Preferences.custom.presets!.count
), ),
action: nil, keyEquivalent: "") action: nil, keyEquivalent: "")
) )
@@ -219,12 +224,12 @@ extension StatusMenu {
action: #selector(MainMenu.restartNginx), keyEquivalent: "n") action: #selector(MainMenu.restartNginx), keyEquivalent: "n")
) )
servicesMenu.addItem( servicesMenu.addItem(
NSMenuItem(title: "mi_restart_all_services".localized, NSMenuItem(title: "mi_restart_valet_services".localized,
action: #selector(MainMenu.restartAllServices), keyEquivalent: "s") action: #selector(MainMenu.restartValetServices), keyEquivalent: "s")
) )
servicesMenu.addItem( servicesMenu.addItem(
NSMenuItem(title: "mi_stop_all_services".localized, NSMenuItem(title: "mi_stop_valet_services".localized,
action: #selector(MainMenu.stopAllServices), keyEquivalent: "s"), action: #selector(MainMenu.stopValetServices), keyEquivalent: "s"),
withKeyModifier: [.command, .shift] withKeyModifier: [.command, .shift]
) )

View File

@@ -10,10 +10,20 @@ import Foundation
struct CustomPrefs: Decodable { struct CustomPrefs: Decodable {
let scanApps: [String] let scanApps: [String]
let presets: [Preset] let presets: [Preset]?
let services: [String]?
public func hasPresets() -> Bool {
return self.presets != nil && !self.presets!.isEmpty
}
public func hasServices() -> Bool {
return self.services != nil && !self.services!.isEmpty
}
private enum CodingKeys: String, CodingKey { private enum CodingKeys: String, CodingKey {
case scanApps = "scan_apps" case scanApps = "scan_apps"
case presets = "presets" case presets = "presets"
case services = "services"
} }
} }

View File

@@ -65,7 +65,7 @@ class Preferences {
public init() { public init() {
Preferences.handleFirstTimeLaunch() Preferences.handleFirstTimeLaunch()
cachedPreferences = Self.cache() cachedPreferences = Self.cache()
customPreferences = CustomPrefs(scanApps: [], presets: []) customPreferences = CustomPrefs(scanApps: [], presets: [], services: [])
loadCustomPreferences() loadCustomPreferences()
} }
@@ -228,7 +228,14 @@ class Preferences {
) )
Log.info("The ~/.config/phpmon/config.json file was successfully parsed.") Log.info("The ~/.config/phpmon/config.json file was successfully parsed.")
Log.info("There are \(customPreferences.presets.count) custom presets.")
if customPreferences.hasPresets() {
Log.info("There are \(customPreferences.presets!.count) custom presets.")
}
if customPreferences.hasServices() {
Log.info("There are custom services: \(customPreferences.services!)")
}
} catch { } catch {
Log.warn("The ~/.config/phpmon/config.json file seems to be missing or malformed.") Log.warn("The ~/.config/phpmon/config.json file seems to be missing or malformed.")
} }

View File

@@ -7,8 +7,18 @@
// //
import Foundation import Foundation
import SwiftUI
var isRunningSwiftUIPreview: Bool { var isRunningSwiftUIPreview: Bool {
return ProcessInfo.processInfo return ProcessInfo.processInfo
.environment["XCODE_RUNNING_FOR_PREVIEWS"] != nil .environment["XCODE_RUNNING_FOR_PREVIEWS"] != nil
} }
extension Color {
public static var debug: Color = {
if ProcessInfo.processInfo.environment["PAINT_PHPMON_SWIFTUI_VIEWS"] != nil {
return Color.yellow
}
return Color.clear
}()
}

View File

@@ -0,0 +1,47 @@
//
// MiniHeaderView.swift
// PHP Monitor
//
// Created by Nico Verbruggen on 10/06/2022.
// Copyright © 2022 Nico Verbruggen. All rights reserved.
//
import SwiftUI
struct HeaderView: View {
@State var text: String
var body: some View {
Text(text.uppercased())
.font(.system(size: 12))
.fontWeight(.bold)
.foregroundColor(.secondary)
.multilineTextAlignment(.leading)
.padding(.leading, 14.0)
.frame(maxWidth: .infinity, alignment: .leading)
.background(Color.debug)
}
// MARK: - NSMenuItem
static func asMenuItem(
text: String,
width: Int? = nil
) -> NSMenuItem {
let view = NSHostingView(rootView: Self(text: text))
view.autoresizingMask = [.width, .height]
view.setFrameSize(CGSize(width: view.frame.width, height: 24))
let item = NSMenuItem()
item.view = view
return item
}
}
struct HeaderView_Previews: PreviewProvider {
static var previews: some View {
HeaderView(text: "Hello world")
.frame(width: 330.0)
}
}

View File

@@ -8,7 +8,8 @@
import SwiftUI import SwiftUI
struct MiniHeaderView: View { struct SectionHeaderView: View {
@State var text: String @State var text: String
var body: some View { var body: some View {
@@ -16,5 +17,6 @@ struct MiniHeaderView: View {
.font(.system(size: 11)) .font(.system(size: 11))
.fontWeight(.medium) .fontWeight(.medium)
.foregroundColor(.secondary) .foregroundColor(.secondary)
.background(Color.debug)
} }
} }

View File

@@ -15,31 +15,47 @@ struct ServicesView: View {
static func asMenuItem() -> NSMenuItem { static func asMenuItem() -> NSMenuItem {
let item = NSMenuItem() let item = NSMenuItem()
var services = [
PhpEnv.phpInstall.formula,
"nginx",
"dnsmasq"
]
if Preferences.custom.hasServices() {
services += Preferences.custom.services!
}
let view = NSHostingView( let view = NSHostingView(
rootView: Self( rootView: Self(
manager: ServicesManager.shared, manager: ServicesManager.shared,
servicesToDisplay: [ servicesToDisplay: services
PhpEnv.phpInstall.formula,
"nginx",
"dnsmasq"
]
) )
) )
view.frame = CGRect(x: 0, y: 0, width: 330, height: 45)
view.autoresizingMask = [.width, .height]
let height = CGFloat(45 * services.chunked(by: 3).count)
view.setFrameSize(CGSize(width: view.frame.width, height: height))
item.view = view item.view = view
return item return item
} }
var body: some View { var body: some View {
HStack(alignment: .firstTextBaseline, spacing: 10) { VStack(alignment: .leading, spacing: 10) {
ForEach(servicesToDisplay, id: \.self) { service in ForEach(servicesToDisplay.chunked(by: 3), id: \.self) { chunk in
VStack(alignment: .center, spacing: 3) { HStack {
MiniHeaderView(text: service.uppercased()) ForEach(chunk, id: \.self) { service in
CheckmarkView(serviceName: service) VStack(alignment: .center, spacing: 3) {
.environmentObject(manager) SectionHeaderView(text: service.uppercased())
}.frame(minWidth: 0, maxWidth: .infinity) CheckmarkView(serviceName: service)
.environmentObject(manager)
}.frame(minWidth: 0, maxWidth: .infinity)
}
}
} }
}.padding(10) }
.padding(10)
.frame(minWidth: 0, maxWidth: .infinity)
.background(Color.debug)
} }
} }
@@ -48,28 +64,39 @@ struct CheckmarkView: View {
@EnvironmentObject var manager: ServicesManager @EnvironmentObject var manager: ServicesManager
public func hasAnyServices() -> Bool { public func hasAnyServices() -> Bool {
return !manager.services.isEmpty return !manager.rootServices.isEmpty
} }
public func active() -> Bool { public func active() -> Bool? {
guard let service = manager.services[serviceName] else { if manager.rootServices.keys.contains(serviceName) {
return false return manager.rootServices[serviceName]!.running
} }
return service.running if manager.userServices.keys.contains(serviceName) {
return manager.userServices[serviceName]!.running
}
return nil
} }
var body: some View { var body: some View {
if !hasAnyServices() { if !hasAnyServices() {
Image(systemName: "questionmark.circle") Image(systemName: "hourglass.circle")
.resizable() .resizable()
.frame(width: 16.0, height: 16.0) .frame(width: 16.0, height: 16.0)
.foregroundColor(.secondary) .foregroundColor(.secondary)
} else { } else {
Image(systemName: active() ? "checkmark.circle" : "exclamationmark.triangle") if active() == nil {
.resizable() Image(systemName: "questionmark.square.dashed")
.frame(width: 16.0, height: 16.0) .resizable()
.foregroundColor(active() ? Color("IconColorGreen") : Color("IconColorRed")) .frame(width: 16.0, height: 16.0)
.foregroundColor(Color("IconColorRed"))
} else {
Image(systemName: active()! ? "checkmark.circle" : "xmark.circle")
.resizable()
.frame(width: 16.0, height: 16.0)
.foregroundColor(active()! ? Color.primary : Color("IconColorRed"))
}
} }
} }
} }
@@ -104,7 +131,8 @@ struct ServicesView_Previews: PreviewProvider {
"dnsmasq": true, "dnsmasq": true,
"mysql": false "mysql": false
]), ]),
servicesToDisplay: ["php", "nginx", "dnsmasq", "mysql"] servicesToDisplay: ["php", "nginx", "dnsmasq",
"mysql", "redis", "mailhog"]
) )
.frame(width: 330.0) .frame(width: 330.0)
.previewDisplayName("Dark Mode") .previewDisplayName("Dark Mode")

View File

@@ -19,7 +19,8 @@ struct StatsView: View {
maxUploadSize: upload maxUploadSize: upload
) )
) )
view.frame = CGRect(x: 0, y: 0, width: 330, height: 55) view.autoresizingMask = [.width, .height]
view.setFrameSize(CGSize(width: view.frame.width, height: 55))
item.view = view item.view = view
return item return item
} }
@@ -31,24 +32,26 @@ struct StatsView: View {
var body: some View { var body: some View {
HStack(alignment: .firstTextBaseline, spacing: 30) { HStack(alignment: .firstTextBaseline, spacing: 30) {
VStack(alignment: .center, spacing: 3) { VStack(alignment: .center, spacing: 3) {
MiniHeaderView(text: "mi_memory_limit".localized.uppercased()) SectionHeaderView(text: "mi_memory_limit".localized.uppercased())
Text(memoryLimit) Text(memoryLimit)
.fontWeight(.medium) .fontWeight(.medium)
.font(.system(size: 16)) .font(.system(size: 16))
} }
VStack(alignment: .center, spacing: 3) { VStack(alignment: .center, spacing: 3) {
MiniHeaderView(text: "mi_post_max_size".localized.uppercased()) SectionHeaderView(text: "mi_post_max_size".localized.uppercased())
Text(maxPostSize) Text(maxPostSize)
.fontWeight(.medium) .fontWeight(.medium)
.font(.system(size: 16)) .font(.system(size: 16))
} }
VStack(alignment: .center, spacing: 3) { VStack(alignment: .center, spacing: 3) {
MiniHeaderView(text: "mi_upload_max_filesize".localized.uppercased()) SectionHeaderView(text: "mi_upload_max_filesize".localized.uppercased())
Text(maxUploadSize) Text(maxUploadSize)
.fontWeight(.medium) .fontWeight(.medium)
.font(.system(size: 16)) .font(.system(size: 16))
} }
}.padding(10) }
.padding(10)
.background(Color.debug)
} }
} }

View File

@@ -23,8 +23,8 @@
"mi_restart_nginx" = "Restart Service: nginx"; "mi_restart_nginx" = "Restart Service: nginx";
"mi_restart_dnsmasq" = "Restart Service: dnsmasq"; "mi_restart_dnsmasq" = "Restart Service: dnsmasq";
"mi_manage_services" = "Manage Services"; "mi_manage_services" = "Manage Services";
"mi_restart_all_services" = "Restart All Services"; "mi_restart_valet_services" = "Restart Valet Services";
"mi_stop_all_services" = "Stop All Services"; "mi_stop_valet_services" = "Stop Valet Services";
"mi_fix_my_valet" = "Fix My Valet..."; "mi_fix_my_valet" = "Fix My Valet...";
"mi_fix_my_valet_tooltip" = "Something wrong with your Valet installation? Try PHP Monitors automatic fixes thatll get you back up and running in no time!"; "mi_fix_my_valet_tooltip" = "Something wrong with your Valet installation? Try PHP Monitors automatic fixes thatll get you back up and running in no time!";
@@ -347,7 +347,7 @@ problem manually, using your own Terminal app (this just shows you the output)."
"alert.fix_homebrew_permissions_done.title" = "All file and folder permissions for Valet's dependencies have been restored."; "alert.fix_homebrew_permissions_done.title" = "All file and folder permissions for Valet's dependencies have been restored.";
"alert.fix_homebrew_permissions_done.subtitle" = "Because of this, all of Valet's services are currently no longer running. You can now interact with Homebrew, but your Valet sites will be unavailable as all services are disabled."; "alert.fix_homebrew_permissions_done.subtitle" = "Because of this, all of Valet's services are currently no longer running. You can now interact with Homebrew, but your Valet sites will be unavailable as all services are disabled.";
"alert.fix_homebrew_permissions_done.desc" = "When you are done with Homebrew (after running `brew upgrade`, for example) you should restart PHP Monitor and select \"Restart All Services\" if you want Valet to work again. It is always recommended to restart PHP Monitor whenever you upgrade PHP versions with `brew upgrade`, or things might break."; "alert.fix_homebrew_permissions_done.desc" = "When you are done with Homebrew (after running `brew upgrade`, for example) you should restart PHP Monitor and select \"Restart Valet Services\" if you want Valet to work again. It is always recommended to restart PHP Monitor whenever you upgrade PHP versions with `brew upgrade`, or things might break.";
// PHP FPM Broken // PHP FPM Broken
"alert.php_fpm_broken.title" = "Your PHP-FPM configuration is not pointing at the Valet socket!"; "alert.php_fpm_broken.title" = "Your PHP-FPM configuration is not pointing at the Valet socket!";