From e439a45e9b12fed0e7f03d46c515b134de145161 Mon Sep 17 00:00:00 2001 From: dkorecko <22599403+dkorecko@users.noreply.github.com> Date: Sun, 4 Jan 2026 15:12:38 +0100 Subject: [PATCH 1/4] done --- .idea/.idea.Ticky/.idea/.gitignore | 15 +++ .idea/.idea.Ticky/.idea/CSharpierPlugin.xml | 6 ++ .idea/.idea.Ticky/.idea/dataSources.xml | 12 +++ .idea/.idea.Ticky/.idea/encodings.xml | 4 + .idea/.idea.Ticky/.idea/indexLayout.xml | 8 ++ .idea/.idea.Ticky/.idea/vcs.xml | 6 ++ Ticky.Web/Components/Pages/BoardView.razor | 107 ++++++++++++++++++++ 7 files changed, 158 insertions(+) create mode 100644 .idea/.idea.Ticky/.idea/.gitignore create mode 100644 .idea/.idea.Ticky/.idea/CSharpierPlugin.xml create mode 100644 .idea/.idea.Ticky/.idea/dataSources.xml create mode 100644 .idea/.idea.Ticky/.idea/encodings.xml create mode 100644 .idea/.idea.Ticky/.idea/indexLayout.xml create mode 100644 .idea/.idea.Ticky/.idea/vcs.xml diff --git a/.idea/.idea.Ticky/.idea/.gitignore b/.idea/.idea.Ticky/.idea/.gitignore new file mode 100644 index 0000000..a5f24f5 --- /dev/null +++ b/.idea/.idea.Ticky/.idea/.gitignore @@ -0,0 +1,15 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Rider ignored files +/contentModel.xml +/projectSettingsUpdater.xml +/modules.xml +/.idea.Ticky.iml +# Ignored default folder with query files +/queries/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/.idea.Ticky/.idea/CSharpierPlugin.xml b/.idea/.idea.Ticky/.idea/CSharpierPlugin.xml new file mode 100644 index 0000000..1b71b0c --- /dev/null +++ b/.idea/.idea.Ticky/.idea/CSharpierPlugin.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/.idea.Ticky/.idea/dataSources.xml b/.idea/.idea.Ticky/.idea/dataSources.xml new file mode 100644 index 0000000..97ee6c8 --- /dev/null +++ b/.idea/.idea.Ticky/.idea/dataSources.xml @@ -0,0 +1,12 @@ + + + + + mysql.8 + true + com.mysql.cj.jdbc.Driver + jdbc:mysql://localhost:3306 + $ProjectFileDir$ + + + \ No newline at end of file diff --git a/.idea/.idea.Ticky/.idea/encodings.xml b/.idea/.idea.Ticky/.idea/encodings.xml new file mode 100644 index 0000000..df87cf9 --- /dev/null +++ b/.idea/.idea.Ticky/.idea/encodings.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/.idea.Ticky/.idea/indexLayout.xml b/.idea/.idea.Ticky/.idea/indexLayout.xml new file mode 100644 index 0000000..7b08163 --- /dev/null +++ b/.idea/.idea.Ticky/.idea/indexLayout.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/.idea.Ticky/.idea/vcs.xml b/.idea/.idea.Ticky/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/.idea.Ticky/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Ticky.Web/Components/Pages/BoardView.razor b/Ticky.Web/Components/Pages/BoardView.razor index bf8cf40..6e045bb 100644 --- a/Ticky.Web/Components/Pages/BoardView.razor +++ b/Ticky.Web/Components/Pages/BoardView.razor @@ -111,6 +111,51 @@
+ + +
+

Column time totals

