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

🚀 Version 6.2.0

This commit is contained in:
2023-10-27 17:10:43 +02:00
43 changed files with 597 additions and 348 deletions

View File

@ -92,8 +92,8 @@
C40FE73B282ABB2E00A302C2 /* AppVersionTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40FE739282ABB2E00A302C2 /* AppVersionTest.swift */; }; C40FE73B282ABB2E00A302C2 /* AppVersionTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40FE739282ABB2E00A302C2 /* AppVersionTest.swift */; };
C412E5FC25700D5300A1FB67 /* HomebrewDecodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C412E5FB25700D5300A1FB67 /* HomebrewDecodable.swift */; }; C412E5FC25700D5300A1FB67 /* HomebrewDecodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C412E5FB25700D5300A1FB67 /* HomebrewDecodable.swift */; };
C413E43528DA3EB100AE33C7 /* TestableShellTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C413E43428DA3EB100AE33C7 /* TestableShellTest.swift */; }; C413E43528DA3EB100AE33C7 /* TestableShellTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C413E43428DA3EB100AE33C7 /* TestableShellTest.swift */; };
C415937F27A1B54F00D2E1B7 /* PhpFrameworks.swift in Sources */ = {isa = PBXBuildFile; fileRef = C415937E27A1B54F00D2E1B7 /* PhpFrameworks.swift */; }; C415937F27A1B54F00D2E1B7 /* ProjectTypeDetection.swift in Sources */ = {isa = PBXBuildFile; fileRef = C415937E27A1B54F00D2E1B7 /* ProjectTypeDetection.swift */; };
C415938027A1B54F00D2E1B7 /* PhpFrameworks.swift in Sources */ = {isa = PBXBuildFile; fileRef = C415937E27A1B54F00D2E1B7 /* PhpFrameworks.swift */; }; C415938027A1B54F00D2E1B7 /* ProjectTypeDetection.swift in Sources */ = {isa = PBXBuildFile; fileRef = C415937E27A1B54F00D2E1B7 /* ProjectTypeDetection.swift */; };
C4159AF728E4D40400545349 /* RealShellTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4159AF628E4D40400545349 /* RealShellTest.swift */; }; C4159AF728E4D40400545349 /* RealShellTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4159AF628E4D40400545349 /* RealShellTest.swift */; };
C415D3B72770F294005EF286 /* Actions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C415D3B62770F294005EF286 /* Actions.swift */; }; C415D3B72770F294005EF286 /* Actions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C415D3B62770F294005EF286 /* Actions.swift */; };
C415D3B82770F294005EF286 /* Actions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C415D3B62770F294005EF286 /* Actions.swift */; }; C415D3B82770F294005EF286 /* Actions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C415D3B62770F294005EF286 /* Actions.swift */; };
@ -132,6 +132,7 @@
C42CFB1627DFDE7900862737 /* nginx-site.test in Resources */ = {isa = PBXBuildFile; fileRef = C42CFB1527DFDE7900862737 /* nginx-site.test */; }; C42CFB1627DFDE7900862737 /* nginx-site.test in Resources */ = {isa = PBXBuildFile; fileRef = C42CFB1527DFDE7900862737 /* nginx-site.test */; };
C42CFB1827DFDFDC00862737 /* nginx-site-isolated.test in Resources */ = {isa = PBXBuildFile; fileRef = C42CFB1727DFDFDC00862737 /* nginx-site-isolated.test */; }; C42CFB1827DFDFDC00862737 /* nginx-site-isolated.test in Resources */ = {isa = PBXBuildFile; fileRef = C42CFB1727DFDFDC00862737 /* nginx-site-isolated.test */; };
C42CFB1A27DFE8BD00862737 /* NginxConfigurationTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42CFB1927DFE8BD00862737 /* NginxConfigurationTest.swift */; }; C42CFB1A27DFE8BD00862737 /* NginxConfigurationTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42CFB1927DFE8BD00862737 /* NginxConfigurationTest.swift */; };
C42E3F772AB0D2880096DFC2 /* ConfigManagerWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42E3F762AB0D2880096DFC2 /* ConfigManagerWindowController.swift */; };
C42F26732805B4B400938AC7 /* ValetListable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42F26722805B4B400938AC7 /* ValetListable.swift */; }; C42F26732805B4B400938AC7 /* ValetListable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42F26722805B4B400938AC7 /* ValetListable.swift */; };
C42F26742805B4B400938AC7 /* ValetListable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42F26722805B4B400938AC7 /* ValetListable.swift */; }; C42F26742805B4B400938AC7 /* ValetListable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42F26722805B4B400938AC7 /* ValetListable.swift */; };
C42F26762805FEE200938AC7 /* nginx-secure-proxy.test in Resources */ = {isa = PBXBuildFile; fileRef = C42F26752805FEE200938AC7 /* nginx-secure-proxy.test */; }; C42F26762805FEE200938AC7 /* nginx-secure-proxy.test in Resources */ = {isa = PBXBuildFile; fileRef = C42F26752805FEE200938AC7 /* nginx-secure-proxy.test */; };
@ -161,6 +162,10 @@
C44067F727E258410045BD4E /* DomainListPhpCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44067F627E258410045BD4E /* DomainListPhpCell.swift */; }; C44067F727E258410045BD4E /* DomainListPhpCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44067F627E258410045BD4E /* DomainListPhpCell.swift */; };
C44067F927E2585E0045BD4E /* DomainListTypeCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44067F827E2585E0045BD4E /* DomainListTypeCell.swift */; }; C44067F927E2585E0045BD4E /* DomainListTypeCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44067F827E2585E0045BD4E /* DomainListTypeCell.swift */; };
C44067FB27E25FD70045BD4E /* DomainListTLSCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44067FA27E25FD70045BD4E /* DomainListTLSCell.swift */; }; C44067FB27E25FD70045BD4E /* DomainListTLSCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44067FA27E25FD70045BD4E /* DomainListTLSCell.swift */; };
C441CC562AE8249400DDFACD /* ConfigFSNotifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = C441CC552AE8249400DDFACD /* ConfigFSNotifier.swift */; };
C441CC572AE8249400DDFACD /* ConfigFSNotifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = C441CC552AE8249400DDFACD /* ConfigFSNotifier.swift */; };
C441CC582AE8249400DDFACD /* ConfigFSNotifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = C441CC552AE8249400DDFACD /* ConfigFSNotifier.swift */; };
C441CC592AE8249400DDFACD /* ConfigFSNotifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = C441CC552AE8249400DDFACD /* ConfigFSNotifier.swift */; };
C44264BE2850B86C007400F1 /* SwiftUIHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44264BD2850B86C007400F1 /* SwiftUIHelper.swift */; }; C44264BE2850B86C007400F1 /* SwiftUIHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44264BD2850B86C007400F1 /* SwiftUIHelper.swift */; };
C44264C02850BD2A007400F1 /* VersionPopoverView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44264BF2850BD2A007400F1 /* VersionPopoverView.swift */; }; C44264C02850BD2A007400F1 /* VersionPopoverView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44264BF2850BD2A007400F1 /* VersionPopoverView.swift */; };
C4463FCC29804BCB007B93D5 /* RCFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4463FCB29804BCB007B93D5 /* RCFile.swift */; }; C4463FCC29804BCB007B93D5 /* RCFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4463FCB29804BCB007B93D5 /* RCFile.swift */; };
@ -227,6 +232,15 @@
C45E2A77291992DA005C7CFD /* FeatureTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = C45E2A76291992DA005C7CFD /* FeatureTestCase.swift */; }; C45E2A77291992DA005C7CFD /* FeatureTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = C45E2A76291992DA005C7CFD /* FeatureTestCase.swift */; };
C45E76142854A65300B4FE0C /* ServicesManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C45E76132854A65300B4FE0C /* ServicesManager.swift */; }; C45E76142854A65300B4FE0C /* ServicesManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C45E76132854A65300B4FE0C /* ServicesManager.swift */; };
C45E76152854A65300B4FE0C /* ServicesManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C45E76132854A65300B4FE0C /* ServicesManager.swift */; }; C45E76152854A65300B4FE0C /* ServicesManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C45E76132854A65300B4FE0C /* ServicesManager.swift */; };
C4611E5A2AEAD2E20010BE24 /* ConfigManagerWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42E3F762AB0D2880096DFC2 /* ConfigManagerWindowController.swift */; };
C4611E5B2AEAD2E30010BE24 /* ConfigManagerWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42E3F762AB0D2880096DFC2 /* ConfigManagerWindowController.swift */; };
C4611E5C2AEAD2E30010BE24 /* ConfigManagerWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42E3F762AB0D2880096DFC2 /* ConfigManagerWindowController.swift */; };
C4611E5D2AEAD2FA0010BE24 /* ConfigManagerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44DFA7B2A67043000B98ED5 /* ConfigManagerView.swift */; };
C4611E5E2AEAD2FB0010BE24 /* ConfigManagerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44DFA7B2A67043000B98ED5 /* ConfigManagerView.swift */; };
C4611E5F2AEAD2FB0010BE24 /* ConfigManagerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44DFA7B2A67043000B98ED5 /* ConfigManagerView.swift */; };
C4611E602AEAD3100010BE24 /* ByteLimitView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D5857B2A7038DB00DDBB63 /* ByteLimitView.swift */; };
C4611E612AEAD3110010BE24 /* ByteLimitView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D5857B2A7038DB00DDBB63 /* ByteLimitView.swift */; };
C4611E622AEAD3110010BE24 /* ByteLimitView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D5857B2A7038DB00DDBB63 /* ByteLimitView.swift */; };
C463E380284930EE00422731 /* PresetHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = C463E37F284930EE00422731 /* PresetHelper.swift */; }; C463E380284930EE00422731 /* PresetHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = C463E37F284930EE00422731 /* PresetHelper.swift */; };
C463E381284930EE00422731 /* PresetHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = C463E37F284930EE00422731 /* PresetHelper.swift */; }; C463E381284930EE00422731 /* PresetHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = C463E37F284930EE00422731 /* PresetHelper.swift */; };
C464ADAC275A7A3F003FCD53 /* DomainListWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C464ADAB275A7A3F003FCD53 /* DomainListWindowController.swift */; }; C464ADAC275A7A3F003FCD53 /* DomainListWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C464ADAB275A7A3F003FCD53 /* DomainListWindowController.swift */; };
@ -342,10 +356,10 @@
C471E81E28F9BB260021E251 /* BetterAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4080FF527BD8C6400BF2C6B /* BetterAlert.swift */; }; C471E81E28F9BB260021E251 /* BetterAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4080FF527BD8C6400BF2C6B /* BetterAlert.swift */; };
C471E81F28F9BB290021E251 /* NginxConfigurationFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D5CFC927E0F9CD00035329 /* NginxConfigurationFile.swift */; }; C471E81F28F9BB290021E251 /* NginxConfigurationFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D5CFC927E0F9CD00035329 /* NginxConfigurationFile.swift */; };
C471E82028F9BB290021E251 /* NginxConfigurationFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D5CFC927E0F9CD00035329 /* NginxConfigurationFile.swift */; }; C471E82028F9BB290021E251 /* NginxConfigurationFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D5CFC927E0F9CD00035329 /* NginxConfigurationFile.swift */; };
C471E82128F9BB2E0021E251 /* PhpFrameworks.swift in Sources */ = {isa = PBXBuildFile; fileRef = C415937E27A1B54F00D2E1B7 /* PhpFrameworks.swift */; }; C471E82128F9BB2E0021E251 /* ProjectTypeDetection.swift in Sources */ = {isa = PBXBuildFile; fileRef = C415937E27A1B54F00D2E1B7 /* ProjectTypeDetection.swift */; };
C471E82228F9BB2E0021E251 /* ComposerWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4CE3BB927B31F670086CA49 /* ComposerWindow.swift */; }; C471E82228F9BB2E0021E251 /* ComposerWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4CE3BB927B31F670086CA49 /* ComposerWindow.swift */; };
C471E82328F9BB2E0021E251 /* ComposerJson.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D89BC52783C99400A02B68 /* ComposerJson.swift */; }; C471E82328F9BB2E0021E251 /* ComposerJson.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D89BC52783C99400A02B68 /* ComposerJson.swift */; };
C471E82428F9BB2E0021E251 /* PhpFrameworks.swift in Sources */ = {isa = PBXBuildFile; fileRef = C415937E27A1B54F00D2E1B7 /* PhpFrameworks.swift */; }; C471E82428F9BB2E0021E251 /* ProjectTypeDetection.swift in Sources */ = {isa = PBXBuildFile; fileRef = C415937E27A1B54F00D2E1B7 /* ProjectTypeDetection.swift */; };
C471E82528F9BB2E0021E251 /* ComposerWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4CE3BB927B31F670086CA49 /* ComposerWindow.swift */; }; C471E82528F9BB2E0021E251 /* ComposerWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4CE3BB927B31F670086CA49 /* ComposerWindow.swift */; };
C471E82628F9BB2E0021E251 /* ComposerJson.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D89BC52783C99400A02B68 /* ComposerJson.swift */; }; C471E82628F9BB2E0021E251 /* ComposerJson.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D89BC52783C99400A02B68 /* ComposerJson.swift */; };
C471E82728F9BB310021E251 /* BrewDiagnostics.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4F2E4362752F0870020E974 /* BrewDiagnostics.swift */; }; C471E82728F9BB310021E251 /* BrewDiagnostics.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4F2E4362752F0870020E974 /* BrewDiagnostics.swift */; };
@ -423,7 +437,7 @@
C471E87828F9BB650021E251 /* TerminalProgressWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44C198C276E3A1C0072762D /* TerminalProgressWindowController.swift */; }; C471E87828F9BB650021E251 /* TerminalProgressWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44C198C276E3A1C0072762D /* TerminalProgressWindowController.swift */; };
C471E87928F9BB650021E251 /* ProgressVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44A874728905BB000498BC4 /* ProgressVC.swift */; }; C471E87928F9BB650021E251 /* ProgressVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44A874728905BB000498BC4 /* ProgressVC.swift */; };
C471E87B28F9BB650021E251 /* App+ConfigWatch.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C8E817276F54D8003AC782 /* App+ConfigWatch.swift */; }; C471E87B28F9BB650021E251 /* App+ConfigWatch.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C8E817276F54D8003AC782 /* App+ConfigWatch.swift */; };
C471E87C28F9BB650021E251 /* PhpConfigWatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C8E81A276F54E5003AC782 /* PhpConfigWatcher.swift */; }; C471E87C28F9BB650021E251 /* ConfigWatchManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C8E81A276F54E5003AC782 /* ConfigWatchManager.swift */; };
C471E87D28F9BB650021E251 /* Preset.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40C5C9B2846A40600E28255 /* Preset.swift */; }; C471E87D28F9BB650021E251 /* Preset.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40C5C9B2846A40600E28255 /* Preset.swift */; };
C471E87E28F9BB650021E251 /* PresetHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = C463E37F284930EE00422731 /* PresetHelper.swift */; }; C471E87E28F9BB650021E251 /* PresetHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = C463E37F284930EE00422731 /* PresetHelper.swift */; };
C471E87F28F9BB650021E251 /* WarningView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4297F7928970D59004C4630 /* WarningView.swift */; }; C471E87F28F9BB650021E251 /* WarningView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4297F7928970D59004C4630 /* WarningView.swift */; };
@ -511,7 +525,7 @@
C471E8DB28F9BB8F0021E251 /* TerminalProgressWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44C198C276E3A1C0072762D /* TerminalProgressWindowController.swift */; }; C471E8DB28F9BB8F0021E251 /* TerminalProgressWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44C198C276E3A1C0072762D /* TerminalProgressWindowController.swift */; };
C471E8DC28F9BB8F0021E251 /* ProgressVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44A874728905BB000498BC4 /* ProgressVC.swift */; }; C471E8DC28F9BB8F0021E251 /* ProgressVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44A874728905BB000498BC4 /* ProgressVC.swift */; };
C471E8DE28F9BB8F0021E251 /* App+ConfigWatch.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C8E817276F54D8003AC782 /* App+ConfigWatch.swift */; }; C471E8DE28F9BB8F0021E251 /* App+ConfigWatch.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C8E817276F54D8003AC782 /* App+ConfigWatch.swift */; };
C471E8DF28F9BB8F0021E251 /* PhpConfigWatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C8E81A276F54E5003AC782 /* PhpConfigWatcher.swift */; }; C471E8DF28F9BB8F0021E251 /* ConfigWatchManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C8E81A276F54E5003AC782 /* ConfigWatchManager.swift */; };
C471E8E028F9BB8F0021E251 /* Preset.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40C5C9B2846A40600E28255 /* Preset.swift */; }; C471E8E028F9BB8F0021E251 /* Preset.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40C5C9B2846A40600E28255 /* Preset.swift */; };
C471E8E128F9BB8F0021E251 /* PresetHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = C463E37F284930EE00422731 /* PresetHelper.swift */; }; C471E8E128F9BB8F0021E251 /* PresetHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = C463E37F284930EE00422731 /* PresetHelper.swift */; };
C471E8E228F9BB8F0021E251 /* WarningView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4297F7928970D59004C4630 /* WarningView.swift */; }; C471E8E228F9BB8F0021E251 /* WarningView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4297F7928970D59004C4630 /* WarningView.swift */; };
@ -677,8 +691,8 @@
C4C8900728F0E3EF00CE5E97 /* ActiveFileSystem.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C8900628F0E3EF00CE5E97 /* ActiveFileSystem.swift */; }; C4C8900728F0E3EF00CE5E97 /* ActiveFileSystem.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C8900628F0E3EF00CE5E97 /* ActiveFileSystem.swift */; };
C4C8E818276F54D8003AC782 /* App+ConfigWatch.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C8E817276F54D8003AC782 /* App+ConfigWatch.swift */; }; C4C8E818276F54D8003AC782 /* App+ConfigWatch.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C8E817276F54D8003AC782 /* App+ConfigWatch.swift */; };
C4C8E819276F54D8003AC782 /* App+ConfigWatch.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C8E817276F54D8003AC782 /* App+ConfigWatch.swift */; }; C4C8E819276F54D8003AC782 /* App+ConfigWatch.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C8E817276F54D8003AC782 /* App+ConfigWatch.swift */; };
C4C8E81B276F54E5003AC782 /* PhpConfigWatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C8E81A276F54E5003AC782 /* PhpConfigWatcher.swift */; }; C4C8E81B276F54E5003AC782 /* ConfigWatchManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C8E81A276F54E5003AC782 /* ConfigWatchManager.swift */; };
C4C8E81C276F54E5003AC782 /* PhpConfigWatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C8E81A276F54E5003AC782 /* PhpConfigWatcher.swift */; }; C4C8E81C276F54E5003AC782 /* ConfigWatchManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C8E81A276F54E5003AC782 /* ConfigWatchManager.swift */; };
C4CB250529B28BB800CA4492 /* MainMenuTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4CB250429B28BB800CA4492 /* MainMenuTest.swift */; }; C4CB250529B28BB800CA4492 /* MainMenuTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4CB250429B28BB800CA4492 /* MainMenuTest.swift */; };
C4CB6E65292C362C002E9027 /* Homebrew.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4CB6E64292C362C002E9027 /* Homebrew.swift */; }; C4CB6E65292C362C002E9027 /* Homebrew.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4CB6E64292C362C002E9027 /* Homebrew.swift */; };
C4CB6E66292C362C002E9027 /* Homebrew.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4CB6E64292C362C002E9027 /* Homebrew.swift */; }; C4CB6E66292C362C002E9027 /* Homebrew.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4CB6E64292C362C002E9027 /* Homebrew.swift */; };
@ -897,7 +911,7 @@
C40FE739282ABB2E00A302C2 /* AppVersionTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppVersionTest.swift; sourceTree = "<group>"; }; C40FE739282ABB2E00A302C2 /* AppVersionTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppVersionTest.swift; sourceTree = "<group>"; };
C412E5FB25700D5300A1FB67 /* HomebrewDecodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomebrewDecodable.swift; sourceTree = "<group>"; }; C412E5FB25700D5300A1FB67 /* HomebrewDecodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomebrewDecodable.swift; sourceTree = "<group>"; };
C413E43428DA3EB100AE33C7 /* TestableShellTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestableShellTest.swift; sourceTree = "<group>"; }; C413E43428DA3EB100AE33C7 /* TestableShellTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestableShellTest.swift; sourceTree = "<group>"; };
C415937E27A1B54F00D2E1B7 /* PhpFrameworks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpFrameworks.swift; sourceTree = "<group>"; }; C415937E27A1B54F00D2E1B7 /* ProjectTypeDetection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProjectTypeDetection.swift; sourceTree = "<group>"; };
C4159AF628E4D40400545349 /* RealShellTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RealShellTest.swift; sourceTree = "<group>"; }; C4159AF628E4D40400545349 /* RealShellTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RealShellTest.swift; sourceTree = "<group>"; };
C415D3B62770F294005EF286 /* Actions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Actions.swift; sourceTree = "<group>"; }; C415D3B62770F294005EF286 /* Actions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Actions.swift; sourceTree = "<group>"; };
C415D3E72770F692005EF286 /* AppDelegate+InterApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppDelegate+InterApp.swift"; sourceTree = "<group>"; }; C415D3E72770F692005EF286 /* AppDelegate+InterApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppDelegate+InterApp.swift"; sourceTree = "<group>"; };
@ -929,6 +943,7 @@
C42CFB1527DFDE7900862737 /* nginx-site.test */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "nginx-site.test"; sourceTree = "<group>"; }; C42CFB1527DFDE7900862737 /* nginx-site.test */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "nginx-site.test"; sourceTree = "<group>"; };
C42CFB1727DFDFDC00862737 /* nginx-site-isolated.test */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "nginx-site-isolated.test"; sourceTree = "<group>"; }; C42CFB1727DFDFDC00862737 /* nginx-site-isolated.test */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "nginx-site-isolated.test"; sourceTree = "<group>"; };
C42CFB1927DFE8BD00862737 /* NginxConfigurationTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NginxConfigurationTest.swift; sourceTree = "<group>"; }; C42CFB1927DFE8BD00862737 /* NginxConfigurationTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NginxConfigurationTest.swift; sourceTree = "<group>"; };
C42E3F762AB0D2880096DFC2 /* ConfigManagerWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigManagerWindowController.swift; sourceTree = "<group>"; };
C42F26722805B4B400938AC7 /* ValetListable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValetListable.swift; sourceTree = "<group>"; }; C42F26722805B4B400938AC7 /* ValetListable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValetListable.swift; sourceTree = "<group>"; };
C42F26752805FEE200938AC7 /* nginx-secure-proxy.test */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "nginx-secure-proxy.test"; sourceTree = "<group>"; }; C42F26752805FEE200938AC7 /* nginx-secure-proxy.test */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "nginx-secure-proxy.test"; sourceTree = "<group>"; };
C436039F275E67610028EFC6 /* AppDelegate+Notifications.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppDelegate+Notifications.swift"; sourceTree = "<group>"; }; C436039F275E67610028EFC6 /* AppDelegate+Notifications.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppDelegate+Notifications.swift"; sourceTree = "<group>"; };
@ -944,6 +959,7 @@
C44067F627E258410045BD4E /* DomainListPhpCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomainListPhpCell.swift; sourceTree = "<group>"; }; C44067F627E258410045BD4E /* DomainListPhpCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomainListPhpCell.swift; sourceTree = "<group>"; };
C44067F827E2585E0045BD4E /* DomainListTypeCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DomainListTypeCell.swift; sourceTree = "<group>"; }; C44067F827E2585E0045BD4E /* DomainListTypeCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DomainListTypeCell.swift; sourceTree = "<group>"; };
C44067FA27E25FD70045BD4E /* DomainListTLSCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DomainListTLSCell.swift; sourceTree = "<group>"; }; C44067FA27E25FD70045BD4E /* DomainListTLSCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DomainListTLSCell.swift; sourceTree = "<group>"; };
C441CC552AE8249400DDFACD /* ConfigFSNotifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigFSNotifier.swift; sourceTree = "<group>"; };
C44264BD2850B86C007400F1 /* SwiftUIHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftUIHelper.swift; sourceTree = "<group>"; }; C44264BD2850B86C007400F1 /* SwiftUIHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftUIHelper.swift; sourceTree = "<group>"; };
C44264BF2850BD2A007400F1 /* VersionPopoverView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VersionPopoverView.swift; sourceTree = "<group>"; }; C44264BF2850BD2A007400F1 /* VersionPopoverView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VersionPopoverView.swift; sourceTree = "<group>"; };
C4463FCB29804BCB007B93D5 /* RCFile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RCFile.swift; sourceTree = "<group>"; }; C4463FCB29804BCB007B93D5 /* RCFile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RCFile.swift; sourceTree = "<group>"; };
@ -1052,7 +1068,7 @@
C4C8900428F0E3D100CE5E97 /* RealFileSystem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RealFileSystem.swift; sourceTree = "<group>"; }; C4C8900428F0E3D100CE5E97 /* RealFileSystem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RealFileSystem.swift; sourceTree = "<group>"; };
C4C8900628F0E3EF00CE5E97 /* ActiveFileSystem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActiveFileSystem.swift; sourceTree = "<group>"; }; C4C8900628F0E3EF00CE5E97 /* ActiveFileSystem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActiveFileSystem.swift; sourceTree = "<group>"; };
C4C8E817276F54D8003AC782 /* App+ConfigWatch.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "App+ConfigWatch.swift"; sourceTree = "<group>"; }; C4C8E817276F54D8003AC782 /* App+ConfigWatch.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "App+ConfigWatch.swift"; sourceTree = "<group>"; };
C4C8E81A276F54E5003AC782 /* PhpConfigWatcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhpConfigWatcher.swift; sourceTree = "<group>"; }; C4C8E81A276F54E5003AC782 /* ConfigWatchManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConfigWatchManager.swift; sourceTree = "<group>"; };
C4CB250429B28BB800CA4492 /* MainMenuTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainMenuTest.swift; sourceTree = "<group>"; }; C4CB250429B28BB800CA4492 /* MainMenuTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainMenuTest.swift; sourceTree = "<group>"; };
C4CB6E64292C362C002E9027 /* Homebrew.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Homebrew.swift; sourceTree = "<group>"; }; C4CB6E64292C362C002E9027 /* Homebrew.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Homebrew.swift; sourceTree = "<group>"; };
C4CCBA6B275C567B008C7055 /* PMWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PMWindowController.swift; sourceTree = "<group>"; }; C4CCBA6B275C567B008C7055 /* PMWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PMWindowController.swift; sourceTree = "<group>"; };
@ -1499,6 +1515,7 @@
children = ( children = (
C44DFA7B2A67043000B98ED5 /* ConfigManagerView.swift */, C44DFA7B2A67043000B98ED5 /* ConfigManagerView.swift */,
C4D5857B2A7038DB00DDBB63 /* ByteLimitView.swift */, C4D5857B2A7038DB00DDBB63 /* ByteLimitView.swift */,
C42E3F762AB0D2880096DFC2 /* ConfigManagerWindowController.swift */,
); );
path = UI; path = UI;
sourceTree = "<group>"; sourceTree = "<group>";
@ -1742,7 +1759,6 @@
C4B5635D276AB09000F12CCB /* VersionExtractor.swift */, C4B5635D276AB09000F12CCB /* VersionExtractor.swift */,
C4D3660A29113F20006BD146 /* System.swift */, C4D3660A29113F20006BD146 /* System.swift */,
C4D36614291160A1006BD146 /* WIP.swift */, C4D36614291160A1006BD146 /* WIP.swift */,
C41ADCE72970CCC700120423 /* FSNotifier.swift */,
C47DF1AE299D5A3B0007055D /* LoginItemManager.swift */, C47DF1AE299D5A3B0007055D /* LoginItemManager.swift */,
C49EAA5129B12A5A00AB28FC /* Measurements.swift */, C49EAA5129B12A5A00AB28FC /* Measurements.swift */,
); );
@ -1961,9 +1977,11 @@
C4C8E81D276F5686003AC782 /* Watcher */ = { C4C8E81D276F5686003AC782 /* Watcher */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
C4C8E81A276F54E5003AC782 /* ConfigWatchManager.swift */,
C441CC552AE8249400DDFACD /* ConfigFSNotifier.swift */,
C41ADCE72970CCC700120423 /* FSNotifier.swift */,
C49EAA5629B1689200AB28FC /* App+BrewWatch.swift */, C49EAA5629B1689200AB28FC /* App+BrewWatch.swift */,
C4C8E817276F54D8003AC782 /* App+ConfigWatch.swift */, C4C8E817276F54D8003AC782 /* App+ConfigWatch.swift */,
C4C8E81A276F54E5003AC782 /* PhpConfigWatcher.swift */,
); );
path = Watcher; path = Watcher;
sourceTree = "<group>"; sourceTree = "<group>";
@ -1980,7 +1998,7 @@
children = ( children = (
C4CE3BB927B31F670086CA49 /* ComposerWindow.swift */, C4CE3BB927B31F670086CA49 /* ComposerWindow.swift */,
C4D89BC52783C99400A02B68 /* ComposerJson.swift */, C4D89BC52783C99400A02B68 /* ComposerJson.swift */,
C415937E27A1B54F00D2E1B7 /* PhpFrameworks.swift */, C415937E27A1B54F00D2E1B7 /* ProjectTypeDetection.swift */,
); );
path = Composer; path = Composer;
sourceTree = "<group>"; sourceTree = "<group>";
@ -2475,7 +2493,7 @@
C4B97B78275CF1B5003F3378 /* App+ActivationPolicy.swift in Sources */, C4B97B78275CF1B5003F3378 /* App+ActivationPolicy.swift in Sources */,
C4CE3BB827B31F2E0086CA49 /* MainMenu+Switcher.swift in Sources */, C4CE3BB827B31F2E0086CA49 /* MainMenu+Switcher.swift in Sources */,
C456A0CB2AA6166F0080144F /* BytePhpPreference.swift in Sources */, C456A0CB2AA6166F0080144F /* BytePhpPreference.swift in Sources */,
C415937F27A1B54F00D2E1B7 /* PhpFrameworks.swift in Sources */, C415937F27A1B54F00D2E1B7 /* ProjectTypeDetection.swift in Sources */,
C4811D2422D70A4700B5F6B3 /* App.swift in Sources */, C4811D2422D70A4700B5F6B3 /* App.swift in Sources */,
C44DFA7C2A67043000B98ED5 /* ConfigManagerView.swift in Sources */, C44DFA7C2A67043000B98ED5 /* ConfigManagerView.swift in Sources */,
C40934A2298EEB2C00D25014 /* CaskFile.swift in Sources */, C40934A2298EEB2C00D25014 /* CaskFile.swift in Sources */,
@ -2503,8 +2521,9 @@
C4D4CB3729C109CF00DB9F93 /* InternalSwitcher+Valet.swift in Sources */, C4D4CB3729C109CF00DB9F93 /* InternalSwitcher+Valet.swift in Sources */,
C46EBC4728DB9644007ACC74 /* RealShell.swift in Sources */, C46EBC4728DB9644007ACC74 /* RealShell.swift in Sources */,
C4068CAA27B0890D00544CD5 /* MenuBarIcons.swift in Sources */, C4068CAA27B0890D00544CD5 /* MenuBarIcons.swift in Sources */,
C441CC562AE8249400DDFACD /* ConfigFSNotifier.swift in Sources */,
C44264C02850BD2A007400F1 /* VersionPopoverView.swift in Sources */, C44264C02850BD2A007400F1 /* VersionPopoverView.swift in Sources */,
C4C8E81B276F54E5003AC782 /* PhpConfigWatcher.swift in Sources */, C4C8E81B276F54E5003AC782 /* ConfigWatchManager.swift in Sources */,
C417DC74277614690015E6EE /* Helpers.swift in Sources */, C417DC74277614690015E6EE /* Helpers.swift in Sources */,
C415D3E82770F692005EF286 /* AppDelegate+InterApp.swift in Sources */, C415D3E82770F692005EF286 /* AppDelegate+InterApp.swift in Sources */,
C41C1B3722B0097F00E7CF16 /* AppDelegate.swift in Sources */, C41C1B3722B0097F00E7CF16 /* AppDelegate.swift in Sources */,
@ -2568,6 +2587,7 @@
C4B97B75275CF08C003F3378 /* AppDelegate+MenuOutlets.swift in Sources */, C4B97B75275CF08C003F3378 /* AppDelegate+MenuOutlets.swift in Sources */,
C464ADAC275A7A3F003FCD53 /* DomainListWindowController.swift in Sources */, C464ADAC275A7A3F003FCD53 /* DomainListWindowController.swift in Sources */,
C4CB6E65292C362C002E9027 /* Homebrew.swift in Sources */, C4CB6E65292C362C002E9027 /* Homebrew.swift in Sources */,
C42E3F772AB0D2880096DFC2 /* ConfigManagerWindowController.swift in Sources */,
C464ADB2275A87CA003FCD53 /* DomainListCellProtocol.swift in Sources */, C464ADB2275A87CA003FCD53 /* DomainListCellProtocol.swift in Sources */,
C4EE188422D3386B00E126E5 /* Constants.swift in Sources */, C4EE188422D3386B00E126E5 /* Constants.swift in Sources */,
C493084A279F331F009C240B /* AddSiteVC.swift in Sources */, C493084A279F331F009C240B /* AddSiteVC.swift in Sources */,
@ -2633,8 +2653,10 @@
C4B79EBE29CA38DB00A483EE /* BrewCommand.swift in Sources */, C4B79EBE29CA38DB00A483EE /* BrewCommand.swift in Sources */,
C47DF1B1299D5A3B0007055D /* LoginItemManager.swift in Sources */, C47DF1B1299D5A3B0007055D /* LoginItemManager.swift in Sources */,
C471E85928F9BB650021E251 /* DomainListPhpCell.swift in Sources */, C471E85928F9BB650021E251 /* DomainListPhpCell.swift in Sources */,
C4611E5B2AEAD2E30010BE24 /* ConfigManagerWindowController.swift in Sources */,
C471E85A28F9BB650021E251 /* DomainListTypeCell.swift in Sources */, C471E85A28F9BB650021E251 /* DomainListTypeCell.swift in Sources */,
C471E85B28F9BB650021E251 /* DomainListKindCell.swift in Sources */, C471E85B28F9BB650021E251 /* DomainListKindCell.swift in Sources */,
C4611E5E2AEAD2FB0010BE24 /* ConfigManagerView.swift in Sources */,
C4BF56AD2949381100379603 /* FakeValetInteractor.swift in Sources */, C4BF56AD2949381100379603 /* FakeValetInteractor.swift in Sources */,
C471E85C28F9BB650021E251 /* DomainListWindowController.swift in Sources */, C471E85C28F9BB650021E251 /* DomainListWindowController.swift in Sources */,
C471E85D28F9BB650021E251 /* DomainListVC.swift in Sources */, C471E85D28F9BB650021E251 /* DomainListVC.swift in Sources */,
@ -2679,7 +2701,7 @@
C471E87828F9BB650021E251 /* TerminalProgressWindowController.swift in Sources */, C471E87828F9BB650021E251 /* TerminalProgressWindowController.swift in Sources */,
C471E87928F9BB650021E251 /* ProgressVC.swift in Sources */, C471E87928F9BB650021E251 /* ProgressVC.swift in Sources */,
C471E87B28F9BB650021E251 /* App+ConfigWatch.swift in Sources */, C471E87B28F9BB650021E251 /* App+ConfigWatch.swift in Sources */,
C471E87C28F9BB650021E251 /* PhpConfigWatcher.swift in Sources */, C471E87C28F9BB650021E251 /* ConfigWatchManager.swift in Sources */,
C471E87D28F9BB650021E251 /* Preset.swift in Sources */, C471E87D28F9BB650021E251 /* Preset.swift in Sources */,
C471E87E28F9BB650021E251 /* PresetHelper.swift in Sources */, C471E87E28F9BB650021E251 /* PresetHelper.swift in Sources */,
C471E87F28F9BB650021E251 /* WarningView.swift in Sources */, C471E87F28F9BB650021E251 /* WarningView.swift in Sources */,
@ -2720,10 +2742,11 @@
C471E81828F9BAE80021E251 /* StringExtension.swift in Sources */, C471E81828F9BAE80021E251 /* StringExtension.swift in Sources */,
C471E7FA28F9BACB0021E251 /* InternalSwitcher.swift in Sources */, C471E7FA28F9BACB0021E251 /* InternalSwitcher.swift in Sources */,
C471E82628F9BB2E0021E251 /* ComposerJson.swift in Sources */, C471E82628F9BB2E0021E251 /* ComposerJson.swift in Sources */,
C471E82428F9BB2E0021E251 /* PhpFrameworks.swift in Sources */, C471E82428F9BB2E0021E251 /* ProjectTypeDetection.swift in Sources */,
C471E7E828F9BAC20021E251 /* Actions.swift in Sources */, C471E7E828F9BAC20021E251 /* Actions.swift in Sources */,
C40D72612A018AE30054A067 /* BrewFormula+UI.swift in Sources */, C40D72612A018AE30054A067 /* BrewFormula+UI.swift in Sources */,
C471E82528F9BB2E0021E251 /* ComposerWindow.swift in Sources */, C471E82528F9BB2E0021E251 /* ComposerWindow.swift in Sources */,
C441CC582AE8249400DDFACD /* ConfigFSNotifier.swift in Sources */,
C471E80828F9BAD40021E251 /* PhpExtension.swift in Sources */, C471E80828F9BAD40021E251 /* PhpExtension.swift in Sources */,
C471E7F928F9BACB0021E251 /* PhpSwitcher.swift in Sources */, C471E7F928F9BACB0021E251 /* PhpSwitcher.swift in Sources */,
C471E82A28F9BB330021E251 /* ValetListable.swift in Sources */, C471E82A28F9BB330021E251 /* ValetListable.swift in Sources */,
@ -2752,6 +2775,7 @@
C471E7FD28F9BACE0021E251 /* HomebrewService.swift in Sources */, C471E7FD28F9BACE0021E251 /* HomebrewService.swift in Sources */,
C471E7E428F9BAC20021E251 /* Helpers.swift in Sources */, C471E7E428F9BAC20021E251 /* Helpers.swift in Sources */,
C4CB6E67292C362C002E9027 /* Homebrew.swift in Sources */, C4CB6E67292C362C002E9027 /* Homebrew.swift in Sources */,
C4611E602AEAD3100010BE24 /* ByteLimitView.swift in Sources */,
C489E0BD2A220A4200323F5E /* FakeBrewFormulaeHandler.swift in Sources */, C489E0BD2A220A4200323F5E /* FakeBrewFormulaeHandler.swift in Sources */,
C45E2A77291992DA005C7CFD /* FeatureTestCase.swift in Sources */, C45E2A77291992DA005C7CFD /* FeatureTestCase.swift in Sources */,
C471E82028F9BB290021E251 /* NginxConfigurationFile.swift in Sources */, C471E82028F9BB290021E251 /* NginxConfigurationFile.swift in Sources */,
@ -2781,6 +2805,7 @@
C471E89228F9BB8F0021E251 /* Alert.swift in Sources */, C471E89228F9BB8F0021E251 /* Alert.swift in Sources */,
C471E89328F9BB8F0021E251 /* Application.swift in Sources */, C471E89328F9BB8F0021E251 /* Application.swift in Sources */,
C471E89428F9BB8F0021E251 /* LocalNotification.swift in Sources */, C471E89428F9BB8F0021E251 /* LocalNotification.swift in Sources */,
C441CC592AE8249400DDFACD /* ConfigFSNotifier.swift in Sources */,
C40934A5298EEB2C00D25014 /* CaskFile.swift in Sources */, C40934A5298EEB2C00D25014 /* CaskFile.swift in Sources */,
C471E89528F9BB8F0021E251 /* MenuBarImageGenerator.swift in Sources */, C471E89528F9BB8F0021E251 /* MenuBarImageGenerator.swift in Sources */,
C40D725D2A018ACC0054A067 /* PhpFormulaeStatus.swift in Sources */, C40D725D2A018ACC0054A067 /* PhpFormulaeStatus.swift in Sources */,
@ -2862,12 +2887,13 @@
C471E8D528F9BB8F0021E251 /* CheckboxPreferenceView.swift in Sources */, C471E8D528F9BB8F0021E251 /* CheckboxPreferenceView.swift in Sources */,
C471E8D728F9BB8F0021E251 /* SelectPreferenceView.swift in Sources */, C471E8D728F9BB8F0021E251 /* SelectPreferenceView.swift in Sources */,
C471E8D928F9BB8F0021E251 /* HotkeyPreferenceView.swift in Sources */, C471E8D928F9BB8F0021E251 /* HotkeyPreferenceView.swift in Sources */,
C4611E5D2AEAD2FA0010BE24 /* ConfigManagerView.swift in Sources */,
C471E8DA28F9BB8F0021E251 /* Keys.swift in Sources */, C471E8DA28F9BB8F0021E251 /* Keys.swift in Sources */,
C471E8DB28F9BB8F0021E251 /* TerminalProgressWindowController.swift in Sources */, C471E8DB28F9BB8F0021E251 /* TerminalProgressWindowController.swift in Sources */,
C471E8DC28F9BB8F0021E251 /* ProgressVC.swift in Sources */, C471E8DC28F9BB8F0021E251 /* ProgressVC.swift in Sources */,
C490E3BF29BCA376006D2DE6 /* Measurements.swift in Sources */, C490E3BF29BCA376006D2DE6 /* Measurements.swift in Sources */,
C471E8DE28F9BB8F0021E251 /* App+ConfigWatch.swift in Sources */, C471E8DE28F9BB8F0021E251 /* App+ConfigWatch.swift in Sources */,
C471E8DF28F9BB8F0021E251 /* PhpConfigWatcher.swift in Sources */, C471E8DF28F9BB8F0021E251 /* ConfigWatchManager.swift in Sources */,
C4CB250529B28BB800CA4492 /* MainMenuTest.swift in Sources */, C4CB250529B28BB800CA4492 /* MainMenuTest.swift in Sources */,
C40D72622A018AE30054A067 /* BrewFormula+UI.swift in Sources */, C40D72622A018AE30054A067 /* BrewFormula+UI.swift in Sources */,
C4B79ECE29CA475900A483EE /* RemovePhpVersionCommand.swift in Sources */, C4B79ECE29CA475900A483EE /* RemovePhpVersionCommand.swift in Sources */,
@ -2904,6 +2930,7 @@
C471E7F628F9BAC80021E251 /* PhpHelper.swift in Sources */, C471E7F628F9BAC80021E251 /* PhpHelper.swift in Sources */,
C471E7EE28F9BAC30021E251 /* Constants.swift in Sources */, C471E7EE28F9BAC30021E251 /* Constants.swift in Sources */,
C40934A0298EE8E900D25014 /* AppUpdater.swift in Sources */, C40934A0298EE8E900D25014 /* AppUpdater.swift in Sources */,
C4611E5A2AEAD2E20010BE24 /* ConfigManagerWindowController.swift in Sources */,
C471E80E28F9BAE80021E251 /* DateExtension.swift in Sources */, C471E80E28F9BAE80021E251 /* DateExtension.swift in Sources */,
C490E3BA29BCA368006D2DE6 /* App+BrewWatch.swift in Sources */, C490E3BA29BCA368006D2DE6 /* App+BrewWatch.swift in Sources */,
C471E7D028F9BA630021E251 /* FileSystemProtocol.swift in Sources */, C471E7D028F9BA630021E251 /* FileSystemProtocol.swift in Sources */,
@ -2919,7 +2946,7 @@
C48DDD1029C75C9E00D032D9 /* BlockingOverlayView.swift in Sources */, C48DDD1029C75C9E00D032D9 /* BlockingOverlayView.swift in Sources */,
C471E7F828F9BACB0021E251 /* InternalSwitcher.swift in Sources */, C471E7F828F9BACB0021E251 /* InternalSwitcher.swift in Sources */,
C471E82328F9BB2E0021E251 /* ComposerJson.swift in Sources */, C471E82328F9BB2E0021E251 /* ComposerJson.swift in Sources */,
C471E82128F9BB2E0021E251 /* PhpFrameworks.swift in Sources */, C471E82128F9BB2E0021E251 /* ProjectTypeDetection.swift in Sources */,
C471E7EF28F9BAC30021E251 /* Actions.swift in Sources */, C471E7EF28F9BAC30021E251 /* Actions.swift in Sources */,
C471E82228F9BB2E0021E251 /* ComposerWindow.swift in Sources */, C471E82228F9BB2E0021E251 /* ComposerWindow.swift in Sources */,
C4D3660E29113F20006BD146 /* System.swift in Sources */, C4D3660E29113F20006BD146 /* System.swift in Sources */,
@ -2951,6 +2978,7 @@
C471E7EB28F9BAC30021E251 /* Helpers.swift in Sources */, C471E7EB28F9BAC30021E251 /* Helpers.swift in Sources */,
C4CB6E68292C362C002E9027 /* Homebrew.swift in Sources */, C4CB6E68292C362C002E9027 /* Homebrew.swift in Sources */,
C4181F1128FAF9330042EA28 /* UITestCase.swift in Sources */, C4181F1128FAF9330042EA28 /* UITestCase.swift in Sources */,
C4611E622AEAD3110010BE24 /* ByteLimitView.swift in Sources */,
C4AFC4B129C4F32F00BF4E0D /* BrewFormula.swift in Sources */, C4AFC4B129C4F32F00BF4E0D /* BrewFormula.swift in Sources */,
C471E81F28F9BB290021E251 /* NginxConfigurationFile.swift in Sources */, C471E81F28F9BB290021E251 /* NginxConfigurationFile.swift in Sources */,
C471E7BF28F9B90F0021E251 /* StartupTest.swift in Sources */, C471E7BF28F9B90F0021E251 /* StartupTest.swift in Sources */,
@ -3014,7 +3042,7 @@
C43A8A2425D9D20D00591B77 /* HomebrewPackageTest.swift in Sources */, C43A8A2425D9D20D00591B77 /* HomebrewPackageTest.swift in Sources */,
C485707928BF456C00539B36 /* ArrayExtension.swift in Sources */, C485707928BF456C00539B36 /* ArrayExtension.swift in Sources */,
C4F780CA25D80B75000DBC97 /* HomebrewDecodable.swift in Sources */, C4F780CA25D80B75000DBC97 /* HomebrewDecodable.swift in Sources */,
C4C8E81C276F54E5003AC782 /* PhpConfigWatcher.swift in Sources */, C4C8E81C276F54E5003AC782 /* ConfigWatchManager.swift in Sources */,
C4F319C927B034A500AFF46F /* Stats.swift in Sources */, C4F319C927B034A500AFF46F /* Stats.swift in Sources */,
C4F30B04278E16BA00755FCE /* HomebrewService.swift in Sources */, C4F30B04278E16BA00755FCE /* HomebrewService.swift in Sources */,
54D9E0B527E4F51E003B9AD9 /* Key.swift in Sources */, 54D9E0B527E4F51E003B9AD9 /* Key.swift in Sources */,
@ -3030,6 +3058,7 @@
C4CCBA6D275C567B008C7055 /* PMWindowController.swift in Sources */, C4CCBA6D275C567B008C7055 /* PMWindowController.swift in Sources */,
C4B5635F276AB09000F12CCB /* VersionExtractor.swift in Sources */, C4B5635F276AB09000F12CCB /* VersionExtractor.swift in Sources */,
C463E381284930EE00422731 /* PresetHelper.swift in Sources */, C463E381284930EE00422731 /* PresetHelper.swift in Sources */,
C441CC572AE8249400DDFACD /* ConfigFSNotifier.swift in Sources */,
C46FA98C2822F08F00D78807 /* PhpConfigurationFileTest.swift in Sources */, C46FA98C2822F08F00D78807 /* PhpConfigurationFileTest.swift in Sources */,
C4D5576529C77CC5001A44CD /* PhpVersionManagerWindowController.swift in Sources */, C4D5576529C77CC5001A44CD /* PhpVersionManagerWindowController.swift in Sources */,
C4BF90C127C57C220054E78C /* MainMenu+FixMyValet.swift in Sources */, C4BF90C127C57C220054E78C /* MainMenu+FixMyValet.swift in Sources */,
@ -3037,6 +3066,7 @@
C4F2E4382752F08D0020E974 /* BrewDiagnostics.swift in Sources */, C4F2E4382752F08D0020E974 /* BrewDiagnostics.swift in Sources */,
C485707428BF454E00539B36 /* ServicesView.swift in Sources */, C485707428BF454E00539B36 /* ServicesView.swift in Sources */,
C4B79EC729CA474200A483EE /* FakeCommand.swift in Sources */, C4B79EC729CA474200A483EE /* FakeCommand.swift in Sources */,
C4611E5F2AEAD2FB0010BE24 /* ConfigManagerView.swift in Sources */,
C4F780AE25D80B37000DBC97 /* PhpExtensionTest.swift in Sources */, C4F780AE25D80B37000DBC97 /* PhpExtensionTest.swift in Sources */,
C456A0C72AA614BD0080144F /* PhpPreference.swift in Sources */, C456A0C72AA614BD0080144F /* PhpPreference.swift in Sources */,
C4C8E819276F54D8003AC782 /* App+ConfigWatch.swift in Sources */, C4C8E819276F54D8003AC782 /* App+ConfigWatch.swift in Sources */,
@ -3077,6 +3107,7 @@
C4E49DEE28F764A00026AC4E /* TestableCommand.swift in Sources */, C4E49DEE28F764A00026AC4E /* TestableCommand.swift in Sources */,
C4AF9F78275447F100D44ED0 /* ValetConfigurationTest.swift in Sources */, C4AF9F78275447F100D44ED0 /* ValetConfigurationTest.swift in Sources */,
C490E3B529BC9FEA006D2DE6 /* ProgressWindowView.swift in Sources */, C490E3B529BC9FEA006D2DE6 /* ProgressWindowView.swift in Sources */,
C4611E612AEAD3110010BE24 /* ByteLimitView.swift in Sources */,
C40175B92903108900763A68 /* ValetInteractor.swift in Sources */, C40175B92903108900763A68 /* ValetInteractor.swift in Sources */,
C4CE3BBC27B324250086CA49 /* ComposerWindow.swift in Sources */, C4CE3BBC27B324250086CA49 /* ComposerWindow.swift in Sources */,
C40B24F427A310830018C7D2 /* StatusMenu.swift in Sources */, C40B24F427A310830018C7D2 /* StatusMenu.swift in Sources */,
@ -3105,6 +3136,7 @@
C4D936CA27E3EB6100BD69FE /* PhpHelper.swift in Sources */, C4D936CA27E3EB6100BD69FE /* PhpHelper.swift in Sources */,
C4D36611291140BE006BD146 /* TestableFileSystemTest.swift in Sources */, C4D36611291140BE006BD146 /* TestableFileSystemTest.swift in Sources */,
C45B91542956123A00F4EC78 /* FakeServicesManager.swift in Sources */, C45B91542956123A00F4EC78 /* FakeServicesManager.swift in Sources */,
C4611E5C2AEAD2E30010BE24 /* ConfigManagerWindowController.swift in Sources */,
C4E2E84B28FC1E70003B070C /* DataExtension.swift in Sources */, C4E2E84B28FC1E70003B070C /* DataExtension.swift in Sources */,
C449B4F127EE7FC200C47E8A /* DomainListNameCell.swift in Sources */, C449B4F127EE7FC200C47E8A /* DomainListNameCell.swift in Sources */,
C4F780BA25D80B62000DBC97 /* AppDelegate.swift in Sources */, C4F780BA25D80B62000DBC97 /* AppDelegate.swift in Sources */,
@ -3117,7 +3149,7 @@
C44C198E276E3A1C0072762D /* TerminalProgressWindowController.swift in Sources */, C44C198E276E3A1C0072762D /* TerminalProgressWindowController.swift in Sources */,
C4B79EBD29CA38DB00A483EE /* BrewCommand.swift in Sources */, C4B79EBD29CA38DB00A483EE /* BrewCommand.swift in Sources */,
C485707828BF456300539B36 /* Warning.swift in Sources */, C485707828BF456300539B36 /* Warning.swift in Sources */,
C415938027A1B54F00D2E1B7 /* PhpFrameworks.swift in Sources */, C415938027A1B54F00D2E1B7 /* ProjectTypeDetection.swift in Sources */,
C40F505628ECA64E004AD45B /* TestableConfigurations.swift in Sources */, C40F505628ECA64E004AD45B /* TestableConfigurations.swift in Sources */,
C4D9ADC9277611A0007277F4 /* InternalSwitcher.swift in Sources */, C4D9ADC9277611A0007277F4 /* InternalSwitcher.swift in Sources */,
C449B4F227EE7FC400C47E8A /* DomainListPhpCell.swift in Sources */, C449B4F227EE7FC400C47E8A /* DomainListPhpCell.swift in Sources */,
@ -3488,7 +3520,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 = 1306; CURRENT_PROJECT_VERSION = 1340;
DEAD_CODE_STRIPPING = YES; DEAD_CODE_STRIPPING = YES;
DEBUG = YES; DEBUG = YES;
DEVELOPMENT_TEAM = 8M54J5J787; DEVELOPMENT_TEAM = 8M54J5J787;
@ -3501,7 +3533,7 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 12.4; MACOSX_DEPLOYMENT_TARGET = 12.4;
MARKETING_VERSION = 6.1; MARKETING_VERSION = 6.2;
PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon; PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon;
PRODUCT_MODULE_NAME = PHP_Monitor; PRODUCT_MODULE_NAME = PHP_Monitor;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
@ -3519,7 +3551,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 = 1306; CURRENT_PROJECT_VERSION = 1340;
DEAD_CODE_STRIPPING = YES; DEAD_CODE_STRIPPING = YES;
DEBUG = NO; DEBUG = NO;
DEVELOPMENT_TEAM = 8M54J5J787; DEVELOPMENT_TEAM = 8M54J5J787;
@ -3532,7 +3564,7 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 12.4; MACOSX_DEPLOYMENT_TARGET = 12.4;
MARKETING_VERSION = 6.1; MARKETING_VERSION = 6.2;
PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon; PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon;
PRODUCT_MODULE_NAME = PHP_Monitor; PRODUCT_MODULE_NAME = PHP_Monitor;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
@ -3759,7 +3791,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 = 1306; CURRENT_PROJECT_VERSION = 1340;
DEAD_CODE_STRIPPING = YES; DEAD_CODE_STRIPPING = YES;
DEBUG = NO; DEBUG = NO;
DEVELOPMENT_TEAM = 8M54J5J787; DEVELOPMENT_TEAM = 8M54J5J787;
@ -3772,7 +3804,7 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 12.4; MACOSX_DEPLOYMENT_TARGET = 12.4;
MARKETING_VERSION = 6.1; MARKETING_VERSION = 6.2;
PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon.dev; PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon.dev;
PRODUCT_MODULE_NAME = PHP_Monitor; PRODUCT_MODULE_NAME = PHP_Monitor;
PRODUCT_NAME = "$(TARGET_NAME) DEV"; PRODUCT_NAME = "$(TARGET_NAME) DEV";
@ -3875,7 +3907,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 = 1306; CURRENT_PROJECT_VERSION = 1340;
DEAD_CODE_STRIPPING = YES; DEAD_CODE_STRIPPING = YES;
DEBUG = YES; DEBUG = YES;
DEVELOPMENT_TEAM = 8M54J5J787; DEVELOPMENT_TEAM = 8M54J5J787;
@ -3888,7 +3920,7 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 12.4; MACOSX_DEPLOYMENT_TARGET = 12.4;
MARKETING_VERSION = 6.1; MARKETING_VERSION = 6.2;
PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon.dev; PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon.dev;
PRODUCT_MODULE_NAME = PHP_Monitor; PRODUCT_MODULE_NAME = PHP_Monitor;
PRODUCT_NAME = "$(TARGET_NAME) DEV"; PRODUCT_NAME = "$(TARGET_NAME) DEV";
@ -3991,7 +4023,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 = 1306; CURRENT_PROJECT_VERSION = 1340;
DEAD_CODE_STRIPPING = YES; DEAD_CODE_STRIPPING = YES;
DEBUG = YES; DEBUG = YES;
DEVELOPMENT_TEAM = 8M54J5J787; DEVELOPMENT_TEAM = 8M54J5J787;
@ -4004,7 +4036,7 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 12.4; MACOSX_DEPLOYMENT_TARGET = 12.4;
MARKETING_VERSION = 6.1; MARKETING_VERSION = 6.2;
PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon.eap; PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon.eap;
PRODUCT_MODULE_NAME = PHP_Monitor; PRODUCT_MODULE_NAME = PHP_Monitor;
PRODUCT_NAME = "$(TARGET_NAME) EAP"; PRODUCT_NAME = "$(TARGET_NAME) EAP";
@ -4172,7 +4204,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 = 1306; CURRENT_PROJECT_VERSION = 1340;
DEAD_CODE_STRIPPING = YES; DEAD_CODE_STRIPPING = YES;
DEBUG = NO; DEBUG = NO;
DEVELOPMENT_TEAM = 8M54J5J787; DEVELOPMENT_TEAM = 8M54J5J787;
@ -4185,7 +4217,7 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 12.4; MACOSX_DEPLOYMENT_TARGET = 12.4;
MARKETING_VERSION = 6.1; MARKETING_VERSION = 6.2;
PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon.eap; PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon.eap;
PRODUCT_MODULE_NAME = PHP_Monitor; PRODUCT_MODULE_NAME = PHP_Monitor;
PRODUCT_NAME = "$(TARGET_NAME) EAP"; PRODUCT_NAME = "$(TARGET_NAME) EAP";

