Cover Files duplicate context action
This commit is contained in:
parent
5c47ca2480
commit
03dbede414
|
|
@ -156,6 +156,22 @@ test.describe('G: Files Plugin', () => {
|
|||
await expect(page.locator('[data-file-name="CutMe"]')).toHaveCount(0);
|
||||
});
|
||||
|
||||
test('files explorer duplicates a file from the context menu', async ({ page }) => {
|
||||
await page.locator('.wt-label').filter({ hasText: 'Project' }).click();
|
||||
await openFilesTool(page);
|
||||
await expect(page.locator('.files-breadcrumb')).toContainText('Project', { timeout: 10000 });
|
||||
|
||||
await page.locator('[data-file-name="project-only.txt"]').click({ button: 'right' });
|
||||
await page.locator('[data-files-menu-action="duplicate"]').click();
|
||||
|
||||
await expect(page.locator('[data-file-name="project-only.txt"]')).toBeVisible();
|
||||
await expect(page.locator('[data-file-name="project-only (copy).txt"]')).toBeVisible();
|
||||
|
||||
await page.locator('[data-file-name="project-only.txt"]').click({ button: 'right' });
|
||||
await page.locator('[data-files-menu-action="duplicate"]').click();
|
||||
await expect(page.locator('[data-file-name="project-only (copy 2).txt"]')).toBeVisible();
|
||||
});
|
||||
|
||||
test('files explorer supports multiselect and internal drag/drop move', async ({ page }) => {
|
||||
await page.locator('.wt-label').filter({ hasText: 'Project' }).click();
|
||||
await openFilesTool(page);
|
||||
|
|
|
|||
|
|
@ -897,6 +897,30 @@
|
|||
function cutSelection() { setClipboard('cut', selectedEntries()); }
|
||||
function copySelection() { setClipboard('copy', selectedEntries().filter(function (item) { return item.type !== 'folder'; })); }
|
||||
function uniqueName(name, occupied) { if (!occupied[name]) return name; var dot = name.lastIndexOf('.'); var b = dot > 0 ? name.slice(0, dot) : name; var x = dot > 0 ? name.slice(dot) : ''; for (var i = 2; i < 100; i++) { var c = b + ' (' + i + ')' + x; if (!occupied[c]) return c; } return b + ' (' + Date.now() + ')' + x; }
|
||||
function duplicate(item) {
|
||||
if (!item || item.type === 'folder') return;
|
||||
var dot = item.name.lastIndexOf('.');
|
||||
var stem = dot > 0 ? item.name.slice(0, dot) : item.name;
|
||||
var extension = dot > 0 ? item.name.slice(dot) : '';
|
||||
var folder = parent(item.relativePath);
|
||||
var maxAttempts = 100;
|
||||
function candidatePath(n) {
|
||||
var name = n === 1 ? stem + ' (copy)' + extension : stem + ' (copy ' + n + ')' + extension;
|
||||
return folder ? folder + '/' + name : name;
|
||||
}
|
||||
function tryDuplicate(n) {
|
||||
var target = candidatePath(n);
|
||||
return api.files.metadata(target).then(function () {
|
||||
if (n >= maxAttempts) return Promise.reject(new Error('all duplicate names are taken'));
|
||||
return tryDuplicate(n + 1);
|
||||
}, function () {
|
||||
return api.files.readText(item.relativePath).then(function (text) {
|
||||
return api.files.writeText(target, text, { createIfMissing: true, overwrite: false });
|
||||
});
|
||||
});
|
||||
}
|
||||
tryDuplicate(1).then(load).catch(function (err) { console.error('[files] Duplicate failed:', err); });
|
||||
}
|
||||
function paste() {
|
||||
var clip = window.__filesClipboard;
|
||||
if (!clip || !clip.items || !clip.items.length) return;
|
||||
|
|
@ -920,6 +944,7 @@
|
|||
if (!selected[item.relativePath]) { selected = {}; selected[item.relativePath] = true; render(); }
|
||||
menu.appendChild(menuItem('Open', 'open', function () { open(item); }));
|
||||
menu.appendChild(menuItem('Rename', 'rename', function () { startRename(item); }));
|
||||
if (item.type !== 'folder') menu.appendChild(menuItem('Duplicate', 'duplicate', function () { duplicate(item); }));
|
||||
menu.appendChild(menuItem('Cut', 'cut', cutSelection));
|
||||
menu.appendChild(menuItem('Copy', 'copy', copySelection));
|
||||
menu.appendChild(menuItem('Trash', 'trash', trashSelection));
|
||||
|
|
|
|||
Loading…
Reference in New Issue