+ @foreach(var col in _board.Columns.OrderBy(c => c.Index)) + { + var colCards = _cards.Where(c => c.ColumnId == col.Id).ToList(); + var colTotal = GetTotalForCards(colCards); + var perUser = GetTotalsByUser(colCards); + var expandId = $"coltime_{col.Id}"; + +
+
+
+ + +
+
+ +
+
+ + @if (IsExpanded(expandId)) + { +
+ @if (perUser.Any()) + { + @foreach(var kv in perUser.OrderByDescending(k => k.Value)) + { + var user = _members.FirstOrDefault(m => m.Id == kv.Key); +
+
@((user != null) ? user.Name : "Unknown")
+
@kv.Value.ToElapsedString(true)
+
+ } + } + else + { +
No time tracked
+ } +
+ } +
+ } +
} else @@ -162,6 +207,7 @@ private int? _initialCardId; private HubConnection? _hubConnection; + private HashSet _expandedSections = new(); protected override void OnParametersSet() { @@ -531,5 +577,66 @@ { _adding = columnId; } + + private void ToggleExpand(string id) + { + if (_expandedSections.Contains(id)) + _expandedSections.Remove(id); + else + _expandedSections.Add(id); + + StateHasChanged(); + } + + private bool IsExpanded(string id) => _expandedSections.Contains(id); + + private static TimeSpan GetTotalForCards(List cards) + { + TimeSpan total = TimeSpan.Zero; + var now = DateTime.Now; + + foreach (var card in cards) + { + if (card.TimeRecords is null) + continue; + + foreach (var tr in card.TimeRecords) + { + var end = tr.EndedAt ?? now; + if (end > tr.StartedAt) + total += end - tr.StartedAt; + } + } + + return total; + } + + private static Dictionary GetTotalsByUser(List cards) + { + var totals = new Dictionary(); + var now = DateTime.Now; + + foreach (var card in cards) + { + if (card.TimeRecords is null) + continue; + + foreach (var tr in card.TimeRecords) + { + var end = tr.EndedAt ?? now; + if (end <= tr.StartedAt) + continue; + + var d = end - tr.StartedAt; + if (!totals.ContainsKey(tr.UserId)) + totals[tr.UserId] = TimeSpan.Zero; + + totals[tr.UserId] += d; + } + } + + return totals; + } + } From 2b215598ce410759635f2858e1e61aab227c21e1 Mon Sep 17 00:00:00 2001 From: dkorecko <22599403+dkorecko@users.noreply.github.com> Date: Sun, 4 Jan 2026 16:14:35 +0100 Subject: [PATCH 2/4] improvements --- .gitignore | 5 +- .idea/.idea.Ticky/.idea/CSharpierPlugin.xml | 3 +- Ticky.Base/Entities/Card.cs | 3 + Ticky.Base/Entities/TimeRecord.cs | 5 ++ Ticky.Base/GlobalUsings.cs | 1 + Ticky.Base/Ticky.Base.csproj | 2 +- Ticky.Internal/Ticky.Internal.csproj | 2 +- Ticky.Web/Components/Elements/CardView.razor | 4 +- Ticky.Web/Components/Pages/BoardView.razor | 63 +++----------------- Ticky.Web/Ticky.Web.csproj | 2 +- 10 files changed, 27 insertions(+), 63 deletions(-) diff --git a/.gitignore b/.gitignore index 18b7304..9f2f01c 100644 --- a/.gitignore +++ b/.gitignore @@ -362,4 +362,7 @@ MigrationBackup/ # Fody - auto-generated XML schema FodyWeavers.xsd -**/uploaded/**/* \ No newline at end of file +**/uploaded/**/* + +# Idea +.idea/ \ No newline at end of file diff --git a/.idea/.idea.Ticky/.idea/CSharpierPlugin.xml b/.idea/.idea.Ticky/.idea/CSharpierPlugin.xml index 1b71b0c..a225454 100644 --- a/.idea/.idea.Ticky/.idea/CSharpierPlugin.xml +++ b/.idea/.idea.Ticky/.idea/CSharpierPlugin.xml @@ -1,6 +1,7 @@ - \ No newline at end of file diff --git a/Ticky.Base/Entities/Card.cs b/Ticky.Base/Entities/Card.cs index f565081..80e69c6 100644 --- a/Ticky.Base/Entities/Card.cs +++ b/Ticky.Base/Entities/Card.cs @@ -31,6 +31,9 @@ public class Card : AbstractDbEntity, IOrderable, IDeletable, IAssignable public DateTime? SnoozedUntil { get; set; } + public TimeSpan GetTotalTime() => + TimeRecords.Select(x => x.GetTotalTime()).Sum(); + public DateTime CalculateNextRepeat(DateTime from) { if (RepeatInfo is null) diff --git a/Ticky.Base/Entities/TimeRecord.cs b/Ticky.Base/Entities/TimeRecord.cs index 28a1419..03aa3bc 100644 --- a/Ticky.Base/Entities/TimeRecord.cs +++ b/Ticky.Base/Entities/TimeRecord.cs @@ -13,4 +13,9 @@ public class TimeRecord : AbstractDbEntity public required DateTime StartedAt { get; set; } public DateTime? EndedAt { get; set; } + + public TimeSpan GetTotalTime() => + new TimeSpan( + ((EndedAt ?? DateTime.Now) - StartedAt).Ticks + ); } diff --git a/Ticky.Base/GlobalUsings.cs b/Ticky.Base/GlobalUsings.cs index 64ef504..978d1c8 100644 --- a/Ticky.Base/GlobalUsings.cs +++ b/Ticky.Base/GlobalUsings.cs @@ -1,3 +1,4 @@ +global using Devity.Extensions; global using System.ComponentModel.DataAnnotations; global using System.ComponentModel.DataAnnotations.Schema; global using System.Drawing; diff --git a/Ticky.Base/Ticky.Base.csproj b/Ticky.Base/Ticky.Base.csproj index d3dc56b..3a066e1 100644 --- a/Ticky.Base/Ticky.Base.csproj +++ b/Ticky.Base/Ticky.Base.csproj @@ -7,7 +7,7 @@ - + diff --git a/Ticky.Internal/Ticky.Internal.csproj b/Ticky.Internal/Ticky.Internal.csproj index 069ed2c..fb25093 100644 --- a/Ticky.Internal/Ticky.Internal.csproj +++ b/Ticky.Internal/Ticky.Internal.csproj @@ -7,7 +7,7 @@ - + diff --git a/Ticky.Web/Components/Elements/CardView.razor b/Ticky.Web/Components/Elements/CardView.razor index 07bb035..3847a7c 100644 --- a/Ticky.Web/Components/Elements/CardView.razor +++ b/Ticky.Web/Components/Elements/CardView.razor @@ -34,10 +34,10 @@ } @if (Card.Subtasks.Any()) { - + } @{ - var trackedTime = new TimeSpan(Card.TimeRecords.Select(x => ((x.EndedAt ?? DateTime.Now) - x.StartedAt).Ticks).Sum()).ToElapsedString(true); + var trackedTime = Card.GetTotalTime().ToElapsedString(true); } @if (!string.IsNullOrWhiteSpace(trackedTime)) { diff --git a/Ticky.Web/Components/Pages/BoardView.razor b/Ticky.Web/Components/Pages/BoardView.razor index 6e045bb..6f1b216 100644 --- a/Ticky.Web/Components/Pages/BoardView.razor +++ b/Ticky.Web/Components/Pages/BoardView.razor @@ -97,7 +97,7 @@ @if (_board is not null) { - var completedCards = _cards.Where(x => x.Column.Finished).Count(); + var completedCards = _cards.Count(x => x.Column.Finished); var totalCards = _cards.Count();
@@ -118,15 +118,15 @@ @foreach(var col in _board.Columns.OrderBy(c => c.Index)) { var colCards = _cards.Where(c => c.ColumnId == col.Id).ToList(); - var colTotal = GetTotalForCards(colCards); - var perUser = GetTotalsByUser(colCards); - var expandId = $"coltime_{col.Id}"; + var colTotal = colCards.Select(x => x.GetTotalTime()).Sum(); + var perUser = colCards.SelectMany(x => x.TimeRecords).GroupBy(x => x.UserId).Select(x => new KeyValuePair(x.Key, x.Select(y => y.GetTotalTime()).Sum())).ToDictionary(x => x.Key, x => x.Value); + var expandId = $"columnTime_{col.Id}";
- +
@@ -142,8 +142,8 @@ { var user = _members.FirstOrDefault(m => m.Id == kv.Key);
-
@((user != null) ? user.Name : "Unknown")
-
@kv.Value.ToElapsedString(true)
+
@(user != null ? user.Name : "Unknown")
+
@kv.Value.ToElapsedString()
} } @@ -589,54 +589,5 @@ } private bool IsExpanded(string id) => _expandedSections.Contains(id); - - private static TimeSpan GetTotalForCards(List cards) - { - TimeSpan total = TimeSpan.Zero; - var now = DateTime.Now; - - foreach (var card in cards) - { - if (card.TimeRecords is null) - continue; - - foreach (var tr in card.TimeRecords) - { - var end = tr.EndedAt ?? now; - if (end > tr.StartedAt) - total += end - tr.StartedAt; - } - } - - return total; - } - - private static Dictionary GetTotalsByUser(List cards) - { - var totals = new Dictionary(); - var now = DateTime.Now; - - foreach (var card in cards) - { - if (card.TimeRecords is null) - continue; - - foreach (var tr in card.TimeRecords) - { - var end = tr.EndedAt ?? now; - if (end <= tr.StartedAt) - continue; - - var d = end - tr.StartedAt; - if (!totals.ContainsKey(tr.UserId)) - totals[tr.UserId] = TimeSpan.Zero; - - totals[tr.UserId] += d; - } - } - - return totals; - } - } diff --git a/Ticky.Web/Ticky.Web.csproj b/Ticky.Web/Ticky.Web.csproj index ba7325d..41c30d7 100644 --- a/Ticky.Web/Ticky.Web.csproj +++ b/Ticky.Web/Ticky.Web.csproj @@ -9,7 +9,7 @@ - + From ee3aae853596be3d749ef172d908d46373bde8f3 Mon Sep 17 00:00:00 2001 From: dkorecko <22599403+dkorecko@users.noreply.github.com> Date: Sun, 4 Jan 2026 16:15:44 +0100 Subject: [PATCH 3/4] Delete .idea/.idea.Ticky/.idea directory --- .idea/.idea.Ticky/.idea/.gitignore | 15 --------------- .idea/.idea.Ticky/.idea/CSharpierPlugin.xml | 7 ------- .idea/.idea.Ticky/.idea/dataSources.xml | 12 ------------ .idea/.idea.Ticky/.idea/encodings.xml | 4 ---- .idea/.idea.Ticky/.idea/indexLayout.xml | 8 -------- .idea/.idea.Ticky/.idea/vcs.xml | 6 ------ 6 files changed, 52 deletions(-) delete mode 100644 .idea/.idea.Ticky/.idea/.gitignore delete mode 100644 .idea/.idea.Ticky/.idea/CSharpierPlugin.xml delete mode 100644 .idea/.idea.Ticky/.idea/dataSources.xml delete mode 100644 .idea/.idea.Ticky/.idea/encodings.xml delete mode 100644 .idea/.idea.Ticky/.idea/indexLayout.xml delete mode 100644 .idea/.idea.Ticky/.idea/vcs.xml diff --git a/.idea/.idea.Ticky/.idea/.gitignore b/.idea/.idea.Ticky/.idea/.gitignore deleted file mode 100644 index a5f24f5..0000000 --- a/.idea/.idea.Ticky/.idea/.gitignore +++ /dev/null @@ -1,15 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml -# Rider ignored files -/contentModel.xml -/projectSettingsUpdater.xml -/modules.xml -/.idea.Ticky.iml -# Ignored default folder with query files -/queries/ -# Datasource local storage ignored files -/dataSources/ -/dataSources.local.xml -# Editor-based HTTP Client requests -/httpRequests/ diff --git a/.idea/.idea.Ticky/.idea/CSharpierPlugin.xml b/.idea/.idea.Ticky/.idea/CSharpierPlugin.xml deleted file mode 100644 index a225454..0000000 --- a/.idea/.idea.Ticky/.idea/CSharpierPlugin.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - \ No newline at end of file diff --git a/.idea/.idea.Ticky/.idea/dataSources.xml b/.idea/.idea.Ticky/.idea/dataSources.xml deleted file mode 100644 index 97ee6c8..0000000 --- a/.idea/.idea.Ticky/.idea/dataSources.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - mysql.8 - true - com.mysql.cj.jdbc.Driver - jdbc:mysql://localhost:3306 - $ProjectFileDir$ - - - \ No newline at end of file diff --git a/.idea/.idea.Ticky/.idea/encodings.xml b/.idea/.idea.Ticky/.idea/encodings.xml deleted file mode 100644 index df87cf9..0000000 --- a/.idea/.idea.Ticky/.idea/encodings.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/.idea.Ticky/.idea/indexLayout.xml b/.idea/.idea.Ticky/.idea/indexLayout.xml deleted file mode 100644 index 7b08163..0000000 --- a/.idea/.idea.Ticky/.idea/indexLayout.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/.idea.Ticky/.idea/vcs.xml b/.idea/.idea.Ticky/.idea/vcs.xml deleted file mode 100644 index 94a25f7..0000000 --- a/.idea/.idea.Ticky/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file From d4d4e5780dde0b1bba99926f51a70d7db83f661a Mon Sep 17 00:00:00 2001 From: dkorecko <22599403+dkorecko@users.noreply.github.com> Date: Sun, 4 Jan 2026 16:25:10 +0100 Subject: [PATCH 4/4] improvement --- Ticky.Base/Entities/TimeRecord.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Ticky.Base/Entities/TimeRecord.cs b/Ticky.Base/Entities/TimeRecord.cs index 03aa3bc..004780b 100644 --- a/Ticky.Base/Entities/TimeRecord.cs +++ b/Ticky.Base/Entities/TimeRecord.cs @@ -13,9 +13,7 @@ public class TimeRecord : AbstractDbEntity public required DateTime StartedAt { get; set; } public DateTime? EndedAt { get; set; } - + public TimeSpan GetTotalTime() => - new TimeSpan( - ((EndedAt ?? DateTime.Now) - StartedAt).Ticks - ); + (EndedAt ?? DateTime.Now) - StartedAt; }