Skip to content

[WEB-4999] feat: implement flexible data export utility with CSV, JSON, and XLSX support#7884

Merged
sriramveeraghanta merged 4 commits intopreviewfrom
feat-export-enhancement
Oct 14, 2025
Merged

[WEB-4999] feat: implement flexible data export utility with CSV, JSON, and XLSX support#7884
sriramveeraghanta merged 4 commits intopreviewfrom
feat-export-enhancement

Conversation

@dheeru0198
Copy link
Member

@dheeru0198 dheeru0198 commented Oct 1, 2025

Description

  • Introduced Exporter class for handling various data formats.
  • Added formatters for CSV, JSON, and XLSX exports.
  • Created schemas for defining export fields and their transformations.
  • Implemented IssueExportSchema for exporting issue data with nested attributes.
  • Enhanced issue export task to utilize the new exporter system for better data handling.

Type of Change

  • Improvement (change that would cause existing functionality to not work as expected)
  • Code refactoring

Screenshots and Media (if applicable)

Test Scenarios

Tested the export before and after making changes and verified both the files to be identical

References

Summary by CodeRabbit

  • New Features

    • Unified CSV/JSON/XLSX export with consistent field ordering/labels and per-project or single-file export options.
    • Richer issue exports: attachments, comments, labels, assignees, cycles, parent/relations, computed fields.
  • Bug Fixes

    • Clear failure reporting for invalid export formats.
    • Consistent presigned URL formatting for downloads.
  • Documentation

    • Added comprehensive guide for the new exporter utilities.
  • Refactor

    • Migrated to a schema-driven exporter with pluggable formatters.

… support

- Introduced Exporter class for handling various data formats.
- Added formatters for CSV, JSON, and XLSX exports.
- Created schemas for defining export fields and their transformations.
- Implemented IssueExportSchema for exporting issue data with nested attributes.
- Enhanced issue export task to utilize the new exporter system for better data handling.
Copilot AI review requested due to automatic review settings October 1, 2025 06:22
@cursor
Copy link

cursor bot commented Oct 1, 2025

You have run out of free Bugbot PR reviews for this billing cycle. This will reset on October 20.

To receive reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 1, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Replaces bespoke per-format export code with a schema-driven Exporter and formatters (CSV/JSON/XLSX), adds declarative ExportSchema and IssueExportSchema, integrates them into the background export task with per-project exports and failure handling, provides docs and public re-exports, and adds a relation_type field plus reverse mapping to IssueRelation.

Changes

Cohort / File(s) Summary
Background task export flow
apps/api/plane/bgtasks/export_task.py
Replaced per-format helpers with an Exporter + IssueExportSchema flow; dynamic exporter creation with invalid-format handling; per-project file outputs; removed EXPORTER_MAPPER and legacy attachment/row assembly; added top-level exception handling and S3 presigned URL endpoint formatting tweak.
Exporter framework (core & public API)
apps/api/plane/utils/exporters/exporter.py, apps/api/plane/utils/exporters/formatters.py, apps/api/plane/utils/exporters/__init__.py
Added generic Exporter with FORMATTERS registry and runtime registration; implemented BaseFormatter, CSVFormatter, JSONFormatter, XLSXFormatter; unified export(filename, data, fields) interface and central re-exports.
Schemas (base & issue)
apps/api/plane/utils/exporters/schemas/base.py, apps/api/plane/utils/exporters/schemas/issue.py, apps/api/plane/utils/exporters/schemas/__init__.py
Introduced declarative ExportField types and ExportSchema (metaclass-driven collection, prepare hooks, queryset serialization); added IssueExportSchema with attachment/cycle context, helper functions (get_issue_attachments_dict, get_issue_last_cycles_dict) and serialize_issues helper.
Documentation
apps/api/plane/utils/exporters/README.md
New README documenting schema design, field types, preparers, formatter usage, examples, API reference, and testing guidance.
Model change (issue relations)
apps/api/plane/db/models/issue.py
Added relation_type CharField to IssueRelation and introduced _RELATION_PAIRS / _REVERSE_MAPPING on IssueRelationChoices to support bidirectional relation semantics.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant BT as BackgroundTask (export_task)
  participant IQ as Issues Queryset
  participant ES as IssueExportSchema
  participant EX as Exporter
  participant FM as Formatter (CSV/JSON/XLSX)
  participant S3 as Storage (S3 / presigned URL)

  BT->>IQ: prepare base queryset
  BT->>ES: serialize_issues(queryset, fields?)
  ES-->>BT: records[]

  BT->>EX: Exporter(format_type, IssueExportSchema, options)
  EX-->>BT: exporter instance

  BT->>EX: exporter.export(filename_base, records)
  EX->>FM: format(filename_base, records, IssueExportSchema, options)
  FM-->>EX: filename.ext, content
  EX-->>BT: filename.ext, content

  BT->>S3: upload(content) / request presigned URL
  S3-->>BT: presigned_url

  alt success
    BT->>BT: mark ExporterHistory success
  else error / invalid format
    BT->>BT: mark ExporterHistory failed (log exception)
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

