Worklog proof of concept
This commit is contained in:
parent
b54cd0d1df
commit
ce46c8daca
10
LICENSE
10
LICENSE
@ -18,5 +18,11 @@ OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Included icons are taken from KDE breeze-icons (https://invent.kde.org/frameworks/breeze-icons),
|
||||
which are licensed under LGPL 3.
|
||||
Included icons (src/fime/icons) are taken from KDE breeze-icons (https://invent.kde.org/frameworks/breeze-icons),
|
||||
which are licensed under LGPL 3.
|
||||
|
||||
Progress indicator (src/fime/progressindicator.py):
|
||||
Author: Jared P. Sutton <jpsutton@gmail.com>
|
||||
License: LGPL
|
||||
Note: I've licensed this code as LGPL because it was a complete translation of the code found here...
|
||||
https://github.com/mojocorp/QProgressIndicator
|
||||
|
123
src/fime/progressindicator.py
Normal file
123
src/fime/progressindicator.py
Normal file
@ -0,0 +1,123 @@
|
||||
"""
|
||||
|
||||
"""
|
||||
|
||||
try:
|
||||
from PySide6 import QtCore, QtGui, QtWidgets
|
||||
except ImportError:
|
||||
from PySide2 import QtCore, QtGui, QtWidgets
|
||||
|
||||
|
||||
class QProgressIndicator(QtWidgets.QWidget):
|
||||
m_angle = None
|
||||
m_timerId = None
|
||||
m_delay = None
|
||||
m_displayedWhenStopped = None
|
||||
m_color = None
|
||||
|
||||
def __init__(self, parent):
|
||||
# Call parent class constructor first
|
||||
super().__init__(parent)
|
||||
|
||||
# Initialize Qt Properties
|
||||
self.setProperties()
|
||||
|
||||
# Intialize instance variables
|
||||
self.m_angle = 0
|
||||
self.m_timerId = -1
|
||||
self.m_delay = 40
|
||||
self.m_displayedWhenStopped = False
|
||||
self.m_color = QtCore.Qt.black
|
||||
|
||||
# Set size and focus policy
|
||||
self.setSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
|
||||
self.setFocusPolicy(QtCore.Qt.NoFocus)
|
||||
|
||||
# Show the widget
|
||||
self.show()
|
||||
|
||||
def animationDelay(self):
|
||||
return self.delay
|
||||
|
||||
def isAnimated(self):
|
||||
return (self.m_timerId != -1)
|
||||
|
||||
def isDisplayedWhenStopped(self):
|
||||
return self.displayedWhenStopped
|
||||
|
||||
def getColor(self):
|
||||
return self.color
|
||||
|
||||
def sizeHint(self):
|
||||
return QtCore.QSize(20, 20)
|
||||
|
||||
def startAnimation(self):
|
||||
self.m_angle = 0
|
||||
|
||||
if self.m_timerId == -1:
|
||||
self.m_timerId = self.startTimer(self.m_delay)
|
||||
|
||||
def stopAnimation(self):
|
||||
if self.m_timerId != -1:
|
||||
self.killTimer(self.m_timerId)
|
||||
|
||||
self.m_timerId = -1
|
||||
self.update()
|
||||
|
||||
def setAnimationDelay(self, delay):
|
||||
if self.m_timerId != -1:
|
||||
self.killTimer(self.m_timerId)
|
||||
|
||||
self.m_delay = delay
|
||||
|
||||
if self.m_timerId != -1:
|
||||
self.m_timerId = self.startTimer(self.m_delay)
|
||||
|
||||
def setDisplayedWhenStopped(self, state):
|
||||
self.displayedWhenStopped = state
|
||||
self.update()
|
||||
|
||||
def setColor(self, color):
|
||||
self.m_color = color
|
||||
self.update()
|
||||
|
||||
def timerEvent(self, event):
|
||||
self.m_angle = (self.m_angle + 30) % 360
|
||||
self.update()
|
||||
|
||||
def paintEvent(self, event):
|
||||
if (not self.m_displayedWhenStopped) and (not self.isAnimated()):
|
||||
return
|
||||
|
||||
width = min(self.width(), self.height())
|
||||
|
||||
painter = QtGui.QPainter(self)
|
||||
painter.setRenderHint(QtGui.QPainter.Antialiasing)
|
||||
|
||||
outerRadius = (width - 1) * 0.5
|
||||
innerRadius = (width - 1) * 0.5 * 0.38
|
||||
|
||||
capsuleHeight = outerRadius - innerRadius
|
||||
capsuleWidth = capsuleHeight * .23 if (width > 32) else capsuleHeight * .35
|
||||
capsuleRadius = capsuleWidth / 2
|
||||
|
||||
color = QtGui.QColor(self.m_color)
|
||||
for i in range(0, 12):
|
||||
if self.isAnimated():
|
||||
color.setAlphaF(1.0 - (i / 12.0))
|
||||
else:
|
||||
color.setAlphaF(0.2)
|
||||
|
||||
painter.setPen(QtCore.Qt.NoPen)
|
||||
painter.setBrush(color)
|
||||
painter.save()
|
||||
painter.translate(self.rect().center())
|
||||
painter.rotate(self.m_angle - (i * 30.0))
|
||||
painter.drawRoundedRect(capsuleWidth * -0.5, (innerRadius + capsuleHeight) * -1, capsuleWidth,
|
||||
capsuleHeight, capsuleRadius, capsuleRadius)
|
||||
painter.restore()
|
||||
|
||||
def setProperties(self):
|
||||
self.delay = QtCore.Property(int, self.animationDelay, self.setAnimationDelay)
|
||||
self.displayedWhenStopped = QtCore.Property(bool, self.isDisplayedWhenStopped, self.setDisplayedWhenStopped)
|
||||
self.color = QtCore.Property(QtGui.QColor, self.getColor, self.setColor)
|
@ -11,6 +11,13 @@ 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()
|
||||
else:
|
||||
print("unable to detect screen width falling back to default value of 1920")
|
||||
return 1920
|
||||
|
||||
|
||||
def get_icon(icon_name):
|
||||
theme_name = icon_name.replace("-light", "") # respect system theme
|
||||
|
94
src/fime/worklog.py
Normal file
94
src/fime/worklog.py
Normal file
@ -0,0 +1,94 @@
|
||||
from PySide2.QtCore import Qt, QUrl
|
||||
from PySide2.QtGui import QIcon
|
||||
from PySide2.QtQuickWidgets import QQuickWidget
|
||||
from PySide2.QtWidgets import QLabel
|
||||
|
||||
from fime.ok_icon import OkIcon
|
||||
from fime.progressindicator import QProgressIndicator
|
||||
from fime.spinner import Spinner
|
||||
|
||||
try:
|
||||
from PySide6 import QtCore, QtGui, QtWidgets
|
||||
except ImportError:
|
||||
from PySide2 import QtCore, QtGui, QtWidgets
|
||||
|
||||
from fime.util import get_screen_height, get_screen_width
|
||||
# noinspection PyUnresolvedReferences
|
||||
import fime.icons
|
||||
|
||||
|
||||
class Worklog(QtWidgets.QDialog):
|
||||
def __init__(self, parent, *args, **kwargs):
|
||||
super().__init__(parent, *args, **kwargs)
|
||||
|
||||
self.setWindowTitle("Worklog")
|
||||
|
||||
self.tableWidget = QtWidgets.QTableWidget()
|
||||
self.tableWidget.verticalHeader().hide()
|
||||
self.tableWidget.setColumnCount(3)
|
||||
self.tableWidget.setHorizontalHeaderLabels(["Task", "Comment", "Duration"])
|
||||
self.header = QtWidgets.QHeaderView(QtCore.Qt.Orientation.Horizontal)
|
||||
self.header.setMinimumSectionSize(1)
|
||||
self.header.setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)
|
||||
self.tableWidget.setHorizontalHeader(self.header)
|
||||
self.header.setSectionResizeMode(self.header.logicalIndex(1), QtWidgets.QHeaderView.Stretch)
|
||||
|
||||
layout = QtWidgets.QVBoxLayout(self)
|
||||
layout.addWidget(self.tableWidget)
|
||||
self.setLayout(layout)
|
||||
self.refresh_table()
|
||||
|
||||
def refresh_table(self):
|
||||
self._report_data = [
|
||||
["ASG-8690 Ansible - Debian 11 Support", "", "01:23"],
|
||||
["ASG-8342 Ansible - MariaDB Rolle überarbeiten ", "", "03:57"],
|
||||
["ASG-8685 CATS Testsystem: Debian Upgrades Server mit Version kleiner 10 ", "", "02:12"],
|
||||
]
|
||||
self.tableWidget.setRowCount(len(self._report_data))
|
||||
|
||||
for row, _ in enumerate(self._report_data):
|
||||
item0 = QtWidgets.QTableWidgetItem(self._report_data[row][0])
|
||||
item0.setToolTip("something has gone wrong")
|
||||
self.tableWidget.setItem(row, 0, item0)
|
||||
size = self.tableWidget.rowHeight(row)
|
||||
if row == 1:
|
||||
qpi = QProgressIndicator(self)
|
||||
qpi.setMaximumSize(QtCore.QSize(size * 0.75, size * 0.75))
|
||||
qpi.setAnimationDelay(70)
|
||||
qpi.startAnimation()
|
||||
layout = QtWidgets.QVBoxLayout()
|
||||
layout.addWidget(qpi, alignment=Qt.AlignRight | Qt.AlignVCenter)
|
||||
layout.setContentsMargins(size * 0.1, size * 0.1, size * 0.1, size * 0.1)
|
||||
wdgt = QtWidgets.QWidget()
|
||||
wdgt.setLayout(layout)
|
||||
#label.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
|
||||
#label.setMargin(size * 0.1)
|
||||
label = wdgt
|
||||
else:
|
||||
label = QLabel()
|
||||
if row == 0:
|
||||
item_name = "dialog-ok"
|
||||
elif row == 2:
|
||||
item_name = "edit-delete-remove"
|
||||
label.setPixmap(QIcon.fromTheme(item_name).pixmap(size * 0.75, size * 0.75))
|
||||
label.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
|
||||
label.setMargin(size*0.1)
|
||||
self.tableWidget.setCellWidget(row, 0, label)
|
||||
item1 = QtWidgets.QTableWidgetItem(self._report_data[row][1])
|
||||
self.tableWidget.setItem(row, 1, item1)
|
||||
item2 = QtWidgets.QTableWidgetItem(self._report_data[row][2])
|
||||
self.tableWidget.setItem(row, 2, item2)
|
||||
#item2.setFlags(item2.flags() & QtCore.Qt.ItemIsEnabled)
|
||||
self.tableWidget.resizeColumnToContents(0)
|
||||
# TODO integrate entered text and max screen width
|
||||
comment_width = get_screen_width(self) * 0.2
|
||||
self.tableWidget.setMinimumWidth(self.tableWidget.columnWidth(0) + comment_width + self.tableWidget.columnWidth(2))
|
||||
self.tableWidget.setColumnWidth(0, self.tableWidget.columnWidth(0) * 1.05)
|
||||
|
||||
@QtCore.Slot()
|
||||
def disable_buttons(self):
|
||||
pass
|
||||
|
||||
@QtCore.Slot()
|
||||
def enable_buttons(self):
|
||||
pass
|
56
src/fime/worklog_.py
Normal file
56
src/fime/worklog_.py
Normal 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)
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user