From 1a9bf38a5d22e9af45f2ac8662098a7c88b148cf Mon Sep 17 00:00:00 2001 From: Nico Verbruggen Date: Thu, 19 Feb 2026 12:15:33 +0100 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Reworked=20AddSiteVC,=20Ad?= =?UTF-8?q?dProxyVC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Reworked add site view with SwiftUI - Reworked add proxy view with SwiftUI - Add missing icon for "Remove proxy" in context menu --- PHP Monitor.xcodeproj/project.pbxproj | 50 ++- phpmon/Domain/App/Base.lproj/Main.storyboard | 398 ------------------ phpmon/Domain/SwiftUI/Common/ErrorView.swift | 26 ++ .../Domain/SwiftUI/Domains/AddProxyView.swift | 128 ++++++ .../Domain/SwiftUI/Domains/AddSiteView.swift | 150 +++++++ .../Modules/Domain List/UI/AddProxyVC.swift | 178 -------- phpmon/Modules/Domain List/UI/AddSiteVC.swift | 157 ------- .../UI/DomainListVC+ContextMenu.swift | 9 +- .../UI/DomainListWindowController.swift | 75 +++- phpmon/en.lproj/Localizable.strings | 2 +- 10 files changed, 401 insertions(+), 772 deletions(-) create mode 100644 phpmon/Domain/SwiftUI/Common/ErrorView.swift create mode 100644 phpmon/Domain/SwiftUI/Domains/AddProxyView.swift create mode 100644 phpmon/Domain/SwiftUI/Domains/AddSiteView.swift delete mode 100644 phpmon/Modules/Domain List/UI/AddProxyVC.swift delete mode 100644 phpmon/Modules/Domain List/UI/AddSiteVC.swift diff --git a/PHP Monitor.xcodeproj/project.pbxproj b/PHP Monitor.xcodeproj/project.pbxproj index 69b7d1b3..435b6fad 100644 --- a/PHP Monitor.xcodeproj/project.pbxproj +++ b/PHP Monitor.xcodeproj/project.pbxproj @@ -22,6 +22,14 @@ 031D74822F46225C00D4FF48 /* SelectDomainTypeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031D74802F46225C00D4FF48 /* SelectDomainTypeView.swift */; }; 031D74832F46225C00D4FF48 /* SelectDomainTypeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031D74802F46225C00D4FF48 /* SelectDomainTypeView.swift */; }; 031D74842F46225C00D4FF48 /* SelectDomainTypeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031D74802F46225C00D4FF48 /* SelectDomainTypeView.swift */; }; + 031D74862F46307300D4FF48 /* AddSiteView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031D74852F46306F00D4FF48 /* AddSiteView.swift */; }; + 031D74872F46307300D4FF48 /* AddSiteView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031D74852F46306F00D4FF48 /* AddSiteView.swift */; }; + 031D74882F46307300D4FF48 /* AddSiteView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031D74852F46306F00D4FF48 /* AddSiteView.swift */; }; + 031D74892F46307300D4FF48 /* AddSiteView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031D74852F46306F00D4FF48 /* AddSiteView.swift */; }; + 031D748B2F46307A00D4FF48 /* AddProxyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031D748A2F46307600D4FF48 /* AddProxyView.swift */; }; + 031D748C2F46307A00D4FF48 /* AddProxyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031D748A2F46307600D4FF48 /* AddProxyView.swift */; }; + 031D748D2F46307A00D4FF48 /* AddProxyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031D748A2F46307600D4FF48 /* AddProxyView.swift */; }; + 031D748E2F46307A00D4FF48 /* AddProxyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031D748A2F46307600D4FF48 /* AddProxyView.swift */; }; 031E2B692B1525A7007C29E1 /* BrewPhpExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031E2B682B1525A7007C29E1 /* BrewPhpExtension.swift */; }; 031E2B6A2B1525A7007C29E1 /* BrewPhpExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031E2B682B1525A7007C29E1 /* BrewPhpExtension.swift */; }; 031E2B6B2B1525A7007C29E1 /* BrewPhpExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031E2B682B1525A7007C29E1 /* BrewPhpExtension.swift */; }; @@ -181,6 +189,10 @@ 03DAD3A72EB3B08F003417BD /* DomainListVC+Certs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03DAD3A52EB3B08A003417BD /* DomainListVC+Certs.swift */; }; 03DAD3A82EB3B08F003417BD /* DomainListVC+Certs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03DAD3A52EB3B08A003417BD /* DomainListVC+Certs.swift */; }; 03DAD3A92EB3B08F003417BD /* DomainListVC+Certs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03DAD3A52EB3B08A003417BD /* DomainListVC+Certs.swift */; }; + 03EC943C2F47297B00231276 /* ErrorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03EC943B2F47297100231276 /* ErrorView.swift */; }; + 03EC943D2F47297B00231276 /* ErrorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03EC943B2F47297100231276 /* ErrorView.swift */; }; + 03EC943E2F47297B00231276 /* ErrorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03EC943B2F47297100231276 /* ErrorView.swift */; }; + 03EC943F2F47297B00231276 /* ErrorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03EC943B2F47297100231276 /* ErrorView.swift */; }; 03FE39E72E81682800B7B5AC /* AppIcon.icon in Resources */ = {isa = PBXBuildFile; fileRef = 03FE39E52E81682800B7B5AC /* AppIcon.icon */; }; 03FE39E82E81682800B7B5AC /* AppIconEAP.icon in Resources */ = {isa = PBXBuildFile; fileRef = 03FE39E62E81682800B7B5AC /* AppIconEAP.icon */; }; 03FE39EA2E81694500B7B5AC /* AppIconUD.icon in Resources */ = {isa = PBXBuildFile; fileRef = 03FE39E92E81694500B7B5AC /* AppIconUD.icon */; }; @@ -607,8 +619,6 @@ C471E85D28F9BB650021E251 /* DomainListVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C464ADAE275A7A69003FCD53 /* DomainListVC.swift */; }; C471E85E28F9BB650021E251 /* DomainListVC+ContextMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41E87192763D42300161EE0 /* DomainListVC+ContextMenu.swift */; }; C471E85F28F9BB650021E251 /* DomainListVC+Actions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41CA5EC2774F8EE00A2C80E /* DomainListVC+Actions.swift */; }; - C471E86128F9BB650021E251 /* AddSiteVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4930849279F331F009C240B /* AddSiteVC.swift */; }; - C471E86228F9BB650021E251 /* AddProxyVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D9F24A280B69E100DCD39A /* AddProxyVC.swift */; }; C471E86328F9BB650021E251 /* PMTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A81CA328C67101008DD9D1 /* PMTableView.swift */; }; C471E86428F9BB650021E251 /* Warning.swift in Sources */ = {isa = PBXBuildFile; fileRef = C47699F028A2F3150060FEB8 /* Warning.swift */; }; C471E86528F9BB650021E251 /* WarningManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C47699EE28A2F2A30060FEB8 /* WarningManager.swift */; }; @@ -690,8 +700,6 @@ C471E8C028F9BB8F0021E251 /* DomainListVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C464ADAE275A7A69003FCD53 /* DomainListVC.swift */; }; C471E8C128F9BB8F0021E251 /* DomainListVC+ContextMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41E87192763D42300161EE0 /* DomainListVC+ContextMenu.swift */; }; C471E8C228F9BB8F0021E251 /* DomainListVC+Actions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41CA5EC2774F8EE00A2C80E /* DomainListVC+Actions.swift */; }; - C471E8C428F9BB8F0021E251 /* AddSiteVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4930849279F331F009C240B /* AddSiteVC.swift */; }; - C471E8C528F9BB8F0021E251 /* AddProxyVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D9F24A280B69E100DCD39A /* AddProxyVC.swift */; }; C471E8C628F9BB8F0021E251 /* PMTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A81CA328C67101008DD9D1 /* PMTableView.swift */; }; C471E8C728F9BB8F0021E251 /* Warning.swift in Sources */ = {isa = PBXBuildFile; fileRef = C47699F028A2F3150060FEB8 /* Warning.swift */; }; C471E8C828F9BB8F0021E251 /* WarningManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C47699EE28A2F2A30060FEB8 /* WarningManager.swift */; }; @@ -782,8 +790,6 @@ C490E3BF29BCA376006D2DE6 /* Measurements.swift in Sources */ = {isa = PBXBuildFile; fileRef = C49EAA5129B12A5A00AB28FC /* Measurements.swift */; }; C4927F0B27B2DFC200C55AFD /* Errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4927F0A27B2DFC200C55AFD /* Errors.swift */; }; C4927F0C27B2DFC200C55AFD /* Errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4927F0A27B2DFC200C55AFD /* Errors.swift */; }; - C493084A279F331F009C240B /* AddSiteVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4930849279F331F009C240B /* AddSiteVC.swift */; }; - C493084B279F331F009C240B /* AddSiteVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4930849279F331F009C240B /* AddSiteVC.swift */; }; C495F5AF28A42E080087F70A /* EnvironmentCheck.swift in Sources */ = {isa = PBXBuildFile; fileRef = C495F5AE28A42E080087F70A /* EnvironmentCheck.swift */; }; C495F5B028A42E080087F70A /* EnvironmentCheck.swift in Sources */ = {isa = PBXBuildFile; fileRef = C495F5AE28A42E080087F70A /* EnvironmentCheck.swift */; }; C4998F0A2617633900B2526E /* PreferencesWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4998F092617633900B2526E /* PreferencesWindowController.swift */; }; @@ -911,8 +917,6 @@ C4D9ADC0277610E1007277F4 /* PhpSwitcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D9ADBE277610E1007277F4 /* PhpSwitcher.swift */; }; C4D9ADC8277611A0007277F4 /* InternalSwitcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D9ADC7277611A0007277F4 /* InternalSwitcher.swift */; }; C4D9ADC9277611A0007277F4 /* InternalSwitcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D9ADC7277611A0007277F4 /* InternalSwitcher.swift */; }; - C4D9F24B280B69E100DCD39A /* AddProxyVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D9F24A280B69E100DCD39A /* AddProxyVC.swift */; }; - C4D9F24C280B69E100DCD39A /* AddProxyVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D9F24A280B69E100DCD39A /* AddProxyVC.swift */; }; C4DEB7D427A5D60B00834718 /* Stats.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4DEB7D327A5D60B00834718 /* Stats.swift */; }; C4E0F7ED27BEBDA9007475F2 /* NSWindowExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4E0F7EC27BEBDA9007475F2 /* NSWindowExtension.swift */; }; C4E0F7EE27BEBDA9007475F2 /* NSWindowExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4E0F7EC27BEBDA9007475F2 /* NSWindowExtension.swift */; }; @@ -1042,6 +1046,8 @@ 0309E6662B0D4B2F002AC007 /* BrewExtensionsObservable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrewExtensionsObservable.swift; sourceTree = ""; }; 031D747B2F46225600D4FF48 /* SimpleButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleButton.swift; sourceTree = ""; }; 031D74802F46225C00D4FF48 /* SelectDomainTypeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectDomainTypeView.swift; sourceTree = ""; }; + 031D74852F46306F00D4FF48 /* AddSiteView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddSiteView.swift; sourceTree = ""; }; + 031D748A2F46307600D4FF48 /* AddProxyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddProxyView.swift; sourceTree = ""; }; 031E2B682B1525A7007C29E1 /* BrewPhpExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrewPhpExtension.swift; sourceTree = ""; }; 031F247F2EA1071700CFB8D9 /* Container+Fake.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Container+Fake.swift"; sourceTree = ""; }; 031F24842EA1132300CFB8D9 /* PHP Monitor.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = "PHP Monitor.xctestplan"; sourceTree = ""; }; @@ -1096,6 +1102,7 @@ 03D846242EB6344A006EFE3C /* DomainListVC+Window.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DomainListVC+Window.swift"; sourceTree = ""; }; 03D846312EB64E35006EFE3C /* CrashReporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrashReporter.swift; sourceTree = ""; }; 03DAD3A52EB3B08A003417BD /* DomainListVC+Certs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DomainListVC+Certs.swift"; sourceTree = ""; }; + 03EC943B2F47297100231276 /* ErrorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorView.swift; sourceTree = ""; }; 03FE39E52E81682800B7B5AC /* AppIcon.icon */ = {isa = PBXFileReference; lastKnownFileType = folder.iconcomposer.icon; path = AppIcon.icon; sourceTree = ""; }; 03FE39E62E81682800B7B5AC /* AppIconEAP.icon */ = {isa = PBXFileReference; lastKnownFileType = folder.iconcomposer.icon; path = AppIconEAP.icon; sourceTree = ""; }; 03FE39E92E81694500B7B5AC /* AppIconUD.icon */ = {isa = PBXFileReference; lastKnownFileType = folder.iconcomposer.icon; path = AppIconUD.icon; sourceTree = ""; }; @@ -1258,7 +1265,6 @@ C48D6C73279CD3E400F26D7E /* PhpVersionNumberTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhpVersionNumberTest.swift; sourceTree = ""; }; C48DDD0C29C75C9E00D032D9 /* BlockingOverlayView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockingOverlayView.swift; sourceTree = ""; }; C4927F0A27B2DFC200C55AFD /* Errors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Errors.swift; sourceTree = ""; }; - C4930849279F331F009C240B /* AddSiteVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddSiteVC.swift; sourceTree = ""; }; C495F5AE28A42E080087F70A /* EnvironmentCheck.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnvironmentCheck.swift; sourceTree = ""; }; C4998F092617633900B2526E /* PreferencesWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesWindowController.swift; sourceTree = ""; }; C49DA9BC2D67AC49006F9CF4 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = ""; }; @@ -1319,7 +1325,6 @@ C4D936C827E3EB6100BD69FE /* PhpHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpHelper.swift; sourceTree = ""; }; C4D9ADBE277610E1007277F4 /* PhpSwitcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpSwitcher.swift; sourceTree = ""; }; C4D9ADC7277611A0007277F4 /* InternalSwitcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InternalSwitcher.swift; sourceTree = ""; }; - C4D9F24A280B69E100DCD39A /* AddProxyVC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddProxyVC.swift; sourceTree = ""; }; C4DD662A2A4A1B4E00D6A731 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = ""; }; C4DEB7D327A5D60B00834718 /* Stats.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Stats.swift; sourceTree = ""; }; C4E0F7EC27BEBDA9007475F2 /* NSWindowExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSWindowExtension.swift; sourceTree = ""; }; @@ -1972,8 +1977,6 @@ 03DAD3A52EB3B08A003417BD /* DomainListVC+Certs.swift */, C41E87192763D42300161EE0 /* DomainListVC+ContextMenu.swift */, C41CA5EC2774F8EE00A2C80E /* DomainListVC+Actions.swift */, - C4930849279F331F009C240B /* AddSiteVC.swift */, - C4D9F24A280B69E100DCD39A /* AddProxyVC.swift */, C44067F327E256560045BD4E /* Cells */, C44DFA872A67092300B98ED5 /* Subclass */, ); @@ -2265,6 +2268,7 @@ C4B609162853AA9A00C95265 /* Common */ = { isa = PBXGroup; children = ( + 03EC943B2F47297100231276 /* ErrorView.swift */, 031D747B2F46225600D4FF48 /* SimpleButton.swift */, C44264BD2850B86C007400F1 /* SwiftUIHelper.swift */, C451AFF52969E40F0078E617 /* HelpButton.swift */, @@ -2289,6 +2293,8 @@ C4B609182853AAA700C95265 /* Domains */ = { isa = PBXGroup; children = ( + 031D748A2F46307600D4FF48 /* AddProxyView.swift */, + 031D74852F46306F00D4FF48 /* AddSiteView.swift */, 031D74802F46225C00D4FF48 /* SelectDomainTypeView.swift */, 0392CDEA2EB25371009176DA /* SecurePopoverView.swift */, C44264BF2850BD2A007400F1 /* VersionPopoverView.swift */, @@ -2863,7 +2869,6 @@ 0392CDEB2EB25371009176DA /* SecurePopoverView.swift in Sources */, C4E4404627C56F4700D225E1 /* ValetSite.swift in Sources */, C4F2E43A2752F7D00020E974 /* PhpInstallation.swift in Sources */, - C4D9F24B280B69E100DCD39A /* AddProxyVC.swift in Sources */, C45B914E295608E300F4EC78 /* ValetServicesManager.swift in Sources */, C4D5576429C77CC5001A44CD /* PhpVersionManagerWindowController.swift in Sources */, C4E49DED28F764A00026AC4E /* TestableCommand.swift in Sources */, @@ -2920,6 +2925,7 @@ 54D9E0B827E4F51E003B9AD9 /* KeyCombo.swift in Sources */, C4C0E8E727F88B41002D32A9 /* DomainScanner.swift in Sources */, C4C3ED4327834C5200AB15D8 /* CustomPrefs.swift in Sources */, + 03EC943D2F47297B00231276 /* ErrorView.swift in Sources */, 54B48B5F275F66AE006D90C5 /* Application.swift in Sources */, C4B97B78275CF1B5003F3378 /* App+ActivationPolicy.swift in Sources */, C4CE3BB827B31F2E0086CA49 /* MainMenu+Switcher.swift in Sources */, @@ -2991,6 +2997,7 @@ C4D3660B29113F20006BD146 /* System.swift in Sources */, C4D36601291132B7006BD146 /* ValetScanners.swift in Sources */, 03ACC6472ECCBA130070D4CD /* CaskFile+API.swift in Sources */, + 031D74872F46307300D4FF48 /* AddSiteView.swift in Sources */, 0386B0B52ED36C3D00CA6795 /* Locked.swift in Sources */, C4EED88927A48778006D7272 /* InterAppHandler.swift in Sources */, C40C7F1E2772136000DDDCDC /* PhpEnvironments.swift in Sources */, @@ -3031,6 +3038,7 @@ C43BCD4429FBEF40001547BC /* ModifyPhpVersionCommand.swift in Sources */, C4E2E84A28FC1E70003B070C /* DataExtension.swift in Sources */, C46FA23F246C358E00944F05 /* StringExtension.swift in Sources */, + 031D748C2F46307A00D4FF48 /* AddProxyView.swift in Sources */, C42337A3281F19F000459A48 /* Xdebug.swift in Sources */, C4B97B75275CF08C003F3378 /* AppDelegate+MenuOutlets.swift in Sources */, C464ADAC275A7A3F003FCD53 /* DomainListWindowController.swift in Sources */, @@ -3038,7 +3046,6 @@ C42E3F772AB0D2880096DFC2 /* ConfigManagerWindowController.swift in Sources */, C464ADB2275A87CA003FCD53 /* DomainListCellProtocol.swift in Sources */, C4EE188422D3386B00E126E5 /* Constants.swift in Sources */, - C493084A279F331F009C240B /* AddSiteVC.swift in Sources */, C4DEB7D427A5D60B00834718 /* Stats.swift in Sources */, 039C29182E8AA314007F5FAB /* TestableWebApi.swift in Sources */, C47015022C46D6910069AAE7 /* NVAlertExtension.swift in Sources */, @@ -3130,8 +3137,6 @@ C4D5576629C77CC5001A44CD /* PhpVersionManagerWindowController.swift in Sources */, C47015042C46D7F00069AAE7 /* NVAlertExtension.swift in Sources */, C4ACE9E329F84EDD00110766 /* PhpGuard.swift in Sources */, - C471E86128F9BB650021E251 /* AddSiteVC.swift in Sources */, - C471E86228F9BB650021E251 /* AddProxyVC.swift in Sources */, C471E86328F9BB650021E251 /* PMTableView.swift in Sources */, C471E86428F9BB650021E251 /* Warning.swift in Sources */, 03C29A772EC88E3100FBA25E /* ValetServicesDataManager.swift in Sources */, @@ -3147,6 +3152,7 @@ C471E86728F9BB650021E251 /* OnboardingWindowController.swift in Sources */, C471E86828F9BB650021E251 /* PreferencesWindowController.swift in Sources */, C471E86928F9BB650021E251 /* PreferencesWindowController+Hotkey.swift in Sources */, + 031D74862F46307300D4FF48 /* AddSiteView.swift in Sources */, C48DDD0F29C75C9E00D032D9 /* BlockingOverlayView.swift in Sources */, C4AFC4B029C4F32F00BF4E0D /* BrewPhpFormula.swift in Sources */, C471E86A28F9BB650021E251 /* PreferencesVC.swift in Sources */, @@ -3154,6 +3160,7 @@ C471E86C28F9BB650021E251 /* Preferences.swift in Sources */, C4D3660D29113F20006BD146 /* System.swift in Sources */, 033D45A02B0D513900070080 /* RemovePhpExtensionCommand.swift in Sources */, + 031D748B2F46307A00D4FF48 /* AddProxyView.swift in Sources */, C471E86D28F9BB650021E251 /* CustomPrefs.swift in Sources */, C45D654E29F52F74004C28F9 /* BrewPermissionFixer.swift in Sources */, C4E2E84C28FC1E70003B070C /* DataExtension.swift in Sources */, @@ -3261,6 +3268,7 @@ C471E82028F9BB290021E251 /* NginxConfigurationFile.swift in Sources */, 032DAC2D2E8BEB6B0018E01C /* WebApiProtocol.swift in Sources */, C4513F902B13E2E6001AD760 /* PhpExtensionManagerWindowController.swift in Sources */, + 03EC943F2F47297B00231276 /* ErrorView.swift in Sources */, C471E81528F9BAE80021E251 /* ArrayExtension.swift in Sources */, C471E7DA28F9BA8F0021E251 /* TestableCommand.swift in Sources */, C471E7E528F9BAC20021E251 /* Events.swift in Sources */, @@ -3306,6 +3314,7 @@ C471E89828F9BB8F0021E251 /* ValetProxy.swift in Sources */, C471E89A28F9BB8F0021E251 /* DomainScanner.swift in Sources */, C471E89C28F9BB8F0021E251 /* ValetSite.swift in Sources */, + 031D74882F46307300D4FF48 /* AddSiteView.swift in Sources */, C471E89D28F9BB8F0021E251 /* FakeValetSite.swift in Sources */, C471E89F28F9BB8F0021E251 /* ValetDomainScanner.swift in Sources */, C471E8A028F9BB8F0021E251 /* FakeDomainScanner.swift in Sources */, @@ -3350,6 +3359,7 @@ C471E8BB28F9BB8F0021E251 /* DomainListNameCell.swift in Sources */, C471E8BC28F9BB8F0021E251 /* DomainListPhpCell.swift in Sources */, C471E8BD28F9BB8F0021E251 /* DomainListTypeCell.swift in Sources */, + 031D748D2F46307A00D4FF48 /* AddProxyView.swift in Sources */, C471E8BE28F9BB8F0021E251 /* DomainListKindCell.swift in Sources */, C4E2E86A28FC3002003B070C /* Utility.swift in Sources */, 031E2B6C2B1525A7007C29E1 /* BrewPhpExtension.swift in Sources */, @@ -3360,9 +3370,7 @@ C4BF56AE2949381100379603 /* FakeValetInteractor.swift in Sources */, C471E8C228F9BB8F0021E251 /* DomainListVC+Actions.swift in Sources */, C4821C5D2C2DEDE200357A68 /* AppMenu.swift in Sources */, - C471E8C428F9BB8F0021E251 /* AddSiteVC.swift in Sources */, C45B91562956123A00F4EC78 /* FakeServicesManager.swift in Sources */, - C471E8C528F9BB8F0021E251 /* AddProxyVC.swift in Sources */, C471E8C628F9BB8F0021E251 /* PMTableView.swift in Sources */, C471E8C728F9BB8F0021E251 /* Warning.swift in Sources */, 033E9DFC2F44D93000685F62 /* Startup+Alert.swift in Sources */, @@ -3393,6 +3401,7 @@ C471E8D728F9BB8F0021E251 /* SelectPreferenceView.swift in Sources */, 03C29A7A2EC88E3100FBA25E /* ValetServicesDataManager.swift in Sources */, C471E8D928F9BB8F0021E251 /* HotkeyPreferenceView.swift in Sources */, + 03EC943E2F47297B00231276 /* ErrorView.swift in Sources */, C4611E5D2AEAD2FA0010BE24 /* ConfigManagerView.swift in Sources */, C471E8DA28F9BB8F0021E251 /* Keys.swift in Sources */, C471E8DB28F9BB8F0021E251 /* TerminalProgressWindowController.swift in Sources */, @@ -3546,7 +3555,6 @@ C4D3661B291173EA006BD146 /* DictionaryExtension.swift in Sources */, C45D654D29F52F74004C28F9 /* BrewPermissionFixer.swift in Sources */, C4F780C825D80B75000DBC97 /* DateExtension.swift in Sources */, - C493084B279F331F009C240B /* AddSiteVC.swift in Sources */, C44A874928905BB000498BC4 /* ProgressVC.swift in Sources */, 0379C4A62ED720220035D7EA /* App+DetectApps.swift in Sources */, C4D9ADC0277610E1007277F4 /* PhpSwitcher.swift in Sources */, @@ -3572,10 +3580,12 @@ 037F44162EDB0AAA002EBF75 /* FSNotifierTest.swift in Sources */, C4FBFC532616485F00CDB8E1 /* PhpVersionDetectionTest.swift in Sources */, C43A8A2425D9D20D00591B77 /* HomebrewPackageTest.swift in Sources */, + 031D748E2F46307A00D4FF48 /* AddProxyView.swift in Sources */, C485707928BF456C00539B36 /* ArrayExtension.swift in Sources */, C4F780CA25D80B75000DBC97 /* HomebrewDecodable.swift in Sources */, C4F319C927B034A500AFF46F /* Stats.swift in Sources */, C4F30B04278E16BA00755FCE /* HomebrewService.swift in Sources */, + 03EC943C2F47297B00231276 /* ErrorView.swift in Sources */, 54D9E0B527E4F51E003B9AD9 /* Key.swift in Sources */, C4AF9F7B2754499000D44ED0 /* Valet.swift in Sources */, C4C1019C27C65C6F001FACC2 /* Process.swift in Sources */, @@ -3752,7 +3762,6 @@ 0392CDEC2EB25371009176DA /* SecurePopoverView.swift in Sources */, C41C02AB27E61CB3009F26CB /* FakeValetSite.swift in Sources */, C4F780C925D80B75000DBC97 /* StringExtension.swift in Sources */, - C4D9F24C280B69E100DCD39A /* AddProxyVC.swift in Sources */, C4D4CB3829C109CF00DB9F93 /* InternalSwitcher+Valet.swift in Sources */, C4B79EB729CA387F00A483EE /* BrewPhpFormulaeHandler.swift in Sources */, C4B5853F2770FE3900DA4FBE /* Paths.swift in Sources */, @@ -3762,6 +3771,7 @@ C4E0F7EE27BEBDA9007475F2 /* NSWindowExtension.swift in Sources */, C4A81CA528C67101008DD9D1 /* PMTableView.swift in Sources */, C45E76152854A65300B4FE0C /* ServicesManager.swift in Sources */, + 031D74892F46307300D4FF48 /* AddSiteView.swift in Sources */, C4D36602291132B7006BD146 /* ValetScanners.swift in Sources */, C40934AB298EEDA900D25014 /* CaskFileParserTest.swift in Sources */, C436B39E29F3C42500B6A64E /* PreferencesTabs.swift in Sources */, diff --git a/phpmon/Domain/App/Base.lproj/Main.storyboard b/phpmon/Domain/App/Base.lproj/Main.storyboard index 0ecc4d10..8551db67 100644 --- a/phpmon/Domain/App/Base.lproj/Main.storyboard +++ b/phpmon/Domain/App/Base.lproj/Main.storyboard @@ -457,188 +457,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1022,222 +840,6 @@ Gw - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/phpmon/Domain/SwiftUI/Common/ErrorView.swift b/phpmon/Domain/SwiftUI/Common/ErrorView.swift new file mode 100644 index 00000000..21ed5e81 --- /dev/null +++ b/phpmon/Domain/SwiftUI/Common/ErrorView.swift @@ -0,0 +1,26 @@ +// +// ErrorView.swift +// PHP Monitor +// +// Created by Nico Verbruggen on 19/02/2026. +// Copyright © 2026 Nico Verbruggen. All rights reserved. +// + +import SwiftUI + +struct ErrorView: View { + let message: String + + var body: some View { + HStack(spacing: 4) { + Image(systemName: "exclamationmark.triangle.fill") + Text(message) + .fixedSize(horizontal: false, vertical: true) + Spacer() + } + .padding(.horizontal, 20) + .padding(.vertical, 10) + .background(.statusColorRed.opacity(0.1)) + .font(.system(size: 11)) + } +} diff --git a/phpmon/Domain/SwiftUI/Domains/AddProxyView.swift b/phpmon/Domain/SwiftUI/Domains/AddProxyView.swift new file mode 100644 index 00000000..f09ff820 --- /dev/null +++ b/phpmon/Domain/SwiftUI/Domains/AddProxyView.swift @@ -0,0 +1,128 @@ +// +// AddProxyView.swift +// PHP Monitor +// +// Created by Nico Verbruggen on 18/02/2026. +// Copyright © 2026 Nico Verbruggen. All rights reserved. +// + +import SwiftUI + +struct AddProxyView: View { + let tld: String + var onCancel: () -> Void + var onConfirm: (String, String, Bool) -> Void + var domainExists: (String) -> Bool + + @State private var domainName: String = "" + @State private var proxySubject: String = "http://127.0.0.1:80" + @State private var secure: Bool = false + + private var validationError: String? { + if domainName.isEmpty { + return "domain_list.add.errors.empty".localized + } + if proxySubject.isEmpty { + return "domain_list.add.errors.empty_proxy".localized + } + if proxySubject.range(of: #"(http:\/\/|https:\/\/)(.+)(:)(\d+)$"#, options: .regularExpression) == nil { + return "domain_list.add.errors.subject_invalid".localized + } + if domainExists(domainName) { + return "domain_list.add.errors.already_exists".localized + } + return nil + } + + private var isValid: Bool { validationError == nil } + + private var preview: String { + guard !proxySubject.isEmpty, !domainName.isEmpty else { + return "domain_list.add.empty_fields".localized + } + let key = proxySubject.starts(with: "https://") + ? "domain_list.add.proxy_https_warning" + : "domain_list.add.proxy_available" + return key.localized( + proxySubject, + secure ? "https" : "http", + domainName, + tld + ) + } + + var body: some View { + VStack(alignment: .leading, spacing: 0) { + VStack(alignment: .leading, spacing: 12) { + Text("domain_list.add.set_up_proxy") + .font(.system(size: 16, weight: .bold, design: .default)) + + Text("domain_list.add.proxy_subject") + .foregroundColor(.secondary) + .font(.system(size: 11)) + TextField("", text: Binding( + get: { proxySubject }, + set: { proxySubject = $0.replacing(" ", with: "-") } + )) + + Text("domain_list.add.domain_name") + .foregroundColor(.secondary) + .font(.system(size: 11)) + TextField("", text: Binding( + get: { domainName }, + set: { domainName = $0.replacing(" ", with: "-") } + )) + + Text(preview) + .foregroundColor(.secondary) + .font(.system(size: 11)) + + Toggle( + "domain_list.add.secure_after_creation".localized(domainName, tld), + isOn: $secure + ) + + Text("domain_list.add.secure_description") + .foregroundColor(.secondary) + .font(.system(size: 11)) + .fixedSize(horizontal: false, vertical: true) + } + .padding(20) + + Divider() + + VStack(alignment: .leading, spacing: 0) { + if let error = validationError { + ErrorView(message: error) + } + + if validationError != nil { + Divider() + } + + HStack { + Button("domain_list.add.cancel".localized) { + onCancel() + } + Spacer() + SimpleButton( + title: "domain_list.add.create_proxy".localized, + imageName: "IconProxy", + action: { onConfirm(domainName, proxySubject, secure) } + ) + .disabled(!isValid) + }.padding(20) + } + } + .frame(width: 550) + } +} + +#Preview { + AddProxyView( + tld: "test", + onCancel: {}, + onConfirm: { _, _, _ in }, + domainExists: { _ in false } + ) +} diff --git a/phpmon/Domain/SwiftUI/Domains/AddSiteView.swift b/phpmon/Domain/SwiftUI/Domains/AddSiteView.swift new file mode 100644 index 00000000..bc81119e --- /dev/null +++ b/phpmon/Domain/SwiftUI/Domains/AddSiteView.swift @@ -0,0 +1,150 @@ +// +// AddSiteView.swift +// PHP Monitor +// +// Created by Nico Verbruggen on 18/02/2026. +// Copyright © 2026 Nico Verbruggen. All rights reserved. +// + +import SwiftUI +import AppKit + +private struct PathControl: NSViewRepresentable { + let url: URL + + func makeNSView(context: Context) -> NSPathControl { + let control = NSPathControl() + control.isEditable = false + control.url = url + return control + } + + func updateNSView(_ nsView: NSPathControl, context: Context) { + nsView.url = url + } +} + +struct AddSiteView: View { + let path: String + + let tld: String + var onCancel: () -> Void + var onConfirm: (String, Bool) -> Void + var domainExists: (String) -> Bool + + @State private var domainName: String + @State private var secure: Bool = false + + init( + path: String, + tld: String, + onCancel: @escaping () -> Void, + onConfirm: @escaping (String, Bool) -> Void, + domainExists: @escaping (String) -> Bool + ) { + self.path = path + self.tld = tld + self.onCancel = onCancel + self.onConfirm = onConfirm + self.domainExists = domainExists + + let initial = String(path + .split(separator: "/") + .last ?? "") + .lowercased() + + _domainName = State(initialValue: initial) + } + + private var validationError: String? { + if domainName.isEmpty { + return "domain_list.add.errors.empty".localized + } + if domainExists(domainName) { + return "domain_list.add.errors.already_exists".localized + } + return nil + } + + private var isValid: Bool { validationError == nil && !domainName.isEmpty } + + private var preview: String { + guard !domainName.isEmpty else { + return "domain_list.add.empty_fields".localized + } + return "domain_list.add.folder_available".localized( + secure ? "https" : "http", + domainName, + tld + ) + } + + var body: some View { + VStack(alignment: .leading, spacing: 0) { + VStack(alignment: .leading, spacing: 15) { + Text("domain_list.add.link_folder") + .font(.system(size: 16, weight: .bold, design: .default)) + + PathControl(url: URL(fileURLWithPath: path)) + .frame(height: 22) + + TextField("domain_list.add.domain_name_placeholder".localized, text: Binding( + get: { domainName }, + set: { domainName = $0.replacing(" ", with: "-") } + )) + + Text(preview) + .foregroundColor(.secondary) + .font(.system(size: 11)) + + Toggle( + "domain_list.add.secure_after_creation".localized(domainName, tld), + isOn: $secure + ) + + Text("domain_list.add.secure_description") + .foregroundColor(.secondary) + .font(.system(size: 11)) + .fixedSize(horizontal: false, vertical: true) + } + .padding(20) + + Divider() + + VStack(alignment: .leading, spacing: 0) { + if let error = validationError { + ErrorView(message: error) + } + + if validationError != nil { + Divider() + } + + HStack { + Button("domain_list.add.cancel".localized) { + onCancel() + } + Spacer() + SimpleButton( + title: "domain_list.add.create_link".localized, + imageName: "IconLinked", + action: { onConfirm(domainName, secure) } + ) + .disabled(!isValid) + }.padding(20) + } + + } + .frame(width: 550) + } +} + +#Preview { + AddSiteView( + path: "/Users/nico/Code/my-website", + tld: "test", + onCancel: {}, + onConfirm: { _, _ in }, + domainExists: { _ in false } + ).frame(height: 350) +} diff --git a/phpmon/Modules/Domain List/UI/AddProxyVC.swift b/phpmon/Modules/Domain List/UI/AddProxyVC.swift deleted file mode 100644 index cdeb204f..00000000 --- a/phpmon/Modules/Domain List/UI/AddProxyVC.swift +++ /dev/null @@ -1,178 +0,0 @@ -// -// AddSiteVC.swift -// PHP Monitor -// -// Created by Nico Verbruggen on 24/01/2022. -// Copyright © 2025 Nico Verbruggen. All rights reserved. -// - -import Foundation -import Cocoa - -class AddProxyVC: NSViewController, NSTextFieldDelegate { - - // MARK: - Outlets - - @IBOutlet weak var textFieldTitle: NSTextField! - @IBOutlet weak var textFieldProxySubject: NSTextField! - @IBOutlet weak var textFieldDomainName: NSTextField! - - @IBOutlet weak var inputProxySubject: NSTextField! - @IBOutlet weak var inputDomainName: NSTextField! - - @IBOutlet weak var previewText: NSTextField! - - @IBOutlet weak var buttonSecure: NSButton! - @IBOutlet weak var buttonCreateProxy: NSButton! - @IBOutlet weak var buttonCancel: NSButton! - - @IBOutlet weak var textFieldSecure: NSTextField! - @IBOutlet weak var textFieldError: NSTextField! - - // MARK: - View Lifecycle - - override func viewDidLoad() { - super.viewDidLoad() - loadStaticLocalisedStrings() - - buttonCreateProxy.isEnabled = false - updatePreview() - validate() - } - - private func dismissView(outcome: NSApplication.ModalResponse) { - guard let window = view.window, let parent = window.sheetParent else { return } - parent.endSheet(window, returnCode: outcome) - } - - // MARK: - Localisation - - func loadStaticLocalisedStrings() { - textFieldTitle.stringValue = "domain_list.add.set_up_proxy".localized - textFieldProxySubject.stringValue = "domain_list.add.proxy_subject".localized - textFieldDomainName.stringValue = "domain_list.add.domain_name".localized - textFieldSecure.stringValue = "domain_list.add.secure_description".localized - buttonCancel.title = "domain_list.add.cancel".localized - buttonCreateProxy.title = "domain_list.add.create_proxy".localized - } - - // MARK: - Outlet Interactions - - @IBAction func pressedSecure(_ sender: Any) { - updatePreview() - } - - @IBAction func pressedCreateProxy(_ sender: Any) { - let domain = self.inputDomainName.stringValue - let proxyName = self.inputProxySubject.stringValue - let secure = (self.buttonSecure.state == .on) - - dismissView(outcome: .OK) - - App.shared.domainListWindowController?.contentVC.setUIBusy() - - Task { // Ensure we proxy the site asynchronously and reload UI on main thread again - try? await ValetInteractor.shared.proxy( - domain: domain, - proxy: proxyName, - secure: secure - ) - - Task { @MainActor in - App.shared.domainListWindowController?.contentVC.setUINotBusy() - App.shared.domainListWindowController?.pressedReload(nil) - } - } - } - - @IBAction func pressedCancel(_ sender: Any) { - dismissView(outcome: .cancel) - } - - // MARK: - Text Field Delegate - - func controlTextDidChange(_ obj: Notification) { - updateTextField() - } - - // MARK: - Helper Methods - - private func validate() { - _ = validate( - domain: inputDomainName.stringValue, - proxy: inputProxySubject.stringValue - ) - } - - private func validate(domain: String, proxy: String) -> Bool { - if proxy.isEmpty { - textFieldError.isHidden = false - textFieldError.stringValue = "domain_list.add.errors.empty_proxy".localized - return false - } - - if proxy.range(of: #"(http:\/\/|https:\/\/)(.+)(:)(\d+)$"#, options: .regularExpression) == nil { - textFieldError.isHidden = false - textFieldError.stringValue = "domain_list.add.errors.subject_invalid".localized - return false - } - - if domain.isEmpty { - textFieldError.isHidden = false - textFieldError.stringValue = "domain_list.add.errors.empty".localized - return false - } - - if Valet.shared.sites.contains(where: { $0.name == domain }) { - textFieldError.isHidden = false - textFieldError.stringValue = "domain_list.add.errors.already_exists".localized - return false - } - - textFieldError.isHidden = true - return true - } - - func updateTextField() { - inputDomainName.stringValue = inputDomainName.stringValue - .replacing(" ", with: "-") - - inputProxySubject.stringValue = inputProxySubject.stringValue - .replacing(" ", with: "-") - - buttonCreateProxy.isEnabled = validate( - domain: inputDomainName.stringValue, - proxy: inputProxySubject.stringValue - ) - - updatePreview() - } - - func updatePreview() { - buttonSecure.title = "domain_list.add.secure_after_creation" - .localized( - inputDomainName.stringValue, - Valet.shared.config.tld - ) - - if inputProxySubject.stringValue.isEmpty || inputDomainName.stringValue.isEmpty { - previewText.stringValue = "domain_list.add.empty_fields".localized - return - } - - var translationKey = "domain_list.add.proxy_available" - - if inputProxySubject.stringValue.starts(with: "https://") { - translationKey = "domain_list.add.proxy_https_warning" - } - - previewText.stringValue = - translationKey.localized( - inputProxySubject.stringValue, - buttonSecure.state == .on ? "https" : "http", - inputDomainName.stringValue, - Valet.shared.config.tld - ) - } - -} diff --git a/phpmon/Modules/Domain List/UI/AddSiteVC.swift b/phpmon/Modules/Domain List/UI/AddSiteVC.swift deleted file mode 100644 index 6b5b99b3..00000000 --- a/phpmon/Modules/Domain List/UI/AddSiteVC.swift +++ /dev/null @@ -1,157 +0,0 @@ -// -// AddSiteVC.swift -// PHP Monitor -// -// Created by Nico Verbruggen on 24/01/2022. -// Copyright © 2025 Nico Verbruggen. All rights reserved. -// - -import Foundation -import Cocoa - -class AddSiteVC: NSViewController, NSTextFieldDelegate { - - // MARK: - Outlets - - @IBOutlet weak var textFieldTitle: NSTextField! - - @IBOutlet weak var pathControl: NSPathControl! - @IBOutlet weak var inputDomainName: NSTextField! - - @IBOutlet weak var previewText: NSTextField! - - @IBOutlet weak var buttonSecure: NSButton! - @IBOutlet weak var buttonCreateLink: NSButton! - @IBOutlet weak var buttonCancel: NSButton! - - @IBOutlet weak var textFieldSecure: NSTextField! - @IBOutlet weak var textFieldError: NSTextField! - - // MARK: - View Lifecycle - - override func viewDidLoad() { - super.viewDidLoad() - loadStaticLocalisedStrings() - } - - private func dismissView(outcome: NSApplication.ModalResponse) { - guard let window = self.view.window, let parent = window.sheetParent else { return } - parent.endSheet(window, returnCode: outcome) - } - - // MARK: - Localisation - - func loadStaticLocalisedStrings() { - textFieldTitle.stringValue = "domain_list.add.link_folder".localized - inputDomainName.placeholderString = "domain_list.add.domain_name_placeholder".localized - textFieldSecure.stringValue = "domain_list.add.secure_description".localized - buttonCancel.title = "domain_list.add.cancel".localized - buttonCreateLink.title = "domain_list.add.create_link".localized - } - - // MARK: - Outlet Interactions - - func createLink() async { - let path = pathControl.url!.path - let name = inputDomainName.stringValue - - if !App.shared.container.filesystem.anyExists(path) { - Alert.confirm( - onWindow: view.window!, - messageText: "domain_list.alert.folder_missing.title".localized, - informativeText: "domain_list.alert.folder_missing.desc".localized, - buttonTitle: "domain_list.alert.folder_missing.cancel".localized, - secondButtonTitle: "domain_list.alert.folder_missing.return".localized, - onFirstButtonPressed: { [self] in - dismissView(outcome: .cancel) - } - ) - return - } - - // Adding `valet links` is a workaround for Valet malforming the config.json file - Task { - try? await ValetInteractor.shared.link(path: path, domain: name) - - dismissView(outcome: .OK) - - // Reset search - App.shared.domainListWindowController? - .searchToolbarItem - .searchField.stringValue = "" - - // Add the new item and scrolls to it - await App.shared.domainListWindowController? - .contentVC - .addedNewSite( - name: name, - secureAfterLinking: buttonSecure.state == .on - ) - } - } - - @IBAction func pressedCreateLink(_ sender: Any) { - Task { await createLink() } - } - - @IBAction func pressedCancel(_ sender: Any) { - dismissView(outcome: .cancel) - } - - @IBAction func pressedSecure(_ sender: Any) { - updatePreview() - } - - // MARK: - Text Field Delegate - - func controlTextDidChange(_ obj: Notification) { - updateTextField() - } - - // MARK: - Helper Methods - - private func isValidLinkName(_ name: String) -> Bool { - if name.isEmpty { - textFieldError.isHidden = false - textFieldError.stringValue = "domain_list.add.errors.empty".localized - return false - } - - if Valet.shared.sites.contains(where: { $0.name == name }) { - textFieldError.isHidden = false - textFieldError.stringValue = "domain_list.add.errors.already_exists".localized - return false - } - - textFieldError.isHidden = true - return true - } - - func updateTextField() { - inputDomainName.stringValue = inputDomainName.stringValue - .replacing(" ", with: "-") - - buttonCreateLink.isEnabled = isValidLinkName(inputDomainName.stringValue) - updatePreview() - } - - func updatePreview() { - buttonSecure.title = "domain_list.add.secure_after_creation" - .localized( - inputDomainName.stringValue, - Valet.shared.config.tld - ) - - if inputDomainName.stringValue.isEmpty { - previewText.stringValue = "domain_list.add.empty_fields".localized - return - } - - previewText.stringValue = "domain_list.add.folder_available" - .localized( - buttonSecure.state == .on ? "https" : "http", - inputDomainName.stringValue, - Valet.shared.config.tld - ) - } -} diff --git a/phpmon/Modules/Domain List/UI/DomainListVC+ContextMenu.swift b/phpmon/Modules/Domain List/UI/DomainListVC+ContextMenu.swift index 392d7652..0ea99913 100644 --- a/phpmon/Modules/Domain List/UI/DomainListVC+ContextMenu.swift +++ b/phpmon/Modules/Domain List/UI/DomainListVC+ContextMenu.swift @@ -239,11 +239,12 @@ extension DomainListVC { } private func addRemoveProxy(to menu: NSMenu) { - menu.addItem( - withTitle: "domain_list.unproxy".localized, + menu.addItem(NSMenuItem( + title: "domain_list.unproxy".localized, action: #selector(self.removeProxy), - keyEquivalent: "" - ) + keyEquivalent: "", + systemImage: "trash" + )) } // MARK: - Shared diff --git a/phpmon/Modules/Domain List/UI/DomainListWindowController.swift b/phpmon/Modules/Domain List/UI/DomainListWindowController.swift index 2f0a7321..13f7e34f 100644 --- a/phpmon/Modules/Domain List/UI/DomainListWindowController.swift +++ b/phpmon/Modules/Domain List/UI/DomainListWindowController.swift @@ -119,27 +119,74 @@ class DomainListWindowController: PMWindowController, NSSearchFieldDelegate, NST } private func showLinkPopup(_ folder: String) { - let storyboard = NSStoryboard(name: "Main", bundle: nil) + var hostingController: NSHostingController! - let windowController = storyboard.instantiateController( - withIdentifier: "addSiteWindow" - ) as! NSWindowController + let view = AddSiteView( + path: folder, + tld: Valet.shared.config.tld, + onCancel: { + guard let window = hostingController.view.window, + let parent = window.sheetParent else { return } + parent.endSheet(window, returnCode: .cancel) + }, + onConfirm: { name, secure in + guard let window = hostingController.view.window, + let parent = window.sheetParent else { return } + Task { + self.contentVC.setUIBusy() + try? await ValetInteractor.shared.link(path: folder, domain: name) + self.contentVC.setUINotBusy() - let viewController = windowController.window!.contentViewController as! AddSiteVC - viewController.pathControl.url = URL(fileURLWithPath: folder) - viewController.inputDomainName.stringValue = String(folder.split(separator: "/").last!) - viewController.updateTextField() + await self.contentVC.addedNewSite(name: name, secureAfterLinking: secure) + self.searchToolbarItem.searchField.stringValue = "" + } + parent.endSheet(window, returnCode: .OK) + }, + domainExists: { name in + Valet.shared.sites.contains(where: { $0.name == name }) + } + ) - self.window?.beginSheet(windowController.window!) + hostingController = NSHostingController(rootView: view) + hostingController.sizingOptions = .preferredContentSize + let sheetWindow = NSWindow(contentViewController: hostingController) + sheetWindow.styleMask = [.titled, .fullSizeContentView] + self.window?.beginSheet(sheetWindow) } private func showProxyPopup() { - let storyboard = NSStoryboard(name: "Main", bundle: nil) + var hostingController: NSHostingController! - let windowController = storyboard.instantiateController( - withIdentifier: "addProxyWindow" - ) as! NSWindowController + let view = AddProxyView( + tld: Valet.shared.config.tld, + onCancel: { + guard let window = hostingController.view.window, + let parent = window.sheetParent else { return } + parent.endSheet(window, returnCode: .cancel) + }, + onConfirm: { domain, proxy, secure in + guard let window = hostingController.view.window, + let parent = window.sheetParent else { return } + parent.endSheet(window, returnCode: .OK) + self.contentVC.setUIBusy() + Task { + try? await ValetInteractor.shared.proxy(domain: domain, proxy: proxy, secure: secure) - self.window?.beginSheet(windowController.window!) + await MainActor.run { + self.contentVC.setUINotBusy() + self.pressedReload(nil) + } + } + }, + domainExists: { name in + Valet.shared.sites.contains(where: { $0.name == name }) + } + ) + + hostingController = NSHostingController(rootView: view) + hostingController.sizingOptions = .preferredContentSize + let sheetWindow = NSWindow(contentViewController: hostingController) + sheetWindow.styleMask = [.titled, .fullSizeContentView] + self.window?.beginSheet(sheetWindow) } } diff --git a/phpmon/en.lproj/Localizable.strings b/phpmon/en.lproj/Localizable.strings index 406efb2a..5fd262ba 100644 --- a/phpmon/en.lproj/Localizable.strings +++ b/phpmon/en.lproj/Localizable.strings @@ -295,7 +295,7 @@ You may be asked for your password during the uninstallation process if file per // ADD PROXY TO DOMAINS LIST -"domain_list.add.set_up_proxy" = "Set up a Proxy"; +"domain_list.add.set_up_proxy" = "Configure a Proxy"; "domain_list.add.proxy_subject" = "Proxy subject (must include protocol and port)"; "domain_list.add.domain_name" = "Domain name"; "domain_list.add.create_proxy" = "Create Proxy";