✨feature, ⚙️backend, 🌟improvement

Suggested reviewers

  • pablohashescobar
  • sriramveeraghanta
  • NarayanBavisetti

Poem

I’m a rabbit with a tidy plan,
Fields aligned like rows on land.
CSV, JSON, XLSX in a hop,
Issues marshaled — no more stop.
Off they hop to storage with a clap 🐇📦

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 22.73% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The title clearly and concisely summarizes the main functional change—implementing a flexible data export utility supporting CSV, JSON, and XLSX—and includes the ticket reference without extraneous detail.
Description Check ✅ Passed The description follows the repository template, providing a detailed change summary, clearly marked type of change selections, and test scenarios, with optional media and references sections present even if empty.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat-export-enhancement

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
Contributor

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

This PR introduces a flexible data export utility system that refactors the existing issue export functionality to use a schema-based approach with support for multiple output formats.

Key changes:

  • Created a new exporters utility module with schema-based field definitions and formatters
  • Implemented IssueExportSchema for structured issue data exports with nested attributes
  • Refactored the existing issue export task to use the new exporter system instead of hardcoded formatting functions

Reviewed Changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
apps/api/plane/utils/exporters/schemas/base.py Defines base export field types and schema metaclass for field declarations
apps/api/plane/utils/exporters/schemas/issue.py Implements issue-specific export schema with field definitions and custom preparers
apps/api/plane/utils/exporters/formatters.py Contains format-specific exporters (CSV, JSON, XLSX) with proper data type handling
apps/api/plane/utils/exporters/exporter.py Main exporter class that coordinates schema and formatter usage
apps/api/plane/utils/exporters/__init__.py Module initialization with exported classes
apps/api/plane/utils/exporters/schemas/__init__.py Schema submodule initialization
apps/api/plane/utils/exporters/README.md Comprehensive documentation for the new export system
apps/api/plane/bgtasks/export_task.py Refactored to use the new exporter system, removing old hardcoded functions

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Copy link
Contributor

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

Actionable comments posted: 4

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a69c6f1 and 3ec1dd1.

