Compare commits

..

No commits in common. "32621bcc87ea665e1ab9972f1f7aa901c3770b32" and "169d9749af2cd48d6bb4454d196265e041d1b9fc" have entirely different histories.

5 changed files with 91 additions and 144 deletions

View File

@ -12,6 +12,8 @@ except ImportError:
from PySide2 import QtCore, QtWidgets
PYSIDE_6 = False
# noinspection PyUnresolvedReferences
import fime.icons
from fime.data import Tasks, Log, Data, LogCommentsData
from fime.exceptions import FimeException
from fime.import_task import ImportTask

View File

@ -1,13 +1,8 @@
import enum
try:
from PySide6 import QtCore, QtGui, QtWidgets
except ImportError:
from PySide2 import QtCore, QtGui, QtWidgets
# noinspection PyUnresolvedReferences
import fime.icons
def get_screen_height(qobject):
if hasattr(qobject, "screen"):
@ -16,7 +11,6 @@ def get_screen_height(qobject):
print("unable to detect screen height falling back to default value of 1080")
return 1080
def get_screen_width(qobject):
if hasattr(qobject, "screen"):
return qobject.screen().size().width()
@ -43,9 +37,3 @@ class EditStartedDetector(QtWidgets.QStyledItemDelegate):
editor.editingFinished.connect(self.editFinished)
self.editStarted.emit()
return editor
class Status(enum.Enum):
PROGRESS = enum.auto()
OK = enum.auto()
ERROR = enum.auto()

View File

