Skip to content

feat: add cover image support for work itemsCover image attachment#9240

Open
jribnik wants to merge 4 commits into
makeplane:previewfrom
jribnik:cover-image-attachment
Open

feat: add cover image support for work itemsCover image attachment#9240
jribnik wants to merge 4 commits into
makeplane:previewfrom
jribnik:cover-image-attachment

Conversation

@jribnik

@jribnik jribnik commented Jun 15, 2026

Copy link
Copy Markdown

Description

Closes #3921.

Lets users designate any image attachment on a work item as its cover image, displayed on Kanban cards and the
detail/peek views — giving design-oriented teams a quick visual preview as the issue requests.

The cover is set/cleared from the attachment's context menu ("Make cover image" / "Remove cover image") and
persisted via a new cover_image_attachment foreign key on the issue.

Design note: #3921 floats two ways to choose a cover — upload one, or auto-use the first image in the
description. This PR implements the explicit approach (the user picks which attachment is the cover) rather than
auto-detecting, so the cover is deterministic and user-controlled rather than changing implicitly as description
content changes.

  • API: adds Issue.cover_image_attachment FK → FileAsset (migration 0122), exposes and validates
    cover_image_attachment_id in the issue serializer (must be an image attachment belonging to the work item), and
    includes it in the issue list/detail/sub-issue/grouper projections.
  • Web: resolves the cover URL deterministically from the attachment id (no extra fetch), renders it on Kanban
    cards and the detail/peek views, and adds the set/remove action to the attachment menu.
  • i18n: adds the cover toast/menu strings to all locales (English placeholders per CONTRIBUTING.md).

Type of Change

  • Feature (non-breaking change which adds functionality)

Screenshots and Media (if applicable)

Screen.Recording.2026-06-15.at.3.48.18.PM.mov

Test Scenarios

  • Attach an image to a work item, choose "Make cover image" → cover appears on the Kanban card and the detail/peek
    views.
  • Choose "Remove cover image" → cover clears everywhere.
  • Verified the API rejects a cover_image_attachment_id that isn't an image attachment belonging to the work item.
  • pnpm --filter @plane/i18n run sync:check passes (all locales in sync).

References

Closes #3921

Summary by CodeRabbit

Release Notes

  • New Features
    • Issues now support custom cover images—set or remove an image attachment from the attachment menu.
    • Cover images are shown in issue detail pages and Kanban cards (including peek view).
  • Bug Fixes
    • If the current cover attachment is deleted, the issue cover image reference is cleared to avoid stale/broken covers.
  • Documentation
    • Updated multilingual UI text for setting and removing cover images across supported languages.

jribnik and others added 3 commits June 15, 2026 14:40
Let users designate any image attachment on a work item as its cover,
shown on kanban cards and the detail/peek views. The cover is set and
cleared from the attachment's context menu and persisted via a new
cover_image_attachment foreign key on the issue.

- API: add Issue.cover_image_attachment FK (migration 0122), expose and
  validate cover_image_attachment_id in the issue serializer, and include
  it in the issue list/detail/sub-issue/grouper projections.
- Web: resolve the cover URL deterministically from the attachment id,
  render it on kanban cards and the detail/peek views, and add a
  set/remove cover action to the attachment menu.
- i18n: add the cover toast/menu strings to all locales.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Deleting the attachment that backed a cover image left a dangling
cover_image_attachment_id: the v2 attachment endpoint soft-deletes the
FileAsset, so the cover FK's on_delete=SET_NULL never fired, and the
frontend store never cleared the reference either.

- API: clear cover_image_attachment on any issue referencing the asset
  during the soft delete, so API clients stay consistent too.
- Web: when removeAttachment deletes the current cover, also persist
  cover_image_attachment_id: null on the work item.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The previous cover-clear ran an extra updateIssue PATCH after the delete
had already succeeded; when that second request rejected, the caller's
try/catch surfaced a spurious "Attachment not removed" error even though
the delete went through. The backend already nulls the cover FK during
the soft delete, so mirror it in the local store instead of issuing a
redundant network request.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@CLAassistant

CLAassistant commented Jun 15, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@coderabbitai

coderabbitai Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5a3f814c-7be0-4898-bf2f-1260818e281f

📥 Commits

Reviewing files that changed from the base of the PR and between f3d1027 and a6273a7.

