feat: add delete reference functionality with confirmation modal - #908

Merged
coodos merged 3 commits into
mainfrom
feat/allow-ereference-deletion
Mar 10, 2026
Merged

feat: add delete reference functionality with confirmation modal#908
coodos merged 3 commits into
mainfrom
feat/allow-ereference-deletion

Conversation

@Bekiboo

@BekibooBekiboo commented Mar 10, 2026

Copy link
Copy Markdown
Collaborator

Description of change

API

  • ReferenceService (api/src/services/ReferenceService.ts): Added deleteReference() — verifies author ownership, deletes related signatures, then removes the reference.
  • ReferenceController (api/src/controllers/ReferenceController.ts): Added deleteReference handler with 404 for not found/unauthorized.
  • Routes (api/src/index.ts): Registered DELETE /api/references/:referenceId with auth guard.

Client

  • Dashboard (client/src/pages/dashboard.tsx): Added delete button in activity dropdown (visible for "Reference Provided" entries), confirmation modal, and delete mutation via apiClient. Strips ref-sent- prefix from activity IDs to get the actual reference UUID.

Issue Number

Closes#874

Type of change

  • New (a change which implements a new feature)

How the change has been tested

Change checklist

  • I have ensured that the CI Checks pass locally
  • I have removed any unnecessary logic
  • My code is well documented
  • I have signed my commits
  • My code follows the pattern of the application
  • I have self reviewed my code

Summary by CodeRabbit

  • New Features

    • Users can delete references from the dashboard via a confirmation dialog.
    • Delete option added to activity actions in desktop and mobile views.
    • Success and error notifications shown for deletion attempts.
  • Bug Fixes / UX

    • Unauthorized deletion attempts redirect to login with an explanatory message.
    • Delete button is disabled while the operation is in progress.

@BekibooBekiboo self-assigned this Mar 10, 2026
@Bekiboo
Bekiboo requested a review from coodos as a code ownerMarch 10, 2026 07:09
@coderabbitai

coderabbitaiBot commented Mar 10, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Adds a delete eReference feature: protected DELETE API route and controller, a service method that validates ownership and cascades deletion of related signatures, and a frontend dashboard flow with confirmation modal, mutation, and error handling.

Changes

Cohort / File(s)Summary
Backend Controller & Route
platforms/ereputation/api/src/controllers/ReferenceController.ts, platforms/ereputation/api/src/index.ts
Adds deleteReference controller method and registers DELETE /api/references/:referenceId protected route; returns 404 when not found/unauthorized and 500 on exceptions.
Backend Service
platforms/ereputation/api/src/services/ReferenceService.ts
Adds deleteReference(referenceId, authorId): Promise<boolean> which verifies ownership, deletes related ReferenceSignature records in a transaction, then deletes the reference and returns success flag.
Frontend Dashboard
platforms/ereputation/client/client/src/pages/dashboard.tsx
Introduces React Query deleteMutation, confirmation modal, UI actions for Delete in activity menus, success cache invalidation and toast, and error handling including redirect on unauthorized.

Sequence Diagram(s)

sequenceDiagram
actor User
participant Frontend as Client (Dashboard)
participant API as Backend API
participant Service as ReferenceService
participant DB as Database
User->>Frontend: Click Delete on Reference
Frontend->>Frontend: Open confirmation modal
User->>Frontend: Confirm delete
Frontend->>API: DELETE /api/references/:referenceId (auth)
API->>Service: deleteReference(referenceId, userId)
Service->>DB: Find reference by id & author
alt found & authorized
Service->>DB: Delete ReferenceSignature records
Service->>DB: Delete Reference record
DB-->>Service: success
Service-->>API: return true
API-->>Frontend: 200 OK
Frontend->>Frontend: invalidate queries, show success toast
else not found or not owner
DB-->>Service: not found
Service-->>API: return false
API-->>Frontend: 404 Not Found
Frontend->>Frontend: show error toast
end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • sosweetham
  • xPathin

Poem

🐰 I hopped to the dashboard, quick and spry,

A delete button glinting in my eye.
Signatures cleared with a soft little thunk,
Modal confirmed — then poof! — into the trunk.
Farewell, tiny reference — a tidy goodbye.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring 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 nameStatusExplanation
Title check✅ PassedThe title clearly and accurately summarizes the main feature: adding delete reference functionality with a confirmation modal.
Description check✅ PassedThe description covers all required template sections with comprehensive details about API and client changes, issue reference, type of change, and completed checklist items.
Linked Issues check✅ PassedThe PR successfully implements the acceptance criteria from issue #874 by enabling deletion of eReferences through service, controller, and client-side changes.
Out of Scope Changes check✅ PassedAll changes are directly related to implementing the delete reference feature specified in issue #874, with no unrelated modifications detected.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/allow-ereference-deletion

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


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.

@coderabbitaicoderabbitaiBot 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: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@platforms/ereputation/api/src/services/ReferenceService.ts`:
- Around line 98-112: The deleteReference method currently deletes signatures
then removes the reference separately, risking partial deletes; wrap both
operations in a single DB transaction using AppDataSource.transaction (or a
QueryRunner) so they succeed or roll back together: inside the transaction use
the transactional EntityManager (from AppDataSource.manager.transaction or
queryRunner.manager) to delete ReferenceSignature entries (signatureRepository
via manager.delete) and then remove the Reference entity via manager.remove (or
manager.delete by id) instead of calling AppDataSource.getRepository(...) and
this.referenceRepository.remove outside the transaction; ensure you throw/return
appropriately so failures cause the transaction to rollback.
In `@platforms/ereputation/client/client/src/pages/dashboard.tsx`:
- Around line 85-92: The confirmation dialog is being closed immediately when
the delete is triggered, which prevents the mutation's pending/error UI from
rendering; remove the immediate dialog-close call that runs when the mutation is
invoked (e.g., any closeDialog() or setIsConfirmOpen(false) in the delete
handler) and instead call that same close function inside the mutation onSuccess
block (where queryClient.invalidateQueries and toast are used), leaving the
dialog open on pending and onError so the retry UI (the pending state rendered
around the confirmation dialog) remains visible.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d47f2177-e1c0-4bc7-8d1e-c96d8483ff0d

📥 Commits

Reviewing files that changed from the base of the PR and between 1286539 and b0f96d8.

📒 Files selected for processing (4)
  • platforms/ereputation/api/src/controllers/ReferenceController.ts
  • platforms/ereputation/api/src/index.ts
  • platforms/ereputation/api/src/services/ReferenceService.ts
  • platforms/ereputation/client/client/src/pages/dashboard.tsx

Comment threadplatforms/ereputation/api/src/services/ReferenceService.ts
Comment threadplatforms/ereputation/client/client/src/pages/dashboard.tsx

@coderabbitaicoderabbitaiBot 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)
platforms/ereputation/client/client/src/pages/dashboard.tsx (1)

989-1016: ⚠️ Potential issue | 🟡 Minor

Prevent closing the confirmation modal while the delete is in flight.

onOpenChange and the Cancel button can still dismiss the dialog during deleteMutation.isPending, so the pending/error state disappears again before the request finishes.

Suggested fix
-<Dialog open={!!deleteModalOpen} onOpenChange={(open) => !open && setDeleteModalOpen(null)}>+<Dialog+ open={!!deleteModalOpen}+ onOpenChange={(open) => {+ if (!open && !deleteMutation.isPending) {+ setDeleteModalOpen(null);+ }+ }}+>
@@
- <Button- variant="outline"- onClick={() => setDeleteModalOpen(null)}+ <Button+ variant="outline"+ onClick={() => !deleteMutation.isPending && setDeleteModalOpen(null)}+ disabled={deleteMutation.isPending}
className="flex-1 border-2 border-fig/30 text-fig/70 hover:bg-fig-10 hover:border-fig/40 font-bold h-11"
>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@platforms/ereputation/client/client/src/pages/dashboard.tsx` around lines 989
- 1016, The confirmation dialog can be dismissed while a delete is in progress;
prevent that by blocking both the Dialog's onOpenChange handler and the Cancel
button when deleteMutation.isPending. Update the onOpenChange callback used on
the Dialog so it only calls setDeleteModalOpen(null) when open is false AND
deleteMutation.isPending is false, and set the Cancel <Button> to
disabled={deleteMutation.isPending} (and no-op its onClick when disabled) so
users cannot close the modal while confirmDeleteActivity is in flight.
platforms/ereputation/api/src/services/ReferenceService.ts (1)

98-109: ⚠️ Potential issue | 🔴 Critical

Move the ownership lookup into the transaction.

Lines 99-105 still run outside the transactional delete, so this path keeps a TOCTOU window: a concurrent update/delete can invalidate the ownership check, and Line 109 will then remove a stale entity without re-checking authorId.

Suggested fix
 async deleteReference(referenceId: string, authorId: string): Promise<boolean> {
- const reference = await this.referenceRepository.findOne({- where: { id: referenceId, authorId }- });-- if (!reference) {- return false;- }-- await AppDataSource.manager.transaction(async (manager) => {- await manager.delete("ReferenceSignature", { referenceId });- await manager.remove(reference);- });-- return true;+ return AppDataSource.manager.transaction(async (manager) => {+ const reference = await manager.findOne(Reference, {+ where: { id: referenceId, authorId },+ });++ if (!reference) {+ return false;+ }++ await manager.delete("ReferenceSignature", { referenceId });+ await manager.delete(Reference, { id: referenceId, authorId });+ return true;+ });
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@platforms/ereputation/api/src/services/ReferenceService.ts` around lines 98 -
109, Move the ownership lookup into the same transaction used for deletion:
inside deleteReference, instead of calling this.referenceRepository.findOne(...)
before AppDataSource.manager.transaction(...), perform the find/select for the
Reference by id with authorId within the transaction callback (use
manager.findOne or manager.getRepository('Reference').findOne), and if not found
return false; only then call manager.delete("ReferenceSignature", { referenceId
}) and manager.remove(reference) so the existence/ownership check and removals
occur atomically within the same transaction.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@platforms/ereputation/api/src/services/ReferenceService.ts`:
- Around line 98-109: Move the ownership lookup into the same transaction used
for deletion: inside deleteReference, instead of calling
this.referenceRepository.findOne(...) before
AppDataSource.manager.transaction(...), perform the find/select for the
Reference by id with authorId within the transaction callback (use
manager.findOne or manager.getRepository('Reference').findOne), and if not found
return false; only then call manager.delete("ReferenceSignature", { referenceId
}) and manager.remove(reference) so the existence/ownership check and removals
occur atomically within the same transaction.
In `@platforms/ereputation/client/client/src/pages/dashboard.tsx`:
- Around line 989-1016: The confirmation dialog can be dismissed while a delete
is in progress; prevent that by blocking both the Dialog's onOpenChange handler
and the Cancel button when deleteMutation.isPending. Update the onOpenChange
callback used on the Dialog so it only calls setDeleteModalOpen(null) when open
is false AND deleteMutation.isPending is false, and set the Cancel <Button> to
disabled={deleteMutation.isPending} (and no-op its onClick when disabled) so
users cannot close the modal while confirmDeleteActivity is in flight.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4d58b7d9-ad1a-4e91-8371-a1465c227a33

📥 Commits

Reviewing files that changed from the base of the PR and between b0f96d8 and e6710a4.

📒 Files selected for processing (2)
  • platforms/ereputation/api/src/services/ReferenceService.ts
  • platforms/ereputation/client/client/src/pages/dashboard.tsx

@coodos
coodos merged commit bddfe7a into mainMar 10, 2026
4 checks passed
@coodos
coodos deleted the feat/allow-ereference-deletion branch March 10, 2026 14:43
Sign up for freeto 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] (eReputation): Delete eReference

2 participants

@Bekiboo@coodos
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

