stop search button
Massimo Melina committed
Dec 22, 2021 at 23:38 UTC
46cbf83cf0558f98ee5d710bc5fdab7575c978db
7 files changed
+36
-12
frontend/src/Head.ts
+21
-8
@@ -2,7 +2,7 @@ import { createElement as h, Fragment, useContext, useMemo, useState } from 'rea
2
import { Link, useLocation } from 'react-router-dom'
3
import { ListContext } from './BrowseFiles'
4
import { login, logout } from './login'
5
-import { formatBytes, hIcon, prefix } from './misc'
5
+import { formatBytes, hIcon, prefix, wait } from './misc'
6
import { Spinner } from './components'
7
import { state, useSnapState } from './state'
8
import { useDebounce } from 'use-debounce'
@@ -22,7 +22,7 @@ function MenuPanel() {
22
;[state.listFilter] = useDebounce(filter, 300)
23
if (!showFilter)
24
state.listFilter = ''
25
- const { remoteSearch } = useSnapState()
25
+ const { remoteSearch, stopSearch } = useSnapState()
26
return h('div', { id:'menu-panel' },
27
h('div', { id:'menu-bar' },
28
h(LoginButton),
@@ -37,10 +37,23 @@ function MenuPanel() {
37
h(MenuButton, {
38
icon: 'search',
39
label: 'Search',
40
- onClick() {
40
+ async onClick() {
41
const res = prompt('Search for...')
42
- if (res !== null)
43
- state.remoteSearch = res
42
+ if (res === null) return
43
+ if (state.stoppedSearch) {
44
+ state.remoteSearch = ''
45
+ await wait(500)
46
+ }
47
+ stopSearch?.()
48
+ state.remoteSearch = res
49
+ }
50
+ }),
51
+ stopSearch && h(MenuButton, {
52
+ icon: 'stop',
53
+ label: 'Stop list',
54
+ onClick() {
55
+ stopSearch()
56
+ state.stoppedSearch = true
57
}
58
})
59
),
@@ -98,14 +111,14 @@ function FolderStats() {
111
}
112
return { files, folders, size }
113
}, [list])
101
- const snap = useSnapState()
114
+ const { filteredEntries, stoppedSearch } = useSnapState()
115
return h('div', { id:'folder-stats' },
103
- unfinished && h(Spinner),
116
+ stoppedSearch ? hIcon('interrupted') : unfinished && h(Spinner),
117
[
118
prefix('', stats.files,' file(s)'),
119
prefix('', stats.folders, ' folder(s)'),
120
stats.size ? formatBytes(stats.size) : '',
108
- snap.filteredEntries >= 0 && snap.filteredEntries+' displayed',
121
+ filteredEntries >= 0 && filteredEntries+' displayed',
122
].filter(Boolean).join(', ')
123
)
124
}
frontend/src/components.ts
+1
-1
@@ -1,6 +1,6 @@
1
import { hIcon } from './misc'
2
3
export function Spinner() {
4
- return hIcon('spinner', { style: { animation:'1s spin infinite' } })
4
+ return hIcon('spinner', { className:'spinner' })
5
}
6
frontend/src/icons.ts
+4
-3
@@ -8,6 +8,7 @@ const SYS_ICONS: Record<string,string> = {
8
file: 'description',
9
spinner: 'sports_baseball',
10
filter: 'filter_alt',
11
+ interrupted: 'heart_broken',
12
}
13
14
document.fonts.ready.then(async ()=> {
@@ -17,12 +18,12 @@ document.fonts.ready.then(async ()=> {
18
state.iconsClass = name.replace(/ /g,'-').toLowerCase()
19
})
20
20
-export function Icon({ name, ...props }: { name:string, style?:any }) {
21
+export function Icon({ name, className, ...props }: { name:string, className?:string, style?:any }) {
22
name = SYS_ICONS[name] || name
23
const { iconsClass } = useSnapState()
24
return h('span',{
24
- className: iconsClass+' icon',
25
- ...props
25
+ ...props,
26
+ className: iconsClass+' icon '+className,
27
}, iconsClass ? name : '#')
28
}
29
frontend/src/index.scss
+7
@@ -53,6 +53,10 @@ header {
53
to { transform: rotate(360deg); }
54
}
55
56
+.spinner {
57
+ animation: 1s spin infinite;
58
+}
59
+
60
.breadcrumb {
61
padding: 0.1em 0.6em 0.2em;
62
border-radius: 0.7em;
@@ -68,6 +72,9 @@ header {
72
padding: 0.1em 0.3em;
73
margin: 0.2em 0.5em;
74
float: right;
75
+ & .icon {
76
+ margin-right: .3em;
77
+ }
78
}
79
header input {
80
width: 100%;
frontend/src/state.ts
+1
@@ -2,6 +2,7 @@ import { proxy, useSnapshot } from 'valtio'
2
3
export const state = proxy<{
4
stopSearch?: ()=>void,
5
+ stoppedSearch?: boolean,
6
iconsClass: string,
7
username: string,
8
listFilter: string,
frontend/src/useFetchList.ts
+1
@@ -19,6 +19,7 @@ export default function useFetchList() {
19
}
20
const previous = lastPath.current
21
lastPath.current = desiredPath
22
+ state.stoppedSearch = false
23
if (previous !== desiredPath && search) {
24
state.remoteSearch = ''
25
state.stopSearch?.()
src/index.ts
+1
@@ -54,6 +54,7 @@ srv.use(async (ctx, next) => {
54
55
srv.on('error', err => {
56
if (DEV && err.code === 'ENOENT' && err.path.endsWith('sockjs-node')) return // spam out
57
+ if (err.code === 'ECONNRESET') return // someone interrupted, don't care
58
console.error('server error', err)
59
})
60
srv.listen(PORT, ()=> console.log('running on port', PORT, DEV, new Date().toLocaleString()))