ConflictResolutionWindow.cs 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. // Copyright (c) 2025 TerraByte Inc.
  2. //
  3. // A modal editor window that displays pull conflicts and allows the user
  4. // to select files to reset before proceeding.
  5. using System;
  6. using System.Linq;
  7. using UnityEditor;
  8. using UnityEngine;
  9. using Terra.Arbitrator.Services;
  10. using System.Collections.Generic;
  11. namespace Terra.Arbitrator.GUI
  12. {
  13. public class ConflictResolutionWindow : EditorWindow
  14. {
  15. private List<string> _conflictingFiles;
  16. private List<bool> _filesToReset;
  17. private Vector2 _scrollPosition;
  18. private Action<List<string>> _onCloseCallback;
  19. private bool _callbackInvoked;
  20. /// <summary>
  21. /// Shows a modal window to display pull conflicts and get user action.
  22. /// </summary>
  23. /// <param name="conflictingFiles">The list of files that have conflicts.</param>
  24. /// <param name="onCloseCallback">A callback that provides the list of files the user selected to reset. If the user cancels, the list will be null.</param>
  25. public static void ShowWindow(List<string> conflictingFiles, Action<List<string>> onCloseCallback)
  26. {
  27. var window = GetWindow<ConflictResolutionWindow>(true, "Pull Conflicts Detected", true);
  28. window.minSize = new Vector2(600, 400);
  29. window._conflictingFiles = conflictingFiles;
  30. window._filesToReset = new List<bool>(new bool[conflictingFiles.Count]); // Initialize all to false
  31. window._onCloseCallback = onCloseCallback;
  32. window._callbackInvoked = false;
  33. window.ShowModalUtility();
  34. }
  35. private void OnGUI()
  36. {
  37. EditorGUILayout.HelpBox("A pull would result in conflicts with your local changes. To proceed with a clean pull, you must reset your local changes for the conflicting files listed below.", MessageType.Warning);
  38. EditorGUILayout.LabelField("Conflicting Files:", EditorStyles.boldLabel);
  39. _scrollPosition = EditorGUILayout.BeginScrollView(_scrollPosition, EditorStyles.helpBox);
  40. for (var i = 0; i < _conflictingFiles.Count; i++)
  41. {
  42. EditorGUILayout.BeginHorizontal();
  43. _filesToReset[i] = EditorGUILayout.Toggle(_filesToReset[i], GUILayout.Width(20));
  44. EditorGUILayout.LabelField(_conflictingFiles[i]);
  45. if (GUILayout.Button("Local Diff", GUILayout.Width(100)))
  46. {
  47. // Find the GitChange object to pass to the diff service.
  48. var change = GitService.GetChangeForFile(_conflictingFiles[i]);
  49. if (change != null)
  50. {
  51. GitService.LaunchExternalDiff(change);
  52. }
  53. else
  54. {
  55. Debug.LogWarning($"Could not get status for {_conflictingFiles[i]} to launch diff.");
  56. }
  57. }
  58. EditorGUILayout.EndHorizontal();
  59. }
  60. EditorGUILayout.EndScrollView();
  61. EditorGUILayout.Space();
  62. DrawActionButtons();
  63. }
  64. private void DrawActionButtons()
  65. {
  66. var selectedCount = _filesToReset.Count(selected => selected);
  67. var canReset = selectedCount > 0;
  68. EditorGUILayout.BeginHorizontal();
  69. GUILayout.FlexibleSpace();
  70. EditorGUI.BeginDisabledGroup(!canReset);
  71. if (GUILayout.Button($"Reset {selectedCount} Selected File(s)", GUILayout.Height(30), GUILayout.Width(200)))
  72. {
  73. var filesToResetPaths = new List<string>();
  74. for (var i = 0; i < _conflictingFiles.Count; i++)
  75. {
  76. if (_filesToReset[i])
  77. {
  78. filesToResetPaths.Add(_conflictingFiles[i]);
  79. }
  80. }
  81. _callbackInvoked = true;
  82. _onCloseCallback?.Invoke(filesToResetPaths);
  83. Close();
  84. }
  85. EditorGUI.EndDisabledGroup();
  86. if (GUILayout.Button(new GUIContent("Pull Anyway", "This will perform the pull, leaving merge conflicts in your local files for you to resolve."), GUILayout.Height(30)))
  87. {
  88. _callbackInvoked = true;
  89. _onCloseCallback?.Invoke(new List<string>());
  90. Close();
  91. }
  92. if (GUILayout.Button("Cancel", GUILayout.Height(30)))
  93. {
  94. Close();
  95. }
  96. EditorGUILayout.EndHorizontal();
  97. }
  98. private void OnDestroy()
  99. {
  100. if (!_callbackInvoked)
  101. {
  102. _onCloseCallback?.Invoke(null);
  103. }
  104. }
  105. }
  106. }