clocktopus 1.2.0 → 1.2.1
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/dist/dashboard/routes/timer.js +30 -3
- package/dist/lib/db.js +9 -1
- package/package.json +1 -1
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { Hono } from 'hono';
|
|
2
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
2
3
|
import { Clockify } from '../../clockify.js';
|
|
3
|
-
import { completeLatestSession } from '../../lib/db.js';
|
|
4
|
+
import { completeLatestSession, getOpenSession, logSessionStart } from '../../lib/db.js';
|
|
5
|
+
import { stopJiraTimer } from '../../lib/jira.js';
|
|
6
|
+
function extractJiraTicket(description) {
|
|
7
|
+
const match = description.match(/\b([A-Z][A-Z0-9]+-\d+)\b/);
|
|
8
|
+
return match?.[1];
|
|
9
|
+
}
|
|
4
10
|
const timerRoutes = new Hono();
|
|
5
11
|
timerRoutes.get('/timer/active', async (c) => {
|
|
6
12
|
try {
|
|
@@ -11,11 +17,19 @@ timerRoutes.get('/timer/active', async (c) => {
|
|
|
11
17
|
const timer = await clockify.getActiveTimer(user.defaultWorkspace, user.id);
|
|
12
18
|
if (!timer)
|
|
13
19
|
return c.json({ active: false });
|
|
20
|
+
// Sync externally-started timers (e.g. from Clockify app or Jira plugin) to DB
|
|
21
|
+
const timerStart = timer.timeInterval.start;
|
|
22
|
+
const openSession = getOpenSession();
|
|
23
|
+
const alreadyTracked = openSession && openSession.startedAt.slice(0, 19) === timerStart.slice(0, 19);
|
|
24
|
+
if (!alreadyTracked) {
|
|
25
|
+
const jiraTicket = extractJiraTicket(timer.description ?? '');
|
|
26
|
+
logSessionStart(timer.id ?? uuidv4(), timer.projectId, timer.description ?? '', timerStart, jiraTicket);
|
|
27
|
+
}
|
|
14
28
|
return c.json({
|
|
15
29
|
active: true,
|
|
16
30
|
description: timer.description,
|
|
17
31
|
projectId: timer.projectId,
|
|
18
|
-
start:
|
|
32
|
+
start: timerStart,
|
|
19
33
|
});
|
|
20
34
|
}
|
|
21
35
|
catch {
|
|
@@ -47,10 +61,23 @@ timerRoutes.post('/timer/stop', async (c) => {
|
|
|
47
61
|
const user = await clockify.getUser();
|
|
48
62
|
if (!user)
|
|
49
63
|
return c.json({ ok: false, error: 'Could not connect to Clockify.' }, 500);
|
|
64
|
+
const openSession = getOpenSession();
|
|
50
65
|
const result = await clockify.stopTimer(user.defaultWorkspace, user.id);
|
|
51
66
|
if (!result)
|
|
52
67
|
return c.json({ ok: false, error: 'Failed to stop timer.' }, 500);
|
|
53
|
-
|
|
68
|
+
const completedAt = new Date().toISOString();
|
|
69
|
+
completeLatestSession(completedAt, false);
|
|
70
|
+
if (openSession?.jiraTicket) {
|
|
71
|
+
const timeSpentSeconds = Math.round((new Date(completedAt).getTime() - new Date(openSession.startedAt).getTime()) / 1000);
|
|
72
|
+
if (timeSpentSeconds >= 60) {
|
|
73
|
+
try {
|
|
74
|
+
await stopJiraTimer(openSession.jiraTicket, timeSpentSeconds);
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
console.error('Error stopping Jira timer:', err);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
54
81
|
return c.json({ ok: true });
|
|
55
82
|
}
|
|
56
83
|
catch {
|
package/dist/lib/db.js
CHANGED
|
@@ -105,7 +105,7 @@ export function getLatestToken() {
|
|
|
105
105
|
}
|
|
106
106
|
export function logSessionStart(id, projectId, description, startedAt, jiraTicket) {
|
|
107
107
|
const db = getDb();
|
|
108
|
-
const stmt = db.prepare('INSERT INTO sessions (id, projectId, description, startedAt, isAutoCompleted, jiraTicket) VALUES (?, ?, ?, ?, ?, ?)');
|
|
108
|
+
const stmt = db.prepare('INSERT OR IGNORE INTO sessions (id, projectId, description, startedAt, isAutoCompleted, jiraTicket) VALUES (?, ?, ?, ?, ?, ?)');
|
|
109
109
|
stmt.run(id, projectId, description, startedAt, 0, jiraTicket ?? null);
|
|
110
110
|
}
|
|
111
111
|
export function completeLatestSession(completedAt, isAutoCompleted = false) {
|
|
@@ -130,6 +130,14 @@ export function getSessionCount() {
|
|
|
130
130
|
const row = stmt.get();
|
|
131
131
|
return row.count;
|
|
132
132
|
}
|
|
133
|
+
export function getOpenSession() {
|
|
134
|
+
const db = getDb();
|
|
135
|
+
const stmt = db.prepare('SELECT * FROM sessions WHERE completedAt IS NULL ORDER BY startedAt DESC LIMIT 1');
|
|
136
|
+
const row = stmt.get();
|
|
137
|
+
if (!row)
|
|
138
|
+
return null;
|
|
139
|
+
return SessionSchema.parse(row);
|
|
140
|
+
}
|
|
133
141
|
export function getLatestSession() {
|
|
134
142
|
const db = getDb();
|
|
135
143
|
const stmt = db.prepare(`
|