Commit graph

121 commits

Author SHA1 Message Date
Vadym Samoilenko
70a6b5e6ef fix(ai): strip markdown code block from Anthropic response before JSON parse
Some checks failed
CI / backend (push) Has been cancelled
CI / frontend (push) Has been cancelled
Claude Haiku wraps JSON in ```json ... ``` blocks, causing json.loads to fail
silently. The except clause swallowed the error, leaving ai_title empty for all
303 sessions.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 17:25:14 +01:00
Vadym Samoilenko
e861f20342 fix(migration): cast gen_random_uuid() to uuid not text for omg backfill
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 09:56:30 +01:00
Vadym Samoilenko
f568814be5 feat(omg): backfill omg_entries from all projects with job_number
All CC Dashboard projects that have a non-empty job_number now appear
in the OMG list automatically. Existing entries are preserved (INSERT
only where no entry with that job_number exists for the user).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 09:55:36 +01:00
Vadym Samoilenko
e0f541b082 fix(auth): rebuild frontend with session-restore-before-router fix
Static assets were built before the auth fix commit (13:29 vs 14:14),
so the deployed container ran old code that registered the router before
awaiting authStore.init() — causing page refresh to redirect to login.

Also adds migration 0011 to set job_number=2940884 for Oliver client
projects that had no job number assigned.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 09:52:04 +01:00
Vadym Samoilenko
38d7da93e2 fix(auth): restore session before registering router to prevent refresh redirect
- Move app.use(router) after await authStore.init() so the beforeEach guard
  sees the correct isAuthenticated state on page load
- Fix backfill_session_costs._root_prefix: remove underscore→dash replacement
  that caused paths like /Users/ai_leed/... to not match ~/.claude/projects/ folders

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 14:14:27 +01:00
Vadym Samoilenko
1ff57fff15 fix(router): redirect authenticated users away from login page
When init() restores session from cookie and user's current URL is /login,
the guard was calling next() without checking isAuthenticated — leaving the
user on the login page despite having a valid session. Now redirects to
dashboard if already authenticated.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 13:32:29 +01:00
Vadym Samoilenko
c10932649d fix(auth): set refresh cookie path to "/" for proxy compatibility
Narrow path "/cc-dashboard/api/auth" caused matching issues depending on
how the reverse proxy presents headers to the browser. Using "/" is safe
since the cookie is HttpOnly and the server validates the token type.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 13:20:25 +01:00
Vadym Samoilenko
ff8b20857f fix(ingest): preserve active_hours when backfill sends zero
On conflict update now skips active_hours if incoming value is 0,
preventing the cost-backfill script from clobbering existing session
hours with its sentinel 0.0 value.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 13:13:48 +01:00
Vadym Samoilenko
0148b81e9c fix(auth): correct refresh cookie path for reverse proxy
Cookie was set with path="/api/auth" but browser-visible URL is
"/cc-dashboard/api/auth/..." — browser never sent the cookie back.
Fix: derive path from BASE_PATH so it matches the full proxy-prefixed URL.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 13:04:11 +01:00
Vadym Samoilenko
fde9b61465 feat(cost): track Claude Code token usage and cost per project
- cc-collector.py: extract input/output/cache tokens from JSONL usage
  fields and calculate cost_usd using model-based pricing table
- Session model: add input_tokens, output_tokens, cost_usd columns
- Migration 0010: ALTER TABLE sessions ADD cost columns
- Ingest: persist cost fields on upsert (updated on every sync)
- Dashboard /projects: aggregate total_cost_usd per project from sessions
- ProjectHours schema + ProjectSummary TS type: expose total_cost_usd
- ProjectsView: replace Budget% column with "Cost $" showing total spend;
  Grid cards show CC Cost row when cost > 0
- backfill_session_costs.py: one-time script to populate cost for all
  historical sessions from local JSONL files

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 12:47:26 +01:00
Vadym Samoilenko
c3022c0c66 feat(projects): replace list view with DataTable — search, column filters, resize, sort
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-13 12:36:16 +01:00
Vadym Samoilenko
26127061ec fix: OMG auto-sync, Projects OMG# column, ADO OMG Deliverable Number, session persistence
- Auto-create/update OmgEntry when Project.job_number changes (PATCH /api/projects);
  delete stale entry on clear; sync name/client when those fields change too
