diff options
| author | Craig Jennings <c@cjennings.net> | 2026-06-06 16:09:30 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-06-06 16:09:30 -0500 |
| commit | 132496a6fbe5b1190d3b5cc585e940d12e3c92db (patch) | |
| tree | 2923408a17a2d38052a384e91c8b667c9ed1e283 /tests/test-pearl-grouping.el | |
| parent | 9564501efe2488b9136dc19a7a8d385b8b074b46 (diff) | |
| download | pearl-132496a6fbe5b1190d3b5cc585e940d12e3c92db.tar.gz pearl-132496a6fbe5b1190d3b5cc585e940d12e3c92db.zip | |
fix(views): order group sections by Linear's board order
A grouped view rendered its sections in first-appearance order: whatever order issues came back from the API. So the columns came out scrambled instead of following Linear's board order (Icebox, then In Progress, then Done). Org's own sort couldn't fix it either, since the buffer carried nothing to sort the sections on.
Group sections now order by a per-dimension key. workflowState orders by state type rank (triage, backlog, unstarted, started, completed, canceled), with the state's position breaking ties within a type, so it matches the board. priority orders Urgent down to None last. project, assignee, and cycle have no board order, so they sort alphabetically. One shared helper feeds both the render path and the interactive regroup, so they can't drift.
For the regroup to order without a refetch, the state position has to be in the buffer, so the issue drawer now carries LINEAR-STATE-POSITION (fetched alongside the name and type pearl already pulled). A buffer rendered before this change has no position field and falls back to ordering by type rank alone until its next fetch.
Diffstat (limited to 'tests/test-pearl-grouping.el')
| -rw-r--r-- | tests/test-pearl-grouping.el | 58 |
1 files changed, 58 insertions, 0 deletions
diff --git a/tests/test-pearl-grouping.el b/tests/test-pearl-grouping.el index a30bcc1..5bcae1d 100644 --- a/tests/test-pearl-grouping.el +++ b/tests/test-pearl-grouping.el @@ -354,5 +354,63 @@ SE-1 has a comment subtree; SE-2 has no assignee.") (should (string-match-p "^\\*\\* Apollo$" out)) (should-not (string-match-p "^\\*\\* In Progress$" out)))) +;;; group ordering (board order, not first-appearance) + +(ert-deftest test-pearl-order-groups-workflowstate-by-type-then-position () + "workflowState groups order by state type rank, then position within a type." + (let ((groups (list (cons "In Progress" (list '(:state (:type "started" :position 3.0)))) + (cons "Icebox" (list '(:state (:type "backlog" :position 1.0)))) + (cons "Done" (list '(:state (:type "completed" :position 5.0)))) + (cons "Inbox" (list '(:state (:type "backlog" :position 2.0))))))) + (should (equal (mapcar #'car (pearl--order-groups "workflowState" groups)) + '("Icebox" "Inbox" "In Progress" "Done"))))) + +(ert-deftest test-pearl-order-groups-priority-urgent-first-none-last () + "priority groups order Urgent..Low, then None last." + (let ((groups (list (cons "None" (list '(:priority 0))) + (cons "High" (list '(:priority 2))) + (cons "Urgent" (list '(:priority 1))) + (cons "Low" (list '(:priority 4)))))) + (should (equal (mapcar #'car (pearl--order-groups "priority" groups)) + '("Urgent" "High" "Low" "None"))))) + +(ert-deftest test-pearl-order-groups-other-dimension-alphabetical () + "A dimension with no board order (project) sorts alphabetically by label." + (let ((groups (list (cons "Zeta" (list '(:project (:name "Zeta")))) + (cons "alpha" (list '(:project (:name "alpha"))))))) + (should (equal (mapcar #'car (pearl--order-groups "project" groups)) + '("alpha" "Zeta"))))) + +(ert-deftest test-pearl-group-issues-orders-by-board-order () + "pearl--group-issues sections by board order even when input order differs." + (let ((issues (list '(:id "a" :state (:name "In Progress" :type "started" :position 3.0)) + '(:id "b" :state (:name "Icebox" :type "backlog" :position 1.0))))) + (should (equal (mapcar #'car (pearl--group-issues issues "workflowState")) + '("Icebox" "In Progress"))))) + +(defconst test-pearl-grouping--positioned + (concat + "#+LINEAR-SOURCE: (:type filter :name \"F\" :filter (:open t))\n\n" + "* F\n" + "** TODO SE-1: Alpha\n:PROPERTIES:\n:LINEAR-ID: i1\n" + ":LINEAR-STATE-NAME: In Progress\n:LINEAR-STATE-TYPE: started\n:LINEAR-STATE-POSITION: 3.0\n:END:\nBody.\n" + "** TODO SE-2: Beta\n:PROPERTIES:\n:LINEAR-ID: i2\n" + ":LINEAR-STATE-NAME: Icebox\n:LINEAR-STATE-TYPE: backlog\n:LINEAR-STATE-POSITION: 1.0\n:END:\nBody.\n") + "Flat buffer where first-appearance (In Progress, Icebox) differs from board +order (Icebox before In Progress).") + +(ert-deftest test-pearl-regroup-orders-sections-by-board-order () + "Regrouping by status orders the sections by Linear's board order, not arrival." + (test-pearl-grouping--in-org test-pearl-grouping--positioned + (should (eq (pearl--regroup-issue-subtrees "workflowState") t)) + (should (equal (test-pearl-grouping--group-headings) '("Icebox" "In Progress"))))) + +(ert-deftest test-pearl-format-issue-renders-state-position () + "The issue drawer carries LINEAR-STATE-POSITION so an offline regroup can order." + (let ((out (pearl--format-issue-as-org-entry + '(:id "x" :identifier "SE-9" :title "T" + :state (:name "S" :type "started" :position 2.5))))) + (should (string-match-p "LINEAR-STATE-POSITION:[[:space:]]+2\\.5" out)))) + (provide 'test-pearl-grouping) ;;; test-pearl-grouping.el ends here |
