@latentsearch/timemachine-cli
Version:
CLI tool for TimeMachine API. Generates time entries, lists users/projects, and features an enhanced dry-run output for generation.
157 lines (156 loc) • 6.52 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createEntry = createEntry;
const chalk_1 = __importDefault(require("chalk"));
const inquirer_1 = __importDefault(require("inquirer"));
const inquirer_datepicker_prompt_1 = __importDefault(require("inquirer-datepicker-prompt"));
const ora_1 = __importDefault(require("ora"));
const luxon_1 = require("luxon");
const api_client_1 = require("../utils/api-client");
// Register the datepicker prompt type
inquirer_1.default.registerPrompt("datepicker", inquirer_datepicker_prompt_1.default);
/**
* Creates a time entry interactively
*/
async function createEntry(options) {
try {
const api = (0, api_client_1.createApiClient)(options);
// Fetch users and projects first for selection
console.log(chalk_1.default.blue("Fetching users and projects..."));
const spinner = (0, ora_1.default)("Loading data").start();
const [usersResponse, projectsResponse] = await Promise.all([
api.get("/api/users"),
api.get("/api/projects")
]);
spinner.succeed("Data loaded");
// Prepare user choices
const users = usersResponse.data.map(user => ({
name: `${user.given_name || ""} ${user.surname || ""} (${user.email || "No email"})`.trim(),
value: user.id
}));
// Group projects by company for better organization
const projectsByCompany = {};
projectsResponse.data.forEach(project => {
const companyName = project.company_name || "No Company";
if (!projectsByCompany[companyName]) {
projectsByCompany[companyName] = [];
}
projectsByCompany[companyName].push(project);
});
// Create a list of project choices with company headers
const projectChoices = [];
Object.entries(projectsByCompany).forEach(([companyName, projects]) => {
// Add company header
projectChoices.push({
name: `--- ${companyName} ---`,
value: undefined,
disabled: true
});
// Add company's projects
projects.forEach(project => {
projectChoices.push({
name: ` ${project.name}`,
value: project.id
});
});
});
// Get user input
const answers = await inquirer_1.default.prompt([
{
type: "list",
name: "userId",
message: "Select a user:",
choices: users,
pageSize: 15
},
{
type: "list",
name: "projectId",
message: "Select a project:",
choices: projectChoices,
pageSize: 20
},
{
type: "datepicker",
name: "date",
message: "Select date:",
format: ["Y", "-", "MM", "-", "DD"],
default: new Date()
},
{
type: "number",
name: "hours",
message: "Hours worked:",
default: 8,
validate: (value) => {
if (value <= 0 || value > 24) {
return "Hours must be between 0 and 24";
}
return true;
}
},
{
type: "confirm",
name: "confirm",
message: "Create this time entry?",
default: true
}
]);
if (!answers.confirm) {
console.log(chalk_1.default.yellow("Time entry creation cancelled"));
return;
}
// Format date as YYYY-MM-DD
const formattedDate = luxon_1.DateTime.fromJSDate(answers.date).toISODate();
if (!formattedDate) {
throw new Error("Invalid date format");
}
// Display selected information
console.log("\nCreating time entry with the following information:");
// Find selected user and project names for display
const selectedUser = usersResponse.data.find(u => u.id === answers.userId);
const selectedProject = projectsResponse.data.find(p => p.id === answers.projectId);
console.log(`User: ${chalk_1.default.cyan(selectedUser ? `${selectedUser.given_name} ${selectedUser.surname}` : `ID: ${answers.userId}`)}`);
console.log(`Project: ${chalk_1.default.cyan(selectedProject ? selectedProject.name : `ID: ${answers.projectId}`)}`);
console.log(`Date: ${chalk_1.default.cyan(formatDate(formattedDate))}`);
console.log(`Hours: ${chalk_1.default.cyan(answers.hours)}`);
// Submit the time entry
const submitSpinner = (0, ora_1.default)("Creating time entry...").start();
const timeEntry = {
user_id: answers.userId,
project_id: answers.projectId,
date: formattedDate,
hours_worked: answers.hours
};
const response = await api.post("/api/time_entries", timeEntry);
submitSpinner.succeed("Time entry created successfully");
// Display time entry details
console.log(chalk_1.default.green("\nTime Entry Created:"));
console.log(`ID: ${chalk_1.default.cyan(response.data.id)}`);
console.log(`User: ${chalk_1.default.cyan(response.data.user_name || 'N/A')}`);
console.log(`Project: ${chalk_1.default.cyan(response.data.project_name || 'N/A')}`);
console.log(`Date: ${chalk_1.default.cyan(formatDate(formattedDate))}`);
console.log(`Hours: ${chalk_1.default.cyan(answers.hours)}`);
}
catch (error) {
console.error(chalk_1.default.red("Error creating time entry:"), 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;
}
}