fixxed color selector in the category settings and fixxed drag and drop
Build APK / build (push) Canceled after 2m0s

subtask
This commit is contained in:
2026-08-09 21:42:54 +02:00
parent 4b6e87c979
commit 4c3d1a118c
99 changed files with 3335 additions and 920 deletions
+37 -14
View File
@@ -1,6 +1,9 @@
import { pgTable, text, integer, bigint, boolean, timestamp, unique, index } from 'drizzle-orm/pg-core';
import { pgTable, text, integer, bigint, boolean, unique, index, primaryKey, AnyPgColumn } from 'drizzle-orm/pg-core';
import { sql } from 'drizzle-orm';
export const ENTITIES = ['categories', 'tasks', 'subtasks', 'repeatProfiles', 'friendships'] as const;
export type EntityName = (typeof ENTITIES)[number];
export const users = pgTable('users', {
id: text('id').primaryKey(),
username: text('username').notNull().unique(),
@@ -40,7 +43,7 @@ export const categories = pgTable('categories', {
export const tasks = pgTable('tasks', {
id: text('id').primaryKey(),
userId: text('user_id').notNull().references(() => users.id, { onDelete: 'cascade' }),
categoryId: text('category_id').notNull().references(() => categories.id, { onDelete: 'cascade' }),
categoryId: text('category_id').references(() => categories.id, { onDelete: 'cascade' }),
title: text('title').notNull(),
description: text('description').notNull().default(''),
priority: text('priority', { enum: ['none', 'low', 'medium', 'high', 'critical'] }).notNull().default('none'),
@@ -56,26 +59,31 @@ export const tasks = pgTable('tasks', {
assigneeId: text('assignee_id').references(() => users.id, { onDelete: 'set null' }),
reminder: text('reminder', { enum: ['none', 'at_time', '15', '30', '60', '120', '1440'] }).notNull().default('none'),
reminders: text('reminders').notNull().default(''),
completedAt: bigint('completed_at', { mode: 'number' }),
createdAt: bigint('created_at', { mode: 'number' }).notNull().default(sql`EXTRACT(EPOCH FROM NOW()) * 1000`),
updatedAt: bigint('updated_at', { mode: 'number' }).notNull().default(sql`EXTRACT(EPOCH FROM NOW()) * 1000`),
});
export const repeatProfiles = pgTable('repeat_profiles', {
id: text('id').primaryKey(),
userId: text('user_id').notNull().references(() => users.id, { onDelete: 'cascade' }),
name: text('name').notNull(),
repeat: text('repeat', { enum: ['none', 'daily', 'weekly', 'monthly', 'custom'] }).notNull().default('none'),
repeatInterval: integer('repeat_interval').notNull().default(1),
repeatDays: text('repeat_days').notNull().default(''),
createdAt: bigint('created_at', { mode: 'number' }).notNull().default(sql`EXTRACT(EPOCH FROM NOW()) * 1000`),
updatedAt: bigint('updated_at', { mode: 'number' }).notNull().default(sql`EXTRACT(EPOCH FROM NOW()) * 1000`),
});
export const tombstones = pgTable(
'tombstones',
{
entity: text('entity', { enum: ENTITIES }).notNull(),
entityId: text('entity_id').notNull(),
userId: text('user_id').notNull().references(() => users.id, { onDelete: 'cascade' }),
updatedAt: bigint('updated_at', { mode: 'number' }).notNull(),
},
(t) => ({
pk: primaryKey({ columns: [t.entity, t.entityId] }),
userIdx: index('tombstones_user_updated_idx').on(t.userId, t.updatedAt),
})
);
// Define subtasks with explicit type to avoid circular reference
export const subtasks = pgTable('subtasks', {
id: text('id').primaryKey(),
userId: text('user_id').notNull().references(() => users.id, { onDelete: 'cascade' }),
taskId: text('task_id').notNull().references(() => tasks.id, { onDelete: 'cascade' }),
parentSubtaskId: text('parent_subtask_id').references(() => subtasks.id, { onDelete: 'cascade' }),
parentSubtaskId: text('parent_subtask_id').references((): AnyPgColumn => subtasks.id, { onDelete: 'cascade' }),
title: text('title').notNull(),
description: text('description').notNull().default(''),
priority: text('priority', { enum: ['none', 'low', 'medium', 'high', 'critical'] }).notNull().default('none'),
@@ -94,6 +102,21 @@ export const subtasks = pgTable('subtasks', {
order: integer('order').notNull().default(0),
createdAt: bigint('created_at', { mode: 'number' }).notNull().default(sql`EXTRACT(EPOCH FROM NOW()) * 1000`),
updatedAt: bigint('updated_at', { mode: 'number' }).notNull().default(sql`EXTRACT(EPOCH FROM NOW()) * 1000`),
}, (t) => ({
parentIdx: index('subtasks_parent_idx').on(t.parentSubtaskId),
taskIdx: index('subtasks_task_idx').on(t.taskId),
userIdx: index('subtasks_user_idx').on(t.userId),
}));
export const repeatProfiles = pgTable('repeat_profiles', {
id: text('id').primaryKey(),
userId: text('user_id').notNull().references(() => users.id, { onDelete: 'cascade' }),
name: text('name').notNull(),
repeat: text('repeat', { enum: ['none', 'daily', 'weekly', 'monthly', 'custom'] }).notNull().default('none'),
repeatInterval: integer('repeat_interval').notNull().default(1),
repeatDays: text('repeat_days').notNull().default(''),
createdAt: bigint('created_at', { mode: 'number' }).notNull().default(sql`EXTRACT(EPOCH FROM NOW()) * 1000`),
updatedAt: bigint('updated_at', { mode: 'number' }).notNull().default(sql`EXTRACT(EPOCH FROM NOW()) * 1000`),
});
export const userSettings = pgTable('user_settings', {
@@ -105,4 +128,4 @@ export const userSettings = pgTable('user_settings', {
sortBy: text('sort_by', { enum: ['dueDate', 'priority', 'title', 'createdAt'] }).notNull().default('dueDate'),
sortOrder: text('sort_order', { enum: ['asc', 'desc'] }).notNull().default('asc'),
updatedAt: bigint('updated_at', { mode: 'number' }).notNull().default(sql`EXTRACT(EPOCH FROM NOW()) * 1000`),
});
});