@latentsearch/timemachine-cli
Version:
CLI tool for TimeMachine API. Generates time entries, lists users/projects, and features an enhanced dry-run output for generation.
149 lines (148 loc) • 6.69 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.listEntries = listEntries;
const chalk_1 = __importDefault(require("chalk"));
const console_table_printer_1 = require("console-table-printer");
const luxon_1 = require("luxon");
const api_client_1 = require("../utils/api-client");
const resolvers_1 = require("../utils/resolvers");
/**
* Lists time entries with filtering options
*/
async function listEntries(options) {
try {
const api = (0, api_client_1.createApiClient)(options);
// Parse date inputs
const startDate = luxon_1.DateTime.fromISO(options.startDate || "");
const endDate = luxon_1.DateTime.fromISO(options.endDate || "");
const limit = parseInt(options.limit || "50", 10);
if (!startDate.isValid) {
throw new Error(`Invalid start date "${options.startDate}". Use YYYY-MM-DD format.`);
}
if (!endDate.isValid) {
throw new Error(`Invalid end date "${options.endDate}". Use YYYY-MM-DD format.`);
}
console.log(chalk_1.default.blue(`Fetching time entries from ${startDate.toISODate()} to ${endDate.toISODate()}...`));
// Build query parameters
const params = new URLSearchParams({
start_date: startDate.toISODate() || "",
end_date: endDate.toISODate() || "",
limit: limit.toString()
});
// Resolve user and project if provided
if (options.user) {
try {
const userId = await (0, resolvers_1.resolveUser)(api, options.user);
params.append("user_id", userId.toString());
console.log(chalk_1.default.blue(`Filtering by user ID: ${userId}`));
}
catch (error) {
console.warn(chalk_1.default.yellow(`Warning: ${error.message}`));
}
}
if (options.project) {
try {
const projectId = await (0, resolvers_1.resolveProject)(api, options.project);
params.append("project_id", projectId.toString());
console.log(chalk_1.default.blue(`Filtering by project ID: ${projectId}`));
}
catch (error) {
console.warn(chalk_1.default.yellow(`Warning: ${error.message}`));
}
}
// Fetch time entries
const response = await api.get(`/api/time_entries?${params.toString()}`);
if (response.data && response.data.length > 0) {
// Calculate total hours
const totalHours = response.data.reduce((sum, entry) => sum + entry.hours_worked, 0);
// Group entries by date for better visualization
const entriesByDate = {};
response.data.forEach(entry => {
if (!entriesByDate[entry.date]) {
entriesByDate[entry.date] = [];
}
entriesByDate[entry.date].push(entry);
});
// Sort dates in descending order (newest first)
const sortedDates = Object.keys(entriesByDate).sort((a, b) => luxon_1.DateTime.fromISO(b).toMillis() - luxon_1.DateTime.fromISO(a).toMillis());
// Display entries in a table
const table = new console_table_printer_1.Table({
title: `Time Entries (${response.data.length})`,
columns: [
{ name: "id", title: "ID", alignment: "right" },
{ name: "date", title: "Date" },
{ name: "user", title: "User" },
{ name: "project", title: "Project" },
{ name: "hours", title: "Hours", alignment: "right" }
]
});
// Add entries to table, grouped by date
sortedDates.forEach((date, index) => {
// Add date separator if not the first date
if (index > 0) {
table.addRow({
id: "",
date: "",
user: "",
project: "",
hours: ""
});
}
// Calculate date total
const dateTotal = entriesByDate[date].reduce((sum, entry) => sum + entry.hours_worked, 0);
// Add date header
table.addRow({
id: "",
date: chalk_1.default.bold(formatDate(date)),
user: "",
project: "",
hours: chalk_1.default.bold(dateTotal.toFixed(2))
});
// Add date's entries
entriesByDate[date].forEach(entry => {
table.addRow({
id: entry.id,
date: "", // Date already shown in group header
user: entry.user_name || "N/A",
project: entry.project_name || "N/A",
hours: entry.hours_worked.toFixed(2)
});
});
});
table.printTable();
// Print summary
console.log(chalk_1.default.green(`\nTotal Hours: ${totalHours.toFixed(2)}`));
console.log(`Average per entry: ${(totalHours / response.data.length).toFixed(2)}`);
console.log(`Date range: ${formatDate(startDate.toISODate() || "")} to ${formatDate(endDate.toISODate() || "")}`);
console.log(`Unique dates: ${sortedDates.length}`);
// If there are potentially more entries than the limit, inform the user
if (response.data.length >= limit) {
console.log(chalk_1.default.yellow(`\nNote: Results limited to ${limit} entries. Use --limit to show more.`));
}
}
else {
console.log(chalk_1.default.yellow("No time entries found matching your criteria"));
}
}
catch (error) {
console.error(chalk_1.default.red("Error fetching time entries:"), error.response?.data?.error || error.message);
if (options.verbose && error.response?.data) {
console.error(chalk_1.default.gray(JSON.stringify(error.response.data, null, 2)));
}
process.exit(1);
}
}
/**
* Formats a date string as a readable format
*/
function formatDate(dateStr) {
try {
return luxon_1.DateTime.fromISO(dateStr).toLocaleString(luxon_1.DateTime.DATE_MED_WITH_WEEKDAY);
}
catch (error) {
return dateStr;
}
}