feat: persist columns to localStorage, custom fields as columns

- Column config saves to localStorage on every change
- Load from localStorage on mount (survive reloads without saved view)
- Custom fields appear as column options in picker
- Custom field values render in ticket rows
- Backend now always includes custom_fields in GET /tickets response

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Gjermund Høsøien Wiggen
2026-06-09 21:51:16 +02:00
parent 7ddf82f93f
commit 38a82ad0d8
2 changed files with 105 additions and 8 deletions

View File

@@ -110,6 +110,45 @@ export function createTicketsRouter(db: Db): Hono {
);
}
// Attach custom field values to all tickets
if (filtered.length > 0) {
const ticketIds = filtered.map((t) => t.id);
const allCfValues = await db.query.customFieldValues.findMany({
where: (table, { inArray }) => inArray(table.ticket_id, ticketIds),
});
const fieldIds = [...new Set(allCfValues.map((v) => v.custom_field_id))];
const allFields = fieldIds.length > 0
? await db.query.customFields.findMany({
where: (table, { inArray }) => inArray(table.id, fieldIds),
})
: [];
const fieldMap = new Map(allFields.map((f) => [f.id, f]));
const ticketsWithCf = filtered.map((ticket) => {
const cfs = allCfValues
.filter((v) => v.ticket_id === ticket.id)
.map((v) => ({
id: v.id,
custom_field_id: v.custom_field_id,
ticket_id: v.ticket_id,
value: v.value,
created_at: v.created_at?.toISOString(),
custom_field: fieldMap.has(v.custom_field_id) ? {
id: v.custom_field_id,
key: fieldMap.get(v.custom_field_id)!.key,
name: fieldMap.get(v.custom_field_id)!.name,
field_type: fieldMap.get(v.custom_field_id)!.field_type,
values: fieldMap.get(v.custom_field_id)!.values,
max_values: fieldMap.get(v.custom_field_id)!.max_values,
pattern: fieldMap.get(v.custom_field_id)!.pattern,
} : undefined,
}));
return { ...ticket, custom_fields: cfs };
});
return c.json(ticketsWithCf);
}
return c.json(filtered);
});