admin/fs: "open in new browser" option for links

Massimo Melina committed Apr 12, 2024 at 14:36 UTC 9d01aa7b8edb0e540cf0fa56db083c4cc0f398dc
7 files changed +15 -4
admin/src/FileForm.ts
+8
@@ -151,6 +151,14 @@ export default function FileForm({ file, addToBar, statusApi, accounts, saved }:
151 helperText: !values.source ? "This field is empty, and thus this element is a virtual-folder. You can set this field, pointing at any folder/file on disk."
152 : isDir ? "Content from this path on disk will be listed, but you can also add more" : undefined,
153 },
154 + isLink && {
155 + k: 'target',
156 + comp: BoolField,
157 + sm: 6,
158 + label: "Open in new browser",
159 + fromField: x => x ? '_blank' : null,
160 + toField: x => x > '',
161 + },
162 !isLink && { k: 'id', comp: LinkField, statusApi, xs: 12 },
163 perm('can_read', "Who can see but not download will be asked to login"),
164 perm('can_see', "If you can't see, you may still download with a direct link"),
config.md
+1
@@ -124,6 +124,7 @@ Valid keys in a node are:
124 Value is a dictionary, where the key is the original name.
125 - `mime`: specify what mime to use for this resource. Use "auto" for automatic detection.
126 - `url`: when this value is present, the element is a link to the URL you specify.
127 +- `target`: optional, for links only, used to [open the link in a new browser](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#target). E.g. `_blank`
128 - `accept`: valid only on upload folders, used to restrict the type of files you can upload. E.g. `.zip,.rar`
129 - `default`: to be used with a folder where you want to serve a default html. E.g.: "index.html". Using this will make `mime` default to "auto".
130 - `can_read`: specify who can download this entry. Value is a `WhoCan` descriptor, which is one of these values
frontend/src/BrowseFiles.ts
+1 -1
@@ -231,7 +231,7 @@ const Entry = ({ entry, midnight, separator }: EntryProps) => {
231 h('a', { href: uri, onClick, tabIndex: -1, 'aria-hidden': true }, ico),
232 h(Link, { to: containerDir, className: 'container-folder', tabIndex: -1 }, containerName),
233 h('a', { href: uri, onClick, ...ariaProps }, name)
234 - ] : [h('a', { href: uri, onClick, ...ariaProps }, ico, name)],
234 + ] : [h('a', { href: uri, onClick, target: entry.target, ...ariaProps }, ico, name)],
235 ),
236 h(CustomCode, { name: 'afterEntryName', entry }),
237 entry.comment && h('div', { className: 'entry-comment' }, entry.comment),
frontend/src/state.ts
+1
@@ -94,6 +94,7 @@ export class DirEntry {
94 public readonly icon?: string
95 public readonly web?: true
96 public readonly url?: string
97 + public readonly target?: string
98 public comment?: string
99 // we memoize these value for speed
100 public readonly name: string
src/api.get_file_list.ts
+2 -2
@@ -15,7 +15,7 @@ import { ctxAdminAccess } from './adminApis'
15 import { dontOverwriteUploading } from './upload'
16 import { SendListReadable } from './SendList'
17
18 -export interface DirEntry { n:string, s?:number, m?:Date, c?:Date, p?: string, comment?: string, web?: boolean, url?: string }
18 +export interface DirEntry { n:string, s?:number, m?:Date, c?:Date, p?: string, comment?: string, web?: boolean, url?: string, target?: string }
19
20 export const get_file_list: ApiHandler = async ({ uri='/', offset, limit, search, c, onlyFolders, admin }, ctx) => {
21 const node = await urlToNode(uri, ctx)
@@ -106,7 +106,7 @@ export const get_file_list: ApiHandler = async ({ uri='/', offset, limit, search
106 const { source, url } = node
107 const name = getNodeName(node)
108 if (url)
109 - return name ? { n: name, url } : null
109 + return name ? { n: name, url, target: node.target } : null
110 const isFolder = await nodeIsDirectory(node)
111 try {
112 const st = source ? await stat(source) : undefined
src/api.vfs.ts
+1 -1
@@ -21,7 +21,7 @@ async function urlToNodeOriginal(uri: string) {
21 return n?.isTemp ? n.original : n
22 }
23
24 -const ALLOWED_KEYS = ['name','source','masks','default','accept','rename','mime','url', ...PERM_KEYS]
24 +const ALLOWED_KEYS = ['name','source','masks','default','accept','rename','mime','url','target', ...PERM_KEYS]
25
26 const apis: ApiHandlers = {
27
src/vfs.ts
+1
@@ -18,6 +18,7 @@ export interface VfsNodeStored extends VfsPerms {
18 name?: string
19 source?: string
20 url?: string
21 + target?: string
22 children?: VfsNode[]
23 default?: string | false // we could have used empty string to override inherited default, but false is clearer, even reading the yaml, and works well with pickProps(), where empty strings are removed
24 mime?: string | Record<string, string>