- Backfill script: scripts/backfill_omg_from_projects.py
- Projects List-view: add OMG # column with link to /omg?highlight=<job_number>;
  Grid-view badge also made clickable; OmgView supports ?highlight= deep-link with scroll+highlight
- AzureWorkItem: add omg_number column (migration 0009), extracted from
  fields_json[Custom.OMGDeliverableNumber] on sync; DevOps table shows OMG # column
  with CC-project link when matched; toolbar badge shows count of items without OMG #
- Session no longer lost on F5: refresh_token moved to HttpOnly+SameSite=Lax cookie;
  authStore.init() restores session on app start; axios interceptor retries on 401
  via cookie refresh before logging out; POST /api/auth/logout clears cookie

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-13 12:30:40 +01:00
Vadym Samoilenko
b7a1dc9fdf feat: OMG project dropdown + DevOps toolbar + ADO full fields
OMG page:
- Form now has "Fill from project" dropdown that auto-fills name/client/job#
  from any cc-dashboard project (projects loaded in parallel on mount)
- Job # placeholder updated to show numeric format

DevOps Work Items:
- Count "19" moved into the section heading next to "Work Items" title
- DataTable toolbar (separate row with count+filter) hidden via showToolbar=false
- DataTable: add showToolbar prop (default true) to control toolbar visibility

ADO sync:
- Fetch all fields from ADO API (fields=None) to capture custom fields
  including "OMG Deliverable Number" in fields_json
- Expose fields_json in AzureWorkItemOut schema for frontend inspection

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 11:55:25 +01:00
Vadym Samoilenko
dacbe1de6e feat(omg): add CC Project column linked by job_number
On the OMG page, each entry now shows a "CC Project" column that finds
the matching cc-dashboard project by job_number and links to its detail page.
Projects are loaded in parallel with OMG entries on mount.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 11:44:51 +01:00
Vadym Samoilenko
82208cab61 chore(build): update static assets for ui-polish release
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-13 11:36:38 +01:00
Vadym Samoilenko
80c6b4b47e fix(ui): address code review findings
- ConfirmDialog: guard handleConfirm against AlertDialogAction :disabled bypass
- useDebounce: add { deep: true } so object (filter record) mutations trigger debounce
- useFocusTrap: defer focus restore by 150ms to not interrupt close animation
- KpiRow: migrate to ui/KpiCard (proper interface, tone, lucide icons, animated counter)
- ui/KpiCard: add optional `to` prop with RouterLink support
- Remove legacy dashboard/KpiCard.vue (replaced by ui/KpiCard)
- Fix pre-existing lint errors in TopBar and color.ts

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-13 11:34:18 +01:00
Vadym Samoilenko
56a7ff06d6 fix(ui): lint and type-check fixes
Fix broken ESLint config (.eslintrc.cjs missing @rushstack patch, wrong
@typescript-eslint extend syntax). Remove unused imports and variables in
11 components/views. Fix invalid v-else placement in OmgView (move to
Tooltip wrapper instead of inner span).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 11:25:23 +01:00
Vadym Samoilenko
b8329904e8 refactor(ui): replace title attrs with Tooltip on interactive elements
Wrap 'Mark done', 'Edit project', 'Generate AI summary' buttons and inline-editable OMG spans with Tooltip component; replace priority dot title attr in KanbanCard; also adds focus-visible ring to 'Mark done' button.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 11:20:54 +01:00
Vadym Samoilenko
ebd5616498 refactor(login): form spacing, consistent inputs
Replace focus: with focus-visible: on Microsoft sign-in button for consistent ring pattern; error message already uses text-destructive correctly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 11:19:08 +01:00
Vadym Samoilenko
0ac7d71e9b refactor(admin): ConfirmDialog for destructive actions, spacing
Apply space-y-8 rhythm to admin page sections (no destructive actions currently present in this view — no confirm dialog needed yet).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 11:18:59 +01:00
Vadym Samoilenko
86607fbf06 refactor(live): Skeleton loading, EmptyState, spacing
Show 3 skeleton rows while SSE is not yet connected, replace emoji empty state with EmptyState component (Radio+Zap icons), add focus-visible ring to Clear button, slightly increase event row padding.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 11:18:51 +01:00
Vadym Samoilenko
ec6fb8c37b refactor(tasks): EmptyState, spacing rhythm, focus-visible
Replace inline 'Drop here' placeholder in KanbanColumn with EmptyState component, remove title attr in favour of aria-label on add-task button, add focus-visible ring.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 11:18:28 +01:00
Vadym Samoilenko
3e3826028c refactor(calendar): ConfirmDialog, Skeleton loading, Button/SegmentedControl toolbar
Replace window.confirm with ConfirmDialog for block delete, upgrade view/week-length toggles to SegmentedControl, swap inline SVG nav arrows for lucide ChevronLeft/Right with ghost icon Button, add focus-visible ring to planner toggle.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 11:18:08 +01:00
Vadym Samoilenko
3921f01aab refactor(settings): DateRangePicker, form spacing, focus-visible
- Replace two separate <input type="date"> fields for export range with
  a single DateRangePicker component; format() from date-fns bridges
  Date <-> string for exportFrom/exportTo refs