feat: add delete reference functionality with confirmation modal - #908

Merged
coodos merged 3 commits into
mainfrom
feat/allow-ereference-deletion
Mar 10, 2026
Merged

feat: add delete reference functionality with confirmation modal#908
coodos merged 3 commits into
mainfrom
feat/allow-ereference-deletion

Conversation

@Bekiboo

@BekibooBekiboo commented Mar 10, 2026

Copy link
Copy Markdown
Collaborator

Description of change

API

  • ReferenceService (api/src/services/ReferenceService.ts): Added deleteReference() — verifies author ownership, deletes related signatures, then removes the reference.
  • ReferenceController (api/src/controllers/ReferenceController.ts): Added deleteReference handler with 404 for not found/unauthorized.
  • Routes (api/src/index.ts): Registered DELETE /api/references/:referenceId with auth guard.

Client

  • Dashboard (client/src/pages/dashboard.tsx): Added delete button in activity dropdown (visible for "Reference Provided" entries), confirmation modal, and delete mutation via apiClient. Strips ref-sent- prefix from activity IDs to get the actual reference UUID.

Issue Number

Closes#874

Type of change

  • New (a change which implements a new feature)

How the change has been tested

Change checklist

  • I have ensured that the CI Checks pass locally
  • I have removed any unnecessary logic
  • My code is well documented
  • I have signed my commits
  • My code follows the pattern of the application
  • I have self reviewed my code

Summary by CodeRabbit

  • New Features

    • Users can delete references from the dashboard via a confirmation dialog.
    • Delete option added to activity actions in desktop and mobile views.
    • Success and error notifications shown for deletion attempts.
  • Bug Fixes / UX

    • Unauthorized deletion attempts redirect to login with an explanatory message.
    • Delete button is disabled while the operation is in progress.

@BekibooBekiboo self-assigned this Mar 10, 2026
@Bekiboo
Bekiboo requested a review from coodos as a code ownerMarch 10, 2026 07:09
@coderabbitai

coderabbitaiBot commented Mar 10, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Adds a delete eReference feature: protected DELETE API route and controller, a service method that validates ownership and cascades deletion of related signatures, and a frontend dashboard flow with confirmation modal, mutation, and error handling.

Changes

Cohort / File(s)Summary
Backend Controller & Route
platforms/ereputation/api/src/controllers/ReferenceController.ts, platforms/ereputation/api/src/index.ts
Adds deleteReference controller method and registers DELETE /api/references/:referenceId protected route; returns 404 when not found/unauthorized and 500 on exceptions.
Backend Service
platforms/ereputation/api/src/services/ReferenceService.ts
Adds deleteReference(referenceId, authorId): Promise<boolean> which verifies ownership, deletes related ReferenceSignature records in a transaction, then deletes the reference and returns success flag.
Frontend Dashboard
platforms/ereputation/client/client/src/pages/dashboard.tsx
Introduces React Query deleteMutation, confirmation modal, UI actions for Delete in activity menus, success cache invalidation and toast, and error handling including redirect on unauthorized.

Sequence Diagram(s)

sequenceDiagram
actor User
participant Frontend as Client (Dashboard)
participant API as Backend API
participant Service as ReferenceService
participant DB as Database
User->>Frontend: Click Delete on Reference
Frontend->>Frontend: Open confirmation modal
User->>Frontend: Confirm delete
Frontend->>API: DELETE /api/references/:referenceId (auth)
API->>Service: deleteReference(referenceId, userId)
Service->>DB: Find reference by id & author
alt found & authorized
Service->>DB: Delete ReferenceSignature records
Service->>DB: Delete Reference record
DB-->>Service: success
Service-->>API: return true
API-->>Frontend: 200 OK
Frontend->>Frontend: invalidate queries, show success toast
else not found or not owner
DB-->>Service: not found
Service-->>API: return false
API-->>Frontend: 404 Not Found
Frontend->>Frontend: show error toast
end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • sosweetham
  • xPathin

Poem

🐰 I hopped to the dashboard, quick and spry,

A delete button glinting in my eye.
Signatures cleared with a soft little thunk,
Modal confirmed — then poof! — into the trunk.
Farewell, tiny reference — a tidy goodbye.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring 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 nameStatusExplanation
Title check✅ PassedThe title clearly and accurately summarizes the main feature: adding delete reference functionality with a confirmation modal.
Description check✅ PassedThe description covers all required template sections with comprehensive details about API and client changes, issue reference, type of change, and completed checklist items.
Linked Issues check✅ PassedThe PR successfully implements the acceptance criteria from issue #874 by enabling deletion of eReferences through service, controller, and client-side changes.
Out of Scope Changes check✅ PassedAll changes are directly related to implementing the delete reference feature specified in issue #874, with no unrelated modifications detected.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/allow-ereference-deletion

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


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.

@coderabbitaicoderabbitaiBot 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: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@platforms/ereputation/api/src/services/ReferenceService.ts`:
- Around line 98-112: The deleteReference method currently deletes signatures
then removes the reference separately, risking partial deletes; wrap both
operations in a single DB transaction using AppDataSource.transaction (or a
QueryRunner) so they succeed or roll back together: inside the transaction use
the transactional EntityManager (from AppDataSource.manager.transaction or
queryRunner.manager) to delete ReferenceSignature entries (signatureRepository
via manager.delete) and then remove the Reference entity via manager.remove (or
manager.delete by id) instead of calling AppDataSource.getRepository(...) and
this.referenceRepository.remove outside the transaction; ensure you throw/return
appropriately so failures cause the transaction to rollback.
In `@platforms/ereputation/client/client/src/pages/dashboard.tsx`:
- Around line 85-92: The confirmation dialog is being closed immediately when
the delete is triggered, which prevents the mutation's pending/error UI from
rendering; remove the immediate dialog-close call that runs when the mutation is
invoked (e.g., any closeDialog() or setIsConfirmOpen(false) in the delete
handler) and instead call that same close function inside the mutation onSuccess
block (where queryClient.invalidateQueries and toast are used), leaving the
dialog open on pending and onError so the retry UI (the pending state rendered
around the confirmation dialog) remains visible.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d47f2177-e1c0-4bc7-8d1e-c96d8483ff0d

📥 Commits

Reviewing files that changed from the base of the PR and between 1286539 and b0f96d8.

📒 Files selected for processing (4)
  • platforms/ereputation/api/src/controllers/ReferenceController.ts
  • platforms/ereputation/api/src/index.ts
  • platforms/ereputation/api/src/services/ReferenceService.ts
  • platforms/ereputation/client/client/src/pages/dashboard.tsx

Comment threadplatforms/ereputation/api/src/services/ReferenceService.ts
Comment threadplatforms/ereputation/client/client/src/pages/dashboard.tsx

@coderabbitaicoderabbitaiBot 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)
platforms/ereputation/client/client/src/pages/dashboard.tsx (1)

989-1016: ⚠️ Potential issue | 🟡 Minor

Prevent closing the confirmation modal while the delete is in flight.

onOpenChange and the Cancel button can still dismiss the dialog during deleteMutation.isPending, so the pending/error state disappears again before the request finishes.

Suggested fix
-<Dialog open={!!deleteModalOpen} onOpenChange={(open) => !open && setDeleteModalOpen(null)}>+<Dialog+ open={!!deleteModalOpen}+ onOpenChange={(open) => {+ if (!open && !deleteMutation.isPending) {+ setDeleteModalOpen(null);+ }+ }}+>
@@
- <Button- variant="outline"- onClick={() => setDeleteModalOpen(null)}+ <Button+ variant="outline"+ onClick={() => !deleteMutation.isPending && setDeleteModalOpen(null)}+ disabled={deleteMutation.isPending}
className="flex-1 border-2 border-fig/30 text-fig/70 hover:bg-fig-10 hover:border-fig/40 font-bold h-11"
>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@platforms/ereputation/client/client/src/pages/dashboard.tsx` around lines 989
- 1016, The confirmation dialog can be dismissed while a delete is in progress;
prevent that by blocking both the Dialog's onOpenChange handler and the Cancel
button when deleteMutation.isPending. Update the onOpenChange callback used on
the Dialog so it only calls setDeleteModalOpen(null) when open is false AND
deleteMutation.isPending is false, and set the Cancel <Button> to
disabled={deleteMutation.isPending} (and no-op its onClick when disabled) so
users cannot close the modal while confirmDeleteActivity is in flight.
platforms/ereputation/api/src/services/ReferenceService.ts (1)

98-109: ⚠️ Potential issue | 🔴 Critical

Move the ownership lookup into the transaction.

Lines 99-105 still run outside the transactional delete, so this path keeps a TOCTOU window: a concurrent update/delete can invalidate the ownership check, and Line 109 will then remove a stale entity without re-checking authorId.

Suggested fix
 async deleteReference(referenceId: string, authorId: string): Promise<boolean> {
- const reference = await this.referenceRepository.findOne({- where: { id: referenceId, authorId }- });-- if (!reference) {- return false;- }-- await AppDataSource.manager.transaction(async (manager) => {- await manager.delete("ReferenceSignature", { referenceId });- await manager.remove(reference);- });-- return true;+ return AppDataSource.manager.transaction(async (manager) => {+ const reference = await manager.findOne(Reference, {+ where: { id: referenceId, authorId },+ });++ if (!reference) {+ return false;+ }++ await manager.delete("ReferenceSignature", { referenceId });+ await manager.delete(Reference, { id: referenceId, authorId });+ return true;+ });
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@platforms/ereputation/api/src/services/ReferenceService.ts` around lines 98 -
109, Move the ownership lookup into the same transaction used for deletion:
inside deleteReference, instead of calling this.referenceRepository.findOne(...)
before AppDataSource.manager.transaction(...), perform the find/select for the
Reference by id with authorId within the transaction callback (use
manager.findOne or manager.getRepository('Reference').findOne), and if not found
return false; only then call manager.delete("ReferenceSignature", { referenceId
}) and manager.remove(reference) so the existence/ownership check and removals
occur atomically within the same transaction.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@platforms/ereputation/api/src/services/ReferenceService.ts`:
- Around line 98-109: Move the ownership lookup into the same transaction used
for deletion: inside deleteReference, instead of calling
this.referenceRepository.findOne(...) before
AppDataSource.manager.transaction(...), perform the find/select for the
Reference by id with authorId within the transaction callback (use
manager.findOne or manager.getRepository('Reference').findOne), and if not found
return false; only then call manager.delete("ReferenceSignature", { referenceId
}) and manager.remove(reference) so the existence/ownership check and removals
occur atomically within the same transaction.
In `@platforms/ereputation/client/client/src/pages/dashboard.tsx`:
- Around line 989-1016: The confirmation dialog can be dismissed while a delete
is in progress; prevent that by blocking both the Dialog's onOpenChange handler
and the Cancel button when deleteMutation.isPending. Update the onOpenChange
callback used on the Dialog so it only calls setDeleteModalOpen(null) when open
is false AND deleteMutation.isPending is false, and set the Cancel <Button> to
disabled={deleteMutation.isPending} (and no-op its onClick when disabled) so
users cannot close the modal while confirmDeleteActivity is in flight.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4d58b7d9-ad1a-4e91-8371-a1465c227a33

📥 Commits

Reviewing files that changed from the base of the PR and between b0f96d8 and e6710a4.

📒 Files selected for processing (2)
  • platforms/ereputation/api/src/services/ReferenceService.ts
  • platforms/ereputation/client/client/src/pages/dashboard.tsx

@coodos
coodos merged commit bddfe7a into mainMar 10, 2026
4 checks passed
@coodos
coodos deleted the feat/allow-ereference-deletion branch March 10, 2026 14:43
Sign up for freeto 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] (eReputation): Delete eReference

2 participants

