Add 'Created at' to time log table. Show total hours for the day in the time log table (not just in the widget in sidebar)
All checks were successful
CI / test (push) Successful in 6m19s
Lint / test (push) Successful in 34s
Trivy / test (push) Successful in 25s

This commit is contained in:
Miguel Jacq 2025-12-03 14:59:57 +11:00
parent 779049e467
commit f8909d7fcb
Signed by: mig5
GPG key ID: 59B3F0C24135C6A9
4 changed files with 30 additions and 11 deletions

View file

@ -1,6 +1,8 @@
# 0.6.2 # 0.6.2
* Ensure that adding a document whilst on an older date page, uses that date as its upload date * Ensure that adding a document whilst on an older date page, uses that date as its upload date
* Add 'Created at' to time log table.
* Show total hours for the day in the time log table (not just in the widget in sidebar)
# 0.6.1 # 0.6.1

View file

@ -1075,7 +1075,8 @@ class DBManager:
t.activity_id, t.activity_id,
a.name AS activity_name, a.name AS activity_name,
t.minutes, t.minutes,
t.note t.note,
t.created_at AS created_at
FROM time_log t FROM time_log t
JOIN projects p ON p.id = t.project_id JOIN projects p ON p.id = t.project_id
JOIN activities a ON a.id = t.activity_id JOIN activities a ON a.id = t.activity_id
@ -1097,6 +1098,7 @@ class DBManager:
r["activity_name"], r["activity_name"],
r["minutes"], r["minutes"],
r["note"], r["note"],
r["created_at"],
) )
) )
return result return result

View file

@ -206,6 +206,7 @@
"delete_time_entry": "Delete time entry", "delete_time_entry": "Delete time entry",
"group_by": "Group by", "group_by": "Group by",
"hours": "Hours", "hours": "Hours",
"created_at": "Created at",
"invalid_activity_message": "The activity is invalid", "invalid_activity_message": "The activity is invalid",
"invalid_activity_title": "Invalid activity", "invalid_activity_title": "Invalid activity",
"invalid_project_message": "The project is invalid", "invalid_project_message": "The project is invalid",

View file