View File

@ -17,6 +17,7 @@ public class Paths {
internal var baseDir: Paths.HomebrewDir internal var baseDir: Paths.HomebrewDir
private var userName: String private var userName: String
private var preferredShell: String
init() { init() {
// Assume the default directory is correct // Assume the default directory is correct
@ -31,9 +32,11 @@ public class Paths {
} }
userName = identity() userName = identity()
preferredShell = preferred_shell()
if !isRunningSwiftUIPreview { if !isRunningSwiftUIPreview {
Log.info("The current username is `\(userName)`.") Log.info("The current username is `\(userName)`.")
Log.info("The user's shell is `\(preferredShell)`.")
} }
} }
@ -104,6 +107,10 @@ public class Paths {
+ (App.identifier.contains(".dev") ? "phpmon-dev" : "phpmon") + (App.identifier.contains(".dev") ? "phpmon-dev" : "phpmon")
} }
public static var shell: String {
return shared.preferredShell
}
// MARK: - Flexible Binaries // MARK: - Flexible Binaries
// (these can be in multiple locations, so we scan common places because) // (these can be in multiple locations, so we scan common places because)
// (PHP Monitor will not use the user's own PATH) // (PHP Monitor will not use the user's own PATH)

View File

@ -37,7 +37,7 @@ class PMWindowController: NSWindowController, NSWindowDelegate {
extension NSWindowController { extension NSWindowController {
public func positionWindowInTopLeftCorner(offsetY: CGFloat = 0, offsetX: CGFloat = 0) { public func positionWindowInTopRightCorner(offsetY: CGFloat = 0, offsetX: CGFloat = 0) {
guard let frame = NSScreen.main?.frame else { return } guard let frame = NSScreen.main?.frame else { return }
guard let window = self.window else { return } guard let window = self.window else { return }

View File

@ -65,3 +65,11 @@ public func identity() -> String {
return output.trimmingCharacters(in: .whitespacesAndNewlines) return output.trimmingCharacters(in: .whitespacesAndNewlines)
} }
/**
Retrieves the user's preferred shell.
*/
public func preferred_shell() -> String {
return system("dscl . -read ~/ UserShell | sed 's/UserShell: //'")
.trimmingCharacters(in: .whitespacesAndNewlines)
}

View File

@ -49,8 +49,10 @@ class PhpHelper {
let path = URL(fileURLWithPath: "\(Paths.optPath)/php@\(version)/bin") let path = URL(fileURLWithPath: "\(Paths.optPath)/php@\(version)/bin")
.resolvingSymlinksInPath().path .resolvingSymlinksInPath().path
// The contents of the script! // Check if the user uses Fish
let script = script(path, keyPhrase, version, dotless) let script = Paths.shell.contains("/fish")
? fishScript(path, keyPhrase, version, dotless)
: zshScript(path, keyPhrase, version, dotless)
Task { @MainActor in Task { @MainActor in
try FileSystem.writeAtomicallyToFile(destination, content: script) try FileSystem.writeAtomicallyToFile(destination, content: script)
@ -78,7 +80,7 @@ class PhpHelper {
} }
} }
private static func script( private static func zshScript(
_ path: String, _ path: String,
_ keyPhrase: String, _ keyPhrase: String,
_ version: String, _ version: String,
@ -96,6 +98,22 @@ class PhpHelper {
""" """
} }
private static func fishScript(
_ path: String,
_ keyPhrase: String,
_ version: String,
_ dotless: String
) -> String {
return """
#!\(Paths.binPath)/fish
# \(keyPhrase)
# It reflects the location of PHP \(version)'s binaries on your system.
# Usage: . pm\(dotless)
echo "PHP Monitor has enabled this terminal to use PHP \(version)."; \\
set -x PATH \(path) $PATH
"""
}
private static func createSymlink(_ dotless: String) async { private static func createSymlink(_ dotless: String) async {
let source = "\(Paths.homePath)/.config/phpmon/bin/pm\(dotless)" let source = "\(Paths.homePath)/.config/phpmon/bin/pm\(dotless)"
let destination = "/usr/local/bin/pm\(dotless)" let destination = "/usr/local/bin/pm\(dotless)"

View File

@ -69,8 +69,9 @@ class PhpConfigurationFile: CreatedFromFile {
return nil return nil
} }
enum ReplacementErrors: Error { public enum ReplacementErrors: Error {
case missingKey case missingKey
case missingFile
} }
/** /**
@ -95,10 +96,16 @@ class PhpConfigurationFile: CreatedFromFile {
// Replace the specific line // Replace the specific line
self.lines[item.lineIndex] = components.joined(separator: "=") self.lines[item.lineIndex] = components.joined(separator: "=")
// Ensure the watchers aren't tripped up by config changes
ConfigWatchManager.ignoresModificationsToConfigValues = true
// Finally, join the string and save the file atomatically again // Finally, join the string and save the file atomatically again
try self.lines.joined(separator: "\n") try self.lines.joined(separator: "\n")
.write(toFile: self.filePath, atomically: true, encoding: .utf8) .write(toFile: self.filePath, atomically: true, encoding: .utf8)
// Ensure watcher behaviour is reverted
ConfigWatchManager.ignoresModificationsToConfigValues = false
// Reload the original file // Reload the original file
self.reload() self.reload()
} }

View File

@ -43,6 +43,7 @@ public struct TestableConfiguration: Codable {
private var primaryPhpVersion: VersionNumber? private var primaryPhpVersion: VersionNumber?
private var secondaryPhpVersions: [VersionNumber] = [] private var secondaryPhpVersions: [VersionNumber] = []
// swiftlint:disable function_body_length
mutating func addPhpVersion(_ version: VersionNumber, primary: Bool) { mutating func addPhpVersion(_ version: VersionNumber, primary: Bool) {
if primary { if primary {
if primaryPhpVersion != nil { if primaryPhpVersion != nil {

View File

@ -46,8 +46,10 @@ extension App {
} }
hotkey.keyDownHandler = { hotkey.keyDownHandler = {
MainMenu.shared.statusItem.button?.performClick(nil) Task { @MainActor in
NSApplication.shared.activate(ignoringOtherApps: true) MainMenu.shared.statusItem.button?.performClick(nil)
NSApplication.shared.activate(ignoringOtherApps: true)
}
} }
} }

View File

@ -74,10 +74,13 @@ class App {
/** The window controller of the onboarding window. */ /** The window controller of the onboarding window. */
var onboardingWindowController: OnboardingWindowController? var onboardingWindowController: OnboardingWindowController?
/** The window controller of the config manager window. */
var phpConfigManagerWindowController: PhpConfigManagerWindowController?
/** The window controller of the warnings window. */ /** The window controller of the warnings window. */
var phpDoctorWindowController: PhpDoctorWindowController? var phpDoctorWindowController: PhpDoctorWindowController?
/** The window controller of the warnings window. */ /** The window controller of the PHP version manager window. */
var phpVersionManagerWindowController: PhpVersionManagerWindowController? var phpVersionManagerWindowController: PhpVersionManagerWindowController?
/** List of detected (installed) applications that PHP Monitor can work with. */ /** List of detected (installed) applications that PHP Monitor can work with. */
@ -86,9 +89,6 @@ class App {
/** The warning manager, responsible for keeping track of warnings. */ /** The warning manager, responsible for keeping track of warnings. */
var warnings = WarningManager.shared var warnings = WarningManager.shared
/** The filesystem watchers, responsible for keeping track of changes to the PHP installation. */
var watchers: [FSNotifier.Kind: FSNotifier] = [:]
/** Timer that will periodically reload info about the user's PHP installation. */ /** Timer that will periodically reload info about the user's PHP installation. */
var timer: Timer? var timer: Timer?
@ -117,8 +117,12 @@ class App {
// MARK: - App Watchers // MARK: - App Watchers
/** /** Individual filesystem watchers, which are, i.e. responsible for watching the Homebrew folders. */
The `PhpConfigWatcher` is responsible for watching the `.ini` files and the `.conf.d` folder. var watchers: [String: FSNotifier] = [:]
/**
The `ConfigWatchManager` is responsible for watching the `.ini` files and the `.conf.d` folder.
This manager object can immediately start or stop all watchers (or pause them) all at once.
*/ */
var watcher: PhpConfigWatcher! var watchManager: ConfigWatchManager!
} }

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="21701" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES"> <document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="22155" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies> <dependencies>
<deployment identifier="macosx"/> <deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="21701"/> <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="22155"/>
<capability name="Image references" minToolsVersion="12.0"/> <capability name="Image references" minToolsVersion="12.0"/>
<capability name="Named colors" minToolsVersion="9.0"/> <capability name="Named colors" minToolsVersion="9.0"/>
<capability name="Search Toolbar Item" minToolsVersion="12.0" minSystemVersion="11.0"/> <capability name="Search Toolbar Item" minToolsVersion="12.0" minSystemVersion="11.0"/>
@ -429,7 +429,7 @@
</toolbarItem> </toolbarItem>
<searchToolbarItem implicitItemIdentifier="7C834FBE-7118-4082-A09F-7CBECEC1356A" label="Search" paletteLabel="Search" visibilityPriority="1001" id="G2g-jS-RVc"> <searchToolbarItem implicitItemIdentifier="7C834FBE-7118-4082-A09F-7CBECEC1356A" label="Search" paletteLabel="Search" visibilityPriority="1001" id="G2g-jS-RVc">
<nil key="toolTip"/> <nil key="toolTip"/>
<searchField key="view" verticalHuggingPriority="750" textCompletion="NO" id="0gE-Yr-MLy"> <searchField key="view" focusRingType="none" verticalHuggingPriority="750" textCompletion="NO" id="0gE-Yr-MLy">
<rect key="frame" x="0.0" y="0.0" width="100" height="21"/> <rect key="frame" x="0.0" y="0.0" width="100" height="21"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<searchFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" usesSingleLineMode="YES" bezelStyle="round" sendsSearchStringImmediately="YES" id="vp9-vH-goQ"> <searchFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" usesSingleLineMode="YES" bezelStyle="round" sendsSearchStringImmediately="YES" id="vp9-vH-goQ">
@ -521,9 +521,6 @@
<subviews> <subviews>
<button wantsLayer="YES" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="8zu-cF-KCX"> <button wantsLayer="YES" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="8zu-cF-KCX">
<rect key="frame" x="383" y="13" width="104" height="32"/> <rect key="frame" x="383" y="13" width="104" height="32"/>
<constraints>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="90" id="4Uf-fh-jWJ"/>
</constraints>
<buttonCell key="cell" type="push" title="Primary" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="F26-vf-hFH"> <buttonCell key="cell" type="push" title="Primary" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="F26-vf-hFH">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/> <font key="font" metaFont="system"/>
@ -531,15 +528,15 @@
DQ DQ
</string> </string>
</buttonCell> </buttonCell>
<constraints>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="90" id="4Uf-fh-jWJ"/>
</constraints>
<connections> <connections>
<action selector="primaryButtonAction:" target="hkw-9V-NxP" id="W7d-3b-pZT"/> <action selector="primaryButtonAction:" target="hkw-9V-NxP" id="W7d-3b-pZT"/>
</connections> </connections>
</button> </button>
<button wantsLayer="YES" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="TCp-nS-HN2"> <button wantsLayer="YES" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="TCp-nS-HN2">
<rect key="frame" x="281" y="13" width="104" height="32"/> <rect key="frame" x="281" y="13" width="104" height="32"/>
<constraints>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="90" id="QWZ-BA-0g9"/>
</constraints>
<buttonCell key="cell" type="push" title="Secondary" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="eCk-FC-9Zr"> <buttonCell key="cell" type="push" title="Secondary" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="eCk-FC-9Zr">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/> <font key="font" metaFont="system"/>
@ -547,6 +544,9 @@ DQ
Gw Gw
</string> </string>
</buttonCell> </buttonCell>
<constraints>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="90" id="QWZ-BA-0g9"/>
</constraints>
<connections> <connections>
<action selector="secondaryButtonAction:" target="hkw-9V-NxP" id="YJs-Hu-lFP"/> <action selector="secondaryButtonAction:" target="hkw-9V-NxP" id="YJs-Hu-lFP"/>
</connections> </connections>
@ -575,7 +575,7 @@ Gw
<constraint firstAttribute="bottom" secondItem="8zu-cF-KCX" secondAttribute="bottom" constant="20" symbolic="YES" id="wIl-uw-y3p"/> <constraint firstAttribute="bottom" secondItem="8zu-cF-KCX" secondAttribute="bottom" constant="20" symbolic="YES" id="wIl-uw-y3p"/>
</constraints> </constraints>
</visualEffectView> </visualEffectView>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="U1c-qS-cIm"> <textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="U1c-qS-cIm">
<rect key="frame" x="98" y="153" width="384" height="19"/> <rect key="frame" x="98" y="153" width="384" height="19"/>
<constraints> <constraints>
<constraint firstAttribute="width" relation="lessThanOrEqual" constant="380" id="WgB-hj-d4P"/> <constraint firstAttribute="width" relation="lessThanOrEqual" constant="380" id="WgB-hj-d4P"/>
@ -586,7 +586,7 @@ Gw
<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="yI6-qf-htf"> <textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="yI6-qf-htf">
<rect key="frame" x="98" y="127" width="384" height="16"/> <rect key="frame" x="98" y="127" width="384" height="16"/>
<textFieldCell key="cell" selectable="YES" title="This is a slightly more expanded explanation." id="rY3-Nd-Iit"> <textFieldCell key="cell" selectable="YES" title="This is a slightly more expanded explanation." id="rY3-Nd-Iit">
<font key="font" metaFont="system"/> <font key="font" metaFont="system"/>
@ -610,7 +610,7 @@ Gw
</constraints> </constraints>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" id="7eT-Hw-EL9"/> <imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" id="7eT-Hw-EL9"/>
</imageView> </imageView>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="hml-dl-Cah"> <textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="hml-dl-Cah">
<rect key="frame" x="98" y="70" width="384" height="42"/> <rect key="frame" x="98" y="70" width="384" height="42"/>
<textFieldCell key="cell" selectable="YES" id="7iW-Lc-DqO"> <textFieldCell key="cell" selectable="YES" id="7iW-Lc-DqO">
<font key="font" metaFont="smallSystem"/> <font key="font" metaFont="smallSystem"/>
@ -685,9 +685,6 @@ DQ
</button> </button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="SwS-o8-pbl"> <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="SwS-o8-pbl">
<rect key="frame" x="13" y="13" width="114" height="32"/> <rect key="frame" x="13" y="13" width="114" height="32"/>
<constraints>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="80" id="qCP-Sp-gxm"/>
</constraints>
<buttonCell key="cell" type="push" title="[i18n] Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="WHE-HW-jwp"> <buttonCell key="cell" type="push" title="[i18n] Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="WHE-HW-jwp">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/> <font key="font" metaFont="system"/>
@ -695,11 +692,14 @@ DQ
Gw Gw
</string> </string>
</buttonCell> </buttonCell>
<constraints>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="80" id="qCP-Sp-gxm"/>
</constraints>
<connections> <connections>
<action selector="pressedCancel:" target="glS-wF-sEU" id="q0L-YZ-F3J"/> <action selector="pressedCancel:" target="glS-wF-sEU" id="q0L-YZ-F3J"/>
</connections> </connections>
</button> </button>
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="ZX9-s1-23i"> <textField focusRingType="none" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="ZX9-s1-23i">
<rect key="frame" x="20" y="150" width="440" height="21"/> <rect key="frame" x="20" y="150" width="440" height="21"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" placeholderString="Enter a domain name here." drawsBackground="YES" id="NFa-1D-Bi4"> <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" placeholderString="Enter a domain name here." drawsBackground="YES" id="NFa-1D-Bi4">
<font key="font" metaFont="system"/> <font key="font" metaFont="system"/>
@ -710,7 +710,7 @@ Gw
<outlet property="delegate" destination="glS-wF-sEU" id="Dyf-0M-Gwj"/> <outlet property="delegate" destination="glS-wF-sEU" id="Dyf-0M-Gwj"/>
</connections> </connections>
</textField> </textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="VzR-5a-cmT"> <textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="VzR-5a-cmT">
<rect key="frame" x="18" y="128" width="444" height="14"/> <rect key="frame" x="18" y="128" width="444" height="14"/>
<textFieldCell key="cell" title="[i18n] Preview text here" id="bJr-s6-tdP"> <textFieldCell key="cell" title="[i18n] Preview text here" id="bJr-s6-tdP">
<font key="font" metaFont="smallSystem"/> <font key="font" metaFont="smallSystem"/>
@ -728,7 +728,7 @@ Gw
<action selector="pressedSecure:" target="glS-wF-sEU" id="OIj-Pz-5Ea"/> <action selector="pressedSecure:" target="glS-wF-sEU" id="OIj-Pz-5Ea"/>
</connections> </connections>
</button> </button>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="mmQ-7e-dlb"> <textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="mmQ-7e-dlb">
<rect key="frame" x="18" y="60" width="444" height="28"/> <rect key="frame" x="18" y="60" width="444" height="28"/>
<textFieldCell key="cell" title="[i18n] Securing a domain requires administrative privileges. You may be prompted for your password or Touch ID." id="4gd-KM-5Fu"> <textFieldCell key="cell" title="[i18n] Securing a domain requires administrative privileges. You may be prompted for your password or Touch ID." id="4gd-KM-5Fu">
<font key="font" metaFont="smallSystem"/> <font key="font" metaFont="smallSystem"/>
@ -743,7 +743,7 @@ Gw
<url key="url" string="file:///Users/"/> <url key="url" string="file:///Users/"/>
</pathCell> </pathCell>
</pathControl> </pathControl>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="P0B-Ht-R8n"> <textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="P0B-Ht-R8n">
<rect key="frame" x="18" y="209" width="128" height="16"/> <rect key="frame" x="18" y="209" width="128" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="[i18n] Link a Folder" id="S4j-ZC-ddT"> <textFieldCell key="cell" lineBreakMode="clipping" title="[i18n] Link a Folder" id="S4j-ZC-ddT">
<font key="font" textStyle="headline" name=".SFNS-Bold"/> <font key="font" textStyle="headline" name=".SFNS-Bold"/>
@ -751,7 +751,7 @@ Gw
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell> </textFieldCell>
</textField> </textField>
<textField hidden="YES" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="900-Z2-tID"> <textField hidden="YES" focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="900-Z2-tID">
<rect key="frame" x="140" y="23" width="180" height="14"/> <rect key="frame" x="140" y="23" width="180" height="14"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="That domain name already exists." id="jOt-n6-TQf"> <textFieldCell key="cell" lineBreakMode="clipping" title="That domain name already exists." id="jOt-n6-TQf">
<font key="font" metaFont="smallSystem"/> <font key="font" metaFont="smallSystem"/>
@ -886,7 +886,7 @@ Gw
<rect key="frame" x="69" y="0.0" width="200" height="54"/> <rect key="frame" x="69" y="0.0" width="200" height="54"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews> <subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="XJL-Uw-frD"> <textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="XJL-Uw-frD">
<rect key="frame" x="3" y="26" width="145" height="16"/> <rect key="frame" x="3" y="26" width="145" height="16"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="my-domain-name.test" id="SGC-Gm-Mxd"> <textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="my-domain-name.test" id="SGC-Gm-Mxd">
<font key="font" metaFont="systemSemibold" size="13"/> <font key="font" metaFont="systemSemibold" size="13"/>
@ -894,7 +894,7 @@ Gw
<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" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="CXK-Q9-CpO"> <textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="CXK-Q9-CpO">
<rect key="frame" x="3" y="12" width="75" height="14"/> <rect key="frame" x="3" y="12" width="75" height="14"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="~/path/to/site" id="fe7-Ha-mR9"> <textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="~/path/to/site" id="fe7-Ha-mR9">
<font key="font" metaFont="smallSystem"/> <font key="font" metaFont="smallSystem"/>
@ -937,13 +937,13 @@ Gw
<subviews> <subviews>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="ZXQ-bg-Xba"> <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="ZXQ-bg-Xba">
<rect key="frame" x="27" y="18" width="70" height="18"/> <rect key="frame" x="27" y="18" width="70" height="18"/>
<constraints>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="70" id="MBa-bB-DTB"/>
</constraints>
<buttonCell key="cell" type="inline" title="PHP X.X" bezelStyle="inline" alignment="center" borderStyle="border" inset="2" id="Tfk-YR-L4B"> <buttonCell key="cell" type="inline" title="PHP X.X" bezelStyle="inline" alignment="center" borderStyle="border" inset="2" id="Tfk-YR-L4B">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="smallSystemBold"/> <font key="font" metaFont="smallSystemBold"/>
</buttonCell> </buttonCell>
<constraints>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="70" id="MBa-bB-DTB"/>
</constraints>
<connections> <connections>
<action selector="pressedPhpVersion:" target="T49-0U-d58" id="jVO-TS-F6d"/> <action selector="pressedPhpVersion:" target="T49-0U-d58" id="jVO-TS-F6d"/>
</connections> </connections>
@ -987,11 +987,11 @@ Gw
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/> <tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<prototypeCellViews> <prototypeCellViews>
<tableCellView identifier="domainListKindCell" wantsLayer="YES" id="AhT-xR-16a" customClass="DomainListKindCell" customModule="PHP_Monitor" customModuleProvider="target"> <tableCellView identifier="domainListKindCell" wantsLayer="YES" id="AhT-xR-16a" customClass="DomainListKindCell" customModule="PHP_Monitor" customModuleProvider="target">
<rect key="frame" x="403" y="0.0" width="48" height="54"/> <rect key="frame" x="403" y="0.0" width="50" height="54"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews> <subviews>
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="sYR-vb-OW1"> <imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="sYR-vb-OW1">
<rect key="frame" x="15" y="18" width="18" height="18"/> <rect key="frame" x="16" y="18" width="18" height="18"/>
<constraints> <constraints>
<constraint firstAttribute="width" constant="18" id="XcB-uw-szU"/> <constraint firstAttribute="width" constant="18" id="XcB-uw-szU"/>
<constraint firstAttribute="height" constant="18" id="bGN-Vh-Sh0"/> <constraint firstAttribute="height" constant="18" id="bGN-Vh-Sh0"/>
@ -1024,10 +1024,10 @@ Gw
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/> <tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<prototypeCellViews> <prototypeCellViews>
<tableCellView identifier="domainListTypeCell" wantsLayer="YES" id="ntU-Rl-ciP" customClass="DomainListTypeCell" customModule="PHP_Monitor" customModuleProvider="target"> <tableCellView identifier="domainListTypeCell" wantsLayer="YES" id="ntU-Rl-ciP" customClass="DomainListTypeCell" customModule="PHP_Monitor" customModuleProvider="target">
<rect key="frame" x="468" y="0.0" width="97" height="54"/> <rect key="frame" x="470" y="0.0" width="97" height="54"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews> <subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Ljl-8B-key"> <textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Ljl-8B-key">
<rect key="frame" x="6" y="26" width="93" height="14"/> <rect key="frame" x="6" y="26" width="93" height="14"/>
<textFieldCell key="cell" alignment="left" title="Laravel" id="0lu-L6-oKr"> <textFieldCell key="cell" alignment="left" title="Laravel" id="0lu-L6-oKr">
<font key="font" metaFont="smallSystem"/> <font key="font" metaFont="smallSystem"/>
@ -1035,7 +1035,7 @@ Gw
<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="aPK-Xc-J4B"> <textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="aPK-Xc-J4B">
<rect key="frame" x="6" y="15" width="93" height="11"/> <rect key="frame" x="6" y="15" width="93" height="11"/>
<textFieldCell key="cell" alignment="left" title="PHP 8.0" id="puf-Jh-ham"> <textFieldCell key="cell" alignment="left" title="PHP 8.0" id="puf-Jh-ham">
<font key="font" metaFont="miniSystem"/> <font key="font" metaFont="miniSystem"/>
@ -1125,7 +1125,7 @@ Gw
<rect key="frame" x="0.0" y="0.0" width="540" height="286"/> <rect key="frame" x="0.0" y="0.0" width="540" height="286"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews> <subviews>
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="QCK-Z9-w7g"> <textField focusRingType="none" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="QCK-Z9-w7g">
<rect key="frame" x="20" y="196" width="500" height="21"/> <rect key="frame" x="20" y="196" width="500" height="21"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" title="http://127.0.0.1:80" placeholderString="http://127.0.0.1:80" drawsBackground="YES" id="muS-8M-KSy"> <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" title="http://127.0.0.1:80" placeholderString="http://127.0.0.1:80" drawsBackground="YES" id="muS-8M-KSy">
<font key="font" metaFont="system"/> <font key="font" metaFont="system"/>
@ -1136,7 +1136,7 @@ Gw
<outlet property="delegate" destination="dwh-CF-6iv" id="lNE-OI-G93"/> <outlet property="delegate" destination="dwh-CF-6iv" id="lNE-OI-G93"/>
</connections> </connections>
</textField> </textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Uib-vA-HRc"> <textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Uib-vA-HRc">
<rect key="frame" x="18" y="221" width="325" height="14"/> <rect key="frame" x="18" y="221" width="325" height="14"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="[i18n] Proxy subject (usually: protocol, IP address and port)" id="G1Z-3f-BhL"> <textFieldCell key="cell" lineBreakMode="clipping" title="[i18n] Proxy subject (usually: protocol, IP address and port)" id="G1Z-3f-BhL">
<font key="font" metaFont="systemMedium" size="11"/> <font key="font" metaFont="systemMedium" size="11"/>
@ -1144,7 +1144,7 @@ Gw
<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="mlA-Zt-Hu8"> <textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="mlA-Zt-Hu8">
<rect key="frame" x="18" y="172" width="112" height="14"/> <rect key="frame" x="18" y="172" width="112" height="14"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="[i18n] Domain name" id="dQs-oZ-80e"> <textFieldCell key="cell" lineBreakMode="clipping" title="[i18n] Domain name" id="dQs-oZ-80e">
<font key="font" metaFont="systemMedium" size="11"/> <font key="font" metaFont="systemMedium" size="11"/>
@ -1152,7 +1152,7 @@ Gw
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell> </textFieldCell>
</textField> </textField>
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="SNw-oQ-bnb"> <textField focusRingType="none" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="SNw-oQ-bnb">
<rect key="frame" x="20" y="147" width="500" height="21"/> <rect key="frame" x="20" y="147" width="500" height="21"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" placeholderString="Enter a domain name here." drawsBackground="YES" id="gTQ-Y2-Y9w"> <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" placeholderString="Enter a domain name here." drawsBackground="YES" id="gTQ-Y2-Y9w">
<font key="font" metaFont="system"/> <font key="font" metaFont="system"/>
@ -1194,9 +1194,6 @@ DQ
</button> </button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="nC0-dk-QaF"> <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="nC0-dk-QaF">
<rect key="frame" x="13" y="13" width="114" height="32"/> <rect key="frame" x="13" y="13" width="114" height="32"/>
<constraints>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="80" id="uCc-fF-wS2"/>
</constraints>
<buttonCell key="cell" type="push" title="[i18n] Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="D8g-GE-7TU"> <buttonCell key="cell" type="push" title="[i18n] Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="D8g-GE-7TU">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/> <font key="font" metaFont="system"/>
@ -1204,11 +1201,14 @@ DQ
Gw Gw
</string> </string>
</buttonCell> </buttonCell>
<constraints>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="80" id="uCc-fF-wS2"/>
</constraints>
<connections> <connections>
<action selector="pressedCancel:" target="dwh-CF-6iv" id="J2T-Zj-A0j"/> <action selector="pressedCancel:" target="dwh-CF-6iv" id="J2T-Zj-A0j"/>
</connections> </connections>
</button> </button>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="JSZ-x8-Pqi"> <textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="JSZ-x8-Pqi">
<rect key="frame" x="18" y="128" width="504" height="14"/> <rect key="frame" x="18" y="128" width="504" height="14"/>
<constraints> <constraints>
<constraint firstAttribute="width" relation="lessThanOrEqual" constant="500" id="sF1-RG-URI"/> <constraint firstAttribute="width" relation="lessThanOrEqual" constant="500" id="sF1-RG-URI"/>
@ -1229,7 +1229,7 @@ Gw
<action selector="pressedSecure:" target="dwh-CF-6iv" id="b74-8T-AzO"/> <action selector="pressedSecure:" target="dwh-CF-6iv" id="b74-8T-AzO"/>
</connections> </connections>
</button> </button>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="5x7-ll-2f7"> <textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="5x7-ll-2f7">
<rect key="frame" x="18" y="60" width="504" height="28"/> <rect key="frame" x="18" y="60" width="504" height="28"/>
<textFieldCell key="cell" title="[i18n] Securing a domain requires administrative privileges. You may be prompted for your password or Touch ID." id="IMB-O5-ZOy"> <textFieldCell key="cell" title="[i18n] Securing a domain requires administrative privileges. You may be prompted for your password or Touch ID." id="IMB-O5-ZOy">
<font key="font" metaFont="smallSystem"/> <font key="font" metaFont="smallSystem"/>
@ -1237,7 +1237,7 @@ Gw
<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="DAh-br-Dfx"> <textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="DAh-br-Dfx">
<rect key="frame" x="18" y="250" width="123" height="16"/> <rect key="frame" x="18" y="250" width="123" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="[i18n] Add a Proxy" id="AZ1-04-kUl"> <textFieldCell key="cell" lineBreakMode="clipping" title="[i18n] Add a Proxy" id="AZ1-04-kUl">
<font key="font" textStyle="headline" name=".SFNS-Bold"/> <font key="font" textStyle="headline" name=".SFNS-Bold"/>
@ -1245,7 +1245,7 @@ Gw
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell> </textFieldCell>
</textField> </textField>
<textField hidden="YES" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="w0k-CK-0u4"> <textField hidden="YES" focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="w0k-CK-0u4">
<rect key="frame" x="191" y="23" width="180" height="14"/> <rect key="frame" x="191" y="23" width="180" height="14"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="That domain name already exists." id="4sH-94-UJl"> <textFieldCell key="cell" lineBreakMode="clipping" title="That domain name already exists." id="4sH-94-UJl">
<font key="font" metaFont="smallSystem"/> <font key="font" metaFont="smallSystem"/>
@ -1340,9 +1340,6 @@ Gw
<subviews> <subviews>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="FhN-AM-SkI"> <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="FhN-AM-SkI">
<rect key="frame" x="13" y="13" width="114" height="32"/> <rect key="frame" x="13" y="13" width="114" height="32"/>
<constraints>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="80" id="Zhu-D8-cLK"/>
</constraints>
<buttonCell key="cell" type="push" title="[i18n] Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="LxP-t4-H2W"> <buttonCell key="cell" type="push" title="[i18n] Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="LxP-t4-H2W">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/> <font key="font" metaFont="system"/>
@ -1350,6 +1347,9 @@ Gw
Gw Gw
</string> </string>
</buttonCell> </buttonCell>
<constraints>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="80" id="Zhu-D8-cLK"/>
</constraints>
<connections> <connections>
<action selector="pressedCancel:" target="gOD-Gu-zDG" id="wMp-sM-0A4"/> <action selector="pressedCancel:" target="gOD-Gu-zDG" id="wMp-sM-0A4"/>
</connections> </connections>
@ -1389,7 +1389,7 @@ Gw
<real value="3.4028234663852886e+38"/> <real value="3.4028234663852886e+38"/>
</customSpacing> </customSpacing>
</stackView> </stackView>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="fJK-Ke-IK3"> <textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="fJK-Ke-IK3">
<rect key="frame" x="18" y="138" width="504" height="19"/> <rect key="frame" x="18" y="138" width="504" height="19"/>
<textFieldCell key="cell" selectable="YES" alignment="left" title="[i18n] What kind of domain would you like to set up?" id="agk-Nj-FLd"> <textFieldCell key="cell" selectable="YES" alignment="left" title="[i18n] What kind of domain would you like to set up?" id="agk-Nj-FLd">
<font key="font" metaFont="systemBold" size="15"/> <font key="font" metaFont="systemBold" size="15"/>
@ -1397,7 +1397,7 @@ Gw
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell> </textFieldCell>
</textField> </textField>
<textField wantsLayer="YES" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="urj-Xq-TrJ"> <textField wantsLayer="YES" focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="urj-Xq-TrJ">
<rect key="frame" x="18" y="60" width="504" height="70"/> <rect key="frame" x="18" y="60" width="504" height="70"/>
<constraints> <constraints>
<constraint firstAttribute="width" relation="lessThanOrEqual" constant="500" id="tbl-AV-4qB"/> <constraint firstAttribute="width" relation="lessThanOrEqual" constant="500" id="tbl-AV-4qB"/>

View File

@ -241,6 +241,20 @@ class Startup {
descriptionText: "startup.errors.which_alias_issue.desc".localized descriptionText: "startup.errors.which_alias_issue.desc".localized
), ),
// ================================================================================= // =================================================================================
// Determine that Laravel Herd is not running (may cause conflicts)
// =================================================================================
EnvironmentCheck(
command: {
return NSWorkspace.shared.runningApplications.contains(where: { app in
return app.bundleIdentifier == "de.beyondco.herd"
})
},
name: "Herd is not running",
titleText: "startup.errors.herd_running.title".localized,
subtitleText: "startup.errors.herd_running.subtitle".localized,
descriptionText: "startup.errors.herd_running.desc".localized
),
// =================================================================================
// Determine that Valet works correctly (no issues in platform detected) // Determine that Valet works correctly (no issues in platform detected)
// ================================================================================= // =================================================================================
EnvironmentCheck( EnvironmentCheck(

View File

@ -62,12 +62,13 @@ struct ComposerJson: Decodable {
public func getNotableDependencies() -> [String: String] { public func getNotableDependencies() -> [String: String] {
var notable: [String: String] = [:] var notable: [String: String] = [:]
var scan = Array(PhpFrameworks.DependencyList.keys) let scan = Array(ProjectTypeDetection.CommonDependencyList.keys) +
scan.append("php") Array(ProjectTypeDetection.SpecificDependencyList.keys) +
["php"]
scan.forEach { dependency in scan.forEach { dependency in
if dependencies?[dependency] != nil { if let resolvedDependency = dependencies?[dependency] {
notable[dependency] = dependencies![dependency] notable[dependency] = resolvedDependency
} }
} }

View File

@ -8,20 +8,20 @@
import Foundation import Foundation
struct PhpFrameworks { struct ProjectTypeDetection {
/** /**
This list should probably be reversed when checked, because some of these This list is only checked if the specific dependency list doesn't report a match.
will also require either `laravel/framework` or `symfony/symfony`.
*/ */
public static let DependencyList = [ public static let CommonDependencyList = [
// COMMON FRAMEWORKS
"laravel/framework": "Laravel", "laravel/framework": "Laravel",
"symfony/symfony": "Symfony", "symfony/symfony": "Symfony",
"laravel/lumen": "Lumen", "laravel/lumen": "Lumen"
]
// VARIOUS CMS /**
This list is checked first to see if a project dependency can be mapped to a certain project type.
*/
public static let SpecificDependencyList = [
"roots/bedrock": "Bedrock", "roots/bedrock": "Bedrock",
"cakephp/app": "CakePHP", "cakephp/app": "CakePHP",
"craftcms/craft": "Craft", "craftcms/craft": "Craft",
@ -37,30 +37,8 @@ struct PhpFrameworks {
"johnpbloch/wordpress-core": "WordPress", "johnpbloch/wordpress-core": "WordPress",
"zendframework/zendframework": "Zend", "zendframework/zendframework": "Zend",
"zendframework/zend-mvc": "Zend", "zendframework/zend-mvc": "Zend",
"typo3/cms-core": "Typo3" "typo3/cms-core": "Typo3",
// "magento/*": "Magento", "slim/slim": "Slim"
// "concrete5/*": "Concrete5",
// "contao/*": "Contao",
// "slim/*": "Slim",
]
public static let FileMapping: [String: [String]] = [
"Drupal": [
// Legacy installations
"/misc/drupal.js",
"/core/lib/Drupal.php",
// The default (new) installation w/ Composer puts the modules in /web
"/web/misc/drupal.js",
"/web/core/lib/Drupal.php"
],
"WordPress": [
"/wp-config.php",
"/wp-config-sample.php"
],
"Typo3": [
"/typo3",
"/public/typo3"
]
] ]
/** /**
@ -82,4 +60,25 @@ struct PhpFrameworks {
return nil return nil
} }
/**
File mapping is used as a fallback if neither specific nor framework matches could be done.
*/
public static let FileMapping: [String: [String]] = [
"Drupal": [
// Legacy installations
"/misc/drupal.js",
"/core/lib/Drupal.php",
// The default (new) installation w/ Composer puts the modules in /web
"/web/misc/drupal.js",
"/web/core/lib/Drupal.php"
],
"WordPress": [
"/wp-config.php",
"/wp-config-sample.php"
],
"Typo3": [
"/typo3",
"/public/typo3"
]
]
} }

View File

@ -141,7 +141,7 @@ class ValetSite: ValetListable {
self.determineDriverViaComposer() self.determineDriverViaComposer()
if self.driver == nil { if self.driver == nil {
self.driver = PhpFrameworks.detectFallbackDependency(self.absolutePath) self.driver = ProjectTypeDetection.detectFallbackDependency(self.absolutePath)
} }
} }
@ -155,10 +155,16 @@ class ValetSite: ValetListable {
private func determineDriverViaComposer() { private func determineDriverViaComposer() {
self.driverDeterminedByComposer = true self.driverDeterminedByComposer = true
PhpFrameworks.DependencyList.reversed().forEach { (key: String, value: String) in for (key, value) in ProjectTypeDetection.SpecificDependencyList
if self.notableComposerDependencies.keys.contains(key) { where notableComposerDependencies.keys.contains(key) {
self.driver = value self.driver = value
} return
}
for (key, value) in ProjectTypeDetection.CommonDependencyList
where notableComposerDependencies.keys.contains(key) {
self.driver = value
return
} }
} }

View File

@ -206,6 +206,10 @@ class MainMenu: NSObject, NSWindowDelegate, NSMenuDelegate, PhpSwitcherDelegate
PhpDoctorWindowController.show() PhpDoctorWindowController.show()
} }
@objc func openConfigGUI() {
PhpConfigManagerWindowController.show()
}
@objc func openDomainList() { @objc func openDomainList() {
DomainListVC.show() DomainListVC.show()
} }

View File

@ -200,6 +200,16 @@ extension StatusMenu {
post: stats.post_max_size, post: stats.post_max_size,
upload: stats.upload_max_filesize) upload: stats.upload_max_filesize)
) )
// TODO: As soon as this does more than just edit memory limits, move this
/*
addItem(NSMenuItem.separator())
addItem(NSMenuItem(
title: "mi_manage_limits".localized,
action: #selector(MainMenu.openConfigGUI),
keyEquivalent: "l")
)
*/
} }
// MARK: - Extensions // MARK: - Extensions

View File

@ -91,6 +91,7 @@ class BetterAlert {
} }
NSApp.activate(ignoringOtherApps: true) NSApp.activate(ignoringOtherApps: true)
windowController.window?.makeKeyAndOrderFront(nil) windowController.window?.makeKeyAndOrderFront(nil)
windowController.window?.setCenterPosition(offsetY: 70) windowController.window?.setCenterPosition(offsetY: 70)
return NSApplication.shared.runModal(for: windowController.window!) return NSApplication.shared.runModal(for: windowController.window!)

View File

@ -65,7 +65,7 @@ class PreferencesWindowController: PMWindowController {
App.shared.preferencesWindowController?.showWindow(self) App.shared.preferencesWindowController?.showWindow(self)
if justCreated { if justCreated {
App.shared.preferencesWindowController?.positionWindowInTopLeftCorner() App.shared.preferencesWindowController?.positionWindowInTopRightCorner()
} }
NSApp.activate(ignoringOtherApps: true) NSApp.activate(ignoringOtherApps: true)

View File

@ -18,5 +18,6 @@ struct SectionHeaderView: View {
.fontWeight(.medium) .fontWeight(.medium)
.foregroundColor(.appSecondary) .foregroundColor(.appSecondary)
.background(Color.debug) .background(Color.debug)
.minimumScaleFactor(0.8)
} }
} }

View File

@ -60,27 +60,39 @@ struct StatsView: View {
.padding(.leading, 30) .padding(.leading, 30)
.padding(.trailing, 30) .padding(.trailing, 30)
} else { } else {
HStack(alignment: .firstTextBaseline, spacing: 30) { HStack(alignment: .center, spacing: 10) {
VStack(alignment: .center, spacing: 3) { VStack(alignment: .center, spacing: 3) {
SectionHeaderView(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))
} }
Divider()
VStack(alignment: .center, spacing: 3) { VStack(alignment: .center, spacing: 3) {
SectionHeaderView(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))
} }
Divider()
VStack(alignment: .center, spacing: 3) { VStack(alignment: .center, spacing: 3) {
SectionHeaderView(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))
} }
Divider().hidden()
Button {
Task { @MainActor in
MainMenu.shared.openConfigGUI()
}
} label: {
Image(systemName: "gearshape.fill")
}
.focusable(false)
.frame(minWidth: 30, alignment: .center)
} }
.padding(10) .padding(5)
.background(Color.debug) .background(Color.debug)
} }
} }
@ -92,6 +104,6 @@ struct StatsView_Previews: PreviewProvider {
memoryLimit: "1024 MB", memoryLimit: "1024 MB",
maxPostSize: "1024 MB", maxPostSize: "1024 MB",
maxUploadSize: "1024 MB" maxUploadSize: "1024 MB"
) ).frame(height: 100)
} }
} }

