mirror of
https://github.com/sourcegit-scm/sourcegit.git
synced 2024-12-24 20:57:19 -08:00
feature: add commit web links (#357)
This commit is contained in:
parent
a145d6e4c3
commit
34a598d421
13 changed files with 124 additions and 52 deletions
8
src/Models/CommitLink.cs
Normal file
8
src/Models/CommitLink.cs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
namespace SourceGit.Models
|
||||||
|
{
|
||||||
|
public class CommitLink
|
||||||
|
{
|
||||||
|
public string Name { get; set; } = null;
|
||||||
|
public string URLTemplate { get; set; } = null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -59,6 +59,7 @@
|
||||||
<StreamGeometry x:Key="Icons.LFS">M40 9 15 23 15 31 9 28 9 20 34 5 24 0 0 14 0 34 25 48 25 28 49 14zM26 29 26 48 49 34 49 15z</StreamGeometry>
|
<StreamGeometry x:Key="Icons.LFS">M40 9 15 23 15 31 9 28 9 20 34 5 24 0 0 14 0 34 25 48 25 28 49 14zM26 29 26 48 49 34 49 15z</StreamGeometry>
|
||||||
<StreamGeometry x:Key="Icons.Lines.Incr">M408 232C408 210 426 192 448 192h416a40 40 0 110 80H448a40 40 0 01-40-40zM408 512c0-22 18-40 40-40h416a40 40 0 110 80H448A40 40 0 01408 512zM448 752A40 40 0 00448 832h416a40 40 0 100-80H448zM32 480l132 0 0-128 64 0 0 128 132 0 0 64-132 0 0 128-64 0 0-128-132 0Z</StreamGeometry>
|
<StreamGeometry x:Key="Icons.Lines.Incr">M408 232C408 210 426 192 448 192h416a40 40 0 110 80H448a40 40 0 01-40-40zM408 512c0-22 18-40 40-40h416a40 40 0 110 80H448A40 40 0 01408 512zM448 752A40 40 0 00448 832h416a40 40 0 100-80H448zM32 480l132 0 0-128 64 0 0 128 132 0 0 64-132 0 0 128-64 0 0-128-132 0Z</StreamGeometry>
|
||||||
<StreamGeometry x:Key="Icons.Lines.Decr">M408 232C408 210 426 192 448 192h416a40 40 0 110 80H448a40 40 0 01-40-40zM408 512c0-22 18-40 40-40h416a40 40 0 110 80H448A40 40 0 01408 512zM448 752A40 40 0 00448 832h416a40 40 0 100-80H448zM32 480l328 0 0 64-328 0Z</StreamGeometry>
|
<StreamGeometry x:Key="Icons.Lines.Decr">M408 232C408 210 426 192 448 192h416a40 40 0 110 80H448a40 40 0 01-40-40zM408 512c0-22 18-40 40-40h416a40 40 0 110 80H448A40 40 0 01408 512zM448 752A40 40 0 00448 832h416a40 40 0 100-80H448zM32 480l328 0 0 64-328 0Z</StreamGeometry>
|
||||||
|
<StreamGeometry x:Key="Icons.Link">M 968 418 l -95 94 c -59 59 -146 71 -218 37 L 874 331 a 64 64 0 0 0 0 -90 L 783 150 a 64 64 0 0 0 -90 0 L 475 368 c -34 -71 -22 -159 37 -218 l 94 -94 c 75 -75 196 -75 271 0 l 90 90 c 75 75 75 196 0 271 z M 332 693 a 64 64 0 0 1 0 -90 l 271 -271 c 25 -25 65 -25 90 0 s 25 65 0 90 L 422 693 a 64 64 0 0 1 -90 0 z M 151 783 l 90 90 a 64 64 0 0 0 90 0 l 218 -218 c 34 71 22 159 -37 218 l -86 94 a 192 192 0 0 1 -271 0 l -98 -98 a 192 192 0 0 1 0 -271 l 94 -86 c 59 -59 146 -71 218 -37 L 151 693 a 64 64 0 0 0 0 90 z</StreamGeometry>
|
||||||
<StreamGeometry x:Key="Icons.List">M0 33h1024v160H0zM0 432h1024v160H0zM0 831h1024v160H0z</StreamGeometry>
|
<StreamGeometry x:Key="Icons.List">M0 33h1024v160H0zM0 432h1024v160H0zM0 831h1024v160H0z</StreamGeometry>
|
||||||
<StreamGeometry x:Key="Icons.Loading">M512 0C233 0 7 223 0 500C6 258 190 64 416 64c230 0 416 200 416 448c0 53 43 96 96 96s96-43 96-96c0-283-229-512-512-512zm0 1023c279 0 505-223 512-500c-6 242-190 436-416 436c-230 0-416-200-416-448c0-53-43-96-96-96s-96 43-96 96c0 283 229 512 512 512z</StreamGeometry>
|
<StreamGeometry x:Key="Icons.Loading">M512 0C233 0 7 223 0 500C6 258 190 64 416 64c230 0 416 200 416 448c0 53 43 96 96 96s96-43 96-96c0-283-229-512-512-512zm0 1023c279 0 505-223 512-500c-6 242-190 436-416 436c-230 0-416-200-416-448c0-53-43-96-96-96s-96 43-96 96c0 283 229 512 512 512z</StreamGeometry>
|
||||||
<StreamGeometry x:Key="Icons.Local">M976 0h-928A48 48 0 000 48v652a48 48 0 0048 48h416V928H200a48 48 0 000 96h624a48 48 0 000-96H560v-180h416a48 48 0 0048-48V48A48 48 0 00976 0zM928 652H96V96h832v556z</StreamGeometry>
|
<StreamGeometry x:Key="Icons.Local">M976 0h-928A48 48 0 000 48v652a48 48 0 0048 48h416V928H200a48 48 0 000 96h624a48 48 0 000-96H560v-180h416a48 48 0 0048-48V48A48 48 0 00976 0zM928 652H96V96h832v556z</StreamGeometry>
|
||||||
|
|
|
@ -66,7 +66,7 @@ namespace SourceGit.ViewModels
|
||||||
if (value == null || value.Count != 1)
|
if (value == null || value.Count != 1)
|
||||||
DiffContext = null;
|
DiffContext = null;
|
||||||
else
|
else
|
||||||
DiffContext = new DiffContext(_repo, new Models.DiffOption(_commit, value[0]), _diffContext);
|
DiffContext = new DiffContext(_repo.FullPath, new Models.DiffOption(_commit, value[0]), _diffContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -89,15 +89,19 @@ namespace SourceGit.ViewModels
|
||||||
set => SetProperty(ref _viewRevisionFileContent, value);
|
set => SetProperty(ref _viewRevisionFileContent, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public AvaloniaList<Models.IssueTrackerRule> IssueTrackerRules
|
public AvaloniaList<Models.CommitLink> WebLinks
|
||||||
{
|
{
|
||||||
get => _issueTrackerRules;
|
get => _repo.TryGetCommitLinks();
|
||||||
}
|
}
|
||||||
|
|
||||||
public CommitDetail(string repo, AvaloniaList<Models.IssueTrackerRule> issueTrackerRules)
|
public AvaloniaList<Models.IssueTrackerRule> IssueTrackerRules
|
||||||
|
{
|
||||||
|
get => _repo.Settings?.IssueTrackerRules;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommitDetail(Repository repo)
|
||||||
{
|
{
|
||||||
_repo = repo;
|
_repo = repo;
|
||||||
_issueTrackerRules = issueTrackerRules;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Cleanup()
|
public void Cleanup()
|
||||||
|
@ -118,8 +122,7 @@ namespace SourceGit.ViewModels
|
||||||
|
|
||||||
public void NavigateTo(string commitSHA)
|
public void NavigateTo(string commitSHA)
|
||||||
{
|
{
|
||||||
var repo = App.FindOpenedRepository(_repo);
|
_repo?.NavigateToCommit(commitSHA);
|
||||||
repo?.NavigateToCommit(commitSHA);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ClearSearchChangeFilter()
|
public void ClearSearchChangeFilter()
|
||||||
|
@ -129,7 +132,7 @@ namespace SourceGit.ViewModels
|
||||||
|
|
||||||
public List<Models.Object> GetRevisionFilesUnderFolder(string parentFolder)
|
public List<Models.Object> GetRevisionFilesUnderFolder(string parentFolder)
|
||||||
{
|
{
|
||||||
return new Commands.QueryRevisionObjects(_repo, _commit.SHA, parentFolder).Result();
|
return new Commands.QueryRevisionObjects(_repo.FullPath, _commit.SHA, parentFolder).Result();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ViewRevisionFile(Models.Object file)
|
public void ViewRevisionFile(Models.Object file)
|
||||||
|
@ -145,13 +148,13 @@ namespace SourceGit.ViewModels
|
||||||
case Models.ObjectType.Blob:
|
case Models.ObjectType.Blob:
|
||||||
Task.Run(() =>
|
Task.Run(() =>
|
||||||
{
|
{
|
||||||
var isBinary = new Commands.IsBinary(_repo, _commit.SHA, file.Path).Result();
|
var isBinary = new Commands.IsBinary(_repo.FullPath, _commit.SHA, file.Path).Result();
|
||||||
if (isBinary)
|
if (isBinary)
|
||||||
{
|
{
|
||||||
var ext = Path.GetExtension(file.Path);
|
var ext = Path.GetExtension(file.Path);
|
||||||
if (IMG_EXTS.Contains(ext))
|
if (IMG_EXTS.Contains(ext))
|
||||||
{
|
{
|
||||||
var stream = Commands.QueryFileContent.Run(_repo, _commit.SHA, file.Path);
|
var stream = Commands.QueryFileContent.Run(_repo.FullPath, _commit.SHA, file.Path);
|
||||||
var bitmap = stream.Length > 0 ? new Bitmap(stream) : null;
|
var bitmap = stream.Length > 0 ? new Bitmap(stream) : null;
|
||||||
Dispatcher.UIThread.Invoke(() =>
|
Dispatcher.UIThread.Invoke(() =>
|
||||||
{
|
{
|
||||||
|
@ -160,7 +163,7 @@ namespace SourceGit.ViewModels
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var size = new Commands.QueryFileSize(_repo, file.Path, _commit.SHA).Result();
|
var size = new Commands.QueryFileSize(_repo.FullPath, file.Path, _commit.SHA).Result();
|
||||||
Dispatcher.UIThread.Invoke(() =>
|
Dispatcher.UIThread.Invoke(() =>
|
||||||
{
|
{
|
||||||
ViewRevisionFileContent = new Models.RevisionBinaryFile() { Size = size };
|
ViewRevisionFileContent = new Models.RevisionBinaryFile() { Size = size };
|
||||||
|
@ -170,7 +173,7 @@ namespace SourceGit.ViewModels
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var contentStream = Commands.QueryFileContent.Run(_repo, _commit.SHA, file.Path);
|
var contentStream = Commands.QueryFileContent.Run(_repo.FullPath, _commit.SHA, file.Path);
|
||||||
var content = new StreamReader(contentStream).ReadToEnd();
|
var content = new StreamReader(contentStream).ReadToEnd();
|
||||||
var matchLFS = REG_LFS_FORMAT().Match(content);
|
var matchLFS = REG_LFS_FORMAT().Match(content);
|
||||||
if (matchLFS.Success)
|
if (matchLFS.Success)
|
||||||
|
@ -191,7 +194,7 @@ namespace SourceGit.ViewModels
|
||||||
case Models.ObjectType.Commit:
|
case Models.ObjectType.Commit:
|
||||||
Task.Run(() =>
|
Task.Run(() =>
|
||||||
{
|
{
|
||||||
var submoduleRoot = Path.Combine(_repo, file.Path);
|
var submoduleRoot = Path.Combine(_repo.FullPath, file.Path);
|
||||||
var commit = new Commands.QuerySingleCommit(submoduleRoot, file.SHA).Result();
|
var commit = new Commands.QuerySingleCommit(submoduleRoot, file.SHA).Result();
|
||||||
if (commit != null)
|
if (commit != null)
|
||||||
{
|
{
|
||||||
|
@ -237,7 +240,7 @@ namespace SourceGit.ViewModels
|
||||||
var toolPath = Preference.Instance.ExternalMergeToolPath;
|
var toolPath = Preference.Instance.ExternalMergeToolPath;
|
||||||
var opt = new Models.DiffOption(_commit, change);
|
var opt = new Models.DiffOption(_commit, change);
|
||||||
|
|
||||||
Task.Run(() => Commands.MergeTool.OpenForDiff(_repo, toolType, toolPath, opt));
|
Task.Run(() => Commands.MergeTool.OpenForDiff(_repo.FullPath, toolType, toolPath, opt));
|
||||||
ev.Handled = true;
|
ev.Handled = true;
|
||||||
};
|
};
|
||||||
menu.Items.Add(diffWithMerger);
|
menu.Items.Add(diffWithMerger);
|
||||||
|
@ -249,7 +252,7 @@ namespace SourceGit.ViewModels
|
||||||
history.Icon = App.CreateMenuIcon("Icons.Histories");
|
history.Icon = App.CreateMenuIcon("Icons.Histories");
|
||||||
history.Click += (_, ev) =>
|
history.Click += (_, ev) =>
|
||||||
{
|
{
|
||||||
var window = new Views.FileHistories() { DataContext = new FileHistories(_repo, change.Path, _issueTrackerRules) };
|
var window = new Views.FileHistories() { DataContext = new FileHistories(_repo, change.Path) };
|
||||||
window.Show();
|
window.Show();
|
||||||
ev.Handled = true;
|
ev.Handled = true;
|
||||||
};
|
};
|
||||||
|
@ -259,12 +262,12 @@ namespace SourceGit.ViewModels
|
||||||
blame.Icon = App.CreateMenuIcon("Icons.Blame");
|
blame.Icon = App.CreateMenuIcon("Icons.Blame");
|
||||||
blame.Click += (_, ev) =>
|
blame.Click += (_, ev) =>
|
||||||
{
|
{
|
||||||
var window = new Views.Blame() { DataContext = new Blame(_repo, change.Path, _commit.SHA) };
|
var window = new Views.Blame() { DataContext = new Blame(_repo.FullPath, change.Path, _commit.SHA) };
|
||||||
window.Show();
|
window.Show();
|
||||||
ev.Handled = true;
|
ev.Handled = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
var full = Path.GetFullPath(Path.Combine(_repo, change.Path));
|
var full = Path.GetFullPath(Path.Combine(_repo.FullPath, change.Path));
|
||||||
var explore = new MenuItem();
|
var explore = new MenuItem();
|
||||||
explore.Header = App.Text("RevealFile");
|
explore.Header = App.Text("RevealFile");
|
||||||
explore.Icon = App.CreateMenuIcon("Icons.Explore");
|
explore.Icon = App.CreateMenuIcon("Icons.Explore");
|
||||||
|
@ -312,7 +315,7 @@ namespace SourceGit.ViewModels
|
||||||
history.Icon = App.CreateMenuIcon("Icons.Histories");
|
history.Icon = App.CreateMenuIcon("Icons.Histories");
|
||||||
history.Click += (_, ev) =>
|
history.Click += (_, ev) =>
|
||||||
{
|
{
|
||||||
var window = new Views.FileHistories() { DataContext = new FileHistories(_repo, file.Path, _issueTrackerRules) };
|
var window = new Views.FileHistories() { DataContext = new FileHistories(_repo, file.Path) };
|
||||||
window.Show();
|
window.Show();
|
||||||
ev.Handled = true;
|
ev.Handled = true;
|
||||||
};
|
};
|
||||||
|
@ -323,12 +326,12 @@ namespace SourceGit.ViewModels
|
||||||
blame.IsEnabled = file.Type == Models.ObjectType.Blob;
|
blame.IsEnabled = file.Type == Models.ObjectType.Blob;
|
||||||
blame.Click += (_, ev) =>
|
blame.Click += (_, ev) =>
|
||||||
{
|
{
|
||||||
var window = new Views.Blame() { DataContext = new Blame(_repo, file.Path, _commit.SHA) };
|
var window = new Views.Blame() { DataContext = new Blame(_repo.FullPath, file.Path, _commit.SHA) };
|
||||||
window.Show();
|
window.Show();
|
||||||
ev.Handled = true;
|
ev.Handled = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
var full = Path.GetFullPath(Path.Combine(_repo, file.Path));
|
var full = Path.GetFullPath(Path.Combine(_repo.FullPath, file.Path));
|
||||||
var explore = new MenuItem();
|
var explore = new MenuItem();
|
||||||
explore.Header = App.Text("RevealFile");
|
explore.Header = App.Text("RevealFile");
|
||||||
explore.Icon = App.CreateMenuIcon("Icons.Explore");
|
explore.Icon = App.CreateMenuIcon("Icons.Explore");
|
||||||
|
@ -353,7 +356,7 @@ namespace SourceGit.ViewModels
|
||||||
if (selected.Count == 1)
|
if (selected.Count == 1)
|
||||||
{
|
{
|
||||||
var saveTo = Path.Combine(selected[0].Path.LocalPath, Path.GetFileName(file.Path));
|
var saveTo = Path.Combine(selected[0].Path.LocalPath, Path.GetFileName(file.Path));
|
||||||
Commands.SaveRevisionFile.Run(_repo, _commit.SHA, file.Path, saveTo);
|
Commands.SaveRevisionFile.Run(_repo.FullPath, _commit.SHA, file.Path, saveTo);
|
||||||
}
|
}
|
||||||
|
|
||||||
ev.Handled = true;
|
ev.Handled = true;
|
||||||
|
@ -406,9 +409,9 @@ namespace SourceGit.ViewModels
|
||||||
|
|
||||||
Task.Run(() =>
|
Task.Run(() =>
|
||||||
{
|
{
|
||||||
var fullMessage = new Commands.QueryCommitFullMessage(_repo, _commit.SHA).Result();
|
var fullMessage = new Commands.QueryCommitFullMessage(_repo.FullPath, _commit.SHA).Result();
|
||||||
var parent = _commit.Parents.Count == 0 ? "4b825dc642cb6eb9a060e54bf8d69288fbee4904" : _commit.Parents[0];
|
var parent = _commit.Parents.Count == 0 ? "4b825dc642cb6eb9a060e54bf8d69288fbee4904" : _commit.Parents[0];
|
||||||
var cmdChanges = new Commands.CompareRevisions(_repo, parent, _commit.SHA) { Cancel = _cancelToken };
|
var cmdChanges = new Commands.CompareRevisions(_repo.FullPath, parent, _commit.SHA) { Cancel = _cancelToken };
|
||||||
var changes = cmdChanges.Result();
|
var changes = cmdChanges.Result();
|
||||||
var visible = changes;
|
var visible = changes;
|
||||||
if (!string.IsNullOrWhiteSpace(_searchChangeFilter))
|
if (!string.IsNullOrWhiteSpace(_searchChangeFilter))
|
||||||
|
@ -463,8 +466,7 @@ namespace SourceGit.ViewModels
|
||||||
".ico", ".bmp", ".jpg", ".png", ".jpeg"
|
".ico", ".bmp", ".jpg", ".png", ".jpeg"
|
||||||
};
|
};
|
||||||
|
|
||||||
private string _repo;
|
private Repository _repo = null;
|
||||||
private AvaloniaList<Models.IssueTrackerRule> _issueTrackerRules = null;
|
|
||||||
private int _activePageIndex = 0;
|
private int _activePageIndex = 0;
|
||||||
private Models.Commit _commit = null;
|
private Models.Commit _commit = null;
|
||||||
private string _fullMessage = string.Empty;
|
private string _fullMessage = string.Empty;
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Avalonia.Collections;
|
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
|
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
|
||||||
namespace SourceGit.ViewModels
|
namespace SourceGit.ViewModels
|
||||||
|
@ -35,7 +33,7 @@ namespace SourceGit.ViewModels
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DiffContext = new DiffContext(_repo, new Models.DiffOption(value, _file), _diffContext);
|
DiffContext = new DiffContext(_repo.FullPath, new Models.DiffOption(value, _file), _diffContext);
|
||||||
DetailContext.Commit = value;
|
DetailContext.Commit = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,15 +52,15 @@ namespace SourceGit.ViewModels
|
||||||
set => SetProperty(ref _detailContext, value);
|
set => SetProperty(ref _detailContext, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public FileHistories(string repo, string file, AvaloniaList<Models.IssueTrackerRule> issueTrackerRules)
|
public FileHistories(Repository repo, string file)
|
||||||
{
|
{
|
||||||
_repo = repo;
|
_repo = repo;
|
||||||
_file = file;
|
_file = file;
|
||||||
_detailContext = new CommitDetail(repo, issueTrackerRules);
|
_detailContext = new CommitDetail(repo);
|
||||||
|
|
||||||
Task.Run(() =>
|
Task.Run(() =>
|
||||||
{
|
{
|
||||||
var commits = new Commands.QueryCommits(_repo, $"-n 10000 -- \"{file}\"", false).Result();
|
var commits = new Commands.QueryCommits(_repo.FullPath, $"-n 10000 -- \"{file}\"", false).Result();
|
||||||
Dispatcher.UIThread.Invoke(() =>
|
Dispatcher.UIThread.Invoke(() =>
|
||||||
{
|
{
|
||||||
IsLoading = false;
|
IsLoading = false;
|
||||||
|
@ -73,7 +71,7 @@ namespace SourceGit.ViewModels
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly string _repo = null;
|
private readonly Repository _repo = null;
|
||||||
private readonly string _file = null;
|
private readonly string _file = null;
|
||||||
private bool _isLoading = true;
|
private bool _isLoading = true;
|
||||||
private List<Models.Commit> _commits = null;
|
private List<Models.Commit> _commits = null;
|
||||||
|
|
|
@ -93,7 +93,7 @@ namespace SourceGit.ViewModels
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var commitDetail = new CommitDetail(_repo.FullPath, _repo.Settings.IssueTrackerRules);
|
var commitDetail = new CommitDetail(_repo);
|
||||||
commitDetail.Commit = commit;
|
commitDetail.Commit = commit;
|
||||||
DetailContext = commitDetail;
|
DetailContext = commitDetail;
|
||||||
}
|
}
|
||||||
|
@ -121,7 +121,7 @@ namespace SourceGit.ViewModels
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var commitDetail = new CommitDetail(_repo.FullPath, _repo.Settings.IssueTrackerRules);
|
var commitDetail = new CommitDetail(_repo);
|
||||||
commitDetail.Commit = commit;
|
commitDetail.Commit = commit;
|
||||||
DetailContext = commitDetail;
|
DetailContext = commitDetail;
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,7 +114,7 @@ namespace SourceGit.ViewModels
|
||||||
Current = current;
|
Current = current;
|
||||||
On = on;
|
On = on;
|
||||||
IsLoading = true;
|
IsLoading = true;
|
||||||
DetailContext = new CommitDetail(repoPath, repo.Settings.IssueTrackerRules);
|
DetailContext = new CommitDetail(repo);
|
||||||
|
|
||||||
Task.Run(() =>
|
Task.Run(() =>
|
||||||
{
|
{
|
||||||
|
|
|
@ -491,6 +491,25 @@ namespace SourceGit.ViewModels
|
||||||
PopupHost.ShowAndStartPopup(new Cleanup(this));
|
PopupHost.ShowAndStartPopup(new Cleanup(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AvaloniaList<Models.CommitLink> TryGetCommitLinks()
|
||||||
|
{
|
||||||
|
var rs = new AvaloniaList<Models.CommitLink>();
|
||||||
|
foreach (var remote in _remotes)
|
||||||
|
{
|
||||||
|
if (remote.TryGetVisitURL(out var url))
|
||||||
|
{
|
||||||
|
if (url.StartsWith("https://github.com/", StringComparison.Ordinal))
|
||||||
|
rs.Add(new Models.CommitLink() { Name = "Github", URLTemplate = $"{url}/commit/SOURCEGIT_COMMIT_HASH_CODE" });
|
||||||
|
else if (url.StartsWith("https://gitlab.com/", StringComparison.Ordinal))
|
||||||
|
rs.Add(new Models.CommitLink() { Name = "GitLab", URLTemplate = $"{url}/-/commit/SOURCEGIT_COMMIT_HASH_CODE" });
|
||||||
|
else if (url.StartsWith("https://gitee.com/", StringComparison.Ordinal))
|
||||||
|
rs.Add(new Models.CommitLink() { Name = "Gitee", URLTemplate = $"{url}/commit/SOURCEGIT_COMMIT_HASH_CODE" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rs;
|
||||||
|
}
|
||||||
|
|
||||||
public void ClearHistoriesFilter()
|
public void ClearHistoriesFilter()
|
||||||
{
|
{
|
||||||
_settings.Filters.Clear();
|
_settings.Filters.Clear();
|
||||||
|
|
|
@ -567,7 +567,7 @@ namespace SourceGit.ViewModels
|
||||||
history.Icon = App.CreateMenuIcon("Icons.Histories");
|
history.Icon = App.CreateMenuIcon("Icons.Histories");
|
||||||
history.Click += (_, e) =>
|
history.Click += (_, e) =>
|
||||||
{
|
{
|
||||||
var window = new Views.FileHistories() { DataContext = new FileHistories(_repo.FullPath, change.Path, _repo.Settings.IssueTrackerRules) };
|
var window = new Views.FileHistories() { DataContext = new FileHistories(_repo, change.Path) };
|
||||||
window.Show();
|
window.Show();
|
||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
};
|
};
|
||||||
|
|
|
@ -54,7 +54,17 @@
|
||||||
<Grid RowDefinitions="24,Auto,Auto,Auto" ColumnDefinitions="96,*">
|
<Grid RowDefinitions="24,Auto,Auto,Auto" ColumnDefinitions="96,*">
|
||||||
<!-- SHA -->
|
<!-- SHA -->
|
||||||
<TextBlock Grid.Row="0" Grid.Column="0" Classes="info_label" Text="{DynamicResource Text.CommitDetail.Info.SHA}" />
|
<TextBlock Grid.Row="0" Grid.Column="0" Classes="info_label" Text="{DynamicResource Text.CommitDetail.Info.SHA}" />
|
||||||
<SelectableTextBlock Grid.Row="0" Grid.Column="1" Classes="primary" Text="{Binding SHA}" Margin="12,0,0,0" VerticalAlignment="Center"/>
|
<StackPanel Grid.Row="0" Grid.Column="1" Orientation="Horizontal">
|
||||||
|
<SelectableTextBlock Classes="primary"
|
||||||
|
Text="{Binding SHA}"
|
||||||
|
Margin="12,0,0,0"
|
||||||
|
VerticalAlignment="Center"/>
|
||||||
|
|
||||||
|
<Button Classes="icon_button" Click="OnOpenWebLink" IsVisible="{Binding #ThisControl.WebLinks, Converter={x:Static c:ListConverters.IsNotNullOrEmpty}}">
|
||||||
|
<Path Width="12" Height="12" Data="{StaticResource Icons.Link}" Fill="{DynamicResource Brush.Link}"/>
|
||||||
|
</Button>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
|
||||||
<!-- PARENTS -->
|
<!-- PARENTS -->
|
||||||
<TextBlock Grid.Row="1" Grid.Column="0" Classes="info_label" Text="{DynamicResource Text.CommitDetail.Info.Parents}" IsVisible="{Binding Parents.Count, Converter={x:Static c:IntConverters.IsGreaterThanZero}}"/>
|
<TextBlock Grid.Row="1" Grid.Column="0" Classes="info_label" Text="{DynamicResource Text.CommitDetail.Info.Parents}" IsVisible="{Binding Parents.Count, Converter={x:Static c:IntConverters.IsGreaterThanZero}}"/>
|
||||||
|
|
|
@ -2,20 +2,12 @@ using Avalonia;
|
||||||
using Avalonia.Collections;
|
using Avalonia.Collections;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
|
using Avalonia.Interactivity;
|
||||||
|
|
||||||
namespace SourceGit.Views
|
namespace SourceGit.Views
|
||||||
{
|
{
|
||||||
public partial class CommitBaseInfo : UserControl
|
public partial class CommitBaseInfo : UserControl
|
||||||
{
|
{
|
||||||
public static readonly StyledProperty<bool> CanNavigateProperty =
|
|
||||||
AvaloniaProperty.Register<CommitBaseInfo, bool>(nameof(CanNavigate), true);
|
|
||||||
|
|
||||||
public bool CanNavigate
|
|
||||||
{
|
|
||||||
get => GetValue(CanNavigateProperty);
|
|
||||||
set => SetValue(CanNavigateProperty, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static readonly StyledProperty<string> MessageProperty =
|
public static readonly StyledProperty<string> MessageProperty =
|
||||||
AvaloniaProperty.Register<CommitBaseInfo, string>(nameof(Message), string.Empty);
|
AvaloniaProperty.Register<CommitBaseInfo, string>(nameof(Message), string.Empty);
|
||||||
|
|
||||||
|
@ -25,6 +17,15 @@ namespace SourceGit.Views
|
||||||
set => SetValue(MessageProperty, value);
|
set => SetValue(MessageProperty, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static readonly StyledProperty<AvaloniaList<Models.CommitLink>> WebLinksProperty =
|
||||||
|
AvaloniaProperty.Register<CommitBaseInfo, AvaloniaList<Models.CommitLink>>(nameof(WebLinks));
|
||||||
|
|
||||||
|
public AvaloniaList<Models.CommitLink> WebLinks
|
||||||
|
{
|
||||||
|
get => GetValue(WebLinksProperty);
|
||||||
|
set => SetValue(WebLinksProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
public static readonly StyledProperty<AvaloniaList<Models.IssueTrackerRule>> IssueTrackerRulesProperty =
|
public static readonly StyledProperty<AvaloniaList<Models.IssueTrackerRule>> IssueTrackerRulesProperty =
|
||||||
AvaloniaProperty.Register<CommitBaseInfo, AvaloniaList<Models.IssueTrackerRule>>(nameof(IssueTrackerRules));
|
AvaloniaProperty.Register<CommitBaseInfo, AvaloniaList<Models.IssueTrackerRule>>(nameof(IssueTrackerRules));
|
||||||
|
|
||||||
|
@ -39,11 +40,43 @@ namespace SourceGit.Views
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnOpenWebLink(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (DataContext is ViewModels.CommitDetail detail)
|
||||||
|
{
|
||||||
|
var links = WebLinks;
|
||||||
|
if (links.Count > 1)
|
||||||
|
{
|
||||||
|
var menu = new ContextMenu();
|
||||||
|
|
||||||
|
foreach (var link in links)
|
||||||
|
{
|
||||||
|
var url = link.URLTemplate.Replace("SOURCEGIT_COMMIT_HASH_CODE", detail.Commit.SHA);
|
||||||
|
var item = new MenuItem() { Header = link.Name };
|
||||||
|
item.Click += (_, ev) =>
|
||||||
|
{
|
||||||
|
Native.OS.OpenBrowser(url);
|
||||||
|
ev.Handled = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
menu.Items.Add(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
(sender as Control)?.OpenContextMenu(menu);
|
||||||
|
}
|
||||||
|
else if (links.Count == 1)
|
||||||
|
{
|
||||||
|
var url = links[0].URLTemplate.Replace("SOURCEGIT_COMMIT_HASH_CODE", detail.Commit.SHA);
|
||||||
|
Native.OS.OpenBrowser(url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
|
|
||||||
private void OnParentSHAPressed(object sender, PointerPressedEventArgs e)
|
private void OnParentSHAPressed(object sender, PointerPressedEventArgs e)
|
||||||
{
|
{
|
||||||
if (sender is Control { DataContext: string sha } &&
|
if (DataContext is ViewModels.CommitDetail detail && sender is Control { DataContext: string sha })
|
||||||
DataContext is ViewModels.CommitDetail detail &&
|
|
||||||
CanNavigate)
|
|
||||||
{
|
{
|
||||||
detail.NavigateTo(sha);
|
detail.NavigateTo(sha);
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
<!-- Base Information -->
|
<!-- Base Information -->
|
||||||
<v:CommitBaseInfo Content="{Binding Commit}"
|
<v:CommitBaseInfo Content="{Binding Commit}"
|
||||||
Message="{Binding FullMessage}"
|
Message="{Binding FullMessage}"
|
||||||
|
WebLinks="{Binding WebLinks}"
|
||||||
IssueTrackerRules="{Binding IssueTrackerRules}"/>
|
IssueTrackerRules="{Binding IssueTrackerRules}"/>
|
||||||
|
|
||||||
<!-- Line -->
|
<!-- Line -->
|
||||||
|
|
|
@ -176,7 +176,7 @@
|
||||||
<ContentControl.DataTemplates>
|
<ContentControl.DataTemplates>
|
||||||
<DataTemplate DataType="m:RevisionSubmodule">
|
<DataTemplate DataType="m:RevisionSubmodule">
|
||||||
<Border Margin="0,0,0,8" BorderThickness="1" BorderBrush="{DynamicResource Brush.Border1}" Background="{DynamicResource Brush.Window}">
|
<Border Margin="0,0,0,8" BorderThickness="1" BorderBrush="{DynamicResource Brush.Border1}" Background="{DynamicResource Brush.Window}">
|
||||||
<v:CommitBaseInfo MaxHeight="256" Margin="0,0,0,4" CanNavigate="False" Content="{Binding Commit}" Message="{Binding FullMessage}"/>
|
<v:CommitBaseInfo MaxHeight="256" Margin="0,0,0,4" Content="{Binding Commit}" Message="{Binding FullMessage}"/>
|
||||||
</Border>
|
</Border>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ContentControl.DataTemplates>
|
</ContentControl.DataTemplates>
|
||||||
|
@ -190,7 +190,7 @@
|
||||||
<Path Width="16" Height="16" Data="{StaticResource Icons.DoubleDown}" HorizontalAlignment="Center" IsVisible="{Binding Old, Converter={x:Static ObjectConverters.IsNotNull}}"/>
|
<Path Width="16" Height="16" Data="{StaticResource Icons.DoubleDown}" HorizontalAlignment="Center" IsVisible="{Binding Old, Converter={x:Static ObjectConverters.IsNotNull}}"/>
|
||||||
|
|
||||||
<Border Margin="0,8,0,0" BorderThickness="1" BorderBrush="Green" Background="{DynamicResource Brush.Window}">
|
<Border Margin="0,8,0,0" BorderThickness="1" BorderBrush="Green" Background="{DynamicResource Brush.Window}">
|
||||||
<v:CommitBaseInfo MaxHeight="256" Margin="0,0,0,4" CanNavigate="False" Content="{Binding New.Commit}" Message="{Binding New.FullMessage}"/>
|
<v:CommitBaseInfo MaxHeight="256" Margin="0,0,0,4" Content="{Binding New.Commit}" Message="{Binding New.FullMessage}"/>
|
||||||
</Border>
|
</Border>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
|
|
|
@ -73,7 +73,7 @@
|
||||||
<DataTemplate DataType="m:RevisionSubmodule">
|
<DataTemplate DataType="m:RevisionSubmodule">
|
||||||
<StackPanel Orientation="Vertical" HorizontalAlignment="Stretch" Margin="8,8,8,0">
|
<StackPanel Orientation="Vertical" HorizontalAlignment="Stretch" Margin="8,8,8,0">
|
||||||
<TextBlock Text="{DynamicResource Text.CommitDetail.Files.Submodule}" FontSize="18" FontWeight="Bold" HorizontalAlignment="Center" Foreground="{DynamicResource Brush.FG2}"/>
|
<TextBlock Text="{DynamicResource Text.CommitDetail.Files.Submodule}" FontSize="18" FontWeight="Bold" HorizontalAlignment="Center" Foreground="{DynamicResource Brush.FG2}"/>
|
||||||
<v:CommitBaseInfo Margin="0,16,0,0" CanNavigate="False" Content="{Binding Commit}" Message="{Binding FullMessage}"/>
|
<v:CommitBaseInfo Margin="0,16,0,0" Content="{Binding Commit}" Message="{Binding FullMessage}"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ContentControl.DataTemplates>
|
</ContentControl.DataTemplates>
|
||||||
|
|
Loading…
Reference in a new issue