📒 Files selected for processing (3)
  • apps/api/plane/app/serializers/issue.py
  • apps/web/core/components/issues/issue-detail/cover-image.tsx
  • apps/web/core/components/issues/issue-layouts/kanban/cover-image.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
  • apps/web/core/components/issues/issue-layouts/kanban/cover-image.tsx
  • apps/web/core/components/issues/issue-detail/cover-image.tsx
  • apps/api/plane/app/serializers/issue.py

📝 Walkthrough

Walkthrough

Adds end-to-end cover image support for issues: a new nullable cover_image_attachment FK on the Issue model (with migration), API serializer validation and field propagation across all issue endpoints, a frontend URL-builder hook, store synchronization on set/remove, a "Make/Remove cover image" toggle in the attachment list UI, and new IssueDetailCoverImage/KanbanIssueCoverImage display components integrated into detail, peek overview, and kanban views, with i18n strings added for 19 locales.

Changes

Issue Cover Image Feature

Layer / File(s) Summary
DB model, migration, and shared type contract
apps/api/plane/db/models/issue.py, apps/api/plane/db/migrations/0122_issue_cover_image_attachment.py, packages/types/src/issues/issue.ts
Adds a nullable cover_image_attachment FK (SET_NULL) to the Issue model with corresponding Django migration, and extends TBaseIssue with cover_image_attachment_id: string | null.
API serializer validation and field propagation
apps/api/plane/app/serializers/issue.py, apps/api/plane/app/views/issue/base.py, apps/api/plane/app/views/issue/sub_issue.py, apps/api/plane/app/views/issue/attachment.py, apps/api/plane/utils/grouper.py
IssueCreateSerializer accepts and validates cover_image_attachment_id (confirms image MIME type, entity_type for issue attachments, project ownership, update-time instance match; disallows on create). IssueSerializer.Meta.fields includes the field. All issue list, create, paginated, sub-issue endpoints and grouper utility add field to responses. Attachment delete endpoint clears dangling cover references on Issues.
Frontend URL hook and store synchronization
apps/web/core/hooks/use-issue-cover-image.ts, apps/web/core/store/issue/issue-details/issue.store.ts, apps/web/core/store/issue/issue-details/attachment.store.ts
useIssueCoverImage hook constructs backend asset URLs from workspace/project/issue/attachment ids. addIssueToStore persists cover_image_attachment_id from payloads. removeAttachment detects and nulls dangling cover references locally after deletion.
Attachment list item cover-image toggle UI
apps/web/core/components/issues/attachment/attachment-list-item.tsx, apps/web/core/components/issues/attachment/attachment-item-list.tsx
IssueAttachmentsListItem adds onToggleCoverImage/isCoverImage props and conditional "Make/Remove cover image" menu action for image attachments (detected by filename extension). Parent list component implements handleToggleCoverImage (updates cover_image_attachment_id, refreshes activities, provides promise-based toast feedback with translated strings).
Cover image display in detail, peek, and kanban views
apps/web/core/components/issues/issue-detail/cover-image.tsx, apps/web/core/components/issues/issue-detail/main-content.tsx, apps/web/core/components/issues/peek-overview/issue-detail.tsx, apps/web/core/components/issues/issue-layouts/kanban/cover-image.tsx, apps/web/core/components/issues/issue-layouts/kanban/block.tsx
Adds IssueDetailCoverImage component (rendered in issue detail main content and peek overview with customizable layout) and KanbanIssueCoverImage (rendered in each kanban card). Both use useIssueCoverImage, suppress rendering on missing URL or image load error, and track failure state. Kanban card structure updated with overflow-hidden and inner padded wrapper.
i18n strings for cover image actions (19 locales)
packages/i18n/src/locales/*/common.json
Adds make_cover_image, remove_cover_image, and loading/success/error title+message keys under attachment section for all supported locales (en, cs, de, es, fr, id, it, ja, ko, pl, pt-BR, ro, ru, sk, tr-TR, ua, vi-VN, zh-CN, zh-TW).

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant AttachmentListItem as IssueAttachmentsListItem
  participant AttachmentList as IssueAttachmentItemList
  participant API as BackendAPI
  participant Store as IssueStore
  participant Display as CoverImageComponent

  rect rgba(59, 130, 246, 0.5)
    note over User,AttachmentList: Setting a cover image
    User->>AttachmentListItem: Click "Make cover image"
    AttachmentListItem->>AttachmentList: onToggleCoverImage(attachmentId)
    AttachmentList->>API: PATCH issue {cover_image_attachment_id: attachmentId}
    API-->>AttachmentList: {cover_image_attachment_id, ...}
    AttachmentList->>Store: updateIssue(cover_image_attachment_id)
    AttachmentList->>API: fetchActivities
    AttachmentList-->>User: setPromiseToast(success)
  end

  rect rgba(16, 185, 129, 0.5)
    note over Store,Display: Rendering cover image
    Display->>Store: read cover_image_attachment_id
    Display->>Display: useIssueCoverImage(workspace, project, issue, attachment)
    Display->>Display: fetch image from asset URL
    Display-->>User: render img with object-cover
  end

  rect rgba(239, 68, 68, 0.5)
    note over User,Store: Removing cover image via attachment delete
    User->>API: DELETE attachment
    API->>API: Issue.filter(cover_image_attachment=attachment).update(None)
    API-->>AttachmentList: {deleted}
    AttachmentList->>Store: updateIssue({cover_image_attachment_id: null})
    Store-->>User: cover image cleared
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐇 A bunny hops with art in sight,
A cover image, just right!
Each kanban card now has a face,
Attachments toggle into place.
Set it, remove it, toast appears—
Visual issues bring us cheer! 🖼️

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main feature addition: enabling cover image support for work items, which directly matches the primary change across the changeset.
Description check ✅ Passed The PR description comprehensively covers all required sections: detailed explanation, feature type selection, test scenarios, and issue references. It explains the explicit user-controlled approach, API changes, web implementation, and i18n updates.
Linked Issues check ✅ Passed All coding requirements from issue #3921 are met: cover image functionality is implemented with explicit user control via attachment context menu, covers display on Kanban cards and detail/peek views, API validates cover attachments, and i18n strings are added across all locales.
Out of Scope Changes check ✅ Passed All changes are directly scoped to implementing cover image support. Database migrations, API serializers, web components, styling adjustments, and i18n additions all serve the single feature objective without introducing unrelated functionality.

✏️ 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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 16

🧹 Nitpick comments (1)
apps/web/core/components/issues/attachment/attachment-item-list.tsx (1)

71-98: ⚡ Quick win

Add explicit typed error handling and logging around cover toggle updates.

This new async path relies on promise chaining without a typed try/catch log path in the handler, which makes failures harder to diagnose.

♻️ Suggested update
   const handleToggleCoverImage = useCallback(
     async (attachmentId: string) => {
       const isCurrentCover = getIssueById(issueId)?.cover_image_attachment_id === attachmentId;
       const nextCoverId = isCurrentCover ? null : attachmentId;
-      const coverPromise = updateIssue(workspaceSlug, projectId, issueId, {
-        cover_image_attachment_id: nextCoverId,
-      }).then(() => {
-        handleFetchPropertyActivities();
-        return;
-      });
-
-      setPromiseToast(coverPromise, {
-        loading: isCurrentCover ? t("attachment.remove_cover_loading") : t("attachment.set_cover_loading"),
-        success: {
-          title: isCurrentCover ? t("attachment.remove_cover_success_title") : t("attachment.set_cover_success_title"),
-          message: () =>
-            isCurrentCover ? t("attachment.remove_cover_success_message") : t("attachment.set_cover_success_message"),
-        },
-        error: {
-          title: isCurrentCover ? t("attachment.remove_cover_error_title") : t("attachment.set_cover_error_title"),
-          message: () =>
-            isCurrentCover ? t("attachment.remove_cover_error_message") : t("attachment.set_cover_error_message"),
-        },
-      });
-
-      return coverPromise;
+      try {
+        const coverPromise = updateIssue(workspaceSlug, projectId, issueId, {
+          cover_image_attachment_id: nextCoverId,
+        }).then(() => {
+          handleFetchPropertyActivities();
+        });
+
+        setPromiseToast(coverPromise, {
+          loading: isCurrentCover ? t("attachment.remove_cover_loading") : t("attachment.set_cover_loading"),
+          success: {
+            title: isCurrentCover ? t("attachment.remove_cover_success_title") : t("attachment.set_cover_success_title"),
+            message: () =>
+              isCurrentCover ? t("attachment.remove_cover_success_message") : t("attachment.set_cover_success_message"),
+          },
+          error: {
+            title: isCurrentCover ? t("attachment.remove_cover_error_title") : t("attachment.set_cover_error_title"),
+            message: () =>
+              isCurrentCover ? t("attachment.remove_cover_error_message") : t("attachment.set_cover_error_message"),
+          },
+        });
+
+        await coverPromise;
+      } catch (error: unknown) {
+        console.error("Failed to toggle cover image", error);
+        throw error;
+      }
     },

As per coding guidelines: **/*.{ts,tsx,js,jsx}: Use try-catch with proper error types and log errors appropriately for error handling.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/core/components/issues/attachment/attachment-item-list.tsx` around
lines 71 - 98, The handleToggleCoverImage function uses promise chaining without
explicit typed error handling and logging, making failures difficult to
diagnose. Add a try-catch block around the updateIssue call to explicitly catch
and log errors with proper error type handling. Inside the catch block, log the
error with appropriate context to aid debugging, then re-throw or handle the
error appropriately so setPromiseToast can still handle the error state. This
ensures all async failures in the cover image toggle operation are properly
captured and logged.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/api/plane/app/serializers/issue.py`:
- Around line 203-214: The cover image attachment validation in the serializer
is missing a check for creation requests. Currently, the condition on line 206
only enforces issue ownership during updates (when self.instance is not None),
which allows a create request to reference an image attachment from a different
issue in the same project. Modify the validation logic to either disallow
setting a cover_image_attachment during creation entirely (by raising a
ValidationError if self.instance is None and cover_image_attachment is
provided), or add explicit validation to ensure the cover image doesn't already
belong to another issue, preventing cross-issue cover image references at both
create and update time.