View File

@ -46,7 +46,7 @@ struct ProgressWindowView: View {
window.contentView = NSHostingView(rootView: view) window.contentView = NSHostingView(rootView: view)
let controller = NSWindowController(window: window) let controller = NSWindowController(window: window)
controller.showWindow(nil) controller.showWindow(nil)
controller.positionWindowInTopLeftCorner() controller.positionWindowInTopRightCorner()
controller.window?.makeKeyAndOrderFront(self) controller.window?.makeKeyAndOrderFront(self)
// NSApp.activate(ignoringOtherApps: true) // NSApp.activate(ignoringOtherApps: true)
return controller return controller

View File

@ -20,7 +20,7 @@ class TerminalProgressWindowController: NSWindowController, NSWindowDelegate {
windowController.showWindow(windowController) windowController.showWindow(windowController)
windowController.window?.makeKeyAndOrderFront(nil) windowController.window?.makeKeyAndOrderFront(nil)
windowController.positionWindowInTopLeftCorner() windowController.positionWindowInTopRightCorner()
windowController.progressView?.labelTitle.stringValue = title windowController.progressView?.labelTitle.stringValue = title
windowController.progressView?.labelDescription.stringValue = description windowController.progressView?.labelDescription.stringValue = description

View File

@ -17,13 +17,13 @@ extension App {
onChange: { Task { await self.onHomebrewPhpModification() } } onChange: { Task { await self.onHomebrewPhpModification() } }
) )
App.shared.watchers[.homebrewBinaries] = notifier App.shared.watchers["homebrewBinaries"] = notifier
} }
public func destroyHomebrewWatchers() { public func destroyHomebrewWatchers() {
// Removing requires termination and then removing reference // Removing requires termination and then removing reference
self.watchers[.homebrewBinaries]?.terminate() self.watchers["homebrewBinaries"]?.terminate()
self.watchers[.homebrewBinaries] = nil self.watchers["homebrewBinaries"] = nil
} }
public func onHomebrewPhpModification() async { public func onHomebrewPhpModification() async {
@ -31,10 +31,13 @@ extension App {
Log.info("Something changed in the Homebrew binary directory...") Log.info("Something changed in the Homebrew binary directory...")
await PhpEnvironments.detectPhpVersions() await PhpEnvironments.detectPhpVersions()
await MainMenu.shared.refreshActiveInstallation() await MainMenu.shared.refreshActiveInstallation()
// let new = PhpEnvironments.shared.currentInstall?.version.text
// TODO: //
// Check if the new and previous version are different // TODO: PHP Guard 2.0
// if so, we can show a notification if needed // Check if the new and previous version of PHP are different
// if so, we can show a notification if needed or alert the user
//
// let new = PhpEnvironments.shared.currentInstall?.version.text
//
} }
} }

