feat: show files trash metadata
This commit is contained in:
parent
10bc28cef7
commit
67ac99c24d
|
|
@ -312,6 +312,8 @@
|
|||
var disposed = false;
|
||||
var fileActions = [];
|
||||
var contextMenuEntries = [];
|
||||
var showingTrash = false;
|
||||
var trashEntries = [];
|
||||
var historyStack = Array.isArray(savedHistory.stack) && savedHistory.stack.length ? savedHistory.stack.map(cleanPath) : [currentPath];
|
||||
var historyIndex = Math.max(0, Math.min(Number(savedHistory.index) || 0, historyStack.length - 1));
|
||||
if (historyStack[historyIndex] !== currentPath) {
|
||||
|
|
@ -337,13 +339,14 @@
|
|||
var backBtn = iconButton('back', 'Back', 'back', goBack);
|
||||
var forwardBtn = iconButton('forward', 'Forward', 'forward', goForward);
|
||||
var upBtn = iconButton('up', 'Up', 'up', goUp);
|
||||
var refreshBtn = iconButton('refresh', 'Refresh', 'refresh', loadEntries);
|
||||
var refreshBtn = iconButton('refresh', 'Refresh', 'refresh', function () { if (showingTrash) loadTrashEntries(); else loadEntries(); });
|
||||
var newFolderBtn = iconButton('new-folder', 'New folder', 'folderAdd', function () { startCreate('folder'); });
|
||||
var newMdBtn = iconButton('new-markdown', 'New markdown file', 'markdownAdd', function () { startCreate('markdown'); });
|
||||
var newTextBtn = iconButton('new-text', 'New text file', 'textAdd', function () { startCreate('text'); });
|
||||
var openBtn = iconButton('open', 'Open', 'open', function () { openEntry(selectedEntry()); });
|
||||
var renameBtn = iconButton('rename', 'Rename', 'rename', function () { beginRename(); });
|
||||
var trashBtn = iconButton('trash', 'Move to trash', 'trash', function () { trashEntry(); });
|
||||
var trashViewBtn = iconButton('trash-view', 'Trash metadata', 'trash', function () { loadTrashEntries(); });
|
||||
var cutBtn = iconButton('cut', 'Cut', 'cut', function () { cutSelection(); });
|
||||
var copyBtn = iconButton('copy', 'Copy', 'copy', function () { copySelection(); });
|
||||
var pasteBtn = iconButton('paste', 'Paste', 'paste', function () { pasteEntry(); });
|
||||
|
|
@ -356,7 +359,7 @@
|
|||
el('option', { value: 'size-desc' }, ['Size'])
|
||||
]);
|
||||
toolbar.appendChild(breadcrumb);
|
||||
[backBtn, forwardBtn, upBtn, refreshBtn, newFolderBtn, newMdBtn, newTextBtn, openBtn, renameBtn, trashBtn, cutBtn, copyBtn, pasteBtn, filterInput, sortSelect].forEach(function (node) { toolbar.appendChild(node); });
|
||||
[backBtn, forwardBtn, upBtn, refreshBtn, newFolderBtn, newMdBtn, newTextBtn, openBtn, renameBtn, trashBtn, trashViewBtn, cutBtn, copyBtn, pasteBtn, filterInput, sortSelect].forEach(function (node) { toolbar.appendChild(node); });
|
||||
containerEl.appendChild(toolbar);
|
||||
|
||||
var listContainer = el('div', { className: 'files-list', 'data-files-list': '' });
|
||||
|
|
@ -398,13 +401,16 @@
|
|||
|
||||
function updateButtons() {
|
||||
var count = selectedCount();
|
||||
upBtn.disabled = !currentPath;
|
||||
openBtn.disabled = count !== 1;
|
||||
renameBtn.disabled = count !== 1;
|
||||
trashBtn.disabled = count === 0;
|
||||
cutBtn.disabled = count === 0;
|
||||
copyBtn.disabled = count === 0;
|
||||
pasteBtn.disabled = !(window.__filesClipboard && window.__filesClipboard.items && window.__filesClipboard.items.length);
|
||||
upBtn.disabled = showingTrash || !currentPath;
|
||||
newFolderBtn.disabled = showingTrash;
|
||||
newMdBtn.disabled = showingTrash;
|
||||
newTextBtn.disabled = showingTrash;
|
||||
openBtn.disabled = showingTrash || count !== 1;
|
||||
renameBtn.disabled = showingTrash || count !== 1;
|
||||
trashBtn.disabled = showingTrash || count === 0;
|
||||
cutBtn.disabled = showingTrash || count === 0;
|
||||
copyBtn.disabled = showingTrash || count === 0;
|
||||
pasteBtn.disabled = showingTrash || !(window.__filesClipboard && window.__filesClipboard.items && window.__filesClipboard.items.length);
|
||||
}
|
||||
|
||||
function updateHistoryButtons() {
|
||||
|
|
@ -509,6 +515,7 @@
|
|||
}
|
||||
|
||||
function renderList() {
|
||||
showingTrash = false;
|
||||
listContainer.innerHTML = '';
|
||||
var header = el('div', { className: 'files-header' }, [
|
||||
el('span', {}, ['Name']),
|
||||
|
|
@ -571,7 +578,45 @@
|
|||
updateButtons();
|
||||
}
|
||||
|
||||
function renderTrashList() {
|
||||
listContainer.innerHTML = '';
|
||||
breadcrumb.innerHTML = '';
|
||||
breadcrumb.appendChild(el('span', { className: 'files-breadcrumb-current' }, ['Trash metadata']));
|
||||
selectedPaths = {};
|
||||
lastClickedPath = '';
|
||||
|
||||
var header = el('div', { className: 'files-header' }, [
|
||||
el('span', {}, ['Original path']),
|
||||
el('span', {}, ['Type']),
|
||||
el('span', {}, ['Deleted']),
|
||||
el('span', {}, ['Trash ID']),
|
||||
el('span', {}, ['Trash path'])
|
||||
]);
|
||||
listContainer.appendChild(header);
|
||||
|
||||
if (!trashEntries || trashEntries.length === 0) {
|
||||
listContainer.appendChild(el('div', { className: 'files-empty' }, ['Trash is empty']));
|
||||
updateButtons();
|
||||
return;
|
||||
}
|
||||
|
||||
trashEntries.forEach(function (entry) {
|
||||
listContainer.appendChild(el('div', {
|
||||
className: 'files-item',
|
||||
'data-files-trash-id': entry.trashId || ''
|
||||
}, [
|
||||
el('span', { className: 'files-item-name', textContent: entry.originalPath || entry.basename || '', title: entry.originalPath || '' }),
|
||||
el('span', { className: 'files-item-meta' }, [entry.originalType || '']),
|
||||
el('span', { className: 'files-item-meta hide-narrow' }, [formatDate(entry.deletedAt)]),
|
||||
el('span', { className: 'files-item-meta hide-narrow' }, [entry.trashId || '']),
|
||||
el('span', { className: 'files-item-meta' }, [entry.trashPath || ''])
|
||||
]));
|
||||
});
|
||||
updateButtons();
|
||||
}
|
||||
|
||||
function loadEntries() {
|
||||
showingTrash = false;
|
||||
selectedPaths = {};
|
||||
lastClickedPath = '';
|
||||
listContainer.innerHTML = '';
|
||||
|
|
@ -591,6 +636,36 @@
|
|||
});
|
||||
}
|
||||
|
||||
function loadTrashEntries() {
|
||||
showingTrash = true;
|
||||
selectedPaths = {};
|
||||
lastClickedPath = '';
|
||||
listContainer.innerHTML = '';
|
||||
listContainer.appendChild(el('div', { className: 'files-loading' }, ['Loading...']));
|
||||
if (!api.files || typeof api.files.listTrash !== 'function') {
|
||||
trashEntries = [];
|
||||
listContainer.innerHTML = '';
|
||||
listContainer.appendChild(el('div', { className: 'files-error' }, [
|
||||
el('div', {}, ['Trash metadata is unavailable'])
|
||||
]));
|
||||
updateButtons();
|
||||
return;
|
||||
}
|
||||
api.files.listTrash().then(function (result) {
|
||||
if (disposed) return;
|
||||
trashEntries = result || [];
|
||||
renderTrashList();
|
||||
}).catch(function (err) {
|
||||
if (disposed) return;
|
||||
listContainer.innerHTML = '';
|
||||
listContainer.appendChild(el('div', { className: 'files-error' }, [
|
||||
el('div', {}, ['Failed to load trash metadata']),
|
||||
el('div', { className: 'files-error-msg' }, [(err && err.message) ? err.message : String(err)])
|
||||
]));
|
||||
updateButtons();
|
||||
});
|
||||
}
|
||||
|
||||
function contributionContextMatches(item, entry) {
|
||||
var context = String(item && item.context || '').toLowerCase();
|
||||
if (!context || context === '*' || context === 'files' || context === 'vault-entry') return true;
|
||||
|
|
|
|||
|
|
@ -218,6 +218,14 @@ function makeApi() {
|
|||
createFolder: async () => undefined,
|
||||
move: async () => undefined,
|
||||
trash: async () => undefined,
|
||||
listTrash: async () => [{
|
||||
originalPath: 'Docs/deleted.md',
|
||||
trashPath: '.verstak/trash/files/mock/deleted.md',
|
||||
trashId: 'mock-trash',
|
||||
deletedAt: '2026-06-27T01:02:03Z',
|
||||
originalType: 'file',
|
||||
basename: 'deleted.md',
|
||||
}],
|
||||
openExternal: async (relativePath) => { externalCalls.push({ action: 'open', path: relativePath }); },
|
||||
showInFolder: async (relativePath) => { externalCalls.push({ action: 'show', path: relativePath }); },
|
||||
},
|
||||
|
|
@ -308,6 +316,15 @@ async function flush() {
|
|||
throw new Error(`expected provider file action call, got ${JSON.stringify(api.contributionCalls)}`);
|
||||
}
|
||||
|
||||
const trashViewButton = walk(container, (node) => node.getAttribute && node.getAttribute('data-files-action') === 'trash-view');
|
||||
if (!trashViewButton) throw new Error('trash metadata toolbar button not found');
|
||||
trashViewButton.click();
|
||||
await flush();
|
||||
const trashRow = walk(container, (node) => node.getAttribute && node.getAttribute('data-files-trash-id') === 'mock-trash');
|
||||
if (!trashRow || !trashRow.textContent.includes('Docs/deleted.md')) {
|
||||
throw new Error(`trash metadata row not rendered: ${container.textContent}`);
|
||||
}
|
||||
|
||||
console.log('files frontend smoke passed');
|
||||
})().catch((err) => {
|
||||
console.error(err);
|
||||
|
|
|
|||
Loading…
Reference in New Issue