📒 Files selected for processing (8)
  • apps/api/plane/bgtasks/export_task.py (5 hunks)
  • apps/api/plane/utils/exporters/README.md (1 hunks)
  • apps/api/plane/utils/exporters/__init__.py (1 hunks)
  • apps/api/plane/utils/exporters/exporter.py (1 hunks)
  • apps/api/plane/utils/exporters/formatters.py (1 hunks)
  • apps/api/plane/utils/exporters/schemas/__init__.py (1 hunks)
  • apps/api/plane/utils/exporters/schemas/base.py (1 hunks)
  • apps/api/plane/utils/exporters/schemas/issue.py (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (5)
apps/api/plane/utils/exporters/schemas/__init__.py (2)
apps/api/plane/utils/exporters/schemas/base.py (9)
  • BooleanField (107-115)
  • DateField (65-76)
  • DateTimeField (80-91)
  • ExportField (6-49)
  • ExportSchema (170-187)
  • JSONField (137-150)
  • ListField (119-133)
  • NumberField (95-103)
  • StringField (53-61)
apps/api/plane/utils/exporters/schemas/issue.py (1)
  • IssueExportSchema (40-171)
apps/api/plane/utils/exporters/exporter.py (1)
apps/api/plane/utils/exporters/formatters.py (7)
  • CSVFormatter (55-100)
  • JSONFormatter (103-127)
  • XLSXFormatter (130-179)
  • format (12-30)
  • format (87-100)
  • format (115-127)
  • format (164-179)
apps/api/plane/utils/exporters/schemas/issue.py (2)
apps/api/plane/db/models/asset.py (2)
  • FileAsset (24-95)
  • EntityTypeContext (29-39)
apps/api/plane/utils/exporters/schemas/base.py (8)
  • DateField (65-76)
  • DateTimeField (80-91)
  • ExportSchema (170-187)
  • JSONField (137-150)
  • ListField (119-133)
  • NumberField (95-103)
  • StringField (53-61)
  • serialize (174-187)
apps/api/plane/utils/exporters/__init__.py (4)
apps/api/plane/utils/exporters/exporter.py (1)
  • Exporter (6-56)
apps/api/plane/utils/exporters/formatters.py (4)
  • BaseFormatter (9-52)
  • CSVFormatter (55-100)
  • JSONFormatter (103-127)
  • XLSXFormatter (130-179)
apps/api/plane/utils/exporters/schemas/base.py (9)
  • BooleanField (107-115)
  • DateField (65-76)
  • DateTimeField (80-91)
  • ExportField (6-49)
  • ExportSchema (170-187)
  • JSONField (137-150)
  • ListField (119-133)
  • NumberField (95-103)
  • StringField (53-61)
apps/api/plane/utils/exporters/schemas/issue.py (1)
  • IssueExportSchema (40-171)
apps/api/plane/bgtasks/export_task.py (3)
apps/api/plane/db/models/exporter.py (1)
  • ExporterHistory (20-63)
apps/api/plane/utils/exporters/exporter.py (2)
  • Exporter (6-56)
  • export (32-46)
apps/api/plane/utils/exporters/schemas/issue.py (2)
  • IssueExportSchema (40-171)
  • serialize_issues (146-171)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Build and lint web apps
  • GitHub Check: Analyze (javascript)

…xt handling

- Updated issue export task to utilize new IssueRelation model for better relationship management.
- Refactored Exporter class to accept QuerySets directly, improving performance and flexibility.
- Enhanced IssueExportSchema to include parent issues and relations in the export.
- Improved documentation for exporting multiple projects and filtering fields during export.
@dheeru0198 dheeru0198 changed the title feat: implement flexible data export utility with CSV, JSON, and XLSX support [WEB-4999] feat: implement flexible data export utility with CSV, JSON, and XLSX support Oct 6, 2025
@makeplane
Copy link

makeplane bot commented Oct 6, 2025

Linked to Plane Work Item(s)

This comment was auto-generated by Plane

Copy link
Contributor

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

Actionable comments posted: 5

♻️ Duplicate comments (2)
apps/api/plane/bgtasks/export_task.py (1)

199-205: Good: per-project exports no longer skipped when empty

You now generate a file per requested project regardless of issue count, addressing prior feedback.

apps/api/plane/utils/exporters/schemas/issue.py (1)

138-145: Past review comments still apply: cache cycle queries and format dates.

The issues flagged in previous reviews remain unaddressed:

  1. Multiple calls to i.issue_cycle.last() execute the same query repeatedly
  2. prepare_cycle_start_date and prepare_cycle_end_date return raw date objects that bypass DateField formatting, causing JSON serialization errors

Please apply the fixes suggested in the previous review comments.

🧹 Nitpick comments (4)
apps/api/plane/db/models/issue.py (1)

276-289: Use enum values in reverse-mapping; avoid hard-coded strings

Hard-coded keys risk drift if enum values change. Build the mapping using IssueRelationChoices values.

Apply this diff:

-IssueRelationChoices._RELATION_PAIRS = (
-    ("blocked_by", "blocking"),
-    ("relates_to", "relates_to"),  # symmetric
-    ("duplicate", "duplicate"),  # symmetric
-    ("start_before", "start_after"),
-    ("finish_before", "finish_after"),
-    ("implemented_by", "implements"),
-)
+IssueRelationChoices._RELATION_PAIRS = (
+    (IssueRelationChoices.BLOCKED_BY.value, "blocking"),
+    (IssueRelationChoices.RELATES_TO.value, "relates_to"),  # symmetric
+    (IssueRelationChoices.DUPLICATE.value, "duplicate"),    # symmetric
+    (IssueRelationChoices.START_BEFORE.value, "start_after"),
+    (IssueRelationChoices.FINISH_BEFORE.value, "finish_after"),
+    (IssueRelationChoices.IMPLEMENTED_BY.value, "implements"),
+)
 
-# Generate reverse mapping from pairs
-IssueRelationChoices._REVERSE_MAPPING = {forward: reverse for forward, reverse in IssueRelationChoices._RELATION_PAIRS}
+# Generate reverse mapping from pairs
+IssueRelationChoices._REVERSE_MAPPING = {
+    forward: reverse for forward, reverse in IssueRelationChoices._RELATION_PAIRS
+}

Additionally, consider constraining IssueRelation.relation_type to known values for data integrity:

# outside selected lines (for IssueRelation.relation_type)
relation_type = models.CharField(
    max_length=20,
    choices=IssueRelationChoices.choices,
    verbose_name="Issue Relation Type",
    default=IssueRelationChoices.BLOCKED_BY,
)

Please confirm a migration exists to add relation_type and, if needed, backfill accurate types for existing rows (not all should default to "blocked_by").

apps/api/plane/bgtasks/export_task.py (2)

175-179: Use select_related for forward FK 'parent'

Prefetching a forward FK is suboptimal; select_related is faster and simpler.

Apply this diff:

-                Prefetch(
-                    "parent",
-                    queryset=Issue.objects.select_related("type", "project"),
-                ),
+            ).select_related(
+                "parent",
+                "parent__type",
+                "parent__project",
             )

