547 Commits

Author SHA1 Message Date
f6a24ea4e1 fix(psa): resource assignment targets CW owner, status PATCH verifies apply
Some checks failed
Mirror to GitHub / mirror (push) Successful in 2s
CI / backend (pull_request) Failing after 15m32s
CI / frontend (pull_request) Failing after 45s
CI / e2e (pull_request) Has been skipped
Previous `resources`-string PATCH was silently ignored by CW — the
`resources` field is server-derived from the ticket's owner + schedule
entries, not freely writable. Status PATCH could also silently no-op
when a cross-board status id was sent.

- add_resource: when the ticket is unassigned, set the `owner`
  MemberReference (the canonical writable primary-assignee field).
  If already owned by someone else, append the identifier to the
  `resources` co-assignee string best-effort.
- remove_resource: clear `owner` (with remove→replace:null fallback) if
  the target is the current owner, otherwise strip from `resources`.
- list_resources: merge owner + resources string, deduped by member id,
  so the UI reflects both single-owner and multi-resource assignments.
- update_ticket_status: verify CW applied the status by comparing the
  response body's status.id — raises PSAError with a clear message when
  CW silently rejects the change (e.g., status invalid for ticket's
  board), instead of reporting spurious success.
- Frontend: surface the backend error detail in the toast so users see
  the real reason instead of a generic "Failed to update" message.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 21:39:21 +00:00
04ff2ea301 fix(tickets): refresh status and resources in detail panel after update
Some checks failed
Mirror to GitHub / mirror (push) Successful in 3s
CI / backend (pull_request) Failing after 17m32s
CI / frontend (pull_request) Failing after 48s
CI / e2e (pull_request) Has been skipped
Status update was returning only new_status (string) and the parent list's
onStatusUpdated only set status_name. The <select> was bound to status_id,
which never changed — so it visually reverted to the old status even though
the PATCH succeeded.

- Backend: include new_status_id in the status-update response.
- Panel: own currentStatusId/currentStatusName state so the select reflects
  the change immediately and survives stale parent snapshots.
- Parent list: update status_id on both the row and selectedTicket so the
  list row stays in sync when the panel stays open.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 21:28:48 +00:00
60851b400a fix(tickets): status filter dropdown and CW resource assignment
Some checks failed
Mirror to GitHub / mirror (push) Successful in 4s
CI / backend (pull_request) Failing after 17m51s
CI / frontend (pull_request) Failing after 52s
CI / e2e (pull_request) Has been skipped
- Status filter: aggregate statuses across all boards (deduped by name)
  when no board is selected. Backend accepts status_name and filters by
  status/name so the same status matches across boards.
- Resource assignment: CW has no /service/tickets/{id}/members endpoint —
  assignees live in the ticket's comma-separated `resources` string field.
  Rewrote list/add/remove to read/PATCH that field via member identifier.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 21:03:00 +00:00
294b309faa fix: pre-landing review fixes — company_id filter and CW condition injection
- Apply company_id filter in CW search_tickets conditions (was silently ignored)
- Sanitize query string to strip single quotes before CW condition interpolation
- Add psaError state to TicketsPage for permissions error surfacing

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 14:42:05 +00:00
fb7690485b fix(tickets): fix statuses endpoint, members auth gate, and graceful error handling
All checks were successful
Mirror to GitHub / mirror (push) Successful in 3s
- Add GET /boards/{board_id}/statuses endpoint — direct board-to-statuses lookup
  without ticket roundabout; used by filter bar and new ticket form
- Fix TicketsPage and NewTicketModal to call getBoardStatuses(board_id) instead
  of misusing getTicketStatuses(ticket_id) with a board_id value
- Fix list_members auth: was require_account_owner (owner/super_admin only) —
  changed to require_engineer_or_admin so engineers can see member list for
  ticket assignment
- list_members: return [] on PSAError instead of 502 (Lesson 111 pattern)
- get_ticket_statuses: return [] on PSAError instead of 502

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 05:33:23 +00:00
6044d5a88b fix(tickets): fix permissions toast, board fallback, assignment search, remove load more
All checks were successful
Mirror to GitHub / mirror (push) Successful in 2s
- list_resources: return [] on PSAError instead of 502 — stops global interceptor
  toast when CW API key lacks ticket members permission (Lesson 111)
