Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
d302361
fix(enhanced-kanban): remove unused Skeleton import in EnhancedKanban…
shancds Jul 11, 2025
02d814b
refactor(task-list): enhance task row components with depth handling
chamikaJ Jul 14, 2025
1c98131
feat(task-drawer): enhance task navigation and hierarchy display
chamikaJ Jul 14, 2025
3d67145
refactor(task-list): adjust subtask indentation for improved visual h…
chamikaJ Jul 14, 2025
407dc41
feat(sort-orders): implement separate sort orders for task groupings
chamikaJ Jul 15, 2025
8f09814
Merge branch 'main' of https://github.com/Worklenz/worklenz into test…
shancds Jul 15, 2025
a1c0cef
Remove PerformanceMonitor and VirtualizedTaskList components along wi…
shancds Jul 15, 2025
6d8c475
refactor(sort-orders): remove outdated deployment and implementation …
chamikaJ Jul 15, 2025
d970cbb
feat(task-management): enhance task timer synchronization and color h…
chamikaJ Jul 15, 2025
fca8ace
Merge pull request #267 from Worklenz/feature/show-multiples-levels-o…
chamikaJ Jul 15, 2025
a03d9ef
Merge pull request #268 from Worklenz/fix/task-sort-order
chamikaJ Jul 15, 2025
8304407
Enhance task status handling and progress visualization in Kanban board
shancds Jul 15, 2025
1737120
feat(drag-and-drop): enhance task grouping updates and socket event h…
chamikaJ Jul 15, 2025
55a0028
refactor(drag-and-drop): replace console logging with error logging
chamikaJ Jul 15, 2025
c34b94c
Merge pull request #269 from shancds/test/row-kanban-board-v1.2.0
chamikaJ Jul 15, 2025
8d7d54b
Enhance TaskCard accessibility by adding title attribute to task name
shancds Jul 15, 2025
d462014
Update TaskProgressCircle to visually indicate task completion
shancds Jul 15, 2025
ba5d497
Merge pull request #270 from shancds/test/row-kanban-board-v1.2.0
chamikaJ Jul 15, 2025
0bb748c
feat(database-migrations): implement grouping-specific sort orders an…
chamikaJ Jul 15, 2025
6e911d7
feat(auth): add combined AuthAndSetupGuard for route protection
chamikaJ Jul 15, 2025
0434bbb
refactor(account-setup): update ProjectStep to use custom dispatch an…
chamikaJ Jul 15, 2025
cb5610d
feat(timer): add useTimerInitialization hook for managing running timers
chamikaJ Jul 15, 2025
833879e
feat(logout): implement cache cleanup and service worker unregistrati…
chamikaJ Jul 15, 2025
737f7ca
refactor(App): streamline cache cleanup process on logout
chamikaJ Jul 15, 2025
4788294
Merge pull request #271 from Worklenz/release/v2.1.2
chamikaJ Jul 15, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .claude/settings.local.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"permissions": {
"allow": [
"Bash(find:*)",
"Bash(npm run build:*)",
"Bash(npm run type-check:*)",
"Bash(npm run:*)"
],
"deny": []
}
}
41 changes: 41 additions & 0 deletions test_sort_fix.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
-- Test script to verify the sort order constraint fix

-- Test the helper function
SELECT get_sort_column_name('status'); -- Should return 'status_sort_order'
SELECT get_sort_column_name('priority'); -- Should return 'priority_sort_order'
SELECT get_sort_column_name('phase'); -- Should return 'phase_sort_order'
SELECT get_sort_column_name('members'); -- Should return 'member_sort_order'
SELECT get_sort_column_name('unknown'); -- Should return 'status_sort_order' (default)

-- Test bulk update function (example - would need real project_id and task_ids)
/*
SELECT update_task_sort_orders_bulk(
'[
{"task_id": "example-uuid", "sort_order": 1, "status_id": "status-uuid"},
{"task_id": "example-uuid-2", "sort_order": 2, "status_id": "status-uuid"}
]'::json,
'status'
);
*/

-- Verify that sort_order constraint still exists and works
SELECT
tc.constraint_name,
tc.table_name,
kcu.column_name
FROM information_schema.table_constraints tc
JOIN information_schema.key_column_usage kcu
ON tc.constraint_name = kcu.constraint_name
WHERE tc.constraint_name = 'tasks_sort_order_unique';

-- Check that new sort order columns don't have unique constraints (which is correct)
SELECT
tc.constraint_name,
tc.table_name,
kcu.column_name
FROM information_schema.table_constraints tc
JOIN information_schema.key_column_usage kcu
ON tc.constraint_name = kcu.constraint_name
WHERE kcu.table_name = 'tasks'
AND kcu.column_name IN ('status_sort_order', 'priority_sort_order', 'phase_sort_order', 'member_sort_order')
AND tc.constraint_type = 'UNIQUE';
30 changes: 30 additions & 0 deletions test_sort_orders.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
-- Test script to validate the separate sort order implementation

