mirror of
https://github.com/narrrl/narl-workspace.git
synced 2026-11-04 08:57:00 +01:00
trash: a delete can be undone
`x`, `dd`, `:delete` and `:rmspace` no longer end anything. What they delete is moved, whole, under one hidden root, and `u` puts the last of it back where it was. `:trash` lists everything deleted, the last first: Enter or `r` restores, `x` deletes one for good and `:trash purge` empties it, each asking first. Something whose folder has gone since comes back to the root of its space; something whose space is in the trash too waits for the space. The daily sweep purges what has waited WORKSPACE_TRASH_DAYS (30), and only then are its files deleted. While it waits, a trashed node is out of the tree, the search, the agenda, the mails, the SFTP mount, the export and the readable files/ view, and a shared document answers 404 until it comes back with the same link. `rm` over the mount trashes too; a rename onto a taken name still replaces what was there, so editor saves do not fill the trash.
This commit is contained in:
1 parent
439d5b083b
commit
8ffad6350f
22 files changed
+1154
-78
No files matched your search
+42
-1
@@ -14,6 +14,7 @@
|
||||
import Login from './lib/Login.svelte'
|
||||
import Overview from './lib/Overview.svelte'
|
||||
import MediaBrowser, { copyMedia, insertMedia, removeMedia } from './lib/MediaBrowser.svelte'
|
||||
import Trash, { purgeTrashed, restoreTrashed } from './lib/Trash.svelte'
|
||||
import Actions from './lib/Actions.svelte'
|
||||
import Prompt from './lib/Prompt.svelte'
|
||||
import SecretPrompt from './lib/SecretPrompt.svelte'
|
||||
@@ -391,6 +392,35 @@
|
||||
}
|
||||
}
|
||||
|
||||
/** The trash's keys: j/k down what was deleted, Enter or r restores, x deletes for good. */
|
||||
function trashKey(event: KeyboardEvent): boolean {
|
||||
const items = workspace.trash
|
||||
const last = Math.max(items.length - 1, 0)
|
||||
const item = items[workspace.trashCursor]
|
||||
switch (event.key) {
|
||||
case 'j':
|
||||
case 'ArrowDown':
|
||||
workspace.trashCursor = Math.min(workspace.trashCursor + 1, last)
|
||||
return true
|
||||
case 'k':
|
||||
case 'ArrowUp':
|
||||
workspace.trashCursor = Math.max(workspace.trashCursor - 1, 0)
|
||||
return true
|
||||
case 'G':
|
||||
workspace.trashCursor = last
|
||||
return true
|
||||
case 'Enter':
|
||||
case 'r':
|
||||
if (item) void restoreTrashed(item)
|
||||
return true
|
||||
case 'x':
|
||||
if (item) void purgeTrashed(item)
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* `F`: the hints are pinned where the targets are, so a pane still sliding
|
||||
* in — a space switch, the board just opened — is let settle first.
|
||||
@@ -578,6 +608,12 @@
|
||||
return
|
||||
}
|
||||
}
|
||||
if (workspace.overlay === 'trash' && listening && !event.ctrlKey && !event.metaKey && !event.altKey) {
|
||||
if (trashKey(event)) {
|
||||
event.preventDefault()
|
||||
return
|
||||
}
|
||||
}
|
||||
if (workspace.overlay === 'outline' && listening && !event.ctrlKey && !event.metaKey && !event.altKey) {
|
||||
if (outlineKey(event)) {
|
||||
event.preventDefault()
|
||||
@@ -862,6 +898,11 @@
|
||||
event.preventDefault()
|
||||
void runCommand('d')
|
||||
break
|
||||
case 'u':
|
||||
// A delete goes to the trash, so it can be undone the way vim undoes.
|
||||
event.preventDefault()
|
||||
void workspace.guard(() => workspace.undoDelete())
|
||||
break
|
||||
case 's':
|
||||
// Sharing is a key away; taking a link back from its readers asks first.
|
||||
event.preventDefault()
|
||||
@@ -1000,7 +1041,7 @@
|
||||
<!-- svelte-ignore a11y_click_events_have_key_events, a11y_no_static_element_interactions, a11y_no_noninteractive_tabindex -->
|
||||
<div class="overlay" tabindex="-1" bind:this={overlayEl} onclick={(e) => e.target === e.currentTarget && (workspace.overlay = 'none')}
|
||||
>
|
||||
{#if workspace.overlay === 'help'}<Help />{:else if workspace.overlay === 'overview'}<Overview />{:else if workspace.overlay === 'agenda'}<Agenda />{:else if workspace.overlay === 'actions'}<Actions />{:else if workspace.overlay === 'verify'}<Verify />{:else if workspace.overlay === 'outline'}<Headings />{:else}<MediaBrowser />{/if}
|
||||
{#if workspace.overlay === 'help'}<Help />{:else if workspace.overlay === 'overview'}<Overview />{:else if workspace.overlay === 'agenda'}<Agenda />{:else if workspace.overlay === 'actions'}<Actions />{:else if workspace.overlay === 'verify'}<Verify />{:else if workspace.overlay === 'outline'}<Headings />{:else if workspace.overlay === 'trash'}<Trash />{:else}<MediaBrowser />{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user