Commit Graph

33 Commits

Author SHA1 Message Date
Gjermund Høsøien Wiggen
dd747946ea fix: wider resize handles, table minWidth instead of width 100%
- table-layout: fixed with minWidth instead of width:100% to avoid
  browser recalculating explicit column widths
- Wider resize handles (w-3, 12px) for easier grabbing
- Better visibility on hover

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 22:18:49 +02:00
Gjermund Høsøien Wiggen
dde19f5fab fix: table-layout fixed + consistent column widths
- table-layout: fixed on the table wrapper so browser respects explicit widths
- All cells (header + rows) now use the same col.width consistently
- Subject column no longer special-cased for width

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 22:16:49 +02:00
Gjermund Høsøien Wiggen
5970e3fe9d fix: resize adjusts both adjacent columns (left expands, right shrinks)
Left column gets wider, right column gets narrower by same amount.
Subject column now has fixed width (not flexible) so the table
doesn't redistribute space unpredictably.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 22:12:44 +02:00
Gjermund Høsøien Wiggen
7f91a51e32 fix: resize handle now adjusts column to its left
Handle on the left edge resizes the PREVIOUS column, not itself.
This matches the mental model: dragging the boundary between Subject
and Status changes Subject's width. First column has no handle.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 22:10:14 +02:00
Gjermund Høsøien Wiggen
30108c7600 fix: move resize handles to left edge of columns
Handles now sit on the left edge (the boundary between columns).
Dragging feels natural — you pull the dividing line between two columns.
Wider hit area (w-2) for easier grabbing.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 22:08:36 +02:00
Gjermund Høsøien Wiggen
d7a5b5ba1d fix: use CSS table layout for column alignment
Replaced flex containers with display: table/table-row/table-cell.
This guarantees column widths are shared between header and all rows,
fixing the misalignment. Subject column gets remaining width, all
others use fixed pixel widths. Resize handles on header cells still work.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 22:06:12 +02:00
Gjermund Høsøien Wiggen
b2fb69ffc5 fix: add checkbox spacer to column header for alignment
Column header was missing the w-9 spacer that ticket rows have
for the batch checkbox. Added spacer so columns align properly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 22:03:40 +02:00
Gjermund Høsøien Wiggen
dd7bd867bf fix: remove duplicate column header, portal column picker, clean widths
- Remove old fixed column header (was showing above dynamic one)
- Column picker now renders via createPortal (no longer behind elements)
- Remove forced inline widths on header and rows (flex naturally)
- Cleaner column header styling (subtle muted, no forced min-width)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 22:01:48 +02:00
Gjermund Høsøien Wiggen
e486558309 feat: batch ticket operations — multi-select, bulk status, bulk assign
- Checkbox column on every ticket row
- Select multiple tickets via checkboxes
- Floating sticky action bar at bottom when tickets selected:
  - Shows count: "3 selected" with Clear button
  - Quick status change buttons
  - Assign to me button
