Skip to content

Dev#692

Merged
ashwin31 merged 6 commits into
masterfrom
dev
May 25, 2026
Merged

Dev#692
ashwin31 merged 6 commits into
masterfrom
dev

Conversation

@ashwin31

@ashwin31 ashwin31 commented May 25, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • New Features

    • Added CSV bulk import for contacts with preview validation and commit support.
    • Added kanban board view for opportunities with drag-and-drop card positioning within and between stages.
    • Seeded demo data now uses demo-safe fictional data pools for names, companies, emails, and phone numbers.
  • Chores

    • Updated frontend package dependencies and workspace configuration.
    • Updated mobile app version.

Review Change Stack

Copilot AI review requested due to automatic review settings May 25, 2026 13:29
@@ -0,0 +1,2 @@
export { default as OpportunityKanban } from './OpportunityKanban.svelte';
export { default as OpportunityCard } from './OpportunityCard.svelte';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'export' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,2 @@
export { default as OpportunityKanban } from './OpportunityKanban.svelte';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'export' is only available in ES6 (use 'esversion: 6').

);
body = {};
}
return { status: response.status, body };

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'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}):`,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'template literal syntax' is only available in ES6 (use 'esversion: 6').

body: fd
});
const raw = await response.text();
let body;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'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`;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'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';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'import' is only available in ES6 (use 'esversion: 6').