@Bekiboo@coodos
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: add delete reference functionality with confirmation modal - #908

Merged
coodos merged 3 commits into
mainfrom
feat/allow-ereference-deletion
Mar 10, 2026
Merged

feat: add delete reference functionality with confirmation modal#908
coodos merged 3 commits into
mainfrom
feat/allow-ereference-deletion

Conversation

@Bekiboo

@BekibooBekiboo commented Mar 10, 2026

Copy link
Copy Markdown
Collaborator

Description of change

API

  • ReferenceService (api/src/services/ReferenceService.ts): Added deleteReference() — verifies author ownership, deletes related signatures, then removes the reference.
  • ReferenceController (api/src/controllers/ReferenceController.ts): Added deleteReference handler with 404 for not found/unauthorized.
  • Routes (api/src/index.ts): Registered DELETE /api/references/:referenceId with auth guard.

Client

  • Dashboard (client/src/pages/dashboard.tsx): Added delete button in activity dropdown (visible for "Reference Provided" entries), confirmation modal, and delete mutation via apiClient. Strips ref-sent- prefix from activity IDs to get the actual reference UUID.

Issue Number

Closes#874

Type of change

  • New (a change which implements a new feature)

How the change has been tested

Change checklist

  • I have ensured that the CI Checks pass locally
  • I have removed any unnecessary logic
  • My code is well documented
  • I have signed my commits
  • My code follows the pattern of the application
  • I have self reviewed my code

Summary by CodeRabbit

  • New Features

    • Users can delete references from the dashboard via a confirmation dialog.
    • Delete option added to activity actions in desktop and mobile views.
    • Success and error notifications shown for deletion attempts.
  • Bug Fixes / UX

    • Unauthorized deletion attempts redirect to login with an explanatory message.
    • Delete button is disabled while the operation is in progress.

@BekibooBekiboo self-assigned this Mar 10, 2026
@Bekiboo
Bekiboo requested a review from coodos as a code ownerMarch 10, 2026 07:09
@coderabbitai

coderabbitaiBot commented Mar 10, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Adds a delete eReference feature: protected DELETE API route and controller, a service method that validates ownership and cascades deletion of related signatures, and a frontend dashboard flow with confirmation modal, mutation, and error handling.

Changes

Cohort / File(s)Summary
Backend Controller & Route
platforms/ereputation/api/src/controllers/ReferenceController.ts, platforms/ereputation/api/src/index.ts
Adds deleteReference controller method and registers DELETE /api/references/:referenceId protected route; returns 404 when not found/unauthorized and 500 on exceptions.
Backend Service
platforms/ereputation/api/src/services/ReferenceService.ts
Adds deleteReference(referenceId, authorId): Promise<boolean> which verifies ownership, deletes related ReferenceSignature records in a transaction, then deletes the reference and returns success flag.
Frontend Dashboard
platforms/ereputation/client/client/src/pages/dashboard.tsx
Introduces React Query deleteMutation, confirmation modal, UI actions for Delete in activity menus, success cache invalidation and toast, and error handling including redirect on unauthorized.

Sequence Diagram(s)

sequenceDiagram
actor User
participant Frontend as Client (Dashboard)
participant API as Backend API
participant Service as ReferenceService
participant DB as Database
User->>Frontend: Click Delete on Reference
Frontend->>Frontend: Open confirmation modal
User->>Frontend: Confirm delete
Frontend->>API: DELETE /api/references/:referenceId (auth)
API->>Service: deleteReference(referenceId, userId)
Service->>DB: Find reference by id & author
alt found & authorized
Service->>DB: Delete ReferenceSignature records
Service->>DB: Delete Reference record
DB-->>Service: success
Service-->>API: return true
API-->>Frontend: 200 OK
Frontend->>Frontend: invalidate queries, show success toast
else not found or not owner
DB-->>Service: not found
Service-->>API: return false
API-->>Frontend: 404 Not Found
Frontend->>Frontend: show error toast
end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • sosweetham
  • xPathin

Poem

🐰 I hopped to the dashboard, quick and spry,

A delete button glinting in my eye.
Signatures cleared with a soft little thunk,
Modal confirmed — then poof! — into the trunk.
Farewell, tiny reference — a tidy goodbye.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring 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 nameStatusExplanation
Title check✅ PassedThe title clearly and accurately summarizes the main feature: adding delete reference functionality with a confirmation modal.
Description check✅ PassedThe description covers all required template sections with comprehensive details about API and client changes, issue reference, type of change, and completed checklist items.
Linked Issues check✅ PassedThe PR successfully implements the acceptance criteria from issue #874 by enabling deletion of eReferences through service, controller, and client-side changes.
Out of Scope Changes check✅ PassedAll changes are directly related to implementing the delete reference feature specified in issue #874, with no unrelated modifications detected.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/allow-ereference-deletion

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


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.

@coderabbitaicoderabbitaiBot 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: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@platforms/ereputation/api/src/services/ReferenceService.ts`:
- Around line 98-112: The deleteReference method currently deletes signatures
then removes the reference separately, risking partial deletes; wrap both
operations in a single DB transaction using AppDataSource.transaction (or a
QueryRunner) so they succeed or roll back together: inside the transaction use
the transactional EntityManager (from AppDataSource.manager.transaction or
queryRunner.manager) to delete ReferenceSignature entries (signatureRepository
via manager.delete) and then remove the Reference entity via manager.remove (or
manager.delete by id) instead of calling AppDataSource.getRepository(...) and
this.referenceRepository.remove outside the transaction; ensure you throw/return
appropriately so failures cause the transaction to rollback.
In `@platforms/ereputation/client/client/src/pages/dashboard.tsx`:
- Around line 85-92: The confirmation dialog is being closed immediately when
the delete is triggered, which prevents the mutation's pending/error UI from
rendering; remove the immediate dialog-close call that runs when the mutation is
invoked (e.g., any closeDialog() or setIsConfirmOpen(false) in the delete
handler) and instead call that same close function inside the mutation onSuccess
block (where queryClient.invalidateQueries and toast are used), leaving the
dialog open on pending and onError so the retry UI (the pending state rendered
around the confirmation dialog) remains visible.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d47f2177-e1c0-4bc7-8d1e-c96d8483ff0d

📥 Commits

Reviewing files that changed from the base of the PR and between 1286539 and b0f96d8.

📒 Files selected for processing (4)
  • platforms/ereputation/api/src/controllers/ReferenceController.ts
  • platforms/ereputation/api/src/index.ts
  • platforms/ereputation/api/src/services/ReferenceService.ts
  • platforms/ereputation/client/client/src/pages/dashboard.tsx

Comment threadplatforms/ereputation/api/src/services/ReferenceService.ts
Comment threadplatforms/ereputation/client/client/src/pages/dashboard.tsx

@coderabbitaicoderabbitaiBot 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)
platforms/ereputation/client/client/src/pages/dashboard.tsx (1)

989-1016: ⚠️ Potential issue | 🟡 Minor

Prevent closing the confirmation modal while the delete is in flight.

onOpenChange and the Cancel button can still dismiss the dialog during deleteMutation.isPending, so the pending/error state disappears again before the request finishes.

Suggested fix
-<Dialog open={!!deleteModalOpen} onOpenChange={(open) => !open && setDeleteModalOpen(null)}>+<Dialog+ open={!!deleteModalOpen}+ onOpenChange={(open) => {+ if (!open && !deleteMutation.isPending) {+ setDeleteModalOpen(null);+ }+ }}+>
@@
- <Button- variant="outline"- onClick={() => setDeleteModalOpen(null)}+ <Button+ variant="outline"+ onClick={() => !deleteMutation.isPending && setDeleteModalOpen(null)}+ disabled={deleteMutation.isPending}
className="flex-1 border-2 border-fig/30 text-fig/70 hover:bg-fig-10 hover:border-fig/40 font-bold h-11"
>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@platforms/ereputation/client/client/src/pages/dashboard.tsx` around lines 989
- 1016, The confirmation dialog can be dismissed while a delete is in progress;
prevent that by blocking both the Dialog's onOpenChange handler and the Cancel
button when deleteMutation.isPending. Update the onOpenChange callback used on
the Dialog so it only calls setDeleteModalOpen(null) when open is false AND
deleteMutation.isPending is false, and set the Cancel <Button> to
disabled={deleteMutation.isPending} (and no-op its onClick when disabled) so
users cannot close the modal while confirmDeleteActivity is in flight.
platforms/ereputation/api/src/services/ReferenceService.ts (1)

98-109: ⚠️ Potential issue | 🔴 Critical

Move the ownership lookup into the transaction.

Lines 99-105 still run outside the transactional delete, so this path keeps a TOCTOU window: a concurrent update/delete can invalidate the ownership check, and Line 109 will then remove a stale entity without re-checking authorId.

Suggested fix
 async deleteReference(referenceId: string, authorId: string): Promise<boolean> {
- const reference = await this.referenceRepository.findOne({- where: { id: referenceId, authorId }- });-- if (!reference) {- return false;- }-- await AppDataSource.manager.transaction(async (manager) => {- await manager.delete("ReferenceSignature", { referenceId });- await manager.remove(reference);- });-- return true;+ return AppDataSource.manager.transaction(async (manager) => {+ const reference = await manager.findOne(Reference, {+ where: { id: referenceId, authorId },+ });++ if (!reference) {+ return false;+ }++ await manager.delete("ReferenceSignature", { referenceId });+ await manager.delete(Reference, { id: referenceId, authorId });+ return true;+ });
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@platforms/ereputation/api/src/services/ReferenceService.ts` around lines 98 -
109, Move the ownership lookup into the same transaction used for deletion:
inside deleteReference, instead of calling this.referenceRepository.findOne(...)
before AppDataSource.manager.transaction(...), perform the find/select for the
Reference by id with authorId within the transaction callback (use
manager.findOne or manager.getRepository('Reference').findOne), and if not found
return false; only then call manager.delete("ReferenceSignature", { referenceId
}) and manager.remove(reference) so the existence/ownership check and removals
occur atomically within the same transaction.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@platforms/ereputation/api/src/services/ReferenceService.ts`:
- Around line 98-109: Move the ownership lookup into the same transaction used
for deletion: inside deleteReference, instead of calling
this.referenceRepository.findOne(...) before
AppDataSource.manager.transaction(...), perform the find/select for the
Reference by id with authorId within the transaction callback (use
manager.findOne or manager.getRepository('Reference').findOne), and if not found
return false; only then call manager.delete("ReferenceSignature", { referenceId
}) and manager.remove(reference) so the existence/ownership check and removals
occur atomically within the same transaction.
In `@platforms/ereputation/client/client/src/pages/dashboard.tsx`:
- Around line 989-1016: The confirmation dialog can be dismissed while a delete
is in progress; prevent that by blocking both the Dialog's onOpenChange handler
and the Cancel button when deleteMutation.isPending. Update the onOpenChange
callback used on the Dialog so it only calls setDeleteModalOpen(null) when open
is false AND deleteMutation.isPending is false, and set the Cancel <Button> to
disabled={deleteMutation.isPending} (and no-op its onClick when disabled) so
users cannot close the modal while confirmDeleteActivity is in flight.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4d58b7d9-ad1a-4e91-8371-a1465c227a33

📥 Commits

Reviewing files that changed from the base of the PR and between b0f96d8 and e6710a4.

📒 Files selected for processing (2)
  • platforms/ereputation/api/src/services/ReferenceService.ts
  • platforms/ereputation/client/client/src/pages/dashboard.tsx

@coodos
coodos merged commit bddfe7a into mainMar 10, 2026
4 checks passed
@coodos
coodos deleted the feat/allow-ereference-deletion branch March 10, 2026 14:43
Sign up for freeto 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] (eReputation): Delete eReference

2 participants

