feat: add alignment property to fields and update related database and UI handling

This commit is contained in:
2025-11-12 00:15:16 +01:00
parent cb5880f861
commit f3181116d4
7 changed files with 100 additions and 47 deletions
+11
View File
@@ -65,6 +65,8 @@ class SqliteAdapter implements DBAdapter {
name TEXT NOT NULL,
fieldType TEXT NOT NULL,
fieldOptions TEXT,
alignment TEXT NOT NULL DEFAULT 'start',
alignment TEXT NOT NULL DEFAULT 'start',
listId TEXT NOT NULL,
"order" INTEGER NOT NULL,
createdAt INTEGER NOT NULL,
@@ -97,6 +99,12 @@ class SqliteAdapter implements DBAdapter {
CREATE INDEX IF NOT EXISTS idx_item_values_itemId ON item_values(itemId);
CREATE INDEX IF NOT EXISTS idx_item_values_fieldId ON item_values(fieldId);
`);
// Attempt to add alignment column if upgrading an existing DB (ignore error if exists)
try {
this.db.exec(`ALTER TABLE fields ADD COLUMN alignment TEXT NOT NULL DEFAULT 'start'`);
} catch (e) {
// Column may already exist; ignore
}
}
async queryAll(sql: string, params: Param[] = []): Promise<any[]> {
@@ -166,6 +174,7 @@ class PostgresAdapter implements DBAdapter {
name TEXT NOT NULL,
fieldType TEXT NOT NULL,
fieldOptions TEXT,
alignment TEXT NOT NULL DEFAULT 'start',
listId TEXT NOT NULL,
"order" INTEGER NOT NULL,
createdAt BIGINT NOT NULL,
@@ -199,6 +208,8 @@ class PostgresAdapter implements DBAdapter {
await client.query(`CREATE INDEX IF NOT EXISTS idx_items_listId ON items(listId);`);
await client.query(`CREATE INDEX IF NOT EXISTS idx_item_values_itemId ON item_values(itemId);`);
await client.query(`CREATE INDEX IF NOT EXISTS idx_item_values_fieldId ON item_values(fieldId);`);
// Migrate existing DBs: ensure alignment column exists
await client.query(`ALTER TABLE fields ADD COLUMN IF NOT EXISTS alignment TEXT NOT NULL DEFAULT 'start';`);
await client.query('COMMIT');
} catch (e) {
await client.query('ROLLBACK');
+6 -6
View File
@@ -17,10 +17,10 @@ router.get('/list/:listId', async (req: Request, res: Response) => {
// Create field
router.post('/', async (req: Request, res: Response) => {
try {
const { id, name, fieldType, fieldOptions, listId, order, createdAt, updatedAt, isDeleted } = req.body;
const { id, name, fieldType, fieldOptions, alignment, listId, order, createdAt, updatedAt, isDeleted } = req.body;
await dbAdapter.execute(
'INSERT INTO fields (id, name, fieldType, fieldOptions, listId, "order", createdAt, updatedAt, isDeleted) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)',
[id, name, fieldType, fieldOptions, listId, order, createdAt, updatedAt, isDeleted ? 1 : 0]
'INSERT INTO fields (id, name, fieldType, fieldOptions, alignment, listId, "order", createdAt, updatedAt, isDeleted) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
[id, name, fieldType, fieldOptions, alignment ?? 'start', listId, order, createdAt, updatedAt, isDeleted ? 1 : 0]
);
const field = await dbAdapter.queryOne('SELECT * FROM fields WHERE id = ?', [id]);
res.status(201).json({ ...(field as any), isDeleted: !!(field as any).isDeleted });
@@ -33,10 +33,10 @@ router.post('/', async (req: Request, res: Response) => {
router.put('/:id', async (req: Request, res: Response) => {
try {
const updatedAt = Date.now();
const { name, fieldType, fieldOptions, order } = req.body;
const { name, fieldType, fieldOptions, alignment, order } = req.body;
const result = await dbAdapter.execute(
'UPDATE fields SET name = ?, fieldType = ?, fieldOptions = ?, "order" = ?, updatedAt = ? WHERE id = ?',
[name, fieldType, fieldOptions, order, updatedAt, req.params.id]
'UPDATE fields SET name = ?, fieldType = ?, fieldOptions = ?, alignment = ?, "order" = ?, updatedAt = ? WHERE id = ?',
[name, fieldType, fieldOptions, alignment ?? 'start', order, updatedAt, req.params.id]
);
if (result.changes === 0) {
+3 -1
View File
@@ -59,7 +59,7 @@ setInterval(() => {
// Helper function to get prepared statements (lazy initialization)
// We'll perform upserts with positional params for cross-DB portability
const UPSERT_LIST = 'INSERT INTO lists (id, name, createdAt, updatedAt, isDeleted) VALUES (?, ?, ?, ?, ?) ON CONFLICT(id) DO UPDATE SET name = EXCLUDED.name, updatedAt = EXCLUDED.updatedAt, isDeleted = EXCLUDED.isDeleted';
const UPSERT_FIELD = 'INSERT INTO fields (id, name, fieldType, fieldOptions, listId, "order", createdAt, updatedAt, isDeleted) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(id) DO UPDATE SET name = EXCLUDED.name, fieldType = EXCLUDED.fieldType, fieldOptions = EXCLUDED.fieldOptions, "order" = EXCLUDED."order", updatedAt = EXCLUDED.updatedAt, isDeleted = EXCLUDED.isDeleted';
const UPSERT_FIELD = 'INSERT INTO fields (id, name, fieldType, fieldOptions, alignment, listId, "order", createdAt, updatedAt, isDeleted) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(id) DO UPDATE SET name = EXCLUDED.name, fieldType = EXCLUDED.fieldType, fieldOptions = EXCLUDED.fieldOptions, alignment = EXCLUDED.alignment, "order" = EXCLUDED."order", updatedAt = EXCLUDED.updatedAt, isDeleted = EXCLUDED.isDeleted';
const UPSERT_ITEM = 'INSERT INTO items (id, listId, createdAt, updatedAt, isDeleted) VALUES (?, ?, ?, ?, ?) ON CONFLICT(id) DO UPDATE SET updatedAt = EXCLUDED.updatedAt, isDeleted = EXCLUDED.isDeleted';
const UPSERT_ITEM_VALUE = 'INSERT INTO item_values (id, itemId, fieldId, value, updatedAt) VALUES (?, ?, ?, ?, ?) ON CONFLICT(id) DO UPDATE SET value = EXCLUDED.value, updatedAt = EXCLUDED.updatedAt';
@@ -144,6 +144,7 @@ router.post('/sync', async (req: Request, res: Response) => {
field.name,
field.fieldType,
field.fieldOptions,
(field.alignment ?? 'start'),
field.listId,
field.order,
field.createdAt,
@@ -316,6 +317,7 @@ router.post('/sync', async (req: Request, res: Response) => {
name: f.name,
fieldType: f.fieldType ?? f.fieldtype,
fieldOptions: f.fieldOptions ?? f.fieldoptions ?? '',
alignment: f.alignment ?? 'start',
order: f.order,
createdAt: toMillis(pick(f, 'createdAt', 'createdat')),
updatedAt: toMillis(pick(f, 'updatedAt', 'updatedat')),