-- Check if new columns exist
SELECT column_name, data_type, is_nullable, column_default
FROM information_schema.columns
WHERE table_name = 'tasks'
AND column_name IN ('status_sort_order', 'priority_sort_order', 'phase_sort_order', 'member_sort_order')
ORDER BY column_name;

-- Check if helper function exists
SELECT routine_name, routine_type
FROM information_schema.routines
WHERE routine_name IN ('get_sort_column_name', 'update_task_sort_orders_bulk', 'handle_task_list_sort_order_change');

-- Sample test data to verify different sort orders work
-- (This would be run after the migrations)
/*
-- Test: Tasks should have different orders for different groupings
SELECT
id,
name,
sort_order,
status_sort_order,
priority_sort_order,
phase_sort_order,
member_sort_order
FROM tasks
WHERE project_id = '<test-project-id>'
ORDER BY status_sort_order;
*/
300 changes: 300 additions & 0 deletions worklenz-backend/database/migrations/fix_duplicate_sort_orders.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,300 @@
-- Fix Duplicate Sort Orders Script
-- This script detects and fixes duplicate sort order values that break task ordering

-- 1. DETECTION QUERIES - Run these first to see the scope of the problem

-- Check for duplicates in main sort_order column
SELECT
project_id,
sort_order,
COUNT(*) as duplicate_count,
STRING_AGG(id::text, ', ') as task_ids
FROM tasks
WHERE project_id IS NOT NULL
GROUP BY project_id, sort_order
HAVING COUNT(*) > 1
ORDER BY project_id, sort_order;

-- Check for duplicates in status_sort_order
SELECT
project_id,
status_sort_order,
COUNT(*) as duplicate_count,
STRING_AGG(id::text, ', ') as task_ids
FROM tasks
WHERE project_id IS NOT NULL
GROUP BY project_id, status_sort_order
HAVING COUNT(*) > 1
ORDER BY project_id, status_sort_order;

-- Check for duplicates in priority_sort_order
SELECT
project_id,
priority_sort_order,
COUNT(*) as duplicate_count,
STRING_AGG(id::text, ', ') as task_ids
FROM tasks
WHERE project_id IS NOT NULL
GROUP BY project_id, priority_sort_order
HAVING COUNT(*) > 1
ORDER BY project_id, priority_sort_order;

-- Check for duplicates in phase_sort_order
SELECT
project_id,
phase_sort_order,
COUNT(*) as duplicate_count,
STRING_AGG(id::text, ', ') as task_ids
FROM tasks
WHERE project_id IS NOT NULL
GROUP BY project_id, phase_sort_order
HAVING COUNT(*) > 1
ORDER BY project_id, phase_sort_order;

-- Note: member_sort_order removed - no longer used

-- 2. CLEANUP FUNCTIONS

-- Fix duplicates in main sort_order column
CREATE OR REPLACE FUNCTION fix_sort_order_duplicates() RETURNS void
LANGUAGE plpgsql
AS
$$
DECLARE
_project RECORD;
_task RECORD;
_counter INTEGER;
BEGIN
-- For each project, reassign sort_order values to ensure uniqueness
FOR _project IN
SELECT DISTINCT project_id
FROM tasks
WHERE project_id IS NOT NULL
LOOP
_counter := 0;

-- Reassign sort_order values sequentially for this project
FOR _task IN
SELECT id
FROM tasks
WHERE project_id = _project.project_id
ORDER BY sort_order, created_at
LOOP
UPDATE tasks
SET sort_order = _counter
WHERE id = _task.id;

_counter := _counter + 1;
END LOOP;
END LOOP;

RAISE NOTICE 'Fixed sort_order duplicates for all projects';
END
$$;

-- Fix duplicates in status_sort_order column
CREATE OR REPLACE FUNCTION fix_status_sort_order_duplicates() RETURNS void
LANGUAGE plpgsql
AS
$$
DECLARE
_project RECORD;
_task RECORD;
_counter INTEGER;
BEGIN
FOR _project IN
SELECT DISTINCT project_id
FROM tasks
WHERE project_id IS NOT NULL
LOOP
_counter := 0;

FOR _task IN
SELECT id
FROM tasks
WHERE project_id = _project.project_id
ORDER BY status_sort_order, created_at
LOOP
UPDATE tasks
SET status_sort_order = _counter
WHERE id = _task.id;

_counter := _counter + 1;
END LOOP;
END LOOP;

RAISE NOTICE 'Fixed status_sort_order duplicates for all projects';
END
$$;

