Skip to content

feat: soft-delete conversations with batch checkbox support#566

Open
HirenGajjar wants to merge 7 commits into
Arcadia-Solutions:mainfrom
HirenGajjar:feat/delete-conversation
Open

feat: soft-delete conversations with batch checkbox support#566
HirenGajjar wants to merge 7 commits into
Arcadia-Solutions:mainfrom
HirenGajjar:feat/delete-conversation

Conversation

@HirenGajjar
Copy link
Copy Markdown

@HirenGajjar HirenGajjar commented May 15, 2026

Closes #564

What this does

  • Users can delete their own conversations from the conversations list
  • Checkboxes on each row allow batch-selecting multiple conversations
  • A "Delete selected" button appears when at least one conversation is checked
  • Deletion is soft — sets deleted_by_sender or deleted_by_receiver to true depending on who deletes
  • One-sided: deleting only hides the conversation for you, not the other person

Changes

  • Migration: adds deleted_by_sender and deleted_by_receiver boolean columns to conversations
  • Backend: new DELETE /api/conversations endpoint accepting { conversation_ids: [id, ...] }
  • Backend: search and unread count queries filter out conversations deleted by the current user
  • Frontend: checkbox column + delete bar in ConversationsView

Summary by CodeRabbit

  • New Features

    • Added multi-selection to conversations. Users can select one or more conversations using checkboxes and delete them in bulk via the new "Delete selected" action button.
  • Chores

    • Updated database schema and translations to support conversation deletion.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 15, 2026

📝 Walkthrough

Walkthrough

Implements one-sided soft deletion of conversations by adding per-user deletion flags to the database schema, updating queries to exclude deleted conversations, creating a repository delete method, exposing a DELETE API endpoint, and providing frontend UI for bulk multi-select deletion with corresponding i18n strings and error handling.

Changes

Conversation Soft-Delete Feature

Layer / File(s) Summary
Database schema and data models
backend/storage/migrations/20250312215600_initdb.sql, backend/storage/src/models/conversation.rs
Migration adds deleted_by_sender and deleted_by_receiver boolean columns to conversations; Conversation struct and DeleteConversationsRequest type updated to include deletion state fields and bulk-delete payload.
Soft-delete SQL and repository update
backend/storage/.sqlx/query-f711b5827411954a9c91da7bfbbe1aa0e1cf3f9caff40ac25617472f92e26bcd.json, backend/storage/src/repositories/conversation_repository.rs
New SQLx UPDATE query metadata conditionally sets deletion flags per user role; delete_conversations method implemented to update flags; create_conversation RETURNING clause expanded with deletion state and additional metadata columns.
Query filtering for deleted conversations
backend/storage/.sqlx/query-4d9607ff2d309b1bca47660d3ba69c794d9eef2fcae0e584e103882e72414d9a.json, backend/storage/.sqlx/query-90af7add601e367b15cc3de3add6a5711724242eb7728522014c9a6116c74b0e.json, backend/storage/src/repositories/conversation_repository.rs
Search, count, and unread-count queries updated with WHERE predicates excluding conversations marked deleted by current user; find_unread_conversations_amount filters unread counts by deletion flags.
API handler, routing, and error types
backend/api/src/handlers/conversations/delete_conversations.rs, backend/api/src/handlers/conversations/mod.rs, backend/common/src/error/mod.rs
New DELETE /api/conversations handler validates request body, checks auth, calls repository delete method; route registered on base conversations endpoint; error enum extended with CouldNotDeleteConversation and ConversationIdsEmpty variants mapped to 500 and 400 status codes respectively.
Frontend bulk-selection and deletion UI
frontend/src/views/conversation/ConversationsView.vue, frontend/src/i18n/en.json
ConversationsView adds per-row selection checkboxes, conditional delete toolbar with danger button, deleteSelected method calling DELETE API with selected IDs, local filtering of removed conversations, clears selection in finally block; two i18n keys added for UI labels.
SQLx artifact updates
backend/storage/.sqlx/query-1a6dc57754fac6101be5a22d8a2dccd75115f1d7e8549df2a1fbfa58ae7f685f.json
Minor edits to stored query artifacts: removed trailing semicolon from query string and updated hash values to match.