@Bekiboo@coodos
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: add delete reference functionality with confirmation modal - #908

Merged
coodos merged 3 commits into
mainfrom
feat/allow-ereference-deletion
Mar 10, 2026
Merged

feat: add delete reference functionality with confirmation modal#908
coodos merged 3 commits into
mainfrom
feat/allow-ereference-deletion

Conversation

@Bekiboo

@BekibooBekiboo commented Mar 10, 2026

Copy link
Copy Markdown
Collaborator

Description of change

API

  • ReferenceService (api/src/services/ReferenceService.ts): Added deleteReference() — verifies author ownership, deletes related signatures, then removes the reference.
  • ReferenceController (api/src/controllers/ReferenceController.ts): Added deleteReference handler with 404 for not found/unauthorized.
  • Routes (api/src/index.ts): Registered DELETE /api/references/:referenceId with auth guard.

Client

  • Dashboard (client/src/pages/dashboard.tsx): Added delete button in activity dropdown (visible for "Reference Provided" entries), confirmation modal, and delete mutation via apiClient. Strips ref-sent- prefix from activity IDs to get the actual reference UUID.

Issue Number

Closes#874

Type of change

  • New (a change which implements a new feature)

How the change has been tested

Change checklist

  • I have ensured that the CI Checks pass locally
  • I have removed any unnecessary logic
  • My code is well documented
  • I have signed my commits
  • My code follows the pattern of the application
  • I have self reviewed my code

Summary by CodeRabbit

  • New Features

    • Users can delete references from the dashboard via a confirmation dialog.
    • Delete option added to activity actions in desktop and mobile views.
    • Success and error notifications shown for deletion attempts.
  • Bug Fixes / UX

    • Unauthorized deletion attempts redirect to login with an explanatory message.
    • Delete button is disabled while the operation is in progress.

@BekibooBekiboo self-assigned this Mar 10, 2026
@Bekiboo
Bekiboo requested a review from coodos as a code ownerMarch 10, 2026 07:09
@coderabbitai

coderabbitaiBot commented Mar 10, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Adds a delete eReference feature: protected DELETE API route and controller, a service method that validates ownership and cascades deletion of related signatures, and a frontend dashboard flow with confirmation modal, mutation, and error handling.

Changes

Cohort / File(s)Summary
Backend Controller & Route
platforms/ereputation/api/src/controllers/ReferenceController.ts, platforms/ereputation/api/src/index.ts
Adds deleteReference controller method and registers DELETE /api/references/:referenceId protected route; returns 404 when not found/unauthorized and 500 on exceptions.
Backend Service
platforms/ereputation/api/src/services/ReferenceService.ts
Adds deleteReference(referenceId, authorId): Promise<boolean> which verifies ownership, deletes related ReferenceSignature records in a transaction, then deletes the reference and returns success flag.
Frontend Dashboard
platforms/ereputation/client/client/src/pages/dashboard.tsx
Introduces React Query deleteMutation, confirmation modal, UI actions for Delete in activity menus, success cache invalidation and toast, and error handling including redirect on unauthorized.

Sequence Diagram(s)

sequenceDiagram
actor User
participant Frontend as Client (Dashboard)
participant API as Backend API
participant Service as ReferenceService
participant DB as Database
User->>Frontend: Click Delete on Reference
Frontend->>Frontend: Open confirmation modal
User->>Frontend: Confirm delete
Frontend->>API: DELETE /api/references/:referenceId (auth)
API->>Service: deleteReference(referenceId, userId)
Service->>DB: Find reference by id & author
alt found & authorized
Service->>DB: Delete ReferenceSignature records
Service->>DB: Delete Reference record
DB-->>Service: success
Service-->>API: return true
API-->>Frontend: 200 OK
Frontend->>Frontend: invalidate queries, show success toast
else not found or not owner
DB-->>Service: not found
Service-->>API: return false
API-->>Frontend: 404 Not Found
Frontend->>Frontend: show error toast
end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • sosweetham
  • xPathin

Poem

🐰 I hopped to the dashboard, quick and spry,

A delete button glinting in my eye.
Signatures cleared with a soft little thunk,
Modal confirmed — then poof! — into the trunk.
Farewell, tiny reference — a tidy goodbye.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring 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 nameStatusExplanation
Title check✅ PassedThe title clearly and accurately summarizes the main feature: adding delete reference functionality with a confirmation modal.
Description check✅ PassedThe description covers all required template sections with comprehensive details about API and client changes, issue reference, type of change, and completed checklist items.
Linked Issues check✅ PassedThe PR successfully implements the acceptance criteria from issue #874 by enabling deletion of eReferences through service, controller, and client-side changes.
Out of Scope Changes check✅ PassedAll changes are directly related to implementing the delete reference feature specified in issue #874, with no unrelated modifications detected.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/allow-ereference-deletion

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


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.

@coderabbitaicoderabbitaiBot 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: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@platforms/ereputation/api/src/services/ReferenceService.ts`:
- Around line 98-112: The deleteReference method currently deletes signatures
then removes the reference separately, risking partial deletes; wrap both
operations in a single DB transaction using AppDataSource.transaction (or a
QueryRunner) so they succeed or roll back together: inside the transaction use
the transactional EntityManager (from AppDataSource.manager.transaction or
queryRunner.manager) to delete ReferenceSignature entries (signatureRepository
via manager.delete) and then remove the Reference entity via manager.remove (or
manager.delete by id) instead of calling AppDataSource.getRepository(...) and
this.referenceRepository.remove outside the transaction; ensure you throw/return
appropriately so failures cause the transaction to rollback.
In `@platforms/ereputation/client/client/src/pages/dashboard.tsx`:
- Around line 85-92: The confirmation dialog is being closed immediately when
the delete is triggered, which prevents the mutation's pending/error UI from
rendering; remove the immediate dialog-close call that runs when the mutation is
invoked (e.g., any closeDialog() or setIsConfirmOpen(false) in the delete
handler) and instead call that same close function inside the mutation onSuccess
block (where queryClient.invalidateQueries and toast are used), leaving the
dialog open on pending and onError so the retry UI (the pending state rendered
around the confirmation dialog) remains visible.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d47f2177-e1c0-4bc7-8d1e-c96d8483ff0d

📥 Commits

Reviewing files that changed from the base of the PR and between 1286539 and b0f96d8.

📒 Files selected for processing (4)
  • platforms/ereputation/api/src/controllers/ReferenceController.ts
  • platforms/ereputation/api/src/index.ts
  • platforms/ereputation/api/src/services/ReferenceService.ts
  • platforms/ereputation/client/client/src/pages/dashboard.tsx

Comment threadplatforms/ereputation/api/src/services/ReferenceService.ts
Comment threadplatforms/ereputation/client/client/src/pages/dashboard.tsx

@coderabbitaicoderabbitaiBot 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)
platforms/ereputation/client/client/src/pages/dashboard.tsx (1)

989-1016: ⚠️ Potential issue | 🟡 Minor

Prevent closing the confirmation modal while the delete is in flight.

onOpenChange and the Cancel button can still dismiss the dialog during deleteMutation.isPending, so the pending/error state disappears again before the request finishes.

Suggested fix
-<Dialog open={!!deleteModalOpen} onOpenChange={(open) => !open && setDeleteModalOpen(null)}>+<Dialog+ open={!!deleteModalOpen}+ onOpenChange={(open) => {+ if (!open && !deleteMutation.isPending) {+ setDeleteModalOpen(null);+ }+ }}+>
@@
- <Button- variant="outline"- onClick={() => setDeleteModalOpen(null)}+ <Button+ variant="outline"+ onClick={() => !deleteMutation.isPending && setDeleteModalOpen(null)}+ disabled={deleteMutation.isPending}
className="flex-1 border-2 border-fig/30 text-fig/70 hover:bg-fig-10 hover:border-fig/40 font-bold h-11"
>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@platforms/ereputation/client/client/src/pages/dashboard.tsx` around lines 989
- 1016, The confirmation dialog can be dismissed while a delete is in progress;
prevent that by blocking both the Dialog's onOpenChange handler and the Cancel
button when deleteMutation.isPending. Update the onOpenChange callback used on
the Dialog so it only calls setDeleteModalOpen(null) when open is false AND
deleteMutation.isPending is false, and set the Cancel <Button> to
disabled={deleteMutation.isPending} (and no-op its onClick when disabled) so
users cannot close the modal while confirmDeleteActivity is in flight.
platforms/ereputation/api/src/services/ReferenceService.ts (1)

98-109: ⚠️ Potential issue | 🔴 Critical

Move the ownership lookup into the transaction.

Lines 99-105 still run outside the transactional delete, so this path keeps a TOCTOU window: a concurrent update/delete can invalidate the ownership check, and Line 109 will then remove a stale entity without re-checking authorId.

Suggested fix
 async deleteReference(referenceId: string, authorId: string): Promise<boolean> {
- const reference = await this.referenceRepository.findOne({- where: { id: referenceId, authorId }- });-- if (!reference) {- return false;- }-- await AppDataSource.manager.transaction(async (manager) => {- await manager.delete("ReferenceSignature", { referenceId });- await manager.remove(reference);- });-- return true;+ return AppDataSource.manager.transaction(async (manager) => {+ const reference = await manager.findOne(Reference, {+ where: { id: referenceId, authorId },+ });++ if (!reference) {+ return false;+ }++ await manager.delete("ReferenceSignature", { referenceId });+ await manager.delete(Reference, { id: referenceId, authorId });+ return true;+ });
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@platforms/ereputation/api/src/services/ReferenceService.ts` around lines 98 -
109, Move the ownership lookup into the same transaction used for deletion:
inside deleteReference, instead of calling this.referenceRepository.findOne(...)
before AppDataSource.manager.transaction(...), perform the find/select for the
Reference by id with authorId within the transaction callback (use
manager.findOne or manager.getRepository('Reference').findOne), and if not found
return false; only then call manager.delete("ReferenceSignature", { referenceId
}) and manager.remove(reference) so the existence/ownership check and removals
occur atomically within the same transaction.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@platforms/ereputation/api/src/services/ReferenceService.ts`:
- Around line 98-109: Move the ownership lookup into the same transaction used
for deletion: inside deleteReference, instead of calling
this.referenceRepository.findOne(...) before
AppDataSource.manager.transaction(...), perform the find/select for the
Reference by id with authorId within the transaction callback (use
manager.findOne or manager.getRepository('Reference').findOne), and if not found
return false; only then call manager.delete("ReferenceSignature", { referenceId
}) and manager.remove(reference) so the existence/ownership check and removals
occur atomically within the same transaction.
In `@platforms/ereputation/client/client/src/pages/dashboard.tsx`:
- Around line 989-1016: The confirmation dialog can be dismissed while a delete
is in progress; prevent that by blocking both the Dialog's onOpenChange handler
and the Cancel button when deleteMutation.isPending. Update the onOpenChange
callback used on the Dialog so it only calls setDeleteModalOpen(null) when open
is false AND deleteMutation.isPending is false, and set the Cancel <Button> to
disabled={deleteMutation.isPending} (and no-op its onClick when disabled) so
users cannot close the modal while confirmDeleteActivity is in flight.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4d58b7d9-ad1a-4e91-8371-a1465c227a33

📥 Commits

Reviewing files that changed from the base of the PR and between b0f96d8 and e6710a4.

📒 Files selected for processing (2)
  • platforms/ereputation/api/src/services/ReferenceService.ts
  • platforms/ereputation/client/client/src/pages/dashboard.tsx

@coodos
coodos merged commit bddfe7a into mainMar 10, 2026
4 checks passed
@coodos
coodos deleted the feat/allow-ereference-deletion branch March 10, 2026 14:43
Sign up for freeto 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] (eReputation): Delete eReference

2 participants

@Bekiboo@coodos
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