In `@apps/web/core/components/issues/issue-detail/cover-image.tsx`:
- Around line 7-31: The imageLoadError state in the IssueDetailCoverImage
component remains true after an image fails to load, causing the component to
return null even when a new valid cover image URL is provided. Add a useEffect
hook that depends on the coverImageUrl dependency and resets imageLoadError to
false whenever the coverImageUrl changes, ensuring the component attempts to
render new cover images instead of maintaining the previous failure state.

In `@apps/web/core/components/issues/issue-layouts/kanban/cover-image.tsx`:
- Around line 21-27: The imageLoadError state is set to true when image loading
fails but is never reset when a new coverImageAttachmentId arrives and
coverImageUrl updates. Add a useEffect hook that depends on coverImageUrl and
resets imageLoadError to false whenever coverImageUrl changes. This ensures that
when the useIssueCoverImage hook updates coverImageUrl with a new valid URL, the
stale error state from the previous failed image load is cleared and the
component can render the new image instead of continuing to return null.

In `@packages/i18n/src/locales/cs/common.json`:
- Around line 766-777: The newly added cover-image related strings in the Czech
locale file are currently in English, causing mixed-language UI for Czech users.
Translate all twelve strings (make_cover_image, remove_cover_image,
set_cover_loading, set_cover_success_title, set_cover_success_message,
set_cover_error_title, set_cover_error_message, remove_cover_loading,
remove_cover_success_title, remove_cover_success_message,
remove_cover_error_title, and remove_cover_error_message) from English to Czech
to ensure consistent localization throughout the cover image workflow.