View File

@ -10,52 +10,52 @@ import Foundation
extension App { extension App {
func startWatcher(_ url: URL) { func startWatchManager(_ url: URL) {
Log.perf("No watcher currently active...") Log.perf("Starting config watch manager...")
self.watcher = PhpConfigWatcher(for: url) self.watchManager = ConfigWatchManager(for: url)
self.watcher.didChange = { url in self.watchManager.didChange = { url in
Log.perf("Something has changed in: \(url)") Log.perf("Something has changed in: \(url)")
// Check if the watcher has last updated the menu less than 0.75s ago // Check if the watcher has last updated the menu less than 0.75s ago
let distance = self.watcher.lastUpdate?.distance(to: Date().timeIntervalSince1970) let distance = self.watchManager.lastUpdate?.distance(to: Date().timeIntervalSince1970)
if distance == nil || distance != nil && distance! > 0.75 { if distance == nil || distance != nil && distance! > 0.75 {
Log.perf("Refreshing menu...") Log.perf("Refreshing menu...")
Task { @MainActor in MainMenu.shared.reloadPhpMonitorMenuInBackground() } Task { @MainActor in MainMenu.shared.reloadPhpMonitorMenuInBackground() }
self.watcher.lastUpdate = Date().timeIntervalSince1970 self.watchManager.lastUpdate = Date().timeIntervalSince1970
} }
} }
} }
func handlePhpConfigWatcher(forceReload: Bool = false) { func handlePhpConfigWatcher(forceReload: Bool = false) {
if ActiveFileSystem.shared is TestableFileSystem { if ActiveFileSystem.shared is TestableFileSystem {
Log.warn("FS watcher is disabled when using testable filesystem.") Log.warn("Config watch manager is disabled when using testable filesystem.")
return return
} }
guard let install = PhpEnvironments.phpInstall else { guard let install = PhpEnvironments.phpInstall else {
Log.info("It appears as if no PHP installation is currently active.") Log.info("It appears as if no PHP installation is currently active.")
Log.info("The FS watcher will be disabled until a PHP install is active.") Log.info("The config watch manager be disabled until a PHP install is active.")
return return
} }
let url = URL(fileURLWithPath: "\(Paths.etcPath)/php/\(install.version.short)") let url = URL(fileURLWithPath: "\(Paths.etcPath)/php/\(install.version.short)")
// Check whether the watcher exists and schedule on the main thread // Check whether the manager exists and schedule on the main thread
// if we don't consistently do this, the app will create duplicate watchers // if we don't consistently do this, the app will create duplicate watchers
// due to timing issues, which creates retain cycles. // due to timing issues, which creates retain cycles
Task { @MainActor in Task { @MainActor in
// Watcher needs to be created // Watcher needs to be created
if self.watcher == nil { if self.watchManager == nil {
self.startWatcher(url) self.startWatchManager(url)
} }
// Watcher needs to be updated // Watcher needs to be updated
if self.watcher.url != url || forceReload { if self.watchManager.url != url || forceReload {
self.watcher.disable() self.watchManager.disable()
self.watcher = nil self.watchManager = nil
Log.perf("Watcher has stopped watching files. Starting new one...") Log.perf("Watcher has stopped watching files. Starting new one...")
self.startWatcher(url) self.startWatchManager(url)
} }
} }
} }

View File

@ -0,0 +1,77 @@
//
// ConfigFSNotifier.swift
// PHP Monitor
//
// Created by Nico Verbruggen on 24/10/2023.
// Copyright © 2023 Nico Verbruggen. All rights reserved.
//
import Foundation
class ConfigFSNotifier {
enum Behaviour {
case reloadsMenu
case reloadsWatchers
}
private var parent: ConfigWatchManager!
private var monitoredFolderFileDescriptor: CInt = -1
private var folderMonitorSource: DispatchSourceFileSystemObject?
let url: URL
init(
for url: URL,
eventMask: DispatchSource.FileSystemEvent,
parent: ConfigWatchManager,
behaviour: ConfigFSNotifier.Behaviour = .reloadsMenu
) {
self.url = url
self.parent = parent
self.startMonitoring(eventMask, behaviour: behaviour)
}
func startMonitoring(
_ eventMask: DispatchSource.FileSystemEvent,
behaviour: ConfigFSNotifier.Behaviour
) {
guard folderMonitorSource == nil && monitoredFolderFileDescriptor == -1 else {
return
}
monitoredFolderFileDescriptor = open(url.path, O_EVTONLY)
folderMonitorSource = DispatchSource.makeFileSystemObjectSource(
fileDescriptor: monitoredFolderFileDescriptor,
eventMask: eventMask,
queue: parent.folderMonitorQueue
)
folderMonitorSource?.setEventHandler { [weak self] in
if behaviour == .reloadsWatchers
&& !ConfigWatchManager.ignoresModificationsToConfigValues {
// Reload all configuration watchers
return App.shared.handlePhpConfigWatcher(forceReload: true)
}
self?.parent.didChange?(self!.url)
}
folderMonitorSource?.setCancelHandler { [weak self] in
guard let self = self else { return }
close(self.monitoredFolderFileDescriptor)
self.monitoredFolderFileDescriptor = -1
self.folderMonitorSource = nil
}
folderMonitorSource?.resume()
}
func stopMonitoring() {
folderMonitorSource?.cancel()
self.parent = nil
}
}

View File

@ -0,0 +1,82 @@
//
// ConfigWatchManager.swift
// PHP Monitor
//
// Created by Nico Verbruggen on 30/03/2021.
// Copyright © 2023 Nico Verbruggen. All rights reserved.
//
import Foundation
class ConfigWatchManager {
static var ignoresModificationsToConfigValues: Bool = false
let folderMonitorQueue = DispatchQueue(label: "FolderMonitorQueue", attributes: .concurrent)
let url: URL
var didChange: ((URL) -> Void)?
var lastUpdate: TimeInterval?
var watchers: [ConfigFSNotifier] = []
init(for url: URL) {
if FileSystem is TestableFileSystem {
fatalError("""
ConfigWatchManager is currently incompatible with a testable filesystem!"
You are not allowed to instantiate these while using a testable filesystem.
""")
}
self.url = url
// Add a watcher for php.ini
self.addWatcher(for: self.url.appendingPathComponent("php.ini"), eventMask: .write)
// Add a watcher for conf.d (in case a new file is added or a file is deleted)
// This watcher, when triggered, will restart all watchers
self.addWatcher(for: self.url.appendingPathComponent("conf.d"), eventMask: .all, behaviour: .reloadsWatchers)
// Scan the conf.d folder for .ini files, and add a watcher for each file
let filePaths = FileManager.default.enumerator(
atPath: self.url.appendingPathComponent("conf.d").path
)?.allObjects as! [String]
// Loop over the .ini files that we discovered
filePaths.filter { $0.contains(".ini") }.forEach { (file) in
// Add a watcher for each file we have discovered
self.addWatcher(for: self.url.appendingPathComponent("conf.d/\(file)"), eventMask: .write)
}
Log.perf("A watcher exists for the following config paths:")
Log.perf(self.watchers.map({ watcher in
return watcher.url.relativePath
}))
}
func addWatcher(
for url: URL,
eventMask: DispatchSource.FileSystemEvent,
behaviour: ConfigFSNotifier.Behaviour = .reloadsMenu
) {
if !FileSystem.anyExists(url.path) {
Log.warn("No watcher was created for \(url.path) because the requested file does not exist.")
return
}
let watcher = ConfigFSNotifier(for: url, eventMask: eventMask, parent: self, behaviour: behaviour)
self.watchers.append(watcher)
}
func disable() {
Log.perf("Turning off all individual existing watchers...")
self.watchers.forEach { (watcher) in
watcher.stopMonitoring()
}
}
deinit {
Log.perf("deinit: \(String(describing: self)).\(#function)")
}
}

View File

@ -6,12 +6,9 @@
// Copyright © 2023 Nico Verbruggen. All rights reserved. // Copyright © 2023 Nico Verbruggen. All rights reserved.
// //
import Cocoa import Foundation
class FSNotifier { class FSNotifier {
enum Kind {
case homebrewLocks, homebrewBinaries
}
public static var shared: FSNotifier! = nil public static var shared: FSNotifier! = nil
@ -66,4 +63,5 @@ class FSNotifier {
deinit { deinit {
Log.perf("FSNotifier for \(self.url) will be deinitialized.") Log.perf("FSNotifier for \(self.url) will be deinitialized.")
} }
} }

View File

@ -1,154 +0,0 @@
//
// FolderWatcher.swift
// PHP Monitor
//
// Created by Nico Verbruggen on 30/03/2021.
// Copyright © 2023 Nico Verbruggen. All rights reserved.
//
import Foundation
class PhpConfigWatcher {
let folderMonitorQueue = DispatchQueue(label: "FolderMonitorQueue", attributes: .concurrent)
let url: URL
var didChange: ((URL) -> Void)?
var lastUpdate: TimeInterval?
var watchers: [FSWatcher] = []
init(for url: URL) {
if FileSystem is TestableFileSystem {
fatalError("""
PhpConfigWatcher is not compatible with testable FS! "
You are not allowed to instantiate these while using a testable FS.
""")
}
self.url = url
// Add a watcher for php.ini
self.addWatcher(for: self.url.appendingPathComponent("php.ini"), eventMask: .write)
// Add a watcher for conf.d (in case a new file is added or a file is deleted)
// This watcher, when triggered, will restart all watchers
self.addWatcher(for: self.url.appendingPathComponent("conf.d"), eventMask: .all, behaviour: .reloadsWatchers)
// Scan the conf.d folder for .ini files, and add a watcher for each file
let enumerator = FileManager.default.enumerator(atPath: self.url.appendingPathComponent("conf.d").path)
let filePaths = enumerator?.allObjects as! [String]
// Loop over the .ini files that we discovered
filePaths.filter { $0.contains(".ini") }.forEach { (file) in
// Add a watcher for each file we have discovered
self.addWatcher(for: self.url.appendingPathComponent("conf.d/\(file)"), eventMask: .write)
}
Log.perf("A watcher exists for the following config paths:")
Log.perf(self.watchers.map({ watcher in
return watcher.url.relativePath
}))
}
func addWatcher(
for url: URL,
eventMask: DispatchSource.FileSystemEvent,
behaviour: FSWatcherBehaviour = .reloadsMenu
) {
if !FileSystem.anyExists(url.path) {
Log.warn("No watcher was created for \(url.path) because the requested file does not exist.")
return
}
let watcher = FSWatcher(for: url, eventMask: eventMask, parent: self, behaviour: behaviour)
self.watchers.append(watcher)
}
func disable() {
Log.perf("Turning off all individual existing watchers...")
self.watchers.forEach { (watcher) in
watcher.stopMonitoring()
}
}
deinit {
Log.perf("deinit: \(String(describing: self)).\(#function)")
}
}
enum FSWatcherBehaviour {
case reloadsMenu
case reloadsWatchers
}
class FSWatcher {
private var parent: PhpConfigWatcher!
private var monitoredFolderFileDescriptor: CInt = -1
private var folderMonitorSource: DispatchSourceFileSystemObject?
let url: URL
init(
for url: URL,
eventMask: DispatchSource.FileSystemEvent,
parent: PhpConfigWatcher,
behaviour: FSWatcherBehaviour = .reloadsMenu
) {
self.url = url
self.parent = parent
self.startMonitoring(eventMask, behaviour: behaviour)
}
func startMonitoring(
_ eventMask: DispatchSource.FileSystemEvent,
behaviour: FSWatcherBehaviour
) {
guard folderMonitorSource == nil && monitoredFolderFileDescriptor == -1 else {
return
}
// Open the file or folder referenced by URL for monitoring only.
monitoredFolderFileDescriptor = open(url.path, O_EVTONLY)
folderMonitorSource = DispatchSource.makeFileSystemObjectSource(
fileDescriptor: monitoredFolderFileDescriptor,
eventMask: eventMask,
queue: parent.folderMonitorQueue
)
// Define the block to call when a file change is detected.
folderMonitorSource?.setEventHandler { [weak self] in
// The default behaviour is to reload the menu
switch behaviour {
case .reloadsMenu:
// Default behaviour: reload the menu items
self?.parent.didChange?(self!.url)
case .reloadsWatchers:
// Alternative behaviour: reload all watchers
App.shared.handlePhpConfigWatcher(forceReload: true)
}
}
// Define a cancel handler to ensure the directory is closed when the source is cancelled.
folderMonitorSource?.setCancelHandler { [weak self] in
guard let self = self else { return }
close(self.monitoredFolderFileDescriptor)
self.monitoredFolderFileDescriptor = -1
self.folderMonitorSource = nil
}
// Start monitoring the directory via the source.
folderMonitorSource?.resume()
}
func stopMonitoring() {
folderMonitorSource?.cancel()
self.parent = nil
}
}

View File

@ -85,6 +85,7 @@ class DomainListVC: NSViewController, NSTableViewDelegate, NSTableViewDataSource
App.shared.domainListWindowController!.showWindow(self) App.shared.domainListWindowController!.showWindow(self)
NSApp.activate(ignoringOtherApps: true) NSApp.activate(ignoringOtherApps: true)
App.shared.domainListWindowController?.window?.orderFrontRegardless()
} }
// MARK: - Lifecycle // MARK: - Lifecycle

View File

@ -52,7 +52,20 @@ class BytePhpPreference: PhpPreference {
// MARK: Save Value // MARK: Save Value
private func updatedFieldValue() { private func updatedFieldValue() {
internalValue = "\(value)\(unit.rawValue)" if value == -1 {
// In case we're dealing with unlimited value, we don't need a unit
internalValue = "-1"
} else {
// We need to append the unit otherwise
internalValue = "\(value)\(unit.rawValue)"
}
do {
try PhpPreference.persistToIniFile(key: self.key, value: self.internalValue)
Log.info("The preference \(key) was updated to: \(value)")
} catch {
Log.info("The preference \(key) could not be updated")
}
} }
public static func readFrom(internalValue: String) -> (UnitOption, Int)? { public static func readFrom(internalValue: String) -> (UnitOption, Int)? {

View File

@ -15,6 +15,14 @@ class PhpPreference {
init(key: String) { init(key: String) {
self.key = key self.key = key
} }
internal static func persistToIniFile(key: String, value: String) throws {
if let file = PhpEnvironments.shared.getConfigFile(forKey: key) {
return try file.replace(key: key, value: value)
}
throw PhpConfigurationFile.ReplacementErrors.missingFile
}
} }
class BoolPhpPreference: PhpPreference { class BoolPhpPreference: PhpPreference {

View File

@ -35,12 +35,12 @@ struct PreferenceContainer<ControlView: View>: View {
VStack(alignment: .leading) { VStack(alignment: .leading) {
controlView controlView
Text(self.description.localizedForSwiftUI) Text(self.description.localizedForSwiftUI)
.lineLimit(nil)
.font(.subheadline) .font(.subheadline)
.foregroundColor(Color.secondary)
.fixedSize(horizontal: false, vertical: true) .fixedSize(horizontal: false, vertical: true)
} }
.frame(maxWidth: .infinity, alignment: .topLeading)
} }
} }
.padding(5) .padding(5)
@ -51,6 +51,7 @@ struct ByteLimitView: View {
@State private var unit: BytePhpPreference.UnitOption @State private var unit: BytePhpPreference.UnitOption
@State private var numberText: String @State private var numberText: String
@State private var unlimited: Bool @State private var unlimited: Bool
@State private var timer: Timer?
private var preference: BytePhpPreference private var preference: BytePhpPreference
@ -65,9 +66,11 @@ struct ByteLimitView: View {
if !unlimited { if !unlimited {
HStack { HStack {
TextField("", text: $numberText) TextField("", text: $numberText)
.onChange(of: numberText) { newText in .onChange(of: numberText) { [weak preference] newText in
self.preference.value = Int(newText) ?? 256 timer?.invalidate()
print(self.preference.internalValue) timer = Timer.scheduledTimer(withTimeInterval: 1.5, repeats: false) { _ in
preference?.value = Int(newText) ?? 256
}
} }
Picker("Limit Name", selection: $unit) { Picker("Limit Name", selection: $unit) {
ForEach(BytePhpPreference.UnitOption.allCases, id: \.self) { ForEach(BytePhpPreference.UnitOption.allCases, id: \.self) {
@ -79,22 +82,32 @@ struct ByteLimitView: View {
.pickerStyle(.menu) .pickerStyle(.menu)
.onChange(of: unit) { newValue in .onChange(of: unit) { newValue in
self.preference.unit = newValue self.preference.unit = newValue
print(self.preference.internalValue)
} }
} }
} }
Toggle(isOn: $unlimited) { Toggle(isOn: $unlimited) {
Label("Allow unlimited usage", systemImage: "heart").labelStyle(.titleOnly) Text("confman.byte_limit.unlimited".localizedForSwiftUI)
} }.onChange(of: unlimited, perform: { [weak preference] unlimited in
timer?.invalidate()
timer = Timer.scheduledTimer(withTimeInterval: 0.8, repeats: false) { _ in
preference?.value = unlimited ? -1 : 512
preference?.unit = .megabyte
}
})
} }
} }
struct ByteLimitView_Previews: PreviewProvider { struct ByteLimitView_Previews: PreviewProvider {
static var previews: some View { static var previews: some View {
PreferenceContainer(name: "Max Size", description: "Some maximum size") { PreferenceContainer(
name: "Max Size",
description:
"Here's an extensive description that is obviously way too long but it should wrap." +
"The point of the wrapping text is that is allows us to see what's going on with the layout here."
) {
ByteLimitView(preference: BytePhpPreference(key: "max_memory")) ByteLimitView(preference: BytePhpPreference(key: "max_memory"))
} }.frame(width: 600, height: 200)
ConfigManagerView() ConfigManagerView()
.frame(width: 600, height: .infinity) .frame(width: 600, height: .infinity)

View File

@ -13,14 +13,14 @@ struct ConfigManagerView: View {
var preferences: [PhpPreference] = [ var preferences: [PhpPreference] = [
BytePhpPreference(key: "memory_limit"), BytePhpPreference(key: "memory_limit"),
BytePhpPreference(key: "post_max_size"), BytePhpPreference(key: "post_max_size"),
BoolPhpPreference(key: "file_uploads"), // BoolPhpPreference(key: "file_uploads"),
BytePhpPreference(key: "upload_max_filesize") BytePhpPreference(key: "upload_max_filesize")
] ]
var body: some View { var body: some View {
VStack { VStack {
HStack(alignment: .center, spacing: 15) { HStack(alignment: .center, spacing: 15) {
Image(systemName: "square.and.pencil.circle.fill") Image(systemName: "gearshape.fill")
.resizable() .resizable()
.frame(width: 40, height: 40) .frame(width: 40, height: 40)
.foregroundColor(Color.blue) .foregroundColor(Color.blue)
@ -51,6 +51,7 @@ struct ConfigManagerView: View {
if let preference = preference as? BytePhpPreference { if let preference = preference as? BytePhpPreference {
ByteLimitView(preference: preference) ByteLimitView(preference: preference)
} }
/*
if let preference = preference as? BoolPhpPreference { if let preference = preference as? BoolPhpPreference {
Toggle("", isOn: preference.$value) Toggle("", isOn: preference.$value)
.toggleStyle(.switch) .toggleStyle(.switch)
@ -59,6 +60,7 @@ struct ConfigManagerView: View {
if let preference = preference as? StringPhpPreference { if let preference = preference as? StringPhpPreference {
TextField("Placeholder", text: preference.$value) TextField("Placeholder", text: preference.$value)
} }
*/
}.frame(maxWidth: .infinity) }.frame(maxWidth: .infinity)
} }
}.padding(10) }.padding(10)
@ -67,7 +69,7 @@ struct ConfigManagerView: View {
VStack(alignment: .trailing) { VStack(alignment: .trailing) {
Button("Close", action: { Button("Close", action: {
App.shared.phpConfigManagerWindowController?.close()
}) })
} }
.padding(.vertical, 10) .padding(.vertical, 10)
@ -78,7 +80,7 @@ struct ConfigManagerView: View {
alignment: .topTrailing alignment: .topTrailing
) )
} }
} }.frame(maxHeight: 485)
} }
} }

View File

@ -0,0 +1,46 @@
//
// ConfigManagerWindowController.swift
// PHP Monitor
//
// Created by Nico Verbruggen on 12/09/2023.
// Copyright © 2023 Nico Verbruggen. All rights reserved.
//
import Cocoa
import SwiftUI
class PhpConfigManagerWindowController: PMWindowController {
// MARK: - Window Identifier
override var windowName: String {
return "ConfigManager"
}
public static func create(delegate: NSWindowDelegate?) {
let windowController = Self()
windowController.window = NSWindow()
guard let window = windowController.window else { return }
window.title = ""
window.styleMask = [.titled, .closable, .miniaturizable]
window.titlebarAppearsTransparent = true
window.delegate = delegate ?? windowController
window.contentView = NSHostingView(rootView: ConfigManagerView())
window.setContentSize(NSSize(width: 600, height: 480))
App.shared.phpConfigManagerWindowController = windowController
}
public static func show(delegate: NSWindowDelegate? = nil) {
if App.shared.phpConfigManagerWindowController == nil {
Self.create(delegate: delegate)
}
App.shared.phpConfigManagerWindowController?.showWindow(self)
App.shared.phpConfigManagerWindowController?.positionWindowInTopRightCorner()
NSApp.activate(ignoringOtherApps: true)
App.shared.phpConfigManagerWindowController?.window?.orderFrontRegardless()
}
}

View File

@ -41,5 +41,6 @@ class PhpDoctorWindowController: PMWindowController {
App.shared.phpDoctorWindowController?.window?.setCenterPosition(offsetY: 70) App.shared.phpDoctorWindowController?.window?.setCenterPosition(offsetY: 70)
NSApp.activate(ignoringOtherApps: true) NSApp.activate(ignoringOtherApps: true)
App.shared.phpDoctorWindowController?.window?.orderFrontRegardless()
} }
} }

