diff --git a/Flawless-Version-Control.sln.DotSettings.user b/Flawless-Version-Control.sln.DotSettings.user
index ef0f228..8361805 100644
--- a/Flawless-Version-Control.sln.DotSettings.user
+++ b/Flawless-Version-Control.sln.DotSettings.user
@@ -4,6 +4,7 @@
ForceIncluded
ForceIncluded
ForceIncluded
+ ForceIncluded
ForceIncluded
ForceIncluded
ForceIncluded
@@ -12,11 +13,13 @@
ForceIncluded
ForceIncluded
ForceIncluded
+ ForceIncluded
ForceIncluded
ForceIncluded
ForceIncluded
ForceIncluded
ForceIncluded
+ ForceIncluded
ForceIncluded
ForceIncluded
ForceIncluded
diff --git a/Flawless.Client/Models/RepositoryResetMethod.cs b/Flawless.Client/Models/RepositoryResetMethod.cs
new file mode 100644
index 0000000..756f92e
--- /dev/null
+++ b/Flawless.Client/Models/RepositoryResetMethod.cs
@@ -0,0 +1,29 @@
+namespace Flawless.Client.Models;
+
+public enum RepositoryResetMethod
+{
+ ///
+ /// Tracked files will being reset, changes will being keep.
+ ///
+ Keep,
+
+ ///
+ /// Tracked files will being reset, changes will being reset.
+ ///
+ Soft,
+
+ ///
+ /// All files will being reset, changes will being reset, changes list will being cleaned.
+ ///
+ Hard,
+
+ ///
+ /// Tracked files will being reset, changes will being merged.
+ ///
+ Merge,
+
+ ///
+ /// All files will being reset, changes will being merged.
+ ///
+ HardMerge
+}
\ No newline at end of file
diff --git a/Flawless.Client/PathUtility.cs b/Flawless.Client/PathUtility.cs
index 177a54f..a47cdfa 100644
--- a/Flawless.Client/PathUtility.cs
+++ b/Flawless.Client/PathUtility.cs
@@ -21,4 +21,22 @@ public static class PathUtility
=> Path.Combine(SettingService.C.AppSetting.RepositoryPath, login, owner, repo,
AppDefaultValues.RepoLocalStorageManagerFolder, AppDefaultValues.RepoLocalStorageDepotFolder);
+ public static string ConvertBytesToBestDisplay(ulong bytes)
+ {
+ string[] units = { "B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" };
+ int unitIndex = 0;
+ double size = bytes;
+
+ if (bytes <= 0) return "0B"; // 处理零值和负值[6,7](@ref)
+
+ // 单位递进计算[6](@ref)
+ while (size >= 1024 && unitIndex < units.Length - 1)
+ {
+ size /= 1024.0;
+ unitIndex++;
+ }
+
+ // 智能格式化输出[6,7](@ref)
+ return $"{size:0.#}{units[unitIndex]}";
+ }
}
\ No newline at end of file
diff --git a/Flawless.Client/Service/LocalFileTreeAccessor.cs b/Flawless.Client/Service/LocalFileTreeAccessor.cs
index 9d1a0de..5acb415 100644
--- a/Flawless.Client/Service/LocalFileTreeAccessor.cs
+++ b/Flawless.Client/Service/LocalFileTreeAccessor.cs
@@ -9,30 +9,57 @@ using Flawless.Core.Modal;
namespace Flawless.Client.Service;
+public enum ChangeInfoType
+{
+ Folder = 0,
+ Add,
+ Remove,
+ Modify
+}
+
+public struct ChangeInfo : IEquatable
+{
+ public ChangeInfoType Type { get; }
+
+ public WorkspaceFile File { get; }
+
+
+ public ChangeInfo(ChangeInfoType type, WorkspaceFile file)
+ {
+ Type = type;
+ File = file;
+ }
+
+ public bool Equals(ChangeInfo other)
+ {
+ return Type == other.Type && File.Equals(other.File);
+ }
+
+ public override bool Equals(object? obj)
+ {
+ return obj is ChangeInfo other && Equals(other);
+ }
+
+ public override int GetHashCode()
+ {
+ return HashCode.Combine((int)Type, File);
+ }
+
+ public static bool operator ==(ChangeInfo left, ChangeInfo right)
+ {
+ return left.Equals(right);
+ }
+
+ public static bool operator !=(ChangeInfo left, ChangeInfo right)
+ {
+ return !left.Equals(right);
+ }
+}
+
+
public class LocalFileTreeAccessor
{
- public enum ChangeType
- {
- Folder = 0,
- Add,
- Remove,
- Modify
- }
-
- public struct ChangeRecord
- {
- public ChangeType Type { get; }
-
- public WorkspaceFile File { get; }
-
- public ChangeRecord(ChangeType type, WorkspaceFile file)
- {
- Type = type;
- File = file;
- }
- }
-
private static readonly string[] IgnoredDirectories =
{
AppDefaultValues.RepoLocalStorageManagerFolder
@@ -44,7 +71,7 @@ public class LocalFileTreeAccessor
private IReadOnlyDictionary _baseline;
- private Dictionary _changes = new();
+ private Dictionary _changes = new();
private Dictionary _currentFiles = new();
@@ -56,7 +83,7 @@ public class LocalFileTreeAccessor
public IReadOnlyDictionary BaselineFiles => _baseline;
- public IReadOnlyDictionary Changes => _changes;
+ public IReadOnlyDictionary Changes => _changes;
public IReadOnlyDictionary CurrentFiles => _currentFiles;
@@ -108,8 +135,8 @@ public class LocalFileTreeAccessor
var news = _currentFiles.Values.Where(v => !_baseline.ContainsKey(v.WorkPath));
var removed = _baseline.Values.Where(v => !_currentFiles.ContainsKey(v.WorkPath));
- foreach (var f in changes) _changes.Add(f.WorkPath, new ChangeRecord(ChangeType.Modify, f));
- foreach (var f in news) _changes.Add(f.WorkPath, new ChangeRecord(ChangeType.Add, f));
- foreach (var f in removed) _changes.Add(f.WorkPath, new ChangeRecord(ChangeType.Remove, f));
+ foreach (var f in changes) _changes.Add(f.WorkPath, new ChangeInfo(ChangeInfoType.Modify, f));
+ foreach (var f in news) _changes.Add(f.WorkPath, new ChangeInfo(ChangeInfoType.Add, f));
+ foreach (var f in removed) _changes.Add(f.WorkPath, new ChangeInfo(ChangeInfoType.Remove, f));
}
}
\ No newline at end of file
diff --git a/Flawless.Client/Service/RepositoryService.cs b/Flawless.Client/Service/RepositoryService.cs
index 4180192..4321d53 100644
--- a/Flawless.Client/Service/RepositoryService.cs
+++ b/Flawless.Client/Service/RepositoryService.cs
@@ -440,9 +440,58 @@ public class RepositoryService : BaseService
_openedRepos.Add(repo);
return true;
}
+
+ public bool RevertChangesToBaseline(RepositoryModel repo, ICollection changes)
+ {
+ var needBaseline = changes.Any(static x => x.Type is ChangeInfoType.Modify or ChangeInfoType.Remove);
+ var ls = GetRepositoryLocalDatabase(repo);
+ if (needBaseline && ls.RepoAccessor == null)
+ {
+ var e = new InvalidDataException(
+ "Remove and modify will not able comes with changes when it is the first commit.");
+
+ UIHelper.NotifyError(e);
+ Console.WriteLine(e);
+ return false;
+ }
+
+ foreach (var ci in changes)
+ {
+ try
+ {
+ string wfs;
+ switch (ci.Type)
+ {
+ case ChangeInfoType.Add:
+ wfs = WorkPath.ToPlatformPath(ci.File.WorkPath, ls.LocalAccessor.WorkingDirectory);
+ File.Delete(wfs);
+ break;
+
+ case ChangeInfoType.Remove:
+ case ChangeInfoType.Modify:
+ wfs = WorkPath.ToPlatformPath(ci.File.WorkPath, ls.LocalAccessor.WorkingDirectory);
+ ls.RepoAccessor!.TryWriteDataIntoStream(ci.File.WorkPath, wfs);
+ break;
+
+ case ChangeInfoType.Folder:
+ default:
+ break;
+ }
+ }
+ catch (Exception e)
+ {
+ UIHelper.NotifyError(e);
+ Console.WriteLine(e);
+ }
+ }
+
+
+ return true;
+ }
- public async ValueTask ResetCommitPointerToTargetAndMergeDepotsIntoRepositoryFromRemoteAsync
- (RepositoryModel repo, Guid commitId)
+ public async ValueTask SetPointerAndMergeDepotsWithLocalFromRemoteAsync
+ (RepositoryModel repo, Guid commitId, IReadOnlyDictionary localChangesTable,
+ RepositoryResetMethod method)
{
// Try Download base repo info
var accessor = await DownloadDepotsAndUseLocalCachesToGenerateRepositoryFileTreeAccessorFromServerAsync(repo, commitId);
@@ -456,25 +505,56 @@ public class RepositoryService : BaseService
await accessor.CreateCacheAsync();
var ls = GetRepositoryLocalDatabase(repo);
- var oldAcceesor = ls.RepoAccessor;
+ var oldAccessor = ls.RepoAccessor;
ls.CurrentCommit = commitId;
ls.RepoAccessor = accessor;
ls.LocalAccessor.SetBaseline(accessor);
try
{
+ var mergeChanges = method is RepositoryResetMethod.Merge or RepositoryResetMethod.HardMerge;
+ var resetChanges = method is RepositoryResetMethod.Soft or RepositoryResetMethod.Hard;
+ var hardMode = method is RepositoryResetMethod.Hard or RepositoryResetMethod.HardMerge;
+ List unmerged = new();
+
+ // Apply files excepts local changed.
foreach (var f in accessor.Manifest.FilePaths)
{
var pfs = WorkPath.ToPlatformPath(f.WorkPath, ls.LocalAccessor.WorkingDirectory);
var directory = Path.GetDirectoryName(pfs);
-
- // Write into fs
if (directory != null) Directory.CreateDirectory(directory);
- // todo Check if we need merge at here and add logic to handle that...
-
- if (!accessor.TryWriteDataIntoStream(f.WorkPath, pfs))
- throw new InvalidDataException($"Can not write {f.WorkPath} into repository.");
+ var isChanged = localChangesTable.ContainsKey(f.WorkPath);
+ if (isChanged)
+ {
+ if (mergeChanges)
+ unmerged.Add(f);
+ else if (resetChanges && !accessor.TryWriteDataIntoStream(f.WorkPath, pfs))
+ throw new InvalidDataException($"Can not write {f.WorkPath} into repository. (Reset changes)");
+
+ }
+ else
+ {
+ if (!accessor.TryWriteDataIntoStream(f.WorkPath, pfs))
+ throw new InvalidDataException($"Can not write {f.WorkPath} into repository.");
+ }
+ }
+
+ // Try remove files not being tracked
+ if (hardMode)
+ {
+ var tester = accessor.Manifest.FilePaths.Select(static x => x.WorkPath).ToHashSet();
+ foreach (var f in Directory.GetFiles(ls.LocalAccessor.WorkingDirectory, "*", SearchOption.AllDirectories))
+ {
+ var wfs = WorkPath.FromPlatformPath(f, ls.LocalAccessor.WorkingDirectory);
+ if (!tester.Contains(wfs)) File.Delete(f);
+ }
+ }
+
+ // Handle merge one by one.
+ foreach (var f in unmerged)
+ {
+ throw new Exception("No merge tools has been detected! Merge failed.");
}
}
catch (Exception e)
@@ -482,8 +562,8 @@ public class RepositoryService : BaseService
// Revert baseline
try
{
- ls.RepoAccessor = oldAcceesor;
- if (oldAcceesor != null) ls.LocalAccessor.SetBaseline(oldAcceesor);
+ ls.RepoAccessor = oldAccessor;
+ if (oldAccessor != null) ls.LocalAccessor.SetBaseline(oldAccessor);
else ls.LocalAccessor.SetBaseline([]);
}
catch (Exception exception) { Console.WriteLine(exception); }
@@ -496,7 +576,7 @@ public class RepositoryService : BaseService
}
// Dispose old RepoAccessor
- try { if (oldAcceesor != null) await oldAcceesor.DisposeAsync(); }
+ try { if (oldAccessor != null) await oldAccessor.DisposeAsync(); }
catch (Exception exception) { Console.WriteLine(exception); }
SaveRepositoryLocalDatabaseChanges(repo);
@@ -505,7 +585,7 @@ public class RepositoryService : BaseService
return true;
}
- public async ValueTask IsCurrentPointedToCommitIsNotPeekResultFromServerAsync(RepositoryModel repo)
+ public async ValueTask IsPointedToCommitNotPeekResultFromServerAsync(RepositoryModel repo)
{
var api = Api.C;
try
@@ -759,11 +839,11 @@ public class RepositoryService : BaseService
}
public async ValueTask CommitWorkspaceAsBaselineAsync
- (RepositoryModel repo, IEnumerable changes, string message)
+ (RepositoryModel repo, IEnumerable changes, string message)
{
// Check if current version is the latest
var api = Api.C;
- var requireUpdate = await IsCurrentPointedToCommitIsNotPeekResultFromServerAsync(repo);
+ var requireUpdate = await IsPointedToCommitNotPeekResultFromServerAsync(repo);
if (!requireUpdate.HasValue) return null;
if (requireUpdate.Value)
@@ -844,7 +924,7 @@ public class RepositoryService : BaseService
}
public List CreateCommitManifestByCurrentBaselineAndChanges
- (LocalFileTreeAccessor accessor, IEnumerable changes, bool hard = false)
+ (LocalFileTreeAccessor accessor, IEnumerable changes, bool hard = false)
{
// Create a new depot file manifest.
var files = accessor.BaselineFiles.Values.ToList();
@@ -852,7 +932,7 @@ public class RepositoryService : BaseService
{
switch (c.Type)
{
- case LocalFileTreeAccessor.ChangeType.Folder:
+ case ChangeInfoType.Folder:
{
if (hard) throw new InvalidProgramException(
$"Can not commit folder into version control: {c.File.WorkPath}");
@@ -860,7 +940,7 @@ public class RepositoryService : BaseService
Console.WriteLine($"Can not commit folder into version control...Ignored: {c.File.WorkPath}");
continue;
}
- case LocalFileTreeAccessor.ChangeType.Add:
+ case ChangeInfoType.Add:
{
if (files.Any(f => f.WorkPath == c.File.WorkPath))
{
@@ -874,7 +954,7 @@ public class RepositoryService : BaseService
files.Add(c.File);
break;
}
- case LocalFileTreeAccessor.ChangeType.Remove:
+ case ChangeInfoType.Remove:
{
var idx = files.FindIndex(f => f.WorkPath == c.File.WorkPath);
if (idx < 0)
@@ -889,7 +969,7 @@ public class RepositoryService : BaseService
files.RemoveAt(idx);
break;
}
- case LocalFileTreeAccessor.ChangeType.Modify:
+ case ChangeInfoType.Modify:
{
var idx = files.FindIndex(f => f.WorkPath == c.File.WorkPath);
if (idx < 0)
diff --git a/Flawless.Client/ViewModels/RepositoryViewModel.cs b/Flawless.Client/ViewModels/RepositoryViewModel.cs
index b503af1..4c31d8f 100644
--- a/Flawless.Client/ViewModels/RepositoryViewModel.cs
+++ b/Flawless.Client/ViewModels/RepositoryViewModel.cs
@@ -1,11 +1,10 @@
using System;
using System.Collections.Generic;
+using System.Collections.Immutable;
using System.Collections.ObjectModel;
-using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reactive.Linq;
-using System.Reactive.Threading.Tasks;
using System.Threading.Tasks;
using Avalonia.Controls;
using Avalonia.Controls.Models.TreeDataGrid;
@@ -20,7 +19,6 @@ using Flawless.Core.Modal;
using ReactiveUI;
using ReactiveUI.SourceGenerators;
using Ursa.Controls;
-using ChangeType = Flawless.Client.Service.LocalFileTreeAccessor.ChangeType;
namespace Flawless.Client.ViewModels;
@@ -64,7 +62,7 @@ public partial class LocalChangesNode : ReactiveModel
};
}
- public static LocalChangesNode FromWorkspaceFile(LocalChangesNode? parent, LocalFileTreeAccessor.ChangeRecord file)
+ public static LocalChangesNode FromWorkspaceFile(LocalChangesNode? parent, ChangeInfo file)
{
return new LocalChangesNode
{
@@ -130,21 +128,26 @@ public partial class RepositoryViewModel : RoutableViewModelBase
public FlatTreeDataGridSource Commits { get; }
- public ObservableCollection LocalChangeSetRaw { get; } = new();
+ public ObservableCollectionExtended LocalChangeSetRaw { get; } = new();
- public ObservableCollection CurrentCommitFileTreeRaw { get; } = new();
+ public ObservableCollectionExtended CurrentCommitFileTreeRaw { get; } = new();
+
+ public ObservableCollectionExtended CommitsRaw { get; } = new();
public UserModel User { get; }
[Reactive] private bool _autoDetectChanges = true;
[Reactive] private bool _isOwnerRole, _isDeveloperRole, _isReporterRole, _isGuestRole;
+
+ private string _wsRoot;
public RepositoryViewModel(RepositoryModel repo, IScreen hostScreen) : base(hostScreen)
{
Repository = repo;
LocalDatabase = RepositoryService.C.GetRepositoryLocalDatabase(repo);
User = UserService.C.GetUserInfoAsync(Api.C.Username.Value!)!;
+ _wsRoot = PathUtility.GetWorkspacePath(Api.C.Username.Value!, Repository.OwnerName, Repository.Name);
// Setup local change set
LocalChange = new HierarchicalTreeDataGridSource(LocalChangeSetRaw)
@@ -173,16 +176,16 @@ public partial class RepositoryViewModel : RoutableViewModelBase
"File Type",
n => n.Contents != null ? "Folder" : Path.GetExtension(n.FullPath)),
- new TextColumn(
+ new TextColumn(
"Size",
- n => 0),
+ n => PathUtility.ConvertBytesToBestDisplay(GetFileSize(n))),
new TextColumn(
"ModifiedTime", n => n.ModifiedTime.HasValue ? n.ModifiedTime.Value.ToLocalTime() : null),
}
};
- Commits = new FlatTreeDataGridSource(Repository.Commits.Select(CommitTransitNode.FromCommit))
+ Commits = new FlatTreeDataGridSource(CommitsRaw)
{
Columns =
{
@@ -229,11 +232,19 @@ public partial class RepositoryViewModel : RoutableViewModelBase
_ = StartupTasksAsync();
}
+ private ulong GetFileSize(LocalChangesNode node)
+ {
+ if (!File.Exists(node.FullPath)) return 0;
+ var path = Path.Combine(_wsRoot, node.FullPath);
+ return (ulong)new FileInfo(path).Length;
+ }
+
private async Task StartupTasksAsync()
{
+ await RefreshRepositoryRoleInfoAsyncCommand.Execute();
await DetectLocalChangesAsyncCommand.Execute();
await RendererFileTreeAsync();
- await RefreshRepositoryRoleInfoAsyncCommand.Execute();
+ SyncCommitsFromRepository();
}
private async ValueTask RendererFileTreeAsync()
@@ -241,20 +252,26 @@ public partial class RepositoryViewModel : RoutableViewModelBase
if (LocalDatabase.RepoAccessor == null) return;
var accessor = LocalDatabase.RepoAccessor;
var nodes = await CalculateFileTreeOfChangesNodeAsync(accessor.Select(
- f => new LocalFileTreeAccessor.ChangeRecord(ChangeType.Add, f)));
+ f => new ChangeInfo(ChangeInfoType.Add, f)));
CurrentCommitFileTreeRaw.Clear();
CurrentCommitFileTreeRaw.AddRange(nodes);
}
+
+ private void SyncCommitsFromRepository()
+ {
+ CommitsRaw.Clear();
+ CommitsRaw.AddRange(Repository.Commits.Select(CommitTransitNode.FromCommit));
+ }
- private void CollectChanges(List store, IEnumerable changesNode)
+ private void CollectChanges(List store, IEnumerable changesNode)
{
foreach (var n in changesNode)
{
if (n.Contents != null) CollectChanges(store, n.Contents);
else if (n.Included)
{
- store.Add(new LocalFileTreeAccessor.ChangeRecord(Enum.Parse(n.Type), new WorkspaceFile
+ store.Add(new ChangeInfo(Enum.Parse(n.Type), new WorkspaceFile
{
WorkPath = n.FullPath,
ModifyTime = n.ModifiedTime!.Value
@@ -263,7 +280,7 @@ public partial class RepositoryViewModel : RoutableViewModelBase
}
}
- private Task> CalculateFileTreeOfChangesNodeAsync(IEnumerable changesNode)
+ private Task> CalculateFileTreeOfChangesNodeAsync(IEnumerable changesNode)
{
return Task.Run(() =>
{
@@ -316,12 +333,127 @@ public partial class RepositoryViewModel : RoutableViewModelBase
if (role >= RepositoryModel.RepositoryRole.Reporter) IsReporterRole = true;
if (role >= RepositoryModel.RepositoryRole.Guest) IsGuestRole = true;
}
-
+ [ReactiveCommand]
+ private async Task RevertFileTreeToSelectedCommitKeepAsync()
+ {
+ var sel = Commits.RowSelection?.SelectedItem;
+ if (sel != null)
+ {
+ using var l = UIHelper.MakeLoading($"Reset (Keep) to Commit {sel.CommitId}");
+
+ var changes = new List();
+ CollectChanges(changes, LocalChangeSetRaw);
+
+ var kid = Repository.Commits.First(x => x.CommitId.ToString() == sel.CommitId).CommitId;
+ var changeDict = changes.ToImmutableDictionary(x => x.File.WorkPath, x => x.File);
+ await RepositoryService.C
+ .SetPointerAndMergeDepotsWithLocalFromRemoteAsync(
+ Repository, kid, changeDict, RepositoryResetMethod.Keep);
+
+ await DetectLocalChangesAsyncCommand.Execute();
+ await RendererFileTreeAsync();
+ SyncCommitsFromRepository();
+ }
+ }
+
+ [ReactiveCommand]
+ private async Task RevertFileTreeToSelectedCommitSoftAsync()
+ {
+ var sel = Commits.RowSelection?.SelectedItem;
+ if (sel != null)
+ {
+ using var l = UIHelper.MakeLoading($"Reset (Soft) to Commit {sel.CommitId}");
+ var changes = new List();
+ CollectChanges(changes, LocalChangeSetRaw);
+
+ if (changes.Count != 0)
+ {
+ var result = await UIHelper.SimpleAskAsync(
+ "There are commits that has not been committed. Do you wish discard them at all?",
+ DialogMode.Warning);
+
+ if (result == DialogResult.No) return;
+ }
+
+
+ var kid = Repository.Commits.First(x => x.CommitId.ToString() == sel.CommitId).CommitId;
+ var changeDict = changes.ToImmutableDictionary(x => x.File.WorkPath, x => x.File);
+ await RepositoryService.C
+ .SetPointerAndMergeDepotsWithLocalFromRemoteAsync(
+ Repository, kid, changeDict, RepositoryResetMethod.Soft);
+
+ await DetectLocalChangesAsyncCommand.Execute();
+ await RendererFileTreeAsync();
+ SyncCommitsFromRepository();
+ }
+ }
+
+ [ReactiveCommand]
+ private async Task RevertFileTreeToSelectedCommitHardAsync()
+ {
+ var sel = Commits.RowSelection?.SelectedItem;
+ if (sel != null)
+ {
+ using var l = UIHelper.MakeLoading($"Reset (Hard) to Commit {sel.CommitId}");
+
+ if (!await RepositoryService.C.UpdateCommitsHistoryFromServerAsync(Repository)) return;
+ var changes = new List();
+ CollectChanges(changes, LocalChangeSetRaw);
+
+
+ var result = await UIHelper.SimpleAskAsync(
+ "All files will being matched with this commit. Do you wish to execute it?",
+ DialogMode.Warning);
+
+ if (result == DialogResult.No) return;
+
+ var kid = Repository.Commits.First(x => x.CommitId.ToString() == sel.CommitId).CommitId;
+ var changeDict = changes.ToImmutableDictionary(x => x.File.WorkPath, x => x.File);
+ await RepositoryService.C
+ .SetPointerAndMergeDepotsWithLocalFromRemoteAsync(
+ Repository, kid, changeDict, RepositoryResetMethod.Hard);
+
+ await DetectLocalChangesAsyncCommand.Execute();
+ await RendererFileTreeAsync();
+ SyncCommitsFromRepository();
+ }
+ }
+
+
+ [ReactiveCommand]
+ private async Task PullLatestRepositoryAsync()
+ {
+ using var l = UIHelper.MakeLoading("Pulling latest changes...");
+ var mayUpdate = await RepositoryService.C.IsPointedToCommitNotPeekResultFromServerAsync(Repository);
+ if (!mayUpdate.HasValue) return;
+ if (mayUpdate.Value == false)
+ {
+ await UIHelper.SimpleAskAsync("Everything is new, no needs to pull.");
+ return;
+ }
+
+ if (!await RepositoryService.C.UpdateCommitsHistoryFromServerAsync(Repository)) return;
+
+ if (!await RepositoryService.C.UpdateCommitsHistoryFromServerAsync(Repository)) return;
+ var changes = new List();
+ CollectChanges(changes, LocalChangeSetRaw);
+
+ var kid = Repository.Commits.MaxBy(k => k.CommittedOn)!.CommitId;
+ var changeDict = changes.ToImmutableDictionary(x => x.File.WorkPath, x => x.File);
+ await RepositoryService.C.SetPointerAndMergeDepotsWithLocalFromRemoteAsync(
+ Repository, kid, changeDict, RepositoryResetMethod.Merge);
+
+ await DetectLocalChangesAsyncCommand.Execute();
+ await RendererFileTreeAsync();
+ SyncCommitsFromRepository();
+ }
+
+
[ReactiveCommand]
private async Task CommitSelectedChangesAsync()
{
- var changes = new List();
+ var changes = new List();
CollectChanges(changes, LocalChangeSetRaw);
if (changes.Count == 0)
@@ -335,7 +467,7 @@ public partial class RepositoryViewModel : RoutableViewModelBase
await UIHelper.SimpleAlert("Commit message can not be empty!");
return;
}
-
+
using var l = UIHelper.MakeLoading("Committing changes...");
var manifest = await RepositoryService.C.CommitWorkspaceAsBaselineAsync(Repository, changes, LocalDatabase.CommitMessage!);
if (manifest == null) return;
@@ -344,6 +476,26 @@ public partial class RepositoryViewModel : RoutableViewModelBase
LocalDatabase.CommitMessage = string.Empty;
await DetectLocalChangesAsyncCommand.Execute();
await RendererFileTreeAsync();
+ SyncCommitsFromRepository();
+ }
+
+ [ReactiveCommand]
+ private async Task RevertSelectedChangesAsync()
+ {
+ var changes = new List();
+ CollectChanges(changes, LocalChangeSetRaw);
+
+ if (changes.Count == 0)
+ {
+ await UIHelper.SimpleAlert("You haven't choose any changes yet!");
+ return;
+ }
+
+ using var l = UIHelper.MakeLoading("Reverting changes...");
+ RepositoryService.C.RevertChangesToBaseline(Repository, changes);
+ await DetectLocalChangesAsyncCommand.Execute();
+ await RendererFileTreeAsync();
+ SyncCommitsFromRepository();
}
[ReactiveCommand]
@@ -363,23 +515,6 @@ public partial class RepositoryViewModel : RoutableViewModelBase
}
}
- [ReactiveCommand]
- private async Task PullLatestRepositoryAsync()
- {
- using var l = UIHelper.MakeLoading("Pulling latest changes...");
- var mayUpdate = await RepositoryService.C.IsCurrentPointedToCommitIsNotPeekResultFromServerAsync(Repository);
- if (!mayUpdate.HasValue) return;
- if (mayUpdate.Value == false)
- {
- await UIHelper.SimpleAskAsync("Everything is new, no needs to pull.");
- return;
- }
-
- if (!await RepositoryService.C.UpdateCommitsHistoryFromServerAsync(Repository)) return;
- var kid = Repository.Commits.MaxBy(k => k.CommittedOn)!.CommitId;
- await RepositoryService.C.ResetCommitPointerToTargetAndMergeDepotsIntoRepositoryFromRemoteAsync(Repository, kid);
- }
-
[ReactiveCommand]
private async Task CloseRepositoryAsync()
{
diff --git a/Flawless.Client/Views/RepositoryPage/RepoCommitPageView.axaml b/Flawless.Client/Views/RepositoryPage/RepoCommitPageView.axaml
index e299b92..a71ea2a 100644
--- a/Flawless.Client/Views/RepositoryPage/RepoCommitPageView.axaml
+++ b/Flawless.Client/Views/RepositoryPage/RepoCommitPageView.axaml
@@ -7,15 +7,25 @@
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Flawless.Client.Views.RepositoryPage.RepoCommitPageView">
-
+
+
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
diff --git a/Flawless.Client/Views/RepositoryPage/RepoFileTreePageView.axaml b/Flawless.Client/Views/RepositoryPage/RepoFileTreePageView.axaml
index 739061f..7299d73 100644
--- a/Flawless.Client/Views/RepositoryPage/RepoFileTreePageView.axaml
+++ b/Flawless.Client/Views/RepositoryPage/RepoFileTreePageView.axaml
@@ -9,12 +9,5 @@
-
-
-
-
-
-
-
diff --git a/Flawless.Client/Views/RepositoryPage/RepoWorkspacePageView.axaml b/Flawless.Client/Views/RepositoryPage/RepoWorkspacePageView.axaml
index bbb24a7..253d628 100644
--- a/Flawless.Client/Views/RepositoryPage/RepoWorkspacePageView.axaml
+++ b/Flawless.Client/Views/RepositoryPage/RepoWorkspacePageView.axaml
@@ -20,14 +20,21 @@
-
-
+
+
+
+
+
+
-
+