In `@packages/i18n/src/locales/de/common.json`:
- Around line 766-777: The cover image feature strings in the German locale file
(packages/i18n/src/locales/de/common.json) are currently in English, causing
mixed-language UI for German users. Translate all twelve newly added strings
(make_cover_image, remove_cover_image, set_cover_loading,
set_cover_success_title, set_cover_success_message, set_cover_error_title,
set_cover_error_message, remove_cover_loading, remove_cover_success_title,
remove_cover_success_message, remove_cover_error_title, and
remove_cover_error_message) to their proper German equivalents to maintain
language consistency throughout the cover image workflow.

In `@packages/i18n/src/locales/es/common.json`:
- Around line 766-777: The newly added cover-image related strings in
packages/i18n/src/locales/es/common.json are in English, causing mixed-language
display for Spanish users. Translate all the English values for the keys from
make_cover_image through remove_cover_error_message into proper Spanish
translations. This includes the action labels, loading states, success messages,
and error messages for the cover image feature. Ensure each key maintains its
corresponding Spanish translation value rather than the English text currently
present.

In `@packages/i18n/src/locales/fr/common.json`:
- Around line 766-777: The newly added cover image strings in the French locale
file are still in English, causing French users to see mixed-language content in
the same workflow. Translate all twelve string values for the keys
"make_cover_image", "remove_cover_image", "set_cover_loading",
"set_cover_success_title", "set_cover_success_message", "set_cover_error_title",
"set_cover_error_message", "remove_cover_loading", "remove_cover_success_title",
"remove_cover_success_message", "remove_cover_error_title", and
"remove_cover_error_message" from their current English values to appropriate
French translations in the common.json file.