🐰 Soft whispers of deletion float,
Flags that mark what each has forgot,
Checkboxes checked in a gentle dance,
One-sided goodbyes, a second chance! 🗑️

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 37.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: soft-delete conversations with batch checkbox support' clearly summarizes the main changes: soft-delete functionality and batch selection via checkboxes.
Linked Issues check ✅ Passed The PR fully implements all requirements from issue #564: soft-delete conversations, batch-selection checkboxes, one-sided deletion per user, and DB soft-delete flags.
Out of Scope Changes check ✅ Passed All changes directly support soft-delete conversation functionality; no unrelated or out-of-scope modifications detected.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@FrenchGithubUser
Copy link
Copy Markdown
Contributor

I think that the schema-check fails because the removed files in the .sqlx/ folder shouldn't be removed, it's a bug from sqlx: launchbadge/sqlx#4117

@HirenGajjar
Copy link
Copy Markdown
Author

@FrenchGithubUser
Sorry about that — I ran cargo sqlx prepare from within the backend/storage crate which caused it to remove query cache files from other workspace crates. I've restored the deleted files from upstream/main. Should be clean now.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
frontend/src/views/conversation/ConversationsView.vue (1)

1-160: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Fix Prettier violations to unblock Frontend CI.

This file is currently failing prettier --check src, which is blocking the pipeline.

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

