Integrate Jira tasks

This commit is contained in:
Fabian 2021-11-17 03:12:22 +01:00
parent 3e1f17cfa2
commit c3cde56eb8
5 changed files with 104 additions and 43 deletions

77
data.py
View File

@ -1,10 +1,11 @@
import os
import json
import base64
import atexit import atexit
from datetime import datetime, date, time, timedelta import base64
from threading import Thread, Event import json
import os
from collections.abc import MutableMapping from collections.abc import MutableMapping
from datetime import datetime, date, timedelta
from threading import Thread, Event
from typing import List
from PySide2 import QtCore from PySide2 import QtCore
@ -15,33 +16,67 @@ tasks_path = os.path.join(data_dir_path, "tasks.json")
data_path = os.path.join(data_dir_path, "data_{}.json") data_path = os.path.join(data_dir_path, "data_{}.json")
save_delay = 3 * 60 save_delay = 3 * 60
max_jira_tasks = 50
class Tasks: class Tasks:
def __init__(self): def __init__(self, data):
if not os.path.exists(data_dir_path): self._data = data
os.mkdir(data_dir_path) if "tasks" in self._data:
if os.path.exists(tasks_path): self._tasks = list(map(lambda x: base64.b64decode(x.encode("utf-8")).decode("utf-8"), self._data["tasks"]))
with open(tasks_path, "r") as f:
encoded_tasks = json.loads(f.read())
self._tasks = list(map(lambda x: base64.b64decode(x.encode("utf-8")).decode("utf-8"), encoded_tasks))
else: else:
self._tasks = [] self._tasks = []
if "jira_tasks" in self._data:
self._jira_tasks_usage = dict()
for k, v in self._data["jira_tasks"].items():
key = base64.b64decode(k.encode("utf-8")).decode("utf-8")
self._jira_tasks_usage[key] = datetime.fromisoformat(v)
self._jira_tasks = sorted(self._jira_tasks_usage.keys(), key=lambda x: self._jira_tasks_usage[x])
else:
self._jira_tasks_usage = dict()
self._jira_tasks = []
@property @property
def tasks(self): def tasks(self) -> List[str]:
return self._tasks return self._tasks
@tasks.setter @tasks.setter
def tasks(self, tasks): def tasks(self, tasks):
self._tasks = tasks self._tasks = tasks
self._save()
def _save(self):
print("... saving tasks ...")
encoded_tasks = list(map(lambda x: base64.b64encode(x.encode("utf-8")).decode("utf-8"), self._tasks)) encoded_tasks = list(map(lambda x: base64.b64encode(x.encode("utf-8")).decode("utf-8"), self._tasks))
with open(tasks_path, "w+") as f: self._data["tasks"] = encoded_tasks
f.write(json.dumps(encoded_tasks))
@property
def jira_tasks(self):
return self._jira_tasks
def add_jira_task(self, task_name):
print(f"before: {self._jira_tasks}")
self._jira_tasks.append(task_name)
print(f"after: {self._jira_tasks}")
self._jira_tasks_usage[task_name] = datetime.now()
if len(self._jira_tasks_usage) > max_jira_tasks:
sorted_tasks = sorted(self._jira_tasks_usage.keys(), key=lambda x: self._jira_tasks_usage[x])
overhang_tasks = sorted_tasks[:len(sorted_tasks) - max_jira_tasks]
for task in overhang_tasks:
del self._jira_tasks_usage[task]
self._save_jira_tasks()
def update_jira_task_usage(self, task_name):
if task_name in self._jira_tasks_usage:
self._jira_tasks_usage[task_name] = datetime.now()
self._save_jira_tasks()
def _save_jira_tasks(self):
serialized = dict()
for k, v in self._jira_tasks_usage.items():
key = base64.b64encode(k.encode("utf-8")).decode("utf-8")
serialized[key] = datetime.isoformat(v)
self._data["jira_tasks"] = serialized
@property
def all_tasks(self):
return self.tasks + self.jira_tasks
class Data(MutableMapping): class Data(MutableMapping):
@ -110,8 +145,8 @@ class Data(MutableMapping):
class Log: class Log:
def __init__(self): def __init__(self, data):
self._data = Data() self._data = data
def cleanup(): def cleanup():
self.log("End") self.log("End")

