admin/options: new option "KB for size"
Massimo Melina committed
Dec 8, 2024 at 21:03 UTC
ab3fc1267adb64d8728207aa65665f553ac17c42
5 files changed
+12
-8
admin/src/OptionsPage.ts
+1
@@ -220,6 +220,7 @@ export default function OptionsPage() {
220
221
{ k: 'descript_ion', comp: BoolField, ...isWindows && { sm: 4, md: 3 }, label: "Enable comments", helperText: "In file DESCRIPT.ION" },
222
{ k: 'show_hidden_files', comp: BoolField, sm: 4, md: 3 },
223
+ { k: CFG.size_1024, label: "KB size", comp: SelectField, md: 3, options: { 1000: false, 1024: true } },
224
{ k: 'descript_ion_encoding', sm: 4, md: 6, label: "Encoding of file DESCRIPT.ION", comp: SelectField, disabled: !values.descript_ion,
225
options: ['utf8',720,775,819,850,852,862,869,874,808, ..._.range(1250,1257),10029,20866,21866] },
226
frontend/src/fileMenu.ts
+1
-1
@@ -72,7 +72,7 @@ export function openFileMenu(entry: DirEntry, ev: MouseEvent, addToMenu: (Falsy
72
const props = [
73
{ id: 'name', label: t`Name`, value: entry.name },
74
typeof s === 'number' && { id: 'size', label: t`Size`,
75
- value: h(Fragment, {}, formatBytes(s), h('small', {}, prefix(' (', s > 1024 && s.toLocaleString(), ')')) ) },
75
+ value: h(Fragment, {}, formatBytes(s), h('small', {}, prefix(' (', s > getHFS().kb && s.toLocaleString(), ')')) ) },
76
entry.t && { id: 'timestamp', label: t`Timestamp`, value: entry.t.toLocaleString() },
77
folder && {
78
id: 'folder',
shared/index.ts
+2
-1
@@ -2,7 +2,7 @@
2
3
import _ from 'lodash'
4
import { apiCall } from './api'
5
-import { DAY, Dict, HOUR, MINUTE, objSameKeys, typedEntries } from '../src/cross'
5
+import { DAY, Dict, formatBytes, HOUR, MINUTE, objSameKeys, typedEntries } from '../src/cross'
6
export * from './react'
7
export * from './dialogs'
8
export * from './md'
@@ -35,6 +35,7 @@ Object.assign(HFS, {
35
copyTextToClipboard,
36
urlParams,
37
})
38
+formatBytes.k = HFS.kb
39
40
export const IMAGE_FILEMASK = '*.jpg|*.jpeg|*.gif|*.svg'
41
src/cross.ts
+5
-5
@@ -28,7 +28,7 @@ export const THEME_OPTIONS = { auto: '', light: 'light', dark: 'dark' }
28
export const CFG = constMap(['geo_enable', 'geo_allow', 'geo_list', 'geo_allow_unknown', 'dynamic_dns_url',
29
'log', 'error_log', 'log_rotation', 'dont_log_net', 'log_gui', 'log_api', 'log_ua', 'log_spam', 'track_ips',
30
'max_downloads', 'max_downloads_per_ip', 'max_downloads_per_account', 'roots', 'force_address', 'split_uploads',
31
- 'allow_session_ip_change', 'force_lang', 'suspend_plugins', 'base_url'])
31
+ 'allow_session_ip_change', 'force_lang', 'suspend_plugins', 'base_url', 'size_1024'])
32
export const LIST = { add: '+', remove: '-', update: '=', props: 'props', ready: 'ready', error: 'e' }
33
export type Dict<T=any> = Record<string, T>
34
export type Falsy = false | null | undefined | '' | 0
@@ -89,9 +89,11 @@ export function isWhoObject(v: undefined | Who): v is WhoObject {
89
}
90
91
const MULTIPLIERS = ['', 'K', 'M', 'G', 'T']
92
-export function formatBytes(n: number, { post='B', k=1024, digits=NaN, sep=' ' }={}) {
92
+export declare namespace formatBytes { let k: number }
93
+export function formatBytes(n: number, { post='B', k=0, digits=NaN, sep=' ' }={}) {
94
if (isNaN(Number(n)) || n < 0)
95
return ''
96
+ k ||= formatBytes.k ?? 1024 // default value
97
const i = n && Math.min(MULTIPLIERS.length - 1, Math.floor(Math.log2(n) / Math.log2(k)))
98
n /= k ** i
99
const nAsString = i && !isNaN(digits) ? n.toFixed(digits)
@@ -100,9 +102,7 @@ export function formatBytes(n: number, { post='B', k=1024, digits=NaN, sep=' ' }
102
} // formatBytes
103
104
export function formatSpeed(n: number, options: { digits?: number }={}) {
103
- return formatBytes(n, { post: 'B/s', k: 1000, ...options })
104
- .replace('K', 'k') // ref https://en.wikipedia.org/wiki/Data-rate_units
105
-
105
+ return formatBytes(n, { post: 'B/s', ...options })
106
}
107
108
export function prefix(pre: Falsy | string, v: string | number | undefined | null | false, post: Falsy | string='') {
src/serveGuiFiles.ts
+3
-1
@@ -9,7 +9,7 @@ import { getPluginConfigFields, getPluginInfo, mapPlugins, pluginsConfig } from
9
import { refresh_session } from './api.auth'
10
import { ApiError } from './apiMiddleware'
11
import { join, extname } from 'path'
12
-import { CFG, debounceAsync, FRONTEND_OPTIONS, isPrimitive, newObj, onlyTruthy, parseFile } from './misc'
12
+import { CFG, debounceAsync, formatBytes, FRONTEND_OPTIONS, isPrimitive, newObj, onlyTruthy, parseFile } from './misc'
13
import { favicon, title } from './adminApis'
14
import { customHtml, getAllSections, getSection } from './customHtml'
15
import _ from 'lodash'
@@ -17,6 +17,7 @@ import { defineConfig, getConfig } from './config'
17
import { getLangData } from './lang'
18
import { dontOverwriteUploading } from './upload'
19
20
+const size1024 = defineConfig(CFG.size_1024, false, x => formatBytes.k = x ? 1024 : 1000) // we both configure formatBytes, and also provide a compiled version (number instead of boolean)
21
const splitUploads = defineConfig(CFG.split_uploads, 0)
22
export const logGui = defineConfig(CFG.log_gui, false)
23
_.each(FRONTEND_OPTIONS, (v,k) => defineConfig(k, v)) // define default values
@@ -107,6 +108,7 @@ async function treatIndex(ctx: Koa.Context, filesUri: string, body: string) {
108
prefixUrl: ctx.state.revProxyPath,
109
dontOverwriteUploading: dontOverwriteUploading.get(),
110
splitUploads: splitUploads.get(),
111
+ kb: size1024.compiled(),
112
forceTheme: mapPlugins(p => _.isString(p.isTheme) ? p.isTheme : undefined).find(Boolean),
113
customHtml: _.omit(getAllSections(), ['top', 'bottom', 'htmlHead', 'style']), // exclude the sections we already apply in this phase
114
...newObj(FRONTEND_OPTIONS, (v, k) => getConfig(k)),