In `@packages/i18n/src/locales/id/common.json`:
- Around line 766-777: The newly added cover-image related strings in the
Indonesian locale file (id/common.json) are currently in English, causing
mixed-language display for Indonesian users. Translate all twelve cover-image
string values to Indonesian: make_cover_image, remove_cover_image,
set_cover_loading, set_cover_success_title, set_cover_success_message,
set_cover_error_title, set_cover_error_message, remove_cover_loading,
remove_cover_success_title, remove_cover_success_message,
remove_cover_error_title, and remove_cover_error_message. Keep the keys
unchanged; only replace the English text values with proper Indonesian
translations.

In `@packages/i18n/src/locales/it/common.json`:
- Around line 766-777: Translate all the newly added cover-image related strings
from English to Italian in the common.json file for the Italian locale. The
strings that need translation are: make_cover_image, remove_cover_image,
set_cover_loading, set_cover_success_title, set_cover_success_message,
set_cover_error_title, set_cover_error_message, remove_cover_loading,
remove_cover_success_title, remove_cover_success_message,
remove_cover_error_title, and remove_cover_error_message. Replace each English
value with its appropriate Italian translation to ensure consistent language
presentation for Italian users throughout the cover image flow.

In `@packages/i18n/src/locales/ja/common.json`:
- Around line 766-777: The cover-image related keys (make_cover_image,
remove_cover_image, set_cover_loading, set_cover_success_title,
set_cover_success_message, set_cover_error_title, set_cover_error_message,
remove_cover_loading, remove_cover_success_title, remove_cover_success_message,
remove_cover_error_title, remove_cover_error_message) were added in English but
not translated into other locales, causing mixed-language UI. Replace all these
key values with appropriate translations in each locale file: at
packages/i18n/src/locales/ja/common.json lines 766-777 with Japanese
translations, at packages/i18n/src/locales/ko/common.json lines 766-777 with
Korean translations, at packages/i18n/src/locales/pl/common.json lines 766-777
with Polish translations, at packages/i18n/src/locales/pt-BR/common.json lines
766-777 with Portuguese (Brazil) translations, at
packages/i18n/src/locales/ro/common.json lines 766-777 with Romanian
translations, and at packages/i18n/src/locales/ru/common.json lines 766-777 with
Russian translations.

In `@packages/i18n/src/locales/sk/common.json`:
- Around line 766-777: Translate all the English cover image strings in the
Slovak locale file to Slovak. The strings with keys make_cover_image,
remove_cover_image, set_cover_loading, set_cover_success_title,
set_cover_success_message, set_cover_error_title, set_cover_error_message,
remove_cover_loading, remove_cover_success_title, remove_cover_success_message,
remove_cover_error_title, and remove_cover_error_message currently contain
English text. Replace each English value with its appropriate Slovak translation
to ensure consistent localization and avoid mixed-language UI in the Slovak
locale.

In `@packages/i18n/src/locales/tr-TR/common.json`:
- Around line 766-777: The cover-image related strings in the Turkish locale
file (packages/i18n/src/locales/tr-TR/common.json) are currently in English and
need to be translated to Turkish. Replace the English values for all twelve keys
(make_cover_image, remove_cover_image, set_cover_loading,
set_cover_success_title, set_cover_success_message, set_cover_error_title,
set_cover_error_message, remove_cover_loading, remove_cover_success_title,
remove_cover_success_message, remove_cover_error_title, and
remove_cover_error_message) with their appropriate Turkish translations to
ensure Turkish users see localized content in the UI for cover image actions and
toast messages.

In `@packages/i18n/src/locales/ua/common.json`:
- Around line 766-777: The cover image related strings in the Ukrainian locale
file (make_cover_image, remove_cover_image, set_cover_loading,
set_cover_success_title, set_cover_success_message, set_cover_error_title,
set_cover_error_message, remove_cover_loading, remove_cover_success_title,
remove_cover_success_message, remove_cover_error_title, and
remove_cover_error_message keys) are currently in English rather than Ukrainian,
breaking localization consistency. Translate each of these string values from
English to their corresponding Ukrainian equivalents while keeping the key names
unchanged.

In `@packages/i18n/src/locales/vi-VN/common.json`:
- Around line 766-777: The cover-image related strings in the Vietnamese locale
file are currently in English and need to be translated to Vietnamese. Translate
all twelve keys (make_cover_image, remove_cover_image, set_cover_loading,
set_cover_success_title, set_cover_success_message, set_cover_error_title,
set_cover_error_message, remove_cover_loading, remove_cover_success_title,
remove_cover_success_message, remove_cover_error_title, and
remove_cover_error_message) from their English values to their appropriate
Vietnamese equivalents to ensure the cover image workflow is fully localized for
Vietnamese users.