View File

@ -45,8 +45,10 @@ class PhpVersionManagerWindowController: PMWindowController {
} }
App.shared.phpVersionManagerWindowController?.showWindow(self) App.shared.phpVersionManagerWindowController?.showWindow(self)
App.shared.phpVersionManagerWindowController?.positionWindowInTopLeftCorner() App.shared.phpVersionManagerWindowController?.positionWindowInTopRightCorner()
NSApp.activate(ignoringOtherApps: true) NSApp.activate(ignoringOtherApps: true)
App.shared.phpVersionManagerWindowController?.window?.orderFrontRegardless()
} }
} }

View File

@ -653,6 +653,11 @@ Wenn Sie diese Meldung sehen, aber nicht wissen, warum dieser Ordner verschwunde
"startup.errors.which_alias_issue.subtitle" = "Es scheint, dass es eine Datei in `/usr/local/bin/which` gibt. Diese wird normalerweise von NodeJS eingerichtet, aber `node` ist nicht im PATH in `/usr/local/bin`. Um dies zu beheben, lesen Sie weiter."; "startup.errors.which_alias_issue.subtitle" = "Es scheint, dass es eine Datei in `/usr/local/bin/which` gibt. Diese wird normalerweise von NodeJS eingerichtet, aber `node` ist nicht im PATH in `/usr/local/bin`. Um dies zu beheben, lesen Sie weiter.";
"startup.errors.which_alias_issue.desc" = "Sie müssen einen Symlink von `node` in das Verzeichnis `/usr/local/bin` setzen, um sicherzustellen, dass PHP Monitor erfolgreich starten kann. Für weitere Informationen siehe: https://github.com/nicoverbruggen/phpmon/issues/174"; "startup.errors.which_alias_issue.desc" = "Sie müssen einen Symlink von `node` in das Verzeichnis `/usr/local/bin` setzen, um sicherzustellen, dass PHP Monitor erfolgreich starten kann. Für weitere Informationen siehe: https://github.com/nicoverbruggen/phpmon/issues/174";
// Laravel Herd conflicts
"startup.errors.herd_running.title" = "Laravel Herd scheint aktiv zu sein";
"startup.errors.herd_running.subtitle" = "Es scheint, dass Laravel Herd derzeit aktiv ist. Die integrierte Valet-Konfiguration von Herd kann mit Ihrer regulären Valet-Installation kollidieren. Beenden Sie daher Herd, bevor Sie fortfahren. (Sie können Herd und reguläres Valet problemlos kombinieren, sollten sie jedoch nicht gleichzeitig ausführen.)";
"startup.errors.herd_running.desc" = "Möglicherweise stellt der von Herd zu Ihrem $PATH hinzugefügte `php`-Alias eine Behinderung für das Aliasen von PHP Monitor als `php` dar. Beachten Sie dies bitte. Schauen Sie in die Datei `~/.zshrc`, um zu sehen, was Herd zu Ihrem $PATH hinzugefügt hat.";
// Warning about a different PHP version linked than last time // Warning about a different PHP version linked than last time
"startup.version_mismatch.title" = "Die aktive PHP-Version hat sich geändert."; "startup.version_mismatch.title" = "Die aktive PHP-Version hat sich geändert.";
"startup.version_mismatch.subtitle" = "Seitdem PHP Monitor das letzte Mal aktiv war, wurde Ihre verlinkte PHP-Version auf PHP %@ geändert. Möchten Sie zurück zu PHP %@ wechseln oder möchten Sie die aktuelle Version weiter verwenden?"; "startup.version_mismatch.subtitle" = "Seitdem PHP Monitor das letzte Mal aktiv war, wurde Ihre verlinkte PHP-Version auf PHP %@ geändert. Möchten Sie zurück zu PHP %@ wechseln oder möchten Sie die aktuelle Version weiter verwenden?";

