Conversation
…ation for seed_data command
…l updates with optimistic UI and rollback capabilities
…p ordering and status-based columns.
| @@ -0,0 +1,2 @@ | |||
| export { default as OpportunityKanban } from './OpportunityKanban.svelte'; | |||
| export { default as OpportunityCard } from './OpportunityCard.svelte'; | |||
There was a problem hiding this comment.
'export' is only available in ES6 (use 'esversion: 6').
| @@ -0,0 +1,2 @@ | |||
| export { default as OpportunityKanban } from './OpportunityKanban.svelte'; | |||
There was a problem hiding this comment.
'export' is only available in ES6 (use 'esversion: 6').
| ); | ||
| body = {}; | ||
| } | ||
| return { status: response.status, body }; |
There was a problem hiding this comment.
'object short notation' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).
| body = raw ? JSON.parse(raw) : {}; | ||
| } catch (err) { | ||
| console.error( | ||
| `forwardMultipart: non-JSON response from ${endpoint} (status ${response.status}):`, |
There was a problem hiding this comment.
'template literal syntax' is only available in ES6 (use 'esversion: 6').
| body: fd | ||
| }); | ||
| const raw = await response.text(); | ||
| let body; |
There was a problem hiding this comment.
'let' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).
| import { env } from '$env/dynamic/public'; | ||
| import { apiRequest, buildQueryParams } from '$lib/api-helpers.js'; | ||
|
|
||
| const API_BASE_URL = `${env.PUBLIC_DJANGO_API_URL}/api`; |
There was a problem hiding this comment.
'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).
'template literal syntax' is only available in ES6 (use 'esversion: 6').
| */ | ||
|
|
||
| import { error, fail } from '@sveltejs/kit'; | ||
| import { env } from '$env/dynamic/public'; |
There was a problem hiding this comment.
'import' is only available in ES6 (use 'esversion: 6').
| `/opportunities/kanban/${kanbanQueryString ? '?' + kanbanQueryString : ''}`, | ||
| {}, | ||
| { cookies, org } | ||
| ).catch((err) => { |
There was a problem hiding this comment.
'arrow function syntax (=>)' is only available in ES6 (use 'esversion: 6').
| ? apiRequest( | ||
| `/opportunities/kanban/${kanbanQueryString ? '?' + kanbanQueryString : ''}`, | ||
| {}, | ||
| { cookies, org } |
There was a problem hiding this comment.
'object short notation' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).
| apiRequest(`/opportunities/${queryString ? `?${queryString}` : ''}`, {}, { cookies, org }), | ||
| viewMode === 'kanban' | ||
| ? apiRequest( | ||
| `/opportunities/kanban/${kanbanQueryString ? '?' + kanbanQueryString : ''}`, |
There was a problem hiding this comment.
'template literal syntax' is only available in ES6 (use 'esversion: 6').
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (2)
📒 Files selected for processing (34)
📝 WalkthroughWalkthroughThis PR enhances kanban management across the CRM, introduces CSV-based contact import, refactors seed data to use demo-safe pools, and simplifies kanban card styling. The changes span backend models/views/services, frontend components/pages, tests, migrations, and dependencies. ChangesKanban Infrastructure & Opportunity Pipeline
CSV Contact Import System
Demo-Safe Seed Data Refactoring
Dependency Updates
Sequence Diagram(s)sequenceDiagram
participant User
participant KanbanBoard
participant Column
participant API
User->>KanbanBoard: Drag opportunity card
KanbanBoard->>KanbanBoard: Clone drag image, mark source
User->>Column: Drop below neighbor
Column->>Column: Resolve above/below IDs
Column->>KanbanBoard: onDrop(card, column, {aboveId, belowId})
KanbanBoard->>KanbanBoard: Optimistic insert at position
KanbanBoard->>API: PATCH /opportunities/{id}/move/
API->>API: Calculate fractional kanban_order
API->>API: Update stage, save
alt Success
API-->>KanbanBoard: 200 OK
else Failure
API-->>KanbanBoard: Error
KanbanBoard->>KanbanBoard: Rollback items
end
sequenceDiagram
participant User
participant ImportDrawer
participant PreviewAction
participant parse_and_validate
participant CommitAction
participant commit_rows
participant DB
User->>ImportDrawer: Select CSV file
User->>ImportDrawer: Click Preview
ImportDrawer->>PreviewAction: fetch(?/importPreview)
PreviewAction->>parse_and_validate: Parse & validate (no write)
parse_and_validate->>parse_and_validate: Check refs, detect duplicates
parse_and_validate-->>PreviewAction: {valid, errors, summary}
PreviewAction-->>ImportDrawer: 200 OK
ImportDrawer->>ImportDrawer: Show results + error details
User->>ImportDrawer: Click Import
ImportDrawer->>CommitAction: fetch(?/importCommit)
CommitAction->>commit_rows: Parse, validate, commit (atomic)
commit_rows->>DB: BEGIN
commit_rows->>DB: CREATE Contact rows + assign teams/users
commit_rows->>DB: GET OR CREATE tags
alt All rows valid
commit_rows->>DB: COMMIT
DB-->>CommitAction: Success
CommitAction-->>ImportDrawer: 200 OK
ImportDrawer->>ImportDrawer: invalidateAll(), show toast
else Any row invalid
commit_rows-->>CommitAction: 400 with row errors
CommitAction-->>ImportDrawer: {error: true, rows: [...]}
ImportDrawer->>ImportDrawer: Show per-row error list
else IntegrityError (race)
DB-->>commit_rows: Conflict
commit_rows-->>CommitAction: 400 with concurrency msg
CommitAction-->>ImportDrawer: {error: true}
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
| http_status = ( | ||
| status.HTTP_400_BAD_REQUEST if result.get("error") else status.HTTP_200_OK | ||
| ) | ||
| return Response(result, status=http_status) |
There was a problem hiding this comment.
Pull request overview
This PR updates the mobile app version and enhances several SvelteKit “app” routes with improved Kanban interactions (neighbor-aware ordering) plus some UI/UX refinements for tickets/tasks views.
Changes:
- Bump Flutter app version and update the Dart/Flutter lockfile.
- Update tickets/tasks pages to support neighbor-aware Kanban moves (above/below IDs) and reorganize parts of the header/filter UI.
- Extend opportunity move API behavior for Kanban-driven stage changes (including stamping
closed_byon close).
Reviewed changes
Copilot reviewed 33 out of 36 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| mobile/pubspec.yaml | App version bump (1.1.0+10 → 1.2.0+11). |
| mobile/pubspec.lock | Updates/adjusts resolved dependency versions and hashes. |
| frontend/src/routes/(app)/tickets/+page.svelte | Updates Kanban move handler signature to accept above/below IDs; UI/header refactor; loading now derived from kanbanData. |
| frontend/src/routes/(app)/tasks/+page.svelte | Adds untrack-based SSR-friendly initialization for optimistic task list state; supports adding a task from a Kanban column; updates Kanban move handler signature. |
| backend/opportunity/views/kanban_views.py | Opportunity Kanban move endpoint logic, including RBAC and close-stage handling (closed_by). |
Files not reviewed (1)
- frontend/pnpm-lock.yaml: Language not supported
Comments suppressed due to low confidence (1)
frontend/src/routes/(app)/opportunities/+page.svelte:1405
OpportunityKanbanis passedloading={!kanbanData}. In this page’s server load, the kanban fetch is explicitlycatched and returnsnullon failure; in that case the UI will show the Kanban loading skeleton indefinitely (becauseloadingstays true) instead of the board’s empty/error state.loadingshould reflect “currently fetching”, not “no data returned”.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const response = await fetch('?/moveOpportunity', { method: 'POST', body: form }); | ||
| const result = await response.json(); | ||
|
|
||
| if (result.type === 'failure' || result.data?.error) { | ||
| // Throw so KanbanBoard can roll back its optimistic move. | ||
| throw new Error(result.data?.message || 'Failed to move opportunity'); | ||
| } |
| <LeadKanban | ||
| data={kanbanData} | ||
| loading={!kanbanData} | ||
| onStatusChange={handleKanbanStatusChange} |
| new_stage = data["stage"] | ||
| # If the user is moving INTO a closed stage, stamp closed_by — mirrors | ||
| # the OpportunityListView.post / OpportunityDetailView.put behavior so | ||
| # kanban-driven close events look identical to form-driven ones. | ||
| if new_stage in ("CLOSED_WON", "CLOSED_LOST") and opportunity.stage != new_stage: | ||
| opportunity.closed_by = request.profile | ||
|
|
||
| opportunity.stage = new_stage | ||
| opportunity.kanban_order = self._calculate_order(data, opportunity, org) | ||
|
|
||
| # Opportunity.save() auto-updates probability + stage_changed_at — no | ||
| # need to pass update_fields here, the model handles its own bookkeeping. | ||
| opportunity.save() |
Summary by CodeRabbit
New Features
Chores