feat(trash): move trash API to normalized version (with cursor, orderBy) + normalize Trash section to existing components
normalize also component to format badges (expiry, role, etc)
This commit is contained in:
@@ -18,6 +18,7 @@ import { recent } from '../features/library/recent.js';
|
||||
import { fileSharing } from '../features/sharing/fileSharing.js';
|
||||
import { grants } from '../model/grants.js';
|
||||
import { recentView } from '../views/recent/recentView.js';
|
||||
import { trashView } from '../views/trash/trashView.js';
|
||||
import { checkAuthentication } from './authSession.js';
|
||||
import { loadFiles } from './filesView.js';
|
||||
import {
|
||||
@@ -34,7 +35,6 @@ import {
|
||||
} from './navigation.js';
|
||||
import { performSearch } from './searchView.js';
|
||||
import { app, appElements as elements } from './state.js';
|
||||
import { loadTrashItems } from './trashView.js';
|
||||
import { ui } from './ui.js';
|
||||
import { setupUserMenu } from './userMenu.js';
|
||||
|
||||
@@ -362,7 +362,7 @@ function setupActionsBarDelegation() {
|
||||
break;
|
||||
case 'empty-trash-btn':
|
||||
if (await fileOps.emptyTrash()) {
|
||||
loadTrashItems();
|
||||
await trashView.init();
|
||||
}
|
||||
break;
|
||||
case 'clear-recent-btn':
|
||||
|
||||
@@ -15,10 +15,10 @@ import { favoritesView } from '../views/favorites/favoritesView.js';
|
||||
import { mySharesView } from '../views/myShares/mySharesView.js';
|
||||
import { recentView } from '../views/recent/recentView.js';
|
||||
import { sharedWithMeView } from '../views/sharedWithMe/sharedWithMeView.js';
|
||||
import { trashView } from '../views/trash/trashView.js';
|
||||
import { filesView, loadFiles, refreshSharedBadges } from './filesView.js';
|
||||
import { setActionsBarMode, setGroupByView, syncGroupByMenu } from './main.js';
|
||||
import { app, appElements } from './state.js';
|
||||
import { loadTrashItems } from './trashView.js';
|
||||
import { ui } from './ui.js';
|
||||
|
||||
/**
|
||||
@@ -186,6 +186,11 @@ function setCurrentSection(section) {
|
||||
recentView.hide();
|
||||
}
|
||||
|
||||
// Hide trashView "Load more" button when leaving the trash section
|
||||
if (section !== 'trash' && trashView) {
|
||||
trashView.hide();
|
||||
}
|
||||
|
||||
// Reset owner column — sections that need it re-enable it explicitly below.
|
||||
ui.setOwnerColumnVisible(false);
|
||||
|
||||
@@ -410,8 +415,8 @@ function switchToTrashSection() {
|
||||
toggleFileContainer(true);
|
||||
|
||||
setActionsBarMode('trash');
|
||||
setGroupByView(null);
|
||||
syncGroupByMenu([]);
|
||||
setGroupByView(trashView);
|
||||
syncGroupByMenu(trashView.groupByDefs);
|
||||
|
||||
//reset files view + remove any error
|
||||
ui.resetFilesList();
|
||||
@@ -420,8 +425,8 @@ function switchToTrashSection() {
|
||||
restoreView('trash');
|
||||
syncViewContainers();
|
||||
|
||||
// Load trash items
|
||||
loadTrashItems();
|
||||
// Load trash items (cursor-based view)
|
||||
trashView.init();
|
||||
|
||||
if (batchToolbar) batchToolbar.clear();
|
||||
}
|
||||
|
||||
@@ -1,132 +0,0 @@
|
||||
/**
|
||||
* Trash view loading and rendering logic
|
||||
*/
|
||||
|
||||
import { escapeHtml, formatDateTime } from '../core/formatters.js';
|
||||
import { i18n } from '../core/i18n.js';
|
||||
import { batchToolbar } from '../features/files/batchToolbar.js';
|
||||
import { fileOps } from '../features/files/fileOperations.js';
|
||||
import * as itemTooltip from '../features/itemTooltip.js';
|
||||
import { appElements } from './state.js';
|
||||
import { ui } from './ui.js';
|
||||
|
||||
/** Categories whose items have a server-side thumbnail. */
|
||||
const THUMBNAILABLE = new Set(['image', 'video', 'pdf']);
|
||||
|
||||
/**
|
||||
*
|
||||
* @import {TrashItem} from '../core/types.js'
|
||||
*/
|
||||
|
||||
async function loadTrashItems() {
|
||||
const elements = appElements;
|
||||
|
||||
try {
|
||||
if (batchToolbar) batchToolbar.clear();
|
||||
itemTooltip.destroy(elements.filesList);
|
||||
ui.resetFilesList(); // ensure also list visible & error hidden
|
||||
elements.filesList.innerHTML = `
|
||||
<div class="list-header trash-header">
|
||||
<div data-i18n="files.name">${i18n.t('files.name')}</div>
|
||||
<div data-i18n="files.type">${i18n.t('files.type')}</div>
|
||||
<div data-i18n="trash.original_location">${i18n.t('trash.original_location')}</div>
|
||||
<div data-i18n="trash.deleted_date">${i18n.t('trash.deleted_date')}</div>
|
||||
<div data-i18n="trash.actions">${i18n.t('trash.actions')}</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
ui.updateBreadcrumb();
|
||||
|
||||
const trashItems = await fileOps.getTrashItems();
|
||||
|
||||
if (trashItems.length === 0) {
|
||||
ui.showError(`
|
||||
<i class="fas fa-trash empty-state-icon"></i>
|
||||
<p>${i18n.t('trash.empty_state')}</p>
|
||||
`);
|
||||
return;
|
||||
}
|
||||
|
||||
trashItems.forEach((item) => {
|
||||
addTrashItemToView(item);
|
||||
});
|
||||
itemTooltip.init(elements.filesList);
|
||||
} catch (error) {
|
||||
console.error('Error loading trash items:', error);
|
||||
ui.showNotification('Error', 'Error loading trash items');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {TrashItem} item
|
||||
*/
|
||||
function addTrashItemToView(item) {
|
||||
const elements = appElements;
|
||||
const isFile = item.item_type === 'file';
|
||||
|
||||
const formattedDate = formatDateTime(item.trashed_at);
|
||||
|
||||
let iconClass;
|
||||
let typeLabel;
|
||||
let iconSpecialClass = '';
|
||||
if (!isFile) {
|
||||
iconClass = item.icon_class || 'fas fa-folder';
|
||||
typeLabel = i18n.t('files.file_types.folder');
|
||||
} else {
|
||||
iconClass = item.icon_class || (ui?.getIconClass ? ui.getIconClass(item.name) : 'fas fa-file');
|
||||
iconSpecialClass = ui?.getIconSpecialClass ? ui.getIconSpecialClass(item.name) : '';
|
||||
const cat = item.category || '';
|
||||
typeLabel = cat ? i18n.t(`files.file_types.${cat.toLowerCase()}`) || cat : i18n.t('files.file_types.document');
|
||||
}
|
||||
|
||||
const isFolder = !isFile;
|
||||
const iconWrapClass = isFolder ? 'file-icon folder-icon' : `file-icon ${iconSpecialClass}`.trim();
|
||||
const canThumbnail = isFile && THUMBNAILABLE.has((item.category || '').toLowerCase());
|
||||
|
||||
const listElement = document.createElement('div');
|
||||
listElement.className = 'file-item trash-item';
|
||||
listElement.dataset.trashId = item.id;
|
||||
listElement.dataset.originalId = item.original_id;
|
||||
listElement.dataset.itemType = item.item_type;
|
||||
if (item.original_path) listElement.dataset.path = item.original_path;
|
||||
|
||||
listElement.innerHTML = `
|
||||
<div class="name-cell">
|
||||
<div class="${iconWrapClass}">
|
||||
<i class="${iconClass}"></i>
|
||||
${canThumbnail ? `<img class="file-thumb" src="/api/files/${item.original_id}/thumbnail/icon" loading="lazy" alt="">` : ''}
|
||||
</div>
|
||||
<span>${escapeHtml(item.name)}</span>
|
||||
</div>
|
||||
<div class="type-cell">${escapeHtml(typeLabel)}</div>
|
||||
<div class="path-cell">${escapeHtml(item.original_path || '--')}</div>
|
||||
<div class="date-cell">${escapeHtml(formattedDate)}</div>
|
||||
<div class="actions-cell">
|
||||
<button class="btn-restore" title="${i18n.t('trash.restore')}">
|
||||
<i class="fas fa-undo"></i>
|
||||
</button>
|
||||
<button class="btn-delete" title="${i18n.t('trash.delete_permanently')}">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
listElement.querySelector('.btn-restore').addEventListener('click', async (e) => {
|
||||
e.stopPropagation();
|
||||
if (await fileOps.restoreFromTrash(item.id)) {
|
||||
loadTrashItems();
|
||||
}
|
||||
});
|
||||
|
||||
listElement.querySelector('.btn-delete').addEventListener('click', async (e) => {
|
||||
e.stopPropagation();
|
||||
if (await fileOps.deletePermanently(item.id)) {
|
||||
loadTrashItems();
|
||||
}
|
||||
});
|
||||
|
||||
elements.filesList.appendChild(listElement);
|
||||
}
|
||||
|
||||
export { loadTrashItems };
|
||||
Reference in New Issue
Block a user