add hours to issue details (1.1.3)
This commit is contained in:
105
Blueberry.Redmine/Dto/TimeOnIssue.cs
Normal file
105
Blueberry.Redmine/Dto/TimeOnIssue.cs
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable.
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace Blueberry.Redmine.Dto
|
||||||
|
{
|
||||||
|
public class TimeOnIssue
|
||||||
|
{
|
||||||
|
public class Activity
|
||||||
|
{
|
||||||
|
[JsonPropertyName("id")]
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("name")]
|
||||||
|
public string Name { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CustomField
|
||||||
|
{
|
||||||
|
[JsonPropertyName("id")]
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("name")]
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("value")]
|
||||||
|
public string Value { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Issue
|
||||||
|
{
|
||||||
|
[JsonPropertyName("id")]
|
||||||
|
public int Id { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Project
|
||||||
|
{
|
||||||
|
[JsonPropertyName("id")]
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("name")]
|
||||||
|
public string Name { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Root : IResponseList
|
||||||
|
{
|
||||||
|
[JsonPropertyName("time_entries")]
|
||||||
|
public List<TimeEntry> TimeEntries { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("total_count")]
|
||||||
|
public int TotalCount { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("offset")]
|
||||||
|
public int Offset { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("limit")]
|
||||||
|
public int Limit { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TimeEntry
|
||||||
|
{
|
||||||
|
[JsonPropertyName("id")]
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("project")]
|
||||||
|
public Project Project { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("issue")]
|
||||||
|
public Issue Issue { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("user")]
|
||||||
|
public User User { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("activity")]
|
||||||
|
public Activity Activity { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("hours")]
|
||||||
|
public double Hours { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("comments")]
|
||||||
|
public string Comments { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("spent_on")]
|
||||||
|
public string SpentOn { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("created_on")]
|
||||||
|
public DateTime CreatedOn { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("updated_on")]
|
||||||
|
public DateTime UpdatedOn { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("custom_fields")]
|
||||||
|
public List<CustomField> CustomFields { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class User
|
||||||
|
{
|
||||||
|
[JsonPropertyName("id")]
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("name")]
|
||||||
|
public string Name { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable.
|
||||||
@@ -232,6 +232,13 @@ namespace Blueberry.Redmine
|
|||||||
await SendRequestAsync<object>(HttpMethod.Put, path, payload, token: token);
|
await SendRequestAsync<object>(HttpMethod.Put, path, payload, token: token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<List<TimeOnIssue.TimeEntry>> GetTimeOnIssue(int issueId, int limit = 25, IProgress<(int, int)>? progress = null, CancellationToken? token = null)
|
||||||
|
{
|
||||||
|
var path = $"time_entries.json?issue_id={issueId}";
|
||||||
|
var times = await SendRequestWithPagingAsync<TimeOnIssue.Root, TimeOnIssue.TimeEntry>(HttpMethod.Get, path, limit, (x)=>x.TimeEntries, progress, token: token);
|
||||||
|
return times;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<int> CreateNewIssue(int projectId, int trackerId, string subject, string description,
|
public async Task<int> CreateNewIssue(int projectId, int trackerId, string subject, string description,
|
||||||
double estimatedHours, int priorityId, int? assigneeId = null, int? parentIssueId = null, CancellationToken? token = null)
|
double estimatedHours, int priorityId, int? assigneeId = null, int? parentIssueId = null, CancellationToken? token = null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -131,6 +131,12 @@ namespace Blueberry.Redmine
|
|||||||
return await _apiClient.GetTrackersForProject(projectId.ToString(), token);
|
return await _apiClient.GetTrackersForProject(projectId.ToString(), token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<List<TimeOnIssue.TimeEntry>> GetTimeOnIssue(int issueId, int limit = 25, IProgress<(int, int)>? progress = null, CancellationToken? token = null)
|
||||||
|
{
|
||||||
|
var result = await _apiClient.GetTimeOnIssue(issueId, limit, progress, token);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task SetIssueStatusAsync(int issueId, int statusId, CancellationToken? token = null)
|
public async Task SetIssueStatusAsync(int issueId, int statusId, CancellationToken? token = null)
|
||||||
{
|
{
|
||||||
await _apiClient.SetIssueStatus(issueId, statusId, token);
|
await _apiClient.SetIssueStatus(issueId, statusId, token);
|
||||||
|
|||||||
@@ -37,7 +37,8 @@ namespace Blueberry
|
|||||||
iUpdatedTextBox.Text = _issue.UpdatedOn.ToString("yyyy-MM-dd");
|
iUpdatedTextBox.Text = _issue.UpdatedOn.ToString("yyyy-MM-dd");
|
||||||
iSpentTimeTextBox.Text = _issue.SpentHours.ToString();
|
iSpentTimeTextBox.Text = _issue.SpentHours.ToString();
|
||||||
journalProgressRing.Visibility = Visibility.Visible;
|
journalProgressRing.Visibility = Visibility.Visible;
|
||||||
_journalDisplays.AddRange(await ProcessJournal(_issue.Journals));
|
var hours = await _manager.GetTimeOnIssue(_issue.Id);
|
||||||
|
_journalDisplays.AddRange(await ProcessJournal(_issue.Journals, hours));
|
||||||
if(!_journalDisplays.Any(x=>!x.IsData))
|
if(!_journalDisplays.Any(x=>!x.IsData))
|
||||||
detailsToggleSwitch.IsChecked = true;
|
detailsToggleSwitch.IsChecked = true;
|
||||||
await LoadJournal();
|
await LoadJournal();
|
||||||
@@ -75,7 +76,7 @@ namespace Blueberry
|
|||||||
|
|
||||||
public partial class IssueWindow
|
public partial class IssueWindow
|
||||||
{
|
{
|
||||||
public async Task<List<JournalDisplay>> ProcessJournal(IEnumerable<DetailedIssue.Journal> journals)
|
public async Task<List<JournalDisplay>> ProcessJournal(IEnumerable<DetailedIssue.Journal> journals, List<TimeOnIssue.TimeEntry> hours)
|
||||||
{
|
{
|
||||||
var js = new List<JournalDisplay>();
|
var js = new List<JournalDisplay>();
|
||||||
|
|
||||||
@@ -187,6 +188,24 @@ namespace Blueberry
|
|||||||
} catch (Exception) { }
|
} catch (Exception) { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var totalHours = 0d;
|
||||||
|
hours = [.. hours.OrderBy(x => x.CreatedOn)];
|
||||||
|
foreach (var hour in hours)
|
||||||
|
{
|
||||||
|
totalHours += hour.Hours;
|
||||||
|
var user = hour.User.Name;
|
||||||
|
var date = hour.CreatedOn.ToString("yyyy-MM-dd HH:mm");
|
||||||
|
var content = $"Idő: {hour.Hours}\nEddig összesen: {totalHours}\n{hour.Comments}";
|
||||||
|
js.Add(new JournalDisplay
|
||||||
|
{
|
||||||
|
User = user,
|
||||||
|
Date = date,
|
||||||
|
Content = content,
|
||||||
|
IsData = true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
js = [.. js.OrderBy(x => x.Date)];
|
||||||
return js;
|
return js;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ namespace Blueberry
|
|||||||
public static class UpdateManager
|
public static class UpdateManager
|
||||||
{
|
{
|
||||||
private const string releaseUrl = "https://git.technopunk.space/api/v1/repos/tomi/Blueberry/releases/latest";
|
private const string releaseUrl = "https://git.technopunk.space/api/v1/repos/tomi/Blueberry/releases/latest";
|
||||||
public const string CurrentVersion = "0.1.2";
|
public const string CurrentVersion = "0.1.3";
|
||||||
private static readonly string AppDir = AppDomain.CurrentDomain.BaseDirectory;
|
private static readonly string AppDir = AppDomain.CurrentDomain.BaseDirectory;
|
||||||
private static readonly HttpClient client = new();
|
private static readonly HttpClient client = new();
|
||||||
public delegate void DownloadCompletedEventArgs();
|
public delegate void DownloadCompletedEventArgs();
|
||||||
|
|||||||
Reference in New Issue
Block a user