Skip to content

Commit

Permalink
Add command to group entries by field (#8)
Browse files Browse the repository at this point in the history
* Add quick prototype for `entries group-by` command

* Format duration using the hh:mm format

The 'human' format is nice, but it make reading durations at glance
harder.

* Add --project-id option to the 'entries' group

The Time Entries API doesn't have filtering options, so I am filtering
the response client side. Not great, we'll see if there are other
options.

* Add a table footer with duration total

The Rich's table has the option of adding a table footer. It adds an
additional row visually distinct from the data rows:

     $ tgl entries --project-id 178435728 group-by --field tags --start-date 2023-01-30

          Time Entries

     tags           Duration
     ─────────────────────────
     type:support   9:40
     type:meeting   7:38
     type:goal      5:58
     type:sync      5:08
     type:hr        0:54
     ─────────────────────────
     Total          29:20

* Filter running timers from duration sum

Running timers have a negative duration that would impact totals.

* Update usage in the README file

We are now showing:

- tgl entries list
- tgl entries list --project-id 123
- tgl entries group-by --field tags

* Fix test

I should lower the maintenance cost of these tests!
  • Loading branch information
zmoog committed Feb 4, 2023
1 parent 0a45b43 commit c432440
Show file tree
Hide file tree
Showing 15 changed files with 789 additions and 243 deletions.
71 changes: 55 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,57 @@ Install this tool using `pip`:
For listing the time entries in the last 24 hours, run:

$ tgl entries list
Time Entries
At Description Start Stop Duration Tags
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
2023-01-28 toggl-track: list time entries 04:33 AM
2023-01-27 ESF: telemetry 05:23 PM 07:19 PM an hour type:goal
2023-01-27 ESF: telemetry 03:28 PM 05:00 PM an hour type:goal
2023-01-27 Community: Fix parsing error client port is blank and adjust for timeStamp 03:13 PM 03:28 PM 15 minutes type:support
2023-01-27 Community: Azure Signin Module authentication_processing_details Issue 02:47 PM 03:13 PM 25 minutes type:support
2023-01-27 sync 02:31 PM 02:47 PM 16 minutes type:sync
2023-01-27 🍜 Lunch 01:11 PM 02:31 PM an hour
2023-01-27 Community: Fix parsing error client port is blank and adjust for timeStamp 12:19 PM 12:29 PM 10 minutes type:support
2023-01-27 Community: Fix parsing error client port is blank and adjust for timeStamp 11:54 AM 12:06 PM 11 minutes type:support
2023-01-27 Community: Azure Signin Module authentication_processing_details Issue 09:30 AM 11:54 AM 2 hours type:support
2023-01-27 sync 08:34 AM 09:30 AM 56 minutes type:sync
2023-01-27 toggl-track: list time entries 07:04 AM 08:34 AM an hour
Time Entries

At Description Start Stop Duration Tags
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
2023-02-04 toggl-track: insights 05:37 AM -
2023-02-03 Community: Allow parsing of IPv6 addresses in ingest pipeline 08:18 PM 10:09 PM 1:51 type:support
2023-02-03 🍲 Dinner 07:19 PM 08:18 PM 0:58
2023-02-03 sync 06:19 PM 06:55 PM 0:35 type:sync
2023-02-03 🚌 Shuttling kids between home and whatever 04:46 PM 06:19 PM 1:33
2023-02-03 App Service logs integration: troubleshootign lucianpy issues 04:40 PM 04:46 PM 0:06 type:goal
2023-02-03 Community: Allow parsing of IPv6 addresses in ingest pipeline 04:21 PM 04:40 PM 0:18 type:support
2023-02-03 Community: Fix parsing error client port is blank and adjust for timeStamp 03:15 PM 04:21 PM 1:05 type:support
2023-02-03 Community: Azure Signin Module authentication_processing_details Issue 02:37 PM 03:15 PM 0:38 type:support
2023-02-03 Rosanna 11:06 AM 02:37 PM 3:31
2023-02-03 Community: Azure Signin Module authentication_processing_details Issue 09:25 AM 11:06 AM 1:41 type:support
2023-02-03 sync 08:37 AM 09:25 AM 0:48 type:sync
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Total 13:08

Now you can also filter time entries by project ID:

$ tgl entries --project-id 178435728 list
Time Entries

At Description Start Stop Duration Tags
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
2023-02-03 Community: Allow parsing of IPv6 addresses in ingest pipeline 08:18 PM 10:09 PM 1:51 type:support
2023-02-03 sync 06:19 PM 06:55 PM 0:35 type:sync
2023-02-03 App Service logs integration: troubleshootign lucianpy issues 04:40 PM 04:46 PM 0:06 type:goal
2023-02-03 Community: Allow parsing of IPv6 addresses in ingest pipeline 04:21 PM 04:40 PM 0:18 type:support
2023-02-03 Community: Fix parsing error client port is blank and adjust for timeStamp 03:15 PM 04:21 PM 1:05 type:support
2023-02-03 Community: Azure Signin Module authentication_processing_details Issue 02:37 PM 03:15 PM 0:38 type:support
2023-02-03 Community: Azure Signin Module authentication_processing_details Issue 09:25 AM 11:06 AM 1:41 type:support
2023-02-03 sync 08:37 AM 09:25 AM 0:48 type:sync
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Total 7:05

For grouping time entries by tags and sum up the totals, run:

$ tgl entries --project-id 178435728 group-by --field tags --start-date 2023-02-01
Time Entries

tags Duration
─────────────────────────
type:support 7:13
type:goal 5:10
type:meeting 4:29
type:sync 3:38
type:hr 0:09
─────────────────────────
Total 20:40

For help, run:

Expand All @@ -58,3 +93,7 @@ Now install the dependencies and test dependencies:
To run the tests:

pytest

If you need to send other requests to Toggl API, you can capture responses using:

pytest --record-mode=once
1 change: 0 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ def get_long_description():
""",
install_requires=[
"click",
"humanize",
"pydantic",
"requests",
"rich",
Expand Down
81 changes: 0 additions & 81 deletions tests/cassettes/test_entries/test_entries.yaml

This file was deleted.

81 changes: 81 additions & 0 deletions tests/cassettes/test_entries_group_by/test_group_by_tags.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
interactions:
- request:
body: null
headers:
Accept:
- '*/*'
Accept-Encoding:
- gzip, deflate
Connection:
- keep-alive
User-Agent:
- python-requests/2.28.2
method: GET
uri: https://api.track.toggl.com/api/v9/me/time_entries?start_date=2023-01-26T00%3A00%3A00Z&end_date=2023-01-27T00%3A00%3A00Z
response:
body:
string: !!binary |
H4sIAAAAAAAEA9WZ3Y7jNBTHX8XKLR3JH7GT+G6ZYaWVQCDNSkisViNP47bZpklInC2ziDdgJa4R
Ele8AE/GI3CSJpO6KZluacIg9aZO1Nrndz7+5/jNj04UOpL6JCCU48CbOds0XxeZmuu76gnxCcfE
nzlZnr7Tc7Nb9HyXcY/CslHFul5LyjieOfdRHKv7WDtyoeJCz5zCqNw40qGYsitMrqh4TamkXDL+
GcYSY6d6J816r3BXMvYdPA3LXJkoTWAvHoN/DHUxz6Nst+Rcp5tNmUTmQaIXcZxuUabyIkqWKF2g
V9+8F0iFYa6LQhcoSuCz1IVBWZTpOEo0/LpRy8KRbxzzkGlZlFmWwnbf1utwrOoRodjzscCwCFtJ
k/jBkSYv4Wyqf7B6193BdP5e53ehjrXR4V31/s5MZQHLteEFJYyxmVNa37a26etvrc1/mnXMsE+p
oFMwI9LlkpDuaMeY1VhtZtSl7gCzl9EPj8R0nqc5mseRTgARcEBRge5jlayRSkIA+a4Edgt4x0Qb
fWvUJrs8wAPPnAKgO0nQ7QDiIYANYxsg+T/Qo1eYvcaedIVkQXfEKeiR6ehhvztaP/wawDY9yA3/
mC+fTez9V/QwIxzce/yCh8Erpes9SQ8HNj0W0CGALz6UuUa30TKB0vZVGpaxRqo0K8if0byumXdQ
tedQ/aDuQRUyKooL9KooyotXvtr58HSh5/se1L7TQo/62CUBw2eJFeJLHkg+mDcbvDY7HlRiyg6+
v37/+Ce6iZJE513lssTGCSKj50wXzHKtqfY0hu8Rl2JQKKOHCfEkYSANB8KkouFLeqALBQ0GdeGz
CZN2+90JL8iOHBGIvhA+P1EgtuzPCxMhXQAzFCYtXjtMoLvg/TD59Wd0uyqNAZG+RGvQ4ehem63W
CVqlG0hyIAe3K2U0qOuzA6ndzygwWmPuBxIXAvPTUtYjy/NgcMmhwdrLxj21QHa8qA2DEQGBbues
/Qbr+QRSs/1R2D0a34LnBtwFTx0/C3JQCpK43dH68Bq+NrwjgXSTpxlaaRXqHMXpElU9b9UGX8dp
Gb6EXtYgCKHEFF0QXaQRJj0HHDvPuYJgAhV+CjyYSXeoEYbT1wRtPFSQXmx9EasCpNrXSa3kJPq+
hOkEjDoKtMjTDbrRSfQBXafFukwuT+jAy8YmRD3ieZMEEJOYDI+XCMyWQEYJmxBnbr/ZrSIFtDVM
mNK8KkZX6Fut1zADqkdE3ehoo7WB5/boKAiYgAL3tKhrN9QF/dg4YJbGPXFSwLS17LxaRAGFZEO9
D4g+mAQe0iBuEBzWItDPv6Evy2S+6sz/ifIZ/gzQ8730ekFLt5baLxyE+rwagY2fmajEUBYHJdgO
BrH9Hlyh5/fFQzLvbNwUhWrNMnczGiUnOHjzz9M5OPa48CapCJBs4POE3Ws0tt0pqSqWrbaWCtp3
GHCm217G/5cZpucdF/T7o4oJw2h6kvsEAvEMgmNoOEZ2jA4cvxq9HwJQlcalEsbM9W1C2RsxL1MV
H40CdkIUNNuYLAo8z2e0ur0ZPftg6P5cSQZ7joaTHQUB7uf5i2efnoeM7Pyeh6G+Qv06we4BxzQQ
VZN+xl0azLypL929ctbrFoAMfAi2zU6ZgOpvJx+TLpfxlcnVfC2hV4DLluqiBUGDkEd6r0ewasDT
Xt9uYBSvb623V3I9GHrgAOw5uvHrLpQP+TzwgTkDPhhYEeH3LsXGMn6zgemMz+Am+bS628ql8zxf
VHJnsOxWNbca3x54PnePCMs/fkGf51qtF9CRdcLnUz295xAXzDOttSxPJxga3wk8vbr7He6pwNg1
D9vYjAa98d5Ynt5ziAsa/zHNvP0bd0fgfDIhAAA=
headers:
Alt-Svc:
- h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
Cache-Control:
- no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0
Content-Encoding:
- gzip
Content-Type:
- application/json; charset=utf-8
Date:
- Fri, 03 Feb 2023 07:48:05 GMT
Instance:
- time-public-api2
Referrer-Policy:
- strict-origin-when-cross-origin
Server:
- nginx
Strict-Transport-Security:
- max-age=15552000; includeSubDomains
Transfer-Encoding:
- chunked
Vary:
- Accept-Encoding
Via:
- 1.1 google
X-Content-Type-Options:
- nosniff
X-Request-ID:
- 1012c9aa6eee4f312cfe0bf58f2b58cf
X-Service-Level:
- GREEN
X-Toggl-Request-Id:
- 1012c9aa6eee4f312cfe0bf58f2b58cf
X-We-are-hiring:
- https://toggl.com/jobs/
status:
code: 200
message: OK
version: 1
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
interactions:
- request:
body: null
headers:
Accept:
- '*/*'
Accept-Encoding:
- gzip, deflate
Connection:
- keep-alive
User-Agent:
- python-requests/2.28.2
method: GET
uri: https://api.track.toggl.com/api/v9/me/time_entries?start_date=2023-01-26T00%3A00%3A00Z&end_date=2023-01-27T00%3A00%3A00Z
response:
body:
string: !!binary |
H4sIAAAAAAAEA9WZ3Y7jNBTHX8XKLR3JH7GT+G6ZYaWVQCDNSkisViNP47bZpklInC2ziDdgJa4R
Ele8AE/GI3CSJpO6KZluacIg9aZO1Nrndz7+5/jNj04UOpL6JCCU48CbOds0XxeZmuu76gnxCcfE
nzlZnr7Tc7Nb9HyXcY/CslHFul5LyjieOfdRHKv7WDtyoeJCz5zCqNw40qGYsitMrqh4TamkXDL+
GcYSY6d6J816r3BXMvYdPA3LXJkoTWAvHoN/DHUxz6Nst+Rcp5tNmUTmQaIXcZxuUabyIkqWKF2g
V9+8F0iFYa6LQhcoSuCz1IVBWZTpOEo0/LpRy8KRbxzzkGlZlFmWwnbf1utwrOoRodjzscCwCFtJ
k/jBkSYv4Wyqf7B6193BdP5e53ehjrXR4V31/s5MZQHLteEFJYyxmVNa37a26etvrc1/mnXMsE+p
oFMwI9LlkpDuaMeY1VhtZtSl7gCzl9EPj8R0nqc5mseRTgARcEBRge5jlayRSkIA+a4Edgt4x0Qb
fWvUJrs8wAPPnAKgO0nQ7QDiIYANYxsg+T/Qo1eYvcaedIVkQXfEKeiR6ehhvztaP/wawDY9yA3/
mC+fTez9V/QwIxzce/yCh8Erpes9SQ8HNj0W0CGALz6UuUa30TKB0vZVGpaxRqo0K8if0byumXdQ
tedQ/aDuQRUyKooL9KooyotXvtr58HSh5/se1L7TQo/62CUBw2eJFeJLHkg+mDcbvDY7HlRiyg6+
v37/+Ce6iZJE513lssTGCSKj50wXzHKtqfY0hu8Rl2JQKKOHCfEkYSANB8KkouFLeqALBQ0GdeGz
CZN2+90JL8iOHBGIvhA+P1EgtuzPCxMhXQAzFCYtXjtMoLvg/TD59Wd0uyqNAZG+RGvQ4ehem63W
CVqlG0hyIAe3K2U0qOuzA6ndzygwWmPuBxIXAvPTUtYjy/NgcMmhwdrLxj21QHa8qA2DEQGBbues
/Qbr+QRSs/1R2D0a34LnBtwFTx0/C3JQCpK43dH68Bq+NrwjgXSTpxlaaRXqHMXpElU9b9UGX8dp
Gb6EXtYgCKHEFF0QXaQRJj0HHDvPuYJgAhV+CjyYSXeoEYbT1wRtPFSQXmx9EasCpNrXSa3kJPq+
hOkEjDoKtMjTDbrRSfQBXafFukwuT+jAy8YmRD3ieZMEEJOYDI+XCMyWQEYJmxBnbr/ZrSIFtDVM
mNK8KkZX6Fut1zADqkdE3ehoo7WB5/boKAiYgAL3tKhrN9QF/dg4YJbGPXFSwLS17LxaRAGFZEO9
D4g+mAQe0iBuEBzWItDPv6Evy2S+6sz/ifIZ/gzQ8730ekFLt5baLxyE+rwagY2fmajEUBYHJdgO
BrH9Hlyh5/fFQzLvbNwUhWrNMnczGiUnOHjzz9M5OPa48CapCJBs4POE3Ws0tt0pqSqWrbaWCtp3
GHCm217G/5cZpucdF/T7o4oJw2h6kvsEAvEMgmNoOEZ2jA4cvxq9HwJQlcalEsbM9W1C2RsxL1MV
H40CdkIUNNuYLAo8z2e0ur0ZPftg6P5cSQZ7joaTHQUB7uf5i2efnoeM7Pyeh6G+Qv06we4BxzQQ
VZN+xl0azLypL929ctbrFoAMfAi2zU6ZgOpvJx+TLpfxlcnVfC2hV4DLluqiBUGDkEd6r0ewasDT
Xt9uYBSvb623V3I9GHrgAOw5uvHrLpQP+TzwgTkDPhhYEeH3LsXGMn6zgemMz+Am+bS628ql8zxf
VHJnsOxWNbca3x54PnePCMs/fkGf51qtF9CRdcLnUz295xAXzDOttSxPJxga3wk8vbr7He6pwNg1
D9vYjAa98d5Ynt5ziAsa/zHNvP0bd0fgfDIhAAA=
headers:
Alt-Svc:
- h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
Cache-Control:
- no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0
Content-Encoding:
- gzip
Content-Type:
- application/json; charset=utf-8
Date:
- Fri, 03 Feb 2023 07:48:05 GMT
Instance:
- time-public-api2
Referrer-Policy:
- strict-origin-when-cross-origin
Server:
- nginx
Strict-Transport-Security:
- max-age=15552000; includeSubDomains
Transfer-Encoding:
- chunked
Vary:
- Accept-Encoding
Via:
- 1.1 google
X-Content-Type-Options:
- nosniff
X-Request-ID:
- 3461241a983f5db01e7ae9f26b929aeb
X-Service-Level:
- GREEN
X-Toggl-Request-Id:
- 3461241a983f5db01e7ae9f26b929aeb
X-We-are-hiring:
- https://toggl.com/jobs/
status:
code: 200
message: OK
version: 1
Loading

0 comments on commit c432440

Please sign in to comment.