feat: Add is_system column to notes and update task note handling for system notes
This commit is contained in:
@@ -28,7 +28,7 @@ export async function GET(req) {
|
|||||||
// POST: Add a note to a task
|
// POST: Add a note to a task
|
||||||
export async function POST(req) {
|
export async function POST(req) {
|
||||||
try {
|
try {
|
||||||
const { task_id, note } = await req.json();
|
const { task_id, note, is_system } = await req.json();
|
||||||
|
|
||||||
if (!task_id || !note) {
|
if (!task_id || !note) {
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
@@ -37,7 +37,7 @@ export async function POST(req) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
addNoteToTask(task_id, note);
|
addNoteToTask(task_id, note, is_system);
|
||||||
return NextResponse.json({ success: true });
|
return NextResponse.json({ success: true });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error adding task note:", error);
|
console.error("Error adding task note:", error);
|
||||||
|
|||||||
@@ -516,9 +516,7 @@ export default function ProjectTasksSection({ projectId }) {
|
|||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
)}
|
)} {/* Notes row (expandable) */}
|
||||||
|
|
||||||
{/* Notes row (expandable) */}
|
|
||||||
{expandedNotes[task.id] && (
|
{expandedNotes[task.id] && (
|
||||||
<tr className="bg-gray-50">
|
<tr className="bg-gray-50">
|
||||||
<td colSpan="6" className="px-4 py-4">
|
<td colSpan="6" className="px-4 py-4">
|
||||||
@@ -534,9 +532,20 @@ export default function ProjectTasksSection({ projectId }) {
|
|||||||
{taskNotes[task.id].map((note) => (
|
{taskNotes[task.id].map((note) => (
|
||||||
<div
|
<div
|
||||||
key={note.note_id}
|
key={note.note_id}
|
||||||
className="bg-white p-3 rounded border flex justify-between items-start"
|
className={`p-3 rounded border flex justify-between items-start ${
|
||||||
|
note.is_system
|
||||||
|
? 'bg-blue-50 border-blue-200'
|
||||||
|
: 'bg-white border-gray-200'
|
||||||
|
}`}
|
||||||
>
|
>
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
|
<div className="flex items-center gap-2 mb-1">
|
||||||
|
{note.is_system && (
|
||||||
|
<span className="px-2 py-1 text-xs bg-blue-100 text-blue-700 rounded-full font-medium">
|
||||||
|
System
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
<p className="text-sm text-gray-800">
|
<p className="text-sm text-gray-800">
|
||||||
{note.note}
|
{note.note}
|
||||||
</p>
|
</p>
|
||||||
@@ -550,6 +559,7 @@ export default function ProjectTasksSection({ projectId }) {
|
|||||||
).toLocaleTimeString()}
|
).toLocaleTimeString()}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
{!note.is_system && (
|
||||||
<button
|
<button
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
handleDeleteNote(
|
handleDeleteNote(
|
||||||
@@ -562,6 +572,7 @@ export default function ProjectTasksSection({ projectId }) {
|
|||||||
>
|
>
|
||||||
×
|
×
|
||||||
</button>
|
</button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -137,7 +137,6 @@ export default function initializeDatabase() {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Column migration already done or geo_info doesn't exist, ignore error
|
// Column migration already done or geo_info doesn't exist, ignore error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Migration: Add date_started column to project_tasks table
|
// Migration: Add date_started column to project_tasks table
|
||||||
try {
|
try {
|
||||||
db.exec(`
|
db.exec(`
|
||||||
@@ -146,4 +145,13 @@ export default function initializeDatabase() {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Column already exists, ignore error
|
// Column already exists, ignore error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Migration: Add is_system column to notes table
|
||||||
|
try {
|
||||||
|
db.exec(`
|
||||||
|
ALTER TABLE notes ADD COLUMN is_system INTEGER DEFAULT 0;
|
||||||
|
`);
|
||||||
|
} catch (e) {
|
||||||
|
// Column already exists, ignore error
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,10 +19,11 @@ export function getNotesByTaskId(task_id) {
|
|||||||
.all(task_id);
|
.all(task_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function addNoteToTask(task_id, note) {
|
export function addNoteToTask(task_id, note, is_system = false) {
|
||||||
db.prepare(`INSERT INTO notes (task_id, note) VALUES (?, ?)`).run(
|
db.prepare(`INSERT INTO notes (task_id, note, is_system) VALUES (?, ?, ?)`).run(
|
||||||
task_id,
|
task_id,
|
||||||
note
|
note,
|
||||||
|
is_system ? 1 : 0
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import db from "../db.js";
|
import db from "../db.js";
|
||||||
|
import { addNoteToTask } from "./notes.js";
|
||||||
|
|
||||||
// Get all task templates (for dropdown selection)
|
// Get all task templates (for dropdown selection)
|
||||||
export function getAllTaskTemplates() {
|
export function getAllTaskTemplates() {
|
||||||
@@ -59,25 +60,33 @@ export function getProjectTasks(projectId) {
|
|||||||
|
|
||||||
// Create a new project task
|
// Create a new project task
|
||||||
export function createProjectTask(data) {
|
export function createProjectTask(data) {
|
||||||
|
let result;
|
||||||
|
let taskName;
|
||||||
|
|
||||||
if (data.task_template_id) {
|
if (data.task_template_id) {
|
||||||
// Creating from template - explicitly set custom_max_wait_days to NULL so COALESCE uses template value
|
// Creating from template - explicitly set custom_max_wait_days to NULL so COALESCE uses template value
|
||||||
const stmt = db.prepare(`
|
const stmt = db.prepare(`
|
||||||
INSERT INTO project_tasks (project_id, task_template_id, custom_max_wait_days, status, priority)
|
INSERT INTO project_tasks (project_id, task_template_id, custom_max_wait_days, status, priority)
|
||||||
VALUES (?, ?, NULL, ?, ?)
|
VALUES (?, ?, NULL, ?, ?)
|
||||||
`);
|
`);
|
||||||
return stmt.run(
|
result = stmt.run(
|
||||||
data.project_id,
|
data.project_id,
|
||||||
data.task_template_id,
|
data.task_template_id,
|
||||||
data.status || "pending",
|
data.status || "pending",
|
||||||
data.priority || "normal"
|
data.priority || "normal"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Get the template name for the log
|
||||||
|
const templateStmt = db.prepare("SELECT name FROM tasks WHERE task_id = ?");
|
||||||
|
const template = templateStmt.get(data.task_template_id);
|
||||||
|
taskName = template?.name || "Unknown template";
|
||||||
} else {
|
} else {
|
||||||
// Creating custom task
|
// Creating custom task
|
||||||
const stmt = db.prepare(`
|
const stmt = db.prepare(`
|
||||||
INSERT INTO project_tasks (project_id, custom_task_name, custom_max_wait_days, custom_description, status, priority)
|
INSERT INTO project_tasks (project_id, custom_task_name, custom_max_wait_days, custom_description, status, priority)
|
||||||
VALUES (?, ?, ?, ?, ?, ?)
|
VALUES (?, ?, ?, ?, ?, ?)
|
||||||
`);
|
`);
|
||||||
return stmt.run(
|
result = stmt.run(
|
||||||
data.project_id,
|
data.project_id,
|
||||||
data.custom_task_name,
|
data.custom_task_name,
|
||||||
data.custom_max_wait_days || 0,
|
data.custom_max_wait_days || 0,
|
||||||
@@ -85,31 +94,50 @@ export function createProjectTask(data) {
|
|||||||
data.status || "pending",
|
data.status || "pending",
|
||||||
data.priority || "normal"
|
data.priority || "normal"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
taskName = data.custom_task_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add system note for task creation
|
||||||
|
if (result.lastInsertRowid) {
|
||||||
|
const priority = data.priority || "normal";
|
||||||
|
const status = data.status || "pending";
|
||||||
|
const logMessage = `Task "${taskName}" created with priority: ${priority}, status: ${status}`;
|
||||||
|
addNoteToTask(result.lastInsertRowid, logMessage, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update project task status
|
// Update project task status
|
||||||
export function updateProjectTaskStatus(taskId, status) {
|
export function updateProjectTaskStatus(taskId, status) {
|
||||||
// First get the current status to check if we're transitioning from pending to in_progress
|
// First get the current task details for logging
|
||||||
const getCurrentStatus = db.prepare(
|
const getCurrentTask = db.prepare(`
|
||||||
"SELECT status FROM project_tasks WHERE id = ?"
|
SELECT
|
||||||
);
|
pt.status,
|
||||||
const currentTask = getCurrentStatus.get(taskId);
|
COALESCE(pt.custom_task_name, t.name) as task_name
|
||||||
|
FROM project_tasks pt
|
||||||
|
LEFT JOIN tasks t ON pt.task_template_id = t.task_id
|
||||||
|
WHERE pt.id = ?
|
||||||
|
`);
|
||||||
|
const currentTask = getCurrentTask.get(taskId);
|
||||||
|
|
||||||
|
if (!currentTask) {
|
||||||
|
throw new Error(`Task with ID ${taskId} not found`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const oldStatus = currentTask.status;
|
||||||
let stmt;
|
let stmt;
|
||||||
|
let result;
|
||||||
|
|
||||||
if (
|
if (oldStatus === "pending" && status === "in_progress") {
|
||||||
currentTask &&
|
|
||||||
currentTask.status === "pending" &&
|
|
||||||
status === "in_progress"
|
|
||||||
) {
|
|
||||||
// Starting a task - set date_started
|
// Starting a task - set date_started
|
||||||
stmt = db.prepare(`
|
stmt = db.prepare(`
|
||||||
UPDATE project_tasks
|
UPDATE project_tasks
|
||||||
SET status = ?, date_started = CURRENT_TIMESTAMP
|
SET status = ?, date_started = CURRENT_TIMESTAMP
|
||||||
WHERE id = ?
|
WHERE id = ?
|
||||||
`);
|
`);
|
||||||
return stmt.run(status, taskId);
|
result = stmt.run(status, taskId);
|
||||||
} else {
|
} else {
|
||||||
// Just updating status without changing date_started
|
// Just updating status without changing date_started
|
||||||
stmt = db.prepare(`
|
stmt = db.prepare(`
|
||||||
@@ -117,8 +145,17 @@ export function updateProjectTaskStatus(taskId, status) {
|
|||||||
SET status = ?
|
SET status = ?
|
||||||
WHERE id = ?
|
WHERE id = ?
|
||||||
`);
|
`);
|
||||||
return stmt.run(status, taskId);
|
result = stmt.run(status, taskId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add system note for status change (only if status actually changed)
|
||||||
|
if (result.changes > 0 && oldStatus !== status) {
|
||||||
|
const taskName = currentTask.task_name || "Unknown task";
|
||||||
|
const logMessage = `Status changed from "${oldStatus}" to "${status}"`;
|
||||||
|
addNoteToTask(taskId, logMessage, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete a project task
|
// Delete a project task
|
||||||
|
|||||||
Reference in New Issue
Block a user