- Use space-y-8 between card sections, space-y-2 between label + input
- Add explicit focus-visible:ring-2 on raw Button usages

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 11:16:20 +01:00
Vadym Samoilenko
5cc38b3aae refactor(project-detail): EmptyState, Skeleton loading, spacing
- Replace "No data" / "No sessions" / "No tools" terse text with EmptyState
  components (FileText, Wrench, CalendarDays icons)
- Add Skeleton placeholders for header, chart, and grid during loading
- Replace raw <input> elements in edit mode with shared Input component
- Replace raw save/cancel buttons in edit mode with Button component
- Upgrade summarize button touch target from h-6/w-6 to h-8/w-8
- Add focus-visible rings on interactive buttons and links
- Use space-y-8 between top-level sections, space-y-2 for label+input pairs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 11:16:15 +01:00
Vadym Samoilenko
b118166693 refactor(keys): ConfirmDialog with type-to-confirm, EmptyState
- Replace window.confirm for key revoke with ConfirmDialog + confirmText prop
  requiring user to type the key label before confirmation
- Replace terse "No API keys" text with EmptyState component (Key, Plus, Shield icons)
- Add focus-visible ring on Revoke button

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 11:16:10 +01:00
Vadym Samoilenko
a605ba44eb refactor(omg): touch targets, shared Input, ConfirmDialog, Tooltip
- Replace raw h-7 w-7 action buttons with Button size="icon" (40px)
- Replace raw inline <input> elements with shared Input component
- Replace handleDelete/window.confirm guard with ConfirmDialog + pendingDeleteId ref
- Wrap action buttons in Tooltip with descriptive content
- Upgrade empty state to EmptyState component
- Add focus-visible rings on interactive elements

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 11:16:06 +01:00
Vadym Samoilenko
fd49ad9865 refactor(projects): SegmentedControl, EmptyState, typed icons
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 11:12:53 +01:00
Vadym Samoilenko
13c262184a refactor(reports): SegmentedControl, Button, EmptyState
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 11:12:50 +01:00
Vadym Samoilenko
ba99a4dd65 refactor(devops): SegmentedControl, design tokens, ConfirmDialog, spacing
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 11:12:48 +01:00
Vadym Samoilenko
e2f9f35362 refactor(dashboard): extract ProjectBreakdown and ToolUsageList
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 11:09:46 +01:00
Vadym Samoilenko
0a6ce6c3c4 refactor(dashboard): extract TimelineChart component
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 11:09:43 +01:00
Vadym Samoilenko
4e9de2d3c3 refactor(dashboard): extract KpiRow with KpiCard components
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 11:09:41 +01:00
Vadym Samoilenko
be6d557622 refactor(dashboard): extract DateRangeFilter component
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 11:09:38 +01:00
Vadym Samoilenko
8a31f46c88 fix(button): ensure icon size meets 40px touch target minimum 2026-05-13 11:06:55 +01:00
Vadym Samoilenko
58f2edadb3 fix(select): use focus-visible for keyboard-only ring 2026-05-13 11:06:28 +01:00
Vadym Samoilenko
823b41e28d feat(dialog): focus trap, autofocus on open, scrollable body 2026-05-13 11:06:19 +01:00
Vadym Samoilenko
2425e241c0 feat(datatable): typed sort, debounced filters, shared Button/Input, EmptyState 2026-05-13 11:06:17 +01:00
Vadym Samoilenko
34c40798be feat(ui): add SegmentedControl, KpiCard with animated counter
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 11:03:33 +01:00
Vadym Samoilenko
d586e9474c feat(ui): add Calendar and DateRangePicker components 2026-05-13 11:01:51 +01:00
Vadym Samoilenko
b382ff640c feat(ui): add EmptyState and ConfirmDialog components 2026-05-13 11:00:14 +01:00
Vadym Samoilenko
f19e5122eb feat(ui): add Tooltip, Popover, Skeleton primitives (radix-vue) 2026-05-13 10:58:41 +01:00
Vadym Samoilenko
9eb7e077ec feat(styles): add spacing scale comment and skeleton shimmer keyframes 2026-05-13 10:56:52 +01:00
Vadym Samoilenko
bc5eb64c40 fix(migration): remove duplicate index creation in 0008_kanban_and_omg
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-07 14:12:04 +01:00
Vadym Samoilenko
36118cb759 feat: replace Planka with in-app Kanban + add OMG page
- Remove Planka: docker-compose services, apache /board/ proxy, env vars, custom CSS dir
- Add Kanban board at /tasks: 4 columns (To Do / Doing / Testing / Done),
  native HTML5 drag-and-drop, card modal (TaskForm reuse), per-column "+" button