View File

@ -13,6 +13,8 @@
"mi_fix_php_link" = "Fix Automatically..."; "mi_fix_php_link" = "Fix Automatically...";
"mi_no_php_linked_explain" = "What's This?"; "mi_no_php_linked_explain" = "What's This?";
"mi_php_version_manager" = "PHP Version Manager..."; "mi_php_version_manager" = "PHP Version Manager...";
"mi_php_config_manager" = "PHP Configuration Editor...";
"mi_manage_limits" = "Manage Limits...";
"mi_diagnostics" = "Diagnostics"; "mi_diagnostics" = "Diagnostics";
"mi_active_services" = "Active Services"; "mi_active_services" = "Active Services";
@ -84,7 +86,8 @@
// CONFMAN // CONFMAN
"confman.title" = "PHP Configuration Editor"; "confman.title" = "PHP Configuration Editor";
"confman.description" = "This feature lets you customize your PHP installation with ease. Changes are automatically applied."; "confman.description" = "This feature lets you customize your PHP installation's configuration with ease.\nPlease note that any changes you make are immediately and automatically applied.";
"confman.byte_limit.unlimited" = "Allow unlimited usage";
"php_ini.memory_limit.title" = "Memory Limit"; "php_ini.memory_limit.title" = "Memory Limit";
"php_ini.memory_limit.description" = "This sets the maximum amount of memory in bytes that a script is allowed to allocate. This helps prevent poorly written scripts for eating up all available memory on a server."; "php_ini.memory_limit.description" = "This sets the maximum amount of memory in bytes that a script is allowed to allocate. This helps prevent poorly written scripts for eating up all available memory on a server.";
@ -667,6 +670,11 @@ If you are seeing this message but are confused why this folder has gone missing
"startup.errors.which_alias_issue.subtitle" = "It appears that there's a file in `/usr/local/bin/which`. This is usually set up by NodeJS, but `node` isn't in the PATH in `/usr/local/bin`. To fix this, keep reading."; "startup.errors.which_alias_issue.subtitle" = "It appears that there's a file in `/usr/local/bin/which`. This is usually set up by NodeJS, but `node` isn't in the PATH in `/usr/local/bin`. To fix this, keep reading.";
"startup.errors.which_alias_issue.desc" = "You will need to symlink `node` into the `/usr/local/bin` directory to make sure PHP Monitor can start successfully. For more info, see: https://github.com/nicoverbruggen/phpmon/issues/174"; "startup.errors.which_alias_issue.desc" = "You will need to symlink `node` into the `/usr/local/bin` directory to make sure PHP Monitor can start successfully. For more info, see: https://github.com/nicoverbruggen/phpmon/issues/174";
/// Laravel Herd conflicts
"startup.errors.herd_running.title" = "Laravel Herd appears to be running";
"startup.errors.herd_running.subtitle" = "It seems that Laravel Herd is currently running. Herd's built-in Valet setup may conflict with your regular Valet installation, so please quit Herd before continuing. (You can perfectly mix usage of Herd and regular Valet but you shouldn't run both at the same time.)";
"startup.errors.herd_running.desc" = "You may also find that the `php` alias by Herd added to your $PATH may prevent `php` aliasing of PHP Monitor from working, so keep that in mind. You can check out `~/.zshrc` and see what Herd has added to your $PATH.";
// Warning about a different PHP version linked than last time // Warning about a different PHP version linked than last time
"startup.version_mismatch.title" = "Your active PHP version has changed."; "startup.version_mismatch.title" = "Your active PHP version has changed.";
"startup.version_mismatch.subtitle" = "Since PHP Monitor was last active, your linked PHP version has been changed to PHP %@. Would you like to switch back to PHP %@, or do you want to keep using the current version?"; "startup.version_mismatch.subtitle" = "Since PHP Monitor was last active, your linked PHP version has been changed to PHP %@. Would you like to switch back to PHP %@, or do you want to keep using the current version?";