46
main.py
View File

@ -7,7 +7,7 @@ from functools import partial
from PySide2 import QtCore, QtGui, QtWidgets from PySide2 import QtCore, QtGui, QtWidgets
from PySide2.QtWidgets import QMessageBox from PySide2.QtWidgets import QMessageBox
from data import Tasks, Log from data import Tasks, Log, Data
from exceptions import FimeFrackingException from exceptions import FimeFrackingException
from new_task import NewTask from new_task import NewTask
from task_edit import TaskEdit from task_edit import TaskEdit
@ -18,8 +18,9 @@ class App:
def __init__(self): def __init__(self):
self.app = QtWidgets.QApplication(sys.argv) self.app = QtWidgets.QApplication(sys.argv)
self.tasks = Tasks() data = Data()
self.log = Log() self.tasks = Tasks(data)
self.log = Log(data)
self.active_task = self.log.last_log() or "Nothing" self.active_task = self.log.last_log() or "Nothing"
icon = QtGui.QIcon.fromTheme("appointment-new") icon = QtGui.QIcon.fromTheme("appointment-new")
@ -27,12 +28,12 @@ class App:
self.menu = QtWidgets.QMenu() self.menu = QtWidgets.QMenu()
self.new_task = NewTask(None) self.new_task = NewTask(None)
self.new_task.accepted.connect(self.new_task_selected) self.new_task.accepted.connect(self.new_task_imported)
self.taskEdit = TaskEdit(None) self.taskEdit = TaskEdit(None)
self.taskEdit.accepted.connect(self.tasks_edited) self.taskEdit.accepted.connect(self.tasks_edited)
self.reportDialog = Report(None) self.reportDialog = Report(self.tasks, None)
self.reportDialog.accepted.connect(self.report_done) self.reportDialog.accepted.connect(self.report_done)
self.tray = QtWidgets.QSystemTrayIcon() self.tray = QtWidgets.QSystemTrayIcon()
@ -43,8 +44,10 @@ class App:
self.update_tray_menu() self.update_tray_menu()
@QtCore.Slot() @QtCore.Slot()
def new_task_selected(self): def new_task_imported(self):
print(f"dialog input: {self.new_task.task_text}") if self.new_task.task_text:
self.tasks.add_jira_task(self.new_task.task_text)
self.update_tray_menu()
@QtCore.Slot() @QtCore.Slot()
def tasks_edited(self): def tasks_edited(self):
@ -64,21 +67,28 @@ class App:
self.update_tray_menu() self.update_tray_menu()
def update_tray_menu(self): def update_tray_menu(self):
self.menu.clear() def add_tasks(tasks):
tasks = list(self.tasks.tasks) for t in tasks:
tasks.append("Pause") a = self.menu.addAction(t)
if self.active_task == "Nothing": a.triggered.connect(partial(self.change_task, t))
tasks.append("Nothing") if t == self.active_task:
a.setIcon(QtGui.QIcon.fromTheme("go-next"))
for t in tasks: self.menu.clear()
a = self.menu.addAction(t)
a.triggered.connect(partial(self.change_task, t)) add_tasks(self.tasks.tasks)
if t == self.active_task:
a.setIcon(QtGui.QIcon.fromTheme("go-next")) self.menu.addSeparator()
add_tasks(self.tasks.jira_tasks)
self.menu.addSeparator()
add_tasks(["Pause"])
if self.active_task == "Nothing":
add_tasks(["Nothing"])
self.menu.addSeparator() self.menu.addSeparator()
new_action = self.menu.addAction("New task") new_action = self.menu.addAction("Import Jira task")
new_action.triggered.connect(self.new_task_slot) new_action.triggered.connect(self.new_task_slot)
edit_action = self.menu.addAction("Edit tasks") edit_action = self.menu.addAction("Edit tasks")