- Add 'testing' status to Task model validator and frontend union type
- Add GET /api/tasks/{id} endpoint (was missing, frontend already called it)
- Enrich DevOps clone: live-fetches description, AC, assignee, iteration,
  comments and attachments from ADO; renders as Markdown in task.notes
- Add /omg page: standalone project/client/job# registry with inline editing
  and create/edit/delete dialog; backed by new omg_entries table (migration 0008)
- Add omg router to main.py; add OMG + Tasks to sidebar and router
- Fix dead /planner link on Dashboard -> /tasks

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-07 14:09:36 +01:00
Vadym Samoilenko
7c15f884c1 fix: Planka admin user + branding CSS; project job_number edit form; report filename; devops title
- docker-compose: add DEFAULT_ADMIN_* passthrough + CUSTOM_UI_OVERRIDE_STYLESHEETS + mount planka-custom/
- planka-custom/planka.css: hide Planka logo/title/footer, override to orange theme matching CC Dashboard
- ProjectDetailView: inline edit form for display_name/client/job_number/repo_url via PATCH /api/projects/:id
- ReportsView: download filename uses report.period_date + report.type (report-2026-05-07-daily.md)
- AppLayout: add devops → 'Azure DevOps' title entry

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-07 13:49:00 +01:00
Vadym Samoilenko
09cfc0a89a feat: light theme redesign + DataTable with sort/filter/resize + bug fixes
- Sidebar: white background, orange gradient logo, orange active pill
- TopBar: glassmorphism (white/80 + backdrop-blur-xl)
- AppLayout: warm gradient background mesh
- DataTable: new reusable component with column sort, filter, resize
- DevopsView: rebuilt with DataTable; connection shows "all assigned work items"
- ADO work item URLs: use org-level URL (no project in path)
- CalendarBlock: planned blocks show task title instead of project name
- Reports export: replaced <a download> with fetch+blob to send JWT auth header
- Sidebar Tasks: fixed path /board/ (trailing slash for Apache ProxyPass)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-07 13:15:19 +01:00
Vadym Samoilenko
e16e4a16a5 fix(project-detail): show all-time data when no date range given
Default 30d window hid projects inactive for >30 days (e.g. Enterprise Ai Hub
Nexus, last session 2026-04-01). Project detail now returns all history unless
explicit from/to params are passed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-07 12:52:51 +01:00
Vadym Samoilenko
e401f9a60b feat(planka): add Planka kanban to docker-compose + wire UI
- docker-compose: add planka + planka-db services (port 1337, isolated volume)
- apache.conf: add ProxyPass /board/ → localhost:1337
- .env.example: add PLANKA_SECRET_KEY + PLANKA_BASE_URL
- Sidebar: rename Planner → Tasks, open /board in new tab via <a>
- Router: remove /planner route
- Delete PlannerView.vue, TaskList.vue, TaskCard.vue (Calendar keeps TaskForm)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-07 12:15:25 +01:00
Vadym Samoilenko
fe31ca0fd7 feat(dashboard): add Tasks Today + ADO Priority Items panels
Tasks Today shows pending tasks for today with quick-complete.
ADO Priority Items shows top 5 open items sorted by priority.
Falls back to a connect prompt when no DevOps integration is configured.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-07 12:11:51 +01:00