In `@frontend/src/views/conversation/ConversationsView.vue` around lines 1 - 160,
The file fails Prettier checks; run your formatter or apply Prettier rules to
ConversationsView.vue and fix spacing/quoting/order issues so the file matches
project formatting. Specifically, format the template and script blocks, ensure
import statements and const declarations (e.g., imports for DataTable/Column,
useConversationSearch, and the consts t, notificationsStore, selectedIds) follow
project Prettier settings, and reformat the isConversationRead and
deleteSelected functions (including consistent spacing around operators, ternary
branches, and arrow functions) to resolve the CI failure.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@backend/storage/src/models/conversation.rs`:
- Around line 158-161: Run cargo fmt to fix the formatting warning in this file;
then add an API-level validation for
DeleteConversationsRequest::conversation_ids so empty Vecs are rejected before
DB calls — e.g., in the request handler that receives DeleteConversationsRequest
check that request.conversation_ids.is_empty() and return a 400/validation error
if so (or wire a validator on DeleteConversationsRequest if your project uses a
validation crate), ensuring you reference DeleteConversationsRequest and its
conversation_ids field when adding the check.

In `@backend/storage/src/repositories/conversation_repository.rs`:
- Around line 446-469: Validate and return early when the conversation_ids slice
is empty in the API handler delete_conversations.rs to avoid issuing a no-op DB
query; add a guard at the start of the handler that returns a 400/204 (choose
project convention) if the incoming list is empty. Also decide and implement
consistent "resurrection" behavior: if you want a new message to undelete the
conversation, update create_conversation_message to clear the appropriate
deleted_by_sender/deleted_by_receiver flag(s) for the conversation (identify
conversation by conversation_id used in create_conversation_message) when
inserting a message; otherwise document/leave behavior as permanent. Ensure you
reference the conversation_repository::delete_conversations logic and
list_conversations/search_conversations filters when making the change so flags
remain consistent.

In `@frontend/src/views/conversation/ConversationsView.vue`:
- Line 19: Replace the hardcoded label "Delete selected" in
ConversationsView.vue with a localized i18n lookup (e.g. use this.$t(...) or the
<i18n> key binding used elsewhere) so the delete action uses the translations;
locate the attribute label="Delete selected" and change it to use the same i18n
key pattern as other labels in this view (for example
conversations.deleteSelected) and add the corresponding key to your locale
files.
- Around line 127-140: The deleteSelected function currently removes
conversations from searchResults and clears selectedIds regardless of the DELETE
API outcome; modify deleteSelected to await the fetch response, check
response.ok (or HTTP status) and only on a successful response update
searchResults and reset selectedIds.value, otherwise do not change local state
and surface an error (e.g., throw, return, or show a UI error). Ensure you
reference the same symbols: deleteSelected, selectedIds.value, and
searchResults.value so the UI update is strictly gated by a successful response.

---

Outside diff comments:
In `@frontend/src/views/conversation/ConversationsView.vue`:
- Around line 1-160: The file fails Prettier checks; run your formatter or apply
Prettier rules to ConversationsView.vue and fix spacing/quoting/order issues so
the file matches project formatting. Specifically, format the template and
script blocks, ensure import statements and const declarations (e.g., imports
for DataTable/Column, useConversationSearch, and the consts t,
notificationsStore, selectedIds) follow project Prettier settings, and reformat
the isConversationRead and deleteSelected functions (including consistent
spacing around operators, ternary branches, and arrow functions) to resolve the
CI failure.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f084a3e8-e5e4-4504-932e-4ba2acadf3c2

📥 Commits

Reviewing files that changed from the base of the PR and between d488b34 and ca40bfe.

📒 Files selected for processing (12)
  • backend/api/src/handlers/conversations/delete_conversations.rs
  • backend/api/src/handlers/conversations/mod.rs
  • backend/common/src/error/mod.rs
  • backend/storage/.sqlx/query-1a6dc57754fac6101be5a22d8a2dccd75115f1d7e8549df2a1fbfa58ae7f685f.json
  • backend/storage/.sqlx/query-4d9607ff2d309b1bca47660d3ba69c794d9eef2fcae0e584e103882e72414d9a.json
  • backend/storage/.sqlx/query-90af7add601e367b15cc3de3add6a5711724242eb7728522014c9a6116c74b0e.json
  • backend/storage/.sqlx/query-d5d60d7bc3f8609f335124dd9db0e473d5e1e55cb53a4a82eed74234964b67cd.json
  • backend/storage/.sqlx/query-f711b5827411954a9c91da7bfbbe1aa0e1cf3f9caff40ac25617472f92e26bcd.json
  • backend/storage/migrations/20250514000001_add_conversation_soft_delete.sql
  • backend/storage/src/models/conversation.rs
  • backend/storage/src/repositories/conversation_repository.rs
  • frontend/src/views/conversation/ConversationsView.vue

Comment on lines +158 to +161
#[derive(Debug, Deserialize, ToSchema)]
pub struct DeleteConversationsRequest {
pub conversation_ids: Vec<i64>,
} No newline at end of file
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Address the formatting warning and consider validating conversation_ids.

The static analysis tool flagged a formatting issue. Run cargo fmt to fix it.

Additionally, consider validating that conversation_ids is non-empty at the API layer to avoid unnecessary database round-trips.

🧰 Tools
🪛 GitHub Check: cargo fmt

[warning] 159-159:
Diff in /home/runner/work/arcadia/arcadia/backend/storage/src/models/conversation.rs

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

In `@backend/storage/src/models/conversation.rs` around lines 158 - 161, Run cargo
fmt to fix the formatting warning in this file; then add an API-level validation
for DeleteConversationsRequest::conversation_ids so empty Vecs are rejected
before DB calls — e.g., in the request handler that receives
DeleteConversationsRequest check that request.conversation_ids.is_empty() and
return a 400/validation error if so (or wire a validator on
DeleteConversationsRequest if your project uses a validation crate), ensuring
you reference DeleteConversationsRequest and its conversation_ids field when
adding the check.

Comment thread backend/storage/src/repositories/conversation_repository.rs
Comment thread frontend/src/views/conversation/ConversationsView.vue Outdated
Comment thread frontend/src/views/conversation/ConversationsView.vue Outdated
@FrenchGithubUser
Copy link
Copy Markdown
Contributor

FrenchGithubUser commented May 15, 2026

@HirenGajjar looks better now, thanks! Could you now run cargo fmt in the root folder and npm run prettier in the frontend/ folder? Then have a look at the comments from CodeRabbit, they might be relevant sometimes :)

And thanks for this PR!

@FrenchGithubUser
Copy link
Copy Markdown
Contributor

@HirenGajjar let me know when you're done with the coderabbit comments and I'll have a look at your changes :)

btw feel free to join the discord server if you wanna chat some time! (link in readme)

- validate empty conversation_ids in delete handler (400)
- guard UI state update behind successful DELETE response
- use i18n for delete button label
- add missing newline at end of conversation.rs
- run cargo fmt and prettier
@FrenchGithubUser
Copy link
Copy Markdown
Contributor

could you also post a screenshot of how the UI looks like?

@FrenchGithubUser FrenchGithubUser force-pushed the main branch 2 times, most recently from 4c57b76 to bf0ed97 Compare May 16, 2026 18:43
@HirenGajjar
Copy link
Copy Markdown
Author

Here's a UI mockup showing the new feature — a checkbox column is added as the first column in the conversations table.
When one or more rows are selected, a "Delete selected (N)" button appears above the table. Selecting all and clicking delete soft-deletes the conversations from the user's view only.
I wasn't able to spin up the full local stack (requires 12+ services) to get a real screenshot — the mockup accurately represents the UX flow.
Happy to provide a real screenshot if you can share a simpler way to run the app locally.

@FrenchGithubUser
Copy link
Copy Markdown
Contributor

don't you have a screenshot @HirenGajjar ?

@HirenGajjar
Copy link
Copy Markdown
Author

Screenshot 2026-05-17 at 12 45 13 PM

) -> Result<HttpResponse> {
if body.conversation_ids.is_empty() {
return Ok(HttpResponse::BadRequest().json(serde_json::json!({
"error": "conversation_ids cannot be empty"
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.

In general use a variant from the existing Error enum, you can add a variant if necessary.

@@ -0,0 +1,3 @@
ALTER TABLE conversations
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.

db changes should be added in the existing migration file, don't create new ones until we have a first release.

</div>
</ContentContainer>

<div v-if="selectedIds.length > 0" class="delete-bar">
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.

Suggested change
<div v-if="selectedIds.length > 0" class="delete-bar">
<div v-if="selectedIds.length > 0" class="actions">

This will also be used for other action btns

const deleteSelected = async () => {
if (selectedIds.value.length === 0) return

const response = await fetch('/api/conversations', {
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.

Don't use a raw fetch but instead use the existing api client, like it is done in other components. It also looks like this won't actually use the configured api endpoint, but just the window url

body: JSON.stringify({ conversation_ids: selectedIds.value }),
})

if (!response.ok) return
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.

use .then() and .finally() instead

Comment thread .gitignore Outdated

# kiwiirc client
kiwiirc/config.json
.sqlx/
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.

remove this

- move migration to existing initdb.sql, remove separate migration file
- use Error enum variant for empty conversation_ids validation
- rename delete-bar css class to actions
- use axios api client instead of raw fetch
- use .then()/.finally() pattern
- remove .sqlx/ from .gitignore
- run cargo fmt and prettier
@HirenGajjar
Copy link
Copy Markdown
Author

Addressed all review comments:

  • Migration moved into the existing initdb.sql file
  • Empty conversation_ids now returns an
  • Error::ConversationIdsEmpty variant instead of raw JSON
  • CSS class renamed to actions
  • Replaced raw fetch with the axios API client, using .then()/.finally()
  • Removed .sqlx/ from .gitignore

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
frontend/src/views/conversation/ConversationsView.vue (1)

119-127: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Sync pagination totals after successful delete.

Line 123 removes rows locally, but totalResults is not decremented, so paginator totals can become stale until a refresh.

Suggested patch
 const deleteSelected = () => {
+  const idsToDelete = [...selectedIds.value]
   api
-    .delete('/api/conversations', { data: { conversation_ids: selectedIds.value } })
+    .delete('/api/conversations', { data: { conversation_ids: idsToDelete } })
     .then(() => {
-      searchResults.value = searchResults.value.filter((c) => !selectedIds.value.includes(c.conversation_id as number))
+      searchResults.value = searchResults.value.filter((c) => !idsToDelete.includes(c.conversation_id as number))
+      totalResults.value = Math.max(0, totalResults.value - idsToDelete.length)
     })
     .finally(() => {
       selectedIds.value = []
     })
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/views/conversation/ConversationsView.vue` around lines 119 -
127, The deleteSelected handler removes items from searchResults but doesn't
update the pagination count; inside the successful .then() of deleteSelected
(the function name), after filtering searchResults.value, decrement
totalResults.value (or the pagination total variable) by the number of removed
items (e.g., const removed = selectedIds.value.length) and guard it to never go
below zero, so the paginator totals stay in sync with searchResults.value; leave
the selectedIds reset in .finally() as-is.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@backend/storage/migrations/20250312215600_initdb.sql`:
- Around line 1572-1574: The init migration 20250312215600_initdb.sql was edited
to add two columns (ALTER TABLE conversations ADD COLUMN deleted_by_sender
BOOLEAN ... and deleted_by_receiver ...); revert that change in the historical
init file and instead create a new forward migration (new timestamped SQL file)
that runs ALTER TABLE conversations ADD COLUMN deleted_by_sender BOOLEAN NOT
NULL DEFAULT FALSE, ADD COLUMN deleted_by_receiver BOOLEAN NOT NULL DEFAULT
FALSE so existing DBs get the change when migrations are run and the original
init migration remains immutable.

---

Duplicate comments:
In `@frontend/src/views/conversation/ConversationsView.vue`:
- Around line 119-127: The deleteSelected handler removes items from
searchResults but doesn't update the pagination count; inside the successful
.then() of deleteSelected (the function name), after filtering
searchResults.value, decrement totalResults.value (or the pagination total
variable) by the number of removed items (e.g., const removed =
selectedIds.value.length) and guard it to never go below zero, so the paginator
totals stay in sync with searchResults.value; leave the selectedIds reset in
.finally() as-is.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 29e0e828-4a46-4afc-9318-53a4f0920ced

📥 Commits

Reviewing files that changed from the base of the PR and between 23e111e and 84cb8e5.

📒 Files selected for processing (4)
  • backend/api/src/handlers/conversations/delete_conversations.rs
  • backend/common/src/error/mod.rs
  • backend/storage/migrations/20250312215600_initdb.sql
  • frontend/src/views/conversation/ConversationsView.vue

Comment on lines +1572 to +1574
ALTER TABLE conversations
ADD COLUMN deleted_by_sender BOOLEAN NOT NULL DEFAULT FALSE,
ADD COLUMN deleted_by_receiver BOOLEAN NOT NULL DEFAULT FALSE;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Do not evolve schema by editing a historical init migration.

Line 1572 adds new schema changes to an old migration file. That risks missing columns in already-initialized environments because this file is not replayed there. Please move this ALTER TABLE into a new forward migration and keep 20250312215600_initdb.sql immutable.

Suggested change
-ALTER TABLE conversations
-    ADD COLUMN deleted_by_sender BOOLEAN NOT NULL DEFAULT FALSE,
-    ADD COLUMN deleted_by_receiver BOOLEAN NOT NULL DEFAULT FALSE;
-- New migration file (new timestamp), e.g. backend/storage/migrations/<new>_add_conversation_soft_delete_flags.sql
ALTER TABLE conversations
    ADD COLUMN deleted_by_sender BOOLEAN NOT NULL DEFAULT FALSE,
    ADD COLUMN deleted_by_receiver BOOLEAN NOT NULL DEFAULT FALSE;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
ALTER TABLE conversations
ADD COLUMN deleted_by_sender BOOLEAN NOT NULL DEFAULT FALSE,
ADD COLUMN deleted_by_receiver BOOLEAN NOT NULL DEFAULT FALSE;
-- (previous migration content remains unchanged)
-- The ALTER TABLE statements for deleted_by_sender and deleted_by_receiver have been removed from this historical init migration
-- These changes should be added to a new forward migration file instead
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/storage/migrations/20250312215600_initdb.sql` around lines 1572 -
1574, The init migration 20250312215600_initdb.sql was edited to add two columns
(ALTER TABLE conversations ADD COLUMN deleted_by_sender BOOLEAN ... and
deleted_by_receiver ...); revert that change in the historical init file and
instead create a new forward migration (new timestamped SQL file) that runs
ALTER TABLE conversations ADD COLUMN deleted_by_sender BOOLEAN NOT NULL DEFAULT
FALSE, ADD COLUMN deleted_by_receiver BOOLEAN NOT NULL DEFAULT FALSE so existing
DBs get the change when migrations are run and the original init migration
remains immutable.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: delete conversations

2 participants