- Checkbox click stops propagation (doesn't select ticket for triage panel)
- Batch operations run sequentially via API

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 21:58:09 +02:00
Gjermund Høsøien Wiggen
38a82ad0d8 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>
2026-06-09 21:51:16 +02:00
Gjermund Høsøien Wiggen
7ddf82f93f feat: customizable, resizable columns on ticket list, saved per view
- Column picker dropdown (grid icon next to sort/density)
  - Check/uncheck columns: ID, Subject, Status, Queue, Owner, Created, Updated
  - Subject column auto-expands (flex), others have fixed width
- Column resize handles: drag right edge of any column header
  - Min 50px, max 800px, body gets select-none during drag
- Columns persist with saved views (columns jsonb field)
- Reset to defaults when navigating away from a saved view
- Sticky column header row with muted background

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 14:57:34 +02:00
Gjermund Høsøien Wiggen
d5d6a209bd fix: All tickets link, redesign side panel into triage panel
- Fix sidebar All tickets link: /?view=all instead of / (avoids dashboard redirect)
- Replace useless side panel with triage command center:
  - Quick status change buttons (click to transition inline)
  - Assign to me button (appears when unassigned)
  - Mini activity feed showing last 8 transactions with type labels,
    status badges, old→new values, and comment previews
  - Relative timestamps
  - Open full view button
- Fetches ticket transactions on selection

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 14:51:51 +02:00
Gjermund Høsøien Wiggen
3d7ba0d6a7 feat: team assignment on tickets + My team's tickets view
Backend:
- team_id column on tickets table
- team_id filter in GET /tickets (resolves team members)
- team_id in UpdateTicketSchema + PATCH handler
- SetTeam transaction type

Frontend:
- Team selector in ticket detail properties sidebar
- My team's tickets in sidebar (when user belongs to a team)
- team_id passed through to API from ticket list page

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 14:40:00 +02:00
Gjermund Høsøien Wiggen
35b7f49518 fix: add-filter popover renders via portal to avoid stacking context
- Popover now renders via createPortal into document.body with z-index 9999
- This avoids the header backdrop-blur stacking context trapping it
- Add + button in Dashboards sidebar section to create dashboards
- Inline input on Dashboards section header, Enter to create/Escape to cancel

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 13:19:22 +02:00
Gjermund Høsøien Wiggen
f7e34f1690 feat: dashboard auto-refresh, collapsible sidebar, error retry
- Dashboard: auto-refresh toggle (30s interval, spins when live)
- Dashboard: responsive grid (6 cols mobile, 12 cols desktop)
- Sidebar: Dashboards, Saved views, Queues sections now collapsible
  with chevron toggle
- Error banner: added Retry button next to error message

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 13:14:47 +02:00
Gjermund Høsøien Wiggen
6263ce1332 feat: seed dashboard, fix My tickets filter
- Add demo dashboard with 7 widgets to seed script
- Dashboard is_default=true — appears as home page on fresh seed
- Add views/dashboards/dashboardWidgets to seed reset
- Fix My tickets: now filters by first non-system user (not any owner)
- Pass owner param in sidebar My tickets link
- Update page.tsx view=my to respect owner URL param
- Scrip engine already sorts by sort_order (verified)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 13:09:02 +02:00
Gjermund Høsøien Wiggen
c6c5272e50 feat: SQL filtering, Users admin tab, dashboard polish
- Move ticket filtering from in-memory to SQL WHERE clauses
  (queue_id, status, owner use Drizzle eq/isNull; text search uses ilike;
  custom field filters use EXISTS subqueries)
- Add limit param to GET /tickets
- Add POST/PATCH/DELETE /users routes
- Add Users tab to admin page with create/edit/delete
- Smart widget positioning in dashboard (3-column grid fill)
- Show pattern hint below CF inputs in New Ticket dialog

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 13:04:10 +02:00
Gjermund Høsøien Wiggen
7be90684fb fix: replace broken add-filter button with stepped filter builder
- Fixed popover z-index: uses fixed positioning with z-50 above backdrop
- Stepped flow: select field → set operator (is/is_not) → choose/write value → Apply
- Removed old inline CF value inputs (handled inline in the new flow)
- Fixed filter persistence: clear filters when navigating away from saved view
- Fixed home redirect: check for default dashboard on load

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 11:30:17 +02:00
Gjermund Høsøien Wiggen
b70a133ea2 feat: add dashboards — tables, CRUD API, widget data endpoint
- New dashboards table (name, description, layout, is_default)
- New dashboard_widgets table (view_id, title, widget_type, position, config)
- GET/POST/PATCH/DELETE /dashboards
- GET/POST/PATCH/DELETE /dashboards/:id/widgets
- GET /dashboards/:id/widgets/:id/data — runs saved view filters,
  returns pre-aggregated data for count/ticket_list/status_chart/grouped_counts
- is_default uniqueness enforced on PATCH

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 11:26:22 +02:00
Gjermund Høsøien Wiggen
aa90b88991 feat: add saved views — database table, CRUD API, migration
- New views table (id, name, filters jsonb, sort_key, is_public, creator_id)
- GET/POST/PATCH/DELETE /views endpoints
- Register views router in server

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 11:10:25 +02:00
Gjermund Høsøien Wiggen
aa808f1d3f feat: return scrip results on ticket create, update frontend types
- POST /tickets now returns { ticket, scrip_results } matching PATCH pattern
- createTicket API function returns UpdateResult instead of Ticket
- Update call site to use data.ticket.id

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 10:51:14 +02:00
Gjermund Høsøien Wiggen
06cc7c79a3 feat: enhance frontend UI — command palette, admin redesign, API coverage
Types + API:
- Add User, TemplatePreview, QueueCustomField types
- Add getUsers, getTemplates, createTemplate, updateTemplate,
  previewTemplate, updateQueue, updateLifecycle, updateCustomField API functions

UI:
- Command palette: keyboard-first navigation with fuzzy ticket search
- Admin: comprehensive redesign with tab-based layout (Queues, Lifecycles,
  Scrips, Custom Fields, Templates, Users)
- Ticket list: improved inbox-style rows with quick actions
- Ticket detail: enhanced conversation thread and properties sidebar
- App shell: sidebar visual refinement with active indicator bar
- Theme toggle: smoother transitions

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 10:43:28 +02:00
Gjermund Høsøien Wiggen
04b4e28d21 Change ticket IDs from UUID to sequential integers
Backend:
- tickets.id: uuid → integer GENERATED ALWAYS AS IDENTITY
- transactions.ticket_id, custom_field_values.ticket_id: uuid → integer
- Routes convert string params to Number() for DB queries
- ScripEngine.prepare takes ticketId: number
- ActionPayload.ticketId: string → number

Frontend:
- Ticket.id: string → number, Transaction.ticket_id: string → number
- API functions accept number params
- formatTicketId() helper returns TKT-0001 format
- Ticket rows display TKT-XXXX, detail page uses formatTicketId

Migration: drops FKs, clears data, alters column types, re-adds FKs
2026-06-07 23:23:05 +02:00
Gjermund Høsøien Wiggen
7da52dfff6 Revert to single-column ticket list with inbox-style rows
- Remove three-column layout, inline detail panel, and properties sidebar
- Click a ticket navigates to /tickets/[id] via router.push
- Redesign TicketRow as inbox-style: status dot, bold subject on top line,
  muted ID/queue/owner meta on second line, time right-aligned
- Cleaner visual hierarchy with increased padding and gap
2026-06-07 23:14:59 +02:00
Gjermund Høsøien Wiggen
86e00b076a Add properties sidebar to inline ticket detail panel
- Two-column layout inside TicketDetailPanel: conversation (left) + sidebar (right)
- Status section: Select dropdown with all statuses, previewTicket + updateTicket flow with Apply/Cancel
- Assignment section: read-only assignee display with avatar initial
- Details section: queue name, created/updated/resolved dates
- Custom fields section: name:value pairs when present
- Sidebar skeleton during loading
- Fetches queue info alongside ticket data for display
2026-06-07 23:13:00 +02:00
Gjermund Høsøien Wiggen
88ab30a7fd Fix transaction_type case mismatch in both ticket pages
Backend returns PascalCase (Create, StatusChange, SetOwner, Comment, Correspond).
Frontend was checking lowercase, causing transaction rendering to fall through to raw type strings.
2026-06-07 23:06:25 +02:00
Gjermund Høsøien Wiggen
737e8942f6 Redesign ticket list to three-column layout with proportional widths
- Replace Sheet slide-over with inline peer detail column
- List column: 40% width (min 360px) when ticket selected, flex-1 otherwise
- Detail column: 60% width (min 480px), slides in from right (300ms)
- Mobile: list hidden when ticket selected, detail becomes full-width
- Subtle border-r divider on list column
- Taller ticket rows (py-4) with smooth hover transitions
- width transition on list column resize
2026-06-07 23:00:45 +02:00
Gjermund Høsøien Wiggen
10962f795f feat: three-column ticket list layout (list + detail as peers, no Sheet)
- Replace Sheet slide-over with persistent right-column detail panel
- Ticket list shrinks to w-80 when ticket selected, detail takes flex-1
- Animated transition (300ms ease-out) when selecting/deselecting
- Kept existing conversation thread, properties sidebar, reply box inline
2026-06-07 22:58:50 +02:00
Gjermund Høsøien Wiggen
784d30acbd fix: wrap TicketListPage in Suspense boundary for useSearchParams 2026-06-07 22:46:34 +02:00
Gjermund Høsøien Wiggen
b2423f2821 feat: inbox-style ticket rows, Sheet detail slide-over, gradient New Ticket button 2026-06-07 22:34:27 +02:00
Gjermund Høsøien Wiggen
77860eb6c4 Redesign: Linear-inspired dark mode frontend
Complete rewrite of all pages:
- layout.tsx: App shell with 240px sidebar (saved views, queue list, admin link)
- app-shell.tsx: Client sidebar component with route highlighting + counts
- page.tsx: Sleek ticket list with filter chips (All/Open/In progress/Resolved), search bar, status dots, assignee avatars, skeleton loading
- tickets/[id]/page.tsx: Two-panel conversation layout — message thread (left) + properties sidebar (right) with status change, scrip preview, reply box
- admin/page.tsx: Suspense-wrapped admin with tabs in sheet panels
- command-palette.tsx: Cmd+K search with keyboard navigation

Design tokens from Linear:
- bg-[#08090a] canvas, bg-[#0f1011] panels, bg-[#191a1b] cards
- text-[#f7f8f8] primary, text-[#d0d6e0] secondary, text-[#8a8f98] tertiary
- borders: rgba(255,255,255,0.08) standard, rgba(255,255,255,0.05) subtle
- accent: #5e6ad2 primary, #7170ff interactive
- status colors: new=gray, open=indigo, in_progress=amber, resolved=green
- Inter font, weights 400/510/590, no pure white

Fixed: Suspense boundaries for useSearchParams in layout and admin pages
Build: passes with zero errors
2026-06-07 22:16:18 +02:00
Gjermund Høsøien Wiggen
a49e888011 Add ticket list page with filters, status badges, create dialog 2026-06-07 22:02:06 +02:00
Gjermund Høsøien Wiggen
9b1af0b7b3 Add Next.js + shadcn/ui scaffold with deps
- Next.js 15 App Router, TypeScript, Tailwind CSS
- shadcn/ui components: button, input, select, textarea, dialog, tabs, table, card, badge, label, separator, dropdown-menu, form, sheet, tooltip
- Runtime deps: @tanstack/react-table, zod, react-hook-form, @hookform/resolvers, lucide-react, date-fns
2026-06-07 21:55:54 +02:00