-- Fix duplicates in priority_sort_order column
CREATE OR REPLACE FUNCTION fix_priority_sort_order_duplicates() RETURNS void
LANGUAGE plpgsql
AS
$$
DECLARE
_project RECORD;
_task RECORD;
_counter INTEGER;
BEGIN
FOR _project IN
SELECT DISTINCT project_id
FROM tasks
WHERE project_id IS NOT NULL
LOOP
_counter := 0;

FOR _task IN
SELECT id
FROM tasks
WHERE project_id = _project.project_id
ORDER BY priority_sort_order, created_at
LOOP
UPDATE tasks
SET priority_sort_order = _counter
WHERE id = _task.id;

_counter := _counter + 1;
END LOOP;
END LOOP;

RAISE NOTICE 'Fixed priority_sort_order duplicates for all projects';
END
$$;

-- Fix duplicates in phase_sort_order column
CREATE OR REPLACE FUNCTION fix_phase_sort_order_duplicates() RETURNS void
LANGUAGE plpgsql
AS
$$
DECLARE
_project RECORD;
_task RECORD;
_counter INTEGER;
BEGIN
FOR _project IN
SELECT DISTINCT project_id
FROM tasks
WHERE project_id IS NOT NULL
LOOP
_counter := 0;

FOR _task IN
SELECT id
FROM tasks
WHERE project_id = _project.project_id
ORDER BY phase_sort_order, created_at
LOOP
UPDATE tasks
SET phase_sort_order = _counter
WHERE id = _task.id;

_counter := _counter + 1;
END LOOP;
END LOOP;

RAISE NOTICE 'Fixed phase_sort_order duplicates for all projects';
END
$$;

-- Note: fix_member_sort_order_duplicates() removed - no longer needed

-- Master function to fix all sort order duplicates
CREATE OR REPLACE FUNCTION fix_all_duplicate_sort_orders() RETURNS void
LANGUAGE plpgsql
AS
$$
BEGIN
RAISE NOTICE 'Starting sort order cleanup for all columns...';

PERFORM fix_sort_order_duplicates();
PERFORM fix_status_sort_order_duplicates();
PERFORM fix_priority_sort_order_duplicates();
PERFORM fix_phase_sort_order_duplicates();

RAISE NOTICE 'Completed sort order cleanup for all columns';
END
$$;

-- 3. VERIFICATION FUNCTION

-- Verify that duplicates have been fixed
CREATE OR REPLACE FUNCTION verify_sort_order_integrity() RETURNS TABLE(
column_name text,
project_id uuid,
duplicate_count bigint,
status text
)
LANGUAGE plpgsql
AS
$$
BEGIN
-- Check sort_order duplicates
RETURN QUERY
SELECT
'sort_order'::text as column_name,
t.project_id,
COUNT(*) as duplicate_count,
CASE WHEN COUNT(*) > 1 THEN 'DUPLICATES FOUND' ELSE 'OK' END as status
FROM tasks t
WHERE t.project_id IS NOT NULL
GROUP BY t.project_id, t.sort_order
HAVING COUNT(*) > 1;

-- Check status_sort_order duplicates
RETURN QUERY
SELECT
'status_sort_order'::text as column_name,
t.project_id,
COUNT(*) as duplicate_count,
CASE WHEN COUNT(*) > 1 THEN 'DUPLICATES FOUND' ELSE 'OK' END as status
FROM tasks t
WHERE t.project_id IS NOT NULL
GROUP BY t.project_id, t.status_sort_order
HAVING COUNT(*) > 1;

-- Check priority_sort_order duplicates
RETURN QUERY
SELECT
'priority_sort_order'::text as column_name,
t.project_id,
COUNT(*) as duplicate_count,
CASE WHEN COUNT(*) > 1 THEN 'DUPLICATES FOUND' ELSE 'OK' END as status
FROM tasks t
WHERE t.project_id IS NOT NULL
GROUP BY t.project_id, t.priority_sort_order
HAVING COUNT(*) > 1;

-- Check phase_sort_order duplicates
RETURN QUERY
SELECT
'phase_sort_order'::text as column_name,
t.project_id,
COUNT(*) as duplicate_count,
CASE WHEN COUNT(*) > 1 THEN 'DUPLICATES FOUND' ELSE 'OK' END as status
FROM tasks t
WHERE t.project_id IS NOT NULL
GROUP BY t.project_id, t.phase_sort_order
HAVING COUNT(*) > 1;

-- Note: member_sort_order verification removed - column no longer used

END
$$;

-- 4. USAGE INSTRUCTIONS

/*
USAGE:

1. First, run the detection queries to see which projects have duplicates
2. Then run this to fix all duplicates:
SELECT fix_all_duplicate_sort_orders();
3. Finally, verify the fix worked:
SELECT * FROM verify_sort_order_integrity();

If verification returns no rows, all duplicates have been fixed successfully.

WARNING: This will reassign sort order values based on current order + creation time.
Make sure to backup your database before running these functions.
*/
Loading