Skip to content

feat(component): allow providing a comment when declining a request#1633

Open
ornelasf1 wants to merge 11 commits into
seerr-team:developfrom
ornelasf1:feat/decline-w-comment
Open

feat(component): allow providing a comment when declining a request#1633
ornelasf1 wants to merge 11 commits into
seerr-team:developfrom
ornelasf1:feat/decline-w-comment

Conversation

@ornelasf1

@ornelasf1 ornelasf1 commented May 5, 2025

Copy link
Copy Markdown

Description

A user is able to decline a request with a message. The request will be declined and the requester will be notified with the reason for it. The message is optional so if the field is left blank, then no message will be added

AI Disclosure: None.

How Has This Been Tested?

I ran the app locally. I signed in with an admin user and a regular on separate browsers. Created requests and declined with and without reasons. Verified the request was updated with message and that the notifications were delivered with messages.

Screenshots / Logs (if applicable)

Modal for declining with message
decline-comment-1

Comment appearing in list of requests
decline-comment-2

Email with decline reason.
decline-comment-3
Discord webhook with decline reason.
image
Pushbullet with decline reason
image
And other notification providers.

Checklist:

  • I have read and followed the contribution guidelines.
  • Disclosed any use of AI (see our policy)
  • I have updated the documentation accordingly.
  • All new and existing tests passed.
  • Successful build pnpm build
  • Translation keys pnpm i18n:extract
  • Database migration (if required)

Summary by CodeRabbit

  • New Features
    • Added an improved decline flow with a dedicated modal that lets you enter an optional decline reason when declining media requests.
    • The backend and API now accept and store an optional declineReason for declined requests.
    • Decline reasons are shown to users and admins across the UI (tooltips on request cards) and in notifications on all supported channels, including reason-specific message templates for declined requests.

@thymon13

Copy link
Copy Markdown

It should also be able to work in 'auto-approve' mode, because currently, we can only delete the ongoing request without providing a reason.

@ornelasf1

Copy link
Copy Markdown
Author

It should also be able to work in 'auto-approve' mode, because currently, we can only delete the ongoing request without providing a reason.

Are you sure you want to be deleting the request instead of declining? You can't leave a reason if it's deleted from the system.

With this, the reason is optional. Simply decline without adding a message

@ojmaster

ojmaster commented Aug 4, 2025

Copy link
Copy Markdown

Hey it's been a few months i was wondering if this could get looked at by the reviewers? not sure if there's anything else it's waiting on

@gauthier-th

Copy link
Copy Markdown
Member

Hey it's been a few months i was wondering if this could get looked at by the reviewers? not sure if there's anything else it's waiting on

We are always focused on fixing bugs and merging fixes before adding new features.
We have not yet had time to review this either.

@thymon13

Copy link
Copy Markdown

Great !! Can't wait 😅😆

@github-actions github-actions Bot added the merge conflict Cannot merge due to merge conflicts label Oct 6, 2025
@github-actions

github-actions Bot commented Oct 6, 2025

Copy link
Copy Markdown

This pull request has merge conflicts. Please resolve the conflicts so the PR can be successfully reviewed and merged.

@ornelasf1 ornelasf1 requested a review from a team as a code owner October 11, 2025 20:29
@github-actions github-actions Bot removed the merge conflict Cannot merge due to merge conflicts label Oct 11, 2025
@github-actions github-actions Bot added the merge conflict Cannot merge due to merge conflicts label Apr 6, 2026
@github-actions

github-actions Bot commented Apr 6, 2026

Copy link
Copy Markdown

This pull request has merge conflicts. Please resolve the conflicts so the PR can be successfully reviewed and merged.

@gauthier-th

Copy link
Copy Markdown
Member

@ornelasf1 sorry for the late review. Can you please rebase this on develop to fix the merge conflict?
Could you also edit your PR description to match the new PR template (available here)

@github-actions

github-actions Bot commented Jun 6, 2026

Copy link
Copy Markdown

This PR is stale because it has been open 30 days with no activity. Please address the feedback or provide an update to keep it open.

@github-actions github-actions Bot added the stale label Jun 6, 2026
@thymon13

This comment was marked as off-topic.

@github-actions github-actions Bot removed the stale label Jun 7, 2026
@daveemu

This comment was marked as off-topic.

@M0NsTeRRR

