Compare commits
No commits in common. "8d7f36b51106e0e8c6b85b1ed574f44ab1831d39" and "5584eb4d6bf0438952a606543f31db96456249b7" have entirely different histories.
8d7f36b511
...
5584eb4d6b
1
Pipfile
1
Pipfile
@ -8,7 +8,6 @@ pyside6 = "~=6.3"
|
||||
requests = "~=2.28"
|
||||
requests-futures = "~=1.0"
|
||||
packaging = "~=21.3"
|
||||
loguru = "~=0.6"
|
||||
|
||||
[dev-packages]
|
||||
pyinstaller = "~=5.1"
|
||||
|
10
Pipfile.lock
generated
10
Pipfile.lock
generated
@ -1,7 +1,7 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "b04dfa0eda7fd2df5b6d27d5a1f7d71168c984c74ce363c45a888430bca7b7d8"
|
||||
"sha256": "633aca7e0b43a295ce3429d3e12976a4c16dcf422cee53e37d266f8000ef5feb"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
@ -40,14 +40,6 @@
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==3.4"
|
||||
},
|
||||
"loguru": {
|
||||
"hashes": [
|
||||
"sha256:066bd06758d0a513e9836fd9c6b5a75bfb3fd36841f4b996bc60b547a309d41c",
|
||||
"sha256:4e2414d534a2ab57573365b3e6d0234dfb1d84b68b7f3b948e6fb743860a77c3"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.6.0"
|
||||
},
|
||||
"packaging": {
|
||||
"hashes": [
|
||||
"sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb",
|
||||
|
@ -1,8 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
last_patch=$(git tag | sort -V | tail -n1 | cut -d "." -f3)
|
||||
git tag "1.0.$((last_patch + 1))"
|
||||
git push gitlab main -o ci.skip
|
||||
git push gitlab --tags
|
||||
git push origin main
|
||||
git push origin --tags
|
@ -22,7 +22,6 @@ install_requires =
|
||||
requests
|
||||
requests-futures
|
||||
packaging
|
||||
loguru
|
||||
|
||||
[options.packages.find]
|
||||
where = src
|
||||
|
@ -1,5 +1,5 @@
|
||||
try:
|
||||
from fime._version import __version__, __version_tuple__
|
||||
except ImportError:
|
||||
__version__ = version = '0+devfallback'
|
||||
__version_tuple__ = version_tuple = (0, 'devfallback')
|
||||
__version__ = version = '1.0.0.dev0'
|
||||
__version_tuple__ = version_tuple = (1, 0, 0, 'dev0')
|
||||
|
@ -1,22 +1,22 @@
|
||||
import sys
|
||||
import traceback
|
||||
from copy import copy
|
||||
from pathlib import Path
|
||||
from textwrap import dedent
|
||||
from threading import Lock
|
||||
from typing import Optional
|
||||
|
||||
from loguru import logger
|
||||
from packaging.version import Version
|
||||
from requests_futures.sessions import FuturesSession
|
||||
|
||||
from fime.progressindicator import ProgressIndicator
|
||||
from fime.util import get_icon
|
||||
|
||||
try:
|
||||
from PySide6 import QtCore, QtGui, QtWidgets
|
||||
except ImportError:
|
||||
from PySide2 import QtCore, QtGui, QtWidgets
|
||||
|
||||
import fime
|
||||
from fime.progressindicator import ProgressIndicator
|
||||
from fime.util import get_icon
|
||||
|
||||
URL = "https://gitlab.com/faerbit/fime/-/releases/permalink/latest"
|
||||
|
||||
@ -51,7 +51,8 @@ class UpdateChecker:
|
||||
else:
|
||||
self.result = f"Newer fime version available: {latest_version}"
|
||||
except Exception:
|
||||
logger.exception("Could not get update info")
|
||||
print("Could not get update info:\n", file=sys.stderr)
|
||||
print(traceback.format_exc(), file=sys.stderr)
|
||||
finally:
|
||||
with self.lock:
|
||||
self._done = True
|
||||
@ -62,18 +63,14 @@ class About(QtWidgets.QDialog):
|
||||
super().__init__(parent, *args, **kwargs)
|
||||
self.setWindowTitle("About")
|
||||
|
||||
log_dir_path = Path(QtCore.QStandardPaths.writableLocation(QtCore.QStandardPaths.AppDataLocation)) / "logs"
|
||||
|
||||
text = dedent(f"""\
|
||||
fime
|
||||
Copyright (c) 2020 - 2022 Faerbit
|
||||
<a href="https://fime.faerb.it">Website</a> <a href="https://gitlab.com/faerbit/fime/-/blob/main/LICENSE">License</a>
|
||||
<a href="https://gitlab.com/faerbit/fime/-/blob/main/LICENSE">License</a>
|
||||
|
||||
fime Version {fime.__version__}
|
||||
Qt Version {QtCore.__version__}
|
||||
Python Version {sys.version}
|
||||
|
||||
Log directory: <a href="{log_dir_path}">{log_dir_path}</a>
|
||||
""")
|
||||
text = text.replace("\n", "<br/>")
|
||||
version_label = QtWidgets.QLabel(self)
|
||||
|
@ -1,9 +1,6 @@
|
||||
from configparser import ConfigParser
|
||||
from io import StringIO
|
||||
from pathlib import Path
|
||||
|
||||
from loguru import logger
|
||||
|
||||
try:
|
||||
from PySide6 import QtCore
|
||||
except ImportError:
|
||||
@ -23,63 +20,32 @@ class Config:
|
||||
def __init__(self):
|
||||
self._configparser = ConfigParser()
|
||||
config_dir_path = Path(QtCore.QStandardPaths.writableLocation(QtCore.QStandardPaths.AppConfigLocation))
|
||||
self.config_path = config_dir_path / "fime.conf"
|
||||
if self.config_path.exists():
|
||||
logger.info(f'reading config file "{self.config_path}"')
|
||||
with self.config_path.open(encoding="utf-8") as f:
|
||||
config_path = config_dir_path / "fime.conf"
|
||||
if config_path.exists():
|
||||
print(f'Reading config file "{config_path}"')
|
||||
with open(config_path) as f:
|
||||
config_text = f.read()
|
||||
config_text = "[DEFAULT]\n" + config_text
|
||||
self._configparser.read_string(config_text)
|
||||
# TODO change menu items
|
||||
if (not self._configparser.has_option("DEFAULT", "jira_url") or
|
||||
not self._configparser.has_option("DEFAULT", "jira_token")):
|
||||
raise FimeException(f'Please add config file {self.config_path} '
|
||||
raise FimeException(f'Please add config file {config_path} '
|
||||
f'with config keys "jira_url" and "jira_token" in INI style')
|
||||
|
||||
def save(self):
|
||||
logger.info(f'writing config file "{self.config_path}"')
|
||||
config_str = StringIO()
|
||||
self._configparser.write(config_str)
|
||||
# do not conform to configparser's stupid section requirement
|
||||
config_str = "\n".join(config_str.getvalue().splitlines()[1:])
|
||||
with self.config_path.open("w", encoding="utf-8") as f:
|
||||
f.write(config_str)
|
||||
|
||||
@property
|
||||
def jira_url(self):
|
||||
return dequotify(self._configparser["DEFAULT"]["jira_url"])
|
||||
|
||||
@jira_url.setter
|
||||
def jira_url(self, value):
|
||||
self._configparser["DEFAULT"]["jira_url"] = f'"{value}"'
|
||||
|
||||
@property
|
||||
def jira_token(self):
|
||||
return dequotify(self._configparser["DEFAULT"]["jira_token"])
|
||||
|
||||
@jira_token.setter
|
||||
def jira_token(self, value):
|
||||
self._configparser["DEFAULT"]["jira_token"] = f'"{value}"'
|
||||
|
||||
@property
|
||||
def tray_theme(self):
|
||||
val = dequotify(self._configparser.get("DEFAULT", "tray_theme", fallback="dark")).lower()
|
||||
return val if val in ["light", "dark"] else "dark"
|
||||
|
||||
@tray_theme.setter
|
||||
def tray_theme(self, value):
|
||||
value = value.lower()
|
||||
if value not in ["light", "dark"]:
|
||||
raise RuntimeError('config key "tray_theme" can only be set to "light" or "dark"')
|
||||
self._configparser["DEFAULT"]["tray_theme"] = f'"{value}"'
|
||||
|
||||
@property
|
||||
def flip_menu(self):
|
||||
val = dequotify(self._configparser.get("DEFAULT", "flip_menu", fallback="no")).lower()
|
||||
return val in ["yes", "true", "1"]
|
||||
|
||||
@flip_menu.setter
|
||||
def flip_menu(self, value):
|
||||
if type(value) is not bool:
|
||||
raise RuntimeError('config key "flip_menu" must be a bool')
|
||||
self._configparser["DEFAULT"]["flip_menu"] = f'"{value}"'
|
||||
|
@ -8,8 +8,6 @@ from datetime import datetime, date, timedelta, time
|
||||
from threading import Thread, Event
|
||||
from typing import List, Tuple, Dict, Union
|
||||
|
||||
from loguru import logger
|
||||
|
||||
try:
|
||||
from PySide6 import QtCore
|
||||
except ImportError:
|
||||
@ -65,7 +63,7 @@ class Data(MutableMapping):
|
||||
|
||||
def _save(self):
|
||||
for key in self._hot_keys:
|
||||
logger.info(f"saving dict {key}")
|
||||
print(f"... saving dict {key} ...")
|
||||
to_write = self._cache[key] # apparently thread-safe
|
||||
with open(self.data_path.format(key), "w+") as f:
|
||||
f.write(json.dumps(to_write))
|
||||
|
@ -14,19 +14,17 @@ class ImportTask(QtWidgets.QDialog):
|
||||
super().__init__(parent, *args, **kwargs)
|
||||
self.setWindowTitle("New Tasks")
|
||||
|
||||
self.config = config
|
||||
|
||||
self.line_edit = QtWidgets.QLineEdit(self)
|
||||
self.completer = TaskCompleter(config)
|
||||
self.line_edit.setCompleter(self.completer)
|
||||
self.line_edit.textChanged.connect(self.completer.update_picker)
|
||||
completer = TaskCompleter(config)
|
||||
self.line_edit.setCompleter(completer)
|
||||
self.line_edit.textChanged.connect(completer.update_picker)
|
||||
self.line_edit.setFocus()
|
||||
|
||||
self.indicator = ProgressIndicator(self)
|
||||
self.indicator.setAnimationDelay(70)
|
||||
self.indicator.setDisplayedWhenStopped(False)
|
||||
self.completer.running.connect(self.spin)
|
||||
self.completer.stopped.connect(self.no_spin)
|
||||
completer.running.connect(self.spin)
|
||||
completer.stopped.connect(self.no_spin)
|
||||
|
||||
ok_button = QtWidgets.QPushButton()
|
||||
ok_button.setText("OK")
|
||||
@ -79,8 +77,6 @@ class ImportTask(QtWidgets.QDialog):
|
||||
return self.line_edit.text()
|
||||
|
||||
def showEvent(self, _):
|
||||
# pick up config changes
|
||||
self.completer.update_urls()
|
||||
self.line_edit.setText("")
|
||||
self.raise_()
|
||||
self.activateWindow()
|
||||
|
@ -2,10 +2,10 @@
|
||||
import signal
|
||||
import sys
|
||||
from functools import partial
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
from loguru import logger
|
||||
from fime.about import About
|
||||
from fime.config import Config
|
||||
from fime.worklog import WorklogDialog
|
||||
|
||||
try:
|
||||
from PySide6 import QtCore, QtWidgets
|
||||
@ -14,14 +14,10 @@ except ImportError:
|
||||
from PySide2 import QtCore, QtWidgets
|
||||
PYSIDE_6 = False
|
||||
|
||||
from fime.about import About
|
||||
from fime.config import Config
|
||||
from fime.worklog import WorklogDialog
|
||||
from fime.data import Tasks, Log, Data, LogCommentsData, Worklog, Report
|
||||
from fime.exceptions import FimeException
|
||||
from fime.import_task import ImportTask
|
||||
from fime.report import ReportDialog
|
||||
from fime.settings import Settings
|
||||
from fime.task_edit import TaskEdit
|
||||
from fime.util import get_screen_height, get_icon
|
||||
|
||||
@ -37,44 +33,37 @@ class App:
|
||||
self.log = Log(lcd)
|
||||
self._active_task = self.log.last_log() or "Nothing"
|
||||
|
||||
self.config = Config()
|
||||
config = Config()
|
||||
if config.tray_theme == "light":
|
||||
icon = get_icon("appointment-new-light")
|
||||
else:
|
||||
icon = get_icon("appointment-new")
|
||||
|
||||
self.menu_flipped = config.flip_menu
|
||||
|
||||
self.menu = QtWidgets.QMenu(None)
|
||||
|
||||
self.import_task = ImportTask(self.config, None)
|
||||
self.import_task = ImportTask(config, None)
|
||||
self.import_task.accepted.connect(self.new_task_imported)
|
||||
|
||||
self.taskEdit = TaskEdit(self.tasks, None)
|
||||
self.taskEdit = TaskEdit(None)
|
||||
self.taskEdit.accepted.connect(self.tasks_edited)
|
||||
|
||||
self.reportDialog = ReportDialog(self.tasks, Report(lcd), None)
|
||||
self.reportDialog.accepted.connect(self.log_edited)
|
||||
|
||||
self.worklogDialog = WorklogDialog(self.config, Worklog(lcd), None)
|
||||
self.worklogDialog = WorklogDialog(config, Worklog(lcd), None)
|
||||
self.worklogDialog.accepted.connect(self.log_edited)
|
||||
|
||||
self.settings = Settings(self.config, None)
|
||||
self.settings.accepted.connect(self.update_icon)
|
||||
self.settings.accepted.connect(self.update_tray_menu)
|
||||
|
||||
self.about = About(None)
|
||||
|
||||
self.tray = QtWidgets.QSystemTrayIcon()
|
||||
self.tray.setIcon(icon)
|
||||
self.tray.setContextMenu(self.menu)
|
||||
self.update_icon()
|
||||
self.tray.show()
|
||||
self.tray.setToolTip("fime")
|
||||
self.update_tray_menu()
|
||||
|
||||
self.last_dialog: Optional[QtWidgets.QDialog] = None
|
||||
|
||||
def update_icon(self):
|
||||
if self.config.tray_theme == "light":
|
||||
icon = get_icon("appointment-new-light")
|
||||
else:
|
||||
icon = get_icon("appointment-new")
|
||||
self.tray.setIcon(icon)
|
||||
|
||||
@QtCore.Slot()
|
||||
def new_task_imported(self):
|
||||
if self.import_task.task_text:
|
||||
@ -100,21 +89,11 @@ class App:
|
||||
self.tray.setToolTip(f"{task} - fime")
|
||||
self.update_tray_menu()
|
||||
|
||||
def close_open_dialog(self):
|
||||
if self.last_dialog and self.last_dialog.isVisible():
|
||||
self.last_dialog.reject()
|
||||
|
||||
def change_task(self, task):
|
||||
self.close_open_dialog()
|
||||
self.active_task = task
|
||||
self.log.log(task)
|
||||
self.tasks.update_jira_task_usage(task)
|
||||
|
||||
def open_new_dialog(self, new_dialog: QtWidgets.QDialog):
|
||||
self.close_open_dialog()
|
||||
self.last_dialog = new_dialog
|
||||
new_dialog.show()
|
||||
|
||||
def update_tray_menu(self):
|
||||
menu_items = []
|
||||
tmp_action = self.menu.addAction("tmp")
|
||||
@ -128,7 +107,7 @@ class App:
|
||||
add_tasks(self.tasks.tasks)
|
||||
|
||||
menu_items.append((1, None))
|
||||
already_taken = (len(self.tasks.tasks) + 6) * action_height
|
||||
already_taken = (len(self.tasks.tasks) + 5) * action_height
|
||||
available_space = get_screen_height(self.menu) * 0.8 - already_taken
|
||||
jira_entry_count = int(available_space // action_height)
|
||||
add_tasks(self.tasks.jira_tasks[-jira_entry_count:])
|
||||
@ -139,21 +118,17 @@ class App:
|
||||
add_tasks(["Nothing"])
|
||||
|
||||
menu_items.append((1, None))
|
||||
jira_integration = self.config.jira_url and self.config.jira_token
|
||||
if jira_integration:
|
||||
menu_items.append(("Import Jira task", partial(self.open_new_dialog, self.import_task)))
|
||||
menu_items.append(("Edit tasks", partial(self.open_new_dialog, self.taskEdit)))
|
||||
menu_items.append(("Report", partial(self.open_new_dialog, self.reportDialog)))
|
||||
if jira_integration:
|
||||
menu_items.append(("Worklog", partial(self.open_new_dialog, self.worklogDialog)))
|
||||
menu_items.append(("Import Jira task", self.import_task.show))
|
||||
menu_items.append(("Edit tasks", self.edit_tasks))
|
||||
menu_items.append(("Report", self.reportDialog.show))
|
||||
menu_items.append(("Worklog", self.worklogDialog.show))
|
||||
|
||||
menu_items.append((1, None))
|
||||
|
||||
menu_items.append(("Settings", partial(self.open_new_dialog, self.settings)))
|
||||
menu_items.append(("About", partial(self.open_new_dialog, self.about)))
|
||||
menu_items.append(("About", self.about.show))
|
||||
menu_items.append(("Close", self.app.quit))
|
||||
|
||||
if self.config.flip_menu:
|
||||
if self.menu_flipped:
|
||||
menu_items.reverse()
|
||||
|
||||
seps = 0
|
||||
@ -168,7 +143,7 @@ class App:
|
||||
action.triggered.connect(item[1])
|
||||
|
||||
def sigterm_handler(self, signo, _frame):
|
||||
logger.debug(f'handling signal "{signal.strsignal(signo)}"')
|
||||
print(f'handling signal "{signal.strsignal(signo)}"')
|
||||
self.app.quit()
|
||||
|
||||
def run(self):
|
||||
@ -183,28 +158,25 @@ class App:
|
||||
else:
|
||||
self.app.exec_()
|
||||
|
||||
|
||||
def init_logging():
|
||||
log_dir_path = Path(QtCore.QStandardPaths.writableLocation(QtCore.QStandardPaths.AppDataLocation)) / "logs"
|
||||
logger.add(log_dir_path / "fime_{time:YYYY-MM-DD}.log", rotation="1d", retention="30d", compression="zip", level="DEBUG")
|
||||
@QtCore.Slot()
|
||||
def edit_tasks(self):
|
||||
self.taskEdit.tasks = self.tasks.tasks
|
||||
self.taskEdit.show()
|
||||
|
||||
|
||||
def excepthook(e_type, e_value, tb_obj):
|
||||
def excepthook(original, e_type, e_value, tb_obj):
|
||||
if e_type is FimeException:
|
||||
QtWidgets.QMessageBox.critical(None, "Error", str(e_value), QtWidgets.QMessageBox.Ok)
|
||||
elif issubclass(e_type, KeyboardInterrupt):
|
||||
sys.__excepthook__(e_type, e_value, tb_obj)
|
||||
else:
|
||||
logger.critical("Unhandled exception", exc_info=(e_type, e_value, tb_obj))
|
||||
sys.__excepthook__(e_type, e_value, tb_obj)
|
||||
original(e_type, e_value, tb_obj)
|
||||
|
||||
|
||||
def main():
|
||||
# important for QStandardPath to be correct
|
||||
QtCore.QCoreApplication.setApplicationName("fime")
|
||||
init_logging()
|
||||
# also catches exceptions in other threads
|
||||
sys.excepthook = excepthook
|
||||
original_excepthook = sys.excepthook
|
||||
sys.excepthook = partial(excepthook, original_excepthook)
|
||||
app = App()
|
||||
app.run()
|
||||
|
||||
|
@ -1,93 +0,0 @@
|
||||
from fime.util import get_icon
|
||||
|
||||
try:
|
||||
from PySide6 import QtCore, QtGui, QtWidgets
|
||||
except ImportError:
|
||||
from PySide2 import QtCore, QtGui, QtWidgets
|
||||
|
||||
from fime.config import Config
|
||||
|
||||
|
||||
class Settings(QtWidgets.QDialog):
|
||||
def __init__(self, config: Config, parent, *args, **kwargs):
|
||||
super().__init__(parent, *args, **kwargs)
|
||||
self.setWindowTitle("Settings")
|
||||
|
||||
self.config = config
|
||||
|
||||
caption_label = QtWidgets.QLabel()
|
||||
caption_label.setText("Settings")
|
||||
caption_label.setAlignment(QtCore.Qt.AlignHCenter)
|
||||
|
||||
settings_layout = QtWidgets.QGridLayout()
|
||||
|
||||
jira_url_label = QtWidgets.QLabel()
|
||||
jira_url_label.setText("Jira URL")
|
||||
settings_layout.addWidget(jira_url_label, 0, 0)
|
||||
self.jira_url_edit = QtWidgets.QLineEdit()
|
||||
settings_layout.addWidget(self.jira_url_edit, 0, 1)
|
||||
|
||||
jira_token_label = QtWidgets.QLabel()
|
||||
jira_token_label.setText("Jira Personal Access Token<br/> see <a href='https://confluence.atlassian.com/enterprise/using-personal-access-tokens-1026032365.html#UsingPersonalAccessTokens-CreatingPATsinapplication'>here</a> for how to get one")
|
||||
jira_token_label.setTextFormat(QtCore.Qt.RichText)
|
||||
jira_token_label.setTextInteractionFlags(QtCore.Qt.TextBrowserInteraction)
|
||||
jira_token_label.setOpenExternalLinks(True)
|
||||
settings_layout.addWidget(jira_token_label, 1, 0)
|
||||
self.jira_token_edit = QtWidgets.QLineEdit()
|
||||
settings_layout.addWidget(self.jira_token_edit, 1, 1)
|
||||
|
||||
tray_theme_label = QtWidgets.QLabel()
|
||||
tray_theme_label.setText("Tray theme")
|
||||
settings_layout.addWidget(tray_theme_label, 2, 0)
|
||||
self.tray_theme_combo_box = QtWidgets.QComboBox()
|
||||
self.tray_theme_combo_box.addItem("Light")
|
||||
self.tray_theme_combo_box.addItem("Dark")
|
||||
settings_layout.addWidget(self.tray_theme_combo_box, 2, 1, QtCore.Qt.AlignRight)
|
||||
|
||||
flip_menu_label = QtWidgets.QLabel()
|
||||
flip_menu_label.setText("Flip menu")
|
||||
settings_layout.addWidget(flip_menu_label, 3, 0)
|
||||
self.flip_menu_check_box = QtWidgets.QCheckBox()
|
||||
settings_layout.addWidget(self.flip_menu_check_box, 3, 1, QtCore.Qt.AlignRight)
|
||||
|
||||
self.ok_button = QtWidgets.QPushButton()
|
||||
self.ok_button.setText("OK")
|
||||
self.ok_button.setIcon(get_icon("dialog-ok"))
|
||||
self.ok_button.pressed.connect(self.accept)
|
||||
self.ok_button.setAutoDefault(True)
|
||||
|
||||
button_layout = QtWidgets.QHBoxLayout()
|
||||
button_layout.addStretch(66)
|
||||
button_layout.addWidget(self.ok_button, 33)
|
||||
|
||||
layout = QtWidgets.QVBoxLayout()
|
||||
layout.addWidget(caption_label)
|
||||
layout.addLayout(settings_layout)
|
||||
layout.addLayout(button_layout)
|
||||
|
||||
self.setLayout(layout)
|
||||
self.resize(500, 0)
|
||||
self.accepted.connect(self._accepted)
|
||||
|
||||
def showEvent(self, _):
|
||||
self.jira_url_edit.setText(self.config.jira_url)
|
||||
self.jira_token_edit.setText(self.config.jira_token)
|
||||
self.tray_theme_combo_box.setCurrentText(self.config.tray_theme.capitalize())
|
||||
self.flip_menu_check_box.setChecked(self.config.flip_menu)
|
||||
|
||||
def _accepted(self):
|
||||
self.config.jira_url = self.jira_url_edit.text()
|
||||
self.config.jira_token = self.jira_token_edit.text()
|
||||
self.config.tray_theme = self.tray_theme_combo_box.currentText()
|
||||
self.config.flip_menu = self.flip_menu_check_box.isChecked()
|
||||
self.config.save()
|
||||
|
||||
|
||||
# only for dev/debug
|
||||
if __name__ == "__main__":
|
||||
QtCore.QCoreApplication.setApplicationName("fime")
|
||||
app = QtWidgets.QApplication()
|
||||
cfg = Config()
|
||||
settings = Settings(cfg, None)
|
||||
settings.show()
|
||||
app.exec()
|
@ -1,11 +1,11 @@
|
||||
import os
|
||||
import sys
|
||||
import threading
|
||||
import traceback
|
||||
from enum import Enum, auto
|
||||
from functools import reduce, partial
|
||||
from queue import Queue, Empty
|
||||
|
||||
from loguru import logger
|
||||
|
||||
try:
|
||||
from PySide6 import QtCore, QtWidgets
|
||||
except ImportError:
|
||||
@ -29,9 +29,8 @@ class TaskCompleter(QtWidgets.QCompleter):
|
||||
self.setCaseSensitivity(QtCore.Qt.CaseInsensitive)
|
||||
self.session = FuturesSession()
|
||||
self.config = config
|
||||
self.picker_url = None
|
||||
self.search_url = None
|
||||
self.update_urls()
|
||||
self.picker_url = os.path.join(self.config.jira_url, "rest/api/2/issue/picker")
|
||||
self.search_url = os.path.join(self.config.jira_url, "rest/api/2/search")
|
||||
self.text = ""
|
||||
self.response_text = ""
|
||||
self.model_data = set()
|
||||
@ -45,10 +44,6 @@ class TaskCompleter(QtWidgets.QCompleter):
|
||||
self.rif_counter_lock = threading.Lock()
|
||||
self.last_rif_state = TaskCompleter.RifState.STOPPED
|
||||
|
||||
def update_urls(self):
|
||||
self.picker_url = os.path.join(self.config.jira_url, "rest/api/2/issue/picker")
|
||||
self.search_url = os.path.join(self.config.jira_url, "rest/api/2/search")
|
||||
|
||||
@QtCore.Slot()
|
||||
def process_response(self):
|
||||
with self.rif_counter_lock:
|
||||
@ -110,11 +105,12 @@ class TaskCompleter(QtWidgets.QCompleter):
|
||||
})
|
||||
else:
|
||||
if not self.escalate:
|
||||
logger.debug("No picker results. Escalating")
|
||||
print("No picker results. Escalating")
|
||||
self.escalate = True
|
||||
self.update_search()
|
||||
except Exception:
|
||||
logger.exception("Ignoring exception, as it only breaks autocompletion")
|
||||
print("Ignoring exception, as it only breaks autocompletion:", file=sys.stderr)
|
||||
print(traceback.format_exc(), file=sys.stderr)
|
||||
return
|
||||
|
||||
def update_search(self):
|
||||
@ -148,5 +144,6 @@ class TaskCompleter(QtWidgets.QCompleter):
|
||||
"result": extracted,
|
||||
})
|
||||
except Exception:
|
||||
logger.exception("Ignoring exception, as it only breaks autocompletion")
|
||||
print("Ignoring exception, as it only breaks autocompletion:", file=sys.stderr)
|
||||
print(traceback.format_exc(), file=sys.stderr)
|
||||
return
|
||||
|
@ -3,15 +3,12 @@ try:
|
||||
except ImportError:
|
||||
from PySide2 import QtCore, QtGui, QtWidgets
|
||||
|
||||
from fime.data import Tasks
|
||||
from fime.util import get_icon, EditStartedDetector
|
||||
|
||||
|
||||
class TaskEdit(QtWidgets.QDialog):
|
||||
def __init__(self, tasks: Tasks, parent, *args, **kwargs):
|
||||
def __init__(self, parent, *args, **kwargs):
|
||||
super().__init__(parent, *args, **kwargs)
|
||||
self._task_data = tasks
|
||||
|
||||
self.setWindowTitle("Edit Tasks")
|
||||
self.list = QtCore.QStringListModel()
|
||||
|
||||
@ -85,7 +82,10 @@ class TaskEdit(QtWidgets.QDialog):
|
||||
ret = self.list.stringList()
|
||||
return list(filter(None, ret)) # filter empty strings
|
||||
|
||||
@tasks.setter
|
||||
def tasks(self, tasks):
|
||||
self.list.setStringList(tasks)
|
||||
|
||||
def showEvent(self, _):
|
||||
self.list.setStringList(self._task_data.tasks)
|
||||
self.raise_()
|
||||
self.activateWindow()
|
||||
|
@ -1,7 +1,5 @@
|
||||
import enum
|
||||
|
||||
from loguru import logger
|
||||
|
||||
try:
|
||||
from PySide6 import QtCore, QtGui, QtWidgets
|
||||
except ImportError:
|
||||
@ -15,7 +13,7 @@ def get_screen_height(qobject):
|
||||
if hasattr(qobject, "screen"):
|
||||
return qobject.screen().size().height()
|
||||
else:
|
||||
logger.info("unable to detect screen height falling back to default value of 1080")
|
||||
print("unable to detect screen height falling back to default value of 1080")
|
||||
return 1080
|
||||
|
||||
|
||||
@ -23,7 +21,7 @@ def get_screen_width(qobject):
|
||||
if hasattr(qobject, "screen"):
|
||||
return qobject.screen().size().width()
|
||||
else:
|
||||
logger.info("unable to detect screen width falling back to default value of 1920")
|
||||
print("unable to detect screen width falling back to default value of 1920")
|
||||
return 1920
|
||||
|
||||
|
||||
|
@ -99,7 +99,7 @@ class WorklogDialog(QtWidgets.QDialog):
|
||||
super().__init__(parent, *args, **kwargs)
|
||||
|
||||
self.config = config
|
||||
self.rest = None
|
||||
self.rest = WorklogRest(self.config)
|
||||
|
||||
self._changing_items = False
|
||||
self._worklog = worklog
|
||||
@ -175,7 +175,7 @@ class WorklogDialog(QtWidgets.QDialog):
|
||||
self.update_timer.timeout.connect(self.update_statuses)
|
||||
|
||||
def showEvent(self, _):
|
||||
# reinitialize to purge caches and pick up config changes
|
||||
# reinitialize to purge caches
|
||||
self.rest = WorklogRest(self.config)
|
||||
self._worklog.date = date.today()
|
||||
self.update_all()
|
||||
|
@ -1,4 +1,6 @@
|
||||
import os
|
||||
import sys
|
||||
import traceback
|
||||
from concurrent.futures import Future
|
||||
from datetime import date, datetime, timedelta, time
|
||||
from functools import partial
|
||||
@ -7,7 +9,6 @@ from threading import Lock
|
||||
from typing import List, Dict, Tuple, Optional
|
||||
|
||||
import requests
|
||||
from loguru import logger
|
||||
from requests_futures.sessions import FuturesSession
|
||||
|
||||
from fime.config import Config
|
||||
@ -41,9 +42,12 @@ class WorklogRest:
|
||||
future.add_done_callback(self._resp_user)
|
||||
return future
|
||||
|
||||
@logger.catch(message="Could not get user key")
|
||||
def _resp_user(self, future):
|
||||
try:
|
||||
self._user = future.result().json()["key"]
|
||||
except Exception:
|
||||
print("Could not get user key:\n", file=sys.stderr)
|
||||
print(traceback.format_exc(), file=sys.stderr)
|
||||
|
||||
def get_issues_state(self, issue_keys: List[str], pdate: date) -> List[Tuple[Status, str, Optional[str]]]:
|
||||
ret = []
|
||||
@ -110,9 +114,9 @@ class WorklogRest:
|
||||
worklog_found = True
|
||||
break
|
||||
if worklog_found:
|
||||
logger.debug(f"Found existing worklog for issue {issue_key}")
|
||||
print(f"Found existing worklog for issue {issue_key}")
|
||||
else:
|
||||
logger.debug(f"Did not find existing worklog for issue {issue_key}")
|
||||
print(f"Did not find existing worklog for issue {issue_key}")
|
||||
self._issue_state[issue_key] = (Status.OK, issue_title)
|
||||
|
||||
def _upload_sanity_check(self, issue_keys: List[str]):
|
||||
@ -179,7 +183,7 @@ class WorklogRest:
|
||||
with self._issues_lock:
|
||||
if resp.status_code in (200, 201):
|
||||
self._issue_state[issue_key] = (Status.OK, "Successfully uploaded")
|
||||
logger.info(f"Successfully uploaded issue {issue_key}")
|
||||
print(f"Successfully uploaded issue {issue_key}")
|
||||
else:
|
||||
msg = dedent(f"""\
|
||||
Worklog upload failed:
|
||||
@ -189,4 +193,4 @@ class WorklogRest:
|
||||
Response: {resp.text}
|
||||
""")
|
||||
self._issue_state[issue_key] = (Status.ERROR, msg)
|
||||
logger.error(msg)
|
||||
print(msg, file=sys.stderr)
|
||||
|
Loading…
Reference in New Issue
Block a user