Skip to content

feat: add project_id and workspace_search to AdvancedSearchWorkItem#24

Open
lifeiscontent wants to merge 1 commit intomakeplane:mainfrom
lifeiscontent:feat/work-item-query-filters
Open

feat: add project_id and workspace_search to AdvancedSearchWorkItem#24
lifeiscontent wants to merge 1 commit intomakeplane:mainfrom
lifeiscontent:feat/work-item-query-filters

Conversation

@lifeiscontent
Copy link
Contributor

@lifeiscontent lifeiscontent commented Mar 23, 2026

Summary

Adds project_id and workspace_search fields to AdvancedSearchWorkItem model, and adds filter fields to WorkItemQueryParams.

Changes

AdvancedSearchWorkItem

  • Added project_id — scope search to a specific project
  • Added workspace_search — search across all projects in the workspace

These fields are already supported by the API (WorkItemAdvancedSearchRequestSerializer) but were missing from the SDK model.

WorkItemQueryParams

  • Added filter fields (assignee_id__in, state_group__in, priority__in, etc.) for future use when the public API list endpoint adds IssueFilterSet support.

Verified

  • All 13 unit tests pass against UAT
  • Advanced search with project_id and workspace_search tested end-to-end

Companion PR

Summary by CodeRabbit

  • New Features
    • Enhanced work item filtering with options to filter by assignees, states, state groups, priorities, labels, and creators.
    • Added draft and archived status filtering for work items.
    • Advanced search accepts project-scoped and workspace-level search flags.
    • List-based filters are now accepted as comma-separated parameters for queries.

Copilot AI review requested due to automatic review settings March 23, 2026 00:17
@coderabbitai
Copy link

coderabbitai bot commented Mar 23, 2026

Warning

Rate limit exceeded

@lifeiscontent has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 27 minutes and 43 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a75b93eb-b393-47f6-a113-ac1abe7bd8d0

📥 Commits

Reviewing files that changed from the base of the PR and between 1b79a9a and 544ea4f.

📒 Files selected for processing (2)
  • plane/models/query_params.py
  • plane/models/work_items.py
📝 Walkthrough

Walkthrough

Added eight optional filter fields and a serializer to WorkItemQueryParams to convert list fields to comma-separated strings for query parameters; extended AdvancedSearchWorkItem with optional project_id and workspace_search fields.

Changes

