feat: multi-person assignment for tasks and calendar events
- DB migration v32: task_assignments and event_assignments join tables with CASCADE delete; existing assigned_to data migrated automatically - Tasks API: accepts assigned_to as array, returns assigned_users[] with json_group_array; filter uses EXISTS on task_assignments - Calendar API: same pattern via event_assignments; serializeEvent includes assigned_users array - Recurring task completion copies all assignments to the new instance - Frontend: shared UserMultiSelect component with avatar stack display (renderAvatarStack, renderUserMultiSelect, getSelectedUserIds, bindUserMultiSelect); tasks.js and calendar.js use it in modals and card/agenda views - CSS: user-multi-select.css with avatar-stack and user-ms classes - 14 new tests covering CRUD, JSON aggregation, EXISTS filter, and CASCADE behavior for both task and event assignments Closes #125
This commit is contained in:
@@ -252,6 +252,17 @@ const MIGRATIONS_SQL = {
|
||||
CREATE INDEX IF NOT EXISTS idx_birthdays_calendar_ref ON birthdays(calendar_event_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_api_tokens_hash ON api_tokens(token_hash);
|
||||
CREATE INDEX IF NOT EXISTS idx_api_tokens_created_by ON api_tokens(created_by);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS task_assignments (
|
||||
task_id INTEGER NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
|
||||
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
PRIMARY KEY (task_id, user_id)
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS event_assignments (
|
||||
event_id INTEGER NOT NULL REFERENCES calendar_events(id) ON DELETE CASCADE,
|
||||
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
PRIMARY KEY (event_id, user_id)
|
||||
);
|
||||
`,
|
||||
2: `
|
||||
CREATE TABLE IF NOT EXISTS sync_config (
|
||||
|
||||
Reference in New Issue
Block a user