feat: usage-driven filters, deal roles, custom fields (v1.2.0) - #8
Conversation
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>
There was a problem hiding this comment.
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-rolesendsopportunity_contact_role_type_id=Nonefor new roles when--role-typeis omitted — please confirm the API accepts that, or require/omit the field. - Improvement:
people searchmay drop results if Apollo returns bothpeopleandcontacts. - Improvement:
resolve_stage_idcould 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} |
There was a problem hiding this comment.
[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-typefor 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 [] |
There was a problem hiding this comment.
[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.
| 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")))) |
There was a problem hiding this comment.
[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
... stagescommand to list them.
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 searchnow 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"andcontacts search --stage-name "Customer"resolve the name → ID internally, removing the round-trip throughpipelines stages/contacts stages(33× combined). Unknown names fail loudly and list the valid ones.3.
conversations transcript IDTranscript-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;--primarymakes the contact the sole primary.custom-fields list [--modality]— list custom field definitions.Dependency
Requires
qodev-apollo-api>=0.3.0(addsupdate_opportunity_roles+list_custom_fields).Verification (local, against apollo-api 0.3.0 via path source)
ruff check✓ ·ruff format --check✓ ·mypy✓ ·pytest71 passed ✓🤖 Generated with Claude Code