182-195: Avoid extra DB get on invalid format path

You already loaded exporter_instance; reuse it to set failure state.

Apply this diff:

-        try:
+        try:
             exporter = Exporter(
                 format_type=provider,
                 schema_class=IssueExportSchema,
                 options={"list_joiner": ", "},
             )
         except ValueError as e:
             # Invalid format type
-            exporter_instance = ExporterHistory.objects.get(token=token_id)
             exporter_instance.status = "failed"
             exporter_instance.reason = str(e)
             exporter_instance.save(update_fields=["status", "reason"])
             return
apps/api/plane/utils/exporters/schemas/base.py (1)

219-244: Consistent defaults when filtering fields

When filtering, you default missing keys to "". Consider using each field’s default for consistency.

Apply this diff:

-            filtered_data = {field: obj_data.get(field, "") for field in fields_to_extract if field in obj_data}
+            filtered_data = {}
+            for field in fields_to_extract:
+                if field in obj_data:
+                    filtered_data[field] = obj_data[field]

Since obj_data already contains all declared fields with proper defaults, omitting the extra default avoids masking schema defaults.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3ec1dd1 and 8e1e8d1.

📒 Files selected for processing (6)
  • apps/api/plane/bgtasks/export_task.py (4 hunks)
  • apps/api/plane/db/models/issue.py (1 hunks)
  • apps/api/plane/utils/exporters/README.md (1 hunks)
  • apps/api/plane/utils/exporters/exporter.py (1 hunks)
  • apps/api/plane/utils/exporters/schemas/base.py (1 hunks)
  • apps/api/plane/utils/exporters/schemas/issue.py (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
apps/api/plane/bgtasks/export_task.py (5)
apps/api/plane/db/models/exporter.py (1)
  • ExporterHistory (20-63)
apps/api/plane/db/models/issue.py (2)
  • Issue (104-250)
  • IssueRelation (291-315)
apps/api/plane/utils/exception_logger.py (1)
  • log_exception (9-20)
apps/api/plane/utils/exporters/exporter.py (2)
  • Exporter (8-67)
  • export (34-57)
apps/api/plane/utils/exporters/schemas/issue.py (1)
  • IssueExportSchema (40-173)
apps/api/plane/utils/exporters/schemas/issue.py (3)
apps/api/plane/db/models/asset.py (2)
  • FileAsset (24-95)
  • EntityTypeContext (29-39)
apps/api/plane/utils/exporters/schemas/base.py (8)
  • DateField (67-78)
  • DateTimeField (82-93)
  • ExportSchema (172-244)
  • JSONField (139-152)
  • ListField (121-135)
  • NumberField (97-105)
  • StringField (55-63)
  • get_context_data (207-216)
apps/api/plane/db/models/issue.py (1)
  • IssueRelationChoices (267-273)
apps/api/plane/utils/exporters/schemas/base.py (1)
apps/api/plane/utils/exporters/schemas/issue.py (1)
  • get_context_data (169-173)
apps/api/plane/utils/exporters/exporter.py (2)
apps/api/plane/utils/exporters/formatters.py (7)
  • CSVFormatter (55-100)
  • JSONFormatter (103-127)
  • XLSXFormatter (130-179)
  • format (12-30)
  • format (87-100)
  • format (115-127)
  • format (164-179)
apps/api/plane/utils/exporters/schemas/base.py (1)
  • serialize_queryset (219-244)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Build and lint web apps
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (1)
apps/api/plane/utils/exporters/schemas/issue.py (1)

162-163: Remove incorrect critical flag: _REVERSE_MAPPING is defined on IssueRelationChoices.

…upport

- Updated Exporter class to merge fields into options for formatting.
- Modified formatters to filter fields based on specified options.
- Enhanced ExportSchema to support optional field selection during serialization.
- Improved documentation for the serialize method to clarify field filtering capabilities.
@dheeru0198 dheeru0198 requested a review from Copilot October 7, 2025 09:58
Copy link
Contributor

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

Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.


Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Copy link
Contributor

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
apps/api/plane/utils/exporters/schemas/issue.py (1)

169-177: Serialize cycle dates as strings to prevent JSON serialization errors.

These methods return raw date objects which bypass the DateField formatting logic. When preparer methods exist, they take precedence over field serialization (see ExportSchema.serialize() in base.py lines 183-197), so the returned date objects will cause TypeError: Object of type date is not JSON serializable in JSON exports.

Based on learnings
Apply this diff to properly format the dates:

 def prepare_cycle_start_date(self, i):
     cycles_dict = self.context.get("cycles_dict") or {}
     last_cycle = cycles_dict.get(i.id)
-    return last_cycle.cycle.start_date if last_cycle else None
+    if not last_cycle or not last_cycle.cycle:
+        return ""
+    return self._format_date(last_cycle.cycle.start_date)

 def prepare_cycle_end_date(self, i):
     cycles_dict = self.context.get("cycles_dict") or {}
     last_cycle = cycles_dict.get(i.id)
-    return last_cycle.cycle.end_date if last_cycle else None
+    if not last_cycle or not last_cycle.cycle:
+        return ""
+    return self._format_date(last_cycle.cycle.end_date)
🧹 Nitpick comments (2)
apps/api/plane/utils/exporters/schemas/issue.py (2)

122-122: Return empty string for consistency.

For consistency with other string fields in the schema, return an empty string instead of None when the state is not available.

Apply this diff:

 def prepare_state_name(self, i):
-    return i.state.name if i.state else None
+    return i.state.name if i.state else ""

124-153: Consider prefetch optimization for related queries.

Multiple prepare methods (lines 125, 131, 140, 147, 150, 153) trigger additional database queries for related objects. While this is not directly fixable in the schema, the caller should use prefetch_related() on the queryset to avoid N+1 query problems when exporting many issues.

Recommended prefetch list for the export queryset:

queryset = queryset.prefetch_related(
    'issue_module__module',
    'labels',
    'issue_comments',
    'issue_link',
    'assignees',
    'issue_subscribers'
)

This should be implemented in the calling code (e.g., the export task).

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 284455f and 697ba8a.

📒 Files selected for processing (1)
  • apps/api/plane/utils/exporters/schemas/issue.py (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
apps/api/plane/utils/exporters/schemas/issue.py (4)
apps/api/plane/db/models/cycle.py (1)
  • CycleIssue (100-123)
apps/api/plane/db/models/asset.py (2)
  • FileAsset (24-95)
  • EntityTypeContext (29-39)
apps/api/plane/utils/exporters/schemas/base.py (8)
  • DateField (55-66)
  • DateTimeField (70-81)
  • ExportSchema (160-234)
  • JSONField (127-140)
  • ListField (109-123)
  • NumberField (85-93)
  • StringField (43-51)
  • get_context_data (202-211)
apps/api/plane/db/models/issue.py (1)
  • IssueRelationChoices (267-273)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Analyze (javascript)
  • GitHub Check: Build and lint web apps
🔇 Additional comments (7)
apps/api/plane/utils/exporters/schemas/issue.py (7)

1-16: LGTM!

Imports are clean and properly structured.


19-37: LGTM!

The function efficiently queries attachments and builds the mapping dictionary with proper use of annotate and defaultdict.


40-63: LGTM!

The function correctly retrieves the most recent cycle per issue with proper query optimization via select_related.


69-84: LGTM!

Both static helper methods properly handle edge cases and None values.


86-116: LGTM!

Field definitions are well-structured with appropriate types and clear labels for exports.


200-206: LGTM!

The get_context_data method correctly leverages the helper functions to provide necessary context for efficient serialization.


184-198: No action required: _REVERSE_MAPPING is defined
IssueRelationChoices._REVERSE_MAPPING is declared at apps/api/plane/db/models/issue.py:288, so the attribute access is valid.

Likely an incorrect or invalid review comment.

@sriramveeraghanta sriramveeraghanta merged commit 4168127 into preview Oct 14, 2025
7 checks passed
@sriramveeraghanta sriramveeraghanta deleted the feat-export-enhancement branch October 14, 2025 10:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants