3c6212da7d
Co-authored-by: Kandev Agent <agent@kandev.dev>
95 lines
3.3 KiB
TypeScript
95 lines
3.3 KiB
TypeScript
import type { Task, TaskState } from "@/lib/types/http";
|
|
|
|
export const TASKS_LIST_SORT_OPTIONS = [
|
|
{ value: "updated_desc", label: "Updated newest" },
|
|
{ value: "updated_asc", label: "Updated oldest" },
|
|
{ value: "created_desc", label: "Created newest" },
|
|
{ value: "created_asc", label: "Created oldest" },
|
|
{ value: "title_asc", label: "Title A-Z" },
|
|
{ value: "title_desc", label: "Title Z-A" },
|
|
] as const;
|
|
|
|
export const TASKS_LIST_GROUP_OPTIONS = [
|
|
{ value: "state", label: "State" },
|
|
{ value: "workflow", label: "Workflow" },
|
|
{ value: "repository", label: "Repository" },
|
|
{ value: "none", label: "None" },
|
|
] as const;
|
|
|
|
export type TasksListSort = (typeof TASKS_LIST_SORT_OPTIONS)[number]["value"];
|
|
export type TasksListGroup = (typeof TASKS_LIST_GROUP_OPTIONS)[number]["value"];
|
|
|
|
export const DEFAULT_TASKS_LIST_SORT: TasksListSort = "updated_desc";
|
|
export const DEFAULT_TASKS_LIST_GROUP: TasksListGroup = "state";
|
|
|
|
// i18next key for each option's display label. The `label` fields above stay
|
|
// as plain English fallback/debug values — UI rendering resolves through
|
|
// these keys instead, in `tasks:` catalog.
|
|
export const SORT_OPTION_LABEL_KEYS: Record<TasksListSort, string> = {
|
|
updated_desc: "tasks:sortUpdatedNewest",
|
|
updated_asc: "tasks:sortUpdatedOldest",
|
|
created_desc: "tasks:sortCreatedNewest",
|
|
created_asc: "tasks:sortCreatedOldest",
|
|
title_asc: "tasks:sortTitleAZ",
|
|
title_desc: "tasks:sortTitleZA",
|
|
};
|
|
|
|
export const GROUP_OPTION_LABEL_KEYS: Record<TasksListGroup, string> = {
|
|
state: "tasks:groupByState",
|
|
workflow: "tasks:groupByWorkflow",
|
|
repository: "tasks:groupByRepository",
|
|
none: "tasks:groupByNone",
|
|
};
|
|
|
|
export const TASK_STATE_ORDER: TaskState[] = [
|
|
"CREATED",
|
|
"SCHEDULING",
|
|
"TODO",
|
|
"IN_PROGRESS",
|
|
"REVIEW",
|
|
"BLOCKED",
|
|
"WAITING_FOR_INPUT",
|
|
"COMPLETED",
|
|
"FAILED",
|
|
"CANCELLED",
|
|
];
|
|
|
|
export function parseTasksListSort(value: string | null | undefined): TasksListSort {
|
|
return TASKS_LIST_SORT_OPTIONS.some((option) => option.value === value)
|
|
? (value as TasksListSort)
|
|
: DEFAULT_TASKS_LIST_SORT;
|
|
}
|
|
|
|
export function parseTasksListGroup(value: string | null | undefined): TasksListGroup {
|
|
return TASKS_LIST_GROUP_OPTIONS.some((option) => option.value === value)
|
|
? (value as TasksListGroup)
|
|
: DEFAULT_TASKS_LIST_GROUP;
|
|
}
|
|
|
|
export function sortTasksForList(tasks: Task[], sort: TasksListSort): Task[] {
|
|
return [...tasks].sort((a, b) => compareTasksForList(a, b, sort));
|
|
}
|
|
|
|
export function compareTasksForList(a: Task, b: Task, sort: TasksListSort): number {
|
|
const titleCompare = a.title.localeCompare(b.title, undefined, { sensitivity: "base" });
|
|
switch (sort) {
|
|
case "updated_asc":
|
|
return compareDate(a.updated_at, b.updated_at) || titleCompare;
|
|
case "created_desc":
|
|
return compareDate(b.created_at, a.created_at) || titleCompare;
|
|
case "created_asc":
|
|
return compareDate(a.created_at, b.created_at) || titleCompare;
|
|
case "title_asc":
|
|
return titleCompare || compareDate(b.updated_at, a.updated_at);
|
|
case "title_desc":
|
|
return -titleCompare || compareDate(b.updated_at, a.updated_at);
|
|
case "updated_desc":
|
|
default:
|
|
return compareDate(b.updated_at, a.updated_at) || titleCompare;
|
|
}
|
|
}
|
|
|
|
function compareDate(a: string, b: string): number {
|
|
return Date.parse(a) - Date.parse(b);
|
|
}
|