admin/options: page_size #1156

Massimo Melina committed Jan 28, 2026 at 20:15 UTC 8e8d86fac3424e82ce04844ebd2e546cb0155002
3 files changed +11 -8
admin/src/OptionsPage.ts
+2 -1
@@ -204,8 +204,9 @@ export default function OptionsPage() {
204 { k: 'folders_first', comp: BoolField, xs: 6, md: 3 },
205 { k: 'sort_numerics', comp: BoolField, xs: 6, md: 3, label: "Sort numeric names" },
206 { k: 'title_with_path', comp: BoolField, xs: 6, md: 3 },
207 - { k: 'favicon', comp: FileField, placeholder: "None", fileMask: '*.ico|' + IMAGE_FILEMASK, xs: 12,
207 + { k: 'favicon', comp: FileField, placeholder: "None", fileMask: '*.ico|' + IMAGE_FILEMASK, xs: 12, sm: 9,
208 helperText: "The icon associated to your website" },
209 + { k: 'page_size', comp: NumberField, xs: true, min: 1, required: true, helperText: "Entries per page" },
210
211 h(Section, { title: "Uploads" }),
212 { k: 'dont_overwrite_uploading', comp: BoolField, md: 4, label: "Uploads don't overwrite",
frontend/src/BrowseFiles.ts
+8 -7
@@ -63,15 +63,15 @@ export function BrowseFiles() {
63 }
64
65 function FilesList() {
66 - const { filteredList, list, loading, searchManuallyInterrupted } = useSnapState()
67 - const midnight = useMidnight() // as an optimization we calculate this only once per list and pass it down
68 - const pageSize = 100
66 + const snap = useSnapState()
67 + const midnight = useMidnight() // as an optimization, we calculate this only once per list and pass it down
68 + const pageSize = Math.max(1, Math.floor(snap.page_size ?? 100))
69 const [page, setPage] = useState(0)
70 const [extraPages, setExtraPages] = useState(0)
71 const [scrolledPages, setScrolledPages] = useState(0)
72 const [atBottom, setAtBottom] = useState(false)
73 const offset = page * pageSize
74 - const theList = filteredList || list
74 + const theList = snap.filteredList || snap.list
75 const total = theList.length
76 const nPages = Math.ceil(total / pageSize)
77 const pageEnd = offset + pageSize * (1+extraPages) - 1
@@ -206,8 +206,9 @@ function FilesList() {
206
207 const {t} = useI18N()
208
209 - const msgInstead = !list.length ? (!loading && (searchManuallyInterrupted ? t('stopped_before', "Stopped before finding anything") : t('empty_list', "Nothing here")))
210 - : filteredList && !filteredList.length && t('filter_none', "No match for this filter")
209 + const msgInstead = snap.list.length ? snap.filteredList && !snap.filteredList.length && t('filter_none', "No match for this filter")
210 + : !snap.loading && (snap.searchManuallyInterrupted ? t('stopped_before', "Stopped before finding anything")
211 + : t('empty_list', "Nothing here"))
212
213 const focusHint = `${t('focus_hint', "By typing on your keyboard, you search and focus elements of the list.")}\n\nESC: ${t`Cancel`}`
214 return h(Fragment, {},
@@ -222,7 +223,7 @@ function FilesList() {
223 separator: idx > 0 && !(idx % pageSize) ? String(offset + idx) : undefined,
224 entry,
225 })),
225 - loading && h(Spinner),
226 + snap.loading && h(Spinner),
227 ),
228 total > pageSize && h(Paging, {
229 nPages,
src/cross.ts
+1
@@ -16,6 +16,7 @@ export const MAX_TILE_SIZE = 10
16 export const FRONTEND_OPTIONS = {
17 file_menu_on_link: true,
18 tile_size: 0,
19 + page_size: 100,
20 sort_by: 'name',
21 invert_order: false,
22 folders_first: true,