From 574543d7d3fd2068b2d4f6a952ce00b58fd17893 Mon Sep 17 00:00:00 2001 From: Dotta <34892728+cryppadotta@users.noreply.github.com> Date: Fri, 26 Jun 2026 13:46:14 -0500 Subject: [PATCH] Sort workspace routines by name (#8666) Reviewed by CTO for PAP-12039. Client-side ordering change only, with focused helper coverage; CI, security scans, and Greptile are green. Co-Authored-By: Paperclip --- ui/src/lib/workspace-routines.test.ts | 28 +++++++++++++++++++++++ ui/src/lib/workspace-routines.ts | 8 +++++++ ui/src/pages/ExecutionWorkspaceDetail.tsx | 3 ++- 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/ui/src/lib/workspace-routines.test.ts b/ui/src/lib/workspace-routines.test.ts index d53b7a2311..c585a8014b 100644 --- a/ui/src/lib/workspace-routines.test.ts +++ b/ui/src/lib/workspace-routines.test.ts @@ -3,6 +3,7 @@ import { describe, expect, it } from "vitest"; import { getWorkspaceSpecificRoutineVariableNames, routineHasWorkspaceSpecificVariables, + sortWorkspaceRoutinesByName, } from "./workspace-routines"; function createRoutine(overrides: Partial = {}): RoutineListItem { @@ -68,4 +69,31 @@ describe("workspace routine helpers", () => { expect(routineHasWorkspaceSpecificVariables(routine)).toBe(false); }); + + it("sorts workspace routines by name regardless of update order", () => { + const routines = [ + createRoutine({ + id: "routine-2", + title: "zeta review", + updatedAt: new Date("2026-05-02T00:00:00.000Z"), + }), + createRoutine({ + id: "routine-3", + title: "Alpha review", + updatedAt: new Date("2026-04-30T00:00:00.000Z"), + }), + createRoutine({ + id: "routine-1", + title: "alpha review", + updatedAt: new Date("2026-05-03T00:00:00.000Z"), + }), + ]; + + expect(sortWorkspaceRoutinesByName(routines).map((routine) => routine.id)).toEqual([ + "routine-1", + "routine-3", + "routine-2", + ]); + expect(routines.map((routine) => routine.id)).toEqual(["routine-2", "routine-3", "routine-1"]); + }); }); diff --git a/ui/src/lib/workspace-routines.ts b/ui/src/lib/workspace-routines.ts index ca70e3cb5e..eddc5f93f1 100644 --- a/ui/src/lib/workspace-routines.ts +++ b/ui/src/lib/workspace-routines.ts @@ -29,3 +29,11 @@ export function getWorkspaceSpecificRoutineVariableNames(routine: RoutineListIte export function routineHasWorkspaceSpecificVariables(routine: RoutineListItem): boolean { return getWorkspaceSpecificRoutineVariableNames(routine).length > 0; } + +export function sortWorkspaceRoutinesByName(routines: RoutineListItem[]): RoutineListItem[] { + return [...routines].sort((left, right) => { + const titleOrder = left.title.localeCompare(right.title, undefined, { sensitivity: "base" }); + if (titleOrder !== 0) return titleOrder; + return left.id.localeCompare(right.id); + }); +} diff --git a/ui/src/pages/ExecutionWorkspaceDetail.tsx b/ui/src/pages/ExecutionWorkspaceDetail.tsx index 7d7b75192b..97e333b004 100644 --- a/ui/src/pages/ExecutionWorkspaceDetail.tsx +++ b/ui/src/pages/ExecutionWorkspaceDetail.tsx @@ -40,6 +40,7 @@ import { cn, formatDateTime, issueUrl, projectRouteRef, projectWorkspaceUrl } fr import { getWorkspaceSpecificRoutineVariableNames, routineHasWorkspaceSpecificVariables, + sortWorkspaceRoutinesByName, } from "../lib/workspace-routines"; type WorkspaceFormState = { @@ -445,7 +446,7 @@ function ExecutionWorkspaceRoutinesList({ }); const workspaceRoutines = useMemo( - () => (routines ?? []).filter(routineHasWorkspaceSpecificVariables), + () => sortWorkspaceRoutinesByName((routines ?? []).filter(routineHasWorkspaceSpecificVariables)), [routines], );