View File

@ -652,6 +652,11 @@ Als u dit bericht ziet, maar verward bent waarom deze map ontbreekt, wilt u moge
"startup.errors.which_alias_issue.subtitle" = "Het lijkt erop dat er een bestand is in `/usr/local/bin/which`. Dit wordt meestal ingesteld door NodeJS, maar `node` staat niet in de PATH in `/usr/local/bin`. Om dit op te lossen, gaat u verder met lezen."; "startup.errors.which_alias_issue.subtitle" = "Het lijkt erop dat er een bestand is in `/usr/local/bin/which`. Dit wordt meestal ingesteld door NodeJS, maar `node` staat niet in de PATH in `/usr/local/bin`. Om dit op te lossen, gaat u verder met lezen.";
"startup.errors.which_alias_issue.desc" = "U moet `node` symbolisch koppelen aan de `/usr/local/bin`-directory om ervoor te zorgen dat PHP Monitor succesvol kan starten. Voor meer informatie, zie: https://github.com/nicoverbruggen/phpmon/issues/174"; "startup.errors.which_alias_issue.desc" = "U moet `node` symbolisch koppelen aan de `/usr/local/bin`-directory om ervoor te zorgen dat PHP Monitor succesvol kan starten. Voor meer informatie, zie: https://github.com/nicoverbruggen/phpmon/issues/174";
/// Laravel Herd conflicts
"startup.errors.herd_running.title" = "Laravel Herd lijkt actief te zijn";
"startup.errors.herd_running.subtitle" = "Het lijkt erop dat Laravel Herd momenteel actief is. De ingebouwde Valet-configuratie van Herd kan conflicteren met je reguliere Valet-installatie, dus sluit Herd af voordat je verdergaat. (Je kunt perfect gebruik maken van zowel Herd als reguliere Valet, maar je moet ze niet tegelijkertijd uitvoeren.)";
"startup.errors.herd_running.desc" = "Je kan ook merken dat de `php`-alias die Herd aan je $PATH heeft toegevoegd, niet werkt met de aliases van PHP Monitor, dus hou daar rekening mee. Je kunt `~/.zshrc` bekijken om te zien wat Herd aan je $PATH heeft toegevoegd.";
// Warning about a different PHP version linked than last time // Warning about a different PHP version linked than last time
"startup.version_mismatch.title" = "Uw actieve PHP-versie is gewijzigd."; "startup.version_mismatch.title" = "Uw actieve PHP-versie is gewijzigd.";
"startup.version_mismatch.subtitle" = "Sinds PHP Monitor voor het laatst actief was, is uw gekoppelde PHP-versie gewijzigd naar PHP %@. Wilt u terugschakelen naar PHP %@, of wilt u de huidige versie blijven gebruiken?"; "startup.version_mismatch.subtitle" = "Sinds PHP Monitor voor het laatst actief was, is uw gekoppelde PHP-versie gewijzigd naar PHP %@. Wilt u terugschakelen naar PHP %@, of wilt u de huidige versie blijven gebruiken?";