In `@packages/i18n/src/locales/zh-CN/common.json`:
- Around line 766-777: The cover-image related strings in the Simplified Chinese
locale file are currently in English instead of being translated to Chinese. In
packages/i18n/src/locales/zh-CN/common.json, translate the values for the
following keys from English to Simplified Chinese: make_cover_image,
remove_cover_image, set_cover_loading, set_cover_success_title,
set_cover_success_message, set_cover_error_title, set_cover_error_message,
remove_cover_loading, remove_cover_success_title, remove_cover_success_message,
remove_cover_error_title, and remove_cover_error_message. Ensure each
translation is contextually appropriate and consistent with the existing tone
and style of the zh-CN locale file.

In `@packages/i18n/src/locales/zh-TW/common.json`:
- Around line 766-777: The cover image feature strings in the zh-TW locale file
(make_cover_image, remove_cover_image, set_cover_loading,
set_cover_success_title, set_cover_success_message, set_cover_error_title,
set_cover_error_message, remove_cover_loading, remove_cover_success_title,
remove_cover_success_message, remove_cover_error_title, and
remove_cover_error_message) are currently in English instead of Traditional
Chinese. Translate each of these twelve string values from English to
Traditional Chinese to ensure consistent localization for zh-TW users.

---

Nitpick comments:
In `@apps/web/core/components/issues/attachment/attachment-item-list.tsx`:
- Around line 71-98: The handleToggleCoverImage function uses promise chaining
without explicit typed error handling and logging, making failures difficult to
diagnose. Add a try-catch block around the updateIssue call to explicitly catch
and log errors with proper error type handling. Inside the catch block, log the
error with appropriate context to aid debugging, then re-throw or handle the
error appropriately so setPromiseToast can still handle the error state. This
ensures all async failures in the cover image toggle operation are properly
captured and logged.
🪄 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: a3f955f0-6deb-483b-ab06-c2d43150909e

📥 Commits

Reviewing files that changed from the base of the PR and between f2feca6 and f3d1027.

📒 Files selected for processing (37)
  • apps/api/plane/app/serializers/issue.py
  • apps/api/plane/app/views/issue/attachment.py
  • apps/api/plane/app/views/issue/base.py
  • apps/api/plane/app/views/issue/sub_issue.py
  • apps/api/plane/db/migrations/0122_issue_cover_image_attachment.py
  • apps/api/plane/db/models/issue.py
  • apps/api/plane/utils/grouper.py
  • apps/web/core/components/issues/attachment/attachment-item-list.tsx
  • apps/web/core/components/issues/attachment/attachment-list-item.tsx
  • apps/web/core/components/issues/issue-detail/cover-image.tsx
  • apps/web/core/components/issues/issue-detail/main-content.tsx
  • apps/web/core/components/issues/issue-layouts/kanban/block.tsx
  • apps/web/core/components/issues/issue-layouts/kanban/cover-image.tsx
  • apps/web/core/components/issues/peek-overview/issue-detail.tsx
  • apps/web/core/hooks/use-issue-cover-image.ts
  • apps/web/core/store/issue/issue-details/attachment.store.ts
  • apps/web/core/store/issue/issue-details/issue.store.ts
  • packages/i18n/src/locales/cs/common.json
  • packages/i18n/src/locales/de/common.json
  • packages/i18n/src/locales/en/common.json
  • packages/i18n/src/locales/es/common.json
  • packages/i18n/src/locales/fr/common.json
  • packages/i18n/src/locales/id/common.json
  • packages/i18n/src/locales/it/common.json
  • packages/i18n/src/locales/ja/common.json
  • packages/i18n/src/locales/ko/common.json
  • packages/i18n/src/locales/pl/common.json
  • packages/i18n/src/locales/pt-BR/common.json
  • packages/i18n/src/locales/ro/common.json
  • packages/i18n/src/locales/ru/common.json
  • packages/i18n/src/locales/sk/common.json
  • packages/i18n/src/locales/tr-TR/common.json
  • packages/i18n/src/locales/ua/common.json
  • packages/i18n/src/locales/vi-VN/common.json
  • packages/i18n/src/locales/zh-CN/common.json
  • packages/i18n/src/locales/zh-TW/common.json
  • packages/types/src/issues/issue.ts