M0NsTeRRR commented Jun 15, 2026

Copy link
Copy Markdown
Member

Avoid commenting here, PRs are not meant for that, read the CONTRIBUTING.md please.

@ornelasf1

Copy link
Copy Markdown
Author

@ornelasf1 Would love to see this feature merged to main!

Hi, I've been busy, but I'll get this done soon

@ornelasf1 ornelasf1 force-pushed the feat/decline-w-comment branch from 35a86bd to a4f32da Compare June 20, 2026 18:58
@github-actions github-actions Bot removed the merge conflict Cannot merge due to merge conflicts label Jun 20, 2026
@coderabbitai

coderabbitai Bot commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds optional decline reason storage, API support, notification rendering, and a modal-based decline flow in the frontend.

Changes

Decline Request with Reason

Layer / File(s) Summary
Entity, migrations, and API contract
server/entity/MediaRequest.ts, server/migration/postgres/..., server/migration/sqlite/..., seerr-api.yml
Adds a nullable declineReason column to MediaRequest, migrates it in Postgres and SQLite, and exposes it in the OpenAPI schema and decline/update request bodies.
Request route persistence
server/routes/request.ts
Reads declineReason from the request body and stores a trimmed, 500-character-limited value on decline updates, otherwise clears it.
Notification formatting
server/lib/notifications/agents/discord.ts, email.ts, gotify.ts, ntfy.ts, pushbullet.ts, pushover.ts, slack.ts, telegram.ts, webpush.ts, server/i18n/...
Conditionally appends decline-reason text to MEDIA_DECLINED notifications across all agents, with supporting i18n keys and locale strings.
DeclineRequestModal
src/components/RequestModal/DeclineRequestModal/index.tsx, src/i18n/globalMessages.ts, src/i18n/locale/en.json
Adds a modal form for optional decline reason entry and posts { declineReason } for each declined request, with new modal text translations.
Request decline entry points
src/components/RequestButton/index.tsx, src/components/RequestCard/index.tsx, src/components/RequestList/RequestItem/index.tsx
Replaces direct decline actions with modal opening, and shows existing declineReason text in tooltips on request cards/items.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • gauthier-th
  • fallenbagel

Poem

🐰 A reason for the rabbit's hop,
Now shows up when the declins stop.
A note can ride along the trail,
In modal, message, card, and mail.
Soft ears, soft words, and one more field—
The declined request’s why is revealed.

🚥 Pre-merge checks | ✅ 3 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The setup sign-in text change in src/i18n/locale/en.json is unrelated to the decline-comment feature. Remove the setup sign-in wording change or move it to a separate localization PR.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly states the main user-facing change: adding an optional comment when declining a request.
Linked Issues check ✅ Passed The PR adds an optional decline reason flow, persists and surfaces it in requests and notifications, and allows blank reasons as requested.

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.

@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: 9

🧹 Nitpick comments (1)
server/lib/notifications/agents/webpush.ts (1)

128-139: 💤 Low value

Redundant null check on payload.request.

The condition payload.request && payload.request?.declineReason is redundant. Since the second operand uses optional chaining, it will safely evaluate to undefined if payload.request is nullish. The email agent (line 172) uses simply if (!payload.request.declineReason).

Suggested simplification
       case Notification.MEDIA_DECLINED:
