comment command in file menu
Massimo Melina committed
Sep 25, 2023 at 12:02 UTC
f39972de4f07c000d0c89a0a3ebdc9593ce36c32
8 files changed
+48
-16
frontend/src/fileMenu.ts
+14
@@ -10,6 +10,7 @@ import { fileShow, getShowType } from './show'
10
import { alertDialog, promptDialog } from './dialog'
11
import { apiCall, useApi } from '@hfs/shared/api'
12
import { navigate } from './App'
13
+import { inputComment } from './upload'
14
15
interface FileMenuEntry {
16
id?: string
@@ -25,6 +26,7 @@ export function openFileMenu(entry: DirEntry, ev: MouseEvent, addToMenu: (FileMe
26
const cantDownload = entry.cantOpen || isFolder && entry.p?.includes('r') // folders needs both list and read
27
const menu = [
28
!cantDownload && { id: 'download', label: t`Download`, href: uri + (isFolder ? '?get=zip' : '?dl'), icon: 'download' },
29
+ state.can_upload && { id: 'comment', label: t`Comment`, icon: 'comment', onClick: () => editComment(entry) },
30
...addToMenu.map(x => {
31
if (x === 'open') {
32
if (entry.cantOpen) return
@@ -131,4 +133,16 @@ async function rename(entry: DirEntry) {
133
catch(e: any) {
134
await alertDialog(e)
135
}
136
+}
137
+
138
+async function editComment(entry: DirEntry) {
139
+ const res = await inputComment(entry.name, entry.comment)
140
+ if (res === null) return
141
+ await apiCall('comment', { uri: entry.uri, comment: res })
142
+ updateEntry(entry, e => e.comment = res)
143
+ alertDialog(t`Operation successful`)
144
+}
145
+
146
+function updateEntry(entry: DirEntry, cb: (e: DirEntry) => unknown) {
147
+ cb(_.find(state.list, { n: entry.n })!)
148
}
\ No newline at end of file
frontend/src/state.ts
+1
-1
@@ -87,7 +87,7 @@ export class DirEntry {
87
public readonly c?: string
88
public readonly p?: string
89
public readonly icon?: string
90
- public readonly comment?: string
90
+ public comment?: string
91
// we memoize these value for speed
92
public readonly name: string
93
public readonly uri: string
frontend/src/upload.ts
+6
-1
@@ -3,6 +3,7 @@
3
import { createElement as h, DragEvent, Fragment, useMemo } from 'react'
4
import { Checkbox, Flex, FlexV, iconBtn } from './components'
5
import {
6
+ basename,
7
closeDialog,
8
formatBytes,
9
formatPerc,
@@ -147,7 +148,7 @@ export function showUpload() {
148
entries: adding,
149
actions: {
150
delete: rec => _.remove(uploadState.adding, { file: rec.file }),
150
- comment: rec => promptDialog(t('enter_comment', "Comment for this file"), { def: rec.comment, type: 'textarea' })
151
+ comment: rec => inputComment(basename(rec.file.name), rec.comment)
152
.then(s => _.find(uploadState.adding, { file: rec.file })!.comment = s || undefined),
153
},
154
}),
@@ -435,4 +436,8 @@ async function createFolder() {
436
catch(e: any) {
437
await alertDialog(e.code === 409 ? t('folder_exists', "Folder with same name already exists") : e)
438
}
439
+}
440
+
441
+export function inputComment(filename: string, def?: string) {
442
+ return promptDialog(t('enter_comment', "Comment for " + filename), { def, type: 'textarea' })
443
}
\ No newline at end of file
src/api.file_list.ts
+2
-2
@@ -76,7 +76,6 @@ export const get_file_list: ApiHandler = async ({ uri, offset, limit, search, c
76
const entry = await nodeToDirEntry(ctx, sub)
77
if (!entry)
78
continue
79
- entry.comment = await getCommentFor(sub.source)
79
const cbParams = { entry, ctx, listUri: uri, node: sub }
80
try {
81
const res = await Promise.all(onDirEntryHandlers.map(cb => cb(cbParams)))
@@ -126,7 +125,8 @@ export const get_file_list: ApiHandler = async ({ uri, offset, limit, search, c
125
c: ctime,
126
m: Math.abs(+mtime-+ctime) < 1000 ? undefined : mtime,
127
s: folder ? undefined : st.size,
129
- p: (pr + pl + pd) || undefined
128
+ p: (pr + pl + pd) || undefined,
129
+ comment: await getCommentFor(source),
130
}
131
}
132
catch {
src/frontEndApis.ts
+16
-7
@@ -7,18 +7,15 @@ import events from './events'
7
import Koa from 'koa'
8
import { dirTraversal, isValidFileName } from './util-files'
9
import {
10
- HTTP_BAD_REQUEST,
11
- HTTP_CONFLICT,
12
- HTTP_FORBIDDEN,
13
- HTTP_NOT_FOUND,
14
- HTTP_SERVER_ERROR,
15
- HTTP_UNAUTHORIZED
10
+ HTTP_BAD_REQUEST, HTTP_CONFLICT, HTTP_FAILED_DEPENDENCY, HTTP_FORBIDDEN,
11
+ HTTP_NOT_FOUND, HTTP_SERVER_ERROR, HTTP_UNAUTHORIZED
12
} from './const'
13
import { hasPermission, urlToNode } from './vfs'
14
import { mkdir, rename, rm } from 'fs/promises'
15
import { dirname, join } from 'path'
16
import { getUploadMeta } from './upload'
17
import { apiAssertTypes } from './misc'
18
+import { setCommentFor } from './comments'
19
20
export const frontEndApis: ApiHandlers = {
21
get_file_list,
@@ -108,8 +105,20 @@ export const frontEndApis: ApiHandlers = {
105
catch (e: any) {
106
throw new ApiError(HTTP_SERVER_ERROR, e)
107
}
111
- }
108
+ },
109
110
+ async comment({ uri, comment }, ctx) {
111
+ apiAssertTypes({ string: { uri, comment } })
112
+ const node = await urlToNode(uri, ctx)
113
+ if (!node)
114
+ throw new ApiError(HTTP_NOT_FOUND)
115
+ if (!hasPermission(node, 'can_upload', ctx))
116
+ throw new ApiError(HTTP_UNAUTHORIZED)
117
+ if (!node.source)
118
+ throw new ApiError(HTTP_FAILED_DEPENDENCY)
119
+ await setCommentFor(node.source, comment)
120
+ return {}
121
+ },
122
}
123
124
export function notifyClient(ctx: Koa.Context, name: string, data: any) {
src/langs/hfs-lang-en.json
+2
-1
@@ -137,6 +137,7 @@
137
"showHelp_F_body": "full screen",
138
"Destination": "Destination",
139
"in_queue": "{n} in queue",
140
- "enter_comment": "Comment for this file"
140
+ "enter_comment": "Comment for this file",
141
+ "Comment": "Comment"
142
}
143
}
src/langs/hfs-lang-it.json
+1
@@ -130,6 +130,7 @@
130
"Destination": "Destinazione",
131
"in_queue": "{n} in coda",
132
"enter_comment": "Comment for this file",
133
+ "Comment": "Comment",
134
135
"": "PLUGINS SECTION",
136
"": "PLUGIN thumbnails",
src/langs/hfs-lang-ru.json
+6
-4
@@ -1,7 +1,7 @@
1
{
2
"author": "Mefistofell, SanokKule",
3
- "version": 2.1,
4
- "hfs_version": "0.48.0",
3
+ "version": 2.2,
4
+ "hfs_version": "0.49.0",
5
"translate": {
6
"Select": "Выбор",
7
"n_files": "{n,plural, one{1 файл} few{# файла} other{# файлов}}",
@@ -137,10 +137,12 @@
137
"showHelp_F_body": "полноэкранный режим",
138
"Destination": "Назначение",
139
"in_queue": "{n} в очереди",
140
+ "enter_comment": "Комментарий для файла",
141
+ "Comment": "Комментировать",
142
143
"": "PLUGINS SECTION",
144
"": "PLUGIN thumbnails",
143
- "Enable tiles mode": "Просмотр в режиме плиток",
144
- "thumbnails_switchBack": "Изменить вид можно в настройках"
145
+ "Enable tiles mode": "Просмотр в режиме плиток",
146
+ "thumbnails_switchBack": "Изменить вид можно в настройках"
147
}
148
}