@beauraines/toggl-cli 2.2.0 → 2.3.0

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/CHANGELOG.md CHANGED
@@ -2,6 +2,20 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
+ ## [2.3.0](https://github.com/beauraines/toggl-cli/compare/v2.2.1...v2.3.0) (2024-05-25)
6
+
7
+
8
+ ### Features
9
+
10
+ * Add time entry, include start with create ([#165](https://github.com/beauraines/toggl-cli/issues/165)) ([d73f181](https://github.com/beauraines/toggl-cli/commit/d73f181115ea0a92e4e1427d0f2c77337ef55132))
11
+
12
+ ### [2.2.1](https://github.com/beauraines/toggl-cli/compare/v2.2.0...v2.2.1) (2024-05-17)
13
+
14
+
15
+ ### Bug Fixes
16
+
17
+ * **deps:** bump cli-table3 from 0.6.4 to 0.6.5 ([#163](https://github.com/beauraines/toggl-cli/issues/163)) ([1cac277](https://github.com/beauraines/toggl-cli/commit/1cac2778e77a2f4c54deab16287fcd3ece4a5807))
18
+
5
19
  ## [2.2.0](https://github.com/beauraines/toggl-cli/compare/v2.1.8...v2.2.0) (2024-05-15)
6
20
 
7
21
 
@@ -0,0 +1,68 @@
1
+ /* eslint-disable no-unused-expressions */
2
+ import Client from '../client.js'
3
+ import { defaultWorkspaceId, getProjectByName, getProjectById, appName, displayTimeEntry, parseTime } from '../utils.js'
4
+ import dayjs from 'dayjs'
5
+ import debugClient from 'debug'
6
+ import utc from 'dayjs/plugin/utc.js'
7
+ import timezone from 'dayjs/plugin/timezone.js'
8
+ dayjs.extend(utc)
9
+ dayjs.extend(timezone)
10
+
11
+ const debug = debugClient('toggl-cli-add');
12
+
13
+ export const command = 'add [startTime] [endTime] [description]'
14
+ export const desc = 'Create a time entry. Time must be parsable by dayjs, e.g. 4:50PM or \'12:00 AM\'.'
15
+
16
+ export const builder = {
17
+ d: { alias: ['description'], describe: 'Time entry name', type: 'string:', demandOption: true},
18
+ p: { alias: ['projectId', 'project'], describe: 'The case insensitive project name or project id.', type: 'string', demandOption: false },
19
+ s: { alias: ['start', 'startTime'], describe: 'The start time for the task, e.g. 13:00 12:45AM.', type: 'string', demandOption: false },
20
+ e: { alias: ['end', 'endTime'], describe: 'The end time for the task, e.g. 13:00 12:45AM.', type: 'string', demandOption: false }
21
+ }
22
+
23
+ export const handler = async function (argv) {
24
+ const client = await Client()
25
+ const params = {}
26
+
27
+ params.workspace_id = +defaultWorkspaceId
28
+ let project
29
+ if (argv.projectId) {
30
+ if (isNaN(argv.projectId)) {
31
+ project = await getProjectByName(params.workspace_id, argv.projectId)
32
+ } else {
33
+ project = await getProjectById(params.workspace_id, argv.projectId)
34
+ }
35
+ }
36
+
37
+ let startTime, endTime
38
+ if (dayjs(argv.startTime).isValid()) {
39
+ startTime = argv.startTime
40
+ } else {
41
+ // Parse the time and set it based upon the current time
42
+ startTime = parseTime(argv.startTime)
43
+ }
44
+
45
+ if (dayjs(argv.endTime).isValid()) {
46
+ endTime = argv.endTime
47
+ } else {
48
+ // Parse the time and set it based upon the current time
49
+ endTime = parseTime(argv.endTime)
50
+ }
51
+
52
+ params.created_with = appName
53
+ project ? params.project_id = +project.id : undefined
54
+ startTime ? params.start = startTime.toISOString() : undefined
55
+ endTime ? params.stop = endTime.toISOString() : undefined
56
+ if (startTime || endTime) {
57
+ const startTimeUnix = startTime.unix()
58
+ const endTimeUnix = endTime.unix()
59
+ let duration = endTimeUnix - startTimeUnix
60
+ duration = endTime ? duration : startTimeUnix * -1
61
+ params.duration = duration
62
+ }
63
+ argv.description ? params.description = argv.description : undefined
64
+ debug(params)
65
+ const timeEntry = await client.timeEntries.create(params)
66
+ await displayTimeEntry(timeEntry)
67
+ }
68
+
package/cmds/edit.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  /* eslint-disable no-unused-expressions */
2
2
  import Client from '../client.js'
3
- import { defaultWorkspaceId, getProjectByName, getProjectById, appName, displayTimeEntry } from '../utils.js'
3
+ import { defaultWorkspaceId, getProjectByName, getProjectById, appName, displayTimeEntry, parseTime } from '../utils.js'
4
4
  import dayjs from 'dayjs'
5
5
  import debugClient from 'debug'
6
6
  import utc from 'dayjs/plugin/utc.js'
@@ -73,21 +73,3 @@ export const handler = async function (argv) {
73
73
  const timeEntry = await client.timeEntries.update(currentTimeEntry.id, params)
74
74
  await displayTimeEntry(timeEntry)
75
75
  }
76
-
77
- /**
78
- * Parses a timelike string into a dayjs object of the current date and that time
79
- * @param {string} timeString timelike string e.g. 4:50PM '12:00 AM' etc.
80
- * @returns {object} dayjs object
81
- */
82
- function parseTime (timeString) {
83
- let h, m
84
- // Assumes time in format 4:50 PM
85
- const time = timeString.split(':', 2)
86
- h = time[0]
87
- m = time[1].match(/[0-9]+/)[0]
88
- if (timeString.match(/PM/i) && h <= 12) {
89
- // + in front of string converts to a number, cool!
90
- h = +h + 12
91
- }
92
- return dayjs().hour(h).minute(m).second(0)
93
- }
package/cmds/index.mjs CHANGED
@@ -8,6 +8,7 @@ import * as edit from './edit.mjs'
8
8
  import * as web from './web.mjs'
9
9
  import * as startTimeEntry from './startTimeEntry.mjs'
10
10
  import * as stopTimeEntry from './stopTimeEntry.mjs'
11
+ import * as addTimeEntry from './addTimeEntry.mjs'
11
12
  import * as removeTimeEntry from './removeTimeEntry.mjs'
12
13
  import * as today from './today.mjs'
13
14
  import * as weekly from './weekly.mjs'
@@ -21,6 +22,7 @@ export const commands = [
21
22
  projects,
22
23
  startTimeEntry,
23
24
  stopTimeEntry,
25
+ addTimeEntry,
24
26
  removeTimeEntry,
25
27
  today,
26
28
  web,
@@ -1,4 +1,5 @@
1
- import { defaultWorkspaceId,getProjectByName, createTimeEntry, getProjectById, defaultProjectId } from '../utils.js'
1
+ import { defaultWorkspaceId, getProjectByName, createTimeEntry, getProjectById, defaultProjectId, parseTime } from '../utils.js'
2
+ import dayjs from 'dayjs'
2
3
 
3
4
  export const command = 'start'
4
5
  export const desc = 'Starts a time entry'
@@ -10,7 +11,8 @@ export const builder = {
10
11
  },
11
12
  p: { alias: ['projectId', 'project'], describe: 'The case insensitive project name or project id.', type: 'string', demandOption: false },
12
13
  // TODO default to default workspace
13
- w: { alias: ['workspaceId', 'workspace'], describe: 'The case insensitive workspace name or workspace id.', type: 'number', demandOption: false }
14
+ w: { alias: ['workspaceId', 'workspace'], describe: 'The case insensitive workspace name or workspace id.', type: 'number', demandOption: false },
15
+ s: { alias: ['start', 'startTime'], describe: 'The start time for the task, e.g. 13:00 12:45AM.', type: 'string', demandOption: false },
14
16
  }
15
17
 
16
18
  export const handler = async function (argv) {
@@ -31,6 +33,19 @@ export const handler = async function (argv) {
31
33
  }
32
34
  }
33
35
 
36
+ if (argv.startTime) {
37
+ let startTime;
38
+ if (dayjs(argv.startTime).isValid()) {
39
+ startTime = argv.startTime
40
+ } else {
41
+ // Parse the time and set it based upon the current time
42
+ startTime = parseTime(argv.startTime)
43
+ }
44
+
45
+ params.start = startTime.toISOString()
46
+ params.duration = -1
47
+ }
48
+
34
49
  params.projectId = project?.id || defaultProjectId || null
35
50
  // TODO check for invalid projectId or catch the error when creating fails
36
51
  const timeEntry = await createTimeEntry(params)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@beauraines/toggl-cli",
3
- "version": "2.2.0",
3
+ "version": "2.3.0",
4
4
  "description": "CLI client for Toggl Time Tracker",
5
5
  "main": "cli.js",
6
6
  "bin": {
package/utils.js CHANGED
@@ -53,7 +53,7 @@ export const createTimeEntry = async function (params) {
53
53
  description: params.description,
54
54
  workspace_id: +params.workspaceId,
55
55
  project_id: +params.projectId,
56
- start: dayjs().toISOString(),
56
+ start: params.start ? params.start : dayjs().toISOString(),
57
57
  duration: -1 * dayjs().unix(),
58
58
  created_with: appName,
59
59
  at: dayjs().toISOString()
@@ -113,11 +113,15 @@ export const displayTimeEntry = async function (timeEntry) {
113
113
  console.info(`${chalk.blueBright(timeEntry.description ? timeEntry.description : 'no description')} ${chalk.yellow('#'+timeEntry.id)}`)
114
114
  console.info(`Billable: ${chalk.gray(timeEntry.billable)}`)
115
115
 
116
- // TODO this should be abstracted for reuse
117
- const startTime = dayjs.unix(timeEntry.duration * -1)
118
- const duration = dayjs().diff(startTime, 's')
119
- const durationFormatted = dayjs.duration(duration * 1000).format('H[h] m[m]')
116
+ let stopTime;
117
+ if (timeEntry.stop == null) {
118
+ stopTime = dayjs()
119
+ } else {
120
+ stopTime = dayjs(timeEntry.stop)
121
+ }
120
122
 
123
+ const duration = stopTime.diff(dayjs(timeEntry.start))
124
+ const durationFormatted = dayjs.duration(duration).format('H[h] m[m]')
121
125
  console.info(`Duration: ${chalk.green(durationFormatted)}`)
122
126
 
123
127
  const projects = await getProjects(timeEntry.wid)
@@ -138,3 +142,23 @@ export const displayTimeEntry = async function (timeEntry) {
138
142
  console.info(`Workspace: ${workspace.name} (#${timeEntry.wid})`)
139
143
  }
140
144
  }
145
+
146
+ /**
147
+ * Parses a timelike string into a dayjs object of the current date and that time
148
+ * @param {string} timeString timelike string e.g. 4:50PM '12:00 AM' etc.
149
+ * @returns {object} dayjs object
150
+ */
151
+ export function parseTime (timeString) {
152
+ let h, m
153
+ // Assumes time in format 4:50 PM
154
+ const time = timeString.split(':', 2)
155
+ h = time[0]
156
+ m = time[1].match(/[0-9]+/)[0]
157
+ if (timeString.match(/PM/i) && h <= 12) {
158
+ // + in front of string converts to a number, cool!
159
+ h = +h + 12
160
+ } else if (h == 12) {
161
+ h = 0
162
+ }
163
+ return dayjs().hour(h).minute(m).second(0).millisecond(0)
164
+ }