@ -4,8 +4,9 @@ import csv
import html import html
from collections import defaultdict from collections import defaultdict
from typing import Optional from datetime import datetime
from sqlcipher3.dbapi2 import IntegrityError from sqlcipher3.dbapi2 import IntegrityError
from typing import Optional
from PySide6.QtCore import Qt, QDate, QUrl from PySide6.QtCore import Qt, QDate, QUrl
from PySide6.QtGui import QPainter, QColor, QImage, QTextDocument, QPageLayout from PySide6.QtGui import QPainter, QColor, QImage, QTextDocument, QPageLayout
@ -204,12 +205,6 @@ class TimeLogWidget(QFrame):
class TimeLogDialog(QDialog): class TimeLogDialog(QDialog):
""" """
Per-day time log dialog. Per-day time log dialog.
Lets you:
1) choose a project
2) enter an activity (free-text with autocomplete)
3) enter time in decimal hours (0.25 = 15 min, 0.17 10 min)
4) manage entries for this date
""" """
def __init__( def __init__(
@ -230,6 +225,8 @@ class TimeLogDialog(QDialog):
# programmatic item changes as user edits. # programmatic item changes as user edits.
self._reloading_entries: bool = False self._reloading_entries: bool = False
self.total_hours = 0
self.close_after_add = close_after_add self.close_after_add = close_after_add
self.setWindowTitle(strings._("time_log_for").format(date=date_iso)) self.setWindowTitle(strings._("time_log_for").format(date=date_iso))
@ -245,7 +242,6 @@ class TimeLogDialog(QDialog):
date_row.addStretch(1) date_row.addStretch(1)
# You can i18n this later if you like
self.change_date_btn = QPushButton(strings._("time_log_change_date")) self.change_date_btn = QPushButton(strings._("time_log_change_date"))
self.change_date_btn.clicked.connect(self._on_change_date_clicked) self.change_date_btn.clicked.connect(self._on_change_date_clicked)
date_row.addWidget(self.change_date_btn) date_row.addWidget(self.change_date_btn)
@ -309,13 +305,14 @@ class TimeLogDialog(QDialog):
# --- Table of entries for this date # --- Table of entries for this date
self.table = QTableWidget() self.table = QTableWidget()
self.table.setColumnCount(4) self.table.setColumnCount(5)
self.table.setHorizontalHeaderLabels( self.table.setHorizontalHeaderLabels(
[ [
strings._("project"), strings._("project"),
strings._("activity"), strings._("activity"),
strings._("note"), strings._("note"),
strings._("hours"), strings._("hours"),
strings._("created_at"),
] ]
) )
self.table.horizontalHeader().setSectionResizeMode(0, QHeaderView.Stretch) self.table.horizontalHeader().setSectionResizeMode(0, QHeaderView.Stretch)
@ -324,6 +321,7 @@ class TimeLogDialog(QDialog):
self.table.horizontalHeader().setSectionResizeMode( self.table.horizontalHeader().setSectionResizeMode(
3, QHeaderView.ResizeToContents 3, QHeaderView.ResizeToContents
) )
self.table.horizontalHeader().setSectionResizeMode(4, QHeaderView.Stretch)
self.table.setSelectionBehavior(QAbstractItemView.SelectRows) self.table.setSelectionBehavior(QAbstractItemView.SelectRows)
self.table.setSelectionMode(QAbstractItemView.SingleSelection) self.table.setSelectionMode(QAbstractItemView.SingleSelection)
self.table.itemSelectionChanged.connect(self._on_row_selected) self.table.itemSelectionChanged.connect(self._on_row_selected)
@ -331,8 +329,12 @@ class TimeLogDialog(QDialog):
self.table.itemChanged.connect(self._on_table_item_changed) self.table.itemChanged.connect(self._on_table_item_changed)
root.addWidget(self.table, 1) root.addWidget(self.table, 1)
# --- Close button # --- Total time and Close button
close_row = QHBoxLayout() close_row = QHBoxLayout()
self.total_label = QLabel(
strings._("time_log_total_hours").format(hours=self.total_hours)
)
close_row.addWidget(self.total_label)
close_row.addStretch(1) close_row.addStretch(1)
close_btn = QPushButton(strings._("close")) close_btn = QPushButton(strings._("close"))
close_btn.clicked.connect(self.accept) close_btn.clicked.connect(self.accept)
@ -381,11 +383,16 @@ class TimeLogDialog(QDialog):
note = r[7] or "" note = r[7] or ""
minutes = r[6] minutes = r[6]
hours = minutes / 60.0 hours = minutes / 60.0
created_at = r[8]
ca_utc = datetime.fromisoformat(created_at.replace("Z", "+00:00"))
ca_local = ca_utc.astimezone()
created = f"{ca_local.day} {ca_local.strftime('%b %Y, %H:%M%p')}"
item_proj = QTableWidgetItem(project_name) item_proj = QTableWidgetItem(project_name)
item_act = QTableWidgetItem(activity_name) item_act = QTableWidgetItem(activity_name)
item_note = QTableWidgetItem(note) item_note = QTableWidgetItem(note)
item_hours = QTableWidgetItem(f"{hours:.2f}") item_hours = QTableWidgetItem(f"{hours:.2f}")
item_created_at = QTableWidgetItem(created)
# store the entry id on the first column # store the entry id on the first column
item_proj.setData(Qt.ItemDataRole.UserRole, entry_id) item_proj.setData(Qt.ItemDataRole.UserRole, entry_id)
@ -394,9 +401,16 @@ class TimeLogDialog(QDialog):
self.table.setItem(row_idx, 1, item_act) self.table.setItem(row_idx, 1, item_act)
self.table.setItem(row_idx, 2, item_note) self.table.setItem(row_idx, 2, item_note)
self.table.setItem(row_idx, 3, item_hours) self.table.setItem(row_idx, 3, item_hours)
self.table.setItem(row_idx, 4, item_created_at)
finally: finally:
self._reloading_entries = False self._reloading_entries = False
total_minutes = sum(r[6] for r in rows)
self.total_hours = total_minutes / 60.0
self.total_label.setText(
strings._("time_log_total_hours").format(hours=self.total_hours)
)
self._current_entry_id = None self._current_entry_id = None
self.delete_btn.setEnabled(False) self.delete_btn.setEnabled(False)
self.add_update_btn.setText("&" + strings._("add_time_entry")) self.add_update_btn.setText("&" + strings._("add_time_entry"))