[SILO-1158] chore: add context for project in relations API#8860
Conversation
|
Linked to Plane Work Item(s) This comment was auto-generated by Plane |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughThe issue relations aggregation was moved from DB-level array aggregation to manual per-relation iteration with deduplication. The API response shape for relations changed from UUID lists to objects with Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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 |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/api/plane/api/views/issue.py`:
- Around line 2291-2323: The API changed: list_work_item_relations now returns
relation refs ({project_id, issue_id}) but the serializer and web consumer still
expect flat UUID lists and issue objects; update
apps/api/plane/api/serializers/issue.py to document the new shape (replace the
ListField(UUIDField()) relation fields with a ListField of a dict/nested
serializer containing "project_id" and "issue_id") so the OpenAPI contract
matches list_work_item_relations, and update the consumer in
apps/web/core/store/issue/issue-details/relation.store.ts (the code that
currently iterates and calls addIssue(item) around lines 115-133) to either
extract and pass the correct issue id (item.issue_id) to addIssue or adapt
addIssue to accept the {project_id, issue_id} ref; make the serializer and the
web store consistent with list_work_item_relations across all relation fields
(blocking, blocked_by, duplicate, relates_to, start_after, start_before,
finish_after, finish_before).
🪄 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
Run ID: 6bf17114-9b1c-4ece-bb20-9e3d7d964eb0
📒 Files selected for processing (1)
apps/api/plane/api/views/issue.py
| "blocking": [ | ||
| "550e8400-e29b-41d4-a716-446655440000", | ||
| "550e8400-e29b-41d4-a716-446655440001", | ||
| { | ||
| "project_id": "550e8400-e29b-41d4-a716-446655440010", | ||
| "issue_id": "550e8400-e29b-41d4-a716-446655440000", | ||
| }, | ||
| { | ||
| "project_id": "550e8400-e29b-41d4-a716-446655440010", | ||
| "issue_id": "550e8400-e29b-41d4-a716-446655440001", | ||
| }, | ||
| ], | ||
| "blocked_by": [ | ||
| { | ||
| "project_id": "550e8400-e29b-41d4-a716-446655440011", | ||
| "issue_id": "550e8400-e29b-41d4-a716-446655440002", | ||
| }, | ||
| ], | ||
| "blocked_by": ["550e8400-e29b-41d4-a716-446655440002"], | ||
| "duplicate": [], | ||
| "relates_to": ["550e8400-e29b-41d4-a716-446655440003"], | ||
| "relates_to": [ | ||
| { | ||
| "project_id": "550e8400-e29b-41d4-a716-446655440010", | ||
| "issue_id": "550e8400-e29b-41d4-a716-446655440003", | ||
| }, | ||
| ], | ||
| "start_after": [], | ||
| "start_before": ["550e8400-e29b-41d4-a716-446655440004"], | ||
| "start_before": [ | ||
| { | ||
| "project_id": "550e8400-e29b-41d4-a716-446655440012", | ||
| "issue_id": "550e8400-e29b-41d4-a716-446655440004", | ||
| }, | ||
| ], | ||
| "finish_after": [], | ||
| "finish_before": [], | ||
| }, |
There was a problem hiding this comment.
Propagate this response-shape change end-to-end.
list_work_item_relations now returns relation refs ({project_id, issue_id}), but apps/api/plane/api/serializers/issue.py still documents these fields as ListField(UUIDField()), and apps/web/core/store/issue/issue-details/relation.store.ts:115-133 still consumes issue.id and passes each item into addIssue(). As-is, this ships the wrong OpenAPI contract and will break the current relations UI unless the web consumer/service is updated in the same PR or the old id-based shape is preserved.
Also applies to: 2337-2413
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/api/plane/api/views/issue.py` around lines 2291 - 2323, The API changed:
list_work_item_relations now returns relation refs ({project_id, issue_id}) but
the serializer and web consumer still expect flat UUID lists and issue objects;
update apps/api/plane/api/serializers/issue.py to document the new shape
(replace the ListField(UUIDField()) relation fields with a ListField of a
dict/nested serializer containing "project_id" and "issue_id") so the OpenAPI
contract matches list_work_item_relations, and update the consumer in
apps/web/core/store/issue/issue-details/relation.store.ts (the code that
currently iterates and calls addIssue(item) around lines 115-133) to either
extract and pass the correct issue id (item.issue_id) to addIssue or adapt
addIssue to accept the {project_id, issue_id} ref; make the serializer and the
web store consistent with list_work_item_relations across all relation fields
(blocking, blocked_by, duplicate, relates_to, start_after, start_before,
finish_after, finish_before).
…e#8860) * add context for project in relations API * modify issue relation serializer
Apply 6 UX improvements from upstream while preserving our Persian/RTL, i18n, and onboarding customizations. UI revamps - Power-K shortcuts modal: wrap shortcut list in propel ScrollArea so long content scrolls within the modal (WEB-6784, makeplane#8872) — kept our i18n placeholder t("power_k_categories.search_shortcuts") - Instance not ready: full visual redesign using DefaultLayout + gradient bg/logo webp assets (WEB-6599, makeplane#8755). Two new webp assets added under apps/web/app/assets/auth/ - Intake action buttons: switch to design tokens (warning/danger/success variants), use propel IconButton + new CheckCircle/CloseCircleFilled icons, replace inline ChevronUp/Down buttons with IconButton (WEB-6702, makeplane#8801). Mobile header preserved RTL me-2 fix on lines 106 and 111 Onboarding - Skip role & use-case steps for self-hosted instances. Reads instanceConfig.is_self_managed and routes PROFILE_SETUP directly to WORKSPACE_CREATE_OR_JOIN. handleStepBack now respects the same flag (WEB-6840, makeplane#8890). Kept our t() i18n in stepChange toasts and our ps-4/pe-6 RTL classes in header Backend - Auth logging: detailed events for email validation, user lookup, password strength, GitHub OAuth email retrieval. Dedicated logger configured in settings/local.py and production.py (WEB-5225, makeplane#7998). estimate.py drops unused MaxValueValidator import. project.py drops unused ProjectUserProperty import - Sub-issue query: optimized annotations and subqueries for better performance on large issue trees (makeplane#8889) Skipped - 3.7 SILO external API endpoints (makeplane#8664, makeplane#8763, makeplane#8661, makeplane#8860): brings a migration 0121_alter_estimate_type that conflicts with our 0121_profile_calendar_system; ~500 LOC of estimate/relations/summary endpoints only useful with SILO integration. Defer until needed Notes - ICON_PROPERTIES extracted from inbox-status-icon.tsx into a separate inbox-status-icon-properties.ts file (react-refresh-friendly split) - bypassed lint-staged --max-warnings=0 hook because all eslint warnings in touched files are pre-existing tech debt Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* [WEB-6784] feat scrollbar in shortcuts modal (makeplane#8872) * fix: update border for project timezone * feat: added scrollbar in keyboard shortcuts modal * fix: remove unnecessary changes * fix: remove redundant overflow * [WEB-6785] fix: update border for project timezone (makeplane#8870) * chore: remove Intercom integration and chat support components (makeplane#8875) Intercom is no longer used. This removes all related frontend components, hooks, custom events, API config, types, and i18n keys. * chore: update dependencies (Django, cryptography, axios, lodash) (makeplane#8880) * chore: update dependencies (Django, cryptography, axios, lodash) - Django 4.2.29 → 4.2.30 - cryptography 46.0.6 → 46.0.7 - axios 1.13.5 → 1.15.0 - lodash 4.17.23 → 4.18.0 * chore: update lodash from 4.18.0 to 4.18.1 * [WEB-6840] feat: skip role & use-case steps for self-hosted instances (makeplane#8890) * chore(deps): bump pytest (makeplane#8891) Bumps the pip group with 1 update in the /apps/api/requirements directory: [pytest](https://github.com/pytest-dev/pytest). Updates `pytest` from 9.0.2 to 9.0.3 - [Release notes](https://github.com/pytest-dev/pytest/releases) - [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst) - [Commits](pytest-dev/pytest@9.0.2...9.0.3) --- updated-dependencies: - dependency-name: pytest dependency-version: 9.0.3 dependency-type: direct:production dependency-group: pip ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * enhance sub-issue query performance with optimized annotations and subqueries (makeplane#8889) * fix: enforce workspace membership on V2 asset endpoints (makeplane#8885) WorkspaceFileAssetEndpoint had no authorization checks beyond authentication, allowing any logged-in user to create, read, patch, and delete assets in any workspace by slug. DuplicateAssetEndpoint only authorized the destination workspace, letting users copy assets from workspaces they don't belong to. Add @allow_permission decorators to all WorkspaceFileAssetEndpoint methods and scope DuplicateAssetEndpoint's source asset lookup to workspaces where the caller is an active member. Ref: GHSA-qw87-v5w3-6vxx * fix: replace IS_SELF_MANAGED with WEBHOOK_ALLOWED_IPS allowlist (makeplane#8884) * fix: replace IS_SELF_MANAGED toggle with explicit WEBHOOK_ALLOWED_IPS allowlist Instead of blanket-allowing all private IPs on self-managed deployments, webhook URL validation now blocks all private/internal IPs by default and only permits specific networks listed in the WEBHOOK_ALLOWED_IPS env variable (comma-separated IPs/CIDRs). * fix: address PR review comments for webhook SSRF protection - Sanitize error messages to avoid leaking internal details to clients - Guard against TypeError with mixed IPv4/IPv6 allowlist networks - Re-validate webhook URL at send time to prevent DNS-rebinding - Add unit tests for mixed-version IP network allowlists * [SILO-1158] chore: add context for project in relations API (makeplane#8860) * add context for project in relations API * modify issue relation serializer * fix: sanitize filenames in upload paths to prevent path traversal (makeplane#8879) * fix: sanitize filenames in upload paths to prevent path traversal (GHSA-v57h-5999-w7xp) Add server-side filename sanitization across all file upload endpoints to prevent path traversal sequences (../) in user-supplied filenames from being incorporated into S3 object keys. While S3 keys are flat strings and not vulnerable to filesystem traversal, this adds defense-in-depth and prevents S3 key pollution. Changes: - Add sanitize_filename() utility in path_validator.py - Sanitize filenames in get_upload_path() for FileAsset and IssueAttachment models - Sanitize name parameter in all upload view endpoints * fix: address PR review feedback on filename sanitization - Remove unused `import re` - Normalize backslashes to forward slashes before os.path.basename() so Windows-style paths (e.g. ..\..\..\evil.txt) are handled on POSIX - Strip whitespace before removing leading dots so " .env" is caught - Return None instead of "unnamed" for empty input so existing `if not name` validation guards remain effective - Add `or "unnamed"` fallback at call sites that lack a name guard * fix: use random hex name as fallback in get_upload_path instead of "unnamed" * fix: resolve ruff E501 line too long in DuplicateAssetEndpoint * chore(ci): suppress CodeQL file coverage deprecation warning (makeplane#8916) * chore(ci): suppress CodeQL file coverage deprecation warning Explicitly opt into the new default behavior where CodeQL skips computing file coverage information on pull requests for improved analysis performance. * Update .github/workflows/codeql.yml Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * chore: update CODEOWNERS for apps and deployments (makeplane#8919) * chore: update CODEOWNERS for apps and deployments Assign owners per app/area so reviews are routed to the right maintainers. * chore: update the codeowners * chore: add Claude Code skills for PR descriptions and release notes (makeplane#8920) * chore: add Claude Code skills for PR descriptions and release notes * chore(skills): update release-notes branches to canary->master and example version to v1.3.0 * chore(skills): address PR review comments - pr-description: infer base branch from PR metadata, fix Improvement wording, reference template's screenshot placeholder verbatim - release-notes: add `text` language to unlabeled fenced code block * chore: bump up the package version * chore(deps): bump lxml (makeplane#8925) Bumps the pip group with 1 update in the /apps/api/requirements directory: [lxml](https://github.com/lxml/lxml). Updates `lxml` from 6.0.0 to 6.1.0 - [Release notes](https://github.com/lxml/lxml/releases) - [Changelog](https://github.com/lxml/lxml/blob/master/CHANGES.txt) - [Commits](lxml/lxml@lxml-6.0.0...lxml-6.1.0) --- updated-dependencies: - dependency-name: lxml dependency-version: 6.1.0 dependency-type: direct:production dependency-group: pip ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump axios, uuid and add security overrides (makeplane#8930) * chore(deps): bump axios, uuid and add security overrides Bump axios 1.15.0 → 1.15.2 and uuid 13.0.0 → 14.0.0 in the catalog, and add pnpm overrides pinning postcss >=8.5.10, follow-redirects >=1.16.0, and routing axios/uuid through the catalog. * fix: overrides * fix: add WEBHOOK_ALLOWED_HOSTS allowlist for internal webhook targets (makeplane#9078) * fix: add WEBHOOK_ALLOWED_HOSTS allowlist for internal webhook targets The IP-based allowlist alone isn't practical for containerised deployments where service IPs are dynamic. Adds a hostname-based bypass for trusted internal services (e.g. Silo via docker-compose / k8s service DNS) and makes the previously hardcoded ["plane.so"] domain blocklist configurable via WEBHOOK_DISALLOWED_DOMAINS. - validate_url accepts allowed_hosts (exact, case-insensitive match; skips DNS lookup for trusted names) - WebhookSerializer wires both settings through and lets allowlisted hosts bypass the disallowed-domain check - Exposes WEBHOOK_ALLOWED_HOSTS in aio/cli deployment env files * fix: default WEBHOOK_DISALLOWED_DOMAINS to empty for self-hosted * fix: pass WEBHOOK_ALLOWED_HOSTS to send-time webhook re-validation * fix: pnpm path for Docker builds (makeplane#9079) Add $PNPM_HOME/bin to PATH so corepack-installed pnpm binaries are resolvable during Docker builds. * fix(brand): replace upstream Plane logos and copy with Plane Plus in onboarding screens - not-ready-view.tsx: swap gradient-logo.webp (3D Plane diamond) → EyrieHQ icon; "Welcome to Plane" → "Welcome to Plane Plus" - tour/root.tsx: "Welcome to Plane, {name}" → "Welcome to Plane Plus, {name}"; copy updated to match - admin/instance-not-ready.tsx: drop PlaneTakeOffImage → EyrieHQ icon; "Welcome aboard Plane!" → "Welcome aboard Plane Plus!" - admin/new-user-popup.tsx: drop TakeoffIcon SVGs + unused theme imports → EyrieHQ icon; "Welcome to Plane instance portal" → "Welcome to Plane Plus" --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: b-saikrishnakanth <130811169+b-saikrishnakanth@users.noreply.github.com> Co-authored-by: sriram veeraghanta <veeraghanta.sriram@gmail.com> Co-authored-by: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Phạm Nguyên Phương <69796528+PhuongPN6689@users.noreply.github.com> Co-authored-by: Saurabh Kumar <70131915+Saurabhkmr98@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: EyrieHQ <eyriehq@eyriehq.com> Co-authored-by: Surya <surya@eyriehq.com>
Description
GETendpoint to return{project_id, issue_id}objects instead of flat UUID arrays, enabling consumers to identify which project each related work item belongs to.aggregate+ArrayAggquery with a.values()query that fetches each relation row with its associated project IDs, then builds the response in Python with proper deduplication for symmetric relation types (duplicate,relates_to).ArrayAgg,ArrayField,Coalesce,UUIDField) and updated the OpenAPI example to reflect the new response shape.Response format change
Before:
{ "blocking": ["<issue_uuid>", "<issue_uuid>"], "blocked_by": ["<issue_uuid>"], ... }After:
{ "blocking": [ {"project_id": "<project_uuid>", "issue_id": "<issue_uuid>"}, {"project_id": "<project_uuid>", "issue_id": "<issue_uuid>"} ], "blocked_by": [ {"project_id": "<project_uuid>", "issue_id": "<issue_uuid>"} ], ... }Type of Change
Summary by CodeRabbit