@beauraines/toggl-cli 0.10.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.json +16 -0
- package/.github/dependabot.yml +11 -0
- package/.github/workflows/main.yml +27 -0
- package/.github/workflows/publish.yml +54 -0
- package/CHANGELOG.md +38 -0
- package/README.md +85 -0
- package/cli.js +13 -0
- package/client.js +29 -0
- package/cmds/continue.mjs +55 -0
- package/cmds/currentTimeEntry.mjs +16 -0
- package/cmds/edit.mjs +84 -0
- package/cmds/index.mjs +26 -0
- package/cmds/ls.mjs +30 -0
- package/cmds/ls.test.js +6 -0
- package/cmds/me.mjs +44 -0
- package/cmds/projects/add.mjs +7 -0
- package/cmds/projects/index.mjs +3 -0
- package/cmds/projects/list.mjs +25 -0
- package/cmds/projects.mjs +11 -0
- package/cmds/startTimeEntry.mjs +38 -0
- package/cmds/stopTimeEntry.mjs +18 -0
- package/cmds/today.mjs +83 -0
- package/cmds/web.mjs +23 -0
- package/cmds/weekly.mjs +98 -0
- package/cmds/workspace.mjs +10 -0
- package/cmds/workspaces/add.mjs +7 -0
- package/cmds/workspaces/index.mjs +3 -0
- package/cmds/workspaces/list.mjs +14 -0
- package/package.json +50 -0
- package/standalone/currentTimeEntry.js +12 -0
- package/standalone/getWorkspaces.js +11 -0
- package/standalone/listProjects.js +21 -0
- package/standalone/startTimeEntry.js +47 -0
- package/standalone/stopCurrentTimeEntry.js +21 -0
- package/standalone/todayReport.js +101 -0
- package/standalone/weeklyReport.js +57 -0
- package/utils.js +133 -0
package/utils.js
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import Client from './client.js'
|
|
2
|
+
import dayjs from 'dayjs'
|
|
3
|
+
import utc from "dayjs/plugin/utc.js";
|
|
4
|
+
import timezone from 'dayjs/plugin/timezone.js';
|
|
5
|
+
import duration from 'dayjs/plugin/duration.js';
|
|
6
|
+
dayjs.extend(utc);
|
|
7
|
+
dayjs.extend(timezone);
|
|
8
|
+
dayjs.extend(duration);
|
|
9
|
+
|
|
10
|
+
// TODO read from file or GET /me
|
|
11
|
+
export const defaultWorkspaceId = process.env.TOGGL_DEFAULT_WORKSPACE_ID
|
|
12
|
+
|
|
13
|
+
// TODO read from file or ENV
|
|
14
|
+
export const defaultProjectId = process.env.TOGGL_DEFAULT_PROJECT_ID
|
|
15
|
+
|
|
16
|
+
export const getProjects = async function (workspaceId) {
|
|
17
|
+
const client = Client()
|
|
18
|
+
const projects = await client.workspaces.projects(workspaceId)
|
|
19
|
+
const activeProjects = projects.filter(x => x.active)
|
|
20
|
+
return activeProjects
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const getWorkspace = async function () {
|
|
24
|
+
const client = Client()
|
|
25
|
+
const workspaces = await client.workspaces.list()
|
|
26
|
+
return workspaces[0]
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const getProjectByName = async function (workspaceId, string) {
|
|
30
|
+
const client = Client()
|
|
31
|
+
const projects = await client.workspaces.projects(workspaceId)
|
|
32
|
+
return projects.find(x => x.name.toLowerCase().includes(string.toLowerCase()))
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export const getProjectById = async function (workspaceId, projectId) {
|
|
36
|
+
const client = Client()
|
|
37
|
+
const projects = await client.workspaces.projects(workspaceId)
|
|
38
|
+
return projects.find(x => x.id == projectId)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export const createTimeEntry = async function (params) {
|
|
42
|
+
const client = Client()
|
|
43
|
+
|
|
44
|
+
const timeEntry = await client.timeEntries.create(
|
|
45
|
+
{
|
|
46
|
+
description: params.description,
|
|
47
|
+
workspace_id: +params.workspaceId,
|
|
48
|
+
project_id: +params.projectId,
|
|
49
|
+
start: dayjs().toISOString(),
|
|
50
|
+
duration: -1 * dayjs().unix(),
|
|
51
|
+
created_with: appName,
|
|
52
|
+
at: dayjs().toISOString()
|
|
53
|
+
}
|
|
54
|
+
)
|
|
55
|
+
return timeEntry
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
*
|
|
60
|
+
* @param {number} milliseconds , if negative the time entry is assumed to be running
|
|
61
|
+
* @returns {string} duration formatted as 25h 32m where duration greater than a day displays
|
|
62
|
+
* total hours
|
|
63
|
+
*/
|
|
64
|
+
export const formatDuration = function (milliseconds) {
|
|
65
|
+
if (milliseconds < 0) {
|
|
66
|
+
const seconds = milliseconds / 1000
|
|
67
|
+
const startTime = dayjs.unix(seconds * -1)
|
|
68
|
+
const duration = dayjs().diff(startTime, 's')
|
|
69
|
+
return dayjs.duration(duration * 1000).format('H[h] m[m]')
|
|
70
|
+
}
|
|
71
|
+
const dur = dayjs.duration(milliseconds)
|
|
72
|
+
const hours = (dur.days() * 24) + dur.hours()
|
|
73
|
+
const duration = `${hours}h ${dur.minutes()}m`
|
|
74
|
+
return duration
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
*
|
|
79
|
+
* @param {number} milliseconds
|
|
80
|
+
* @returns {String} the duration formatted as H:mm:ss
|
|
81
|
+
*/
|
|
82
|
+
export const formatDurationAsTime = function (milliseconds) {
|
|
83
|
+
return dayjs.duration(milliseconds).format('H:mm:ss')
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Formats a dateTime to YYYY-MM-DD HH:mm
|
|
88
|
+
* @param {Date} dateTime
|
|
89
|
+
* @returns {String}
|
|
90
|
+
*/
|
|
91
|
+
export const convertUtcTime = function (dateTime) {
|
|
92
|
+
const tz = process.env.TOGGL_TIMEZONE || 'America/New_York'
|
|
93
|
+
return dayjs(dateTime).tz(tz).format('YYYY-MM-DD HH:mm')
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export const appName = 'toggl-cli-node'
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Displays a time entry on the console
|
|
100
|
+
* @param {TimeEntry} timeEntry
|
|
101
|
+
*/
|
|
102
|
+
export const displayTimeEntry = async function (timeEntry) {
|
|
103
|
+
if (!timeEntry) {
|
|
104
|
+
console.log('There is no time entry running!')
|
|
105
|
+
} else {
|
|
106
|
+
console.info(`${timeEntry.description} #${timeEntry.id}`)
|
|
107
|
+
console.info(`Billable: ${timeEntry.billable}`)
|
|
108
|
+
|
|
109
|
+
// TODO this should be abstracted for reuse
|
|
110
|
+
const startTime = dayjs.unix(timeEntry.duration * -1)
|
|
111
|
+
const duration = dayjs().diff(startTime, 's')
|
|
112
|
+
const durationFormatted = dayjs.duration(duration * 1000).format('H[h] m[m]')
|
|
113
|
+
|
|
114
|
+
console.info(`Duration: ${durationFormatted}`)
|
|
115
|
+
|
|
116
|
+
const projects = await getProjects(timeEntry.wid)
|
|
117
|
+
const project = projects.find(x => x.id == timeEntry.pid)
|
|
118
|
+
|
|
119
|
+
console.info(`Project: ${project?.name} (#${timeEntry.pid})`);
|
|
120
|
+
|
|
121
|
+
const tz = process.env.TOGGL_TIMEZONE || 'America/New_York'
|
|
122
|
+
const startTimeFormatted = dayjs(timeEntry.start).tz(tz).format('YYYY-MM-DD HH:mm')
|
|
123
|
+
const stopTimeFormatted = dayjs(timeEntry.stop).tz(tz).format('YYYY-MM-DD HH:mm')
|
|
124
|
+
|
|
125
|
+
console.info(`Start: ${startTimeFormatted}`)
|
|
126
|
+
console.info(`Stop: ${stopTimeFormatted}`) // This will always be blank for the current entry, but will be useful for a time entry
|
|
127
|
+
// console.info(`Tags: `); // Not going to include these in the near term
|
|
128
|
+
// console.info(`Task: `); // Not going to include these in the near term
|
|
129
|
+
|
|
130
|
+
const workspace = await getWorkspace()
|
|
131
|
+
console.info(`Workspace: ${workspace.name} (#${timeEntry.wid})`)
|
|
132
|
+
}
|
|
133
|
+
}
|