fix(sales): archived deals and stages on the deals board#8820
Conversation
Subscribers label a deal event by matching the payload against their own
filter: matching before but not after means remove, the reverse means add.
- dealsArchive published the pre-archive deal as `deal` and the archived
one as `oldDeal`, exactly backwards, so archiving a whole stage told
every board to add the cards back instead of dropping them. It also
published the list topic by hand, leaving an open deal detail unaware.
Route it through subscriptionWrapper the right way round, and await the
publishes instead of firing them from inside forEach.
- Restoring a deal recomputed its order after the payload had been read,
so the card reappeared at its archived-era position. Keep the item in
sync with the order that was persisted.
- The archive mutation refetched Deals with only { stageId }, which
matches no board column — they query it with pipelineId and the active
filters too — so a missed subscription event had nothing to recover it.
Refetch by operation name.
- Guard the cache as well: a list that excludes archived deals now drops
one as soon as it sees it archived, whatever action the server derived.
"Archive this list" set the stage status and nothing else, so it looked like it had done nothing. salesStages folded two unrelated rules into one condition: archived stages and private stages were both hidden only from non-owners. Being an owner is a reason to see private stages, not finished ones, so an owner kept the archived column on their board. Split the rules; callers that genuinely want everything, like the pipeline settings form, still pass isAll. Nothing was published either, so other sessions kept the column until a reload. Publish a stage status change on the pipeline topic and have the board re-read the stages it builds its columns from.
The archived toggle was offered in both views, so the board could be put into a mode where every column showed archived cards — work that is done and no longer belongs on a board of work in flight. Offer the toggle in the list view only, clear the mode when switching back to the board, and always filter archived deals out of board columns. The archived ribbon on board cards goes with it. While in the column sync: when a drag was still settling it kept every id already sitting in the column, checking only which column the id belonged to. Board items are never deleted from that map, so a deal archived in that window stayed on the board. Keep an id only if the fresh result still has it, or if its own move is the one in flight.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughChangesArchived-only filtering is added across GraphQL contracts, backend queries, and frontend query variables. Archive and stage mutations now publish synchronized updates, while deal subscriptions and boards handle archived records, stage changes, ordering, and empty states consistently. Archived deals flow
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant User
participant dealsArchive
participant subscriptionWrapper
participant useDeals
participant DealsBoard
User->>dealsArchive: archive deals
dealsArchive->>subscriptionWrapper: publish per-deal update
subscriptionWrapper->>useDeals: deliver archived deal event
useDeals->>DealsBoard: remove or update deal card
DealsBoard-->>User: render synchronized board
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
ESLint install timed out. The project may have too many dependencies for the sandbox. 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 |
Reviewer's GuideImplements consistent archived-deal and archived-stage handling so boards always show only active deals/stages while list view can explicitly query archived items, with real-time updates via GraphQL subscriptions and refined query params. Sequence diagram for archiving deals and updating board vs list viewssequenceDiagram
actor User
participant ArchivedDeals
participant ApolloClient
participant dealsArchive
participant models_Deals as models.Deals
participant subscriptionWrapper
participant graphqlPubsub
participant useDeals_board as useDeals_board
participant useDeals_list as useDeals_list
User ->> ArchivedDeals: click handleToggle
ArchivedDeals ->> ArchivedDeals: update URLSearchParams (archivedOnly)
ArchivedDeals ->> ApolloClient: execute DEALS_ARCHIVE
ApolloClient ->> dealsArchive: dealsArchive(stageId)
dealsArchive ->> models_Deals: find({ stageId })
loop for each item
dealsArchive ->> subscriptionWrapper: subscriptionWrapper(models, { action: update, deal, oldDeal, pipelineId })
subscriptionWrapper ->> graphqlPubsub: publish salesDealListChanged
end
graphqlPubsub -->> useDeals_board: salesDealListChanged
graphqlPubsub -->> useDeals_list: salesDealListChanged
useDeals_board ->> useDeals_board: dropsArchived = true
useDeals_board ->> useDeals_board: resolvedAction = remove when status archived
useDeals_board ->> useDeals_board: updateQuery removes archived deals
useDeals_list ->> useDeals_list: filterVariables.archivedOnly optional
useDeals_list ->> useDeals_list: updateQuery applies deal changes
useDeals_list ->> useDeals_list: list can query archivedOnly via getDealsQueryVariables
Sequence diagram for stage status change and board refreshsequenceDiagram
actor User
participant stagesEdit as stagesEdit
participant models_Stages as models.Stages
participant graphqlPubsub
participant usePipelineChanged
participant ApolloClient
User ->> stagesEdit: stageEdit(_id, doc)
stagesEdit ->> models_Stages: getStage(_id)
stagesEdit ->> models_Stages: updateStage(_id, doc)
stagesEdit ->> graphqlPubsub: publish salesPipelinesChanged:stageStatusChanged
graphqlPubsub -->> usePipelineChanged: salesPipelinesChanged
usePipelineChanged ->> usePipelineChanged: action === stageStatusChanged
usePipelineChanged ->> ApolloClient: refetchQueries include SalesStages
ApolloClient ->> usePipelineChanged: updated SalesStages
usePipelineChanged ->> usePipelineChanged: board columns refreshed without archived stages
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
Zolb646
left a comment
There was a problem hiding this comment.
@CodeRabbit add your pr description
There was a problem hiding this comment.
Hey - I've left some high level feedback:
- In
dealMutations.dealsArchive, the mutation args are still typed as{ stageId: string; processId: string }even thoughprocessIdis no longer destructured or used; consider removingprocessIdfrom the type to avoid confusion and keep the signature consistent. - The
withResolvedFieldsOnlyhelper inuseDealsQueryfilters out onlynullvalues from subscription payloads; if the backend ever usesundefinedto clear fields those changes would be ignored, so you may want to treat bothnullandundefinedas unresolved when merging deal updates.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `dealMutations.dealsArchive`, the mutation args are still typed as `{ stageId: string; processId: string }` even though `processId` is no longer destructured or used; consider removing `processId` from the type to avoid confusion and keep the signature consistent.
- The `withResolvedFieldsOnly` helper in `useDealsQuery` filters out only `null` values from subscription payloads; if the backend ever uses `undefined` to clear fields those changes would be ignored, so you may want to treat both `null` and `undefined` as unresolved when merging deal updates.Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@backend/plugins/sales_api/src/modules/sales/graphql/resolvers/queries/stages.ts`:
- Around line 30-32: Replace the explicit any type on filter in the stages query
resolver with FilterQuery<IStageDocument>, preserving the existing isAll
conditional and Mongo status filter while restoring type checking for the
composed query.
In
`@frontend/plugins/sales_ui/src/modules/deals/boards/hooks/usePipelineChanged.ts`:
- Around line 21-25: Update the ISalesPipelinesChangedPayload type to model
stageStatusChanged as a distinct payload variant containing stageId and status
without requiring item or destinationStageId. Use a discriminated union or
action-specific optional fields, while preserving the existing deal payload
requirements for actions that publish item and destinationStageId.
In
`@frontend/plugins/sales_ui/src/modules/deals/cards/hooks/deals/useDealsQuery.tsx`:
- Around line 29-34: Update withResolvedFieldsOnly to retain entries whose
values are explicitly null, so subscription updates can clear previously cached
deal fields during merging. Remove the null-filtering condition while preserving
the existing Partial<IDeal> reduction and handling of other values unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: b6d70bfd-2881-49b4-b672-64b07c6a0033
📒 Files selected for processing (18)
backend/plugins/sales_api/src/modules/sales/@types/deal.tsbackend/plugins/sales_api/src/modules/sales/graphql/resolvers/mutations/deals.tsbackend/plugins/sales_api/src/modules/sales/graphql/resolvers/mutations/stages.tsbackend/plugins/sales_api/src/modules/sales/graphql/resolvers/queries/deals.tsbackend/plugins/sales_api/src/modules/sales/graphql/resolvers/queries/stages.tsbackend/plugins/sales_api/src/modules/sales/graphql/resolvers/utils.tsbackend/plugins/sales_api/src/modules/sales/graphql/schemas/deal.tsfrontend/plugins/sales_ui/src/modules/deals/actionBar/components/ArchivedDeals.tsxfrontend/plugins/sales_ui/src/modules/deals/actionBar/components/MainActionBar.tsxfrontend/plugins/sales_ui/src/modules/deals/boards/components/DealsBoard.tsxfrontend/plugins/sales_ui/src/modules/deals/boards/components/DealsBoardCard.tsxfrontend/plugins/sales_ui/src/modules/deals/boards/components/DealsBoardColumn.tsxfrontend/plugins/sales_ui/src/modules/deals/boards/components/list/DealsRecordTable.tsxfrontend/plugins/sales_ui/src/modules/deals/boards/hooks/usePipelineChanged.tsfrontend/plugins/sales_ui/src/modules/deals/cards/hooks/deals/useDealsArchive.tsxfrontend/plugins/sales_ui/src/modules/deals/cards/hooks/deals/useDealsQuery.tsxfrontend/plugins/sales_ui/src/modules/deals/graphql/queries/DealsQueries.tsfrontend/plugins/sales_ui/src/modules/deals/utils/queryVariables.ts
💤 Files with no reviewable changes (1)
- frontend/plugins/sales_ui/src/modules/deals/boards/components/DealsBoardCard.tsx
- type the stages filter with FilterQuery<IStageDocument> instead of any - model salesPipelinesChanged as a discriminated union per action - guard the deal subscription payload against remove events without a deal
|
Summary
Fix archived deal and stage behavior in the sales pipeline. Archived items now update smoothly in real time, remain hidden from board view, and are available only in list view.
Changes
Summary by Sourcery
Align archived deals and stages behavior across sales board and list views, ensuring archived items are filtered correctly, updated in real time, and surfaced only where intended.
New Features:
Bug Fixes:
Enhancements:
Summary by CodeRabbit
New Features
archivedOnlyfilter across deal search, GraphQL query inputs, and UI query variables.Bug Fixes
UI/UX