Cohort / File(s) Summary
Query Parameter Filtering
plane/models/query_params.py
Added list-based __in filters (assignee_id__in, state_id__in, state_group__in, priority__in, label_id__in, created_by_id__in) and boolean flags (is_draft, is_archived). Added @model_serializer(mode="wrap") _serialize to convert list values into comma-separated strings for serialization.
Advanced Search Payload
plane/models/work_items.py
Extended AdvancedSearchWorkItem request model with optional `project_id: str

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 I nibble on filters, tidy and neat,
Turning lists to commas, a small tasty treat.
Projects and workspaces join the fun,
Hoppity hops — the queries run! 🎉

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Title check ⚠️ Warning The PR title only addresses one of the two major changes: it mentions project_id and workspace_search from AdvancedSearchWorkItem but omits the primary change of adding eight filter fields to WorkItemQueryParams. Update the title to reflect the main change: 'feat: add filter fields to WorkItemQueryParams' or 'feat: add server-side filtering support to WorkItemQueryParams'.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
plane/models/query_params.py (1)

98-105: Implementation is correct; optional improvement for empty list handling.

The wrap serializer correctly post-processes the default serialization to convert lists to comma-separated strings for django-filters compatibility. The handler(self) signature is valid in Pydantic v2.

Minor consideration: an empty list [] will serialize to "", producing a query parameter like ?assignee_id__in=. If this is undesired, filter out empty strings:

Optional: exclude empty list results
 `@model_serializer`(mode="wrap")
 def _serialize(self, handler):  # type: ignore[no-untyped-def]
     """Serialize list fields as comma-separated strings for django-filters."""
     data = handler(self)
     for key, value in data.items():
         if isinstance(value, list):
             data[key] = ",".join(str(v) for v in value)
+    return {k: v for k, v in data.items() if v != ""}
-    return data
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plane/models/query_params.py` around lines 98 - 105, The current _serialize
method converts list fields to comma-separated strings but leaves empty lists as
an empty string (e.g., ?assignee_id__in=); update _serialize (the
model_serializer wrapper that calls handler(self)) to skip or remove keys whose
value is an empty list so they are not serialized as empty strings—detect list
values in the data dict after handler(self) and if the list is empty, delete
data[key] (or set it to None/omit it) instead of converting to ",".join, while
still converting non-empty lists as before.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@plane/models/query_params.py`:
- Around line 98-105: The current _serialize method converts list fields to
comma-separated strings but leaves empty lists as an empty string (e.g.,
?assignee_id__in=); update _serialize (the model_serializer wrapper that calls
handler(self)) to skip or remove keys whose value is an empty list so they are
not serialized as empty strings—detect list values in the data dict after
handler(self) and if the list is empty, delete data[key] (or set it to None/omit
it) instead of converting to ",".join, while still converting non-empty lists as
before.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 53d91f60-ecbd-42b1-a54d-e0c3e241f99c

📥 Commits

Reviewing files that changed from the base of the PR and between 5edb2fc and 94cf652.

📒 Files selected for processing (1)
  • plane/models/query_params.py

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds first-class server-side filtering to the SDK’s WorkItemQueryParams, aligning the Python client with Plane’s REST API filtering capabilities and avoiding client-side filtering workarounds.

Changes:

  • Added filter fields to WorkItemQueryParams (assignee/state/priority/labels/creator + draft/archived flags).
  • Added a Pydantic model_serializer to serialize list filters as comma-separated strings for django-filters BaseInFilter compatibility.

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

Comment on lines +98 to +100
@model_serializer(mode="wrap")
def _serialize(self, handler): # type: ignore[no-untyped-def]
"""Serialize list fields as comma-separated strings for django-filters."""
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

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

The @model_serializer is currently untyped and relies on # type: ignore[no-untyped-def], which conflicts with the repo’s strict mypy config. Please type the serializer signature (e.g., using Pydantic’s SerializerFunctionWrapHandler and optional SerializationInfo) so we can remove the type ignore and keep type safety.

Copilot uses AI. Check for mistakes.
Comment on lines +73 to +80
state_group__in: list[str] | None = Field(
None,
description="Filter by state groups (backlog, unstarted, started, completed, cancelled)",
)
priority__in: list[str] | None = Field(
None,
description="Filter by priority levels (urgent, high, medium, low, none)",
)
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

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

state_group__in and priority__in are typed as list[str], but the codebase already defines constrained Literal types (GroupEnum, PriorityEnum) used across models. Consider typing these as list[GroupEnum] | None and list[PriorityEnum] | None to prevent invalid values at compile/validation time and keep consistency with the rest of the SDK.

Copilot uses AI. Check for mistakes.
"""Serialize list fields as comma-separated strings for django-filters."""
data = handler(self)
for key, value in data.items():
if isinstance(value, list):
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

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

The model-level serializer converts any list-valued field into a comma-separated string. That’s fine for the current __in filters, but it will also affect any future list fields added to WorkItemQueryParams (even if the API expects repeated query params instead of CSV). Consider limiting this conversion to the known *__in keys (or an explicit allowlist) to avoid surprising serialization changes later.

Suggested change
if isinstance(value, list):
if key.endswith("__in") and isinstance(value, list):

Copilot uses AI. Check for mistakes.
Comment on lines +98 to +105
@model_serializer(mode="wrap")
def _serialize(self, handler): # type: ignore[no-untyped-def]
"""Serialize list fields as comma-separated strings for django-filters."""
data = handler(self)
for key, value in data.items():
if isinstance(value, list):
data[key] = ",".join(str(v) for v in value)
return data
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

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

New serialization behavior (converting list filters to comma-separated strings) isn’t covered by tests. Please add a unit test that asserts WorkItemQueryParams(assignee_id__in=[...]).model_dump(exclude_none=True) produces a comma-separated string, since this behavior is critical for server-side filtering to work with requests query encoding.

Copilot uses AI. Check for mistakes.
@lifeiscontent lifeiscontent force-pushed the feat/work-item-query-filters branch from 94cf652 to 1b79a9a Compare March 24, 2026 07:58
@lifeiscontent lifeiscontent changed the title feat: add filter fields to WorkItemQueryParams feat: add project_id and workspace_search to AdvancedSearchWorkItem Mar 24, 2026
…chWorkItem

Add project_id and workspace_search fields to AdvancedSearchWorkItem
model. These fields are already supported by the API endpoint
(WorkItemAdvancedSearchRequestSerializer) but were missing from the
SDK model.
@lifeiscontent lifeiscontent force-pushed the feat/work-item-query-filters branch from 1b79a9a to 544ea4f Compare March 24, 2026 08:00
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.

2 participants