{ "info": { "author": "Eero Vilpponen", "author_email": "eero.vilpponen@gmail.com", "bugtrack_url": null, "classifiers": [ "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 3.7" ], "description": "# TrackLater\n\n![](https://i.imgur.com/cFPdBhN.png)\n\nForgot to track your time for work? TrackLater helps you track time after-the-fact by combining clues and showing your day on a simple timeline view.\n\nThe initial version supports fetching clues from\n* [Thyme](https://github.com/sourcegraph/thyme)\n* Git\n* Slack\n\nTime entries can be exported to\n* Toggl\n\nIssues and projects/clients can be fetched from\n* Jira\n* Taiga\n* Toggl (projects/clients)\n\n# Background\n\nEveryone who uses time-tracking for their work knows that it can be a real pain, especially if you're a forgetful person like me. I pretty much never remember to start my timers, and when I do, I for sure will not remember to turn them off.\n\nWhen working with multiple clients, it can be crucial (billing-wise) to track your time correctly and to be able to differentiate all tasks by client. For people that work 9-5 in-office for the same client and without need to track each task separately this app is probably overkill.\n\nWith this in mind, I built a basic app to use Thyme for passive time-tracking, and Toggl-api for exporting. I quickly found that my workflow was substantially improved by only having to think about time-tracking 1-2 times per week. I've now used this app for about a year, building a new timemodule every now and then.\n\nTrackLater offers a basic set of features to help all time-trackers get their timesheets in order:\n* A timeline overview, which is usually missing from tracking software\n* Easily add time entries, with automatically detected projects and responsive UI\n* Get all your breadcrumbs, tracks, clues, footsteps in one place\n\n# Implementation notes\n\nEvery module separates their issues, time-entries and projects by *group*. This makes inter-module communication simple: e.g. commits made in the git repository for *group* x will be attributed to the corresponding Toggl project for *group* x.\n\n*Groups* are arbitrary and decided by the user when creating their settings file. A good way to choose your amount of *group*s\nis to create a *group* for each client/work project.\n\nWhile all modules are optional, an important backbone for TimeLater is [thyme](https://github.com/sourcegraph/thyme).\nThe thyme module assumes an implementation where every day is stored in a file named `YYYY-MM-DD.json`. It's recommended to set up an automatic thyme tracking script for this.\n\nI'm using a basic script to run thyme. It has evolved a bit after about a year of tracking: Sometimes thyme fails tracking and corrupts the whole file,\nso I definitely recommend using this script. https://gist.github.com/Eerovil/36d109d531659d24bfafea7111b12e90\n\nTo run thyme automatically every 20 seconds you can add this to your crontab. Windows users can probably use services (don't quote me on this).\n```\n* * * * * DISPLAY=:0 /home/eero/Documents/thyme/track-thyme-log.sh\n* * * * * ( sleep 20; DISPLAY=:0 /home/eero/Documents/thyme/track-thyme-log.sh )\n* * * * * ( sleep 40; DISPLAY=:0 /home/eero/Documents/thyme/track-thyme-log.sh )\n```\n\n# Running\n\nClone the repository, install inside a virtualenv and run:\n```\ngit clone git@github.com:Eerovil/TrackLater.git\ncd TrackLater\nmkvirtualenv tracklater -p python3.7 -a .\npip install .\ntracklater\n```\n\nAdditional example command to start the server. Must be run in the root directory.\n```\nFLASK_APP=tracklater python -m flask run\n```\n\n# Usage\n\nSelect time entries from thyme and click export.\n\nYou can also double click on the timeline to create entries. Edit by selecting, dragging etc.\n\n# Contributing\n\nBuilding and running the project is easy, as you can simply clone the repo and start making PRs.\n\nIf your workflow is not exactly like mine and you need additional functionality, please create an issue and we can start working on supporting your required modules.\n\nIdeas for future support:\n* Jira time tracking\n* Maybe a Chrome page history parser?\n\n# Settings guide\n\nCreate a file called `user_settings.py` to the root folder (containing `app.py`)\n\nTo load test settings you can add `from test_settings import *` to the end of the file. This will use test data and no actual API calls will be made.\n\nEach module has their own settings dict, containing a settings dict for each group. There is also\na `global` key for non-group specific settings.\n\nThis example settings file contains two groups: `group1` and `group2`.\n\nIn the example workers workflow, `group1`'s issues are fetched from Jira while `group2`'s issues are from Taiga.io,\nso you will find that the JIRA settings have no `group2` key and TAIGA settings has no `group1` key.\n\nTime tracking (for billing) is done through Toggl. Also, both groups happen to have their own workspaces on slack, and obviously their own git repositories.\n\n```\n\n# edit to your liking and save as ~/.config/tracklater.json. Remove the comments\n\n{\n \"TESTING\": false,\n \"ENABLED_MODULES\": [\n \"thyme\",\n \"gitmodule\",\n \"toggl\",\n \"taiga\",\n \"jira\",\n \"slack\"\n ],\n\n \"UI_SETTINGS\": {\n \"toggl\": {\n \"global\": \"#E01A22\"\n },\n \"thyme\": {\n \"global\": \"#1aef65\"\n },\n \"gitmodule\": {\n \"global\": \"#F44D27\"\n },\n \"slack\": {\n \"global\": \"#4A154B\"\n }\n },\n \"TOGGL\": {\n \"global\": {\n \"API_KEY\": \"your-api-key\"\n },\n \"group1\": {\n \"NAME\": \"First Group\",\n \"PROJECTS\": {\n \"Development\": \"default\",\n \"Bug fixing\": \"bug\"\n }\n },\n \"group2\": {\n \"NAME\": \"Second Group\",\n \"PROJECTS\": {\n \"Development\": \"default\",\n \"Bug fixing\": \"default\"\n }\n }\n },\n\n \"GIT\": {\n \"global\": {\n # Only commits made by users with EMAILS will be shown\n \"EMAILS\": [\"firstname.lastname@email.com\"]\n },\n \"group1\": {\n # Full path to the git repo\n \"REPOS\": [\"/full/path/to/group1/repo\"]\n },\n \"group2\": {\n \"REPOS\": [\"/full/path/to/group2/repo\"]\n }\n },\n\n \"JIRA\": {\n \"group1\": {\n # Each group must have these settings\n \"CREDENTIALS\": [\"username\", \"password\"],\n \"URL\": \"https://group1.atlassian.net\",\n \"PROJECT_KEY\": \"DEV\"\n }\n },\n\n \"TAIGA\": {\n \"global\": {\n \"CREDENTIALS\": [\"username\", \"password\"]\n },\n \"group2\": {\n # project_slug can be found in the URL\n \"project_slug\": \"username-group2\"\n }\n },\n\n \"THYME\": {\n \"global\": {\n # Directory containing the json files generated by thyme\n \"DIR\": \"/full/path/to/thyme/dir\"\n }\n },\n\n \"SLACK\": {\n # Each group should contain a workspace to match all messager to a group\n \"global\": {\n # Global catch-all workspace for all groups\n \"API_KEY\": \"legacy-slack-api-key-global\",\n \"USER_ID\": \"your-user-id\"\n },\n \"group2\": {\n # Messages in this workspace will be matched to group2\n \"API_KEY\": \"legacy-slack-api-key-group2\",\n \"USER_ID\": \"your-user-id\"\n }\n }\n}\n\n```\n\n\n", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/Eerovil/TrackLater", "keywords": "", "license": "", "maintainer": "", "maintainer_email": "", "name": "tracklater", "package_url": "https://pypi.org/project/tracklater/", "platform": "", "project_url": "https://pypi.org/project/tracklater/", "project_urls": { "Homepage": "https://github.com/Eerovil/TrackLater" }, "release_url": "https://pypi.org/project/tracklater/1.2/", "requires_dist": [ "Flask (==1.0.3)", "GitPython (==2.1.11)", "python-dateutil (==2.8.0)", "slackclient (==2.0.1)", "pytz (==2019.1)", "flask-sqlalchemy (==2.4.0)", "requests (==2.22.0)", "appdirs (==1.4.3)" ], "requires_python": ">=3.7.1", "summary": "TrackLater helps you track time after-the-fact by combining clues and showingyour day on a simple timeline view.", "version": "1.2" }, "last_serial": 5406421, "releases": { "1.1": [ { "comment_text": "", "digests": { "md5": "2a562cfa54cd334f95b0545551e7ec36", "sha256": "fa04e6dcd1a75fc7a84b6784013172b9d13f2ef00e5ee8a65bbfa988a63c5d84" }, "downloads": -1, "filename": "tracklater-1.1-py3-none-any.whl", "has_sig": false, "md5_digest": "2a562cfa54cd334f95b0545551e7ec36", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.7.1", "size": 39680, "upload_time": "2019-06-15T17:18:34", "url": "https://files.pythonhosted.org/packages/f9/08/a46b912a51dc0e60327bfce1541f3dd4d62535078a2c01693cb1cfc796e4/tracklater-1.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "f86373837d3eb83b716f7c84fa01600c", "sha256": "56ffec2e666a46d731a4fbede6686ba416eee7ea9f2c25a86fc49b4d54178186" }, "downloads": -1, "filename": "tracklater-1.1.tar.gz", "has_sig": false, "md5_digest": "f86373837d3eb83b716f7c84fa01600c", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.7.1", "size": 29575, "upload_time": "2019-06-15T17:18:36", "url": "https://files.pythonhosted.org/packages/49/32/20678f99cd93e991e63aa1e19b21a3e7a35b5e785d9eacbc2ec96fa6c986/tracklater-1.1.tar.gz" } ], "1.2": [ { "comment_text": "", "digests": { "md5": "5da0cac67f867e20813b1732c742fdfb", "sha256": "a72e87c057bfcbf858250ab7c2669b127d72f2517cc00f0713beea93c877c387" }, "downloads": -1, "filename": "tracklater-1.2-py3-none-any.whl", "has_sig": false, "md5_digest": "5da0cac67f867e20813b1732c742fdfb", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.7.1", "size": 41164, "upload_time": "2019-06-16T13:04:12", "url": "https://files.pythonhosted.org/packages/a8/c7/6aaa3dff5b6569422bb3c3284a91be851b167a42281ba61002b52eb13182/tracklater-1.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "fe361d1d1f5583c430493d06acde3555", "sha256": "c430e580db1e74f43603e934146400306ce2f04f6de98167cf4af674993ddca5" }, "downloads": -1, "filename": "tracklater-1.2.tar.gz", "has_sig": false, "md5_digest": "fe361d1d1f5583c430493d06acde3555", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.7.1", "size": 29000, "upload_time": "2019-06-16T13:04:15", "url": "https://files.pythonhosted.org/packages/2f/5f/da42d972f916a801369799f87117607534f95e53d0f14045625bd06f3c64/tracklater-1.2.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "5da0cac67f867e20813b1732c742fdfb", "sha256": "a72e87c057bfcbf858250ab7c2669b127d72f2517cc00f0713beea93c877c387" }, "downloads": -1, "filename": "tracklater-1.2-py3-none-any.whl", "has_sig": false, "md5_digest": "5da0cac67f867e20813b1732c742fdfb", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.7.1", "size": 41164, "upload_time": "2019-06-16T13:04:12", "url": "https://files.pythonhosted.org/packages/a8/c7/6aaa3dff5b6569422bb3c3284a91be851b167a42281ba61002b52eb13182/tracklater-1.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "fe361d1d1f5583c430493d06acde3555", "sha256": "c430e580db1e74f43603e934146400306ce2f04f6de98167cf4af674993ddca5" }, "downloads": -1, "filename": "tracklater-1.2.tar.gz", "has_sig": false, "md5_digest": "fe361d1d1f5583c430493d06acde3555", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.7.1", "size": 29000, "upload_time": "2019-06-16T13:04:15", "url": "https://files.pythonhosted.org/packages/2f/5f/da42d972f916a801369799f87117607534f95e53d0f14045625bd06f3c64/tracklater-1.2.tar.gz" } ] }