feat: add delete reference functionality with confirmation modal - #908

Merged
coodos merged 3 commits into
mainfrom
feat/allow-ereference-deletion
Mar 10, 2026
Merged

feat: add delete reference functionality with confirmation modal#908
coodos merged 3 commits into
mainfrom
feat/allow-ereference-deletion

Conversation

@Bekiboo

@BekibooBekiboo commented Mar 10, 2026

Copy link
Copy Markdown
Collaborator

Description of change

API

  • ReferenceService (api/src/services/ReferenceService.ts): Added deleteReference() — verifies author ownership, deletes related signatures, then removes the reference.
  • ReferenceController (api/src/controllers/ReferenceController.ts): Added deleteReference handler with 404 for not found/unauthorized.
  • Routes (api/src/index.ts): Registered DELETE /api/references/:referenceId with auth guard.

Client

  • Dashboard (client/src/pages/dashboard.tsx): Added delete button in activity dropdown (visible for "Reference Provided" entries), confirmation modal, and delete mutation via apiClient. Strips ref-sent- prefix from activity IDs to get the actual reference UUID.

Issue Number

Closes#874

Type of change

  • New (a change which implements a new feature)

How the change has been tested

Change checklist

  • I have ensured that the CI Checks pass locally
  • I have removed any unnecessary logic
  • My code is well documented
  • I have signed my commits
  • My code follows the pattern of the application
  • I have self reviewed my code

Summary by CodeRabbit

  • New Features

    • Users can delete references from the dashboard via a confirmation dialog.
    • Delete option added to activity actions in desktop and mobile views.
    • Success and error notifications shown for deletion attempts.
  • Bug Fixes / UX

    • Unauthorized deletion attempts redirect to login with an explanatory message.
    • Delete button is disabled while the operation is in progress.

@BekibooBekiboo self-assigned this Mar 10, 2026
@Bekiboo
Bekiboo requested a review from coodos as a code ownerMarch 10, 2026 07:09
@coderabbitai

coderabbitaiBot commented Mar 10, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Adds a delete eReference feature: protected DELETE API route and controller, a service method that validates ownership and cascades deletion of related signatures, and a frontend dashboard flow with confirmation modal, mutation, and error handling.

Changes

Cohort / File(s)Summary
Backend Controller & Route
platforms/ereputation/api/src/controllers/ReferenceController.ts, platforms/ereputation/api/src/index.ts
Adds deleteReference controller method and registers DELETE /api/references/:referenceId protected route; returns 404 when not found/unauthorized and 500 on exceptions.
Backend Service
platforms/ereputation/api/src/services/ReferenceService.ts
Adds deleteReference(referenceId, authorId): Promise<boolean> which verifies ownership, deletes related ReferenceSignature records in a transaction, then deletes the reference and returns success flag.
Frontend Dashboard
platforms/ereputation/client/client/src/pages/dashboard.tsx
Introduces React Query deleteMutation, confirmation modal, UI actions for Delete in activity menus, success cache invalidation and toast, and error handling including redirect on unauthorized.

Sequence Diagram(s)

sequenceDiagram
actor User
participant Frontend as Client (Dashboard)
participant API as Backend API
participant Service as ReferenceService
participant DB as Database
User->>Frontend: Click Delete on Reference
Frontend->>Frontend: Open confirmation modal
User->>Frontend: Confirm delete
Frontend->>API: DELETE /api/references/:referenceId (auth)
API->>Service: deleteReference(referenceId, userId)
Service->>DB: Find reference by id & author
alt found & authorized
Service->>DB: Delete ReferenceSignature records
Service->>DB: Delete Reference record
DB-->>Service: success
Service-->>API: return true
API-->>Frontend: 200 OK
Frontend->>Frontend: invalidate queries, show success toast
else not found or not owner
DB-->>Service: not found
Service-->>API: return false
API-->>Frontend: 404 Not Found
Frontend->>Frontend: show error toast
end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • sosweetham
  • xPathin

Poem

🐰 I hopped to the dashboard, quick and spry,

A delete button glinting in my eye.
Signatures cleared with a soft little thunk,
Modal confirmed — then poof! — into the trunk.
Farewell, tiny reference — a tidy goodbye.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring 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 nameStatusExplanation
Title check✅ PassedThe title clearly and accurately summarizes the main feature: adding delete reference functionality with a confirmation modal.
Description check✅ PassedThe description covers all required template sections with comprehensive details about API and client changes, issue reference, type of change, and completed checklist items.
Linked Issues check✅ PassedThe PR successfully implements the acceptance criteria from issue #874 by enabling deletion of eReferences through service, controller, and client-side changes.
Out of Scope Changes check✅ PassedAll changes are directly related to implementing the delete reference feature specified in issue #874, with no unrelated modifications detected.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/allow-ereference-deletion

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


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.

@coderabbitaicoderabbitaiBot 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: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@platforms/ereputation/api/src/services/ReferenceService.ts`:
- Around line 98-112: The deleteReference method currently deletes signatures
then removes the reference separately, risking partial deletes; wrap both
operations in a single DB transaction using AppDataSource.transaction (or a
QueryRunner) so they succeed or roll back together: inside the transaction use
the transactional EntityManager (from AppDataSource.manager.transaction or
queryRunner.manager) to delete ReferenceSignature entries (signatureRepository
via manager.delete) and then remove the Reference entity via manager.remove (or
manager.delete by id) instead of calling AppDataSource.getRepository(...) and
this.referenceRepository.remove outside the transaction; ensure you throw/return
appropriately so failures cause the transaction to rollback.
In `@platforms/ereputation/client/client/src/pages/dashboard.tsx`:
- Around line 85-92: The confirmation dialog is being closed immediately when
the delete is triggered, which prevents the mutation's pending/error UI from
rendering; remove the immediate dialog-close call that runs when the mutation is
invoked (e.g., any closeDialog() or setIsConfirmOpen(false) in the delete
handler) and instead call that same close function inside the mutation onSuccess
block (where queryClient.invalidateQueries and toast are used), leaving the
dialog open on pending and onError so the retry UI (the pending state rendered
around the confirmation dialog) remains visible.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d47f2177-e1c0-4bc7-8d1e-c96d8483ff0d

📥 Commits

Reviewing files that changed from the base of the PR and between 1286539 and b0f96d8.

📒 Files selected for processing (4)
  • platforms/ereputation/api/src/controllers/ReferenceController.ts
  • platforms/ereputation/api/src/index.ts
  • platforms/ereputation/api/src/services/ReferenceService.ts
  • platforms/ereputation/client/client/src/pages/dashboard.tsx

Comment threadplatforms/ereputation/api/src/services/ReferenceService.ts
Comment threadplatforms/ereputation/client/client/src/pages/dashboard.tsx

@coderabbitaicoderabbitaiBot 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)
platforms/ereputation/client/client/src/pages/dashboard.tsx (1)

989-1016: ⚠️ Potential issue | 🟡 Minor

Prevent closing the confirmation modal while the delete is in flight.

onOpenChange and the Cancel button can still dismiss the dialog during deleteMutation.isPending, so the pending/error state disappears again before the request finishes.

Suggested fix
-<Dialog open={!!deleteModalOpen} onOpenChange={(open) => !open && setDeleteModalOpen(null)}>+<Dialog+ open={!!deleteModalOpen}+ onOpenChange={(open) => {+ if (!open && !deleteMutation.isPending) {+ setDeleteModalOpen(null);+ }+ }}+>
@@
- <Button- variant="outline"- onClick={() => setDeleteModalOpen(null)}+ <Button+ variant="outline"+ onClick={() => !deleteMutation.isPending && setDeleteModalOpen(null)}+ disabled={deleteMutation.isPending}
className="flex-1 border-2 border-fig/30 text-fig/70 hover:bg-fig-10 hover:border-fig/40 font-bold h-11"
>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@platforms/ereputation/client/client/src/pages/dashboard.tsx` around lines 989
- 1016, The confirmation dialog can be dismissed while a delete is in progress;
prevent that by blocking both the Dialog's onOpenChange handler and the Cancel
button when deleteMutation.isPending. Update the onOpenChange callback used on
the Dialog so it only calls setDeleteModalOpen(null) when open is false AND
deleteMutation.isPending is false, and set the Cancel <Button> to
disabled={deleteMutation.isPending} (and no-op its onClick when disabled) so
users cannot close the modal while confirmDeleteActivity is in flight.
platforms/ereputation/api/src/services/ReferenceService.ts (1)

98-109: ⚠️ Potential issue | 🔴 Critical

Move the ownership lookup into the transaction.

Lines 99-105 still run outside the transactional delete, so this path keeps a TOCTOU window: a concurrent update/delete can invalidate the ownership check, and Line 109 will then remove a stale entity without re-checking authorId.

Suggested fix
 async deleteReference(referenceId: string, authorId: string): Promise<boolean> {
- const reference = await this.referenceRepository.findOne({- where: { id: referenceId, authorId }- });-- if (!reference) {- return false;- }-- await AppDataSource.manager.transaction(async (manager) => {- await manager.delete("ReferenceSignature", { referenceId });- await manager.remove(reference);- });-- return true;+ return AppDataSource.manager.transaction(async (manager) => {+ const reference = await manager.findOne(Reference, {+ where: { id: referenceId, authorId },+ });++ if (!reference) {+ return false;+ }++ await manager.delete("ReferenceSignature", { referenceId });+ await manager.delete(Reference, { id: referenceId, authorId });+ return true;+ });
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@platforms/ereputation/api/src/services/ReferenceService.ts` around lines 98 -
109, Move the ownership lookup into the same transaction used for deletion:
inside deleteReference, instead of calling this.referenceRepository.findOne(...)
before AppDataSource.manager.transaction(...), perform the find/select for the
Reference by id with authorId within the transaction callback (use
manager.findOne or manager.getRepository('Reference').findOne), and if not found
return false; only then call manager.delete("ReferenceSignature", { referenceId
}) and manager.remove(reference) so the existence/ownership check and removals
occur atomically within the same transaction.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@platforms/ereputation/api/src/services/ReferenceService.ts`:
- Around line 98-109: Move the ownership lookup into the same transaction used
for deletion: inside deleteReference, instead of calling
this.referenceRepository.findOne(...) before
AppDataSource.manager.transaction(...), perform the find/select for the
Reference by id with authorId within the transaction callback (use
manager.findOne or manager.getRepository('Reference').findOne), and if not found
return false; only then call manager.delete("ReferenceSignature", { referenceId
}) and manager.remove(reference) so the existence/ownership check and removals
occur atomically within the same transaction.
In `@platforms/ereputation/client/client/src/pages/dashboard.tsx`:
- Around line 989-1016: The confirmation dialog can be dismissed while a delete
is in progress; prevent that by blocking both the Dialog's onOpenChange handler
and the Cancel button when deleteMutation.isPending. Update the onOpenChange
callback used on the Dialog so it only calls setDeleteModalOpen(null) when open
is false AND deleteMutation.isPending is false, and set the Cancel <Button> to
disabled={deleteMutation.isPending} (and no-op its onClick when disabled) so
users cannot close the modal while confirmDeleteActivity is in flight.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4d58b7d9-ad1a-4e91-8371-a1465c227a33

📥 Commits

Reviewing files that changed from the base of the PR and between b0f96d8 and e6710a4.

📒 Files selected for processing (2)
  • platforms/ereputation/api/src/services/ReferenceService.ts
  • platforms/ereputation/client/client/src/pages/dashboard.tsx

@coodos
coodos merged commit bddfe7a into mainMar 10, 2026
4 checks passed
@coodos
coodos deleted the feat/allow-ereference-deletion branch March 10, 2026 14:43
Sign up for freeto 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] (eReputation): Delete eReference

2 participants