View File

@ -652,6 +652,11 @@ Se ainda vê esta mensagem, e não percebe porque a diretoria desapareceu, conv
"startup.errors.which_alias_issue.subtitle" = "Parece que há um ficheiro em `/usr/local/bin/which`. Isto geralmente é configurado pelo NodeJS, mas `node` não está no PATH em `/usr/local/bin`. Para corrigir isto, continue a ler."; "startup.errors.which_alias_issue.subtitle" = "Parece que há um ficheiro em `/usr/local/bin/which`. Isto geralmente é configurado pelo NodeJS, mas `node` não está no PATH em `/usr/local/bin`. Para corrigir isto, continue a ler.";
"startup.errors.which_alias_issue.desc" = "Precisará vincular `node` à diretoria `/usr/local/bin` para garantir que o PHP Monitor possa iniciar com sucesso. Para mais informações, consulte: https://github.com/nicoverbruggen/phpmon/issues/174"; "startup.errors.which_alias_issue.desc" = "Precisará vincular `node` à diretoria `/usr/local/bin` para garantir que o PHP Monitor possa iniciar com sucesso. Para mais informações, consulte: https://github.com/nicoverbruggen/phpmon/issues/174";
// Laravel Herd conflicts
"startup.errors.herd_running.title" = "O Laravel Herd parece estar em execução";
"startup.errors.herd_running.subtitle" = "Parece que o Laravel Herd está atualmente em execução. A configuração integrada do Valet do Herd pode entrar em conflito com a sua instalação regular do Valet. Por favor, encerre o Herd antes de continuar. (Você pode combinar perfeitamente o uso do Herd e do Valet regular, mas não deve executar ambos ao mesmo tempo.)";
"startup.errors.herd_running.desc" = "Você também pode perceber que o alias `php` adicionado pelo Herd ao seu $PATH pode impedir o aliasing do PHP Monitor como `php`, então tenha isso em mente. Você pode verificar o arquivo `~/.zshrc` para ver o que o Herd adicionou ao seu $PATH.";
// Warning about a different PHP version linked than last time // Warning about a different PHP version linked than last time
"startup.version_mismatch.title" = "A sua versão vinculada do PHP mudou."; "startup.version_mismatch.title" = "A sua versão vinculada do PHP mudou.";
"startup.version_mismatch.subtitle" = "Desde que o PHP Monitor esteve ativo a última vez, a sua versão do PHP vinculada foi alterada para PHP %@. Gostaria de voltar para o PHP %@ ou deseja continuar a usar a versão atual?"; "startup.version_mismatch.subtitle" = "Desde que o PHP Monitor esteve ativo a última vez, a sua versão do PHP vinculada foi alterada para PHP %@. Gostaria de voltar para o PHP %@ ou deseja continuar a usar a versão atual?";

View File

@ -646,6 +646,11 @@ Nếu bạn nhìn thấy thông báo này nhưng bối rối vì thư mục này
"startup.errors.which_alias_issue.subtitle" = "Dường như có một tệp trong `/usr/local/bin/which`. Điều này thường được thiết lập bởi NodeJS, nhưng `node` không có trong PATH trong `/usr/local/bin`. Để khắc phục điều này, hãy đọc tiếp."; "startup.errors.which_alias_issue.subtitle" = "Dường như có một tệp trong `/usr/local/bin/which`. Điều này thường được thiết lập bởi NodeJS, nhưng `node` không có trong PATH trong `/usr/local/bin`. Để khắc phục điều này, hãy đọc tiếp.";
"startup.errors.which_alias_issue.desc" = "Bạn sẽ cần tạo liên kết tượng trưng cho `node` vào thư mục `/usr/local/bin` để đảm bảo PHP Monitor có thể khởi động thành công. Để biết thêm thông tin, xem: https://github.com/nicoverbruggen/phpmon/issues/174"; "startup.errors.which_alias_issue.desc" = "Bạn sẽ cần tạo liên kết tượng trưng cho `node` vào thư mục `/usr/local/bin` để đảm bảo PHP Monitor có thể khởi động thành công. Để biết thêm thông tin, xem: https://github.com/nicoverbruggen/phpmon/issues/174";
/// Laravel Herd conflicts
"startup.errors.herd_running.title" = "Có vẻ như Laravel Herd đang chạy";
"startup.errors.herd_running.subtitle" = "Có vẻ như Laravel Herd hiện đang chạy. Cài đặt Valet tích hợp của Herd có thể xung đột với cài đặt Valet thông thường của bạn, vì vậy hãy thoát Herd trước khi tiếp tục. (Bạn có thể hoàn toàn kết hợp sử dụng Herd và Valet thông thường nhưng bạn không nên chạy cả hai cùng một lúc.)";
"startup.errors.herd_running.desc" = "Bạn cũng có thể thấy rằng bí danh `php` mà Herd thêm vào $PATH của bạn có thể ngăn chặn việc đặt bí danh `php` cho PHP Monitor hoạt động, vì vậy hãy lưu ý điều đó. Bạn có thể kiểm tra tệp `~/.zshrc` và xem Herd đã thêm gì vào $PATH của bạn.";
// Warning about a different PHP version linked than last time // Warning about a different PHP version linked than last time
"startup.version_mismatch.title" = "Phiên bản PHP đang hoạt động của bạn đã thay đổi."; "startup.version_mismatch.title" = "Phiên bản PHP đang hoạt động của bạn đã thay đổi.";
"startup.version_mismatch.subtitle" = "Kể từ khi PHP Monitor hoạt động lần cuối, phiên bản PHP được liên kết của bạn đã được thay đổi thành PHP %@. Bạn có muốn chuyển lại sang PHP %@ không, hay bạn muốn tiếp tục sử dụng phiên bản hiện tại?"; "startup.version_mismatch.subtitle" = "Kể từ khi PHP Monitor hoạt động lần cuối, phiên bản PHP được liên kết của bạn đã được thay đổi thành PHP %@. Bạn có muốn chuyển lại sang PHP %@ không, hay bạn muốn tiếp tục sử dụng phiên bản hiện tại?";

View File

@ -27,22 +27,23 @@ final class DomainsListTest: UITestCase {
app.menuItems["mi_domain_list".localized].click() app.menuItems["mi_domain_list".localized].click()
let window = app.windows.allElementsBoundByIndex.first { element in let window = app.windows.element(boundBy: 0)
element.title == "domain_list.title".localized XCTAssertEqual(window.title, "domain_list.title".localized)
}!
let searchField = window.searchFields.firstMatch let searchField = window.searchFields.element(boundBy: 0)
searchField.click() searchField.click()
searchField.typeText("non-existent thing") searchField.typeText("non-existent thing")
Thread.sleep(forTimeInterval: 0.2)
XCTAssertTrue(window.tables.tableRows.count == 0) XCTAssertTrue(window.tables.tableRows.count == 0)
searchField.clearText() searchField.clearText()
searchField.click() searchField.click()
searchField.typeText("concord") searchField.typeText("concord")
Thread.sleep(forTimeInterval: 0.2)
XCTAssertTrue(window.tables.tableRows.count == 1) XCTAssertTrue(window.tables.tableRows.count == 1)
sleep(2) sleep(1)
} }
final func test_can_tap_add_domain_button() throws { final func test_can_tap_add_domain_button() throws {
@ -50,9 +51,8 @@ final class DomainsListTest: UITestCase {
app.menuItems["mi_domain_list".localized].click() app.menuItems["mi_domain_list".localized].click()
let window = app.windows.allElementsBoundByIndex.first { element in let window = app.windows.element(boundBy: 0)
element.title == "domain_list.title".localized XCTAssertEqual(window.title, "domain_list.title".localized)
}!
window.buttons["Add Link"].click() window.buttons["Add Link"].click()
@ -61,6 +61,6 @@ final class DomainsListTest: UITestCase {
assertExists(app.buttons["selection.create_proxy".localized]) assertExists(app.buttons["selection.create_proxy".localized])
assertExists(app.buttons["selection.cancel".localized]) assertExists(app.buttons["selection.cancel".localized])
sleep(2) sleep(1)
} }
} }

View File

@ -58,6 +58,8 @@ final class MainMenuTest: UITestCase {
let app = launch(openMenu: true) let app = launch(openMenu: true)
app.mainMenuItem(withText: "mi_preferences".localized).click() app.mainMenuItem(withText: "mi_preferences".localized).click()
Thread.sleep(forTimeInterval: 0.5)
assertExists(app.buttons["General"]) assertExists(app.buttons["General"])
click(app.buttons["General"]) click(app.buttons["General"])