feat: sort list
TS Lint / Oxlint (push) Successful in 44s
TS Lint / TypeScript (push) Successful in 1m12s
TS Lint / ESLint (push) Successful in 1m13s

This commit is contained in:
2026-07-12 17:14:37 +02:00
parent c07aed8aea
commit d21a829f6b
5 changed files with 63 additions and 2 deletions
+1 -1
View File
@@ -6,7 +6,7 @@
- [x] validate cron string
- [x] clone task
- [x] delete task
- [ ] list option: sort
- [x] list option: sort
- [x] list option: show last completion
- [x] list option: show next refresh
- [x] list option: move completed below
+32 -1
View File
@@ -4,11 +4,14 @@ import type { Task } from "@/types";
import { getTasks, createTask, deleteTask } from "@/api/tasks";
import { CirclePlus } from "@lucide/vue";
import TaskItem from "@/components/TaskItem.vue";
import { taskCompleted } from "@/lib/tasks";
import { taskCompleted, sortTasks } from "@/lib/tasks";
import { SortType } from "@/enums";
const taskInput = ref<string>("");
const tasks = ref<Task[]>([]);
const list = ref<string>("test");
const sortType = ref<SortType>(SortType.RESET_DATE);
const sortReverse = ref<boolean>(false);
const showLastChecked = ref<boolean>(false);
const showNextReset = ref<boolean>(false);
const separateCompleted = ref<boolean>(false);
@@ -19,10 +22,15 @@ function fetchTasks() {
void getTasks(list.value)
.then((data: Task[]) => {
tasks.value = data;
reSortTasks();
setTimeout(fetchTasks, 10000);
});
}
function reSortTasks() {
tasks.value = sortTasks(tasks.value, sortType.value, sortReverse.value);
}
function onNewTask() {
if (taskInput.value.trim()) {
void createTask(list.value, {
@@ -31,6 +39,7 @@ function onNewTask() {
})
.then((data: Task) => {
tasks.value.push(data);
reSortTasks();
})
.finally(() => {
taskInput.value = "";
@@ -53,6 +62,14 @@ function onDeleteTask(task: Task) {
tasks.value.splice(tasks.value.indexOf(task), 1);
}
function onChangeSortType() {
reSortTasks();
}
function onChangeSortReverse() {
reSortTasks();
}
onBeforeMount(fetchTasks);
</script>
@@ -114,6 +131,20 @@ onBeforeMount(fetchTasks);
<div class="collapse-title">Options</div>
<div class="collapse-content text-sm">
<fieldset class="fieldset flex flex-col gap-2">
<label class="label">
Sort by
<select v-model="sortType" class="select" @change="onChangeSortType">
<option :value="SortType.CREATED_AT">Creation date</option>
<option :value="SortType.UPDATED_AT">Creation or update date</option>
<option :value="SortType.CHECK_DATE">Last check date</option>
<option :value="SortType.RESET_DATE">Next reset date</option>
<option :value="SortType.NAME">Name</option>
</select>
</label>
<label class="label">
<input v-model="sortReverse" type="checkbox" class="checkbox" @change="onChangeSortReverse" />
Reverse sort
</label>
<label class="label">
<input v-model="showLastChecked" type="checkbox" class="checkbox" />
Show last checked time
+8
View File
@@ -6,3 +6,11 @@ export enum CronType {
EVERY_YEAR = 5,
SPECIFIC = 6,
}
export enum SortType {
CREATED_AT = 1,
UPDATED_AT = 2,
CHECK_DATE = 3,
RESET_DATE = 4,
NAME = 5,
}
+20
View File
@@ -1,3 +1,4 @@
import { SortType } from "@/enums";
import type { RawTask, Task } from "@/types";
import {CronExpressionParser} from "cron-parser";
@@ -6,6 +7,8 @@ export function parseTask(task: RawTask): Task {
id: task.id,
name: task.name,
reset_cron: task.reset_cron,
created_at: new Date(task.created_at),
updated_at: new Date(task.updated_at),
check_date: task.check_date ? new Date(task.check_date) : null,
previous_check_date: task.previous_check_date
? new Date(task.previous_check_date)
@@ -32,3 +35,20 @@ export function taskCompleted(task: Task): boolean {
}
return nextReset.getTime() > (new Date()).getTime();
}
export function sortTasks(tasks: Task[], sortType: SortType, reverse: boolean): Task[] {
switch (sortType) {
case SortType.CREATED_AT:
return tasks.slice().sort((a: Task, b: Task) => (reverse ? -1 : 1) * (a.created_at.getTime() - b.created_at.getTime()));
case SortType.UPDATED_AT:
return tasks.slice().sort((a: Task, b: Task) => (reverse ? -1 : 1) * (a.updated_at.getTime() - b.updated_at.getTime()));
case SortType.CHECK_DATE:
return tasks.slice().sort((a: Task, b: Task) => (reverse ? -1 : 1) * ((a.check_date ?? a.created_at).getTime() - (b.check_date ?? b.created_at).getTime()));
case SortType.RESET_DATE:
return tasks.slice().sort((a: Task, b: Task) => (reverse ? -1 : 1) * (taskNextReset(a) ?? a.created_at).getTime() - (taskNextReset(b) ?? b.created_at).getTime());
case SortType.NAME:
return tasks.slice().sort((a: Task, b: Task) => (reverse ? -1 : 1) * a.name.localeCompare(b.name));
default:
return tasks.slice();
}
}
+2
View File
@@ -20,6 +20,8 @@ export interface Task {
id: string;
name: string;
reset_cron: string | null;
created_at: Date;
updated_at: Date;
check_date: Date | null;
previous_check_date: Date | null;
}