@Bekiboo@coodos
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: add delete reference functionality with confirmation modal - #908

Merged
coodos merged 3 commits into
mainfrom
feat/allow-ereference-deletion
Mar 10, 2026
Merged

feat: add delete reference functionality with confirmation modal#908
coodos merged 3 commits into
mainfrom
feat/allow-ereference-deletion

Conversation

@Bekiboo

@BekibooBekiboo commented Mar 10, 2026

Copy link
Copy Markdown
Collaborator

Description of change

API

  • ReferenceService (api/src/services/ReferenceService.ts): Added deleteReference() — verifies author ownership, deletes related signatures, then removes the reference.
  • ReferenceController (api/src/controllers/ReferenceController.ts): Added deleteReference handler with 404 for not found/unauthorized.
  • Routes (api/src/index.ts): Registered DELETE /api/references/:referenceId with auth guard.

Client

  • Dashboard (client/src/pages/dashboard.tsx): Added delete button in activity dropdown (visible for "Reference Provided" entries), confirmation modal, and delete mutation via apiClient. Strips ref-sent- prefix from activity IDs to get the actual reference UUID.

Issue Number

Closes#874

Type of change

  • New (a change which implements a new feature)

How the change has been tested

Change checklist

  • I have ensured that the CI Checks pass locally
  • I have removed any unnecessary logic
  • My code is well documented
  • I have signed my commits
  • My code follows the pattern of the application
  • I have self reviewed my code

Summary by CodeRabbit

  • New Features

    • Users can delete references from the dashboard via a confirmation dialog.
    • Delete option added to activity actions in desktop and mobile views.
    • Success and error notifications shown for deletion attempts.
  • Bug Fixes / UX

    • Unauthorized deletion attempts redirect to login with an explanatory message.
    • Delete button is disabled while the operation is in progress.

@BekibooBekiboo self-assigned this Mar 10, 2026
@Bekiboo
Bekiboo requested a review from coodos as a code ownerMarch 10, 2026 07:09
@coderabbitai

coderabbitaiBot commented Mar 10, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Adds a delete eReference feature: protected DELETE API route and controller, a service method that validates ownership and cascades deletion of related signatures, and a frontend dashboard flow with confirmation modal, mutation, and error handling.

Changes

Cohort / File(s)Summary
Backend Controller & Route
platforms/ereputation/api/src/controllers/ReferenceController.ts, platforms/ereputation/api/src/index.ts
Adds deleteReference controller method and registers DELETE /api/references/:referenceId protected route; returns 404 when not found/unauthorized and 500 on exceptions.
Backend Service
platforms/ereputation/api/src/services/ReferenceService.ts
Adds deleteReference(referenceId, authorId): Promise<boolean> which verifies ownership, deletes related ReferenceSignature records in a transaction, then deletes the reference and returns success flag.
Frontend Dashboard
platforms/ereputation/client/client/src/pages/dashboard.tsx
Introduces React Query deleteMutation, confirmation modal, UI actions for Delete in activity menus, success cache invalidation and toast, and error handling including redirect on unauthorized.

Sequence Diagram(s)

sequenceDiagram
actor User
participant Frontend as Client (Dashboard)
participant API as Backend API
participant Service as ReferenceService
participant DB as Database
User->>Frontend: Click Delete on Reference
Frontend->>Frontend: Open confirmation modal
User->>Frontend: Confirm delete
Frontend->>API: DELETE /api/references/:referenceId (auth)
API->>Service: deleteReference(referenceId, userId)
Service->>DB: Find reference by id & author
alt found & authorized
Service->>DB: Delete ReferenceSignature records
Service->>DB: Delete Reference record
DB-->>Service: success
Service-->>API: return true
API-->>Frontend: 200 OK
Frontend->>Frontend: invalidate queries, show success toast
else not found or not owner
DB-->>Service: not found
Service-->>API: return false
API-->>Frontend: 404 Not Found
Frontend->>Frontend: show error toast
end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • sosweetham
  • xPathin

Poem

🐰 I hopped to the dashboard, quick and spry,

A delete button glinting in my eye.
Signatures cleared with a soft little thunk,
Modal confirmed — then poof! — into the trunk.
Farewell, tiny reference — a tidy goodbye.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring 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 nameStatusExplanation
Title check✅ PassedThe title clearly and accurately summarizes the main feature: adding delete reference functionality with a confirmation modal.
Description check✅ PassedThe description covers all required template sections with comprehensive details about API and client changes, issue reference, type of change, and completed checklist items.
Linked Issues check✅ PassedThe PR successfully implements the acceptance criteria from issue #874 by enabling deletion of eReferences through service, controller, and client-side changes.
Out of Scope Changes check✅ PassedAll changes are directly related to implementing the delete reference feature specified in issue #874, with no unrelated modifications detected.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/allow-ereference-deletion

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


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.

@coderabbitaicoderabbitaiBot 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: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@platforms/ereputation/api/src/services/ReferenceService.ts`:
- Around line 98-112: The deleteReference method currently deletes signatures
then removes the reference separately, risking partial deletes; wrap both
operations in a single DB transaction using AppDataSource.transaction (or a
QueryRunner) so they succeed or roll back together: inside the transaction use
the transactional EntityManager (from AppDataSource.manager.transaction or
queryRunner.manager) to delete ReferenceSignature entries (signatureRepository
via manager.delete) and then remove the Reference entity via manager.remove (or
manager.delete by id) instead of calling AppDataSource.getRepository(...) and
this.referenceRepository.remove outside the transaction; ensure you throw/return
appropriately so failures cause the transaction to rollback.
In `@platforms/ereputation/client/client/src/pages/dashboard.tsx`:
- Around line 85-92: The confirmation dialog is being closed immediately when
the delete is triggered, which prevents the mutation's pending/error UI from
rendering; remove the immediate dialog-close call that runs when the mutation is
invoked (e.g., any closeDialog() or setIsConfirmOpen(false) in the delete
handler) and instead call that same close function inside the mutation onSuccess
block (where queryClient.invalidateQueries and toast are used), leaving the
dialog open on pending and onError so the retry UI (the pending state rendered
around the confirmation dialog) remains visible.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d47f2177-e1c0-4bc7-8d1e-c96d8483ff0d

📥 Commits

Reviewing files that changed from the base of the PR and between 1286539 and b0f96d8.

📒 Files selected for processing (4)
  • platforms/ereputation/api/src/controllers/ReferenceController.ts
  • platforms/ereputation/api/src/index.ts
  • platforms/ereputation/api/src/services/ReferenceService.ts
  • platforms/ereputation/client/client/src/pages/dashboard.tsx

Comment threadplatforms/ereputation/api/src/services/ReferenceService.ts
Comment threadplatforms/ereputation/client/client/src/pages/dashboard.tsx

@coderabbitaicoderabbitaiBot 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)
platforms/ereputation/client/client/src/pages/dashboard.tsx (1)

989-1016: ⚠️ Potential issue | 🟡 Minor

Prevent closing the confirmation modal while the delete is in flight.

onOpenChange and the Cancel button can still dismiss the dialog during deleteMutation.isPending, so the pending/error state disappears again before the request finishes.

Suggested fix
-<Dialog open={!!deleteModalOpen} onOpenChange={(open) => !open && setDeleteModalOpen(null)}>+<Dialog+ open={!!deleteModalOpen}+ onOpenChange={(open) => {+ if (!open && !deleteMutation.isPending) {+ setDeleteModalOpen(null);+ }+ }}+>
@@
- <Button- variant="outline"- onClick={() => setDeleteModalOpen(null)}+ <Button+ variant="outline"+ onClick={() => !deleteMutation.isPending && setDeleteModalOpen(null)}+ disabled={deleteMutation.isPending}
className="flex-1 border-2 border-fig/30 text-fig/70 hover:bg-fig-10 hover:border-fig/40 font-bold h-11"
>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@platforms/ereputation/client/client/src/pages/dashboard.tsx` around lines 989
- 1016, The confirmation dialog can be dismissed while a delete is in progress;
prevent that by blocking both the Dialog's onOpenChange handler and the Cancel
button when deleteMutation.isPending. Update the onOpenChange callback used on
the Dialog so it only calls setDeleteModalOpen(null) when open is false AND
deleteMutation.isPending is false, and set the Cancel <Button> to
disabled={deleteMutation.isPending} (and no-op its onClick when disabled) so
users cannot close the modal while confirmDeleteActivity is in flight.
platforms/ereputation/api/src/services/ReferenceService.ts (1)

98-109: ⚠️ Potential issue | 🔴 Critical

Move the ownership lookup into the transaction.

Lines 99-105 still run outside the transactional delete, so this path keeps a TOCTOU window: a concurrent update/delete can invalidate the ownership check, and Line 109 will then remove a stale entity without re-checking authorId.

Suggested fix
 async deleteReference(referenceId: string, authorId: string): Promise<boolean> {
- const reference = await this.referenceRepository.findOne({- where: { id: referenceId, authorId }- });-- if (!reference) {- return false;- }-- await AppDataSource.manager.transaction(async (manager) => {- await manager.delete("ReferenceSignature", { referenceId });- await manager.remove(reference);- });-- return true;+ return AppDataSource.manager.transaction(async (manager) => {+ const reference = await manager.findOne(Reference, {+ where: { id: referenceId, authorId },+ });++ if (!reference) {+ return false;+ }++ await manager.delete("ReferenceSignature", { referenceId });+ await manager.delete(Reference, { id: referenceId, authorId });+ return true;+ });
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@platforms/ereputation/api/src/services/ReferenceService.ts` around lines 98 -
109, Move the ownership lookup into the same transaction used for deletion:
inside deleteReference, instead of calling this.referenceRepository.findOne(...)
before AppDataSource.manager.transaction(...), perform the find/select for the
Reference by id with authorId within the transaction callback (use
manager.findOne or manager.getRepository('Reference').findOne), and if not found
return false; only then call manager.delete("ReferenceSignature", { referenceId
}) and manager.remove(reference) so the existence/ownership check and removals
occur atomically within the same transaction.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@platforms/ereputation/api/src/services/ReferenceService.ts`:
- Around line 98-109: Move the ownership lookup into the same transaction used
for deletion: inside deleteReference, instead of calling
this.referenceRepository.findOne(...) before
AppDataSource.manager.transaction(...), perform the find/select for the
Reference by id with authorId within the transaction callback (use
manager.findOne or manager.getRepository('Reference').findOne), and if not found
return false; only then call manager.delete("ReferenceSignature", { referenceId
}) and manager.remove(reference) so the existence/ownership check and removals
occur atomically within the same transaction.
In `@platforms/ereputation/client/client/src/pages/dashboard.tsx`:
- Around line 989-1016: The confirmation dialog can be dismissed while a delete
is in progress; prevent that by blocking both the Dialog's onOpenChange handler
and the Cancel button when deleteMutation.isPending. Update the onOpenChange
callback used on the Dialog so it only calls setDeleteModalOpen(null) when open
is false AND deleteMutation.isPending is false, and set the Cancel <Button> to
disabled={deleteMutation.isPending} (and no-op its onClick when disabled) so
users cannot close the modal while confirmDeleteActivity is in flight.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4d58b7d9-ad1a-4e91-8371-a1465c227a33

📥 Commits

Reviewing files that changed from the base of the PR and between b0f96d8 and e6710a4.

📒 Files selected for processing (2)
  • platforms/ereputation/api/src/services/ReferenceService.ts
  • platforms/ereputation/client/client/src/pages/dashboard.tsx

@coodos
coodos merged commit bddfe7a into mainMar 10, 2026
4 checks passed
@coodos
coodos deleted the feat/allow-ereference-deletion branch March 10, 2026 14:43
Sign up for freeto 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] (eReputation): Delete eReference

2 participants