@ -1,11 +1,12 @@
import enum
from datetime import datetime
from functools import reduce, partial
from typing import Optional, List, Tuple
from fime.data import Worklog
from fime.progressindicator import ProgressIndicator
from fime.task_completer import TaskCompleter
from fime.util import get_icon, EditStartedDetector, Status
from fime.worklog_rest import WorklogRest
from fime.util import get_icon, get_screen_height, EditStartedDetector
try:
from PySide6 import QtCore, QtGui, QtWidgets
@ -13,6 +14,8 @@ except ImportError:
from PySide2 import QtCore, QtGui, QtWidgets
from fime.util import get_screen_width
# noinspection PyUnresolvedReferences
import fime.icons
class WorklogDialog(QtWidgets.QDialog):
@ -80,7 +83,6 @@ class WorklogDialog(QtWidgets.QDialog):
completer.setFilterMode(QtCore.Qt.MatchFlag.MatchContains)
completer.setCaseSensitivity(QtCore.Qt.CaseInsensitive)
editor.setCompleter(completer)
editor.textChanged.connect(completer.update_picker)
return editor
@QtCore.Slot()
@ -92,20 +94,23 @@ class WorklogDialog(QtWidgets.QDialog):
if not self.return_:
self.edit_finished_row.emit(row)
class Status(enum.Enum):
PROGRESS = enum.auto()
OK = enum.auto()
ERROR = enum.auto()
def __init__(self, config, parent, *args, **kwargs):
super().__init__(parent, *args, **kwargs)
self.rest = WorklogRest(config)
self.setWindowTitle("Worklog")
self._changing_items = False
self._worklog: Optional[Worklog] = None
self._worklog_data: List[List[str]] = []
self._statuses: List[Tuple[Status, str]] = []
self._status: List[Tuple[WorklogDialog.Status, str]] = []
self.row_height = None
self._focussed = False
self.setWindowTitle("Worklog")
self.tableWidget = WorklogDialog.TabTable(self)
self.tableWidget.setColumnCount(3)
self.tableWidget.setHorizontalHeaderLabels(["Task", "Comment", "Duration"])
@ -166,36 +171,18 @@ class WorklogDialog(QtWidgets.QDialog):
layout.addLayout(alayout)
self.setLayout(layout)
self.update_timer = QtCore.QTimer(self)
self.update_timer.setInterval(500)
self.update_timer.timeout.connect(self.update_statuses)
def set_data(self, worklog: Worklog):
self._worklog = worklog
self.update_all()
def update_all(self):
self.refresh_table()
self.update_title()
self.update_prev_next()
self.update_statuses()
self.update_timer.start()
def update_statuses(self):
issue_keys = []
for row in self._worklog_data[:-1]:
issue_keys.append(row[0].split()[0])
old_statuses = self._statuses
self._statuses = self.rest.get_issues_state(issue_keys)
for row, status in enumerate(self._statuses):
if len(old_statuses) != len(self._statuses) or old_statuses[row][0] != status[0]:
def update_status(self, row, new_status, status_text="Could not find specified issue"):
self._status[row] = (new_status, status_text)
self.update_status_view(row)
all_ok = reduce(lambda acc, it: acc and it[0] is Status.OK, self._statuses, True)
all_ok = reduce(lambda acc, it: acc and it[0] is WorklogDialog.Status.OK, self._status, True)
if all_ok:
self.upload_button.setEnabled(True)
all_done = reduce(lambda acc, it: acc and it[0] is not Status.PROGRESS, self._statuses, True)
if all_done:
self.update_timer.stop()
def save(self):
self._worklog.worklog = self._worklog_data
@ -205,6 +192,8 @@ class WorklogDialog(QtWidgets.QDialog):
def refresh_table(self):
self._worklog_data = self._worklog.worklog
for i, _ in enumerate(self._worklog_data[:-1]):
self._status.append((WorklogDialog.Status.PROGRESS, "Fetching"))
self._changing_items = True
if not self.row_height:
self.tableWidget.setRowCount(1)
@ -223,6 +212,7 @@ class WorklogDialog(QtWidgets.QDialog):
self.tableWidget.setItem(row, 1, item1)
item1.setFlags(item1.flags() & QtCore.Qt.ItemIsEnabled)
else:
self.update_status_view(row)
text_edit = WorklogDialog.TableTextEdit(self._worklog_data[row][1], row, self)
text_edit.textChanged.connect(self.on_resize)
text_edit.setFrameStyle(QtWidgets.QFrame.NoFrame)
@ -249,19 +239,19 @@ class WorklogDialog(QtWidgets.QDialog):
self.move(x, y)
def update_status_view(self, row):
if self._statuses[row][0] is Status.PROGRESS:
if self._status[row][0] is WorklogDialog.Status.PROGRESS:
icon = ProgressIndicator(self)
icon.setMaximumSize(QtCore.QSize(self.row_height * 0.75, self.row_height * 0.75))
icon.setAnimationDelay(70)
icon.startAnimation()
else:
if self._statuses[row][0] is Status.OK:
if self._status[row][0] is WorklogDialog.Status.OK:
item_name = "dialog-ok"
elif self._statuses[row][0] is Status.ERROR:
elif self._status[row][0] is WorklogDialog.Status.ERROR:
item_name = "edit-delete-remove"
icon = QtWidgets.QLabel()
icon.setPixmap(get_icon(item_name).pixmap(self.row_height * 0.75, self.row_height * 0.75))
icon.setToolTip(self._statuses[row][1])
icon.setToolTip(self._status[row][1])
layout = QtWidgets.QHBoxLayout()
layout.addWidget(icon, alignment=QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
layout.setContentsMargins(self.row_height * 0.1, self.row_height * 0.1,
@ -296,15 +286,21 @@ class WorklogDialog(QtWidgets.QDialog):
def previous(self):
self.save()
self._worklog.previous()
self.update_title()
self._focussed = False
self.update_all()
self.refresh_table()
self.center_dialog()
self.update_prev_next()
@QtCore.Slot()
def next(self):
self.save()
self._worklog.next()
self.update_title()
self._focussed = False
self.update_all()
self.refresh_table()
self.center_dialog()
self.update_prev_next()
@QtCore.Slot()
def cell_changed(self, row, _):
@ -312,7 +308,8 @@ class WorklogDialog(QtWidgets.QDialog):
return
self._worklog_data[row][0] = self.tableWidget.item(row, 0).text()
self.save()
self.update_all()
self.update_status(row, WorklogDialog.Status.PROGRESS, "Fetching")
self.refresh_table()
@QtCore.Slot()
def text_edit_changed(self, text, row):

56
src/fime/worklog_.py Normal file
View File

@ -0,0 +1,56 @@
import os
from datetime import date, datetime
import requests
from fime.config import Config
class Worklog:
def __init__(self, config: Config):
self.config = config
self.user_url = os.path.join(config.jira_url, "rest/api/2/myself")
self.issue_url = os.path.join(config.jira_url, "rest/api/2/issue/{}")
self.worklog_url = os.path.join(config.jira_url, "rest/api/2/issue/{}/worklog")
self.worklog_update_url = os.path.join(config.jira_url, "rest/api/2/issue/{issue}/worklog/{worklog}")
self.user = self.get_user()
def get_user(self):
resp = requests.get(self.user_url,
headers={
"Authorization": f"Bearer {self.config.jira_token}",
"Accept": "application/json",
},
)
user = resp.json()["key"]
print(user)
return user
def get(self, issue_key: str, date: date):
resp = requests.get(self.issue_url.format(issue_key),
headers={
"Authorization": f"Bearer {self.config.jira_token}",
"Accept": "application/json",
},
)
if resp.status_code != 200:
raise RuntimeError("issue does not exist")
resp = requests.get(self.worklog_url.format(issue_key),
headers={
"Authorization": f"Bearer {self.config.jira_token}",
"Accept": "application/json",
},
)
worklogs = resp.json()["worklogs"]
found = False
for log in worklogs:
if log["author"]["key"] == self.user \
and datetime.strptime(log["started"], "%Y-%m-%dT%H:%M:%S.%f%z").date() == date:
print(log["id"])
print(log["comment"])
found = True
break
print(found)

View File

@ -1,96 +0,0 @@
import os
import traceback
from concurrent.futures import Future
from datetime import date, datetime
from functools import partial
from threading import Lock
from typing import List, Dict, Tuple
import requests
from requests_futures.sessions import FuturesSession
from fime.config import Config
from fime.exceptions import FimeException
from fime.util import Status
class WorklogRest:
def __init__(self, config: Config):
self.config = config
self.user_url = os.path.join(config.jira_url, "rest/api/2/myself")
self.issue_url = os.path.join(config.jira_url, "rest/api/2/issue/{}")
self.worklog_url = os.path.join(config.jira_url, "rest/api/2/issue/{}/worklog")
self.worklog_update_url = os.path.join(config.jira_url, "rest/api/2/issue/{issue}/worklog/{worklog}")
self.session = FuturesSession()
self.user = self._req_user()
self._issue_state: Dict[str, Tuple[Status, str]] = {}
self._issue_state_lock = Lock()
def _req_user(self):
return self.session.get(
self.user_url,
headers={
"Authorization": f"Bearer {self.config.jira_token}",
"Accept": "application/json",
},
)
def _get_user(self):
try:
return self.user.result().json()["key"]
except Exception:
raise FimeException("Could not get user key:\n" + traceback.format_exc())
def get_issues_state(self, issue_keys: List[str]):
ret = []
with self._issue_state_lock:
for issue_key in issue_keys:
if issue_key not in self._issue_state:
self._issue_state[issue_key] = (Status.PROGRESS, "Fetching")
self._req_issue(issue_key)
ret.append(self._issue_state[issue_key])
return ret
def _req_issue(self, issue_key: str):
future = self.session.get(self.issue_url.format(issue_key),
headers={
"Authorization": f"Bearer {self.config.jira_token}",
"Accept": "application/json",
},
)
future.add_done_callback(partial(self._resp_issue, issue_key))
def _resp_issue(self, issue_key: str, future: Future):
resp: requests.Response = future.result()
with self._issue_state_lock:
if resp.status_code == 200:
hint = f'{issue_key} {resp.json()["fields"]["summary"]}'
self._issue_state[issue_key] = (Status.OK, hint)
else:
self._issue_state[issue_key] = (Status.ERROR, "Could not find specified issue")
def get(self, issue_key: str, date: date):
resp = requests.get(self.issue_url.format(issue_key),
headers={
"Authorization": f"Bearer {self.config.jira_token}",
"Accept": "application/json",
},
)
if resp.status_code != 200:
raise RuntimeError("issue does not exist")
resp = requests.get(self.worklog_url.format(issue_key),
headers={
"Authorization": f"Bearer {self.config.jira_token}",
"Accept": "application/json",
},
)
worklogs = resp.json()["worklogs"]
found = False
for log in worklogs:
if log["author"]["key"] == self.user \
and datetime.strptime(log["started"], "%Y-%m-%dT%H:%M:%S.%f%z").date() == date:
print(log["id"])
print(log["comment"])
found = True
break
print(found)