diff --git a/CHANGELOG.md b/CHANGELOG.md index 12cd735..b6f2742 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,14 @@ El formato está basado en [Keep a Changelog](https://keepachangelog.com/es-ES/1 > Las entradas entre la 0.6.0 y la 1.4.0 se reconstruyeron a posteriori a partir del historial de git, agrupadas por los saltos de versión que realmente ocurrieron en `package.json`. La 1.1.0 nunca existió: se pasó directamente de la 1.0.0 a la 1.2.0. +## [1.26.3] - 2026-08-23 + +### Fixed + +- **No se podían poner horas estimadas al crear un ticket**, y el hueco estaba en las dos capas: el formulario no tenía el campo y `IssueService.create()` ni siquiera incluía la columna en su `INSERT`, mientras `update()` sí la tenía entre sus campos permitidos. La única forma de estimar era crear el ticket y volver a abrirlo. `due_date`, un campo idéntico en dificultad, sí estaba: fue un olvido, no una decisión. +- El número se limpia en el servidor. Llega de fuera, así que un texto, un negativo o un `Infinity` habrían entrado tal cual en una columna `REAL` y habrían salido después en los totales del sprint. +- Dos mensajes del formulario que estaban escritos en inglés a mano —«Title is required» y «Creating...»— pasan por el diccionario. + ## [1.26.2] - 2026-08-20 ### Fixed diff --git a/package-lock.json b/package-lock.json index 7980346..a639acc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "forge-js", - "version": "1.26.2", + "version": "1.26.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "forge-js", - "version": "1.26.2", + "version": "1.26.3", "dependencies": { "@astrojs/check": "^0.9.10", "@astrojs/node": "^11.1.2", diff --git a/package.json b/package.json index 5177990..c91332c 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "forge-js", "type": "module", - "version": "1.26.2", + "version": "1.26.3", "engines": { "node": ">=22.12.0" }, diff --git a/src/i18n/en/board.ts b/src/i18n/en/board.ts index 43ebec5..ce10387 100644 --- a/src/i18n/en/board.ts +++ b/src/i18n/en/board.ts @@ -93,5 +93,7 @@ export const en = { 'sprint.err_delete': 'The sprint could not be deleted.', 'board.sprint_actions': 'Sprint', 'board.status_filter': 'Filter by status', + 'issue.err_title': 'The ticket needs a title.', + 'issue.creating': 'Creating…', 'card.move_to': 'Move to', } as const; diff --git a/src/i18n/es/board.ts b/src/i18n/es/board.ts index d447859..74e7846 100644 --- a/src/i18n/es/board.ts +++ b/src/i18n/es/board.ts @@ -93,5 +93,7 @@ export const es = { 'sprint.err_delete': 'No se ha podido borrar el sprint.', 'board.sprint_actions': 'Sprint', 'board.status_filter': 'Filtrar por estado', + 'issue.err_title': 'El ticket necesita un título.', + 'issue.creating': 'Creando…', 'card.move_to': 'Mover a', } as const; diff --git a/src/lib/IssueService.ts b/src/lib/IssueService.ts index 6e0a9c3..40d5305 100644 --- a/src/lib/IssueService.ts +++ b/src/lib/IssueService.ts @@ -127,10 +127,25 @@ export class IssueService { position = lastIssue.position + 100000; } + /** + * Las horas estimadas se insertan al crear, no solo al editar. + * + * Faltaban en este `INSERT` mientras `update()` sí las tenía entre sus + * `allowedFields`, así que la única forma de estimar un ticket era crearlo + * y volver a abrirlo. `due_date`, que es un campo idéntico en dificultad, + * sí estaba: fue un olvido, no una decisión. + * + * Se limpia aquí porque el número llega de fuera: un texto, un negativo o + * un `Infinity` entrarían tal cual en una columna REAL y saldrían luego en + * los totales del sprint. + */ + const estimadas = Number(data.estimated_hours); + const horas = Number.isFinite(estimadas) && estimadas > 0 ? estimadas : 0; + db.prepare(` - INSERT INTO issues (id, workspace_id, sprint_id, title, type, status, reporter_id, position, assignee_id, due_date, description) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) - `).run(issueId, data.workspace_id, data.sprint_id || null, data.title, data.type || 'task', status, userId, position, data.assignee_id || null, data.due_date || null, data.description || null); + INSERT INTO issues (id, workspace_id, sprint_id, title, type, status, reporter_id, position, assignee_id, due_date, description, estimated_hours) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + `).run(issueId, data.workspace_id, data.sprint_id || null, data.title, data.type || 'task', status, userId, position, data.assignee_id || null, data.due_date || null, data.description || null, horas); // Avisar a quien queda asignado **al crear**, no solo al editar después. // diff --git a/src/pages/w/[sys_tag]/board.astro b/src/pages/w/[sys_tag]/board.astro index 7d2eeef..7ea4ebd 100644 --- a/src/pages/w/[sys_tag]/board.astro +++ b/src/pages/w/[sys_tag]/board.astro @@ -437,6 +437,8 @@ const metaDescription = `${workspace.name} board on Forge OS. Track issues, spri data-t-deactivate={t('sprint.deactivate_confirm')} data-t-err-deactivate={t('sprint.err_deactivate')} data-t-err-create={t('issue.err_create')} + data-t-err-title={t('issue.err_title')} + data-t-creating={t('issue.creating')} data-t-err-delete={t('sprint.err_delete')} data-t-err={t('sprint.err_close')} data-t-no-target={t('sprint.err_no_target')} @@ -513,6 +515,10 @@ const metaDescription = `${workspace.name} board on Forge OS. Track issues, spri +