Comment thread apps/api/plane/app/serializers/issue.py Outdated
Comment thread apps/web/core/components/issues/issue-detail/cover-image.tsx Outdated
Comment thread packages/i18n/src/locales/cs/common.json
Comment on lines +766 to +777
"make_cover_image": "Make cover image",
"remove_cover_image": "Remove cover image",
"set_cover_loading": "Setting cover image...",
"set_cover_success_title": "Cover image set",
"set_cover_success_message": "This image is now the cover image",
"set_cover_error_title": "Couldn't set cover image",
"set_cover_error_message": "Could not set this image as the cover",
"remove_cover_loading": "Removing cover image...",
"remove_cover_success_title": "Cover image removed",
"remove_cover_success_message": "This work item no longer has a cover image",
"remove_cover_error_title": "Couldn't remove cover image",
"remove_cover_error_message": "Could not remove the cover image"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Localize the new cover-image strings for this locale.

The newly added values are in English, so German users will see mixed-language labels/toasts in the same flow.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/i18n/src/locales/de/common.json` around lines 766 - 777, The cover
image feature strings in the German locale file
(packages/i18n/src/locales/de/common.json) are currently in English, causing
mixed-language UI for German users. Translate all twelve newly added strings
(make_cover_image, remove_cover_image, set_cover_loading,
set_cover_success_title, set_cover_success_message, set_cover_error_title,
set_cover_error_message, remove_cover_loading, remove_cover_success_title,
remove_cover_success_message, remove_cover_error_title, and
remove_cover_error_message) to their proper German equivalents to maintain
language consistency throughout the cover image workflow.

Comment on lines +766 to +777
"make_cover_image": "Make cover image",
"remove_cover_image": "Remove cover image",
"set_cover_loading": "Setting cover image...",
"set_cover_success_title": "Cover image set",
"set_cover_success_message": "This image is now the cover image",
"set_cover_error_title": "Couldn't set cover image",
"set_cover_error_message": "Could not set this image as the cover",
"remove_cover_loading": "Removing cover image...",
"remove_cover_success_title": "Cover image removed",
"remove_cover_success_message": "This work item no longer has a cover image",
"remove_cover_error_title": "Couldn't remove cover image",
"remove_cover_error_message": "Could not remove the cover image"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Localize new cover-image strings for Turkish.

The newly added cover-image keys are English strings, so Turkish users will see untranslated content in attachment actions/toasts.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/i18n/src/locales/tr-TR/common.json` around lines 766 - 777, The
cover-image related strings in the Turkish locale file
(packages/i18n/src/locales/tr-TR/common.json) are currently in English and need
to be translated to Turkish. Replace the English values for all twelve keys
(make_cover_image, remove_cover_image, set_cover_loading,
set_cover_success_title, set_cover_success_message, set_cover_error_title,
set_cover_error_message, remove_cover_loading, remove_cover_success_title,
remove_cover_success_message, remove_cover_error_title, and
remove_cover_error_message) with their appropriate Turkish translations to
ensure Turkish users see localized content in the UI for cover image actions and
toast messages.

Comment on lines +766 to +777
"make_cover_image": "Make cover image",
"remove_cover_image": "Remove cover image",
"set_cover_loading": "Setting cover image...",
"set_cover_success_title": "Cover image set",
"set_cover_success_message": "This image is now the cover image",
"set_cover_error_title": "Couldn't set cover image",
"set_cover_error_message": "Could not set this image as the cover",
"remove_cover_loading": "Removing cover image...",
"remove_cover_success_title": "Cover image removed",
"remove_cover_success_message": "This work item no longer has a cover image",
"remove_cover_error_title": "Couldn't remove cover image",
"remove_cover_error_message": "Could not remove the cover image"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Localize new cover-image strings for Ukrainian.