- list_boards/list_priorities: add warning logging so Railway logs reveal the
  root cause when CW permissions are missing
- TicketsPage: derive board options from ticket search results when listBoards
  returns empty (CW permissions fallback)
- TicketFilterBar: replace assignment <select> with searchable member picker —
  fixed options (All/Mine/Unassigned) + text-filtered member dropdown
- TicketQueue: remove Load More / infinite scroll; page now exists at /tickets

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 04:59:03 +00:00
00cd8b7c55 feat(tickets): update TicketQueue with mapping detection, 5-item cap, View All link
All checks were successful
Mirror to GitHub / mirror (push) Successful in 4s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 03:42:25 +00:00
fded959b5e fix(tickets): guard linkedTicket fetch with currentChatRef to prevent race condition
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 03:40:31 +00:00
5f5b9e5b23 feat(tickets): add spin-off ticket creation in ResolutionAssist — state, action handler, modal
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 03:37:46 +00:00
b2ee1a2150 fix(tickets): improve accessibility and error logging in ticket creation components
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 03:34:08 +00:00
08909aa884 feat(tickets): add AiTicketParseForm and NewTicketModal with two-tab creation flow
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 03:31:21 +00:00
070d2383bc fix: remove unused PSATicketSearchResult import
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 03:26:23 +00:00
d7b1fe6645 feat(tickets): add TicketResourceManager and full TicketDetailPanel with optimistic hydration
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 03:24:18 +00:00
a3f8bb3427 feat(tickets): add ticket detail subcomponents
- TicketDetailHeader: Display ticket info with status dropdown
- TicketNotesFeed: Chronological list of ticket notes with internal flag
- TicketAddNote: Form to add notes (requires linked session)
- TicketConfigs: Display related configurations/devices
- TicketRelated: List of related tickets as clickable buttons

All components use type-safe imports from psaContext and integrations APIs.
Styling follows design system (flat dark theme, electric blue accent, Tailwind v4).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 03:19:18 +00:00
f050afc2f7 feat(tickets): add /tickets route and sidebar nav item
Add Tickets page route to router with lazy loading and code splitting.
Add Tickets navigation entry to sidebar in RESOLVE section for both
icon rail and pinned layouts.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 03:15:35 +00:00
849e1c16e2 feat(tickets): add TicketsPage with URL-param filter state, stub detail panel and modal
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 03:12:26 +00:00
5310cd3fff fix(tickets): add company_id reset to filter clear button
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 03:09:51 +00:00
d2689afa53 feat(tickets): add TicketFilterBar and TicketListRow components
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 03:08:15 +00:00
9d88c8456c feat(tickets): add tickets API client, update integrations API for paginated search, fix callers
- Create frontend/src/api/tickets.ts with ticketsApi (resources, status, create, ai-parse, priorities, search)
- Update integrationsApi.searchTickets and searchTicketsQueue return types from PSATicketSearchResult[] to TicketListResponse
- Fix TicketQueue.tsx to use results.items (append/set) and results.items.length for pagination check
- Fix TicketPickerModal.tsx to use results.items when setting search results
- Export ticketsApi from api/index.ts

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 03:05:13 +00:00
506aac609d feat(tickets): add tickets types, expand PSATicketSearchResult/PSATicketInfo with IDs
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 03:02:53 +00:00
0d9babb986 fix(rls): add account_id to AISessionStep creations, fix boards toast
Some checks failed
CI / backend (push) Failing after 16m37s
CI / frontend (push) Failing after 45s
CI / e2e (push) Has been skipped
Mirror to GitHub / mirror (push) Successful in 3s
- flowpilot_engine: pass account_id at all 5 AISessionStep instantiation
  sites (_create_step_from_parsed x3, briefing step, status update step).
  Phase 4 RLS blocked every INSERT with NULL account_id — this broke all
  new FlowPilot sessions since the Phase 4 migration was applied.
- integrations: list_boards returns [] on PSAError instead of 502, stopping
  the spurious 'Server error' toast on dashboard load (boards are optional).
- client.ts: 5xx global toast now shows backend detail when available.
- useFlowPilotSession: startSession extracts backend detail for error state;
  suppresses duplicate toast for 5xx (global interceptor already handles it).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 04:41:14 +00:00
346576a730 feat(psa): ticket queue dashboard with board selector and session auto-start
Some checks failed
CI / frontend (push) Has been cancelled
CI / e2e (push) Has been cancelled
CI / backend (push) Has been cancelled
Mirror to GitHub / mirror (push) Successful in 2s
- Add PSABoard type + list_boards() to CW provider (cached 1h)
- Extend search_tickets with assigned_to_me, unassigned, board_ids, page, page_size
- New GET /integrations/psa/boards endpoint
- New TicketQueue dashboard component: My Tickets / Unassigned tabs,
  multi-select board filter, Load more pagination, Start Session per ticket
- Add TicketQueue to QuickStartPage after active sessions
- FlowPilotSessionPage auto-starts with ticket context when navigated
  from TicketQueue (psaTicketId + psaTicket in location.state)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 03:20:45 +00:00
chihlasm
0ed5977fee feat(admin): allow setting owner when creating an account
Adds optional owner_email field to the Create Account modal. Superadmin
can specify an existing user's email to assign as account owner at
creation time. Backend 404s with a clear message if the email is unknown.
Error detail now surfaces to the toast instead of a generic message.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 14:30:23 +00:00
chihlasm
c5b8229ef6 fix(admin): allow owner and admin account roles in user creation and role management
Four places were hardcoded to engineer|viewer only:
- AccountRoleUpdate schema (user.py) — blocked PUT /admin/users/{id}/account-role at the API level
- AdminUserCreate schema (admin.py) — blocked creating users with owner/admin role
- AccountDetailPage role dropdowns (create form + inline member role changer)
- AccountsPage create user role dropdown

Now all four accept the full set: owner, admin, engineer, viewer.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 13:24:17 +00:00
chihlasm
8eb814283d fix(psa): fix time entry AttributeError and show all users in member mapping
- Fix create_time_entry() using self._client instead of self.client
- GET /member-mappings now returns all active account users, not just mapped
  ones — allows manual assignment when auto-match by email doesn't work
- PsaMemberMappingResponse mapping fields are now Optional (id, external_member_id,
  external_member_name, matched_by) to represent unmapped users
- Frontend MemberMappingTab skips null external_member_id when building
  localMappings, and derives user list from all returned entries
- Add docs/connectwise-psa-testing-checklist.md

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 06:09:01 +00:00
chihlasm
b433b232dc polish(network): visual refinements across node, edge, and panel components
- DeviceNode: flat bg-card (no surface gradient), darker icon plate inset,
  correct text-muted token for category label
- GroupNode: label pill gets bg-card/90 background so it reads against canvas
- ConnectionEdge: label now has border + bg-card so it doesn't float invisible
- BaseHandle: tightened to 12px with accent-toned border
- NodeStatusIndicator: glow reduced to 0.15 opacity (design system compliant)
- ContextMenu: Ungroup now uses Ungroup icon instead of BoxSelect
- DeviceToolbar: group type icons coloured with semantic palette
- PropertiesPanel: empty state gets icon tile + cleaner copy hierarchy
- DiagramEditor: shortcut ? button repositioned above MiniMap, accent hover
- NetworkDiagrams list: card thumbnail placeholder uses dot-grid pattern,
  card menu gets icons and divider before destructive action

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 05:35:25 +00:00
chihlasm
015df1fe5f fix(network): consolidate import buttons, redesign empty state, add shortcut overlay
- Import/Export button in editor header: removed standalone Import button, moved
  draw.io import into Export/Import dropdown with labelled sections; fixes
  conceptual trap where Import implied operating on the current diagram
- List page: replaced two identical Upload-icon Import buttons with a single
  dropdown (Import JSON / Import draw.io) with format descriptions
- Empty state: replaced icon-in-box with a horizontal card featuring a static
  SVG topology preview, MSP-specific value prop, and dual CTAs
- Keyboard shortcuts: new KeyboardShortcutsOverlay component (4-group grid),
  triggered by ? key or the ? button pinned to the canvas bottom-right corner;
  wired into useCanvasShortcuts hook
- Fixed Share2 → FileOutput icon for draw.io export (Share2 = send to someone,
  FileOutput = export file format)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 04:49:25 +00:00
chihlasm
cf9c258f9e fix(network): surface connect tool and middle-pan 2026-04-14 03:41:21 +00:00
chihlasm
c063952f12 feat(network): add connect tool and middle-pan 2026-04-14 03:28:07 +00:00
chihlasm
36721eb5af feat(network): improve connector editing 2026-04-14 02:56:28 +00:00
chihlasm
3cd4084f78 refactor(network): simplify diagram node visuals 2026-04-14 02:42:47 +00:00
chihlasm
ed763d1cea chore(network): remove asset style lab 2026-04-14 02:29:26 +00:00
chihlasm
c37e216e0b feat(network): add asset style lab mockups 2026-04-14 02:10:48 +00:00
chihlasm
91cc9a4170 feat(network): draw.io XML import
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 01:30:22 +00:00
chihlasm
2a4220b496 feat(network): draw.io XML export
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 01:25:49 +00:00
chihlasm
c8f571db39 feat(network): thumbnail generation on save, shown on list page
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 01:22:51 +00:00
chihlasm
7efa22454d feat(network): improve PDF export with print stylesheet
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 01:20:28 +00:00
chihlasm
05421fc65c feat(network): add SVG export
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 01:19:19 +00:00
chihlasm
dfcad531e2 fix(network): context menu on groups + group/ungroup in properties panel
Context menu fix:
- Group nodes pass pointer events through to children in React Flow, so
  right-clicking a group fires onPaneContextMenu instead of onNodeContextMenu
- handlePaneContextMenu now checks for selected nodes and shows the node
  context menu (with align/group options) when any nodes are selected

Properties panel multi-select:
- Add Group section with type dropdown (Subnet, VLAN, Site, DMZ, Custom)
- "Group into [Type]" button creates a group of the chosen type
- Ungroup button appears when a group node is in the selection
- useDiagramCommands.groupSelection now accepts a groupType param and
  uses it as the label and color key for the new group node

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 00:55:34 +00:00
chihlasm
684fb07e47 feat(network): add pointer/hand mode toggle to diagram toolbar
- Header shows MousePointer2 (select) and Hand (pan) toggle buttons
- Select mode: drag on canvas draws a selection box (selectionOnDrag)
- Pan mode: drag on canvas pans the viewport (panOnDrag)
- Space held in either mode temporarily switches to pan (panActivationKeyCode)
- Keyboard shortcuts: V = select mode, H = pan mode
- Cursor changes to grab/grabbing in pan mode

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 00:38:51 +00:00
chihlasm
4a12c9b37d fix(network): persist group node type, size, and child parentId on save/load
Backend DiagramNode schema was missing nodeType, style, and parentId fields —
Pydantic stripped them on save, so group nodes lost their identity on reload
and re-appeared as small device icons.

- Backend: add nodeType, style (NodeStyle), parentId to DiagramNode schema
- Frontend: serialize parentId for device nodes inside groups
- Frontend: restore parentId + extent:'parent' on both deserializer paths (setNodes + history init)
- Frontend: add parentId to DiagramNode interface

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-13 23:49:26 +00:00
chihlasm
e41d7bd960 fix(network): align resize border with node visual boundary
NodeResizer handles positioned at RF wrapper size, but NodeTooltip and
NodeStatusIndicator wrappers had no size constraints, causing BaseNode
(w-full h-full) to shrink to content size instead of filling the wrapper.

Add w-full h-full to NodeTooltip, NodeTooltipTrigger, and
NodeStatusIndicator so the full height chain is maintained.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-13 21:27:58 +00:00
chihlasm
f2c3bd7a9b fix(network): normalize z-order to 1..N after bring-to-front/send-to-back
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-13 20:17:44 +00:00
chihlasm
9786c6b1fb feat(network): add inline label editing on DeviceNode (double-click)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-13 20:17:41 +00:00
chihlasm
4529955f7d feat(network): add orthogonal edge routing option
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-13 20:17:33 +00:00
chihlasm
b7b0d41f92 feat(network): add group/ungroup commands with bounding box calculation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-13 20:14:26 +00:00
chihlasm
a4512dcf90 feat(network): add GroupNode component with resize, inline label, and group type colors
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-13 20:13:03 +00:00
chihlasm
764db79060 feat(network): add alignment toolbar to PropertiesPanel for multi-select
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-13 20:11:12 +00:00
chihlasm
f90e2c956f feat(network): add align/distribute/group sections to context menu
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-13 20:09:32 +00:00
chihlasm
bdaea68dd3 feat(network): add useDiagramCommands — alignment and distribution command layer
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-13 20:08:37 +00:00