From ea989a4788200a1e5cb42b09ddfaa6f8a481f2e8 Mon Sep 17 00:00:00 2001
From: David <33458145+davidmcpowell@users.noreply.github.com>
Date: Thu, 30 Jul 2026 12:34:59 +0100
Subject: [PATCH] Merge pull request #35906 from
overleaf/dk-library-references-trashed
Soft-delete library references (move to trash)
GitOrigin-RevId: 908a4d41724300c70d56e850cdb519b7a274ad5a
---
.../web/frontend/extracted-translations.json | 8 ++
.../components/sidebar/sidebar-ds-nav.tsx | 22 ++++-
services/web/frontend/js/utils/meta.ts | 1 +
services/web/locales/en.json | 9 +++
.../sidebar/sidebar-ds-nav.test.tsx | 80 +++++++++++++++++++
5 files changed, 117 insertions(+), 3 deletions(-)
create mode 100644 services/web/test/frontend/features/project-list/components/sidebar/sidebar-ds-nav.test.tsx
diff --git a/services/web/frontend/extracted-translations.json b/services/web/frontend/extracted-translations.json
index 305817715f..f5db4c6f68 100644
--- a/services/web/frontend/extracted-translations.json
+++ b/services/web/frontend/extracted-translations.json
@@ -24,6 +24,7 @@
"about_to_archive_projects": "",
"about_to_delete_cert": "",
"about_to_delete_projects": "",
+ "about_to_delete_reference": "",
"about_to_delete_tag": "",
"about_to_delete_the_following_project": "",
"about_to_delete_the_following_projects": "",
@@ -457,6 +458,7 @@
"delete_message_confirmation": "",
"delete_permanently": "",
"delete_projects": "",
+ "delete_reference": "",
"delete_row_or_column": "",
"delete_sso_config": "",
"delete_table": "",
@@ -469,6 +471,7 @@
"deleted_by_id": "",
"deleted_by_ip": "",
"deleted_by_on": "",
+ "deleted_references_kept_in_trash_for_30_days": "",
"deleted_user": "",
"deleting": "",
"demonstrating_git_integration": "",
@@ -1345,6 +1348,7 @@
"no_selection_select_file": "",
"no_symbols_found": "",
"no_thanks_cancel_now": "",
+ "no_trashed_references": "",
"non_blinking_cursor": "",
"normal": "",
"normally_x_price_per_month": "",
@@ -1635,6 +1639,7 @@
"reference_manager_searched_groups": "",
"reference_manager_unlinked": "",
"reference_managers": "",
+ "reference_moved_to_trash": "",
"reference_search": "",
"reference_search_setting": "",
"reference_search_settings": "",
@@ -2251,11 +2256,13 @@
"trash_projects": "",
"trashed": "",
"trashed_projects": "",
+ "trashed_references": "",
"trashing_projects_wont_affect_collaborators": "",
"trial_last_day": "",
"trial_remaining_days": "",
"tried_to_log_in_with_email": "",
"tried_to_register_with_email": "",
+ "try_a_different_term": "",
"try_a_different_term_or_add_a_new_reference": "",
"try_again": "",
"try_for_free": "",
@@ -2418,6 +2425,7 @@
"view_options": "",
"view_payment_portal": "",
"view_payment_portal_disclaimer": "",
+ "view_trash": "",
"view_your_invoices": "",
"viewer": "",
"viewing": "",
diff --git a/services/web/frontend/js/features/project-list/components/sidebar/sidebar-ds-nav.tsx b/services/web/frontend/js/features/project-list/components/sidebar/sidebar-ds-nav.tsx
index 57bf3a7c5d..4e59a60619 100644
--- a/services/web/frontend/js/features/project-list/components/sidebar/sidebar-ds-nav.tsx
+++ b/services/web/frontend/js/features/project-list/components/sidebar/sidebar-ds-nav.tsx
@@ -15,12 +15,26 @@ import { useProjectListContext } from '@/features/project-list/context/project-l
import importOverleafModules from '../../../../../macros/import-overleaf-module.macro'
import { ActivePage } from '../../util/navigation-state'
-function SidebarDsNav({ activePage }: { activePage: ActivePage }) {
+function SidebarDsNav({
+ activePage,
+ trashActive = false,
+}: {
+ activePage: ActivePage
+
+ /**
+ * Whether the trash is active. This is only relevant when the active page is
+ * "library" as which project page is active is determined by the selected filter.
+ */
+ trashActive?: boolean
+}) {
const { t } = useTranslation()
const { show: showAddAffiliationWidget } = useAddAffiliation()
const isLibraryEnabled = isSplitTestEnabled('overleaf-library')
const { filter, selectedTagId, selectFilter } = useProjectListContext()
- const isTrashActive = selectedTagId === undefined && filter === 'trashed'
+ const isTrashActive =
+ activePage === 'library'
+ ? trashActive
+ : selectedTagId === undefined && filter === 'trashed'
const [dsNavLibraryLinkModule] = importOverleafModules('dsNavLibraryLink')
const DsNavLibraryLink: JSXElementConstructor<{ active?: boolean }> =
dsNavLibraryLinkModule?.import.default
@@ -69,7 +83,9 @@ function SidebarDsNav({ activePage }: { activePage: ActivePage }) {
{isLibraryEnabled && (
<>
{DsNavLibraryLink && (
-
+
)}