attachment.make_cover_image and related set/remove cover toast strings are English here, which breaks localization consistency for ua.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/i18n/src/locales/ua/common.json` around lines 766 - 777, The cover
image related strings in the Ukrainian locale file (make_cover_image,
remove_cover_image, set_cover_loading, set_cover_success_title,
set_cover_success_message, set_cover_error_title, set_cover_error_message,
remove_cover_loading, remove_cover_success_title, remove_cover_success_message,
remove_cover_error_title, and remove_cover_error_message keys) are currently in
English rather than Ukrainian, breaking localization consistency. Translate each
of these string values from English to their corresponding Ukrainian equivalents
while keeping the key names unchanged.

Comment on lines +766 to +777
"make_cover_image": "Make cover image",
"remove_cover_image": "Remove cover image",
"set_cover_loading": "Setting cover image...",
"set_cover_success_title": "Cover image set",
"set_cover_success_message": "This image is now the cover image",
"set_cover_error_title": "Couldn't set cover image",
"set_cover_error_message": "Could not set this image as the cover",
"remove_cover_loading": "Removing cover image...",
"remove_cover_success_title": "Cover image removed",
"remove_cover_success_message": "This work item no longer has a cover image",
"remove_cover_error_title": "Couldn't remove cover image",
"remove_cover_error_message": "Could not remove the cover image"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Localize new cover-image strings for Vietnamese.

The new cover-image labels/messages are English in the vi-VN locale, so this flow won’t be fully localized for Vietnamese users.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/i18n/src/locales/vi-VN/common.json` around lines 766 - 777, The
cover-image related strings in the Vietnamese locale file are currently in
English and need to be translated to Vietnamese. Translate all twelve keys
(make_cover_image, remove_cover_image, set_cover_loading,
set_cover_success_title, set_cover_success_message, set_cover_error_title,
set_cover_error_message, remove_cover_loading, remove_cover_success_title,
remove_cover_success_message, remove_cover_error_title, and
remove_cover_error_message) from their English values to their appropriate
Vietnamese equivalents to ensure the cover image workflow is fully localized for
Vietnamese users.

Comment on lines +766 to +777
"make_cover_image": "Make cover image",
"remove_cover_image": "Remove cover image",
"set_cover_loading": "Setting cover image...",
"set_cover_success_title": "Cover image set",
"set_cover_success_message": "This image is now the cover image",
"set_cover_error_title": "Couldn't set cover image",
"set_cover_error_message": "Could not set this image as the cover",
"remove_cover_loading": "Removing cover image...",
"remove_cover_success_title": "Cover image removed",
"remove_cover_success_message": "This work item no longer has a cover image",
"remove_cover_error_title": "Couldn't remove cover image",
"remove_cover_error_message": "Could not remove the cover image"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Localize new cover-image strings for Simplified Chinese.

The added cover-image action/toast strings are still English, which introduces inconsistent language in zh-CN.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/i18n/src/locales/zh-CN/common.json` around lines 766 - 777, The
cover-image related strings in the Simplified Chinese locale file are currently
in English instead of being translated to Chinese. In
packages/i18n/src/locales/zh-CN/common.json, translate the values for the
following keys from English to Simplified Chinese: make_cover_image,
remove_cover_image, set_cover_loading, set_cover_success_title,
set_cover_success_message, set_cover_error_title, set_cover_error_message,
remove_cover_loading, remove_cover_success_title, remove_cover_success_message,
remove_cover_error_title, and remove_cover_error_message. Ensure each
translation is contextually appropriate and consistent with the existing tone
and style of the zh-CN locale file.

Comment on lines +766 to +777
"make_cover_image": "Make cover image",
"remove_cover_image": "Remove cover image",
"set_cover_loading": "Setting cover image...",
"set_cover_success_title": "Cover image set",
"set_cover_success_message": "This image is now the cover image",
"set_cover_error_title": "Couldn't set cover image",
"set_cover_error_message": "Could not set this image as the cover",
"remove_cover_loading": "Removing cover image...",
"remove_cover_success_title": "Cover image removed",
"remove_cover_success_message": "This work item no longer has a cover image",
"remove_cover_error_title": "Couldn't remove cover image",
"remove_cover_error_message": "Could not remove the cover image"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Translate new attachment cover-image strings in zh-TW locale.

Lines 766-777 are still English, which causes mixed-language UI for Traditional Chinese users.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/i18n/src/locales/zh-TW/common.json` around lines 766 - 777, The
cover image feature strings in the zh-TW locale file (make_cover_image,
remove_cover_image, set_cover_loading, set_cover_success_title,
set_cover_success_message, set_cover_error_title, set_cover_error_message,
remove_cover_loading, remove_cover_success_title, remove_cover_success_message,
remove_cover_error_title, and remove_cover_error_message) are currently in
English instead of Traditional Chinese. Translate each of these twelve string
values from English to Traditional Chinese to ensure consistent localization for
zh-TW users.

- Reset the image load-error flag when the cover URL changes, so a new
  valid cover renders after a previous one failed to load (kanban + detail).
- Reject a cover_image_attachment on issue create: a new issue has no
  attachments of its own yet, so the ownership check now requires an
  existing instance instead of being skipped on create.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
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.

[feature]: Cover images for issue cards previews

2 participants