-        if (payload.request && payload.request?.declineReason) {
+        if (payload.request?.declineReason) {
           message = intl.formatMessage(messages.declinedWithReason, {
🤖 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 `@server/lib/notifications/agents/webpush.ts` around lines 128 - 139, The
condition checking `payload.request && payload.request?.declineReason` contains
a redundant null check. Since optional chaining (the `?.` operator) already
safely handles nullish values by returning undefined, the explicit
`payload.request &&` check is unnecessary. Simplify the if condition to just `if
(payload.request?.declineReason)` to remove the redundancy while maintaining the
same behavior.
🤖 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 `@seerr-api.yml`:
- Around line 1274-1275: The declineReason field in the MediaRequest schema
definition needs to be marked as nullable to match runtime behavior where this
field can be null when no decline reason is stored. Update the declineReason
property definition to allow null values in addition to string values, ensuring
the OpenAPI schema accurately represents the actual response contract and
prevents mismatches for generated clients.

In `@server/entity/MediaRequest.ts`:
- Around line 556-558: The TypeScript type for the declineReason property does
not include null even though the database column is marked as nullable: true,
creating a type safety mismatch. Update the type annotation of the declineReason
field from string to string | null to accurately reflect that the database can
store null values for this column and maintain type safety with strict null
checks enabled.

In `@server/lib/notifications/agents/discord.ts`:
- Around line 145-155: The field name 'Decline Reason' in the fields.push() call
is hardcoded as a string instead of using the localized message like other
notification agents. Replace the hardcoded string 'Decline Reason' with
intl.formatMessage(globalMessages.declineReason) to ensure the Discord
notification agent uses the same internationalization approach as the Email,
Gotify, Ntfy, Pushbullet, Pushover, and Slack agents.

In `@server/lib/notifications/agents/ntfy.ts`:
- Around line 70-76: The declineReason value is being inserted directly into the
Markdown message without escaping user-provided content, creating a consistency
issue and potential Markdown formatting vulnerability. In the code block
handling Notification.MEDIA_DECLINED, wrap payload.request.declineReason with
this.escapeMarkdown() before concatenating it into the message string, following
the same pattern used for escaping payload.request.requestedBy.displayName
elsewhere in the file.

In `@server/migration/postgres/1781897226978-AddRequestDeclinedMessage.ts`:
- Around line 6-172: The migration in the up() method is recreating the entire
database schema instead of incrementally adding just the new declineReason
column to the media_request table. Replace the full table creation logic with an
ALTER TABLE statement that adds only the declineReason text column to the
existing media_request table. Similarly, update the down() method to use ALTER
TABLE to drop only the declineReason column instead of dropping all tables. This
ensures the migration is safe and non-destructive for environments with existing
data.

In `@server/routes/request.ts`:
- Around line 690-692: The declineReason field persists on the request object
even when the status changes from decline to approve or pending, causing
outdated decline reasons to be displayed on the frontend. Add logic to clear the
declineReason field (set it to null or undefined) whenever the request status is
updated to approve or pending status values, ensuring the field only contains a
value when the current status is decline. This should be implemented in the same
section where you handle status changes and set declineReason.

In `@src/components/RequestButton/index.tsx`:
- Line 166: The issue is that setShowDeclineCommentModal and related modal state
setters only flip a boolean flag without preserving which specific decline
action or request target was selected, causing the wrong request set to be
submitted when the modal confirms. To fix this, store the decline target context
(such as the specific request ID or action type being declined) in state
alongside the modal visibility flag at all affected locations (lines 166, 194,
236, 264, and the block at 396-400). Then use this stored context when the modal
confirms the action, rather than recomputing from current state which may have
changed or be ambiguous.

In `@src/components/RequestModal/DeclineRequestModal/index.tsx`:
- Around line 128-132: The decline button in DeclineRequestModal has both
type="submit" and an onClick handler that manually calls handleSubmit(), causing
the form to submit twice. Remove the onClick={() => handleSubmit()} prop from
the button element since Formik's Form component automatically handles
submission when type="submit" is present. Keep only the type, buttonType, and
disabled props on the button.
- Around line 85-95: The current error handling in the results.forEach loop only
catches rejected promises but does not handle HTTP error responses from
handleSubmit. Since fetch resolves even on 4xx/5xx status codes, failed HTTP
responses appear as fulfilled promises and bypass the error check. Modify the
forEach loop that iterates through results to also check if a fulfilled result
has a Response object with a non-ok status (res.ok === false), and throw an
appropriate error in that case so that HTTP failures are properly treated as
failures before onComplete is called.

---

Nitpick comments:
In `@server/lib/notifications/agents/webpush.ts`:
- Around line 128-139: The condition checking `payload.request &&
payload.request?.declineReason` contains a redundant null check. Since optional
chaining (the `?.` operator) already safely handles nullish values by returning
undefined, the explicit `payload.request &&` check is unnecessary. Simplify the
if condition to just `if (payload.request?.declineReason)` to remove the
redundancy while maintaining the same behavior.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: be9ce7ba-9f62-435e-9bdc-3f2a42fd2d17

📥 Commits

Reviewing files that changed from the base of the PR and between 0a1f703 and a4f32da.

📒 Files selected for processing (22)
  • seerr-api.yml
  • server/entity/MediaRequest.ts
  • server/i18n/globalMessages.ts
  • server/i18n/locale/en.json
  • server/lib/notifications/agents/discord.ts
  • server/lib/notifications/agents/email.ts
  • server/lib/notifications/agents/gotify.ts
  • server/lib/notifications/agents/ntfy.ts
  • server/lib/notifications/agents/pushbullet.ts
  • server/lib/notifications/agents/pushover.ts
  • server/lib/notifications/agents/slack.ts
  • server/lib/notifications/agents/telegram.ts
  • server/lib/notifications/agents/webpush.ts
  • server/migration/postgres/1781897226978-AddRequestDeclinedMessage.ts
  • server/migration/sqlite/1781897118247-AddRequestDeclinedMessage.ts
  • server/routes/request.ts
  • src/components/RequestButton/index.tsx
  • src/components/RequestCard/index.tsx
  • src/components/RequestList/RequestItem/index.tsx
  • src/components/RequestModal/DeclineRequestModal/index.tsx
  • src/i18n/globalMessages.ts
  • src/i18n/locale/en.json

Comment thread seerr-api.yml
Comment thread server/entity/MediaRequest.ts
Comment thread server/lib/notifications/agents/discord.ts
Comment thread server/lib/notifications/agents/ntfy.ts
Comment thread server/migration/postgres/1781897226978-AddRequestDeclinedMessage.ts Outdated
Comment thread server/routes/request.ts Outdated
Comment thread src/components/RequestButton/index.tsx
Comment thread src/components/RequestModal/DeclineRequestModal/index.tsx
Comment thread src/components/RequestModal/DeclineRequestModal/index.tsx

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

♻️ Duplicate comments (2)
src/components/RequestModal/DeclineRequestModal/index.tsx (1)

50-58: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Re-throw request failures so batch decline can’t report false success.

Line 50-58 catches axios.post errors but resolves instead of rejecting; then Line 92-94 never detects failures and Line 98-100 may still call onComplete() after partial/failed declines.

Suggested fix
   const handleSubmit = async (
     requestId: number,
     values: { reason: string }
   ) => {
     try {
       await axios.post(`/api/v1/request/${requestId}/decline`, {
         declineReason: values.reason,
       });
-    } catch {
-      if (onError) {
-        onError();
-      }
+    } catch (error) {
+      onError?.();
+      throw error;
     }
   };

Also applies to: 88-95

🤖 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 `@src/components/RequestModal/DeclineRequestModal/index.tsx` around lines 50 -
58, The catch block in the axios.post call for declining a request (lines 50-58)
handles the error by calling the onError callback but does not re-throw the
error, causing the Promise to resolve successfully even when the request fails.
This prevents the batch decline logic from detecting failures, allowing false
success reports. After calling onError() in the catch block, re-throw the error
so that the calling code can properly detect and handle request failures.
src/components/RequestButton/index.tsx (1)

166-166: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Persist decline targets in state; current wiring can decline the wrong requests.

Line 166/194/236/264 only toggles modal visibility. At Line 399, modal requests are always derived from non-4K state (activeRequest/activeRequests), so 4K decline actions can operate on the wrong set. Also, Line 396 prevents rendering when only 4K requests are pending.

Suggested fix
+  const [declineTargets, setDeclineTargets] = useState<MediaRequest[]>([]);
@@
           action: () => {
+            setDeclineTargets([activeRequest]);
             setShowDeclineCommentModal(true);
           },
@@
           action: () => {
+            setDeclineTargets(activeRequests);
             setShowDeclineCommentModal(true);
           },
@@
           action: () => {
+            setDeclineTargets([active4kRequest]);
             setShowDeclineCommentModal(true);
           },
@@
           action: () => {
+            setDeclineTargets(active4kRequests);
             setShowDeclineCommentModal(true);
           },
@@
-      {(activeRequest || (activeRequests && activeRequests.length > 0)) && (
+      {declineTargets.length > 0 && (
         <DeclineRequestModal
           show={showDeclineCommentModal}
-          requests={activeRequest ? [activeRequest] : activeRequests}
+          requests={declineTargets}
           type={mediaType}
-          onCancel={() => setShowDeclineCommentModal(false)}
+          onCancel={() => {
+            setShowDeclineCommentModal(false);
+            setDeclineTargets([]);
+          }}
           onComplete={() => {
             onUpdate();
             mutate('/api/v1/request/count');
             setShowDeclineCommentModal(false);
+            setDeclineTargets([]);
           }}
         />
       )}

Also applies to: 194-194, 236-236, 264-264, 396-400

🤖 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 `@src/components/RequestButton/index.tsx` at line 166, The decline modal
visibility toggles at lines 166, 194, 236, and 264 do not persist which specific
request is being declined. The modal confirmation handler at line 399 always
uses the generic activeRequest or activeRequests state to determine what to
decline, which causes the wrong request to be declined when a 4K request decline
action opens the modal. Add a new state variable to track the specific decline
target (either a single request or list of requests), populate it alongside
setShowDeclineCommentModal(true) at each of the four toggle locations, and then
use this persisted decline target in the modal confirmation handler instead of
dereferencing activeRequest or activeRequests.
🤖 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.

Duplicate comments:
In `@src/components/RequestButton/index.tsx`:
- Line 166: The decline modal visibility toggles at lines 166, 194, 236, and 264
do not persist which specific request is being declined. The modal confirmation
handler at line 399 always uses the generic activeRequest or activeRequests
state to determine what to decline, which causes the wrong request to be
declined when a 4K request decline action opens the modal. Add a new state
variable to track the specific decline target (either a single request or list
of requests), populate it alongside setShowDeclineCommentModal(true) at each of
the four toggle locations, and then use this persisted decline target in the
modal confirmation handler instead of dereferencing activeRequest or
activeRequests.

In `@src/components/RequestModal/DeclineRequestModal/index.tsx`:
- Around line 50-58: The catch block in the axios.post call for declining a
request (lines 50-58) handles the error by calling the onError callback but does
not re-throw the error, causing the Promise to resolve successfully even when
the request fails. This prevents the batch decline logic from detecting
failures, allowing false success reports. After calling onError() in the catch
block, re-throw the error so that the calling code can properly detect and
handle request failures.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0cee2e09-2fc2-4454-a0cd-b73d7c3a050f

📥 Commits

Reviewing files that changed from the base of the PR and between a4f32da and 8da76e6.

📒 Files selected for processing (6)
  • server/lib/notifications/agents/discord.ts
  • server/routes/request.ts
  • src/components/RequestButton/index.tsx
  • src/components/RequestCard/index.tsx
  • src/components/RequestList/RequestItem/index.tsx
  • src/components/RequestModal/DeclineRequestModal/index.tsx
🚧 Files skipped from review as they are similar to previous changes (4)
  • server/lib/notifications/agents/discord.ts
  • server/routes/request.ts
  • src/components/RequestList/RequestItem/index.tsx
  • src/components/RequestCard/index.tsx

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

🧹 Nitpick comments (1)
server/migration/sqlite/1781992375456-AddRequestDeclinedMessage.ts (1)

7-20: ⚡ Quick win

Remove redundant user_push_subscription rebuilds.

The user_push_subscription table is rebuilt twice in up() (lines 7-20 and 47-60) with identical schema each time. Since this migration only adds declineReason to media_request, these operations are unnecessary and appear to be TypeORM migration generator artifacts. They double migration time and add DDL risk without effect.

Same issue exists in down() at lines 64-77 and 104-117.

♻️ Suggested cleanup for up() method
 public async up(queryRunner: QueryRunner): Promise<void> {
-  await queryRunner.query(`DROP INDEX "IDX_03f7958328e311761b0de675fb"`);
-  await queryRunner.query(
-    `CREATE TABLE "temporary_user_push_subscription" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "endpoint" varchar NOT NULL, "p256dh" varchar NOT NULL, "auth" varchar NOT NULL, "userId" integer, "userAgent" varchar, "createdAt" datetime DEFAULT (CURRENT_TIMESTAMP), CONSTRAINT "UQ_6427d07d9a171a3a1ab87480005" UNIQUE ("endpoint", "userId"), CONSTRAINT "UQ_f90ab5a4ed54905a4bb51a7148b" UNIQUE ("auth"), CONSTRAINT "FK_03f7958328e311761b0de675fbe" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`
-  );
-  await queryRunner.query(
-    `INSERT INTO "temporary_user_push_subscription"("id", "endpoint", "p256dh", "auth", "userId", "userAgent", "createdAt") SELECT "id", "endpoint", "p256dh", "auth", "userId", "userAgent", "createdAt" FROM "user_push_subscription"`
-  );
-  await queryRunner.query(`DROP TABLE "user_push_subscription"`);
-  await queryRunner.query(
-    `ALTER TABLE "temporary_user_push_subscription" RENAME TO "user_push_subscription"`
-  );
-  await queryRunner.query(
-    `CREATE INDEX "IDX_03f7958328e311761b0de675fb" ON "user_push_subscription" ("userId") `
-  );
   await queryRunner.query(`DROP INDEX "IDX_4c696e8ed36ae34fe18abe59d2"`);
   // ... media_request rebuild with declineReason ...
   await queryRunner.query(
     `CREATE INDEX "IDX_4c696e8ed36ae34fe18abe59d2" ON "media_request" ("status") `
   );
-  await queryRunner.query(`DROP INDEX "IDX_03f7958328e311761b0de675fb"`);
-  // ... second identical user_push_subscription rebuild ...
 }

Also applies to: 47-60

🤖 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 `@server/migration/sqlite/1781992375456-AddRequestDeclinedMessage.ts` around
lines 7 - 20, The migration file contains duplicate and identical rebuilds of
the user_push_subscription table in both the up() and down() methods. In the
up() method, remove the second identical user_push_subscription rebuild sequence
(lines 47-60) that duplicates the first one (lines 7-20), and in the down()
method, remove the second identical sequence (lines 104-117) that duplicates the
first one (lines 64-77). Since this migration only adds declineReason to
media_request, the duplicate user_push_subscription table operations are
unnecessary and should be eliminated to reduce migration time and DDL risk.
🤖 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.

Nitpick comments:
In `@server/migration/sqlite/1781992375456-AddRequestDeclinedMessage.ts`:
- Around line 7-20: The migration file contains duplicate and identical rebuilds
of the user_push_subscription table in both the up() and down() methods. In the
up() method, remove the second identical user_push_subscription rebuild sequence
(lines 47-60) that duplicates the first one (lines 7-20), and in the down()
method, remove the second identical sequence (lines 104-117) that duplicates the
first one (lines 64-77). Since this migration only adds declineReason to
media_request, the duplicate user_push_subscription table operations are
unnecessary and should be eliminated to reduce migration time and DDL risk.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6e996bef-1bf1-4ea2-a60f-ea912098ebb2

📥 Commits

Reviewing files that changed from the base of the PR and between 8da76e6 and 3c0dbfb.

📒 Files selected for processing (4)
  • server/entity/MediaRequest.ts
  • server/lib/notifications/agents/ntfy.ts
  • server/migration/postgres/1781992427522-AddRequestDeclinedMessage.ts
  • server/migration/sqlite/1781992375456-AddRequestDeclinedMessage.ts
✅ Files skipped from review due to trivial changes (2)
  • server/migration/postgres/1781992427522-AddRequestDeclinedMessage.ts
  • server/entity/MediaRequest.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • server/lib/notifications/agents/ntfy.ts

@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: 1

🤖 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 `@src/components/RequestButton/index.tsx`:
- Around line 401-414: The close/reset logic in RequestButton’s
DeclineRequestModal flow is being triggered even when some decline requests
fail, so the modal can disappear on partial failure. Update the completion
handling around onComplete so it only calls onUpdate,
mutate('/api/v1/request/count'), setShowDeclineCommentModal(false), and
setDeclineTargets([]) when every request in declineTargets succeeds; otherwise
keep the modal open and surface an error state for retry.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d937d037-a986-44fe-97fb-3fd70b292788

📥 Commits

Reviewing files that changed from the base of the PR and between 3c0dbfb and adc1d0e.

📒 Files selected for processing (1)
  • src/components/RequestButton/index.tsx

Comment thread src/components/RequestButton/index.tsx
@github-actions github-actions Bot added the merge conflict Cannot merge due to merge conflicts label Jul 3, 2026
@github-actions

github-actions Bot commented Jul 3, 2026

Copy link
Copy Markdown

This pull request has merge conflicts. Please resolve the conflicts so the PR can be successfully reviewed and merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge conflict Cannot merge due to merge conflicts pending author's response

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature Request] Decline Request with Comment

6 participants