`/opportunities/kanban/${kanbanQueryString ? '?' + kanbanQueryString : ''}`,
{},
{ cookies, org }
).catch((err) => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'arrow function syntax (=>)' is only available in ES6 (use 'esversion: 6').

? apiRequest(
`/opportunities/kanban/${kanbanQueryString ? '?' + kanbanQueryString : ''}`,
{},
{ cookies, org }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'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 : ''}`,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'template literal syntax' is only available in ES6 (use 'esversion: 6').

@ashwin31 ashwin31 merged commit d8422f5 into master May 25, 2026
5 of 7 checks passed
@coderabbitai

coderabbitai Bot commented May 25, 2026

Copy link
Copy Markdown

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1ee502ca-ee73-440b-845c-713c1b9357af

📥 Commits

Reviewing files that changed from the base of the PR and between 571d242 and 9504048.

⛔ Files ignored due to path filters (2)
  • frontend/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • mobile/pubspec.lock is excluded by !**/*.lock
📒 Files selected for processing (34)
  • backend/common/management/commands/seed_data.py
  • backend/contacts/import_views.py
  • backend/contacts/services/__init__.py
  • backend/contacts/services/csv_import.py
  • backend/contacts/tests/test_import.py
  • backend/contacts/urls.py
  • backend/opportunity/migrations/0011_opportunity_kanban_order.py
  • backend/opportunity/models.py
  • backend/opportunity/serializer.py
  • backend/opportunity/urls.py
  • backend/opportunity/views/kanban_views.py
  • frontend/package.json
  • frontend/pnpm-workspace.yaml
  • frontend/src/lib/components/contacts/ContactImportDrawer.svelte
  • frontend/src/lib/components/ui/kanban/KanbanBoard.svelte
  • frontend/src/lib/components/ui/kanban/KanbanColumn.svelte
  • frontend/src/lib/components/ui/lead-kanban/LeadCard.svelte
  • frontend/src/lib/components/ui/lead-kanban/LeadKanban.svelte
  • frontend/src/lib/components/ui/opportunity-kanban/OpportunityCard.svelte
  • frontend/src/lib/components/ui/opportunity-kanban/OpportunityKanban.svelte
  • frontend/src/lib/components/ui/opportunity-kanban/index.js
  • frontend/src/lib/components/ui/task-kanban/TaskCard.svelte
  • frontend/src/lib/components/ui/task-kanban/TaskKanban.svelte
  • frontend/src/lib/components/ui/ticket-kanban/TicketCard.svelte
  • frontend/src/lib/components/ui/ticket-kanban/TicketKanban.svelte
  • frontend/src/routes/(app)/contacts/+page.server.js
  • frontend/src/routes/(app)/contacts/+page.svelte
  • frontend/src/routes/(app)/leads/+page.server.js
  • frontend/src/routes/(app)/leads/+page.svelte
  • frontend/src/routes/(app)/opportunities/+page.server.js
  • frontend/src/routes/(app)/opportunities/+page.svelte
  • frontend/src/routes/(app)/tasks/+page.svelte
  • frontend/src/routes/(app)/tickets/+page.svelte
  • mobile/pubspec.yaml

📝 Walkthrough

Walkthrough

This 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.

Changes

Kanban Infrastructure & Opportunity Pipeline

Layer / File(s) Summary
Kanban positioning infrastructure with neighbors
frontend/src/lib/components/ui/kanban/KanbanBoard.svelte, frontend/src/lib/components/ui/kanban/KanbanColumn.svelte
KanbanBoard and KanbanColumn updated to support neighbor-based drag/drop positioning using aboveId/belowId hints, optimistic insertion with rollback, and styled drag images.
Opportunity kanban backend model, serializers, and views
backend/opportunity/models.py, backend/opportunity/migrations/0011_opportunity_kanban_order.py, backend/opportunity/serializer.py, backend/opportunity/urls.py, backend/opportunity/views/kanban_views.py
Add kanban_order decimal field to Opportunity with migration backfill, implement OpportunityKanbanView (GET with filters/RBAC) and OpportunityMoveView (PATCH with fractional order calculation based on neighbors), add serializers for kanban cards and move payloads.
Opportunity kanban frontend components and page integration
frontend/src/lib/components/ui/opportunity-kanban/OpportunityCard.svelte, frontend/src/lib/components/ui/opportunity-kanban/OpportunityKanban.svelte, frontend/src/lib/components/ui/opportunity-kanban/index.js, frontend/src/routes/(app)/opportunities/+page.server.js, frontend/src/routes/(app)/opportunities/+page.svelte
Add OpportunityCard and OpportunityKanban components, extend opportunities page to fetch kanban data via server load, implement moveOpportunity action, add list/kanban view toggle with conditional column visibility.
Lead, task, and ticket kanban pages wired to neighbor positioning
frontend/src/lib/components/ui/lead-kanban/LeadKanban.svelte, frontend/src/lib/components/ui/task-kanban/TaskKanban.svelte, frontend/src/lib/components/ui/task-kanban/TaskCard.svelte, frontend/src/lib/components/ui/ticket-kanban/TicketKanban.svelte, frontend/src/routes/(app)/leads/+page.server.js, frontend/src/routes/(app)/leads/+page.svelte, frontend/src/routes/(app)/tasks/+page.svelte, frontend/src/routes/(app)/tickets/+page.svelte
Update all three kanban pages' server actions and client components to capture and forward aboveId/belowId context; extend page handlers to support creating new cards from column actions.
Kanban card UI refactoring and simplification
frontend/src/lib/components/ui/lead-kanban/LeadCard.svelte, frontend/src/lib/components/ui/task-kanban/TaskCard.svelte, frontend/src/lib/components/ui/ticket-kanban/TicketCard.svelte
Replace config-driven icon/badge rendering with simplified color-strip approach; reduce Lucide imports; update avatar color generation from gradients to solid classes; remove animations/glows/visual effects.

CSV Contact Import System

Layer / File(s) Summary
CSV import service with validation and transaction handling
backend/contacts/services/csv_import.py
Implement parse_and_validate and commit_rows with CSV decoding, header/field validation, org-scoped duplicate detection (email/phone/full-name), reference lookups, tag caching, and IntegrityError-to-400 conversion.
CSV import REST API endpoints with authorization and file validation
backend/contacts/import_views.py, backend/contacts/urls.py
Add ContactImportPreviewView and ContactImportCommitView with 5 MB upload cap, CSV extension validation, _can_import authorization, and multipart file handling.
CSV import comprehensive test suite
backend/contacts/tests/test_import.py
Add pytest tests covering preview endpoint (valid parsing, header validation, duplicates, field formats, permissions), commit endpoint (atomic creation, all-or-nothing, IntegrityError handling), and CSV builder helper.
CSV import frontend drawer component and page integration
frontend/src/lib/components/contacts/ContactImportDrawer.svelte, frontend/src/routes/(app)/contacts/+page.server.js, frontend/src/routes/(app)/contacts/+page.svelte
Implement multi-step import UI (select/preview/done) with file validation, server action forwarding, error CSV download, template download, and success toast; integrate into contacts page.

Demo-Safe Seed Data Refactoring

Layer / File(s) Summary
Curated fictional data pools and generators
backend/common/management/commands/seed_data.py
Add constant lists (names, companies, streets, job titles) and private helper methods to generate demo-safe identities using reserved domains (example.com), fictional NANP range (+1 555-555-01XX), and deterministic pools.
Apply demo-safe generators to contact/account/lead creation
backend/common/management/commands/seed_data.py
Update contact, account, and lead creation to use new generators; refactor date/list conditionals for readability without changing logic.

Dependency Updates

Layer / File(s) Summary
Frontend package versions
frontend/package.json, frontend/pnpm-workspace.yaml
Bump devDependencies (@lucide/svelte, @sveltejs/kit, etc.) and dependencies (@sentry/sveltekit, axios, etc.); add pnpm workspace minimum release age exclusion for @sveltejs/kit.
Mobile app version bump
mobile/pubspec.yaml
Increment Flutter version from 1.1.0+10 to 1.2.0+11.

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
Loading
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
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • MicroPyramid/Django-CRM#650: Implements opportunity kanban cards with aging status rendering via StageAgingConfig, which this PR builds upon by adding the full kanban view, stage transitions, and fractional positioning.

Poem

🐰 A rabbit hops through pipeline stages swift,
Cards dancing with their fractional shift,
Contacts flood in via CSV delight,
Demo data curated, demo-safe and bright,
Simplified cards, neighbors in sight! 🎯

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dev

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

http_status = (
status.HTTP_400_BAD_REQUEST if result.get("error") else status.HTTP_200_OK
)
return Response(result, status=http_status)

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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_by on 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+101.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

  • OpportunityKanban is passed loading={!kanbanData}. In this page’s server load, the kanban fetch is explicitly catched and returns null on failure; in that case the UI will show the Kanban loading skeleton indefinitely (because loading stays true) instead of the board’s empty/error state. loading should reflect “currently fetching”, not “no data returned”.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +1016 to +1022
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');
}
Comment on lines +1665 to +1668
<LeadKanban
data={kanbanData}
loading={!kanbanData}
onStatusChange={handleKanbanStatusChange}
Comment on lines +178 to +190
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()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants