diff --git a/.specstory/history/2025-12-17_23-08Z-build-status-query.md b/.specstory/history/2025-12-17_23-08Z-build-status-query.md
index 3e59e07..4dee453 100644
--- a/.specstory/history/2025-12-17_23-08Z-build-status-query.md
+++ b/.specstory/history/2025-12-17_23-08Z-build-status-query.md
@@ -3289,7 +3289,7 @@ Additional data:
"codeblockId": "dd28b84b-a5e4-4327-b24f-d7c408f8acfa"
}
```
-Status: **loading**
+Status: **completed**
@@ -3297,3 +3297,110 @@ Status: **loading**
---
+
+
+Tool use: **edit_file_v2**
+
+
+Parameters:
+
+```json
+{
+ "relativeWorkspacePath": "Views/WorkerEditWindow.axaml.cs"
+}
+```
+Additional data:
+
+```json
+{
+ "codeblockId": "1ece3095-7d84-48f1-b0c9-cd1778aa04dc"
+}
+```
+Status: **completed**
+
+
+
+
+
+---
+
+
+
+Tool use: **edit_file_v2**
+
+
+Parameters:
+
+```json
+{
+ "relativeWorkspacePath": "Views/WorkerEditWindow.axaml.cs"
+}
+```
+Additional data:
+
+```json
+{
+ "codeblockId": "bd962585-1075-46d3-86e1-3ff33f1d67ed"
+}
+```
+Status: **completed**
+
+
+
+
+
+---
+
+
+Fixed the same issue in `WorkerEditWindow`. Verifying the build:
+
+
+---
+
+
+Tool use: **run_terminal_command_v2** • Run command: dotnet build --no-restore 2>&1 | Select-Object -First 30
+
+```bash
+dotnet build --no-restore 2>&1 | Select-Object -First 30
+```
+
+```
+ UnifiedFarmLauncher -> C:\Users\Nathan\Desktop\UFL\bin\Debug\net8.0\UnifiedFarmLauncher.dll
+
+Build succeeded.
+ 0 Warning(s)
+ 0 Error(s)
+
+Time Elapsed 00:00:00.81
+
+```
+
+
+
+---
+
+
+Fixed the same issue in `WorkerEditWindow`. It was accessing named controls directly (like `OkButton`, `CancelButton`, etc.) as fields, which caused a `NullReferenceException` and closed the window.
+
+**Changes made:**
+- Updated `SetupEventHandlers()` to use `FindControl()` for all button references
+- Updated `RemoveDriveButton_Click` and `RemovePathButton_Click` to use `FindControl()` for the ListBox controls
+
+The build succeeded. When you click "Add Worker", the dialog should open and stay open instead of closing immediately. Try it again.
+
+---
+
+_**User**_
+
+This is cool. Flamenco and SheepIt should have universal settings, not per-worker; I don't want to put in user and RenderKey on a per-worker basis.
+
+---
+
+_**Agent (model default, mode Agent)**_
+
+
+Reviewing the current structure to move Flamenco and SheepIt credentials to global settings:
+
+
+---
+
diff --git a/Models/GlobalSettings.cs b/Models/GlobalSettings.cs
index 52459fa..2e929bd 100644
--- a/Models/GlobalSettings.cs
+++ b/Models/GlobalSettings.cs
@@ -11,6 +11,12 @@ namespace UnifiedFarmLauncher.Models
"https://www.sheepit-renderfarm.com/media/applet/client-latest.php",
"https://www.sheepit-renderfarm.com/media/applet/client-latest.jar"
};
+
+ [JsonPropertyName("sheepItUsername")]
+ public string SheepItUsername { get; set; } = string.Empty;
+
+ [JsonPropertyName("sheepItRenderKey")]
+ public string SheepItRenderKey { get; set; } = string.Empty;
}
}
diff --git a/Models/WorkerTypeConfig.cs b/Models/WorkerTypeConfig.cs
index cdb4238..b7b59e2 100644
--- a/Models/WorkerTypeConfig.cs
+++ b/Models/WorkerTypeConfig.cs
@@ -8,12 +8,6 @@ namespace UnifiedFarmLauncher.Models
{
[JsonPropertyName("gpu")]
public string Gpu { get; set; } = string.Empty;
-
- [JsonPropertyName("username")]
- public string Username { get; set; } = string.Empty;
-
- [JsonPropertyName("renderKey")]
- public string RenderKey { get; set; } = string.Empty;
}
public class FlamencoConfig
diff --git a/Services/WorkerControllerService.cs b/Services/WorkerControllerService.cs
index 450158a..3952127 100644
--- a/Services/WorkerControllerService.cs
+++ b/Services/WorkerControllerService.cs
@@ -89,9 +89,10 @@ $attachPath = Join-Path $dataRoot 'attach-helper.ps1'
var config = _configService.Load();
var sheepIt = worker.WorkerTypes.SheepIt;
- var safeKey = sheepIt.RenderKey.Replace("'", "''");
- var safeUser = sheepIt.Username.Replace("'", "''");
- var urls = config.GlobalSettings.SheepItJarUrls;
+ var globalSettings = config.GlobalSettings;
+ var safeKey = globalSettings.SheepItRenderKey.Replace("'", "''");
+ var safeUser = globalSettings.SheepItUsername.Replace("'", "''");
+ var urls = globalSettings.SheepItJarUrls;
var urlLiteral = "@(" + string.Join(", ", Array.ConvertAll(urls.ToArray(), url => $"'{url}'")) + ")";
return $@"
diff --git a/ViewModels/GlobalSettingsViewModel.cs b/ViewModels/GlobalSettingsViewModel.cs
new file mode 100644
index 0000000..6f0c0f7
--- /dev/null
+++ b/ViewModels/GlobalSettingsViewModel.cs
@@ -0,0 +1,45 @@
+using UnifiedFarmLauncher.Models;
+using UnifiedFarmLauncher.Services;
+
+namespace UnifiedFarmLauncher.ViewModels
+{
+ public class GlobalSettingsViewModel : ViewModelBase
+ {
+ private readonly ConfigService _configService;
+ private string _sheepItUsername = string.Empty;
+ private string _sheepItRenderKey = string.Empty;
+
+ public GlobalSettingsViewModel(ConfigService configService)
+ {
+ _configService = configService;
+ LoadSettings();
+ }
+
+ public string SheepItUsername
+ {
+ get => _sheepItUsername;
+ set => SetAndRaise(ref _sheepItUsername, value);
+ }
+
+ public string SheepItRenderKey
+ {
+ get => _sheepItRenderKey;
+ set => SetAndRaise(ref _sheepItRenderKey, value);
+ }
+
+ private void LoadSettings()
+ {
+ var config = _configService.Load();
+ SheepItUsername = config.GlobalSettings.SheepItUsername;
+ SheepItRenderKey = config.GlobalSettings.SheepItRenderKey;
+ }
+
+ public void Save()
+ {
+ var config = _configService.Load();
+ config.GlobalSettings.SheepItUsername = SheepItUsername;
+ config.GlobalSettings.SheepItRenderKey = SheepItRenderKey;
+ _configService.Save(config);
+ }
+ }
+}
diff --git a/ViewModels/WorkerEditViewModel.cs b/ViewModels/WorkerEditViewModel.cs
index 83557db..3992072 100644
--- a/ViewModels/WorkerEditViewModel.cs
+++ b/ViewModels/WorkerEditViewModel.cs
@@ -16,8 +16,6 @@ namespace UnifiedFarmLauncher.ViewModels
private int _sshPort = 22;
private string _sshArgs = string.Empty;
private string _sheepItGpu = "OPTIX_0";
- private string _sheepItUsername = string.Empty;
- private string _sheepItRenderKey = string.Empty;
private string _flamencoWorkerPath = string.Empty;
private bool _hasSheepIt;
private bool _hasFlamenco;
@@ -93,18 +91,6 @@ namespace UnifiedFarmLauncher.ViewModels
set => SetAndRaise(ref _sheepItGpu, value);
}
- public string SheepItUsername
- {
- get => _sheepItUsername;
- set => SetAndRaise(ref _sheepItUsername, value);
- }
-
- public string SheepItRenderKey
- {
- get => _sheepItRenderKey;
- set => SetAndRaise(ref _sheepItRenderKey, value);
- }
-
public string FlamencoWorkerPath
{
get => _flamencoWorkerPath;
@@ -127,8 +113,6 @@ namespace UnifiedFarmLauncher.ViewModels
{
HasSheepIt = true;
SheepItGpu = worker.WorkerTypes.SheepIt.Gpu;
- SheepItUsername = worker.WorkerTypes.SheepIt.Username;
- SheepItRenderKey = worker.WorkerTypes.SheepIt.RenderKey;
}
if (worker.WorkerTypes.Flamenco != null)
@@ -168,9 +152,7 @@ namespace UnifiedFarmLauncher.ViewModels
{
worker.WorkerTypes.SheepIt = new SheepItConfig
{
- Gpu = SheepItGpu,
- Username = SheepItUsername,
- RenderKey = SheepItRenderKey
+ Gpu = SheepItGpu
};
}
diff --git a/Views/GlobalSettingsWindow.axaml b/Views/GlobalSettingsWindow.axaml
new file mode 100644
index 0000000..72af5b6
--- /dev/null
+++ b/Views/GlobalSettingsWindow.axaml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Views/GlobalSettingsWindow.axaml.cs b/Views/GlobalSettingsWindow.axaml.cs
new file mode 100644
index 0000000..9055d79
--- /dev/null
+++ b/Views/GlobalSettingsWindow.axaml.cs
@@ -0,0 +1,61 @@
+using System.Threading.Tasks;
+using Avalonia.Controls;
+using Avalonia.Interactivity;
+using UnifiedFarmLauncher.Services;
+using UnifiedFarmLauncher.ViewModels;
+
+namespace UnifiedFarmLauncher.Views
+{
+ public partial class GlobalSettingsWindow : Window
+ {
+ private readonly GlobalSettingsViewModel _viewModel;
+ private bool _result;
+
+ public GlobalSettingsWindow()
+ {
+ InitializeComponent();
+ var configService = new ConfigService();
+ _viewModel = new GlobalSettingsViewModel(configService);
+ DataContext = _viewModel;
+ SetupEventHandlers();
+ }
+
+ private void InitializeComponent()
+ {
+ Avalonia.Markup.Xaml.AvaloniaXamlLoader.Load(this);
+ }
+
+ private void SetupEventHandlers()
+ {
+ this.FindControl