Skip to content

feat: usage-driven filters, deal roles, custom fields (v1.2.0) - #8

Merged
jschfflr merged 1 commit into
mainfrom
feat/filters-roles-custom-fields
Jul 8, 2026
Merged

feat: usage-driven filters, deal roles, custom fields (v1.2.0)#8
jschfflr merged 1 commit into
mainfrom
feat/filters-roles-custom-fields

Conversation

@jschfflr

@jschfflr jschfflr commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Implements the four UX improvements from the usage analysis of recent Apollo sessions. Each closes a gap where users had been dropping to raw curl or doing an extra lookup.

1. people search — company-domain filter (highest signal)

--organization-domains acme.com,globex.com (alias --domains) finds people at specific companies — the single most common raw-curl workaround in the transcripts (q_organization_domains_list, 61×). Also adds --seniorities; people search now respects the global --limit/--page (it silently ignored them before) and renders a table.

2. Filter deals/contacts by stage name

deals search --stage-name "Negotiation" and contacts search --stage-name "Customer" resolve the name → ID internally, removing the round-trip through pipelines stages / contacts stages (33× combined). Unknown names fail loudly and list the valid ones.

3. conversations transcript ID

Transcript-only view (users invoked this expecting it to exist).

4. Deal roles + custom fields (curl-only until now)

  • deals role-types — list available role types.
  • deals set-role DEAL_ID --contact-id C [--role-type "Decision Maker"] [--primary] — read-modify-write of the deal's contact roles; --primary makes the contact the sole primary.
  • custom-fields list [--modality] — list custom field definitions.

Dependency

Requires qodev-apollo-api>=0.3.0 (adds update_opportunity_roles + list_custom_fields).

⚠️ Merge order: this depends on apollo-api 0.3.0 being on PyPI. CI here (UV_NO_SOURCES=1) pulls the API from PyPI, so it will stay red until apollo-api#10 is merged and v0.3.0 is published. Merge/publish apollo-api first.

Verification (local, against apollo-api 0.3.0 via path source)

ruff check ✓ · ruff format --check ✓ · mypy ✓ · pytest 71 passed ✓

🤖 Generated with Claude Code

Closes the highest-signal UX gaps found by analysing recent Apollo usage —
each item removes a raw-curl workaround or an extra lookup:

- people search: --organization-domains (the #1 curl workaround,
  q_organization_domains_list) + --seniorities, and now respects the global
  --limit/--page (previously ignored). Results render as a table.
- deals/contacts search: --stage-name resolves a stage name to its ID
  internally, removing the pipelines/contacts `stages` round-trip. Unknown
  names fail loudly with the valid list.
- conversations transcript ID: transcript-only view.
- deals role-types + deals set-role: manage contact roles on a deal
  (read-modify-write; --primary sets the sole primary). Previously curl-only.
- custom-fields list [--modality]: list custom field definitions.

Requires qodev-apollo-api>=0.3.0 (update_opportunity_roles, list_custom_fields).
Bumps to 1.2.0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@peqy peqy Bot 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.

Solid set of UX improvements (stage-name resolution, people domain filter + pagination, transcript-only view, role types/custom fields), and the tests cover the new behaviors well.

Issues:

  • Question: deals set-role sends opportunity_contact_role_type_id=None for new roles when --role-type is omitted — please confirm the API accepts that, or require/omit the field.
  • Improvement: people search may drop results if Apollo returns both people and contacts.
  • Improvement: resolve_stage_id could emit an overly large “Available:” list.

Found 3 issues (0 critical, 2 improvements, 1 question).


entry = next((r for r in roles if r["contact_id"] == contact_id), None)
if entry is None:
entry = {"contact_id": contact_id, "opportunity_contact_role_type_id": None, "is_primary": False}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[Question] deals set-role adds a new entry with opportunity_contact_role_type_id: None when --role-type isn’t provided.

Fix: Confirm qodev-apollo-api / Apollo accepts roles without a role type. If not, either require --role-type for new roles, or omit the key entirely until it’s set (so we don’t send an explicit null).

output(result, ctx=ctx)
# search_people returns the raw Apollo dict; people live under "people" (and
# sometimes "contacts" for matched CRM records).
items = result.get("people") or result.get("contacts") or []

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[Improvement] people search picks people or contacts (result.get("people") or result.get("contacts")). If Apollo ever returns both, we’ll silently drop the contacts half.

Fix: Consider combining the lists (and maybe annotating source) or at least prefer/merge deterministically based on the API contract.

Comment thread src/apollo_cli/util.py
target = name.strip().lower()
match = next((s for s in stages if (_field(s, "name") or "").lower() == target), None)
if match is None:
available = ", ".join(sorted(n for s in stages if (n := _field(s, "name"))))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[Improvement] resolve_stage_id error message lists all available names unbounded. On large stage lists this could get very noisy.

Fix: Consider capping (e.g., first N sorted names + “…”), or include a count and suggest running the relevant ... stages command to list them.

@jschfflr
jschfflr merged commit 536bf9c into main Jul 8, 2026
6 of 10 checks passed
@jschfflr
jschfflr deleted the feat/filters-roles-custom-fields branch July 8, 2026 12:14
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.

1 participant