@Bekiboo@coodos
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: add delete reference functionality with confirmation modal - #908

Merged
coodos merged 3 commits into
mainfrom
feat/allow-ereference-deletion
Mar 10, 2026
Merged

feat: add delete reference functionality with confirmation modal#908
coodos merged 3 commits into
mainfrom
feat/allow-ereference-deletion

Conversation

@Bekiboo

@BekibooBekiboo commented Mar 10, 2026

Copy link
Copy Markdown
Collaborator

Description of change

API

  • ReferenceService (api/src/services/ReferenceService.ts): Added deleteReference() — verifies author ownership, deletes related signatures, then removes the reference.
  • ReferenceController (api/src/controllers/ReferenceController.ts): Added deleteReference handler with 404 for not found/unauthorized.
  • Routes (api/src/index.ts): Registered DELETE /api/references/:referenceId with auth guard.

Client

  • Dashboard (client/src/pages/dashboard.tsx): Added delete button in activity dropdown (visible for "Reference Provided" entries), confirmation modal, and delete mutation via apiClient. Strips ref-sent- prefix from activity IDs to get the actual reference UUID.

Issue Number

Closes#874

Type of change

  • New (a change which implements a new feature)

How the change has been tested

Change checklist

  • I have ensured that the CI Checks pass locally
  • I have removed any unnecessary logic
  • My code is well documented
  • I have signed my commits
  • My code follows the pattern of the application
  • I have self reviewed my code

Summary by CodeRabbit

  • New Features

    • Users can delete references from the dashboard via a confirmation dialog.
    • Delete option added to activity actions in desktop and mobile views.
    • Success and error notifications shown for deletion attempts.
  • Bug Fixes / UX

    • Unauthorized deletion attempts redirect to login with an explanatory message.
    • Delete button is disabled while the operation is in progress.

@BekibooBekiboo self-assigned this Mar 10, 2026
@Bekiboo
Bekiboo requested a review from coodos as a code ownerMarch 10, 2026 07:09
@coderabbitai

coderabbitaiBot commented Mar 10, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Adds a delete eReference feature: protected DELETE API route and controller, a service method that validates ownership and cascades deletion of related signatures, and a frontend dashboard flow with confirmation modal, mutation, and error handling.

Changes

Cohort / File(s)Summary
Backend Controller & Route
platforms/ereputation/api/src/controllers/ReferenceController.ts, platforms/ereputation/api/src/index.ts
Adds deleteReference controller method and registers DELETE /api/references/:referenceId protected route; returns 404 when not found/unauthorized and 500 on exceptions.
Backend Service
platforms/ereputation/api/src/services/ReferenceService.ts
Adds deleteReference(referenceId, authorId): Promise<boolean> which verifies ownership, deletes related ReferenceSignature records in a transaction, then deletes the reference and returns success flag.
Frontend Dashboard
platforms/ereputation/client/client/src/pages/dashboard.tsx
Introduces React Query deleteMutation, confirmation modal, UI actions for Delete in activity menus, success cache invalidation and toast, and error handling including redirect on unauthorized.

Sequence Diagram(s)

sequenceDiagram
actor User
participant Frontend as Client (Dashboard)
participant API as Backend API
participant Service as ReferenceService
participant DB as Database
User->>Frontend: Click Delete on Reference
Frontend->>Frontend: Open confirmation modal
User->>Frontend: Confirm delete
Frontend->>API: DELETE /api/references/:referenceId (auth)
API->>Service: deleteReference(referenceId, userId)
Service->>DB: Find reference by id & author
alt found & authorized
Service->>DB: Delete ReferenceSignature records
Service->>DB: Delete Reference record
DB-->>Service: success
Service-->>API: return true
API-->>Frontend: 200 OK
Frontend->>Frontend: invalidate queries, show success toast
else not found or not owner
DB-->>Service: not found
Service-->>API: return false
API-->>Frontend: 404 Not Found
Frontend->>Frontend: show error toast
end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • sosweetham
  • xPathin

Poem

🐰 I hopped to the dashboard, quick and spry,

A delete button glinting in my eye.
Signatures cleared with a soft little thunk,
Modal confirmed — then poof! — into the trunk.
Farewell, tiny reference — a tidy goodbye.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring 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 nameStatusExplanation
Title check✅ PassedThe title clearly and accurately summarizes the main feature: adding delete reference functionality with a confirmation modal.
Description check✅ PassedThe description covers all required template sections with comprehensive details about API and client changes, issue reference, type of change, and completed checklist items.
Linked Issues check✅ PassedThe PR successfully implements the acceptance criteria from issue #874 by enabling deletion of eReferences through service, controller, and client-side changes.
Out of Scope Changes check✅ PassedAll changes are directly related to implementing the delete reference feature specified in issue #874, with no unrelated modifications detected.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/allow-ereference-deletion

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


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.

@coderabbitaicoderabbitaiBot 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: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@platforms/ereputation/api/src/services/ReferenceService.ts`:
- Around line 98-112: The deleteReference method currently deletes signatures
then removes the reference separately, risking partial deletes; wrap both
operations in a single DB transaction using AppDataSource.transaction (or a
QueryRunner) so they succeed or roll back together: inside the transaction use
the transactional EntityManager (from AppDataSource.manager.transaction or
queryRunner.manager) to delete ReferenceSignature entries (signatureRepository
via manager.delete) and then remove the Reference entity via manager.remove (or
manager.delete by id) instead of calling AppDataSource.getRepository(...) and
this.referenceRepository.remove outside the transaction; ensure you throw/return
appropriately so failures cause the transaction to rollback.
In `@platforms/ereputation/client/client/src/pages/dashboard.tsx`:
- Around line 85-92: The confirmation dialog is being closed immediately when
the delete is triggered, which prevents the mutation's pending/error UI from
rendering; remove the immediate dialog-close call that runs when the mutation is
invoked (e.g., any closeDialog() or setIsConfirmOpen(false) in the delete
handler) and instead call that same close function inside the mutation onSuccess
block (where queryClient.invalidateQueries and toast are used), leaving the
dialog open on pending and onError so the retry UI (the pending state rendered
around the confirmation dialog) remains visible.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d47f2177-e1c0-4bc7-8d1e-c96d8483ff0d

📥 Commits

Reviewing files that changed from the base of the PR and between 1286539 and b0f96d8.

📒 Files selected for processing (4)
  • platforms/ereputation/api/src/controllers/ReferenceController.ts
  • platforms/ereputation/api/src/index.ts
  • platforms/ereputation/api/src/services/ReferenceService.ts
  • platforms/ereputation/client/client/src/pages/dashboard.tsx

Comment threadplatforms/ereputation/api/src/services/ReferenceService.ts
Comment threadplatforms/ereputation/client/client/src/pages/dashboard.tsx

@coderabbitaicoderabbitaiBot 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)
platforms/ereputation/client/client/src/pages/dashboard.tsx (1)

989-1016: ⚠️ Potential issue | 🟡 Minor

Prevent closing the confirmation modal while the delete is in flight.

onOpenChange and the Cancel button can still dismiss the dialog during deleteMutation.isPending, so the pending/error state disappears again before the request finishes.

Suggested fix
-<Dialog open={!!deleteModalOpen} onOpenChange={(open) => !open && setDeleteModalOpen(null)}>+<Dialog+ open={!!deleteModalOpen}+ onOpenChange={(open) => {+ if (!open && !deleteMutation.isPending) {+ setDeleteModalOpen(null);+ }+ }}+>
@@
- <Button- variant="outline"- onClick={() => setDeleteModalOpen(null)}+ <Button+ variant="outline"+ onClick={() => !deleteMutation.isPending && setDeleteModalOpen(null)}+ disabled={deleteMutation.isPending}
className="flex-1 border-2 border-fig/30 text-fig/70 hover:bg-fig-10 hover:border-fig/40 font-bold h-11"
>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@platforms/ereputation/client/client/src/pages/dashboard.tsx` around lines 989
- 1016, The confirmation dialog can be dismissed while a delete is in progress;
prevent that by blocking both the Dialog's onOpenChange handler and the Cancel
button when deleteMutation.isPending. Update the onOpenChange callback used on
the Dialog so it only calls setDeleteModalOpen(null) when open is false AND
deleteMutation.isPending is false, and set the Cancel <Button> to
disabled={deleteMutation.isPending} (and no-op its onClick when disabled) so
users cannot close the modal while confirmDeleteActivity is in flight.
platforms/ereputation/api/src/services/ReferenceService.ts (1)

98-109: ⚠️ Potential issue | 🔴 Critical

Move the ownership lookup into the transaction.

Lines 99-105 still run outside the transactional delete, so this path keeps a TOCTOU window: a concurrent update/delete can invalidate the ownership check, and Line 109 will then remove a stale entity without re-checking authorId.

Suggested fix
 async deleteReference(referenceId: string, authorId: string): Promise<boolean> {
- const reference = await this.referenceRepository.findOne({- where: { id: referenceId, authorId }- });-- if (!reference) {- return false;- }-- await AppDataSource.manager.transaction(async (manager) => {- await manager.delete("ReferenceSignature", { referenceId });- await manager.remove(reference);- });-- return true;+ return AppDataSource.manager.transaction(async (manager) => {+ const reference = await manager.findOne(Reference, {+ where: { id: referenceId, authorId },+ });++ if (!reference) {+ return false;+ }++ await manager.delete("ReferenceSignature", { referenceId });+ await manager.delete(Reference, { id: referenceId, authorId });+ return true;+ });
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@platforms/ereputation/api/src/services/ReferenceService.ts` around lines 98 -
109, Move the ownership lookup into the same transaction used for deletion:
inside deleteReference, instead of calling this.referenceRepository.findOne(...)
before AppDataSource.manager.transaction(...), perform the find/select for the
Reference by id with authorId within the transaction callback (use
manager.findOne or manager.getRepository('Reference').findOne), and if not found
return false; only then call manager.delete("ReferenceSignature", { referenceId
}) and manager.remove(reference) so the existence/ownership check and removals
occur atomically within the same transaction.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@platforms/ereputation/api/src/services/ReferenceService.ts`:
- Around line 98-109: Move the ownership lookup into the same transaction used
for deletion: inside deleteReference, instead of calling
this.referenceRepository.findOne(...) before
AppDataSource.manager.transaction(...), perform the find/select for the
Reference by id with authorId within the transaction callback (use
manager.findOne or manager.getRepository('Reference').findOne), and if not found
return false; only then call manager.delete("ReferenceSignature", { referenceId
}) and manager.remove(reference) so the existence/ownership check and removals
occur atomically within the same transaction.
In `@platforms/ereputation/client/client/src/pages/dashboard.tsx`:
- Around line 989-1016: The confirmation dialog can be dismissed while a delete
is in progress; prevent that by blocking both the Dialog's onOpenChange handler
and the Cancel button when deleteMutation.isPending. Update the onOpenChange
callback used on the Dialog so it only calls setDeleteModalOpen(null) when open
is false AND deleteMutation.isPending is false, and set the Cancel <Button> to
disabled={deleteMutation.isPending} (and no-op its onClick when disabled) so
users cannot close the modal while confirmDeleteActivity is in flight.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4d58b7d9-ad1a-4e91-8371-a1465c227a33

📥 Commits

Reviewing files that changed from the base of the PR and between b0f96d8 and e6710a4.

📒 Files selected for processing (2)
  • platforms/ereputation/api/src/services/ReferenceService.ts
  • platforms/ereputation/client/client/src/pages/dashboard.tsx

@coodos
coodos merged commit bddfe7a into mainMar 10, 2026
4 checks passed
@coodos
coodos deleted the feat/allow-ereference-deletion branch March 10, 2026 14:43
Sign up for freeto 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] (eReputation): Delete eReference

2 participants

@Bekiboo@coodos
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

feat: add delete reference functionality with confirmation modal - #908

Merged
coodos merged 3 commits into
mainfrom
feat/allow-ereference-deletion
Mar 10, 2026
Merged

feat: add delete reference functionality with confirmation modal#908
coodos merged 3 commits into
mainfrom
feat/allow-ereference-deletion

Conversation

@Bekiboo

@BekibooBekiboo commented Mar 10, 2026

Copy link
Copy Markdown
Collaborator

Description of change

API

  • ReferenceService (api/src/services/ReferenceService.ts): Added deleteReference() — verifies author ownership, deletes related signatures, then removes the reference.
  • ReferenceController (api/src/controllers/ReferenceController.ts): Added deleteReference handler with 404 for not found/unauthorized.
  • Routes (api/src/index.ts): Registered DELETE /api/references/:referenceId with auth guard.

Client

  • Dashboard (client/src/pages/dashboard.tsx): Added delete button in activity dropdown (visible for "Reference Provided" entries), confirmation modal, and delete mutation via apiClient. Strips ref-sent- prefix from activity IDs to get the actual reference UUID.

Issue Number

Closes#874

Type of change

  • New (a change which implements a new feature)

How the change has been tested

Change checklist

  • I have ensured that the CI Checks pass locally
  • I have removed any unnecessary logic
  • My code is well documented
  • I have signed my commits
  • My code follows the pattern of the application
  • I have self reviewed my code

Summary by CodeRabbit

  • New Features

    • Users can delete references from the dashboard via a confirmation dialog.
    • Delete option added to activity actions in desktop and mobile views.
    • Success and error notifications shown for deletion attempts.
  • Bug Fixes / UX

    • Unauthorized deletion attempts redirect to login with an explanatory message.
    • Delete button is disabled while the operation is in progress.

@BekibooBekiboo self-assigned this Mar 10, 2026
@Bekiboo
Bekiboo requested a review from coodos as a code ownerMarch 10, 2026 07:09
@coderabbitai

coderabbitaiBot commented Mar 10, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Adds a delete eReference feature: protected DELETE API route and controller, a service method that validates ownership and cascades deletion of related signatures, and a frontend dashboard flow with confirmation modal, mutation, and error handling.

Changes

Cohort / File(s)Summary
Backend Controller & Route
platforms/ereputation/api/src/controllers/ReferenceController.ts, platforms/ereputation/api/src/index.ts
Adds deleteReference controller method and registers DELETE /api/references/:referenceId protected route; returns 404 when not found/unauthorized and 500 on exceptions.
Backend Service
platforms/ereputation/api/src/services/ReferenceService.ts
Adds deleteReference(referenceId, authorId): Promise<boolean> which verifies ownership, deletes related ReferenceSignature records in a transaction, then deletes the reference and returns success flag.
Frontend Dashboard
platforms/ereputation/client/client/src/pages/dashboard.tsx
Introduces React Query deleteMutation, confirmation modal, UI actions for Delete in activity menus, success cache invalidation and toast, and error handling including redirect on unauthorized.

Sequence Diagram(s)

sequenceDiagram
actor User
participant Frontend as Client (Dashboard)
participant API as Backend API
participant Service as ReferenceService
participant DB as Database
User->>Frontend: Click Delete on Reference
Frontend->>Frontend: Open confirmation modal
User->>Frontend: Confirm delete
Frontend->>API: DELETE /api/references/:referenceId (auth)
API->>Service: deleteReference(referenceId, userId)
Service->>DB: Find reference by id & author
alt found & authorized
Service->>DB: Delete ReferenceSignature records
Service->>DB: Delete Reference record
DB-->>Service: success
Service-->>API: return true
API-->>Frontend: 200 OK
Frontend->>Frontend: invalidate queries, show success toast
else not found or not owner
DB-->>Service: not found
Service-->>API: return false
API-->>Frontend: 404 Not Found
Frontend->>Frontend: show error toast
end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • sosweetham
  • xPathin

Poem

🐰 I hopped to the dashboard, quick and spry,

A delete button glinting in my eye.
Signatures cleared with a soft little thunk,
Modal confirmed — then poof! — into the trunk.
Farewell, tiny reference — a tidy goodbye.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring 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 nameStatusExplanation
Title check✅ PassedThe title clearly and accurately summarizes the main feature: adding delete reference functionality with a confirmation modal.
Description check✅ PassedThe description covers all required template sections with comprehensive details about API and client changes, issue reference, type of change, and completed checklist items.
Linked Issues check✅ PassedThe PR successfully implements the acceptance criteria from issue #874 by enabling deletion of eReferences through service, controller, and client-side changes.
Out of Scope Changes check✅ PassedAll changes are directly related to implementing the delete reference feature specified in issue #874, with no unrelated modifications detected.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/allow-ereference-deletion

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


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.

@coderabbitaicoderabbitaiBot 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: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@platforms/ereputation/api/src/services/ReferenceService.ts`:
- Around line 98-112: The deleteReference method currently deletes signatures
then removes the reference separately, risking partial deletes; wrap both
operations in a single DB transaction using AppDataSource.transaction (or a
QueryRunner) so they succeed or roll back together: inside the transaction use
the transactional EntityManager (from AppDataSource.manager.transaction or
queryRunner.manager) to delete ReferenceSignature entries (signatureRepository
via manager.delete) and then remove the Reference entity via manager.remove (or
manager.delete by id) instead of calling AppDataSource.getRepository(...) and
this.referenceRepository.remove outside the transaction; ensure you throw/return
appropriately so failures cause the transaction to rollback.
In `@platforms/ereputation/client/client/src/pages/dashboard.tsx`:
- Around line 85-92: The confirmation dialog is being closed immediately when
the delete is triggered, which prevents the mutation's pending/error UI from
rendering; remove the immediate dialog-close call that runs when the mutation is
invoked (e.g., any closeDialog() or setIsConfirmOpen(false) in the delete
handler) and instead call that same close function inside the mutation onSuccess
block (where queryClient.invalidateQueries and toast are used), leaving the
dialog open on pending and onError so the retry UI (the pending state rendered
around the confirmation dialog) remains visible.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d47f2177-e1c0-4bc7-8d1e-c96d8483ff0d

📥 Commits

Reviewing files that changed from the base of the PR and between 1286539 and b0f96d8.

📒 Files selected for processing (4)
  • platforms/ereputation/api/src/controllers/ReferenceController.ts
  • platforms/ereputation/api/src/index.ts
  • platforms/ereputation/api/src/services/ReferenceService.ts
  • platforms/ereputation/client/client/src/pages/dashboard.tsx

Comment threadplatforms/ereputation/api/src/services/ReferenceService.ts
Comment threadplatforms/ereputation/client/client/src/pages/dashboard.tsx

@coderabbitaicoderabbitaiBot 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)
platforms/ereputation/client/client/src/pages/dashboard.tsx (1)

989-1016: ⚠️ Potential issue | 🟡 Minor

Prevent closing the confirmation modal while the delete is in flight.

onOpenChange and the Cancel button can still dismiss the dialog during deleteMutation.isPending, so the pending/error state disappears again before the request finishes.

Suggested fix
-<Dialog open={!!deleteModalOpen} onOpenChange={(open) => !open && setDeleteModalOpen(null)}>+<Dialog+ open={!!deleteModalOpen}+ onOpenChange={(open) => {+ if (!open && !deleteMutation.isPending) {+ setDeleteModalOpen(null);+ }+ }}+>
@@
- <Button- variant="outline"- onClick={() => setDeleteModalOpen(null)}+ <Button+ variant="outline"+ onClick={() => !deleteMutation.isPending && setDeleteModalOpen(null)}+ disabled={deleteMutation.isPending}
className="flex-1 border-2 border-fig/30 text-fig/70 hover:bg-fig-10 hover:border-fig/40 font-bold h-11"
>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@platforms/ereputation/client/client/src/pages/dashboard.tsx` around lines 989
- 1016, The confirmation dialog can be dismissed while a delete is in progress;
prevent that by blocking both the Dialog's onOpenChange handler and the Cancel
button when deleteMutation.isPending. Update the onOpenChange callback used on
the Dialog so it only calls setDeleteModalOpen(null) when open is false AND
deleteMutation.isPending is false, and set the Cancel <Button> to
disabled={deleteMutation.isPending} (and no-op its onClick when disabled) so
users cannot close the modal while confirmDeleteActivity is in flight.
platforms/ereputation/api/src/services/ReferenceService.ts (1)

98-109: ⚠️ Potential issue | 🔴 Critical

Move the ownership lookup into the transaction.

Lines 99-105 still run outside the transactional delete, so this path keeps a TOCTOU window: a concurrent update/delete can invalidate the ownership check, and Line 109 will then remove a stale entity without re-checking authorId.

Suggested fix
 async deleteReference(referenceId: string, authorId: string): Promise<boolean> {
- const reference = await this.referenceRepository.findOne({- where: { id: referenceId, authorId }- });-- if (!reference) {- return false;- }-- await AppDataSource.manager.transaction(async (manager) => {- await manager.delete("ReferenceSignature", { referenceId });- await manager.remove(reference);- });-- return true;+ return AppDataSource.manager.transaction(async (manager) => {+ const reference = await manager.findOne(Reference, {+ where: { id: referenceId, authorId },+ });++ if (!reference) {+ return false;+ }++ await manager.delete("ReferenceSignature", { referenceId });+ await manager.delete(Reference, { id: referenceId, authorId });+ return true;+ });
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@platforms/ereputation/api/src/services/ReferenceService.ts` around lines 98 -
109, Move the ownership lookup into the same transaction used for deletion:
inside deleteReference, instead of calling this.referenceRepository.findOne(...)
before AppDataSource.manager.transaction(...), perform the find/select for the
Reference by id with authorId within the transaction callback (use
manager.findOne or manager.getRepository('Reference').findOne), and if not found
return false; only then call manager.delete("ReferenceSignature", { referenceId
}) and manager.remove(reference) so the existence/ownership check and removals
occur atomically within the same transaction.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@platforms/ereputation/api/src/services/ReferenceService.ts`:
- Around line 98-109: Move the ownership lookup into the same transaction used
for deletion: inside deleteReference, instead of calling
this.referenceRepository.findOne(...) before
AppDataSource.manager.transaction(...), perform the find/select for the
Reference by id with authorId within the transaction callback (use
manager.findOne or manager.getRepository('Reference').findOne), and if not found
return false; only then call manager.delete("ReferenceSignature", { referenceId
}) and manager.remove(reference) so the existence/ownership check and removals
occur atomically within the same transaction.
In `@platforms/ereputation/client/client/src/pages/dashboard.tsx`:
- Around line 989-1016: The confirmation dialog can be dismissed while a delete
is in progress; prevent that by blocking both the Dialog's onOpenChange handler
and the Cancel button when deleteMutation.isPending. Update the onOpenChange
callback used on the Dialog so it only calls setDeleteModalOpen(null) when open
is false AND deleteMutation.isPending is false, and set the Cancel <Button> to
disabled={deleteMutation.isPending} (and no-op its onClick when disabled) so
users cannot close the modal while confirmDeleteActivity is in flight.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4d58b7d9-ad1a-4e91-8371-a1465c227a33

📥 Commits

Reviewing files that changed from the base of the PR and between b0f96d8 and e6710a4.

📒 Files selected for processing (2)
  • platforms/ereputation/api/src/services/ReferenceService.ts
  • platforms/ereputation/client/client/src/pages/dashboard.tsx

@coodos
coodos merged commit bddfe7a into mainMar 10, 2026
4 checks passed
@coodos
coodos deleted the feat/allow-ereference-deletion branch March 10, 2026 14:43
Sign up for freeto 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] (eReputation): Delete eReference

2 participants

@Bekiboo@coodos