View File

@ -15,7 +15,7 @@ class NewTask(QtWidgets.QDialog):
ok_button = QtWidgets.QPushButton() ok_button = QtWidgets.QPushButton()
ok_button.setText("OK") ok_button.setText("OK")
ok_button.setIcon(QtGui.QIcon.fromTheme("dialog-ok-apply")) ok_button.setIcon(QtGui.QIcon.fromTheme("dialog-ok"))
ok_button.pressed.connect(self.accept) ok_button.pressed.connect(self.accept)
ok_button.setAutoDefault(True) ok_button.setAutoDefault(True)

View File

@ -2,10 +2,25 @@ from PySide2 import QtCore, QtGui, QtWidgets
from datetime import datetime from datetime import datetime
from data import Tasks
class Report(QtWidgets.QDialog): class Report(QtWidgets.QDialog):
def __init__(self, parent, *args, **kwargs): class TaskItemCompleter(QtWidgets.QStyledItemDelegate):
def __init__(self, tasks: Tasks, parent=None):
super().__init__(parent)
self._tasks = tasks
def createEditor(self, parent, *_):
editor = QtWidgets.QLineEdit(parent)
completer = QtWidgets.QCompleter(self._tasks.all_tasks, parent)
completer.setCaseSensitivity(QtCore.Qt.CaseInsensitive)
editor.setCompleter(completer)
return editor
def __init__(self, tasks: Tasks, parent, *args, **kwargs):
super().__init__(parent, *args, **kwargs) super().__init__(parent, *args, **kwargs)
self._tasks = tasks
self._report = None self._report = None
self._report_data = None self._report_data = None
self._changing_items = False self._changing_items = False
@ -20,6 +35,7 @@ class Report(QtWidgets.QDialog):
self.tableWidget.setColumnCount(3) self.tableWidget.setColumnCount(3)
self.tableWidget.setHorizontalHeaderLabels(["Task", "Start time", "Duration"]) self.tableWidget.setHorizontalHeaderLabels(["Task", "Start time", "Duration"])
self.tableWidget.cellChanged.connect(self.cell_changed) self.tableWidget.cellChanged.connect(self.cell_changed)
self.tableWidget.setItemDelegateForColumn(0, Report.TaskItemCompleter(self._tasks, self))
self.header = QtWidgets.QHeaderView(QtCore.Qt.Orientation.Horizontal) self.header = QtWidgets.QHeaderView(QtCore.Qt.Orientation.Horizontal)
self.tableWidget.setHorizontalHeader(self.header) self.tableWidget.setHorizontalHeader(self.header)
@ -49,7 +65,7 @@ class Report(QtWidgets.QDialog):
ok_button = QtWidgets.QPushButton() ok_button = QtWidgets.QPushButton()
ok_button.setText("OK") ok_button.setText("OK")
ok_button.setIcon(QtGui.QIcon.fromTheme("dialog-ok-apply")) ok_button.setIcon(QtGui.QIcon.fromTheme("dialog-ok"))
ok_button.pressed.connect(self._accept) ok_button.pressed.connect(self._accept)
ok_button.setAutoDefault(True) ok_button.setAutoDefault(True)

View File

@ -26,7 +26,7 @@ class TaskEdit(QtWidgets.QDialog):
ok_button = QtWidgets.QPushButton() ok_button = QtWidgets.QPushButton()
ok_button.setText("OK") ok_button.setText("OK")
ok_button.setIcon(QtGui.QIcon.fromTheme("dialog-ok-apply")) ok_button.setIcon(QtGui.QIcon.fromTheme("dialog-ok"))
ok_button.pressed.connect(self.accept) ok_button.pressed.connect(self.accept)
ok_button.setAutoDefault(True) ok_button.setAutoDefault(True)