Compare commits

...

260 Commits

Author SHA1 Message Date
Oleg Lobanov
0e3b35b30e chore(release): 2.28.0 2024-04-01 16:22:00 +02:00
dependabot[bot]
05bfae264a build(deps): bump google.golang.org/protobuf from 1.31.0 to 1.33.0 (#3045)
Bumps google.golang.org/protobuf from 1.31.0 to 1.33.0.

---
updated-dependencies:
- dependency-name: google.golang.org/protobuf
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-17 21:58:00 +01:00
niubility000
4c233c3db3 feat: enable preview in shared folder (#3055) 2024-03-17 21:53:33 +01:00
dependabot[bot]
7797a4ef18 build(deps): bump google.golang.org/protobuf in /tools (#3044)
Bumps google.golang.org/protobuf from 1.28.0 to 1.33.0.

---
updated-dependencies:
- dependency-name: google.golang.org/protobuf
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-14 11:36:17 +01:00
niubility000
d70650689c feat: auto hiding header bar in preview to enlarge the preview window (#3024) 2024-03-07 11:25:01 +01:00
niubility000
8dddc8a450 chore: show the current used filebrowser.db in cmd window (#3028) 2024-03-07 11:16:41 +01:00
niubility000
cdf8def330 fix: stay in the same position after renaming or deleting (#3039) 2024-03-07 11:14:40 +01:00
niubility000
e167c3e1ef feat: freezing the list in the backgroud while previewing a file (#3004) 2024-02-22 19:42:36 +01:00
ねらひかだ
fe5ca74aa1 fix: fix lint warnings (#2976) 2024-02-09 11:05:35 +01:00
ねらひかだ
dfad87386f chore: update github action versions (#2977) 2024-02-09 11:05:09 +01:00
Shlomo
6d7ba65faf fix: shell direction (#2980) 2024-02-09 11:04:02 +01:00
Feriman
d5487ba6fa chore: add noindex (#2981) 2024-02-09 11:03:06 +01:00
zoui
34a08170c8 fix: editor discard prompt (#2990) 2024-02-09 11:01:41 +01:00
Shlomo
d49c3dfacf feat: select multiple files with ctrl even with singleClick option (#2953) 2024-01-30 10:49:35 +01:00
Shlomo
2cfee2183c fix: dashboard buttons position in rtl layout (#2949) 2024-01-30 10:48:32 +01:00
Shlomo
fb1a09c7c1 feat: prompt to confirm discard editor changes (#2948)
* chore: update he.json

* feat: prompt to confirm discard editor changes

---------

Co-authored-by: Oleg Lobanov <oleg@lobanov.me>
2024-01-30 10:48:03 +01:00
Shlomo
b19710efca feat: focus editor when opened (#2946) 2024-01-30 10:44:20 +01:00
Shlomo
ff9502ff34 fix: keyboard shortcut to confirm prompts (#2932) 2024-01-30 10:44:00 +01:00
Shlomo
62f0dfb302 chore: update he.json (#2933) 2024-01-30 10:37:47 +01:00
Quentin McGaw
81cd8fc6d3 fix(healthcheck): use address configured if not empty (#2938) 2024-01-30 10:37:17 +01:00
Shlomo
70c826133b feat: close editor when click escape key (#2947) 2024-01-30 10:29:37 +01:00
Shlomo
2f6c473977 chore: update pull request template (#2950) 2024-01-30 10:23:41 +01:00
dependabot[bot]
bf36cc00f1 build(deps-dev): bump vite from 4.4.12 to 4.5.2 in /frontend (#2951)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 4.4.12 to 4.5.2.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v4.5.2/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v4.5.2/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-30 10:22:48 +01:00
Shlomo
883383a571 fix: moment locale (#2952) 2024-01-30 10:16:32 +01:00
ねらひかだ
0a05f8c01f chore(i18n): improvement of Japanese translation (#2962) 2024-01-30 10:15:27 +01:00
ねらひかだ
a4b089a6db feat: allow to configure if home directory is automatically created from cli (#2963) 2024-01-30 10:14:50 +01:00
ねらひかだ
5c5ab6b875 fix: files and directories are created with the correct permissions (#2966) 2024-01-30 10:12:38 +01:00
Oleg Lobanov
04e03a83b4 chore(release): 2.27.0 2024-01-02 18:29:29 +04:00
Yogesh
c4e955acf4 fix: typo in build error #2903 (#2904) 2023-12-31 14:32:54 +01:00
People-11
fc04578e28 Update zh-cn.json (#2875) 2023-12-28 10:30:52 +01:00
Shlomo
3264cea830 fix: delete message when delete file from preview 2023-12-28 10:11:53 +01:00
Yarden Shoham
748af7172c feat: allow setting theme via cli (#2881) 2023-12-28 09:52:40 +01:00
Shlomo
da595326ee chore: update he.json (#2877) 2023-12-28 09:44:58 +01:00
dependabot[bot]
821fba41a2 build(deps): bump golang.org/x/crypto from 0.14.0 to 0.17.0 (#2890)
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.14.0 to 0.17.0.
- [Commits](https://github.com/golang/crypto/compare/v0.14.0...v0.17.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-28 09:44:24 +01:00
Omar Hussein
cfafefa35a chore: update Arabic and English translations (#2823) 2023-12-06 11:21:04 +01:00
Fritz Lin
391a078cd4 feat: make user session timeout configurable by flags (#2845) 2023-12-06 11:19:30 +01:00
dependabot[bot]
fc2ee37353 build(deps-dev): bump vite from 4.4.9 to 4.4.12 in /frontend (#2862)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 4.4.9 to 4.4.12.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v4.4.12/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v4.4.12/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-06 11:09:33 +01:00
M A E R Y O
a09dfa8d9f feat: display image resolutions in file details (#2830)
---------

Co-authored-by: MAERYO <maeryo@hanwha.com>
2023-11-25 13:35:00 +01:00
ねらひかだ
4dbc802972 fix: fix typo (#2843) 2023-11-25 13:29:43 +01:00
Emmanuel Frecon
d59ad594b8 fix: set correct port in docker healthcheck (#2812)
When the `FB_PORT` environment variable is set, respect its value. Otherwise, pick the port from the configuration.
2023-11-08 17:59:46 +01:00
Oleg Lobanov
a4cb813ddf chore(release): 2.26.0 2023-11-02 22:49:15 +01:00
Oleg Lobanov
4d0a68e787 fix: goreleaser yaml 2023-11-02 22:48:29 +01:00
dependabot[bot]
a744bd224f build(deps): bump golang.org/x/image from 0.5.0 to 0.10.0 (#2800)
Bumps [golang.org/x/image](https://github.com/golang/image) from 0.5.0 to 0.10.0.
- [Commits](https://github.com/golang/image/compare/v0.5.0...v0.10.0)

---
updated-dependencies:
- dependency-name: golang.org/x/image
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-02 22:36:32 +01:00
Oleg Lobanov
da1fe7c9d7 fix: disable static resource files listing 2023-11-02 22:23:20 +01:00
Dardan
7fabadc871 feat: make user session timeout configurable (#2753)
Co-authored-by: Oleg Lobanov <oleg@lobanov.me>
2023-11-02 22:01:56 +01:00
Isaak Tsalicoglou
c3079d30e2 feat: add modern greek translation (#2778)
---------

Co-authored-by: Oleg Lobanov <oleg@lobanov.me>
2023-11-02 21:55:22 +01:00
shonge
6a31af6c0a fix: solve docker build failed issue (#2797) 2023-11-02 21:38:00 +01:00
dependabot[bot]
21d361ad30 build(deps-dev): bump postcss from 8.4.27 to 8.4.31 in /frontend (#2749)
Bumps [postcss](https://github.com/postcss/postcss) from 8.4.27 to 8.4.31.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.4.27...8.4.31)

---
updated-dependencies:
- dependency-name: postcss
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-02 09:09:01 +01:00
dependabot[bot]
d574fb6d1a build(deps): bump golang.org/x/net from 0.11.0 to 0.17.0 (#2758)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.11.0 to 0.17.0.
- [Commits](https://github.com/golang/net/compare/v0.11.0...v0.17.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-02 09:03:48 +01:00
dependabot[bot]
bb4bb508a9 build(deps): bump @babel/traverse in /frontend (#2775)
Bumps [@babel/traverse](https://github.com/babel/babel/tree/HEAD/packages/babel-traverse) from 7.22.10 to 7.23.2.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.23.2/packages/babel-traverse)

---
updated-dependencies:
- dependency-name: "@babel/traverse"
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-02 09:03:28 +01:00
bufubaoni
edd808f124 fix: avoid the front-end calling api/renew loop (#2792) 2023-11-02 09:02:51 +01:00
kloon15
cdcd9a313a fix: display file size as base 2 (KiB instead of KB) (#2779) 2023-11-02 08:47:55 +01:00
Isaak Tsalicoglou
d0c3aeace1 chore: update en translation (#2777) 2023-11-02 08:43:50 +01:00
Isaak Tsalicoglou
9484454584 chore: update en translation (#2776) 2023-11-02 08:43:32 +01:00
kloon15
bd3c1941ff fix: revert fetchURL changes in auth (Fixes #2729) (#2739) 2023-10-01 18:09:13 +02:00
Oleg Lobanov
01f7842a18 docs: add demo url to README 2023-09-15 01:11:47 +02:00
Oleg Lobanov
38f7788255 build: fix deprecated goreleaser config options 2023-09-15 00:59:16 +02:00
Oleg Lobanov
c1fb4004f7 chore(release): 2.25.0 2023-09-15 00:51:58 +02:00
Cameron
584b706b1e feat: added shell resizing (#2648) 2023-09-15 00:50:40 +02:00
M A E R Y O
ecdd684bf1 feat: implement upload speed calculation and ETA estimation (#2677) 2023-09-15 00:41:36 +02:00
Oleg Lobanov
36af01daa6 fix: tus upload with cloudflare proxy
closes #2593
2023-09-15 00:39:37 +02:00
Thomas
d0c3b8033d chore: update German translation (#2616) 2023-09-10 14:35:51 +02:00
kloon15
aa00c1c89c chore: fixes for vite dev server (#2678) 2023-08-29 20:14:45 +02:00
M A E R Y O
a404fb043d feat: implement abort upload functionality (#2673) 2023-08-27 23:59:49 +02:00
M A E R Y O
95fec7f694 fix: refactor path resolution logic for project root (#2674)
---------

Co-authored-by: MAERYO <maeryo@hanwha.com>
2023-08-27 23:52:33 +02:00
ArthurMousatov
5994224468 feat: add new folder button to move/create dialogs (#2667)
---------

Co-authored-by: Oleg Lobanov <oleg@lobanov.me>
2023-08-27 00:28:58 +02:00
古大羊
374bbd3ec1 perf(backend): optimize subtitles detection performance (#2637) 2023-08-26 14:53:18 +02:00
Oleg Lobanov
2c97573301 build: bump go version to 1.21.0 (#2672) 2023-08-26 14:16:10 +02:00
Oleg Lobanov
70eba7ecc9 build: bump node version to 18 (#2671) 2023-08-26 14:10:07 +02:00
Oleg Lobanov
7a4d0c0c08 chore: fix frontend dev proxy settings 2023-08-26 14:01:01 +02:00
kloon15
8838a09cf5 refactor: migrate frontend tooling to vite 4 (#2645)
---------

Co-authored-by: Oleg Lobanov <oleg@lobanov.me>
2023-08-26 13:55:51 +02:00
Oleg Lobanov
184b7c14f2 chore(release): 2.24.2 2023-08-08 22:30:21 +02:00
M A E R Y O
289c8e6f32 fix: 403 error error when uploading (#2598)
Co-authored-by: 김종성 <ziippy@naver.com>
2023-08-08 22:29:03 +02:00
putty182
ff1e0b8185 fix: config init for branding.disableUsedPercentage (#2576) (#2596) 2023-08-05 11:53:42 +02:00
MichaIng
0ac39684f1 build: add riscv64 binary releases (#2587)
Signed-off-by: MichaIng <micha@dietpi.com>
2023-08-01 15:00:42 +02:00
Oleg Lobanov
fa390c498d chore(release): 2.24.1 2023-07-31 13:33:09 +02:00
M A E R Y O
4b72bbfc7f Remove redundant calls to baseURL/url #2581 (#2579)
---------

Co-authored-by: 이광오 <maeryo@hanwha.com>
Co-authored-by: Oleg Lobanov <oleg.lobanov@bitvavo.com>
2023-07-31 13:27:24 +02:00
M A E R Y O
2a4a46c61a fix: resolved CSS rendering issue in Chrome browser (#2582)
Co-authored-by: 이광오 <maeryo@hanwha.com>
2023-07-31 13:08:30 +02:00
Oleg Lobanov
efd41cc4c1 build(backend): upgrade golangci-lint to v1.53.3 2023-07-31 12:51:00 +02:00
M A E R Y O
912f27a9e3 fix: add directory creation code to partial upload handler (#2575) (#2580) 2023-07-31 12:38:11 +02:00
M A E R Y O
4e28cc13c9 chore: removed duplicate z-index (#2583)
Co-authored-by: 이광오 <maeryo@hanwha.com>
2023-07-31 11:21:58 +02:00
Oleg Lobanov
f37513c45e chore(release): 2.24.0 2023-07-29 11:32:30 +02:00
Oleg Lobanov
4d77ce0955 build: remove armv7-s6 docker target 2023-07-29 11:30:50 +02:00
Oleg Lobanov
66dfbb303c build: remove armv6-s6 docker target 2023-07-29 00:26:32 +02:00
Oleg Lobanov
9bf6b856e5 build(backend): bump go version to 1.20.6 2023-07-28 23:56:57 +02:00
Oleg Lobanov
051104bfa0 fix: goreleaser docker build 2023-07-28 23:54:39 +02:00
Vinicius Almendra
b8ee3404ee fix: solve broken Docker build with alpine image (#2486) 2023-07-28 18:34:21 +02:00
slhmy
853ec906ef fix: error while using fallback of dir move (#2349) 2023-07-28 18:24:42 +02:00
Tobias Goerke
7b35815754 feat: integrate tus.io for resumable and chunked uploads (#2145) 2023-07-28 18:15:44 +02:00
ArthurMousatov
2744f7d5b9 fix: added an early return on non-existent items (#2571) 2023-07-27 18:03:49 +02:00
Anchit Bajaj
b508ac3d4f fix: xss vulnerability in /api/raw (#2570) (#2572) 2023-07-27 11:42:27 +02:00
Andrew Kennedy
ff4375cf6c feat: add a healthcheck script that works with a dynamic port (#2510) 2023-07-22 23:07:15 +02:00
dependabot[bot]
a664ba1f9d build(deps): bump minimatch from 3.0.4 to 3.1.2 in /tools (#2561)
Bumps [minimatch](https://github.com/isaacs/minimatch) from 3.0.4 to 3.1.2.
- [Changelog](https://github.com/isaacs/minimatch/blob/main/changelog.md)
- [Commits](https://github.com/isaacs/minimatch/compare/v3.0.4...v3.1.2)

---
updated-dependencies:
- dependency-name: minimatch
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-22 22:38:34 +02:00
dependabot[bot]
bb3486286c build(deps-dev): bump word-wrap from 1.2.3 to 1.2.4 in /frontend (#2556)
Bumps [word-wrap](https://github.com/jonschlinkert/word-wrap) from 1.2.3 to 1.2.4.
- [Release notes](https://github.com/jonschlinkert/word-wrap/releases)
- [Commits](https://github.com/jonschlinkert/word-wrap/compare/1.2.3...1.2.4)

---
updated-dependencies:
- dependency-name: word-wrap
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-22 21:24:50 +02:00
ChengDaqi2023
ecfcbfd216 chore: update golang.org/x/net v0.6.0 to 0.7.0 (#2559) 2023-07-22 21:24:28 +02:00
Daniel Li
9bcfa900f9 fix: filter ANSI color for shell (#2529)
* feat: filter ANSI color for shell

* chore: fix formatting

---------

Co-authored-by: Oleg Lobanov <oleg.lobanov@bitvavo.com>
2023-07-20 17:38:53 +02:00
dependabot[bot]
c2f1423c02 build(deps): bump semver from 5.7.1 to 5.7.2 in /tools (#2546)
Bumps [semver](https://github.com/npm/node-semver) from 5.7.1 to 5.7.2.
- [Release notes](https://github.com/npm/node-semver/releases)
- [Changelog](https://github.com/npm/node-semver/blob/v5.7.2/CHANGELOG.md)
- [Commits](https://github.com/npm/node-semver/compare/v5.7.1...v5.7.2)

---
updated-dependencies:
- dependency-name: semver
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-17 11:47:56 +02:00
ULiiAn
6744cd47ce fix: video preview click next or prev button subtitles not update (#2423) 2023-05-01 13:09:44 +02:00
Yeicor
a4ef02a47b feat: add option to copy download links from shares (#2442) 2023-05-01 13:07:01 +02:00
Oleg Lobanov
1a5b999545 Merge pull request #2345 from filebrowser/go_1.20.1
build(backend): bump go version to 1.20.1
2023-02-16 09:22:57 +01:00
Oleg Lobanov
10d628aecc chore: upgrade golangci-lint to 1.51.1 2023-02-16 09:19:44 +01:00
Oleg Lobanov
fa95299df4 build(backend): bump go version to 1.20.1 2023-02-15 23:43:20 +01:00
Oleg Lobanov
fd22e0b163 chore(backend): upgrade deps 2023-02-15 23:39:52 +01:00
Gabriel Alencar
428c1c606d feat: add a new setting that disables the display of the disk usage (#2136) 2023-02-15 23:30:48 +01:00
Yonas Yanfa
60d1e2d291 fix: build on FreeBSD and non-Linux platforms (#2332) 2023-02-06 18:34:25 +01:00
Gyuris Gellért
11e9202160 feat: add Hungarian translation (#2232) 2022-12-26 22:36:03 +01:00
Davide Quaranta
59619ba34f chore: update Italian translation (#2260) 2022-12-23 13:07:06 +01:00
brlarini
73dd066670 chore: update pt-br translations (#2248) 2022-12-23 13:06:19 +01:00
Yasin Silavi
2b2c1085fb refactor: replace username old focus logic with the autofocus attribute (#2223) 2022-11-25 12:26:07 +01:00
Oleg Lobanov
02db83c72e chore(release): 2.23.0 2022-11-05 18:53:29 +01:00
dependabot[bot]
3a0dace9a9 build(deps): bump ansi-html and webpack-dev-server in /frontend (#2184)
Removes [ansi-html](https://github.com/Tjatse/ansi-html). It's no longer used after updating ancestor dependency [webpack-dev-server](https://github.com/webpack/webpack-dev-server). These dependencies need to be updated together.


Removes `ansi-html`

Updates `webpack-dev-server` from 3.11.2 to 3.11.3
- [Release notes](https://github.com/webpack/webpack-dev-server/releases)
- [Changelog](https://github.com/webpack/webpack-dev-server/blob/v3.11.3/CHANGELOG.md)
- [Commits](https://github.com/webpack/webpack-dev-server/compare/v3.11.2...v3.11.3)

---
updated-dependencies:
- dependency-name: ansi-html
  dependency-type: indirect
- dependency-name: webpack-dev-server
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-10-22 15:50:34 +02:00
thewh1teagle
a5757b94e8 fix: missing video controls on mobile (#2180) 2022-10-22 11:16:59 +02:00
leplan73
1ebfc64ea1 chore: updated golang.org/x/text to v0.4.0 (#2176) 2022-10-22 11:11:02 +02:00
thewh1teagle
2c14146a31 feat: add rtl support (#2178) 2022-10-21 18:07:11 +02:00
thewh1teagle
a49105db1d feat: hebrew translation (#2168) 2022-10-20 12:27:59 +02:00
Ltzhu76
0401adf7f4 fix: modify the delete confirmation interface logic. (#2138) 2022-09-24 19:05:50 +02:00
Oleg Lobanov
c1e6d5869a ci: increase operations-per-run param to 100 2022-08-30 10:18:12 +02:00
Oleg Lobanov
db0a23aec0 chore: fix exempt-issue-labels of the stale action 2022-08-29 20:02:13 +02:00
Oleg Lobanov
350c73d78e ci: fix stale action permissions 2022-08-29 19:38:30 +02:00
Oleg Lobanov
daf36b28fd ci: close stale issues and PRs 2022-08-29 19:25:50 +02:00
Marcelina Hołub
57c99e0e26 feat: update Polish translation (#2089) 2022-08-17 20:18:51 +02:00
dependabot[bot]
aaed985699 build(deps): bump terser from 4.8.0 to 4.8.1 in /frontend (#2054)
Bumps [terser](https://github.com/terser/terser) from 4.8.0 to 4.8.1.
- [Release notes](https://github.com/terser/terser/releases)
- [Changelog](https://github.com/terser/terser/blob/master/CHANGELOG.md)
- [Commits](https://github.com/terser/terser/commits)

---
updated-dependencies:
- dependency-name: terser
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-22 15:32:39 +02:00
Oleg Lobanov
0ed32c6af8 Merge pull request #1554 from ramiresviana/auth-hook
Hook authentication method
2022-07-22 15:31:28 +02:00
Ramires Viana
dda9a389f3 feat: hook authentication method 2022-07-20 16:40:49 +02:00
Ángel Fernández Sánchez
f80b016ef0 chore: update es translation (#2046) 2022-07-20 12:17:52 +02:00
Oleg Lobanov
ceec4dcfe6 chore(release): 2.22.4 2022-07-19 00:59:29 +02:00
Oleg Lobanov
7177184678 chore: remove dependency on caddy server 2022-07-19 00:58:50 +02:00
Oleg Lobanov
0523b31b96 Merge pull request #2044 from filebrowser/security_fix 2022-07-19 00:42:45 +02:00
Oleg Lobanov
80030dee32 fix: disable cookie auth for non GET requests 2022-07-19 00:39:02 +02:00
dependabot[bot]
cb43770025 build(deps): bump moment from 2.29.2 to 2.29.4 in /frontend (#2036)
Bumps [moment](https://github.com/moment/moment) from 2.29.2 to 2.29.4.
- [Release notes](https://github.com/moment/moment/releases)
- [Changelog](https://github.com/moment/moment/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/moment/moment/compare/2.29.2...2.29.4)

---
updated-dependencies:
- dependency-name: moment
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-12 12:09:06 +02:00
dependabot[bot]
eaba7e5255 build(deps): bump shell-quote from 1.7.2 to 1.7.3 in /frontend (#2025)
Bumps [shell-quote](https://github.com/substack/node-shell-quote) from 1.7.2 to 1.7.3.
- [Release notes](https://github.com/substack/node-shell-quote/releases)
- [Changelog](https://github.com/substack/node-shell-quote/blob/master/CHANGELOG.md)
- [Commits](https://github.com/substack/node-shell-quote/compare/v1.7.2...1.7.3)

---
updated-dependencies:
- dependency-name: shell-quote
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-12 11:49:36 +02:00
Oleg Lobanov
49dbacdccd chore(release): 2.22.3 2022-07-05 16:58:52 +02:00
Oleg Lobanov
d94acdd89a fix: use correct field name in user put api (#2026) 2022-07-05 16:55:31 +02:00
源文雨
06d9c03e92 chore(deps): move golang.org/x/text to direct (#2021) 2022-07-05 16:27:33 +02:00
Oleg Lobanov
9d54046140 chore(release): 2.22.2 2022-07-01 17:21:46 +02:00
Oleg Lobanov
dec3d629d4 fix: display disk capacity in a correct format (#2013) 2022-07-01 16:31:49 +02:00
Oleg Lobanov
8118afd0ac build(backend): upgrade golangci-lint to 1.46.2 (#1991) 2022-06-13 16:13:10 +02:00
langren1353
577c0efa9c fix: don't calculate usage for files (#1973)
* fix: use incorrect suffix and return no 500(#1972、#1967)

* chore: set progress bar to small

Co-authored-by: Ramires Viana <59319979+ramiresviana@users.noreply.github.com>

* chore: refactoring

Co-authored-by: Oleg Lobanov <oleg@lobanov.me>
Co-authored-by: Ramires Viana <59319979+ramiresviana@users.noreply.github.com>
2022-06-13 12:50:39 +02:00
Po Chen
dcf0bc65bf fix: preview url building fix (#1976) 2022-06-10 12:05:05 +02:00
Oleg Lobanov
c211b96719 chore(release): 2.22.1 2022-06-06 16:59:25 +02:00
Jeffrey Schiller
1e7d3b25c2 fix: use correct basepath prefix for preview urls (#1971) 2022-06-06 16:57:19 +02:00
Oleg Lobanov
b16982df0f build(backend): bump go version to 1.8.3 2022-06-03 16:13:56 +02:00
Oleg Lobanov
540ddf47a7 chore(release): 2.22.0 2022-06-03 16:11:07 +02:00
Oleg Lobanov
02730bb9bf fix: set correct scope when user home creation is enabled 2022-06-03 16:04:15 +02:00
Oleg Lobanov
d1d8e3e340 feat: add disk usage information to the sidebar 2022-06-02 13:16:37 +02:00
Oleg Lobanov
42a39b3f1d Merge pull request #1965 from filebrowser/dependabot/npm_and_yarn/frontend/eventsource-1.1.1
build(deps): bump eventsource from 1.1.0 to 1.1.1 in /frontend
2022-06-02 11:18:53 +02:00
dependabot[bot]
dd503695a1 build(deps): bump eventsource from 1.1.0 to 1.1.1 in /frontend
Bumps [eventsource](https://github.com/EventSource/eventsource) from 1.1.0 to 1.1.1.
- [Release notes](https://github.com/EventSource/eventsource/releases)
- [Changelog](https://github.com/EventSource/eventsource/blob/master/HISTORY.md)
- [Commits](https://github.com/EventSource/eventsource/compare/v1.1.0...v1.1.1)

---
updated-dependencies:
- dependency-name: eventsource
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-01 22:10:09 +00:00
Oleg Lobanov
1d66bbe40a Merge pull request #1942 from ramiresviana/fixes-12 2022-05-13 10:42:51 +02:00
Ramires Viana
5da9d74da6 fix: allow CSP inline styling 2022-05-05 15:38:39 +00:00
Ramires Viana
b14b9114f8 feat: invalid symlink icon 2022-05-05 15:14:40 +00:00
Ramires Viana
8a43413f88 feat: page title localization 2022-05-04 13:16:16 +00:00
Ramires Viana
c3bd1188aa fix: expired token error 2022-05-04 12:58:19 +00:00
Ramires Viana
fc209f64de fix: network error object message 2022-05-04 12:36:13 +00:00
Ramires Viana
96afaca0ad chore: refactor response error handling 2022-05-04 12:11:36 +00:00
Oleg Lobanov
f663237a16 chore: bump github.com/miekg/dns to v1.1.25 2022-05-04 01:52:05 +04:00
Oleg Lobanov
ac3ead8dce build(frontend): bump node version from 14 to 16 2022-05-04 01:49:33 +04:00
Oleg Lobanov
7c9a75e725 build(backend): bump dependency versions 2022-05-04 01:00:42 +04:00
Oleg Lobanov
596c73288f feat: automatically focus username field on login page 2022-05-04 00:45:17 +04:00
Ramires Viana
d1d7b23da6 fix: folder info on upload list 2022-05-02 15:03:02 +00:00
Ramires Viana
e677c78471 fix: drag-and-drop folder upload 2022-05-02 15:01:39 +00:00
Ramires Viana
9734f707f0 chore: refactor url creation 2022-05-02 13:47:22 +00:00
dependabot[bot]
e5fa96b666 build(deps): bump async from 2.6.3 to 2.6.4 in /frontend (#1933)
Bumps [async](https://github.com/caolan/async) from 2.6.3 to 2.6.4.
- [Release notes](https://github.com/caolan/async/releases)
- [Changelog](https://github.com/caolan/async/blob/v2.6.4/CHANGELOG.md)
- [Commits](https://github.com/caolan/async/compare/v2.6.3...v2.6.4)

---
updated-dependencies:
- dependency-name: async
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-04-30 13:52:07 +04:00
Oleg Lobanov
bcef7d3f73 chore: make linter happy 2022-04-30 13:49:33 +04:00
Oleg Lobanov
aed3af5838 fix: disable autocapitalize of login input (closes #1910) 2022-04-30 13:37:32 +04:00
Oleg Lobanov
6bd34c7632 build: upgrade go version to 1.18.1 2022-04-30 13:33:56 +04:00
dependabot[bot]
040584c865 build(deps): bump moment from 2.29.1 to 2.29.2 in /frontend (#1900)
Bumps [moment](https://github.com/moment/moment) from 2.29.1 to 2.29.2.
- [Release notes](https://github.com/moment/moment/releases)
- [Changelog](https://github.com/moment/moment/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/moment/moment/compare/2.29.1...2.29.2)

---
updated-dependencies:
- dependency-name: moment
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-04-09 20:36:45 +02:00
Jonathan Zernik
ecb2d1d81b chore: fix readme, remove section about middleware. (#1897) 2022-04-04 21:03:59 +02:00
dependabot[bot]
a74c72db45 build(deps): bump minimist from 1.2.5 to 1.2.6 in /frontend (#1889)
Bumps [minimist](https://github.com/substack/minimist) from 1.2.5 to 1.2.6.
- [Release notes](https://github.com/substack/minimist/releases)
- [Commits](https://github.com/substack/minimist/compare/1.2.5...1.2.6)

---
updated-dependencies:
- dependency-name: minimist
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-04-02 14:35:39 +02:00
dependabot[bot]
f5b1e10618 build(deps): bump minimist from 1.2.5 to 1.2.6 in /tools (#1891)
Bumps [minimist](https://github.com/substack/minimist) from 1.2.5 to 1.2.6.
- [Release notes](https://github.com/substack/minimist/releases)
- [Commits](https://github.com/substack/minimist/compare/1.2.5...1.2.6)

---
updated-dependencies:
- dependency-name: minimist
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-04-01 17:02:17 +02:00
Jan Lucansky
e7fed5a45b chore: fix typo in slovak translation (#1885) 2022-03-30 16:40:29 +02:00
Felix Nüsse
f8dfbf7eee feat: add branding to the window title (#1850) 2022-03-24 12:01:19 +01:00
Sinux
fca5fc5b87 chore: enhance translations for French language (#1876)
Signed-off-by: Simon LEONARD <git-1001af4@sinux.sh>
2022-03-24 11:56:53 +01:00
Daniel
4ee19be63d chore: update german translation (#1855) 2022-03-24 11:56:14 +01:00
dependabot[bot]
b2ad3f7368 build(deps): bump url-parse from 1.5.7 to 1.5.10 in /frontend (#1841)
Bumps [url-parse](https://github.com/unshiftio/url-parse) from 1.5.7 to 1.5.10.
- [Release notes](https://github.com/unshiftio/url-parse/releases)
- [Commits](https://github.com/unshiftio/url-parse/compare/1.5.7...1.5.10)

---
updated-dependencies:
- dependency-name: url-parse
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-03-02 15:57:18 +01:00
Oleg Lobanov
b73d278ded chore(release): 2.21.1 2022-02-22 10:58:44 +01:00
Oleg Lobanov
6366cf0b18 fix: display user scope for admin users (#1834) 2022-02-22 10:58:22 +01:00
Oleg Lobanov
f73518029c chore(release): 2.21.0 2022-02-21 20:49:31 +01:00
Oleg Lobanov
c782f21b0f fix: correctly handle non-ascii passwords for shared resources 2022-02-21 20:47:28 +01:00
Oleg Lobanov
0942fc7042 fix: don't expose scope for non-admin users 2022-02-21 20:17:42 +01:00
Oleg Lobanov
c1987237d0 feat: use real image path to calculate cache key 2022-02-21 19:59:22 +01:00
Filippo Finke
cf85404dd2 feat: add upload file list with progress (#1825) 2022-02-21 19:30:42 +01:00
Oleg Lobanov
6f226fa549 Merge pull request #1832 from filebrowser/dependabot/npm_and_yarn/frontend/url-parse-1.5.7
build(deps): bump url-parse from 1.5.4 to 1.5.7 in /frontend
2022-02-20 12:23:22 +01:00
dependabot[bot]
228ebea66c build(deps): bump url-parse from 1.5.4 to 1.5.7 in /frontend
Bumps [url-parse](https://github.com/unshiftio/url-parse) from 1.5.4 to 1.5.7.
- [Release notes](https://github.com/unshiftio/url-parse/releases)
- [Commits](https://github.com/unshiftio/url-parse/compare/1.5.4...1.5.7)

---
updated-dependencies:
- dependency-name: url-parse
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-19 16:43:38 +00:00
Oleg Lobanov
bb19834042 Merge pull request #1777 from adrium/feat-gallery
Add gallery view mode
2022-02-10 17:39:59 +01:00
Adrian
7870e89bc0 feat: smaller column width to fit 2 columns in landscape mobiles 2022-02-10 17:11:24 +01:00
Adrian
8888b9f446 feat: add gallery view mode 2022-02-10 17:11:24 +01:00
Oleg Lobanov
f6e5c6f0de Merge pull request #1822 from filebrowser/dependabot/npm_and_yarn/frontend/hosted-git-info-2.8.9
build(deps): bump hosted-git-info from 2.8.8 to 2.8.9 in /frontend
2022-02-09 10:38:25 +01:00
dependabot[bot]
e7659ea36b build(deps): bump hosted-git-info from 2.8.8 to 2.8.9 in /frontend
Bumps [hosted-git-info](https://github.com/npm/hosted-git-info) from 2.8.8 to 2.8.9.
- [Release notes](https://github.com/npm/hosted-git-info/releases)
- [Changelog](https://github.com/npm/hosted-git-info/blob/v2.8.9/CHANGELOG.md)
- [Commits](https://github.com/npm/hosted-git-info/compare/v2.8.8...v2.8.9)

---
updated-dependencies:
- dependency-name: hosted-git-info
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-09 09:33:46 +00:00
Oleg Lobanov
7730ccd611 Merge pull request #1819 from filebrowser/dependabot/npm_and_yarn/frontend/browserslist-4.19.1
build(deps): bump browserslist from 4.16.3 to 4.19.1 in /frontend
2022-02-09 10:31:07 +01:00
dependabot[bot]
80890075e8 build(deps): bump browserslist from 4.16.3 to 4.19.1 in /frontend
Bumps [browserslist](https://github.com/browserslist/browserslist) from 4.16.3 to 4.19.1.
- [Release notes](https://github.com/browserslist/browserslist/releases)
- [Changelog](https://github.com/browserslist/browserslist/blob/main/CHANGELOG.md)
- [Commits](https://github.com/browserslist/browserslist/compare/4.16.3...4.19.1)

---
updated-dependencies:
- dependency-name: browserslist
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-08 20:02:42 +00:00
Oleg Lobanov
9b04004120 Merge pull request #1818 from filebrowser/dependabot/npm_and_yarn/frontend/dns-packet-1.3.4
build(deps): bump dns-packet from 1.3.1 to 1.3.4 in /frontend
2022-02-08 21:01:42 +01:00
dependabot[bot]
a73d7f14b7 build(deps): bump dns-packet from 1.3.1 to 1.3.4 in /frontend
Bumps [dns-packet](https://github.com/mafintosh/dns-packet) from 1.3.1 to 1.3.4.
- [Release notes](https://github.com/mafintosh/dns-packet/releases)
- [Changelog](https://github.com/mafintosh/dns-packet/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mafintosh/dns-packet/compare/v1.3.1...v1.3.4)

---
updated-dependencies:
- dependency-name: dns-packet
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-08 19:55:47 +00:00
Oleg Lobanov
ffe960a8c2 Merge pull request #1817 from filebrowser/dependabot/npm_and_yarn/frontend/ws-6.2.2
build(deps): bump ws from 6.2.1 to 6.2.2 in /frontend
2022-02-08 20:55:07 +01:00
dependabot[bot]
73c80732d9 build(deps): bump ws from 6.2.1 to 6.2.2 in /frontend
Bumps [ws](https://github.com/websockets/ws) from 6.2.1 to 6.2.2.
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/6.2.1...6.2.2)

---
updated-dependencies:
- dependency-name: ws
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-08 19:53:09 +00:00
Oleg Lobanov
8e2663bf7b Merge pull request #1816 from filebrowser/dependabot/npm_and_yarn/frontend/path-parse-1.0.7
build(deps): bump path-parse from 1.0.6 to 1.0.7 in /frontend
2022-02-08 20:53:01 +01:00
Oleg Lobanov
e697e58164 Merge pull request #1815 from filebrowser/dependabot/npm_and_yarn/frontend/url-parse-1.5.4
build(deps): bump url-parse from 1.5.1 to 1.5.4 in /frontend
2022-02-08 20:52:24 +01:00
dependabot[bot]
c01496624a build(deps): bump path-parse from 1.0.6 to 1.0.7 in /frontend
Bumps [path-parse](https://github.com/jbgutierrez/path-parse) from 1.0.6 to 1.0.7.
- [Release notes](https://github.com/jbgutierrez/path-parse/releases)
- [Commits](https://github.com/jbgutierrez/path-parse/commits/v1.0.7)

---
updated-dependencies:
- dependency-name: path-parse
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-08 19:29:52 +00:00
dependabot[bot]
8906408a8f build(deps): bump url-parse from 1.5.1 to 1.5.4 in /frontend
Bumps [url-parse](https://github.com/unshiftio/url-parse) from 1.5.1 to 1.5.4.
- [Release notes](https://github.com/unshiftio/url-parse/releases)
- [Commits](https://github.com/unshiftio/url-parse/compare/1.5.1...1.5.4)

---
updated-dependencies:
- dependency-name: url-parse
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-08 19:29:52 +00:00
Oleg Lobanov
3ec7951380 Merge pull request #1813 from filebrowser/dependabot/npm_and_yarn/frontend/postcss-7.0.39
build(deps): bump postcss from 7.0.35 to 7.0.39 in /frontend
2022-02-08 20:29:21 +01:00
Oleg Lobanov
b30aefa522 Merge pull request #1812 from filebrowser/dependabot/npm_and_yarn/frontend/follow-redirects-1.14.8
build(deps): bump follow-redirects from 1.13.3 to 1.14.8 in /frontend
2022-02-08 20:29:04 +01:00
Oleg Lobanov
bc8a750dfe Merge pull request #1814 from filebrowser/dependabot/npm_and_yarn/frontend/tar-6.1.11
build(deps): bump tar from 6.1.0 to 6.1.11 in /frontend
2022-02-08 20:28:47 +01:00
dependabot[bot]
f1f7f17ade build(deps): bump follow-redirects from 1.13.3 to 1.14.8 in /frontend
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.13.3 to 1.14.8.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.13.3...v1.14.8)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-08 19:27:05 +00:00
dependabot[bot]
9182d33e1c build(deps): bump postcss from 7.0.35 to 7.0.39 in /frontend
Bumps [postcss](https://github.com/postcss/postcss) from 7.0.35 to 7.0.39.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/7.0.39/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/7.0.35...7.0.39)

---
updated-dependencies:
- dependency-name: postcss
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-08 19:26:52 +00:00
Oleg Lobanov
7d836a3728 Merge pull request #1786 from Jmainguy/typos
fix typos
2022-02-08 20:25:30 +01:00
dependabot[bot]
010d16fc1d build(deps): bump tar from 6.1.0 to 6.1.11 in /frontend
Bumps [tar](https://github.com/npm/node-tar) from 6.1.0 to 6.1.11.
- [Release notes](https://github.com/npm/node-tar/releases)
- [Changelog](https://github.com/npm/node-tar/blob/main/CHANGELOG.md)
- [Commits](https://github.com/npm/node-tar/compare/v6.1.0...v6.1.11)

---
updated-dependencies:
- dependency-name: tar
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-08 19:25:15 +00:00
Oleg Lobanov
fa89ba4665 Merge branch 'master' into typos 2022-02-08 20:25:14 +01:00
Oleg Lobanov
a0752904c1 Merge pull request #1811 from filebrowser/dependabot/npm_and_yarn/frontend/ssri-6.0.2
build(deps): bump ssri from 6.0.1 to 6.0.2 in /frontend
2022-02-08 20:24:18 +01:00
dependabot[bot]
371718634b build(deps): bump ssri from 6.0.1 to 6.0.2 in /frontend
Bumps [ssri](https://github.com/npm/ssri) from 6.0.1 to 6.0.2.
- [Release notes](https://github.com/npm/ssri/releases)
- [Changelog](https://github.com/npm/ssri/blob/v6.0.2/CHANGELOG.md)
- [Commits](https://github.com/npm/ssri/compare/v6.0.1...v6.0.2)

---
updated-dependencies:
- dependency-name: ssri
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-08 19:09:43 +00:00
Oleg Lobanov
0f4f8751f2 Merge pull request #1769 from adrium/feat-icons
Add colorized file type icons
2022-02-08 20:08:52 +01:00
sejinP
ec45ee471f chore: remove GOMAXPROCS setting (#1803) 2022-02-08 19:56:04 +01:00
Jonathan Seth Mainguy
6fffcbac4e chore: fix typos 2022-01-28 09:46:21 -05:00
Adrian
2948589fcd feat: add colorized file type icons 2022-01-18 08:40:06 +01:00
Adrian
ecd0b2ee0d chore: update Material Icons 2022-01-17 23:21:45 +01:00
on4r
205f11d677 chore: rotate the spinner clockwise (#1765) 2022-01-11 21:23:46 +01:00
niubility000
949f0f277f fix: open all the pdf files correctly (#1742) 2022-01-10 17:01:21 +01:00
Anton Grouchtchak
665e45889c feat: add Ukrainian translation / update Russian translation (#1753) 2022-01-07 12:29:57 +01:00
Oleg Lobanov
8d87e0d5f9 chore(release): 2.20.1 2021-12-21 14:40:04 +01:00
Oleg Lobanov
46d80464d2 build: revert to using the default alpine based docker image
Build both standard and linuxserver based images.
linuxserver based images can be accessed by adding `-s6` suffix to the docker image name
2021-12-21 14:39:34 +01:00
Oleg Lobanov
829ed9fb6d chore(release): 2.20.0 2021-12-21 00:48:46 +01:00
Oleg Lobanov
988d3e5bdd fix: set correct default database path in the config 2021-12-21 00:47:40 +01:00
Oleg Lobanov
6eb3ab0635 fix: upgrade vulnerable versions of the library 2021-12-21 00:17:26 +01:00
Mazen Besher
c2e03bbfab feat: detect multiple subtitle languages (#1723) 2021-12-21 00:07:43 +01:00
Oleg Lobanov
608a0015ee Merge pull request #1729 from filebrowser/add_linuxserver
Refactoring
2021-12-20 23:40:11 +01:00
Oleg Lobanov
f81857acce build: refactor makefile 2021-12-20 23:36:50 +01:00
Oleg Lobanov
b1e0d5b39f chore: add make fmt target 2021-12-20 22:39:00 +01:00
Oleg Lobanov
68cf7a2173 chore: upgrade go to 1.17 2021-12-20 22:31:53 +01:00
Oleg Lobanov
89d1c06441 ci: run CI linters concurrently 2021-12-20 22:31:52 +01:00
Oleg Lobanov
2bebb5f0f8 ci: fix frontend formatting 2021-12-20 22:29:41 +01:00
Oleg Lobanov
683b11d265 chore: add dist folder to .gitignore 2021-12-20 22:29:40 +01:00
Oleg Lobanov
4d1b9dd211 build: remove deprecated goreleaser use_buildx param 2021-12-20 22:29:39 +01:00
Oleg Lobanov
b8f35ce932 feat: use linuxserver based docker image 2021-12-20 22:29:39 +01:00
Oleg Lobanov
a078f0b787 chore(release): 2.19.0 2021-11-24 21:30:26 +01:00
niubility000
7401d16e45 feat: prefetch previous and next images in preview. (#1627) 2021-11-15 14:54:28 +01:00
Oleg Lobanov
958a44f95e Merge pull request #1662 from ramiresviana/fixes-11 2021-11-11 16:45:53 +01:00
Ramires Viana
e08239781f fix: empty file listing on share 2021-11-11 13:06:04 +00:00
Ramires Viana
c29698dffa fix: relative font sizes 2021-11-11 12:54:30 +00:00
coxde
81de95632a chore: update zh-cn.json (#1656) 2021-11-10 15:07:53 +01:00
Oleg Lobanov
7f2d221083 chore(release): 2.18.0 2021-10-31 17:18:01 +01:00
Oleg Lobanov
74b7cd8e81 fix: security issue in command runner (closes #1621) 2021-10-31 17:13:16 +01:00
niubility000
6cb51b4eb4 Add files via upload (#1615) 2021-10-24 13:35:29 +04:00
niubility000
f09bf3e1d0 fix: fix sidebar navigation on mobile devices (#1618) 2021-10-19 20:37:12 +04:00
niubility000
6f345be3e4 fix: search box is misaligned when the browser preferred font size is other than 16px (#1613) 2021-10-19 20:34:17 +04:00
niubility000
ddd4ffa4ca fix: set correct editor height regardless of preferred font size (#1614) 2021-10-19 20:32:25 +04:00
niubility000
deabc80fd7 fix: back button behaviour in preview (#1573) 2021-10-12 13:09:05 +02:00
niubility000
b6a51bed51 fix: zoom pics when dlclick at first time (#1561) 2021-09-23 10:21:17 +02:00
lilihx
0426629a59 feat: add ability to select file modified time format (#1536) 2021-09-11 14:12:51 +02:00
Ryan Qian
0358e42d2c feat: add manifest theme color param (#1542) 2021-09-10 17:08:15 +02:00
Filip Hanes
3768e3345f chore: add slovak translation (#1534) 2021-09-03 12:03:50 +02:00
ahmetlutfu
16e434be66 chore: add turkish translation (#1524) 2021-08-31 11:49:33 +02:00
Oleg Lobanov
bf303c536a chore(release): 2.17.2 2021-08-27 12:40:51 +02:00
Andrew Kennedy
43a460993c fix: bug with inlineLink not creating url properly (#1515) 2021-08-26 12:43:37 +02:00
Oleg Lobanov
7f0673ee70 chore(release): 2.17.1 2021-08-23 10:03:31 +02:00
Oleg Lobanov
4c3099a086 fix: internal server error if --disable-preview-resize flag is set (closes #1510) 2021-08-23 10:03:11 +02:00
Oleg Lobanov
f0bc9167b1 chore(release): 2.17.0 2021-08-21 16:51:34 +02:00
Ramires Viana
23d646c456 fix: escape quote on index template
fixes #1501
2021-08-20 14:43:06 +02:00
Ramires Viana
76add9e527 feat: open file option on preview 2021-08-20 14:43:06 +02:00
Ramires Viana
c63cc5a2d2 fix: file caching directive 2021-08-20 14:43:06 +02:00
Andrew Kennedy
25c8788390 fix: 401 error in share view open file button (#1495) 2021-08-19 14:35:24 +02:00
Oleg Lobanov
aa52b07bb1 chore(release): 2.16.1 2021-08-04 11:44:29 +02:00
Oleg Lobanov
76b466f649 fix: check symlink target type (closes #1488) 2021-08-04 11:44:02 +02:00
194 changed files with 14818 additions and 27599 deletions

View File

@@ -1,3 +1,5 @@
*
!.docker.json
!docker/*
!healthcheck.sh
!docker_config.json
!filebrowser

View File

@@ -4,12 +4,11 @@ Please explain the changes you made here.
If the feature changes current behaviour, explain why your solution is better.
-->
:rotating_light: Before submitting your PR, please read [community](https://github.com/filebrowser/community), and indicate which issues (in any of the repos) are either fixed or closed by this PR. See [GitHub Help: Closing issues using keywords](https://help.github.com/articles/closing-issues-via-commit-messages/).
:rotating_light: Before submitting your PR, please indicate which issues are either fixed or closed by this PR. See [GitHub Help: Closing issues using keywords](https://help.github.com/articles/closing-issues-via-commit-messages/).
- [ ] DO make sure you are requesting to **pull a topic/feature/bugfix branch** (right side). Don't request your master!
- [ ] DO make sure you are making a pull request against the **master branch** (left side). Also you should start *your branch* off *our master*.
- [ ] DO make sure that File Browser can be successfully built. See [builds](https://github.com/filebrowser/community/blob/master/builds.md) and [development](https://github.com/filebrowser/community/blob/master/development.md).
- [ ] DO make sure that related issues are opened in other repositories. I.e., the frontend, caddy plugins or the web page need to be updated accordingly.
- [ ] AVOID breaking the continuous integration build.
**Further comments**

View File

@@ -9,48 +9,82 @@ on:
pull_request:
jobs:
# linters
lint-frontend:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '18'
- run: make lint-frontend
lint-backend:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: 1.21.0
- run: make lint-backend
lint-commits:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: '18'
- run: make lint-commits
lint:
runs-on: ubuntu-latest
needs: [lint-frontend, lint-backend, lint-commits]
steps:
- uses: actions/checkout@v2
- uses: actions/setup-go@v2
with:
go-version: 1.16
- uses: actions/setup-node@v2
with:
node-version: '14'
- run: npm i -g commitlint
- run: make lint
test:
- run: echo "done"
# tests
test-frontend:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-go@v2
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
go-version: 1.16
- uses: actions/setup-node@v2
node-version: '18'
- run: make test-frontend
test-backend:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
node-version: '14'
- run: make test
go-version: 1.21.0
- run: make test-backend
test:
runs-on: ubuntu-latest
needs: [test-frontend, test-backend]
steps:
- run: echo "done"
# release
release:
runs-on: ubuntu-latest
needs: [lint, test]
if: startsWith(github.event.ref, 'refs/tags/v')
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-go@v2
- uses: actions/setup-go@v5
with:
go-version: 1.16
- uses: actions/setup-node@v2
go-version: 1.21.0
- uses: actions/setup-node@v4
with:
node-version: '14'
node-version: '18'
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Build fronetend
- name: Build frontend
run: make build-frontend
- name: Login to Docker Hub
uses: docker/login-action@v1
@@ -61,6 +95,6 @@ jobs:
uses: goreleaser/goreleaser-action@v2
with:
version: latest
args: release --rm-dist
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GH_PAT }}
GITHUB_TOKEN: ${{ secrets.GH_PAT }}

24
.github/workflows/stale.yml vendored Normal file
View File

@@ -0,0 +1,24 @@
name: 'Close stale issues and PRs'
permissions:
issues: write
pull-requests: write
on:
schedule:
- cron: '30 1 * * *'
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v5
with:
stale-pr-message: 'This PR is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.'
close-pr-message: 'This PR was closed because it has been stalled for 5 days with no activity.'
stale-issue-message: 'This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.'
close-issue-message: 'This issue was closed because it has been stalled for 5 days with no activity.'
days-before-stale: 30
days-before-close: 5
exempt-issue-labels: 'feature ☘,enhancement ⚙,bug 🐞'
exempt-pr-labels: 'need-help,wip'
operations-per-run: 100

9
.gitignore vendored
View File

@@ -1,11 +1,11 @@
*.db
*.lock
*.bak
_old
rice-box.go
.idea/
filebrowser
filebrowser.exe
/filebrowser
/filebrowser.exe
/dist
.DS_Store
node_modules
@@ -29,3 +29,6 @@ yarn-error.log*
*.sw*
bin/
build/
/frontend/dist/*
!/frontend/dist/.gitkeep

View File

@@ -54,7 +54,6 @@ linters:
enable:
- bodyclose
- deadcode
- depguard
- dogsled
- dupl
- errcheck
@@ -109,6 +108,7 @@ issues:
- gomnd
run:
go: '1.18'
skip-dirs:
- frontend/
skip-files:

View File

@@ -3,32 +3,33 @@ project_name: filebrowser
env:
- GO111MODULE=on
build:
env:
- CGO_ENABLED=0
ldflags:
- -s -w -X github.com/filebrowser/filebrowser/v2/version.Version={{ .Version }} -X github.com/filebrowser/filebrowser/v2/version.CommitSHA={{ .ShortCommit }}
main: main.go
binary: filebrowser
goos:
- darwin
- linux
- windows
- freebsd
goarch:
- amd64
- 386
- arm
- arm64
goarm:
- 5
- 6
- 7
ignore:
- goos: darwin
goarch: 386
- goos: freebsd
goarch: arm
builds:
- env:
- CGO_ENABLED=0
ldflags:
- -s -w -X github.com/filebrowser/filebrowser/v2/version.Version={{ .Version }} -X github.com/filebrowser/filebrowser/v2/version.CommitSHA={{ .ShortCommit }}
main: main.go
binary: filebrowser
goos:
- darwin
- linux
- windows
- freebsd
goarch:
- amd64
- 386
- arm
- arm64
- riscv64
goarm:
- 5
- 6
- 7
ignore:
- goos: darwin
goarch: 386
- goos: freebsd
goarch: arm
archives:
-
@@ -41,7 +42,7 @@ archives:
dockers:
-
dockerfile: Dockerfile
use_buildx: true
use: buildx
build_flag_templates:
- "--pull"
- "--label=org.opencontainers.image.created={{.Date}}"
@@ -56,10 +57,11 @@ dockers:
- "filebrowser/filebrowser:{{ .Tag }}-amd64"
- "filebrowser/filebrowser:v{{ .Major }}-amd64"
extra_files:
- .docker.json
- docker_config.json
- healthcheck.sh
-
dockerfile: Dockerfile
use_buildx: true
use: buildx
build_flag_templates:
- "--pull"
- "--label=org.opencontainers.image.created={{.Date}}"
@@ -74,10 +76,11 @@ dockers:
- "filebrowser/filebrowser:{{ .Tag }}-arm64"
- "filebrowser/filebrowser:v{{ .Major }}-arm64"
extra_files:
- .docker.json
- docker_config.json
- healthcheck.sh
-
dockerfile: Dockerfile
use_buildx: true
use: buildx
build_flag_templates:
- "--pull"
- "--label=org.opencontainers.image.created={{.Date}}"
@@ -93,10 +96,11 @@ dockers:
- "filebrowser/filebrowser:{{ .Tag }}-armv6"
- "filebrowser/filebrowser:v{{ .Major }}-armv6"
extra_files:
- .docker.json
- docker_config.json
- healthcheck.sh
-
dockerfile: Dockerfile
use_buildx: true
use: buildx
build_flag_templates:
- "--pull"
- "--label=org.opencontainers.image.created={{.Date}}"
@@ -112,29 +116,77 @@ dockers:
- "filebrowser/filebrowser:{{ .Tag }}-armv7"
- "filebrowser/filebrowser:v{{ .Major }}-armv7"
extra_files:
- .docker.json
- docker_config.json
- healthcheck.sh
## s6 based docker images
-
dockerfile: Dockerfile.s6
use: buildx
build_flag_templates:
- "--pull"
- "--label=org.opencontainers.image.created={{.Date}}"
- "--label=org.opencontainers.image.name={{.ProjectName}}"
- "--label=org.opencontainers.image.revision={{.FullCommit}}"
- "--label=org.opencontainers.image.version={{.Version}}"
- "--label=org.opencontainers.image.source={{.GitURL}}"
- "--platform=linux/amd64"
goos: linux
goarch: amd64
image_templates:
- "filebrowser/filebrowser:{{ .Tag }}-amd64-s6"
- "filebrowser/filebrowser:v{{ .Major }}-amd64-s6"
extra_files:
- docker/root
-
dockerfile: Dockerfile.s6.aarch64
use: buildx
build_flag_templates:
- "--pull"
- "--label=org.opencontainers.image.created={{.Date}}"
- "--label=org.opencontainers.image.name={{.ProjectName}}"
- "--label=org.opencontainers.image.revision={{.FullCommit}}"
- "--label=org.opencontainers.image.version={{.Version}}"
- "--label=org.opencontainers.image.source={{.GitURL}}"
- "--platform=linux/arm64"
goos: linux
goarch: arm64
image_templates:
- "filebrowser/filebrowser:{{ .Tag }}-arm64-s6"
- "filebrowser/filebrowser:v{{ .Major }}-arm64-s6"
extra_files:
- docker/root
docker_manifests:
- name_template: "filebrowser/filebrowser:latest"
image_templates:
- "filebrowser/filebrowser:{{ .Tag }}-amd64"
- "filebrowser/filebrowser:{{ .Tag }}-arm64"
- "filebrowser/filebrowser:{{ .Tag }}-armv6"
- "filebrowser/filebrowser:{{ .Tag }}-armv7"
- name_template: "filebrowser/filebrowser:{{ .Tag }}"
image_templates:
- "filebrowser/filebrowser:{{ .Tag }}-amd64"
- "filebrowser/filebrowser:{{ .Tag }}-arm64"
- "filebrowser/filebrowser:{{ .Tag }}-armv6"
- "filebrowser/filebrowser:{{ .Tag }}-armv7"
- name_template: "filebrowser/filebrowser:v{{ .Major }}"
image_templates:
- "filebrowser/filebrowser:v{{ .Major }}-amd64"
- "filebrowser/filebrowser:v{{ .Major }}-arm64"
- "filebrowser/filebrowser:v{{ .Major }}-armv6"
- "filebrowser/filebrowser:v{{ .Major }}-armv7"
## s6 image manifests
- name_template: "filebrowser/filebrowser:s6"
image_templates:
- "filebrowser/filebrowser:{{ .Tag }}-amd64-s6"
- "filebrowser/filebrowser:{{ .Tag }}-arm64-s6"
- name_template: "filebrowser/filebrowser:{{ .Tag }}-s6"
image_templates:
- "filebrowser/filebrowser:{{ .Tag }}-amd64-s6"
- "filebrowser/filebrowser:{{ .Tag }}-arm64-s6"
- name_template: "filebrowser/filebrowser:v{{ .Major }}-s6"
image_templates:
- "filebrowser/filebrowser:v{{ .Major }}-amd64-s6"
- "filebrowser/filebrowser:v{{ .Major }}-arm64-s6"
brews:
- name: filebrowser
tap:
repository:
owner: filebrowser
name: homebrew-tap
folder: Formula
@@ -143,4 +195,4 @@ brews:
name: FileBrowser Robot
email: robot@filebrowser.org
description: File Browser is a create-your-own-cloud-kind of software where you can install it on a server, direct it to a path and then access your files through a nice web interface
license: "MIT"
license: "MIT"

View File

@@ -2,6 +2,424 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
## [2.28.0](https://github.com/filebrowser/filebrowser/compare/v2.27.0...v2.28.0) (2024-04-01)
### Features
* allow to configure if home directory is automatically created from cli ([#2963](https://github.com/filebrowser/filebrowser/issues/2963)) ([a4b089a](https://github.com/filebrowser/filebrowser/commit/a4b089a6dbf9821ecede428cd7d13e69c8b85231))
* auto hiding header bar in preview to enlarge the preview window ([#3024](https://github.com/filebrowser/filebrowser/issues/3024)) ([d706506](https://github.com/filebrowser/filebrowser/commit/d70650689c34ce9f631fda6a453fd521faef22fa))
* close editor when click escape key ([#2947](https://github.com/filebrowser/filebrowser/issues/2947)) ([70c8261](https://github.com/filebrowser/filebrowser/commit/70c826133b8578b8712e6db8f762a15a076cd9a9))
* enable preview in shared folder ([#3055](https://github.com/filebrowser/filebrowser/issues/3055)) ([4c233c3](https://github.com/filebrowser/filebrowser/commit/4c233c3db39ea5a00d6e602ec0ecbddecb590877))
* focus editor when opened ([#2946](https://github.com/filebrowser/filebrowser/issues/2946)) ([b19710e](https://github.com/filebrowser/filebrowser/commit/b19710efca6daa7af56dc211d0051d500d2eea22))
* freezing the list in the backgroud while previewing a file ([#3004](https://github.com/filebrowser/filebrowser/issues/3004)) ([e167c3e](https://github.com/filebrowser/filebrowser/commit/e167c3e1efed8b16be45d994a8d443fda1d8cf49))
* prompt to confirm discard editor changes ([#2948](https://github.com/filebrowser/filebrowser/issues/2948)) ([fb1a09c](https://github.com/filebrowser/filebrowser/commit/fb1a09c7c172b913c12b30975ca545e505df0c05))
* select multiple files with ctrl even with singleClick option ([#2953](https://github.com/filebrowser/filebrowser/issues/2953)) ([d49c3df](https://github.com/filebrowser/filebrowser/commit/d49c3dfacfc0ff07e620b3ad2700e64927b06235))
### Bug Fixes
* dashboard buttons position in rtl layout ([#2949](https://github.com/filebrowser/filebrowser/issues/2949)) ([2cfee21](https://github.com/filebrowser/filebrowser/commit/2cfee2183c98d0cb67fc4e9788644ed4278e25bc))
* editor discard prompt ([#2990](https://github.com/filebrowser/filebrowser/issues/2990)) ([34a0817](https://github.com/filebrowser/filebrowser/commit/34a08170c894321d49bb843e259a0e59e2245998))
* files and directories are created with the correct permissions ([#2966](https://github.com/filebrowser/filebrowser/issues/2966)) ([5c5ab6b](https://github.com/filebrowser/filebrowser/commit/5c5ab6b8750a5168f0ae2a26bd5de41e0b6d9637))
* fix lint warnings ([#2976](https://github.com/filebrowser/filebrowser/issues/2976)) ([fe5ca74](https://github.com/filebrowser/filebrowser/commit/fe5ca74aa1e4257e5cb36f1de58daa0c3548319f))
* **healthcheck:** use address configured if not empty ([#2938](https://github.com/filebrowser/filebrowser/issues/2938)) ([81cd8fc](https://github.com/filebrowser/filebrowser/commit/81cd8fc6d307b00af278beefcdbad4158a128fea))
* keyboard shortcut to confirm prompts ([#2932](https://github.com/filebrowser/filebrowser/issues/2932)) ([ff9502f](https://github.com/filebrowser/filebrowser/commit/ff9502ff34790c46f31d175911cd51c9b62804fb))
* moment locale ([#2952](https://github.com/filebrowser/filebrowser/issues/2952)) ([883383a](https://github.com/filebrowser/filebrowser/commit/883383a5715d82883c51138dfb547805dfad2a3c))
* shell direction ([#2980](https://github.com/filebrowser/filebrowser/issues/2980)) ([6d7ba65](https://github.com/filebrowser/filebrowser/commit/6d7ba65faf576ee4ed095f3d0c41775b21e498de))
* stay in the same position after renaming or deleting ([#3039](https://github.com/filebrowser/filebrowser/issues/3039)) ([cdf8def](https://github.com/filebrowser/filebrowser/commit/cdf8def3304315bef261da7f52f8599d90b1f0f0))
### Build
* **deps-dev:** bump vite from 4.4.12 to 4.5.2 in /frontend ([#2951](https://github.com/filebrowser/filebrowser/issues/2951)) ([bf36cc0](https://github.com/filebrowser/filebrowser/commit/bf36cc00f1369dd10a422f230ccabcbeefae1517))
* **deps:** bump google.golang.org/protobuf from 1.31.0 to 1.33.0 ([#3045](https://github.com/filebrowser/filebrowser/issues/3045)) ([05bfae2](https://github.com/filebrowser/filebrowser/commit/05bfae264a7a477d1b7db582f06f4efb24d26ec9))
* **deps:** bump google.golang.org/protobuf in /tools ([#3044](https://github.com/filebrowser/filebrowser/issues/3044)) ([7797a4e](https://github.com/filebrowser/filebrowser/commit/7797a4ef18038a877df31bd34f2ebf70d18823f8))
## [2.27.0](https://github.com/filebrowser/filebrowser/compare/v2.26.0...v2.27.0) (2024-01-02)
### Features
* allow setting theme via cli ([#2881](https://github.com/filebrowser/filebrowser/issues/2881)) ([748af71](https://github.com/filebrowser/filebrowser/commit/748af7172ce96f0b66c394e88839bd57c194ffc7))
* display image resolutions in file details ([#2830](https://github.com/filebrowser/filebrowser/issues/2830)) ([a09dfa8](https://github.com/filebrowser/filebrowser/commit/a09dfa8d9f190243d811a841de44c4abb4403d87))
* make user session timeout configurable by flags ([#2845](https://github.com/filebrowser/filebrowser/issues/2845)) ([391a078](https://github.com/filebrowser/filebrowser/commit/391a078cd486e618c95a0c5850326076cbc025b6))
### Bug Fixes
* delete message when delete file from preview ([3264cea](https://github.com/filebrowser/filebrowser/commit/3264cea8307dca9ab5463dc81f2a10a817eb3d54))
* fix typo ([#2843](https://github.com/filebrowser/filebrowser/issues/2843)) ([4dbc802](https://github.com/filebrowser/filebrowser/commit/4dbc802972c930f5f42fc27507fac35c28c42afd))
* set correct port in docker healthcheck ([#2812](https://github.com/filebrowser/filebrowser/issues/2812)) ([d59ad59](https://github.com/filebrowser/filebrowser/commit/d59ad594b8649f57f61453b0dfbc350c57b690a2))
* typo in build error [#2903](https://github.com/filebrowser/filebrowser/issues/2903) ([#2904](https://github.com/filebrowser/filebrowser/issues/2904)) ([c4e955a](https://github.com/filebrowser/filebrowser/commit/c4e955acf4a1a8f8e8e94f697ffc838515e69a60))
### Build
* **deps-dev:** bump vite from 4.4.9 to 4.4.12 in /frontend ([#2862](https://github.com/filebrowser/filebrowser/issues/2862)) ([fc2ee37](https://github.com/filebrowser/filebrowser/commit/fc2ee373536584d024f7def62f350bdbb712d927))
* **deps:** bump golang.org/x/crypto from 0.14.0 to 0.17.0 ([#2890](https://github.com/filebrowser/filebrowser/issues/2890)) ([821fba4](https://github.com/filebrowser/filebrowser/commit/821fba41a25ba99d47641f01b10ac51960157888))
## [2.26.0](https://github.com/filebrowser/filebrowser/compare/v2.25.0...v2.26.0) (2023-11-02)
### Features
* add modern greek translation ([#2778](https://github.com/filebrowser/filebrowser/issues/2778)) ([c3079d3](https://github.com/filebrowser/filebrowser/commit/c3079d30e22385d7e677f172324cd9cbab6487ce))
* make user session timeout configurable ([#2753](https://github.com/filebrowser/filebrowser/issues/2753)) ([7fabadc](https://github.com/filebrowser/filebrowser/commit/7fabadc871ea91ea22fe9454e2ca4b33e5c211be))
### Bug Fixes
* avoid the front-end calling api/renew loop ([#2792](https://github.com/filebrowser/filebrowser/issues/2792)) ([edd808f](https://github.com/filebrowser/filebrowser/commit/edd808f124f4ada99bcbe4bca98ddbe20e5a424c))
* disable static resource files listing ([da1fe7c](https://github.com/filebrowser/filebrowser/commit/da1fe7c9d76a9c6a25bfa19ebd6cf8023eff5d62))
* display file size as base 2 (KiB instead of KB) ([#2779](https://github.com/filebrowser/filebrowser/issues/2779)) ([cdcd9a3](https://github.com/filebrowser/filebrowser/commit/cdcd9a313aa50c2e6806a182b6838462d42dcafe))
* goreleaser yaml ([4d0a68e](https://github.com/filebrowser/filebrowser/commit/4d0a68e7875274f4c939f2bfa15739a9b0ecf70a))
* revert fetchURL changes in auth (Fixes [#2729](https://github.com/filebrowser/filebrowser/issues/2729)) ([#2739](https://github.com/filebrowser/filebrowser/issues/2739)) ([bd3c194](https://github.com/filebrowser/filebrowser/commit/bd3c1941ff8289a5dae877e08f7e25fa9b2a92c5))
* solve docker build failed issue ([#2797](https://github.com/filebrowser/filebrowser/issues/2797)) ([6a31af6](https://github.com/filebrowser/filebrowser/commit/6a31af6c0a144128af865d802c8039fa5250e946))
### Build
* **deps-dev:** bump postcss from 8.4.27 to 8.4.31 in /frontend ([#2749](https://github.com/filebrowser/filebrowser/issues/2749)) ([21d361a](https://github.com/filebrowser/filebrowser/commit/21d361ad308d109d2a6b323597019aaa09ce1781))
* **deps:** bump @babel/traverse in /frontend ([#2775](https://github.com/filebrowser/filebrowser/issues/2775)) ([bb4bb50](https://github.com/filebrowser/filebrowser/commit/bb4bb508a9d71516e8fa80b3a6285fe002a059d2))
* **deps:** bump golang.org/x/image from 0.5.0 to 0.10.0 ([#2800](https://github.com/filebrowser/filebrowser/issues/2800)) ([a744bd2](https://github.com/filebrowser/filebrowser/commit/a744bd224f0ff1efc53ab94481fa76ef68788df1))
* **deps:** bump golang.org/x/net from 0.11.0 to 0.17.0 ([#2758](https://github.com/filebrowser/filebrowser/issues/2758)) ([d574fb6](https://github.com/filebrowser/filebrowser/commit/d574fb6d1af41ec31778b0f402674e5111a7875d))
* fix deprecated goreleaser config options ([38f7788](https://github.com/filebrowser/filebrowser/commit/38f77882559133b9ff330cfb955a9d4ea4728cf8))
## [2.25.0](https://github.com/filebrowser/filebrowser/compare/v2.24.2...v2.25.0) (2023-09-14)
### Features
* add new folder button to move/create dialogs ([#2667](https://github.com/filebrowser/filebrowser/issues/2667)) ([5994224](https://github.com/filebrowser/filebrowser/commit/599422446849fa37d5ab448bbf464afb7304b99d))
* added shell resizing ([#2648](https://github.com/filebrowser/filebrowser/issues/2648)) ([584b706](https://github.com/filebrowser/filebrowser/commit/584b706b1e310297acc2580c60442ff5c11ae432))
* implement abort upload functionality ([#2673](https://github.com/filebrowser/filebrowser/issues/2673)) ([a404fb0](https://github.com/filebrowser/filebrowser/commit/a404fb043da2573bf04385863b2d34b1f918b8e1))
* implement upload speed calculation and ETA estimation ([#2677](https://github.com/filebrowser/filebrowser/issues/2677)) ([ecdd684](https://github.com/filebrowser/filebrowser/commit/ecdd684bf1d537a4591caa38348102b61dd51e5d))
### Bug Fixes
* refactor path resolution logic for project root ([#2674](https://github.com/filebrowser/filebrowser/issues/2674)) ([95fec7f](https://github.com/filebrowser/filebrowser/commit/95fec7f69430c108e5cf95c428db9d671cd97a94))
* tus upload with cloudflare proxy ([36af01d](https://github.com/filebrowser/filebrowser/commit/36af01daa6e04005ce3d18985eebaeef06f7393d)), closes [#2593](https://github.com/filebrowser/filebrowser/issues/2593)
### Refactorings
* migrate frontend tooling to vite 4 ([#2645](https://github.com/filebrowser/filebrowser/issues/2645)) ([8838a09](https://github.com/filebrowser/filebrowser/commit/8838a09cf5104deac22b6143050588040c6825e6))
### Build
* bump go version to 1.21.0 ([#2672](https://github.com/filebrowser/filebrowser/issues/2672)) ([2c97573](https://github.com/filebrowser/filebrowser/commit/2c97573301a1b13179678fb7f9bd8316539ecdff))
* bump node version to 18 ([#2671](https://github.com/filebrowser/filebrowser/issues/2671)) ([70eba7e](https://github.com/filebrowser/filebrowser/commit/70eba7ecc9d19545c0899ae40eb3897a7c48562f))
### Performance improvements
* **backend:** optimize subtitles detection performance ([#2637](https://github.com/filebrowser/filebrowser/issues/2637)) ([374bbd3](https://github.com/filebrowser/filebrowser/commit/374bbd3ec199fddbe491ab2b74e520a10a73e54b))
### [2.24.2](https://github.com/filebrowser/filebrowser/compare/v2.24.1...v2.24.2) (2023-08-08)
### Bug Fixes
* 403 error error when uploading ([#2598](https://github.com/filebrowser/filebrowser/issues/2598)) ([289c8e6](https://github.com/filebrowser/filebrowser/commit/289c8e6f32eb520cc711389f6b6a4ed94a73ecd4))
* config init for branding.disableUsedPercentage ([#2576](https://github.com/filebrowser/filebrowser/issues/2576)) ([#2596](https://github.com/filebrowser/filebrowser/issues/2596)) ([ff1e0b8](https://github.com/filebrowser/filebrowser/commit/ff1e0b8185faf14b1f8e91830ca5e71e68ab672e))
### Build
* add riscv64 binary releases ([#2587](https://github.com/filebrowser/filebrowser/issues/2587)) ([0ac3968](https://github.com/filebrowser/filebrowser/commit/0ac39684f175487314e97403406f4d2c482e3d79))
### [2.24.1](https://github.com/filebrowser/filebrowser/compare/v2.24.0...v2.24.1) (2023-07-31)
### Bug Fixes
* add directory creation code to partial upload handler ([#2575](https://github.com/filebrowser/filebrowser/issues/2575)) ([#2580](https://github.com/filebrowser/filebrowser/issues/2580)) ([912f27a](https://github.com/filebrowser/filebrowser/commit/912f27a9e3286ee4bf2a27b366a1d35b3b55799c))
* resolved CSS rendering issue in Chrome browser ([#2582](https://github.com/filebrowser/filebrowser/issues/2582)) ([2a4a46c](https://github.com/filebrowser/filebrowser/commit/2a4a46c61a5d5376bea65b28d0eb6a7ec2fdf4e5))
### Build
* **backend:** upgrade golangci-lint to v1.53.3 ([efd41cc](https://github.com/filebrowser/filebrowser/commit/efd41cc4c147b8d2d5e61fb2642df8d934f49362))
## [2.24.0](https://github.com/filebrowser/filebrowser/compare/v2.23.0...v2.24.0) (2023-07-29)
### Features
* add a healthcheck script that works with a dynamic port ([#2510](https://github.com/filebrowser/filebrowser/issues/2510)) ([ff4375c](https://github.com/filebrowser/filebrowser/commit/ff4375cf6ce849459889f892dd91304703c52dcd))
* add a new setting that disables the display of the disk usage ([#2136](https://github.com/filebrowser/filebrowser/issues/2136)) ([428c1c6](https://github.com/filebrowser/filebrowser/commit/428c1c606d1b858ed0eb58b7c31f570bc6a9b792))
* add Hungarian translation ([#2232](https://github.com/filebrowser/filebrowser/issues/2232)) ([11e9202](https://github.com/filebrowser/filebrowser/commit/11e92021607e12efff9fb2d5c8728483eee31199))
* add option to copy download links from shares ([#2442](https://github.com/filebrowser/filebrowser/issues/2442)) ([a4ef02a](https://github.com/filebrowser/filebrowser/commit/a4ef02a47b53742a0ac1f639563b0c67116619c8))
* integrate tus.io for resumable and chunked uploads ([#2145](https://github.com/filebrowser/filebrowser/issues/2145)) ([7b35815](https://github.com/filebrowser/filebrowser/commit/7b35815754690540f76e3ffe114eedb47cfd5c7e))
### Bug Fixes
* added an early return on non-existent items ([#2571](https://github.com/filebrowser/filebrowser/issues/2571)) ([2744f7d](https://github.com/filebrowser/filebrowser/commit/2744f7d5b9106c7c2eec69010e550e0939c23d80))
* build on FreeBSD and non-Linux platforms ([#2332](https://github.com/filebrowser/filebrowser/issues/2332)) ([60d1e2d](https://github.com/filebrowser/filebrowser/commit/60d1e2d2913cce591fbee97337bd58310480269f))
* error while using fallback of dir move ([#2349](https://github.com/filebrowser/filebrowser/issues/2349)) ([853ec90](https://github.com/filebrowser/filebrowser/commit/853ec906efbdee9013c5d34ed1d9b8fee88a6b29))
* filter ANSI color for shell ([#2529](https://github.com/filebrowser/filebrowser/issues/2529)) ([9bcfa90](https://github.com/filebrowser/filebrowser/commit/9bcfa900f904fe683c8d9085947f57932bfe22a0))
* goreleaser docker build ([051104b](https://github.com/filebrowser/filebrowser/commit/051104bfa061720d4402c612e61bb0fc80a946bf))
* solve broken Docker build with alpine image ([#2486](https://github.com/filebrowser/filebrowser/issues/2486)) ([b8ee340](https://github.com/filebrowser/filebrowser/commit/b8ee3404ee480ef1fd439543ab6d46f318ff3647))
* video preview click next or prev button subtitles not update ([#2423](https://github.com/filebrowser/filebrowser/issues/2423)) ([6744cd4](https://github.com/filebrowser/filebrowser/commit/6744cd47cef87e3a76a2190bdf123b6c2197fe6f))
* xss vulnerability in /api/raw ([#2570](https://github.com/filebrowser/filebrowser/issues/2570)) ([#2572](https://github.com/filebrowser/filebrowser/issues/2572)) ([b508ac3](https://github.com/filebrowser/filebrowser/commit/b508ac3d4f7f0f75d6b49c99bdc661a6d2173f30))
### Refactorings
* replace username old focus logic with the autofocus attribute ([#2223](https://github.com/filebrowser/filebrowser/issues/2223)) ([2b2c108](https://github.com/filebrowser/filebrowser/commit/2b2c1085fb50ad68612ad438e527fd316d8aafee))
### Build
* **backend:** bump go version to 1.20.1 ([fa95299](https://github.com/filebrowser/filebrowser/commit/fa95299df4aa7e4c54d872e786a91ded5bdb01c1))
* **backend:** bump go version to 1.20.6 ([9bf6b85](https://github.com/filebrowser/filebrowser/commit/9bf6b856e5411e635ba9102ff53dfe927183848e))
* **deps-dev:** bump word-wrap from 1.2.3 to 1.2.4 in /frontend ([#2556](https://github.com/filebrowser/filebrowser/issues/2556)) ([bb34862](https://github.com/filebrowser/filebrowser/commit/bb3486286c0da112ad97456ad258ddcdfe17c154))
* **deps:** bump minimatch from 3.0.4 to 3.1.2 in /tools ([#2561](https://github.com/filebrowser/filebrowser/issues/2561)) ([a664ba1](https://github.com/filebrowser/filebrowser/commit/a664ba1f9df45c7f6d03492c85466c5aa07c740e))
* **deps:** bump semver from 5.7.1 to 5.7.2 in /tools ([#2546](https://github.com/filebrowser/filebrowser/issues/2546)) ([c2f1423](https://github.com/filebrowser/filebrowser/commit/c2f1423c02e4736f4c243c3164dc671879e065f3))
* remove armv6-s6 docker target ([66dfbb3](https://github.com/filebrowser/filebrowser/commit/66dfbb303cf792b7b01650d0125d948ab8d81ddd))
* remove armv7-s6 docker target ([4d77ce0](https://github.com/filebrowser/filebrowser/commit/4d77ce0955644551f891af3e4098c37e9cc37e40))
## [2.23.0](https://github.com/filebrowser/filebrowser/compare/v2.22.4...v2.23.0) (2022-11-05)
### Features
* add rtl support ([#2178](https://github.com/filebrowser/filebrowser/issues/2178)) ([2c14146](https://github.com/filebrowser/filebrowser/commit/2c14146a314bb271be66a36c63b64852a2848e26))
* hebrew translation ([#2168](https://github.com/filebrowser/filebrowser/issues/2168)) ([a49105d](https://github.com/filebrowser/filebrowser/commit/a49105db1d5f0d8f3d6641940ea86da959ffe006))
* hook authentication method ([dda9a38](https://github.com/filebrowser/filebrowser/commit/dda9a389f387e94643a9a2ae56027260b210152a))
* update Polish translation ([#2089](https://github.com/filebrowser/filebrowser/issues/2089)) ([57c99e0](https://github.com/filebrowser/filebrowser/commit/57c99e0e261b4ed4c2cf468ce3ab09f1a440b359))
### Bug Fixes
* missing video controls on mobile ([#2180](https://github.com/filebrowser/filebrowser/issues/2180)) ([a5757b9](https://github.com/filebrowser/filebrowser/commit/a5757b94e8ed492d454b9e427b7f45824cc56c5c))
* modify the delete confirmation interface logic. ([#2138](https://github.com/filebrowser/filebrowser/issues/2138)) ([0401adf](https://github.com/filebrowser/filebrowser/commit/0401adf7f4dd76760fe26b5baee02ebc726b51a9))
### Build
* **deps:** bump ansi-html and webpack-dev-server in /frontend ([#2184](https://github.com/filebrowser/filebrowser/issues/2184)) ([3a0dace](https://github.com/filebrowser/filebrowser/commit/3a0dace9a93f9d57855801de548891010cf0830e))
* **deps:** bump terser from 4.8.0 to 4.8.1 in /frontend ([#2054](https://github.com/filebrowser/filebrowser/issues/2054)) ([aaed985](https://github.com/filebrowser/filebrowser/commit/aaed985699b3c63092ecb02c8bc07634123360ab))
### [2.22.4](https://github.com/filebrowser/filebrowser/compare/v2.22.3...v2.22.4) (2022-07-18)
### Bug Fixes
* disable cookie auth for non GET requests ([80030de](https://github.com/filebrowser/filebrowser/commit/80030dee32d161043766d57ba4e0ad0b0d99290b))
### Build
* **deps:** bump moment from 2.29.2 to 2.29.4 in /frontend ([#2036](https://github.com/filebrowser/filebrowser/issues/2036)) ([cb43770](https://github.com/filebrowser/filebrowser/commit/cb437700255e41ff559b9f5a99ab4290b2f8df87))
* **deps:** bump shell-quote from 1.7.2 to 1.7.3 in /frontend ([#2025](https://github.com/filebrowser/filebrowser/issues/2025)) ([eaba7e5](https://github.com/filebrowser/filebrowser/commit/eaba7e5255f960141e0fc1557f87073df9f6d66a))
### [2.22.3](https://github.com/filebrowser/filebrowser/compare/v2.22.2...v2.22.3) (2022-07-05)
### Bug Fixes
* use correct field name in user put api ([#2026](https://github.com/filebrowser/filebrowser/issues/2026)) ([d94acdd](https://github.com/filebrowser/filebrowser/commit/d94acdd89a0069fe87107024fd332a0d59a112fc))
### [2.22.2](https://github.com/filebrowser/filebrowser/compare/v2.22.1...v2.22.2) (2022-07-01)
### Bug Fixes
* display disk capacity in a correct format ([#2013](https://github.com/filebrowser/filebrowser/issues/2013)) ([dec3d62](https://github.com/filebrowser/filebrowser/commit/dec3d629d42de567aa708154ebc4e03b5223608c))
* don't calculate usage for files ([#1973](https://github.com/filebrowser/filebrowser/issues/1973)) ([577c0ef](https://github.com/filebrowser/filebrowser/commit/577c0efa9cff13628d5e3bac710ef568a00949e0)), closes [#1972](https://github.com/filebrowser/filebrowser/issues/1972) [#1967](https://github.com/filebrowser/filebrowser/issues/1967)
* preview url building fix ([#1976](https://github.com/filebrowser/filebrowser/issues/1976)) ([dcf0bc6](https://github.com/filebrowser/filebrowser/commit/dcf0bc65bfcfc7df3804d7392598a92019468cf7))
### Build
* **backend:** upgrade golangci-lint to 1.46.2 ([#1991](https://github.com/filebrowser/filebrowser/issues/1991)) ([8118afd](https://github.com/filebrowser/filebrowser/commit/8118afd0ac0d25f4503c98879369764c35e7408e))
### [2.22.1](https://github.com/filebrowser/filebrowser/compare/v2.22.0...v2.22.1) (2022-06-06)
### Bug Fixes
* use correct basepath prefix for preview urls ([#1971](https://github.com/filebrowser/filebrowser/issues/1971)) ([1e7d3b2](https://github.com/filebrowser/filebrowser/commit/1e7d3b25c283c556d98c65f1c2f46db4e4178995))
### Build
* **backend:** bump go version to 1.8.3 ([b16982d](https://github.com/filebrowser/filebrowser/commit/b16982df0f7da9eedb678455298b42ac55c86666))
## [2.22.0](https://github.com/filebrowser/filebrowser/compare/v2.21.1...v2.22.0) (2022-06-03)
### Features
* add branding to the window title ([#1850](https://github.com/filebrowser/filebrowser/issues/1850)) ([f8dfbf7](https://github.com/filebrowser/filebrowser/commit/f8dfbf7eeecf3ee99ce906276777676f44e81e34))
* add disk usage information to the sidebar ([d1d8e3e](https://github.com/filebrowser/filebrowser/commit/d1d8e3e3405381b01317fe07ae729d70219415a7))
* automatically focus username field on login page ([596c732](https://github.com/filebrowser/filebrowser/commit/596c73288f5b53bd7e79ab8046136dc75ff078b9))
* invalid symlink icon ([b14b911](https://github.com/filebrowser/filebrowser/commit/b14b9114f837cacf9f7788e88c503142a81585be))
* page title localization ([8a43413](https://github.com/filebrowser/filebrowser/commit/8a43413f888440dc11b11c509abff45f706033d8))
### Bug Fixes
* allow CSP inline styling ([5da9d74](https://github.com/filebrowser/filebrowser/commit/5da9d74da62c69c431361bcaf0c07dc1da237ea8))
* disable autocapitalize of login input (closes [#1910](https://github.com/filebrowser/filebrowser/issues/1910)) ([aed3af5](https://github.com/filebrowser/filebrowser/commit/aed3af58384697dc3de30f1450b837b0b74e4fa6))
* drag-and-drop folder upload ([e677c78](https://github.com/filebrowser/filebrowser/commit/e677c78471f09f8d2c21d63d7388e908924aa6d9))
* expired token error ([c3bd118](https://github.com/filebrowser/filebrowser/commit/c3bd1188aa396cbf00c593d259a9da0eddeeea3b))
* folder info on upload list ([d1d7b23](https://github.com/filebrowser/filebrowser/commit/d1d7b23da6cc0c9a2f2f3e17021ec4f13ea557dd))
* network error object message ([fc209f6](https://github.com/filebrowser/filebrowser/commit/fc209f64deff7a2793980d11ee738f7140c444cf))
* set correct scope when user home creation is enabled ([02730bb](https://github.com/filebrowser/filebrowser/commit/02730bb9bfa3bfbfa251bb4736fc4c08d33609ab))
### Build
* **backend:** bump dependency versions ([7c9a75e](https://github.com/filebrowser/filebrowser/commit/7c9a75e72588f92d58fb58d32cdac352bce73b20))
* **deps:** bump async from 2.6.3 to 2.6.4 in /frontend ([#1933](https://github.com/filebrowser/filebrowser/issues/1933)) ([e5fa96b](https://github.com/filebrowser/filebrowser/commit/e5fa96b666eac2e46a02bde832488baca5f2cd6d))
* **deps:** bump eventsource from 1.1.0 to 1.1.1 in /frontend ([dd50369](https://github.com/filebrowser/filebrowser/commit/dd503695a1a8119a631643414d3a9070890f3f3c))
* **deps:** bump minimist from 1.2.5 to 1.2.6 in /frontend ([#1889](https://github.com/filebrowser/filebrowser/issues/1889)) ([a74c72d](https://github.com/filebrowser/filebrowser/commit/a74c72db451207e1275988f3d208fa6d6f0468a9))
* **deps:** bump minimist from 1.2.5 to 1.2.6 in /tools ([#1891](https://github.com/filebrowser/filebrowser/issues/1891)) ([f5b1e10](https://github.com/filebrowser/filebrowser/commit/f5b1e106183fb2192063a72fd195fc8c181ba8f9))
* **deps:** bump moment from 2.29.1 to 2.29.2 in /frontend ([#1900](https://github.com/filebrowser/filebrowser/issues/1900)) ([040584c](https://github.com/filebrowser/filebrowser/commit/040584c86563d869c7a05887ef1f781bce653033))
* **deps:** bump url-parse from 1.5.7 to 1.5.10 in /frontend ([#1841](https://github.com/filebrowser/filebrowser/issues/1841)) ([b2ad3f7](https://github.com/filebrowser/filebrowser/commit/b2ad3f73686a2abaa4fc62963fba6f83c9da9b5e))
* **frontend:** bump node version from 14 to 16 ([ac3ead8](https://github.com/filebrowser/filebrowser/commit/ac3ead8dcef9c64c6be8b5cbbceee143b2cc77a8))
* upgrade go version to 1.18.1 ([6bd34c7](https://github.com/filebrowser/filebrowser/commit/6bd34c76324780c1edd8625d5b22f5a84990852b))
### [2.21.1](https://github.com/filebrowser/filebrowser/compare/v2.21.0...v2.21.1) (2022-02-22)
### Bug Fixes
* display user scope for admin users ([#1834](https://github.com/filebrowser/filebrowser/issues/1834)) ([6366cf0](https://github.com/filebrowser/filebrowser/commit/6366cf0b181f13eac38f69f1760d6f6f0586a5d1))
## [2.21.0](https://github.com/filebrowser/filebrowser/compare/v2.20.1...v2.21.0) (2022-02-21)
### Features
* add colorized file type icons ([2948589](https://github.com/filebrowser/filebrowser/commit/2948589fcde6d1dca7f3ea52a621d8213fa3300c))
* add gallery view mode ([8888b9f](https://github.com/filebrowser/filebrowser/commit/8888b9f44640394df9e3583db4392472d7027a4b))
* add Ukrainian translation / update Russian translation ([#1753](https://github.com/filebrowser/filebrowser/issues/1753)) ([665e458](https://github.com/filebrowser/filebrowser/commit/665e45889cd333f1e3500e4bf38d15d229c9fe2a))
* add upload file list with progress ([#1825](https://github.com/filebrowser/filebrowser/issues/1825)) ([cf85404](https://github.com/filebrowser/filebrowser/commit/cf85404dd25cd7fdd73aa32878b4dc5f85ee3e96))
* smaller column width to fit 2 columns in landscape mobiles ([7870e89](https://github.com/filebrowser/filebrowser/commit/7870e89bc04f1494f2705795476b5f1c9d621e38))
* use real image path to calculate cache key ([c198723](https://github.com/filebrowser/filebrowser/commit/c1987237d05adcce77c614e5247a181ae5cdfacd))
### Bug Fixes
* correctly handle non-ascii passwords for shared resources ([c782f21](https://github.com/filebrowser/filebrowser/commit/c782f21b0fa4511a15e7015117d075eaf5ea332c))
* don't expose scope for non-admin users ([0942fc7](https://github.com/filebrowser/filebrowser/commit/0942fc7042fd949cce91855169d0bcf16eb75771))
* open all the pdf files correctly ([#1742](https://github.com/filebrowser/filebrowser/issues/1742)) ([949f0f2](https://github.com/filebrowser/filebrowser/commit/949f0f277f6004904b3edfa716a8365ec93fa0fa))
### Build
* **deps:** bump browserslist from 4.16.3 to 4.19.1 in /frontend ([8089007](https://github.com/filebrowser/filebrowser/commit/80890075e802e2a4217edbb01d6417122d702f5e))
* **deps:** bump dns-packet from 1.3.1 to 1.3.4 in /frontend ([a73d7f1](https://github.com/filebrowser/filebrowser/commit/a73d7f14b787935c6ebe525dba64b65f8ed733e2))
* **deps:** bump follow-redirects from 1.13.3 to 1.14.8 in /frontend ([f1f7f17](https://github.com/filebrowser/filebrowser/commit/f1f7f17ade8d40fc6cfb22c79960bce299876b56))
* **deps:** bump hosted-git-info from 2.8.8 to 2.8.9 in /frontend ([e7659ea](https://github.com/filebrowser/filebrowser/commit/e7659ea36bdf780ce17005f7170a2fef02a2d5e5))
* **deps:** bump path-parse from 1.0.6 to 1.0.7 in /frontend ([c014966](https://github.com/filebrowser/filebrowser/commit/c01496624a7ebfc8a7c256bd919a400367281cbb))
* **deps:** bump postcss from 7.0.35 to 7.0.39 in /frontend ([9182d33](https://github.com/filebrowser/filebrowser/commit/9182d33e1cc375473fb18989a92d20252884f096))
* **deps:** bump ssri from 6.0.1 to 6.0.2 in /frontend ([3717186](https://github.com/filebrowser/filebrowser/commit/371718634b11f32e68165f31c51b6b1139c829ec))
* **deps:** bump tar from 6.1.0 to 6.1.11 in /frontend ([010d16f](https://github.com/filebrowser/filebrowser/commit/010d16fc1d8f0200e5662943aef17ee89c5877b7))
* **deps:** bump url-parse from 1.5.1 to 1.5.4 in /frontend ([8906408](https://github.com/filebrowser/filebrowser/commit/8906408a8f0ed86d1e11ea90fc573b36815c9c0d))
* **deps:** bump url-parse from 1.5.4 to 1.5.7 in /frontend ([228ebea](https://github.com/filebrowser/filebrowser/commit/228ebea66cc871b33459406590a80ef906298e7d))
* **deps:** bump ws from 6.2.1 to 6.2.2 in /frontend ([73c8073](https://github.com/filebrowser/filebrowser/commit/73c80732d934bc8802a6d7c7a559cad37df405f0))
### [2.20.1](https://github.com/filebrowser/filebrowser/compare/v2.20.0...v2.20.1) (2021-12-21)
### Build
* revert to using the default alpine based docker image ([46d8046](https://github.com/filebrowser/filebrowser/commit/46d80464d2a67927b06a11b83fb137ad364a90ed))
## [2.20.0](https://github.com/filebrowser/filebrowser/compare/v2.19.0...v2.20.0) (2021-12-20)
### Features
* detect multiple subtitle languages ([#1723](https://github.com/filebrowser/filebrowser/issues/1723)) ([c2e03bb](https://github.com/filebrowser/filebrowser/commit/c2e03bbfab97fc6716bcdd59158e9d5129bf0ea7))
* use linuxserver based docker image ([b8f35ce](https://github.com/filebrowser/filebrowser/commit/b8f35ce9322c2b0dbf954cfd3ff584bc9f742fdd))
### Bug Fixes
* set correct default database path in the config ([988d3e5](https://github.com/filebrowser/filebrowser/commit/988d3e5bdd224509ddc2f08444560e3087e9c67d))
* upgrade vulnerable versions of the library ([6eb3ab0](https://github.com/filebrowser/filebrowser/commit/6eb3ab063509a015ad630ab704ae3791461d0982))
### Build
* refactor makefile ([f81857a](https://github.com/filebrowser/filebrowser/commit/f81857acce25936a700945db5ef4af545eaeb1cf))
* remove deprecated goreleaser use_buildx param ([4d1b9dd](https://github.com/filebrowser/filebrowser/commit/4d1b9dd2112002a93bb26cece07dcfd81c31dc2c))
## [2.19.0](https://github.com/filebrowser/filebrowser/compare/v2.18.0...v2.19.0) (2021-11-24)
### Features
* prefetch previous and next images in preview. ([#1627](https://github.com/filebrowser/filebrowser/issues/1627)) ([7401d16](https://github.com/filebrowser/filebrowser/commit/7401d16e457bb232fd7dd7ef427e8960d465705c))
### Bug Fixes
* empty file listing on share ([e082397](https://github.com/filebrowser/filebrowser/commit/e08239781f61e7bb25d9b8c5c6cce90f34621a76))
* relative font sizes ([c29698d](https://github.com/filebrowser/filebrowser/commit/c29698dffac769077ab7c7869569a902979ee3d7))
## [2.18.0](https://github.com/filebrowser/filebrowser/compare/v2.17.2...v2.18.0) (2021-10-31)
### Features
* add ability to select file modified time format ([#1536](https://github.com/filebrowser/filebrowser/issues/1536)) ([0426629](https://github.com/filebrowser/filebrowser/commit/0426629a59c712849570d3e29956948ae7725a4a))
* add manifest theme color param ([#1542](https://github.com/filebrowser/filebrowser/issues/1542)) ([0358e42](https://github.com/filebrowser/filebrowser/commit/0358e42d2c206732fffa77714f5a66f4fe50a69d))
### Bug Fixes
* back button behaviour in preview ([#1573](https://github.com/filebrowser/filebrowser/issues/1573)) ([deabc80](https://github.com/filebrowser/filebrowser/commit/deabc80fd7670983039dfcd29531b45002ca5d9e))
* fix sidebar navigation on mobile devices ([#1618](https://github.com/filebrowser/filebrowser/issues/1618)) ([f09bf3e](https://github.com/filebrowser/filebrowser/commit/f09bf3e1d076b27d29ba8a91cf448a99993bc444))
* search box is misaligned when the browser preferred font size is other than 16px ([#1613](https://github.com/filebrowser/filebrowser/issues/1613)) ([6f345be](https://github.com/filebrowser/filebrowser/commit/6f345be3e47ba57ecc1eb9a62587ab949078c125))
* security issue in command runner (closes [#1621](https://github.com/filebrowser/filebrowser/issues/1621)) ([74b7cd8](https://github.com/filebrowser/filebrowser/commit/74b7cd8e81840537a8206317344f118093153e8d))
* set correct editor height regardless of preferred font size ([#1614](https://github.com/filebrowser/filebrowser/issues/1614)) ([ddd4ffa](https://github.com/filebrowser/filebrowser/commit/ddd4ffa4caa6b292a3a644ecd897aba1237c7503))
* zoom pics when dlclick at first time ([#1561](https://github.com/filebrowser/filebrowser/issues/1561)) ([b6a51be](https://github.com/filebrowser/filebrowser/commit/b6a51bed516814944f8aa41440652242d57824c5))
### [2.17.2](https://github.com/filebrowser/filebrowser/compare/v2.17.1...v2.17.2) (2021-08-27)
### Bug Fixes
* bug with inlineLink not creating url properly ([#1515](https://github.com/filebrowser/filebrowser/issues/1515)) ([43a4609](https://github.com/filebrowser/filebrowser/commit/43a460993c3f0d158b876db4b20caa7963e9f361))
### [2.17.1](https://github.com/filebrowser/filebrowser/compare/v2.17.0...v2.17.1) (2021-08-23)
### Bug Fixes
* internal server error if --disable-preview-resize flag is set (closes [#1510](https://github.com/filebrowser/filebrowser/issues/1510)) ([4c3099a](https://github.com/filebrowser/filebrowser/commit/4c3099a086c206dcb3bc70ee8c8da02eee61c30b))
## [2.17.0](https://github.com/filebrowser/filebrowser/compare/v2.16.1...v2.17.0) (2021-08-21)
### Features
* open file option on preview ([76add9e](https://github.com/filebrowser/filebrowser/commit/76add9e5274b0373c6b983e3b20e387a14ea6c9e))
### Bug Fixes
* 401 error in share view open file button ([#1495](https://github.com/filebrowser/filebrowser/issues/1495)) ([25c8788](https://github.com/filebrowser/filebrowser/commit/25c87883908babde073390a2e2320a8e5880a87c))
* escape quote on index template ([23d646c](https://github.com/filebrowser/filebrowser/commit/23d646c456876d06cf48e71c1e57b69de99511f0)), closes [#1501](https://github.com/filebrowser/filebrowser/issues/1501)
* file caching directive ([c63cc5a](https://github.com/filebrowser/filebrowser/commit/c63cc5a2d25909cc4e2f2e7235f276ec66c32bf2))
### [2.16.1](https://github.com/filebrowser/filebrowser/compare/v2.16.0...v2.16.1) (2021-08-04)
### Bug Fixes
* check symlink target type (closes [#1488](https://github.com/filebrowser/filebrowser/issues/1488)) ([76b466f](https://github.com/filebrowser/filebrowser/commit/76b466f6492e74cf13e66a33e7e5f597ac92b240))
## [2.16.0](https://github.com/filebrowser/filebrowser/compare/v2.15.0...v2.16.0) (2021-07-26)

View File

@@ -1,15 +1,19 @@
FROM alpine:latest
RUN apk --update add ca-certificates \
mailcap \
curl
curl \
jq
COPY healthcheck.sh /healthcheck.sh
RUN chmod +x /healthcheck.sh # Make the script executable
HEALTHCHECK --start-period=2s --interval=5s --timeout=3s \
CMD curl -f http://localhost/health || exit 1
CMD /healthcheck.sh || exit 1
VOLUME /srv
EXPOSE 80
COPY .docker.json /.filebrowser.json
COPY docker_config.json /.filebrowser.json
COPY filebrowser /filebrowser
ENTRYPOINT [ "/filebrowser" ]

16
Dockerfile.s6 Normal file
View File

@@ -0,0 +1,16 @@
FROM ghcr.io/linuxserver/baseimage-alpine:3.17
RUN apk --update add ca-certificates \
mailcap \
curl
HEALTHCHECK --start-period=2s --interval=5s --timeout=3s \
CMD curl -f http://localhost/health || exit 1
# copy local files
COPY docker/root/ /
COPY filebrowser /usr/bin/filebrowser
# ports and volumes
VOLUME /srv /config /database
EXPOSE 80

16
Dockerfile.s6.aarch64 Normal file
View File

@@ -0,0 +1,16 @@
FROM ghcr.io/linuxserver/baseimage-alpine:arm64v8-3.17
RUN apk --update add ca-certificates \
mailcap \
curl
HEALTHCHECK --start-period=2s --interval=5s --timeout=3s \
CMD curl -f http://localhost/health || exit 1
# copy local files
COPY docker/root/ /
COPY filebrowser /usr/bin/filebrowser
# ports and volumes
VOLUME /srv /config /database
EXPOSE 80

16
Dockerfile.s6.armhf Normal file
View File

@@ -0,0 +1,16 @@
FROM ghcr.io/linuxserver/baseimage-alpine:arm32v7-3.17
RUN apk --update add ca-certificates \
mailcap \
curl
HEALTHCHECK --start-period=2s --interval=5s --timeout=3s \
CMD curl -f http://localhost/health || exit 1
# copy local files
COPY docker/root/ /
COPY filebrowser /usr/bin/filebrowser
# ports and volumes
VOLUME /srv /config /database
EXPOSE 80

102
Makefile
View File

@@ -1,94 +1,68 @@
SHELL := /bin/bash
BASE_PATH := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
VERSION ?= $(shell git describe --tags --always --match=v* 2> /dev/null || \
cat $(CURDIR)/.version 2> /dev/null || echo v0)
VERSION_HASH = $(shell git rev-parse HEAD)
BIN = $(BASE_PATH)/bin
PATH := $(BIN):$(PATH)
export PATH
# printing
V = 0
Q = $(if $(filter 1,$V),,@)
M = $(shell printf "\033[34;1m▶\033[0m")
GO = GOGC=off go
# go module
MODULE = $(shell env GO111MODULE=on $(GO) list -m)
DATE ?= $(shell date +%FT%T%z)
VERSION ?= $(shell git describe --tags --always --match=v* 2> /dev/null || \
cat $(CURDIR)/.version 2> /dev/null || echo v0)
VERSION_HASH = $(shell git rev-parse --short HEAD)
BRANCH = $(shell git rev-parse --abbrev-ref HEAD)
include common.mk
include tools.mk
LDFLAGS += -X "$(MODULE)/version.Version=$(VERSION)" -X "$(MODULE)/version.CommitSHA=$(VERSION_HASH)"
# tools
$(BIN):
@mkdir -p $@
$(BIN)/%: | $(BIN) ; $(info $(M) installing $(PACKAGE))
$Q env GOBIN=$(BIN) $(GO) install $(PACKAGE)
## Build:
GOLANGCI_LINT = $(BIN)/golangci-lint
$(BIN)/golangci-lint: PACKAGE=github.com/golangci/golangci-lint/cmd/golangci-lint@v1.41.1
GOIMPORTS = $(BIN)/goimports
$(BIN)/goimports: PACKAGE=golang.org/x/tools/cmd/goimports@v0.1.5
## build: Build
.PHONY: build
build: | build-frontend build-backend ; $(info $(M) building)
build: | build-frontend build-backend ## Build binary
## build-frontend: Build frontend
.PHONY: build-frontend
build-frontend: | ; $(info $(M) building frontend)
build-frontend: ## Build frontend
$Q cd frontend && npm ci && npm run build
## build-backend: Build backend
.PHONY: build-backend
build-backend: | ; $(info $(M) building backend)
$Q $(GO) build -ldflags '$(LDFLAGS)' -o .
build-backend: ## Build backend
$Q $(go) build -ldflags '$(LDFLAGS)' -o .
## test: Run all tests
.PHONY: test
test: | test-frontend test-backend ; $(info $(M) running tests)
test: | test-frontend test-backend ## Run all tests
## test-frontend: Run frontend tests
.PHONY: test-frontend
test-frontend: | ; $(info $(M) running frontend tests)
test-frontend: ## Run frontend tests
## test-backend: Run backend tests
.PHONY: test-backend
test-backend: | ; $(info $(M) running backend tests)
$Q $(GO) test -v ./...
test-backend: ## Run backend tests
$Q $(go) test -v ./...
## lint: Lint
.PHONY: lint
lint: lint-frontend lint-backend lint-commits | ; $(info $(M) running all linters)
lint: lint-frontend lint-backend lint-commits ## Run all linters
## lint-frontend: Lint frontend
.PHONY: lint-frontend
lint-frontend: | ; $(info $(M) running frontend linters)
lint-frontend: ## Run frontend linters
$Q cd frontend && npm ci && npm run lint
## lint-backend: Lint backend
.PHONY: lint-backend
lint-backend: | $(GOLANGCI_LINT) ; $(info $(M) running backend linters)
$Q $(GOLANGCI_LINT) run
lint-backend: | $(golangci-lint) ## Run backend linters
$Q $(golangci-lint) run -v
## lint-commits: Lint commits
.PHONY: lint-commits
lint-commits: | ; $(info $(M) running commitlint)
lint-commits: $(commitlint) ## Run commit linters
$Q ./scripts/commitlint.sh
## bump-version: Bump app version
fmt: $(goimports) ## Format source files
$Q $(goimports) -local $(MODULE) -w $$(find . -type f -name '*.go' -not -path "./vendor/*")
clean: clean-tools ## Clean
## Release:
.PHONY: bump-version
bump-version: | ; $(info $(M) creating a new release)
bump-version: $(standard-version) ## Bump app version
$Q ./scripts/bump_version.sh
## help: Show this help
.PHONY: help
help:
@sed -n 's/^## //p' $(MAKEFILE_LIST) | column -t -s ':' | sed -e 's/^/ /' | sort
## Help:
help: ## Show this help
@echo ''
@echo 'Usage:'
@echo ' ${YELLOW}make${RESET} ${GREEN}<target> [options]${RESET}'
@echo ''
@echo 'Options:'
@$(call global_option, "V [0|1]", "enable verbose mode (default:0)")
@echo ''
@echo 'Targets:'
@awk 'BEGIN {FS = ":.*?## "} { \
if (/^[a-zA-Z_-]+:.*?##.*$$/) {printf " ${YELLOW}%-20s${GREEN}%s${RESET}\n", $$1, $$2} \
else if (/^## .*$$/) {printf " ${CYAN}%s${RESET}\n", substr($$1,4)} \
}' $(MAKEFILE_LIST)

View File

@@ -10,7 +10,13 @@
[![Version](https://img.shields.io/github/release/filebrowser/filebrowser.svg?style=flat-square)](https://github.com/filebrowser/filebrowser/releases/latest)
[![Chat IRC](https://img.shields.io/badge/freenode-%23filebrowser-blue.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23filebrowser)
filebrowser provides a file managing interface within a specified directory and it can be used to upload, delete, preview, rename and edit your files. It allows the creation of multiple users and each user can have its own directory. It can be used as a standalone app or as a middleware.
filebrowser provides a file managing interface within a specified directory and it can be used to upload, delete, preview, rename and edit your files. It allows the creation of multiple users and each user can have its own directory. It can be used as a standalone app.
## Demo
url: https://demo.filebrowser.org/
credentials: `demo`/`demo`
## Features

View File

@@ -3,13 +3,14 @@ package auth
import (
"net/http"
"github.com/filebrowser/filebrowser/v2/settings"
"github.com/filebrowser/filebrowser/v2/users"
)
// Auther is the authentication interface.
type Auther interface {
// Auth is called to authenticate a request.
Auth(r *http.Request, s users.Store, root string) (*users.User, error)
Auth(r *http.Request, usr users.Store, stg *settings.Settings, srv *settings.Server) (*users.User, error)
// LoginPage indicates if this auther needs a login page.
LoginPage() bool
}

302
auth/hook.go Normal file
View File

@@ -0,0 +1,302 @@
package auth
import (
"encoding/json"
"fmt"
"log"
"net/http"
"os"
"os/exec"
"strings"
"github.com/filebrowser/filebrowser/v2/errors"
"github.com/filebrowser/filebrowser/v2/files"
"github.com/filebrowser/filebrowser/v2/settings"
"github.com/filebrowser/filebrowser/v2/users"
)
// MethodHookAuth is used to identify hook auth.
const MethodHookAuth settings.AuthMethod = "hook"
type hookCred struct {
Password string `json:"password"`
Username string `json:"username"`
}
// HookAuth is a hook implementation of an Auther.
type HookAuth struct {
Users users.Store `json:"-"`
Settings *settings.Settings `json:"-"`
Server *settings.Server `json:"-"`
Cred hookCred `json:"-"`
Fields hookFields `json:"-"`
Command string `json:"command"`
}
// Auth authenticates the user via a json in content body.
func (a *HookAuth) Auth(r *http.Request, usr users.Store, stg *settings.Settings, srv *settings.Server) (*users.User, error) {
var cred hookCred
if r.Body == nil {
return nil, os.ErrPermission
}
err := json.NewDecoder(r.Body).Decode(&cred)
if err != nil {
return nil, os.ErrPermission
}
a.Users = usr
a.Settings = stg
a.Server = srv
a.Cred = cred
action, err := a.RunCommand()
if err != nil {
return nil, err
}
switch action {
case "auth":
u, err := a.SaveUser()
if err != nil {
return nil, err
}
return u, nil
case "block":
return nil, os.ErrPermission
case "pass":
u, err := a.Users.Get(a.Server.Root, a.Cred.Username)
if err != nil || !users.CheckPwd(a.Cred.Password, u.Password) {
return nil, os.ErrPermission
}
return u, nil
default:
return nil, fmt.Errorf("invalid hook action: %s", action)
}
}
// LoginPage tells that hook auth requires a login page.
func (a *HookAuth) LoginPage() bool {
return true
}
// RunCommand starts the hook command and returns the action
func (a *HookAuth) RunCommand() (string, error) {
command := strings.Split(a.Command, " ")
envMapping := func(key string) string {
switch key {
case "USERNAME":
return a.Cred.Username
case "PASSWORD":
return a.Cred.Password
default:
return os.Getenv(key)
}
}
for i, arg := range command {
if i == 0 {
continue
}
command[i] = os.Expand(arg, envMapping)
}
cmd := exec.Command(command[0], command[1:]...) //nolint:gosec
cmd.Env = append(os.Environ(), fmt.Sprintf("USERNAME=%s", a.Cred.Username))
cmd.Env = append(cmd.Env, fmt.Sprintf("PASSWORD=%s", a.Cred.Password))
out, err := cmd.Output()
if err != nil {
return "", err
}
a.GetValues(string(out))
return a.Fields.Values["hook.action"], nil
}
// GetValues creates a map with values from the key-value format string
func (a *HookAuth) GetValues(s string) {
m := map[string]string{}
// make line breaks consistent on Windows platform
s = strings.ReplaceAll(s, "\r\n", "\n")
// iterate input lines
for _, val := range strings.Split(s, "\n") {
v := strings.SplitN(val, "=", 2) //nolint: gomnd
// skips non key and value format
if len(v) != 2 { //nolint: gomnd
continue
}
fieldKey := strings.TrimSpace(v[0])
fieldValue := strings.TrimSpace(v[1])
if a.Fields.IsValid(fieldKey) {
m[fieldKey] = fieldValue
}
}
a.Fields.Values = m
}
// SaveUser updates the existing user or creates a new one when not found
func (a *HookAuth) SaveUser() (*users.User, error) {
u, err := a.Users.Get(a.Server.Root, a.Cred.Username)
if err != nil && err != errors.ErrNotExist {
return nil, err
}
if u == nil {
pass, err := users.HashPwd(a.Cred.Password)
if err != nil {
return nil, err
}
// create user with the provided credentials
d := &users.User{
Username: a.Cred.Username,
Password: pass,
Scope: a.Settings.Defaults.Scope,
Locale: a.Settings.Defaults.Locale,
ViewMode: a.Settings.Defaults.ViewMode,
SingleClick: a.Settings.Defaults.SingleClick,
Sorting: a.Settings.Defaults.Sorting,
Perm: a.Settings.Defaults.Perm,
Commands: a.Settings.Defaults.Commands,
HideDotfiles: a.Settings.Defaults.HideDotfiles,
}
u = a.GetUser(d)
userHome, err := a.Settings.MakeUserDir(u.Username, u.Scope, a.Server.Root)
if err != nil {
return nil, fmt.Errorf("user: failed to mkdir user home dir: [%s]", userHome)
}
u.Scope = userHome
log.Printf("user: %s, home dir: [%s].", u.Username, userHome)
err = a.Users.Save(u)
if err != nil {
return nil, err
}
} else if p := !users.CheckPwd(a.Cred.Password, u.Password); len(a.Fields.Values) > 1 || p {
u = a.GetUser(u)
// update the password when it doesn't match the current
if p {
pass, err := users.HashPwd(a.Cred.Password)
if err != nil {
return nil, err
}
u.Password = pass
}
// update user with provided fields
err := a.Users.Update(u)
if err != nil {
return nil, err
}
}
return u, nil
}
// GetUser returns a User filled with hook values or provided defaults
func (a *HookAuth) GetUser(d *users.User) *users.User {
// adds all permissions when user is admin
isAdmin := a.Fields.GetBoolean("user.perm.admin", d.Perm.Admin)
perms := users.Permissions{
Admin: isAdmin,
Execute: isAdmin || a.Fields.GetBoolean("user.perm.execute", d.Perm.Execute),
Create: isAdmin || a.Fields.GetBoolean("user.perm.create", d.Perm.Create),
Rename: isAdmin || a.Fields.GetBoolean("user.perm.rename", d.Perm.Rename),
Modify: isAdmin || a.Fields.GetBoolean("user.perm.modify", d.Perm.Modify),
Delete: isAdmin || a.Fields.GetBoolean("user.perm.delete", d.Perm.Delete),
Share: isAdmin || a.Fields.GetBoolean("user.perm.share", d.Perm.Share),
Download: isAdmin || a.Fields.GetBoolean("user.perm.download", d.Perm.Download),
}
user := users.User{
ID: d.ID,
Username: d.Username,
Password: d.Password,
Scope: a.Fields.GetString("user.scope", d.Scope),
Locale: a.Fields.GetString("user.locale", d.Locale),
ViewMode: users.ViewMode(a.Fields.GetString("user.viewMode", string(d.ViewMode))),
SingleClick: a.Fields.GetBoolean("user.singleClick", d.SingleClick),
Sorting: files.Sorting{
Asc: a.Fields.GetBoolean("user.sorting.asc", d.Sorting.Asc),
By: a.Fields.GetString("user.sorting.by", d.Sorting.By),
},
Commands: a.Fields.GetArray("user.commands", d.Commands),
HideDotfiles: a.Fields.GetBoolean("user.hideDotfiles", d.HideDotfiles),
Perm: perms,
LockPassword: true,
}
return &user
}
// hookFields is used to access fields from the hook
type hookFields struct {
Values map[string]string
}
// validHookFields contains names of the fields that can be used
var validHookFields = []string{
"hook.action",
"user.scope",
"user.locale",
"user.viewMode",
"user.singleClick",
"user.sorting.by",
"user.sorting.asc",
"user.commands",
"user.hideDotfiles",
"user.perm.admin",
"user.perm.execute",
"user.perm.create",
"user.perm.rename",
"user.perm.modify",
"user.perm.delete",
"user.perm.share",
"user.perm.download",
}
// IsValid checks if the provided field is on the valid fields list
func (hf *hookFields) IsValid(field string) bool {
for _, val := range validHookFields {
if field == val {
return true
}
}
return false
}
// GetString returns the string value or provided default
func (hf *hookFields) GetString(k, dv string) string {
val, ok := hf.Values[k]
if ok {
return val
}
return dv
}
// GetBoolean returns the bool value or provided default
func (hf *hookFields) GetBoolean(k string, dv bool) bool {
val, ok := hf.Values[k]
if ok {
return val == "true"
}
return dv
}
// GetArray returns the array value or provided default
func (hf *hookFields) GetArray(k string, dv []string) []string {
val, ok := hf.Values[k]
if ok && strings.TrimSpace(val) != "" {
return strings.Split(val, " ")
}
return dv
}

View File

@@ -26,7 +26,7 @@ type JSONAuth struct {
}
// Auth authenticates the user via a json in content body.
func (a JSONAuth) Auth(r *http.Request, sto users.Store, root string) (*users.User, error) {
func (a JSONAuth) Auth(r *http.Request, usr users.Store, stg *settings.Settings, srv *settings.Server) (*users.User, error) {
var cred jsonCred
if r.Body == nil {
@@ -51,7 +51,7 @@ func (a JSONAuth) Auth(r *http.Request, sto users.Store, root string) (*users.Us
}
}
u, err := sto.Get(root, cred.Username)
u, err := usr.Get(srv.Root, cred.Username)
if err != nil || !users.CheckPwd(cred.Password, u.Password) {
return nil, os.ErrPermission
}

View File

@@ -14,8 +14,8 @@ const MethodNoAuth settings.AuthMethod = "noauth"
type NoAuth struct{}
// Auth uses authenticates user 1.
func (a NoAuth) Auth(r *http.Request, sto users.Store, root string) (*users.User, error) {
return sto.Get(root, uint(1))
func (a NoAuth) Auth(r *http.Request, usr users.Store, stg *settings.Settings, srv *settings.Server) (*users.User, error) {
return usr.Get(srv.Root, uint(1))
}
// LoginPage tells that no auth doesn't require a login page.

View File

@@ -18,9 +18,9 @@ type ProxyAuth struct {
}
// Auth authenticates the user via an HTTP header.
func (a ProxyAuth) Auth(r *http.Request, sto users.Store, root string) (*users.User, error) {
func (a ProxyAuth) Auth(r *http.Request, usr users.Store, stg *settings.Settings, srv *settings.Server) (*users.User, error) {
username := r.Header.Get(a.Header)
user, err := sto.Get(root, username)
user, err := usr.Get(srv.Root, username)
if err == errors.ErrNotExist {
return nil, os.ErrPermission
}

View File

@@ -31,18 +31,23 @@ func addConfigFlags(flags *pflag.FlagSet) {
addServerFlags(flags)
addUserFlags(flags)
flags.BoolP("signup", "s", false, "allow users to signup")
flags.Bool("create-user-dir", false, "generate user's home directory automatically")
flags.String("shell", "", "shell command to which other commands should be appended")
flags.String("auth.method", string(auth.MethodJSONAuth), "authentication type")
flags.String("auth.header", "", "HTTP header for auth.method=proxy")
flags.String("auth.command", "", "command for auth.method=hook")
flags.String("recaptcha.host", "https://www.google.com", "use another host for ReCAPTCHA. recaptcha.net might be useful in China")
flags.String("recaptcha.key", "", "ReCaptcha site key")
flags.String("recaptcha.secret", "", "ReCaptcha secret")
flags.String("branding.name", "", "replace 'File Browser' by this name")
flags.String("branding.theme", "", "set the theme")
flags.String("branding.color", "", "set the theme color")
flags.String("branding.files", "", "path to directory with images and custom styles")
flags.Bool("branding.disableExternal", false, "disable external links such as GitHub links")
flags.Bool("branding.disableUsedPercentage", false, "disable used disk percentage graph")
}
//nolint:gocyclo
@@ -113,6 +118,20 @@ func getAuthentication(flags *pflag.FlagSet, defaults ...interface{}) (settings.
auther = jsonAuth
}
if method == auth.MethodHookAuth {
command := mustGetString(flags, "auth.command")
if command == "" {
command = defaultAuther["command"].(string)
}
if command == "" {
checkErr(nerrors.New("you must set the flag 'auth.command' for method 'hook'"))
}
auther = &auth.HookAuth{Command: command}
}
if auther == nil {
panic(errors.ErrInvalidAuthMethod)
}
@@ -131,6 +150,9 @@ func printSettings(ser *settings.Server, set *settings.Settings, auther auth.Aut
fmt.Fprintf(w, "\tName:\t%s\n", set.Branding.Name)
fmt.Fprintf(w, "\tFiles override:\t%s\n", set.Branding.Files)
fmt.Fprintf(w, "\tDisable external links:\t%t\n", set.Branding.DisableExternal)
fmt.Fprintf(w, "\tDisable used disk percentage graph:\t%t\n", set.Branding.DisableUsedPercentage)
fmt.Fprintf(w, "\tColor:\t%s\n", set.Branding.Color)
fmt.Fprintf(w, "\tTheme:\t%s\n", set.Branding.Theme)
fmt.Fprintln(w, "\nServer:")
fmt.Fprintf(w, "\tLog:\t%s\n", ser.Log)
fmt.Fprintf(w, "\tPort:\t%s\n", ser.Port)

View File

@@ -70,6 +70,8 @@ The path must be for a json or yaml file.`,
auther = getAuther(auth.NoAuth{}, rawAuther).(*auth.NoAuth)
case auth.MethodProxyAuth:
auther = getAuther(auth.ProxyAuth{}, rawAuther).(*auth.ProxyAuth)
case auth.MethodHookAuth:
auther = getAuther(&auth.HookAuth{}, rawAuther).(*auth.HookAuth)
default:
checkErr(errors.New("invalid auth method"))
}

View File

@@ -29,15 +29,18 @@ override the options.`,
authMethod, auther := getAuthentication(flags)
s := &settings.Settings{
Key: generateKey(),
Signup: mustGetBool(flags, "signup"),
Shell: convertCmdStrToCmdArray(mustGetString(flags, "shell")),
AuthMethod: authMethod,
Defaults: defaults,
Key: generateKey(),
Signup: mustGetBool(flags, "signup"),
CreateUserDir: mustGetBool(flags, "create-user-dir"),
Shell: convertCmdStrToCmdArray(mustGetString(flags, "shell")),
AuthMethod: authMethod,
Defaults: defaults,
Branding: settings.Branding{
Name: mustGetString(flags, "branding.name"),
DisableExternal: mustGetBool(flags, "branding.disableExternal"),
Files: mustGetString(flags, "branding.files"),
Name: mustGetString(flags, "branding.name"),
DisableExternal: mustGetBool(flags, "branding.disableExternal"),
DisableUsedPercentage: mustGetBool(flags, "branding.disableUsedPercentage"),
Theme: mustGetString(flags, "branding.theme"),
Files: mustGetString(flags, "branding.files"),
},
}

View File

@@ -49,10 +49,18 @@ you want to change. Other options will remain unchanged.`,
hasAuth = true
case "shell":
set.Shell = convertCmdStrToCmdArray(mustGetString(flags, flag.Name))
case "create-user-dir":
set.CreateUserDir = mustGetBool(flags, flag.Name)
case "branding.name":
set.Branding.Name = mustGetString(flags, flag.Name)
case "branding.color":
set.Branding.Color = mustGetString(flags, flag.Name)
case "branding.theme":
set.Branding.Theme = mustGetString(flags, flag.Name)
case "branding.disableExternal":
set.Branding.DisableExternal = mustGetBool(flags, flag.Name)
case "branding.disableUsedPercentage":
set.Branding.DisableUsedPercentage = mustGetBool(flags, flag.Name)
case "branding.files":
set.Branding.Files = mustGetString(flags, flag.Name)
}

View File

@@ -98,12 +98,12 @@ func generateMarkdown(cmd *cobra.Command, w io.Writer) {
buf.WriteString(long + "\n\n")
if cmd.Runnable() {
buf.WriteString(fmt.Sprintf("```\n%s\n```\n\n", cmd.UseLine()))
_, _ = fmt.Fprintf(buf, "```\n%s\n```\n\n", cmd.UseLine())
}
if len(cmd.Example) > 0 {
buf.WriteString("## Examples\n\n")
buf.WriteString(fmt.Sprintf("```\n%s\n```\n\n", cmd.Example))
_, _ = fmt.Fprintf(buf, "```\n%s\n```\n\n", cmd.Example)
}
printOptions(buf, cmd)

View File

@@ -3,8 +3,8 @@ package cmd
import (
"crypto/tls"
"errors"
"io"
"io/fs"
"io/ioutil"
"log"
"net"
"net/http"
@@ -64,6 +64,7 @@ func addServerFlags(flags *pflag.FlagSet) {
flags.Uint32("socket-perm", 0666, "unix socket file permissions") //nolint:gomnd
flags.StringP("baseurl", "b", "", "base url")
flags.String("cache-dir", "", "file cache directory (disabled if empty)")
flags.String("token-expiration-time", "2h", "user session timeout")
flags.Int("img-processors", 4, "image processors count") //nolint:gomnd
flags.Bool("disable-thumbnails", false, "disable image thumbnails")
flags.Bool("disable-preview-resize", false, "disable resize of image previews")
@@ -181,6 +182,7 @@ user created with the credentials from options "username" and "password".`,
defer listener.Close()
log.Println("Listening on", listener.Addr().String())
//nolint: gosec
if err := http.Serve(listener, handler); err != nil {
log.Fatal(err)
}
@@ -260,6 +262,10 @@ func getRunParams(flags *pflag.FlagSet, st *storage.Storage) *settings.Server {
_, disableExec := getParamB(flags, "disable-exec")
server.EnableExec = !disableExec
if val, set := getParamB(flags, "token-expiration-time"); set {
server.TokenExpirationTime = val
}
return server
}
@@ -299,7 +305,7 @@ func setupLog(logMethod string) {
case "stderr":
log.SetOutput(os.Stderr)
case "":
log.SetOutput(ioutil.Discard)
log.SetOutput(io.Discard)
default:
log.SetOutput(&lumberjack.Logger{
Filename: logMethod,
@@ -312,9 +318,10 @@ func setupLog(logMethod string) {
func quickSetup(flags *pflag.FlagSet, d pythonData) {
set := &settings.Settings{
Key: generateKey(),
Signup: false,
CreateUserDir: false,
Key: generateKey(),
Signup: false,
CreateUserDir: false,
UserHomeBasePath: settings.DefaultUsersHomeBasePath,
Defaults: settings.UserDefaults{
Scope: ".",
Locale: "en",
@@ -330,6 +337,15 @@ func quickSetup(flags *pflag.FlagSet, d pythonData) {
Download: true,
},
},
AuthMethod: "",
Branding: settings.Branding{},
Tus: settings.Tus{
ChunkSize: settings.DefaultTusChunkSize,
RetryCount: settings.DefaultTusRetryCount,
},
Commands: nil,
Shell: nil,
Rules: nil,
}
var err error

View File

@@ -53,7 +53,7 @@ func printUsers(usrs []*users.User) {
}
func parseUsernameOrID(arg string) (username string, id uint) {
id64, err := strconv.ParseUint(arg, 10, 64) //nolint:gomnd
id64, err := strconv.ParseUint(arg, 10, 64)
if err != nil {
return arg, 0
}

View File

@@ -9,7 +9,7 @@ import (
"path/filepath"
"strings"
"github.com/asdine/storm"
"github.com/asdine/storm/v3"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
yaml "gopkg.in/yaml.v2"
@@ -87,16 +87,23 @@ func python(fn pythonFunc, cfg pythonConfig) cobraFunc {
data := pythonData{hadDB: true}
path := getParam(cmd.Flags(), "database")
absPath, err := filepath.Abs(path)
if err != nil {
panic(err)
}
exists, err := dbExists(path)
if err != nil {
panic(err)
} else if exists && cfg.noDB {
log.Fatal(path + " already exists")
log.Fatal(absPath + " already exists")
} else if !exists && !cfg.noDB && !cfg.allowNoDB {
log.Fatal(path + " does not exist. Please run 'filebrowser config init' first.")
log.Fatal(absPath + " does not exist. Please run 'filebrowser config init' first.")
} else if !exists && !cfg.noDB {
log.Println("Warning: filebrowser.db can't be found. Initialing in " + strings.TrimSuffix(absPath, "filebrowser.db"))
}
log.Println("Using database: " + absPath)
data.hadDB = exists
db, err := storm.Open(path)
checkErr(err)

28
common.mk Normal file
View File

@@ -0,0 +1,28 @@
SHELL := /usr/bin/env bash
DATE ?= $(shell date +%FT%T%z)
BASE_PATH := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
VERSION ?= $(shell git describe --tags --always --match=v* 2> /dev/null || \
cat $(CURDIR)/.version 2> /dev/null || echo v0)
VERSION_HASH = $(shell git rev-parse HEAD)
BRANCH = $(shell git rev-parse --abbrev-ref HEAD)
go = GOGC=off go
MODULE = $(shell env GO111MODULE=on go list -m)
# printing
# $Q (quiet) is used in the targets as a replacer for @.
# This macro helps to print the command for debugging by setting V to 1. Example `make test-unit V=1`
V = 0
Q = $(if $(filter 1,$V),,@)
# $M is a macro to print a colored ▶ character. Example `$(info $(M) running coverage tests…)` will print "▶ running coverage tests…"
M = $(shell printf "\033[34;1m▶\033[0m")
GREEN := $(shell tput -Txterm setaf 2)
YELLOW := $(shell tput -Txterm setaf 3)
WHITE := $(shell tput -Txterm setaf 7)
CYAN := $(shell tput -Txterm setaf 6)
RESET := $(shell tput -Txterm sgr0)
define global_option
printf " ${YELLOW}%-20s${GREEN}%s${RESET}\n" $(1) $(2)
endef

View File

@@ -6,7 +6,7 @@ import (
"encoding/hex"
"errors"
"fmt"
"io/ioutil"
"io"
"os"
"path/filepath"
"sync"
@@ -55,7 +55,7 @@ func (f *FileCache) Load(ctx context.Context, key string) (value []byte, exist b
}
defer r.Close()
value, err = ioutil.ReadAll(r)
value, err = io.ReadAll(r)
if err != nil {
return nil, false, err
}

View File

@@ -0,0 +1,8 @@
{
"port": 80,
"baseURL": "",
"address": "",
"log": "stdout",
"database": "/database/filebrowser.db",
"root": "/srv"
}

View File

@@ -0,0 +1,15 @@
#!/usr/bin/with-contenv bash
# make folders
mkdir -p /database
# copy config
if [ ! -f "/config/settings.json" ]; then
cp -a /defaults/settings.json /config/settings.json
fi
# permissions
chown abc:abc \
/config/settings.json \
/database \
/srv

View File

@@ -0,0 +1,3 @@
#!/usr/bin/with-contenv bash
exec s6-setuidgid abc filebrowser -c /config/settings.json -d /database/filebrowser.db;

View File

@@ -7,6 +7,7 @@ import (
"crypto/sha512"
"encoding/hex"
"hash"
"image"
"io"
"log"
"mime"
@@ -23,23 +24,28 @@ import (
"github.com/filebrowser/filebrowser/v2/rules"
)
const PermFile = 0644
const PermDir = 0755
// FileInfo describes a file.
type FileInfo struct {
*Listing
Fs afero.Fs `json:"-"`
Path string `json:"path"`
Name string `json:"name"`
Size int64 `json:"size"`
Extension string `json:"extension"`
ModTime time.Time `json:"modified"`
Mode os.FileMode `json:"mode"`
IsDir bool `json:"isDir"`
IsSymlink bool `json:"isSymlink"`
Type string `json:"type"`
Subtitles []string `json:"subtitles,omitempty"`
Content string `json:"content,omitempty"`
Checksums map[string]string `json:"checksums,omitempty"`
Token string `json:"token,omitempty"`
Fs afero.Fs `json:"-"`
Path string `json:"path"`
Name string `json:"name"`
Size int64 `json:"size"`
Extension string `json:"extension"`
ModTime time.Time `json:"modified"`
Mode os.FileMode `json:"mode"`
IsDir bool `json:"isDir"`
IsSymlink bool `json:"isSymlink"`
Type string `json:"type"`
Subtitles []string `json:"subtitles,omitempty"`
Content string `json:"content,omitempty"`
Checksums map[string]string `json:"checksums,omitempty"`
Token string `json:"token,omitempty"`
currentDir []os.FileInfo `json:"-"`
Resolution *ImageResolution `json:"resolution,omitempty"`
}
// FileOptions are the options when getting a file info.
@@ -54,6 +60,11 @@ type FileOptions struct {
Content bool
}
type ImageResolution struct {
Width int `json:"width"`
Height int `json:"height"`
}
// NewFileInfo creates a File object from a path and a given user. This File
// object will be automatically filled depending on if it is a directory
// or a file. If it's a video file, it will also detect any subtitles.
@@ -124,6 +135,7 @@ func stat(opts FileOptions) (*FileInfo, error) {
// set correct file size in case of symlink
if file != nil && file.IsSymlink {
file.Size = info.Size()
file.IsDir = info.IsDir()
return file, nil
}
@@ -184,8 +196,22 @@ func (i *FileInfo) Checksum(algo string) error {
return nil
}
func (i *FileInfo) RealPath() string {
if realPathFs, ok := i.Fs.(interface {
RealPath(name string) (fPath string, err error)
}); ok {
realPath, err := realPathFs.RealPath(i.Path)
if err == nil {
return realPath
}
}
return i.Path
}
// TODO: use constants
//
//nolint:goconst
//TODO: use constants
func (i *FileInfo) detectType(modify, saveContent, readHeader bool) error {
if IsNamedPipe(i.Mode) {
i.Type = "blob"
@@ -217,6 +243,15 @@ func (i *FileInfo) detectType(modify, saveContent, readHeader bool) error {
return nil
case strings.HasPrefix(mimetype, "image"):
i.Type = "image"
resolution, err := calculateImageResolution(i.Fs, i.Path)
if err != nil {
log.Printf("Error calculating image resolution: %v", err)
} else {
i.Resolution = resolution
}
return nil
case strings.HasSuffix(mimetype, "pdf"):
i.Type = "pdf"
return nil
case (strings.HasPrefix(mimetype, "text") || !isBinary(buffer)) && i.Size <= 10*1024*1024: // 10 MB
i.Type = "text"
@@ -242,6 +277,28 @@ func (i *FileInfo) detectType(modify, saveContent, readHeader bool) error {
return nil
}
func calculateImageResolution(fs afero.Fs, filePath string) (*ImageResolution, error) {
file, err := fs.Open(filePath)
if err != nil {
return nil, err
}
defer func() {
if cErr := file.Close(); cErr != nil {
log.Printf("Failed to close file: %v", cErr)
}
}()
config, _, err := image.DecodeConfig(file)
if err != nil {
return nil, err
}
return &ImageResolution{
Width: config.Width,
Height: config.Height,
}, nil
}
func (i *FileInfo) readFirstBytes() []byte {
reader, err := i.Fs.Open(i.Path)
if err != nil {
@@ -270,11 +327,25 @@ func (i *FileInfo) detectSubtitles() {
i.Subtitles = []string{}
ext := filepath.Ext(i.Path)
// TODO: detect multiple languages. Base.Lang.vtt
// detect multiple languages. Base*.vtt
// TODO: give subtitles descriptive names (lang) and track attributes
parentDir := strings.TrimRight(i.Path, i.Name)
var dir []os.FileInfo
if len(i.currentDir) > 0 {
dir = i.currentDir
} else {
var err error
dir, err = afero.ReadDir(i.Fs, parentDir)
if err != nil {
return
}
}
fPath := strings.TrimSuffix(i.Path, ext) + ".vtt"
if _, err := i.Fs.Stat(fPath); err == nil {
i.Subtitles = append(i.Subtitles, fPath)
base := strings.TrimSuffix(i.Name, ext)
for _, f := range dir {
if !f.IsDir() && strings.HasPrefix(f.Name(), base) && strings.HasSuffix(f.Name(), ".vtt") {
i.Subtitles = append(i.Subtitles, path.Join(parentDir, f.Name()))
}
}
}
@@ -299,7 +370,7 @@ func (i *FileInfo) readListing(checker rules.Checker, readHeader bool) error {
continue
}
isSymlink := false
isSymlink, isInvalidLink := false, false
if IsSymlink(f.Mode()) {
isSymlink = true
// It's a symbolic link. We try to follow it. If it doesn't work,
@@ -307,19 +378,31 @@ func (i *FileInfo) readListing(checker rules.Checker, readHeader bool) error {
info, err := i.Fs.Stat(fPath)
if err == nil {
f = info
} else {
isInvalidLink = true
}
}
file := &FileInfo{
Fs: i.Fs,
Name: name,
Size: f.Size(),
ModTime: f.ModTime(),
Mode: f.Mode(),
IsDir: f.IsDir(),
IsSymlink: isSymlink,
Extension: filepath.Ext(name),
Path: fPath,
Fs: i.Fs,
Name: name,
Size: f.Size(),
ModTime: f.ModTime(),
Mode: f.Mode(),
IsDir: f.IsDir(),
IsSymlink: isSymlink,
Extension: filepath.Ext(name),
Path: fPath,
currentDir: dir,
}
if !file.IsDir && strings.HasPrefix(mime.TypeByExtension(file.Extension), "image/") {
resolution, err := calculateImageResolution(file.Fs, file.Path)
if err != nil {
log.Printf("Error calculating resolution for image %s: %v", file.Path, err)
} else {
file.Resolution = resolution
}
}
if file.IsDir {
@@ -327,9 +410,13 @@ func (i *FileInfo) readListing(checker rules.Checker, readHeader bool) error {
} else {
listing.NumFiles++
err := file.detectType(true, false, readHeader)
if err != nil {
return err
if isInvalidLink {
file.Type = "invalid_link"
} else {
err := file.detectType(true, false, readHeader)
if err != nil {
return err
}
}
}

View File

@@ -16,6 +16,7 @@ type Listing struct {
}
// ApplySort applies the sort order using .Order and .Sort
//
//nolint:goconst
func (l Listing) ApplySort() {
// Check '.Order' to know how to sort

View File

@@ -7,6 +7,8 @@ import (
"path/filepath"
"github.com/spf13/afero"
"github.com/filebrowser/filebrowser/v2/files"
)
// MoveFile moves file from src to dst.
@@ -17,12 +19,12 @@ func MoveFile(fs afero.Fs, src, dst string) error {
return nil
}
// fallback
err := CopyFile(fs, src, dst)
err := Copy(fs, src, dst)
if err != nil {
_ = fs.Remove(dst)
return err
}
if err := fs.Remove(src); err != nil {
if err := fs.RemoveAll(src); err != nil {
return err
}
return nil
@@ -40,13 +42,13 @@ func CopyFile(fs afero.Fs, source, dest string) error {
// Makes the directory needed to create the dst
// file.
err = fs.MkdirAll(filepath.Dir(dest), 0666) //nolint:gomnd
err = fs.MkdirAll(filepath.Dir(dest), files.PermDir)
if err != nil {
return err
}
// Create the destination file.
dst, err := fs.OpenFile(dest, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0775) //nolint:gomnd
dst, err := fs.OpenFile(dest, os.O_RDWR|os.O_CREATE|os.O_TRUNC, files.PermFile)
if err != nil {
return err
}

20
frontend/.eslintrc.json Normal file
View File

@@ -0,0 +1,20 @@
{
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/essential",
"eslint:recommended",
"@vue/eslint-config-prettier"
],
"rules": {
"vue/multi-word-component-names": "off",
"vue/no-reserved-component-names": "warn",
"vue/no-mutating-props": "warn"
},
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
}
}

2
frontend/.prettierignore Normal file
View File

@@ -0,0 +1,2 @@
# Ignore artifacts:
dist

View File

@@ -0,0 +1,3 @@
{
"trailingComma": "es5"
}

View File

@@ -1,3 +1,4 @@
//go:build !dev
// +build !dev
package frontend

View File

@@ -1,3 +1,4 @@
//go:build dev
// +build dev
package frontend

View File

@@ -1,3 +0,0 @@
module.exports = {
presets: ["@vue/app"],
};

View File

@@ -1,4 +0,0 @@
# Ignore everything in this directory
*
# Except this file
!.gitignore

0
frontend/dist/.gitkeep vendored Normal file
View File

192
frontend/index.html Normal file
View File

@@ -0,0 +1,192 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, user-scalable=no"
/>
<title>File Browser</title>
<link
rel="icon"
type="image/png"
sizes="32x32"
href="/img/icons/favicon-32x32.png"
/>
<link
rel="icon"
type="image/png"
sizes="16x16"
href="/img/icons/favicon-16x16.png"
/>
<!-- Add to home screen for Android and modern mobile browsers -->
<link
rel="manifest"
id="manifestPlaceholder"
crossorigin="use-credentials"
/>
<meta name="theme-color" content="#2979ff" />
<!-- Add to home screen for Safari on iOS/iPadOS -->
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<meta name="apple-mobile-web-app-title" content="assets" />
<link rel="apple-touch-icon" href="/img/icons/apple-touch-icon.png" />
<!-- Add to home screen for Windows -->
<meta
name="msapplication-TileImage"
content="/img/icons/mstile-144x144.png"
/>
<meta name="msapplication-TileColor" content="#2979ff" />
<!-- Inject Some Variables and generate the manifest json -->
<script>
// We can assign JSON directly
window.FileBrowser = {
AuthMethod: "json",
BaseURL: "",
CSS: false,
Color: "",
DisableExternal: false,
DisableUsedPercentage: false,
EnableExec: true,
EnableThumbs: true,
LoginPage: true,
Name: "",
NoAuth: false,
ReCaptcha: false,
ResizePreview: true,
Signup: false,
StaticURL: "",
Theme: "",
TusSettings: { chunkSize: 10485760, retryCount: 5 },
Version: "(untracked)",
};
// Global function to prepend static url
window.__prependStaticUrl = (url) => {
return `${window.FileBrowser.StaticURL}/${url.replace(/^\/+/, "")}`;
};
var dynamicManifest = {
name: window.FileBrowser.Name || "File Browser",
short_name: window.FileBrowser.Name || "File Browser",
icons: [
{
src: window.__prependStaticUrl(
"/img/icons/android-chrome-192x192.png"
),
sizes: "192x192",
type: "image/png",
},
{
src: window.__prependStaticUrl(
"/img/icons/android-chrome-512x512.png"
),
sizes: "512x512",
type: "image/png",
},
],
start_url: window.location.origin + window.FileBrowser.BaseURL,
display: "standalone",
background_color: "#ffffff",
theme_color: window.FileBrowser.Color || "#455a64",
};
const stringManifest = JSON.stringify(dynamicManifest);
const blob = new Blob([stringManifest], { type: "application/json" });
const manifestURL = URL.createObjectURL(blob);
document
.querySelector("#manifestPlaceholder")
.setAttribute("href", manifestURL);
</script>
<style>
#loading {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #fff;
z-index: 9999;
transition: 0.1s ease opacity;
-webkit-transition: 0.1s ease opacity;
}
#loading.done {
opacity: 0;
}
#loading .spinner {
width: 70px;
text-align: center;
position: fixed;
top: 50%;
left: 50%;
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
}
#loading .spinner > div {
width: 18px;
height: 18px;
background-color: #333;
border-radius: 100%;
display: inline-block;
-webkit-animation: sk-bouncedelay 1.4s infinite ease-in-out both;
animation: sk-bouncedelay 1.4s infinite ease-in-out both;
}
#loading .spinner .bounce1 {
-webkit-animation-delay: -0.32s;
animation-delay: -0.32s;
}
#loading .spinner .bounce2 {
-webkit-animation-delay: -0.16s;
animation-delay: -0.16s;
}
@-webkit-keyframes sk-bouncedelay {
0%,
80%,
100% {
-webkit-transform: scale(0);
}
40% {
-webkit-transform: scale(1);
}
}
@keyframes sk-bouncedelay {
0%,
80%,
100% {
-webkit-transform: scale(0);
transform: scale(0);
}
40% {
-webkit-transform: scale(1);
transform: scale(1);
}
}
</style>
</head>
<body>
<div id="app"></div>
<div id="loading">
<div class="spinner">
<div class="bounce1"></div>
<div class="bounce2"></div>
<div class="bounce3"></div>
</div>
</div>
<script type="module" src="/src/main.js"></script>
</body>
</html>

10
frontend/jsconfig.json Normal file
View File

@@ -0,0 +1,10 @@
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}

29138
frontend/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -2,67 +2,59 @@
"name": "filebrowser-frontend",
"version": "2.0.0",
"private": true,
"type": "module",
"scripts": {
"serve": "vue-cli-service serve",
"build": "find ./dist -maxdepth 1 -mindepth 1 ! -name '.gitignore' -exec rm -r {} + && vue-cli-service build --no-clean",
"lint": "npx vue-cli-service lint --no-fix",
"fix": "npx vue-cli-service lint",
"watch": "find ./dist -maxdepth 1 -mindepth 1 ! -name '.gitignore' -exec rm -r {} + && vue-cli-service build --watch --no-clean"
"dev": "vite dev",
"serve": "vite serve",
"build": "vite build",
"watch": "vite build --watch",
"clean": "find ./dist -maxdepth 1 -mindepth 1 ! -name '.gitkeep' -exec rm -r {} +",
"lint": "eslint --ext .vue,.js src/",
"lint:fix": "eslint --ext .vue,.js --fix src/",
"format": "prettier --write ."
},
"dependencies": {
"ace-builds": "^1.4.7",
"clipboard": "^2.0.4",
"core-js": "^3.9.1",
"css-vars-ponyfill": "^2.4.3",
"js-base64": "^2.5.1",
"ace-builds": "^1.23.4",
"clipboard": "^2.0.11",
"core-js": "^3.32.0",
"css-vars-ponyfill": "^2.4.8",
"filesize": "^10.0.8",
"js-base64": "^3.7.5",
"lodash.clonedeep": "^4.5.0",
"lodash.throttle": "^4.1.1",
"material-design-icons": "^3.0.1",
"moment": "^2.24.0",
"material-icons": "^1.13.9",
"moment": "^2.29.4",
"normalize.css": "^8.0.1",
"noty": "^3.2.0-beta",
"pretty-bytes": "^6.1.1",
"qrcode.vue": "^1.7.0",
"tus-js-client": "^3.1.1",
"utif": "^3.1.0",
"vue": "^2.6.10",
"vue-i18n": "^8.15.3",
"vue-lazyload": "^1.3.3",
"vue-router": "^3.1.3",
"vuex": "^3.1.2",
"vue": "^2.7.14",
"vue-async-computed": "^3.9.0",
"vue-i18n": "^8.28.2",
"vue-lazyload": "^1.3.5",
"vue-router": "^3.6.5",
"vue-simple-progress": "^1.1.1",
"vuex": "^3.6.2",
"vuex-router-sync": "^5.0.0",
"whatwg-fetch": "^3.6.2"
"whatwg-fetch": "^3.6.17"
},
"devDependencies": {
"@vue/cli-plugin-babel": "^4.1.2",
"@vue/cli-plugin-eslint": "~4.5.0",
"@vue/cli-service": "^4.1.2",
"@vue/eslint-config-prettier": "^6.0.0",
"babel-eslint": "^10.1.0",
"compression-webpack-plugin": "^6.0.3",
"eslint": "^6.7.2",
"eslint-plugin-prettier": "^3.3.1",
"eslint-plugin-vue": "^6.2.2",
"prettier": "^2.2.1",
"vue-template-compiler": "^2.6.10"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/essential",
"eslint:recommended",
"@vue/prettier"
],
"rules": {},
"parserOptions": {
"parser": "babel-eslint"
}
},
"postcss": {
"plugins": {
"autoprefixer": {}
}
"@vitejs/plugin-legacy": "^4.1.1",
"@vitejs/plugin-vue2": "^2.2.0",
"@vue/eslint-config-prettier": "^8.0.0",
"autoprefixer": "^10.4.14",
"eslint": "^8.46.0",
"eslint-plugin-prettier": "^5.0.0",
"eslint-plugin-vue": "^9.16.1",
"jsdom": "^22.1.0",
"postcss": "^8.4.31",
"prettier": "^3.0.1",
"terser": "^5.19.2",
"vite": "^4.5.2",
"vite-plugin-compression2": "^0.10.3",
"vite-plugin-rewrite-all": "^1.0.1"
},
"browserslist": [
"> 1%",

View File

@@ -0,0 +1,5 @@
module.exports = {
plugins: {
autoprefixer: {},
},
};

0
frontend/public/.gitkeep Normal file
View File

View File

@@ -1,144 +1,195 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, user-scalable=no"
/>
[{[ if .ReCaptcha -]}]
[{[ if .ReCaptcha -]}]
<script src="[{[ .ReCaptchaHost ]}]/recaptcha/api.js?render=explicit"></script>
[{[ end ]}]
[{[ end ]}]
<title>[{[ if .Name -]}][{[ .Name ]}][{[ else ]}]File Browser[{[ end ]}]</title>
<title>
[{[ if .Name -]}][{[ .Name ]}][{[ else ]}]File Browser[{[ end ]}]
</title>
<link rel="icon" type="image/png" sizes="32x32" href="[{[ .StaticURL ]}]/img/icons/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="[{[ .StaticURL ]}]/img/icons/favicon-16x16.png">
<meta name="robots" content="noindex,nofollow">
<link
rel="icon"
type="image/png"
sizes="32x32"
href="[{[ .StaticURL ]}]/img/icons/favicon-32x32.png"
/>
<link
rel="icon"
type="image/png"
sizes="16x16"
href="[{[ .StaticURL ]}]/img/icons/favicon-16x16.png"
/>
<!-- Add to home screen for Android and modern mobile browsers -->
<link rel="manifest" id="manifestPlaceholder" crossorigin="use-credentials">
<meta name="theme-color" content="#2979ff">
<!-- Add to home screen for Android and modern mobile browsers -->
<link
rel="manifest"
id="manifestPlaceholder"
crossorigin="use-credentials"
/>
<meta
name="theme-color"
content="[{[ if .Color -]}][{[ .Color ]}][{[ else ]}]#2979ff[{[ end ]}]"
/>
<!-- Add to home screen for Safari on iOS/iPadOS -->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="apple-mobile-web-app-title" content="assets">
<link rel="apple-touch-icon" href="[{[ .StaticURL ]}]/img/icons/apple-touch-icon.png">
<!-- Add to home screen for Safari on iOS/iPadOS -->
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<meta name="apple-mobile-web-app-title" content="assets" />
<link
rel="apple-touch-icon"
href="[{[ .StaticURL ]}]/img/icons/apple-touch-icon.png"
/>
<!-- Add to home screen for Windows -->
<meta name="msapplication-TileImage" content="[{[ .StaticURL ]}]/img/icons/mstile-144x144.png">
<meta name="msapplication-TileColor" content="#2979ff">
<!-- Add to home screen for Windows -->
<meta
name="msapplication-TileImage"
content="[{[ .StaticURL ]}]/img/icons/mstile-144x144.png"
/>
<meta
name="msapplication-TileColor"
content="[{[ if .Color -]}][{[ .Color ]}][{[ else ]}]#2979ff[{[ end ]}]"
/>
<!-- Inject Some Variables and generate the manifest json -->
<script>
window.FileBrowser = JSON.parse('[{[ .Json ]}]');
<!-- Inject Some Variables and generate the manifest json -->
<script>
// We can assign JSON directly
window.FileBrowser = [{[ .Json ]}];
// Global function to prepend static url
window.__prependStaticUrl = (url) => {
return `${window.FileBrowser.StaticURL}/${url.replace(/^\/+/, "")}`;
};
var dynamicManifest = {
name: window.FileBrowser.Name || "File Browser",
short_name: window.FileBrowser.Name || "File Browser",
icons: [
{
src: window.__prependStaticUrl("/img/icons/android-chrome-192x192.png"),
sizes: "192x192",
type: "image/png",
},
{
src: window.__prependStaticUrl("/img/icons/android-chrome-512x512.png"),
sizes: "512x512",
type: "image/png",
},
],
start_url: window.location.origin + window.FileBrowser.BaseURL,
display: "standalone",
background_color: "#ffffff",
theme_color: window.FileBrowser.Color || "#455a64",
};
var fullStaticURL = window.location.origin + window.FileBrowser.StaticURL;
var dynamicManifest = {
"name": window.FileBrowser.Name || 'File Browser',
"short_name": window.FileBrowser.Name || 'File Browser',
"icons": [
{
"src": fullStaticURL + "/img/icons/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": fullStaticURL + "/img/icons/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
const stringManifest = JSON.stringify(dynamicManifest);
const blob = new Blob([stringManifest], { type: "application/json" });
const manifestURL = URL.createObjectURL(blob);
document
.querySelector("#manifestPlaceholder")
.setAttribute("href", manifestURL);
</script>
<style>
#loading {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #fff;
z-index: 9999;
transition: 0.1s ease opacity;
-webkit-transition: 0.1s ease opacity;
}
#loading.done {
opacity: 0;
}
#loading .spinner {
width: 70px;
text-align: center;
position: fixed;
top: 50%;
left: 50%;
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
}
#loading .spinner > div {
width: 18px;
height: 18px;
background-color: #333;
border-radius: 100%;
display: inline-block;
-webkit-animation: sk-bouncedelay 1.4s infinite ease-in-out both;
animation: sk-bouncedelay 1.4s infinite ease-in-out both;
}
#loading .spinner .bounce1 {
-webkit-animation-delay: -0.32s;
animation-delay: -0.32s;
}
#loading .spinner .bounce2 {
-webkit-animation-delay: -0.16s;
animation-delay: -0.16s;
}
@-webkit-keyframes sk-bouncedelay {
0%,
80%,
100% {
-webkit-transform: scale(0);
}
],
"start_url": window.location.origin + window.FileBrowser.BaseURL,
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#455a64"
}
40% {
-webkit-transform: scale(1);
}
}
const stringManifest = JSON.stringify(dynamicManifest);
const blob = new Blob([stringManifest], {type: 'application/json'});
const manifestURL = URL.createObjectURL(blob);
document.querySelector('#manifestPlaceholder').setAttribute('href', manifestURL);
</script>
@keyframes sk-bouncedelay {
0%,
80%,
100% {
-webkit-transform: scale(0);
transform: scale(0);
}
40% {
-webkit-transform: scale(1);
transform: scale(1);
}
}
</style>
</head>
<body>
<div id="app"></div>
<style>
#loading {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #fff;
z-index: 9999;
transition: .1s ease opacity;
-webkit-transition: .1s ease opacity;
}
#loading.done {
opacity: 0;
}
#loading .spinner {
width: 70px;
text-align: center;
position: fixed;
top: 50%;
left: 50%;
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
}
#loading .spinner > div {
width: 18px;
height: 18px;
background-color: #333;
border-radius: 100%;
display: inline-block;
-webkit-animation: sk-bouncedelay 1.4s infinite ease-in-out both;
animation: sk-bouncedelay 1.4s infinite ease-in-out both;
}
#loading .spinner .bounce1 {
-webkit-animation-delay: -0.32s;
animation-delay: -0.32s;
}
#loading .spinner .bounce2 {
-webkit-animation-delay: -0.16s;
animation-delay: -0.16s;
}
@-webkit-keyframes sk-bouncedelay {
0%, 80%, 100% { -webkit-transform: scale(0) }
40% { -webkit-transform: scale(1.0) }
}
@keyframes sk-bouncedelay {
0%, 80%, 100% {
-webkit-transform: scale(0);
transform: scale(0);
} 40% {
-webkit-transform: scale(1.0);
transform: scale(1.0);
}
}
</style>
</head>
<body>
<div id="app"></div>
<div id="loading">
<div class="spinner">
<div class="bounce1"></div>
<div class="bounce2"></div>
<div class="bounce3"></div>
<div id="loading">
<div class="spinner">
<div class="bounce1"></div>
<div class="bounce2"></div>
<div class="bounce3"></div>
</div>
</div>
</div>
[{[ if .Theme -]}]
<link rel="stylesheet" href="[{[ .StaticURL ]}]/themes/[{[ .Theme ]}].css" />
[{[ end ]}]
[{[ if .CSS -]}]
<script type="module" src="/src/main.js"></script>
[{[ if .Theme -]}]
<link
rel="stylesheet"
href="[{[ .StaticURL ]}]/themes/[{[ .Theme ]}].css"
/>
[{[ end ]}] [{[ if .CSS -]}]
<link rel="stylesheet" href="[{[ .StaticURL ]}]/custom.css" />
[{[ end ]}]
</body>
[{[ end ]}]
</body>
</html>

View File

@@ -174,6 +174,12 @@ table th {
background: var(--surfacePrimary);
color: var(--textPrimary);
}
.shell__divider {
background: rgba(255, 255, 255, 0.1);
}
.shell__divider:hover {
background: rgba(255, 255, 255, 0.4);
}
.shell__result {
border-top: 1px solid var(--divider);
}

View File

@@ -6,7 +6,7 @@
<script>
// eslint-disable-next-line no-undef
__webpack_public_path__ = window.FileBrowser.StaticURL + "/";
// __webpack_public_path__ = window.FileBrowser.StaticURL + "/";
export default {
name: "app",

View File

@@ -1,34 +1,31 @@
import { fetchURL, removePrefix } from "./utils";
import { createURL, fetchURL, removePrefix } from "./utils";
import { baseURL } from "@/utils/constants";
import store from "@/store";
import { upload as postTus, useTus } from "./tus";
export async function fetch(url) {
url = removePrefix(url);
const res = await fetchURL(`/api/resources${url}`, {});
if (res.status === 200) {
let data = await res.json();
data.url = `/files${url}`;
let data = await res.json();
data.url = `/files${url}`;
if (data.isDir) {
if (!data.url.endsWith("/")) data.url += "/";
data.items = data.items.map((item, index) => {
item.index = index;
item.url = `${data.url}${encodeURIComponent(item.name)}`;
if (data.isDir) {
if (!data.url.endsWith("/")) data.url += "/";
data.items = data.items.map((item, index) => {
item.index = index;
item.url = `${data.url}${encodeURIComponent(item.name)}`;
if (item.isDir) {
item.url += "/";
}
if (item.isDir) {
item.url += "/";
}
return item;
});
}
return data;
} else {
throw new Error(res.status);
return item;
});
}
return data;
}
async function resourceAction(url, method, content) {
@@ -42,11 +39,7 @@ async function resourceAction(url, method, content) {
const res = await fetchURL(`/api/resources${url}`, opts);
if (res.status !== 200) {
throw new Error(await res.text());
} else {
return res;
}
return res;
}
export async function remove(url) {
@@ -86,6 +79,21 @@ export function download(format, ...files) {
}
export async function post(url, content = "", overwrite = false, onupload) {
// Use the pre-existing API if:
const useResourcesApi =
// a folder is being created
url.endsWith("/") ||
// We're not using http(s)
(content instanceof Blob &&
!["http:", "https:"].includes(window.location.protocol)) ||
// Tus is disabled / not applicable
!(await useTus(content));
return useResourcesApi
? postResources(url, content, overwrite, onupload)
: postTus(url, content, overwrite, onupload);
}
async function postResources(url, content = "", overwrite = false, onupload) {
url = removePrefix(url);
let bufferContent;
@@ -119,8 +127,8 @@ export async function post(url, content = "", overwrite = false, onupload) {
}
};
request.onerror = (error) => {
reject(error);
request.onerror = () => {
reject(new Error("001 Connection aborted"));
};
request.send(bufferContent || content);
@@ -154,3 +162,41 @@ export async function checksum(url, algo) {
const data = await resourceAction(`${url}?checksum=${algo}`, "GET");
return (await data.json()).checksums[algo];
}
export function getDownloadURL(file, inline) {
const params = {
...(inline && { inline: "true" }),
};
return createURL("api/raw" + file.path, params);
}
export function getPreviewURL(file, size) {
const params = {
inline: "true",
key: Date.parse(file.modified),
};
return createURL("api/preview/" + size + file.path, params);
}
export function getSubtitlesURL(file) {
const params = {
inline: "true",
};
const subtitles = [];
for (const sub of file.subtitles) {
subtitles.push(createURL("api/raw" + sub, params));
}
return subtitles;
}
export async function usage(url) {
url = removePrefix(url);
const res = await fetchURL(`/api/usage${url}`, {});
return await res.json();
}

View File

@@ -1,35 +1,35 @@
import { fetchURL, removePrefix } from "./utils";
import { fetchURL, removePrefix, createURL } from "./utils";
import { baseURL } from "@/utils/constants";
export async function fetch(url, password = "") {
url = removePrefix(url);
const res = await fetchURL(`/api/public/share${url}`, {
headers: { "X-SHARE-PASSWORD": password },
});
const res = await fetchURL(
`/api/public/share${url}`,
{
headers: { "X-SHARE-PASSWORD": encodeURIComponent(password) },
},
false
);
if (res.status === 200) {
let data = await res.json();
data.url = `/share${url}`;
let data = await res.json();
data.url = `/share${url}`;
if (data.isDir) {
if (!data.url.endsWith("/")) data.url += "/";
data.items = data.items.map((item, index) => {
item.index = index;
item.url = `${data.url}${encodeURIComponent(item.name)}`;
if (data.isDir) {
if (!data.url.endsWith("/")) data.url += "/";
data.items = data.items.map((item, index) => {
item.index = index;
item.url = `${data.url}${encodeURIComponent(item.name)}`;
if (item.isDir) {
item.url += "/";
}
if (item.isDir) {
item.url += "/";
}
return item;
});
}
return data;
} else {
throw new Error(res.status);
return item;
});
}
return data;
}
export function download(format, hash, token, ...files) {
@@ -59,3 +59,12 @@ export function download(format, hash, token, ...files) {
window.open(url);
}
export function getDownloadURL(share, inline = false) {
const params = {
...(inline && { inline: "true" }),
...(share.token && { token: share.token }),
};
return createURL("api/public/dl/" + share.hash + share.path, params, false);
}

View File

@@ -11,21 +11,17 @@ export default async function search(base, query) {
let res = await fetchURL(`/api/search${base}?query=${query}`, {});
if (res.status === 200) {
let data = await res.json();
let data = await res.json();
data = data.map((item) => {
item.url = `/files${base}` + url.encodePath(item.path);
data = data.map((item) => {
item.url = `/files${base}` + url.encodePath(item.path);
if (item.dir) {
item.url += "/";
}
if (item.dir) {
item.url += "/";
}
return item;
});
return item;
});
return data;
} else {
throw Error(res.status);
}
return data;
}

View File

@@ -5,12 +5,8 @@ export function get() {
}
export async function update(settings) {
const res = await fetchURL(`/api/settings`, {
await fetchURL(`/api/settings`, {
method: "PUT",
body: JSON.stringify(settings),
});
if (res.status !== 200) {
throw new Error(res.status);
}
}

View File

@@ -1,4 +1,4 @@
import { fetchURL, fetchJSON, removePrefix } from "./utils";
import { fetchURL, fetchJSON, removePrefix, createURL } from "./utils";
export async function list() {
return fetchJSON("/api/shares");
@@ -10,13 +10,9 @@ export async function get(url) {
}
export async function remove(hash) {
const res = await fetchURL(`/api/share/${hash}`, {
await fetchURL(`/api/share/${hash}`, {
method: "DELETE",
});
if (res.status !== 200) {
throw new Error(res.status);
}
}
export async function create(url, password = "", expires = "", unit = "hours") {
@@ -34,3 +30,7 @@ export async function create(url, password = "", expires = "", unit = "hours") {
body: body,
});
}
export function getShareURL(share) {
return createURL("share/" + share.hash, {}, false);
}

195
frontend/src/api/tus.js Normal file
View File

@@ -0,0 +1,195 @@
import * as tus from "tus-js-client";
import { baseURL, tusEndpoint, tusSettings } from "@/utils/constants";
import store from "@/store";
import { removePrefix } from "@/api/utils";
import { fetchURL } from "./utils";
const RETRY_BASE_DELAY = 1000;
const RETRY_MAX_DELAY = 20000;
const SPEED_UPDATE_INTERVAL = 1000;
const ALPHA = 0.2;
const ONE_MINUS_ALPHA = 1 - ALPHA;
const RECENT_SPEEDS_LIMIT = 5;
const MB_DIVISOR = 1024 * 1024;
const CURRENT_UPLOAD_LIST = {};
export async function upload(
filePath,
content = "",
overwrite = false,
onupload
) {
if (!tusSettings) {
// Shouldn't happen as we check for tus support before calling this function
throw new Error("Tus.io settings are not defined");
}
filePath = removePrefix(filePath);
let resourcePath = `${tusEndpoint}${filePath}?override=${overwrite}`;
await createUpload(resourcePath);
return new Promise((resolve, reject) => {
let upload = new tus.Upload(content, {
uploadUrl: `${baseURL}${resourcePath}`,
chunkSize: tusSettings.chunkSize,
retryDelays: computeRetryDelays(tusSettings),
parallelUploads: 1,
storeFingerprintForResuming: false,
headers: {
"X-Auth": store.state.jwt,
},
onError: function (error) {
if (CURRENT_UPLOAD_LIST[filePath].interval) {
clearInterval(CURRENT_UPLOAD_LIST[filePath].interval);
}
delete CURRENT_UPLOAD_LIST[filePath];
reject("Upload failed: " + error);
},
onProgress: function (bytesUploaded) {
let fileData = CURRENT_UPLOAD_LIST[filePath];
fileData.currentBytesUploaded = bytesUploaded;
if (!fileData.hasStarted) {
fileData.hasStarted = true;
fileData.lastProgressTimestamp = Date.now();
fileData.interval = setInterval(() => {
calcProgress(filePath);
}, SPEED_UPDATE_INTERVAL);
}
if (typeof onupload === "function") {
onupload({ loaded: bytesUploaded });
}
},
onSuccess: function () {
if (CURRENT_UPLOAD_LIST[filePath].interval) {
clearInterval(CURRENT_UPLOAD_LIST[filePath].interval);
}
delete CURRENT_UPLOAD_LIST[filePath];
resolve();
},
});
CURRENT_UPLOAD_LIST[filePath] = {
upload: upload,
recentSpeeds: [],
initialBytesUploaded: 0,
currentBytesUploaded: 0,
currentAverageSpeed: 0,
lastProgressTimestamp: null,
sumOfRecentSpeeds: 0,
hasStarted: false,
interval: null,
};
upload.start();
});
}
async function createUpload(resourcePath) {
let headResp = await fetchURL(resourcePath, {
method: "POST",
});
if (headResp.status !== 201) {
throw new Error(
`Failed to create an upload: ${headResp.status} ${headResp.statusText}`
);
}
}
function computeRetryDelays(tusSettings) {
if (!tusSettings.retryCount || tusSettings.retryCount < 1) {
// Disable retries altogether
return null;
}
// The tus client expects our retries as an array with computed backoffs
// E.g.: [0, 3000, 5000, 10000, 20000]
const retryDelays = [];
let delay = 0;
for (let i = 0; i < tusSettings.retryCount; i++) {
retryDelays.push(Math.min(delay, RETRY_MAX_DELAY));
delay =
delay === 0 ? RETRY_BASE_DELAY : Math.min(delay * 2, RETRY_MAX_DELAY);
}
return retryDelays;
}
export async function useTus(content) {
return isTusSupported() && content instanceof Blob;
}
function isTusSupported() {
return tus.isSupported === true;
}
function computeETA(state) {
if (state.speedMbyte === 0) {
return Infinity;
}
const totalSize = state.sizes.reduce((acc, size) => acc + size, 0);
const uploadedSize = state.progress.reduce(
(acc, progress) => acc + progress,
0
);
const remainingSize = totalSize - uploadedSize;
const speedBytesPerSecond = state.speedMbyte * 1024 * 1024;
return remainingSize / speedBytesPerSecond;
}
function computeGlobalSpeedAndETA() {
let totalSpeed = 0;
let totalCount = 0;
for (let filePath in CURRENT_UPLOAD_LIST) {
totalSpeed += CURRENT_UPLOAD_LIST[filePath].currentAverageSpeed;
totalCount++;
}
if (totalCount === 0) return { speed: 0, eta: Infinity };
const averageSpeed = totalSpeed / totalCount;
const averageETA = computeETA(store.state.upload, averageSpeed);
return { speed: averageSpeed, eta: averageETA };
}
function calcProgress(filePath) {
let fileData = CURRENT_UPLOAD_LIST[filePath];
let elapsedTime = (Date.now() - fileData.lastProgressTimestamp) / 1000;
let bytesSinceLastUpdate =
fileData.currentBytesUploaded - fileData.initialBytesUploaded;
let currentSpeed = bytesSinceLastUpdate / MB_DIVISOR / elapsedTime;
if (fileData.recentSpeeds.length >= RECENT_SPEEDS_LIMIT) {
fileData.sumOfRecentSpeeds -= fileData.recentSpeeds.shift();
}
fileData.recentSpeeds.push(currentSpeed);
fileData.sumOfRecentSpeeds += currentSpeed;
let avgRecentSpeed =
fileData.sumOfRecentSpeeds / fileData.recentSpeeds.length;
fileData.currentAverageSpeed =
ALPHA * avgRecentSpeed + ONE_MINUS_ALPHA * fileData.currentAverageSpeed;
const { speed, eta } = computeGlobalSpeedAndETA();
store.commit("setUploadSpeed", speed);
store.commit("setETA", eta);
fileData.initialBytesUploaded = fileData.currentBytesUploaded;
fileData.lastProgressTimestamp = Date.now();
}
export function abortAllUploads() {
for (let filePath in CURRENT_UPLOAD_LIST) {
if (CURRENT_UPLOAD_LIST[filePath].interval) {
clearInterval(CURRENT_UPLOAD_LIST[filePath].interval);
}
if (CURRENT_UPLOAD_LIST[filePath].upload) {
CURRENT_UPLOAD_LIST[filePath].upload.abort(true);
}
delete CURRENT_UPLOAD_LIST[filePath];
}
}

View File

@@ -20,13 +20,11 @@ export async function create(user) {
if (res.status === 201) {
return res.headers.get("Location");
} else {
throw new Error(res.status);
}
}
export async function update(user, which = ["all"]) {
const res = await fetchURL(`/api/users/${user.id}`, {
await fetchURL(`/api/users/${user.id}`, {
method: "PUT",
body: JSON.stringify({
what: "user",
@@ -34,18 +32,10 @@ export async function update(user, which = ["all"]) {
data: user,
}),
});
if (res.status !== 200) {
throw new Error(res.status);
}
}
export async function remove(id) {
const res = await fetchURL(`/api/users/${id}`, {
await fetchURL(`/api/users/${id}`, {
method: "DELETE",
});
if (res.status !== 200) {
throw new Error(res.status);
}
}

View File

@@ -1,13 +1,13 @@
import store from "@/store";
import { renew } from "@/utils/auth";
import { renew, logout } from "@/utils/auth";
import { baseURL } from "@/utils/constants";
import { encodePath } from "@/utils/url";
export async function fetchURL(url, opts) {
export async function fetchURL(url, opts, auth = true) {
opts = opts || {};
opts.headers = opts.headers || {};
let { headers, ...rest } = opts;
let res;
try {
res = await fetch(`${baseURL}${url}`, {
@@ -17,14 +17,28 @@ export async function fetchURL(url, opts) {
},
...rest,
});
} catch (error) {
return { status: 0 };
} catch {
const error = new Error("000 No connection");
error.status = 0;
throw error;
}
if (res.headers.get("X-Renew-Token") === "true") {
if (auth && res.headers.get("X-Renew-Token") === "true") {
await renew(store.state.jwt);
}
if (res.status < 200 || res.status > 299) {
const error = new Error(await res.text());
error.status = res.status;
if (auth && res.status == 401) {
logout();
}
throw error;
}
return res;
}
@@ -45,3 +59,22 @@ export function removePrefix(url) {
if (url[0] !== "/") url = "/" + url;
return url;
}
export function createURL(endpoint, params = {}, auth = true) {
let prefix = baseURL;
if (!prefix.endsWith("/")) {
prefix = prefix + "/";
}
const url = new URL(prefix + encodePath(endpoint), origin);
const searchParams = {
...(auth && { auth: store.state.jwt }),
...params,
};
for (const key in searchParams) {
url.searchParams.set(key, searchParams[key]);
}
return url.toString();
}

View File

@@ -90,10 +90,10 @@ export default {
};
},
watch: {
show(val, old) {
this.active = val === "search";
currentPrompt(val, old) {
this.active = val?.prompt === "search";
if (old === "search" && !this.active) {
if (old?.prompt === "search" && !this.active) {
if (this.reload) {
this.setReload(true);
}
@@ -116,8 +116,8 @@ export default {
},
},
computed: {
...mapState(["user", "show"]),
...mapGetters(["isListing"]),
...mapState(["user"]),
...mapGetters(["isListing", "currentPrompt"]),
boxes() {
return boxes;
},

View File

@@ -1,37 +1,54 @@
<template>
<div
@click="focus"
class="shell"
ref="scrollable"
:class="{ ['shell--hidden']: !showShell }"
:style="{ height: `${this.shellHeight}em`, direction: 'ltr' }"
>
<div v-for="(c, index) in content" :key="index" class="shell__result">
<div class="shell__prompt">
<i class="material-icons">chevron_right</i>
<div
@pointerdown="startDrag()"
@pointerup="stopDrag()"
class="shell__divider"
:style="this.shellDrag ? { background: `${checkTheme()}` } : ''"
></div>
<div @click="focus" class="shell__content" ref="scrollable">
<div v-for="(c, index) in content" :key="index" class="shell__result">
<div class="shell__prompt">
<i class="material-icons">chevron_right</i>
</div>
<pre class="shell__text">{{ c.text }}</pre>
</div>
<pre class="shell__text">{{ c.text }}</pre>
</div>
<div class="shell__result" :class="{ 'shell__result--hidden': !canInput }">
<div class="shell__prompt">
<i class="material-icons">chevron_right</i>
<div
class="shell__result"
:class="{ 'shell__result--hidden': !canInput }"
>
<div class="shell__prompt">
<i class="material-icons">chevron_right</i>
</div>
<pre
tabindex="0"
ref="input"
class="shell__text"
contenteditable="true"
@keydown.prevent.38="historyUp"
@keydown.prevent.40="historyDown"
@keypress.prevent.enter="submit"
/>
</div>
<pre
tabindex="0"
ref="input"
class="shell__text"
contenteditable="true"
@keydown.prevent.38="historyUp"
@keydown.prevent.40="historyDown"
@keypress.prevent.enter="submit"
/>
</div>
<div
@pointerup="stopDrag()"
class="shell__overlay"
v-show="this.shellDrag"
></div>
</div>
</template>
<script>
import { mapMutations, mapState, mapGetters } from "vuex";
import { commands } from "@/api";
import { throttle } from "lodash";
import { theme } from "@/utils/constants";
export default {
name: "shell",
@@ -51,9 +68,55 @@ export default {
history: [],
historyPos: 0,
canInput: true,
shellDrag: false,
shellHeight: 25,
fontsize: parseFloat(getComputedStyle(document.documentElement).fontSize),
}),
mounted() {
window.addEventListener("resize", this.resize);
},
beforeDestroy() {
window.removeEventListener("resize", this.resize);
},
methods: {
...mapMutations(["toggleShell"]),
checkTheme() {
if (theme == "dark") {
return "rgba(255, 255, 255, 0.4)";
}
return "rgba(127, 127, 127, 0.4)";
},
startDrag() {
document.addEventListener("pointermove", this.handleDrag);
this.shellDrag = true;
},
stopDrag() {
document.removeEventListener("pointermove", this.handleDrag);
this.shellDrag = false;
},
handleDrag: throttle(function (event) {
const top = window.innerHeight / this.fontsize - 4;
const userPos = (window.innerHeight - event.clientY) / this.fontsize;
const bottom =
2.25 +
document.querySelector(".shell__divider").offsetHeight / this.fontsize;
if (userPos <= top && userPos >= bottom) {
this.shellHeight = userPos.toFixed(2);
}
}, 32),
resize: throttle(function () {
const top = window.innerHeight / this.fontsize - 4;
const bottom =
2.25 +
document.querySelector(".shell__divider").offsetHeight / this.fontsize;
if (this.shellHeight > top) {
this.shellHeight = top;
} else if (this.shellHeight < bottom) {
this.shellHeight = bottom;
}
}, 32),
scroll: function () {
this.$refs.scrollable.scrollTop = this.$refs.scrollable.scrollHeight;
},
@@ -113,7 +176,10 @@ export default {
this.scroll();
},
() => {
results.text = results.text.trimEnd();
results.text = results.text
// eslint-disable-next-line no-control-regex
.replace(/\u001b\[[0-9;]+m/g, "") // Filter ANSI color for now
.trimEnd();
this.canInput = true;
this.$refs.input.focus();
this.scroll();

View File

@@ -1,15 +1,15 @@
<template>
<nav :class="{ active }">
<template v-if="isLogged">
<router-link
<button
class="action"
to="/files/"
@click="toRoot"
:aria-label="$t('sidebar.myFiles')"
:title="$t('sidebar.myFiles')"
>
<i class="material-icons">folder</i>
<span>{{ $t("sidebar.myFiles") }}</span>
</router-link>
</button>
<div v-if="user.perm.create">
<button
@@ -34,18 +34,18 @@
</div>
<div>
<router-link
<button
class="action"
to="/settings"
@click="toSettings"
:aria-label="$t('sidebar.settings')"
:title="$t('sidebar.settings')"
>
<i class="material-icons">settings_applications</i>
<span>{{ $t("sidebar.settings") }}</span>
</router-link>
</button>
<button
v-if="authMethod == 'json'"
v-if="canLogout"
@click="logout"
class="action"
id="logout"
@@ -80,6 +80,18 @@
</router-link>
</template>
<div
class="credits"
v-if="
$router.currentRoute.path.includes('/files/') && !disableUsedPercentage
"
style="width: 90%; margin: 2em 2.5em 3em 2.5em"
>
<progress-bar :val="usage.usedPercentage" size="small"></progress-bar>
<br />
{{ usage.used }} of {{ usage.total }} used
</div>
<p class="credits">
<span>
<span v-if="disableExternal">File Browser</span>
@@ -92,9 +104,9 @@
>
<span> {{ version }}</span>
</span>
<span
><a @click="help">{{ $t("sidebar.help") }}</a></span
>
<span>
<a @click="help">{{ $t("sidebar.help") }}</a>
</span>
</p>
</nav>
</template>
@@ -106,25 +118,68 @@ import {
version,
signup,
disableExternal,
disableUsedPercentage,
noAuth,
authMethod,
loginPage,
} from "@/utils/constants";
import { files as api } from "@/api";
import ProgressBar from "vue-simple-progress";
import prettyBytes from "pretty-bytes";
export default {
name: "sidebar",
components: {
ProgressBar,
},
computed: {
...mapState(["user"]),
...mapGetters(["isLogged"]),
...mapGetters(["isLogged", "currentPrompt"]),
active() {
return this.$store.state.show === "sidebar";
return this.currentPrompt?.prompt === "sidebar";
},
signup: () => signup,
version: () => version,
disableExternal: () => disableExternal,
noAuth: () => noAuth,
authMethod: () => authMethod,
disableUsedPercentage: () => disableUsedPercentage,
canLogout: () => !noAuth && loginPage,
},
asyncComputed: {
usage: {
async get() {
let path = this.$route.path.endsWith("/")
? this.$route.path
: this.$route.path + "/";
let usageStats = { used: 0, total: 0, usedPercentage: 0 };
if (this.disableUsedPercentage) {
return usageStats;
}
try {
let usage = await api.usage(path);
usageStats = {
used: prettyBytes(usage.used, { binary: true }),
total: prettyBytes(usage.total, { binary: true }),
usedPercentage: Math.round((usage.used / usage.total) * 100),
};
} catch (error) {
this.$showError(error);
}
return usageStats;
},
default: { used: "0 B", total: "0 B", usedPercentage: 0 },
shouldUpdate() {
return this.$router.currentRoute.path.includes("/files/");
},
},
},
methods: {
toRoot() {
this.$router.push({ path: "/files/" }, () => {});
this.$store.commit("closeHovers");
},
toSettings() {
this.$router.push({ path: "/settings" }, () => {});
this.$store.commit("closeHovers");
},
help() {
this.$store.commit("showHover", "help");
},

View File

@@ -10,12 +10,7 @@
@mouseup="mouseUp"
@wheel="wheelMove"
>
<img
src=""
class="image-ex-img image-ex-img-center"
ref="imgex"
@load="onLoad"
/>
<img class="image-ex-img image-ex-img-center" ref="imgex" @load="onLoad" />
</div>
</template>
<script>
@@ -44,6 +39,7 @@ export default {
lastX: null,
lastY: null,
inDrag: false,
touches: 0,
lastTouchDistance: 0,
moveDisabled: false,
disabledTimer: null,

View File

@@ -9,6 +9,7 @@
@drop="drop"
@click="itemClick"
:data-dir="isDir"
:data-type="type"
:aria-label="name"
:aria-selected="isSelected"
>
@@ -17,7 +18,7 @@
v-if="readOnly == undefined && type === 'image' && isThumbsEnabled"
v-lazy="thumbnailUrl"
/>
<i v-else class="material-icons">{{ icon }}</i>
<i v-else class="material-icons"></i>
</div>
<div>
@@ -34,10 +35,10 @@
</template>
<script>
import { baseURL, enableThumbs } from "@/utils/constants";
import { enableThumbs } from "@/utils/constants";
import { mapMutations, mapGetters, mapState } from "vuex";
import filesize from "filesize";
import moment from "moment";
import { filesize } from "@/utils";
import moment from "moment/min/moment-with-locales";
import { files as api } from "@/api";
import * as upload from "@/utils/upload";
@@ -57,6 +58,7 @@ export default {
"modified",
"index",
"readOnly",
"path",
],
computed: {
...mapState(["user", "selected", "req", "jwt"]),
@@ -67,13 +69,6 @@ export default {
isSelected() {
return this.selected.indexOf(this.index) !== -1;
},
icon() {
if (this.isDir) return "folder";
if (this.type === "image") return "insert_photo";
if (this.type === "audio") return "volume_up";
if (this.type === "video") return "movie";
return "insert_drive_file";
},
isDraggable() {
return this.readOnly == undefined && this.user.perm.rename;
},
@@ -89,12 +84,12 @@ export default {
return true;
},
thumbnailUrl() {
const path = this.url.replace(/^\/files\//, "");
const file = {
path: this.path,
modified: this.modified,
};
// reload the image when the file is replaced
const key = Date.parse(this.modified);
return `${baseURL}/api/preview/thumb/${path}?k=${key}&inline=true`;
return api.getPreviewURL(file, "thumb");
},
isThumbsEnabled() {
return enableThumbs;
@@ -103,9 +98,12 @@ export default {
methods: {
...mapMutations(["addSelected", "removeSelected", "resetSelected"]),
humanSize: function () {
return filesize(this.size);
return this.type == "invalid_link" ? "invalid link" : filesize(this.size);
},
humanTime: function () {
if (this.readOnly == undefined && this.user.dateFormat) {
return moment(this.modified).format("L LT");
}
return moment(this.modified).fromNow();
},
dragStart: function () {
@@ -193,7 +191,12 @@ export default {
action(overwrite, rename);
},
itemClick: function (event) {
if (this.singleClick && !this.$store.state.multiple) this.open();
if (
!(event.ctrlKey || event.metaKey) &&
this.singleClick &&
!this.$store.state.multiple
)
this.open();
else this.click(event);
},
click: function (event) {

View File

@@ -11,7 +11,7 @@
<slot />
<div id="dropdown" :class="{ active: this.$store.state.show === 'more' }">
<div id="dropdown" :class="{ active: this.currentPromptName === 'more' }">
<slot name="actions" />
</div>
@@ -25,7 +25,7 @@
<div
class="overlay"
v-show="this.$store.state.show == 'more'"
v-show="this.currentPromptName == 'more'"
@click="$store.commit('closeHovers')"
/>
</header>
@@ -34,7 +34,8 @@
<script>
import { logoURL } from "@/utils/constants";
import Action from "@/components/header/Action";
import Action from "@/components/header/Action.vue";
import { mapGetters } from "vuex";
export default {
name: "header-bar",
@@ -52,6 +53,9 @@ export default {
this.$store.commit("showHover", "sidebar");
},
},
computed: {
...mapGetters(["currentPromptName"]),
},
};
</script>

View File

@@ -6,33 +6,50 @@
<div class="card-content">
<p>{{ $t("prompts.copyMessage") }}</p>
<file-list @update:selected="(val) => (dest = val)"></file-list>
<file-list ref="fileList" @update:selected="(val) => (dest = val)">
</file-list>
</div>
<div class="card-action">
<button
class="button button--flat button--grey"
@click="$store.commit('closeHovers')"
:aria-label="$t('buttons.cancel')"
:title="$t('buttons.cancel')"
>
{{ $t("buttons.cancel") }}
</button>
<button
class="button button--flat"
@click="copy"
:aria-label="$t('buttons.copy')"
:title="$t('buttons.copy')"
>
{{ $t("buttons.copy") }}
</button>
<div
class="card-action"
style="display: flex; align-items: center; justify-content: space-between"
>
<template v-if="user.perm.create">
<button
class="button button--flat"
@click="$refs.fileList.createDir()"
:aria-label="$t('sidebar.newFolder')"
:title="$t('sidebar.newFolder')"
style="justify-self: left"
>
<span>{{ $t("sidebar.newFolder") }}</span>
</button>
</template>
<div>
<button
class="button button--flat button--grey"
@click="$store.commit('closeHovers')"
:aria-label="$t('buttons.cancel')"
:title="$t('buttons.cancel')"
>
{{ $t("buttons.cancel") }}
</button>
<button
class="button button--flat"
@click="copy"
:aria-label="$t('buttons.copy')"
:title="$t('buttons.copy')"
>
{{ $t("buttons.copy") }}
</button>
</div>
</div>
</div>
</template>
<script>
import { mapState } from "vuex";
import FileList from "./FileList";
import FileList from "./FileList.vue";
import { files as api } from "@/api";
import buttons from "@/utils/buttons";
import * as upload from "@/utils/upload";
@@ -46,7 +63,7 @@ export default {
dest: null,
};
},
computed: mapState(["req", "selected"]),
computed: mapState(["req", "selected", "user"]),
methods: {
copy: async function (event) {
event.preventDefault();

View File

@@ -1,7 +1,7 @@
<template>
<div class="card floating">
<div class="card-content">
<p v-if="req.kind !== 'listing'">
<p v-if="!this.isListing || selectedCount === 1">
{{ $t("prompts.deleteMessageSingle") }}
</p>
<p v-else>
@@ -37,20 +37,21 @@ import buttons from "@/utils/buttons";
export default {
name: "delete",
computed: {
...mapGetters(["isListing", "selectedCount"]),
...mapState(["req", "selected", "showConfirm"]),
...mapGetters(["isListing", "selectedCount", "currentPrompt"]),
...mapState(["req", "selected"]),
},
methods: {
...mapMutations(["closeHovers"]),
submit: async function () {
buttons.loading("delete");
window.sessionStorage.setItem("modified", "true");
try {
if (!this.isListing) {
await api.remove(this.$route.path);
buttons.success("delete");
this.showConfirm();
this.currentPrompt?.confirm();
this.closeHovers();
return;
}

View File

@@ -0,0 +1,45 @@
<template>
<div class="card floating">
<div class="card-content">
<p>
{{ $t("prompts.discardEditorChanges") }}
</p>
</div>
<div class="card-action">
<button
@click="$store.commit('closeHovers')"
class="button button--flat button--grey"
:aria-label="$t('buttons.cancel')"
:title="$t('buttons.cancel')"
>
{{ $t("buttons.cancel") }}
</button>
<button
@click="submit"
class="button button--flat button--red"
:aria-label="$t('buttons.discardChanges')"
:title="$t('buttons.discardChanges')"
>
{{ $t("buttons.discardChanges") }}
</button>
</div>
</div>
</template>
<script>
import { mapMutations } from "vuex";
import url from "@/utils/url";
export default {
name: "discardEditorChanges",
methods: {
...mapMutations(["closeHovers"]),
submit: async function () {
this.$store.commit("updateRequest", {});
let uri = url.removeLastDir(this.$route.path) + "/";
this.$router.push({ path: uri });
},
},
};
</script>

View File

@@ -11,7 +11,7 @@
v-for="(ext, format) in formats"
:key="format"
class="button button--block"
@click="showConfirm(format)"
@click="currentPrompt.confirm(format)"
v-focus
>
{{ ext }}
@@ -21,7 +21,7 @@
</template>
<script>
import { mapState } from "vuex";
import { mapGetters } from "vuex";
export default {
name: "download",
@@ -38,6 +38,8 @@ export default {
},
};
},
computed: mapState(["showConfirm"]),
computed: {
...mapGetters(["currentPrompt"]),
},
};
</script>

View File

@@ -133,6 +133,17 @@ export default {
this.selected = event.currentTarget.dataset.url;
this.$emit("update:selected", this.selected);
},
createDir: async function () {
this.$store.commit("showHover", {
prompt: "newDir",
action: null,
confirm: null,
props: {
redirect: false,
base: this.current === this.$route.path ? null : this.current,
},
});
},
},
};
</script>

View File

@@ -12,10 +12,17 @@
<p class="break-word" v-if="selected.length < 2">
<strong>{{ $t("prompts.displayName") }}</strong> {{ name }}
</p>
<p v-if="!dir || selected.length > 1">
<strong>{{ $t("prompts.size") }}:</strong>
<span id="content_length"></span> {{ humanSize }}
</p>
<div v-if="resolution">
<strong>{{ $t("prompts.resolution") }}:</strong>
{{ resolution.width }} x {{ resolution.height }}
</div>
<p v-if="selected.length < 2" :title="modTime">
<strong>{{ $t("prompts.lastModified") }}:</strong> {{ humanTime }}
</p>
@@ -81,8 +88,8 @@
<script>
import { mapState, mapGetters } from "vuex";
import filesize from "filesize";
import moment from "moment";
import { filesize } from "@/utils";
import moment from "moment/min/moment-with-locales";
import { files as api } from "@/api";
export default {
@@ -126,6 +133,17 @@ export default {
: this.req.items[this.selected[0]].isDir)
);
},
resolution: function () {
if (this.selectedCount === 1) {
const selectedItem = this.req.items[this.selected[0]];
if (selectedItem && selectedItem.type === "image") {
return selectedItem.resolution;
}
} else if (this.req && this.req.type === "image") {
return this.req.resolution;
}
return null;
},
},
methods: {
checksum: async function (event, algo) {
@@ -142,7 +160,7 @@ export default {
try {
const hash = await api.checksum(link, algo);
// eslint-disable-next-line
event.target.innerHTML = hash
event.target.innerHTML = hash;
} catch (e) {
this.$showError(e);
}

View File

@@ -5,34 +5,51 @@
</div>
<div class="card-content">
<file-list @update:selected="(val) => (dest = val)"></file-list>
<file-list ref="fileList" @update:selected="(val) => (dest = val)">
</file-list>
</div>
<div class="card-action">
<button
class="button button--flat button--grey"
@click="$store.commit('closeHovers')"
:aria-label="$t('buttons.cancel')"
:title="$t('buttons.cancel')"
>
{{ $t("buttons.cancel") }}
</button>
<button
class="button button--flat"
@click="move"
:disabled="$route.path === dest"
:aria-label="$t('buttons.move')"
:title="$t('buttons.move')"
>
{{ $t("buttons.move") }}
</button>
<div
class="card-action"
style="display: flex; align-items: center; justify-content: space-between"
>
<template v-if="user.perm.create">
<button
class="button button--flat"
@click="$refs.fileList.createDir()"
:aria-label="$t('sidebar.newFolder')"
:title="$t('sidebar.newFolder')"
style="justify-self: left"
>
<span>{{ $t("sidebar.newFolder") }}</span>
</button>
</template>
<div>
<button
class="button button--flat button--grey"
@click="$store.commit('closeHovers')"
:aria-label="$t('buttons.cancel')"
:title="$t('buttons.cancel')"
>
{{ $t("buttons.cancel") }}
</button>
<button
class="button button--flat"
@click="move"
:disabled="$route.path === dest"
:aria-label="$t('buttons.move')"
:title="$t('buttons.move')"
>
{{ $t("buttons.move") }}
</button>
</div>
</div>
</div>
</template>
<script>
import { mapState } from "vuex";
import FileList from "./FileList";
import FileList from "./FileList.vue";
import { files as api } from "@/api";
import buttons from "@/utils/buttons";
import * as upload from "@/utils/upload";
@@ -46,7 +63,7 @@ export default {
dest: null,
};
},
computed: mapState(["req", "selected"]),
computed: mapState(["req", "selected", "user"]),
methods: {
move: async function (event) {
event.preventDefault();

View File

@@ -43,6 +43,16 @@ import url from "@/utils/url";
export default {
name: "new-dir",
props: {
redirect: {
type: Boolean,
default: true,
},
base: {
type: [String, null],
default: null,
},
},
data: function () {
return {
name: "",
@@ -57,7 +67,11 @@ export default {
if (this.new === "") return;
// Build the path of the new directory.
let uri = this.isFiles ? this.$route.path + "/" : "/";
let uri;
if (this.base) uri = this.base;
else if (this.isFiles) uri = this.$route.path + "/";
else uri = "/";
if (!this.isListing) {
uri = url.removeLastDir(uri) + "/";
@@ -65,10 +79,14 @@ export default {
uri += encodeURIComponent(this.name) + "/";
uri = uri.replace("//", "/");
try {
await api.post(uri);
this.$router.push({ path: uri });
if (this.redirect) {
this.$router.push({ path: uri });
} else if (!this.base) {
const res = await api.fetch(url.removeLastDir(uri) + "/");
this.$store.commit("updateRequest", res);
}
} catch (e) {
this.$showError(e);
}

View File

@@ -1,26 +1,34 @@
<template>
<div>
<component ref="currentComponent" :is="currentComponent"></component>
<component
v-if="showOverlay"
:ref="currentPromptName"
:is="currentPromptName"
v-bind="currentPrompt.props"
>
</component>
<div v-show="showOverlay" @click="resetPrompts" class="overlay"></div>
</div>
</template>
<script>
import Help from "./Help";
import Info from "./Info";
import Delete from "./Delete";
import Rename from "./Rename";
import Download from "./Download";
import Move from "./Move";
import Copy from "./Copy";
import NewFile from "./NewFile";
import NewDir from "./NewDir";
import Replace from "./Replace";
import ReplaceRename from "./ReplaceRename";
import Share from "./Share";
import Upload from "./Upload";
import ShareDelete from "./ShareDelete";
import { mapState } from "vuex";
import Help from "./Help.vue";
import Info from "./Info.vue";
import Delete from "./Delete.vue";
import Rename from "./Rename.vue";
import Download from "./Download.vue";
import Move from "./Move.vue";
import Copy from "./Copy.vue";
import NewFile from "./NewFile.vue";
import NewDir from "./NewDir.vue";
import Replace from "./Replace.vue";
import ReplaceRename from "./ReplaceRename.vue";
import Share from "./Share.vue";
import Upload from "./Upload.vue";
import ShareDelete from "./ShareDelete.vue";
import Sidebar from "../Sidebar.vue";
import DiscardEditorChanges from "./DiscardEditorChanges.vue";
import { mapGetters, mapState } from "vuex";
import buttons from "@/utils/buttons";
export default {
@@ -40,6 +48,8 @@ export default {
ReplaceRename,
Upload,
ShareDelete,
Sidebar,
DiscardEditorChanges,
},
data: function () {
return {
@@ -52,19 +62,18 @@ export default {
},
created() {
window.addEventListener("keydown", (event) => {
if (this.show == null) return;
if (this.currentPrompt == null) return;
let prompt = this.$refs.currentComponent;
const promptName = this.currentPrompt.prompt;
const prompt = this.$refs[promptName];
// Esc!
if (event.keyCode === 27) {
if (event.code === "Escape") {
event.stopImmediatePropagation();
this.$store.commit("closeHovers");
}
// Enter
if (event.keyCode == 13) {
switch (this.show) {
if (event.code === "Enter") {
switch (promptName) {
case "delete":
prompt.submit();
break;
@@ -82,31 +91,13 @@ export default {
});
},
computed: {
...mapState(["show", "plugins"]),
currentComponent: function () {
const matched =
[
"info",
"help",
"delete",
"rename",
"move",
"copy",
"newFile",
"newDir",
"download",
"replace",
"replace-rename",
"share",
"upload",
"share-delete",
].indexOf(this.show) >= 0;
return (matched && this.show) || null;
},
...mapState(["plugins"]),
...mapGetters(["currentPrompt", "currentPromptName"]),
showOverlay: function () {
return (
this.show !== null && this.show !== "search" && this.show !== "more"
this.currentPrompt !== null &&
this.currentPrompt.prompt !== "search" &&
this.currentPrompt.prompt !== "more"
);
},
},

View File

@@ -88,6 +88,7 @@ export default {
newLink =
url.removeLastDir(oldLink) + "/" + encodeURIComponent(this.name);
window.sessionStorage.setItem("modified", "true");
try {
await api.move([{ from: oldLink, to: newLink }]);
if (!this.isListing) {

View File

@@ -17,9 +17,17 @@
>
{{ $t("buttons.cancel") }}
</button>
<button
class="button button--flat button--blue"
@click="currentPrompt.action"
:aria-label="$t('buttons.continue')"
:title="$t('buttons.continue')"
>
{{ $t("buttons.continue") }}
</button>
<button
class="button button--flat button--red"
@click="showConfirm"
@click="currentPrompt.confirm"
:aria-label="$t('buttons.replace')"
:title="$t('buttons.replace')"
>
@@ -30,10 +38,10 @@
</template>
<script>
import { mapState } from "vuex";
import { mapGetters } from "vuex";
export default {
name: "replace",
computed: mapState(["showConfirm"]),
computed: mapGetters(["currentPrompt"]),
};
</script>

View File

@@ -19,7 +19,7 @@
</button>
<button
class="button button--flat button--blue"
@click="(event) => showConfirm(event, 'rename')"
@click="(event) => currentPrompt.confirm(event, 'rename')"
:aria-label="$t('buttons.rename')"
:title="$t('buttons.rename')"
>
@@ -27,7 +27,7 @@
</button>
<button
class="button button--flat button--red"
@click="(event) => showConfirm(event, 'overwrite')"
@click="(event) => currentPrompt.confirm(event, 'overwrite')"
:aria-label="$t('buttons.replace')"
:title="$t('buttons.replace')"
>
@@ -38,10 +38,10 @@
</template>
<script>
import { mapState } from "vuex";
import { mapGetters } from "vuex";
export default {
name: "replace-rename",
computed: mapState(["showConfirm"]),
computed: mapGetters(["currentPrompt"]),
};
</script>

View File

@@ -25,13 +25,23 @@
<td class="small">
<button
class="action copy-clipboard"
:data-clipboard-text="buildLink(link.hash)"
:data-clipboard-text="buildLink(link)"
:aria-label="$t('buttons.copyToClipboard')"
:title="$t('buttons.copyToClipboard')"
>
<i class="material-icons">content_paste</i>
</button>
</td>
<td class="small" v-if="hasDownloadLink()">
<button
class="action copy-clipboard"
:data-clipboard-text="buildDownloadLink(link)"
:aria-label="$t('buttons.copyDownloadLinkToClipboard')"
:title="$t('buttons.copyDownloadLinkToClipboard')"
>
<i class="material-icons">content_paste_go</i>
</button>
</td>
<td class="small">
<button
class="action"
@@ -117,9 +127,8 @@
<script>
import { mapState, mapGetters } from "vuex";
import { share as api } from "@/api";
import { baseURL } from "@/utils/constants";
import moment from "moment";
import { share as api, pub as pub_api } from "@/api";
import moment from "moment/min/moment-with-locales";
import Clipboard from "clipboard";
export default {
@@ -213,8 +222,16 @@ export default {
humanTime(time) {
return moment(time * 1000).fromNow();
},
buildLink(hash) {
return `${window.location.origin}${baseURL}/share/${hash}`;
buildLink(share) {
return api.getShareURL(share);
},
hasDownloadLink() {
return (
this.selected.length === 1 && !this.req.items[this.selected[0]].isDir
);
},
buildDownloadLink(share) {
return pub_api.getDownloadURL(share);
},
sort() {
this.links = this.links.sort((a, b) => {

View File

@@ -25,16 +25,16 @@
</template>
<script>
import { mapState } from "vuex";
import { mapGetters } from "vuex";
export default {
name: "share-delete",
computed: {
...mapState(["showConfirm"]),
...mapGetters(["currentPrompt"]),
},
methods: {
submit: function () {
this.showConfirm();
this.currentPrompt?.confirm();
},
},
};

View File

@@ -11,11 +11,11 @@
<div class="card-action full">
<div @click="uploadFile" class="action">
<i class="material-icons">insert_drive_file</i>
<div class="title">File</div>
<div class="title">{{ $t("buttons.file") }}</div>
</div>
<div @click="uploadFolder" class="action">
<i class="material-icons">folder</i>
<div class="title">Folder</div>
<div class="title">{{ $t("buttons.folder") }}</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,106 @@
<template>
<div
v-if="filesInUploadCount > 0"
class="upload-files"
v-bind:class="{ closed: !open }"
>
<div class="card floating">
<div class="card-title">
<h2>{{ $t("prompts.uploadFiles", { files: filesInUploadCount }) }}</h2>
<div class="upload-info">
<div class="upload-speed">{{ uploadSpeed.toFixed(2) }} MB/s</div>
<div class="upload-eta">{{ formattedETA }} remaining</div>
</div>
<button
class="action"
@click="abortAll"
aria-label="Abort upload"
title="Abort upload"
>
<i class="material-icons">{{ "cancel" }}</i>
</button>
<button
class="action"
@click="toggle"
aria-label="Toggle file upload list"
title="Toggle file upload list"
>
<i class="material-icons">{{
open ? "keyboard_arrow_down" : "keyboard_arrow_up"
}}</i>
</button>
</div>
<div class="card-content file-icons">
<div
class="file"
v-for="file in filesInUpload"
:key="file.id"
:data-dir="file.isDir"
:data-type="file.type"
:aria-label="file.name"
>
<div class="file-name">
<i class="material-icons"></i> {{ file.name }}
</div>
<div class="file-progress">
<div v-bind:style="{ width: file.progress + '%' }"></div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { mapGetters, mapMutations } from "vuex";
import { abortAllUploads } from "@/api/tus";
import buttons from "@/utils/buttons";
export default {
name: "uploadFiles",
data: function () {
return {
open: false,
};
},
computed: {
...mapGetters([
"filesInUpload",
"filesInUploadCount",
"uploadSpeed",
"eta",
]),
...mapMutations(["resetUpload"]),
formattedETA() {
if (!this.eta || this.eta === Infinity) {
return "--:--:--";
}
let totalSeconds = this.eta;
const hours = Math.floor(totalSeconds / 3600);
totalSeconds %= 3600;
const minutes = Math.floor(totalSeconds / 60);
const seconds = Math.round(totalSeconds % 60);
return `${hours.toString().padStart(2, "0")}:${minutes
.toString()
.padStart(2, "0")}:${seconds.toString().padStart(2, "0")}`;
},
},
methods: {
toggle: function () {
this.open = !this.open;
},
abortAll() {
if (confirm(this.$t("upload.abortUpload"))) {
abortAllUploads();
buttons.done("upload");
this.open = false;
this.$store.commit("resetUpload");
this.$store.commit("setReload", true);
}
},
},
};
</script>

View File

@@ -13,8 +13,11 @@ export default {
data() {
let dataObj = {
locales: {
he: "he",
hu: "hu",
ar: "ar",
de: "de",
el: "el",
en: "en",
es: "es",
fr: "fr",
@@ -28,7 +31,10 @@ export default {
pt: "pt",
ro: "ro",
ru: "ru",
sk: "sk",
"sv-se": "svSE",
tr: "tr",
ua: "ua",
"zh-cn": "zhCN",
"zh-tw": "zhTW",
},

View File

@@ -24,12 +24,18 @@
<p>
<label for="scope">{{ $t("settings.scope") }}</label>
<input
:disabled="createUserDirData"
:placeholder="scopePlaceholder"
class="input input--block"
type="text"
v-model="user.scope"
id="scope"
/>
</p>
<p class="small" v-if="displayHomeDirectoryCheckbox">
<input type="checkbox" v-model="createUserDirData" />
{{ $t("settings.createUserHomeDirectory") }}
</p>
<p>
<label for="locale">{{ $t("settings.language") }}</label>
@@ -61,25 +67,43 @@
</template>
<script>
import Languages from "./Languages";
import Rules from "./Rules";
import Permissions from "./Permissions";
import Commands from "./Commands";
import Languages from "./Languages.vue";
import Rules from "./Rules.vue";
import Permissions from "./Permissions.vue";
import Commands from "./Commands.vue";
import { enableExec } from "@/utils/constants";
export default {
name: "user",
data: () => {
return {
createUserDirData: false,
originalUserScope: "/",
};
},
components: {
Permissions,
Languages,
Rules,
Commands,
},
props: ["user", "isNew", "isDefault"],
props: ["user", "createUserDir", "isNew", "isDefault"],
created() {
this.originalUserScope = this.user.scope;
this.createUserDirData = this.createUserDir;
},
computed: {
passwordPlaceholder() {
return this.isNew ? "" : this.$t("settings.avoidChanges");
},
scopePlaceholder() {
return this.createUserDir
? this.$t("settings.userScopeGenerationPlaceholder")
: "";
},
displayHomeDirectoryCheckbox() {
return this.isNew && this.createUserDir;
},
isExecEnabled: () => enableExec,
},
watch: {
@@ -87,6 +111,9 @@ export default {
if (!this.user.perm.admin) return;
this.user.lockPassword = false;
},
createUserDirData() {
this.user.scope = this.createUserDirData ? "" : this.originalUserScope;
},
},
};
</script>

View File

@@ -2,18 +2,50 @@
position: fixed;
bottom: 0;
left: 0;
height: 25em;
max-height: calc(100% - 4em);
background: white;
color: #212121;
z-index: 9999;
z-index: 9997;
width: 100%;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
transition: .2s ease transform;
}
.shell__divider {
position: relative;
height: 8px;
z-index: 9999;
background: rgba(127, 127, 127, 0.1);
transition: 0.2s ease background;
cursor: ns-resize;
touch-action: none;
user-select: none;
}
.shell__divider:hover {
background: rgba(127, 127, 127, 0.4);
}
.shell__content {
height: 100%;
font-family: monospace;
overflow: auto;
font-size: 1rem;
cursor: text;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
transition: .2s ease transform;
}
.shell__overlay {
position: fixed;
width: 100%;
height: 100%;
top: 0px;
left: 0px;
z-index: 9998;
background-color: rgba(0, 0, 0, 0.05);
}
body.rtl .shell-content {
direction: ltr;
}
.shell__result {

View File

@@ -4,4 +4,11 @@
--red: #F44336;
--dark-red: #D32F2F;
--moon-grey: #f2f2f2;
--icon-red: #da4453;
--icon-orange: #f47750;
--icon-yellow: #fdbc4b;
--icon-green: #2ecc71;
--icon-blue: #1d99f3;
--icon-violet: #9b59b6;
}

View File

@@ -1,10 +1,14 @@
body {
font-family: 'Roboto', sans-serif;
font-family: "Roboto", sans-serif;
padding-top: 4em;
background-color: #fafafa;
color: #333333;
}
body.rtl {
direction: rtl;
}
* {
box-sizing: border-box;
}
@@ -13,7 +17,7 @@ body {
*:hover,
*:active,
*:focus {
outline: 0
outline: 0;
}
a {
@@ -44,7 +48,7 @@ i.spin {
}
#app {
transition: .2s ease padding;
transition: 0.2s ease padding;
}
#app.multiple {
@@ -58,22 +62,32 @@ nav {
left: 0;
}
body.rtl nav {
left: unset;
right: 0;
}
nav .action {
width: 100%;
display: block;
border-radius: 0;
font-size: 1.1em;
padding: .5em;
padding: 0.5em;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
nav>div {
body.rtl .action {
direction: rtl;
text-align: right;
}
nav > div {
border-top: 1px solid rgba(0, 0, 0, 0.05);
}
nav .action>* {
nav .action > * {
vertical-align: middle;
}
@@ -97,19 +111,29 @@ main {
.breadcrumbs a {
color: inherit;
transition: .1s ease-in;
border-radius: .125em;
transition: 0.1s ease-in;
border-radius: 0.125em;
}
body.rtl .breadcrumbs a {
transform: translateX(-16em);
}
.breadcrumbs a:hover {
background-color: rgba(0,0,0, 0.05);
background-color: rgba(0, 0, 0, 0.05);
}
.breadcrumbs span a {
padding: .2em;
padding: 0.2em;
}
#progress {
.files {
position: absolute;
bottom: 30px;
width: 100%;
}
.progress {
position: fixed;
top: 0;
left: 0;
@@ -118,11 +142,11 @@ main {
z-index: 9999999999;
}
#progress div {
.progress div {
height: 100%;
background-color: #40c4ff;
width: 0;
transition: .2s ease width;
transition: 0.2s ease width;
}
.break-word {

View File

@@ -8,6 +8,10 @@
flex-wrap: wrap;
}
body.rtl .dashboard .row {
margin-right: 16em;
}
.dashboard .row .column {
display: flex;
padding: 0 .5em;
@@ -60,6 +64,10 @@ p code {
border-bottom: 2px solid rgba(0, 0, 0, 0.05);
}
body.rtl #nav .wrapper {
margin-right: 16em;
}
.dashboard #nav ul {
list-style: none;
display: flex;
@@ -138,6 +146,13 @@ table tr>*:first-child {
padding-left: 1em;
}
body.rtl table tr>* {
padding-left: unset;
padding-right: 1em;
text-align: right;
direction: ltr;
}
table tr>*:last-child {
padding-right: 1em;
}
@@ -160,7 +175,6 @@ table tr>*:last-child {
max-width: 25em;
width: 90%;
max-height: 95%;
z-index: 99999;
animation: .1s show forwards;
}
@@ -181,6 +195,11 @@ table tr>*:last-child {
margin-right: auto;
}
body.rtl .card .card-title>*:first-child {
margin-right: 0;
text-align: right;
}
.card>div {
padding: 1em 1em;
}
@@ -201,6 +220,10 @@ table tr>*:last-child {
text-align: right;
}
body.rtl .card .card-action {
text-align: left;
}
.card .card-content.full {
padding-bottom: 0;
overflow: auto;
@@ -299,6 +322,8 @@ table tr>*:last-child {
height: 100%;
width: 100%;
z-index: 9999;
visibility: hidden;
opacity: 0;
animation: .1s show forwards;
}
@@ -360,15 +385,15 @@ table tr>*:last-child {
@keyframes show {
0% {
display: none;
visibility: hidden;
opacity: 0;
}
1% {
display: block;
visibility: visible;
opacity: 0;
}
100% {
display: block;
visibility: visible;
opacity: 1;
}
}
@@ -461,4 +486,10 @@ table tr>*:last-child {
.card .card-action.full .action .title {
font-size: 1.5em;
font-weight: 500;
}
/*** RTL - Fix disk usage information (in english) ***/
body.rtl .credits {
text-align: right;
direction: ltr;
}

View File

@@ -1,169 +1,242 @@
@import "material-icons/iconfont/filled.css";
@font-face {
font-family: 'Roboto';
font-family: "Roboto";
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(../assets/fonts/roboto/normal-cyrillic-ext.woff2) format('woff2');
src:
local("Roboto"),
local("Roboto-Regular"),
url(../assets/fonts/roboto/normal-cyrillic-ext.woff2) format("woff2");
unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;
}
@font-face {
font-family: 'Roboto';
font-family: "Roboto";
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(../assets/fonts/roboto/normal-cyrillic.woff2) format('woff2');
src:
local("Roboto"),
local("Roboto-Regular"),
url(../assets/fonts/roboto/normal-cyrillic.woff2) format("woff2");
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
font-family: 'Roboto';
font-family: "Roboto";
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(../assets/fonts/roboto/normal-greek-ext.woff2) format('woff2');
src:
local("Roboto"),
local("Roboto-Regular"),
url(../assets/fonts/roboto/normal-greek-ext.woff2) format("woff2");
unicode-range: U+1F00-1FFF;
}
@font-face {
font-family: 'Roboto';
font-family: "Roboto";
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(../assets/fonts/roboto/normal-greek.woff2) format('woff2');
src:
local("Roboto"),
local("Roboto-Regular"),
url(../assets/fonts/roboto/normal-greek.woff2) format("woff2");
unicode-range: U+0370-03FF;
}
@font-face {
font-family: 'Roboto';
font-family: "Roboto";
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(../assets/fonts/roboto/normal-vietnamese.woff2) format('woff2');
src:
local("Roboto"),
local("Roboto-Regular"),
url(../assets/fonts/roboto/normal-vietnamese.woff2) format("woff2");
unicode-range: U+0102-0103, U+1EA0-1EF9, U+20AB;
}
@font-face {
font-family: 'Roboto';
font-family: "Roboto";
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(../assets/fonts/roboto/normal-latin-ext.woff2) format('woff2');
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
src:
local("Roboto"),
local("Roboto-Regular"),
url(../assets/fonts/roboto/normal-latin-ext.woff2) format("woff2");
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F,
U+A720-A7FF;
}
@font-face {
font-family: 'Roboto';
font-family: "Roboto";
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(../assets/fonts/roboto/normal-latin.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
src:
local("Roboto"),
local("Roboto-Regular"),
url(../assets/fonts/roboto/normal-latin.woff2) format("woff2");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC,
U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
}
@font-face {
font-family: 'Roboto';
font-family: "Roboto";
font-style: normal;
font-weight: 500;
src: local('Roboto Medium'), local('Roboto-Medium'), url(../assets/fonts/roboto/medium-cyrillic-ext.woff2) format('woff2');
src:
local("Roboto Medium"),
local("Roboto-Medium"),
url(../assets/fonts/roboto/medium-cyrillic-ext.woff2) format("woff2");
unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;
}
@font-face {
font-family: 'Roboto';
font-family: "Roboto";
font-style: normal;
font-weight: 500;
src: local('Roboto Medium'), local('Roboto-Medium'), url(../assets/fonts/roboto/medium-cyrillic.woff2) format('woff2');
src:
local("Roboto Medium"),
local("Roboto-Medium"),
url(../assets/fonts/roboto/medium-cyrillic.woff2) format("woff2");
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
font-family: 'Roboto';
font-family: "Roboto";
font-style: normal;
font-weight: 500;
src: local('Roboto Medium'), local('Roboto-Medium'), url(../assets/fonts/roboto/medium-greek-ext.woff2) format('woff2');
src:
local("Roboto Medium"),
local("Roboto-Medium"),
url(../assets/fonts/roboto/medium-greek-ext.woff2) format("woff2");
unicode-range: U+1F00-1FFF;
}
@font-face {
font-family: 'Roboto';
font-family: "Roboto";
font-style: normal;
font-weight: 500;
src: local('Roboto Medium'), local('Roboto-Medium'), url(../assets/fonts/roboto/medium-greek.woff2) format('woff2');
src:
local("Roboto Medium"),
local("Roboto-Medium"),
url(../assets/fonts/roboto/medium-greek.woff2) format("woff2");
unicode-range: U+0370-03FF;
}
@font-face {
font-family: 'Roboto';
font-family: "Roboto";
font-style: normal;
font-weight: 500;
src: local('Roboto Medium'), local('Roboto-Medium'), url(../assets/fonts/roboto/medium-vietnamese.woff2) format('woff2');
src:
local("Roboto Medium"),
local("Roboto-Medium"),
url(../assets/fonts/roboto/medium-vietnamese.woff2) format("woff2");
unicode-range: U+0102-0103, U+1EA0-1EF9, U+20AB;
}
@font-face {
font-family: 'Roboto';
font-family: "Roboto";
font-style: normal;
font-weight: 500;
src: local('Roboto Medium'), local('Roboto-Medium'), url(../assets/fonts/roboto/medium-latin-ext.woff2) format('woff2');
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
src:
local("Roboto Medium"),
local("Roboto-Medium"),
url(../assets/fonts/roboto/medium-latin-ext.woff2) format("woff2");
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F,
U+A720-A7FF;
}
@font-face {
font-family: 'Roboto';
font-family: "Roboto";
font-style: normal;
font-weight: 500;
src: local('Roboto Medium'), local('Roboto-Medium'), url(../assets/fonts/roboto/medium-latin.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
src:
local("Roboto Medium"),
local("Roboto-Medium"),
url(../assets/fonts/roboto/medium-latin.woff2) format("woff2");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC,
U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
}
@font-face {
font-family: 'Roboto';
font-family: "Roboto";
font-style: normal;
font-weight: 700;
src: local('Roboto Bold'), local('Roboto-Bold'), url(../assets/fonts/roboto/bold-cyrillic-ext.woff2) format('woff2');
src:
local("Roboto Bold"),
local("Roboto-Bold"),
url(../assets/fonts/roboto/bold-cyrillic-ext.woff2) format("woff2");
unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;
}
@font-face {
font-family: 'Roboto';
font-family: "Roboto";
font-style: normal;
font-weight: 700;
src: local('Roboto Bold'), local('Roboto-Bold'), url(../assets/fonts/roboto/bold-cyrillic.woff2) format('woff2');
src:
local("Roboto Bold"),
local("Roboto-Bold"),
url(../assets/fonts/roboto/bold-cyrillic.woff2) format("woff2");
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
font-family: 'Roboto';
font-family: "Roboto";
font-style: normal;
font-weight: 700;
src: local('Roboto Bold'), local('Roboto-Bold'), url(../assets/fonts/roboto/bold-greek-ext.woff2) format('woff2');
src:
local("Roboto Bold"),
local("Roboto-Bold"),
url(../assets/fonts/roboto/bold-greek-ext.woff2) format("woff2");
unicode-range: U+1F00-1FFF;
}
@font-face {
font-family: 'Roboto';
font-family: "Roboto";
font-style: normal;
font-weight: 700;
src: local('Roboto Bold'), local('Roboto-Bold'), url(../assets/fonts/roboto/bold-greek.woff2) format('woff2');
src:
local("Roboto Bold"),
local("Roboto-Bold"),
url(../assets/fonts/roboto/bold-greek.woff2) format("woff2");
unicode-range: U+0370-03FF;
}
@font-face {
font-family: 'Roboto';
font-family: "Roboto";
font-style: normal;
font-weight: 700;
src: local('Roboto Bold'), local('Roboto-Bold'), url(../assets/fonts/roboto/bold-vietnamese.woff2) format('woff2');
src:
local("Roboto Bold"),
local("Roboto-Bold"),
url(../assets/fonts/roboto/bold-vietnamese.woff2) format("woff2");
unicode-range: U+0102-0103, U+1EA0-1EF9, U+20AB;
}
@font-face {
font-family: 'Roboto';
font-family: "Roboto";
font-style: normal;
font-weight: 700;
src: local('Roboto Bold'), local('Roboto-Bold'), url(../assets/fonts/roboto/bold-latin-ext.woff2) format('woff2');
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
src:
local("Roboto Bold"),
local("Roboto-Bold"),
url(../assets/fonts/roboto/bold-latin-ext.woff2) format("woff2");
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F,
U+A720-A7FF;
}
@font-face {
font-family: 'Roboto';
font-family: "Roboto";
font-style: normal;
font-weight: 700;
src: local('Roboto Bold'), local('Roboto-Bold'), url(../assets/fonts/roboto/bold-latin.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
src:
local("Roboto Bold"),
local("Roboto-Bold"),
url(../assets/fonts/roboto/bold-latin.woff2) format("woff2");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC,
U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
}
@import "~material-design-icons/iconfont/material-icons.css";
.material-icons {
font-size: 1.5rem;
}

View File

@@ -84,7 +84,8 @@ header .menu-button {
#search #input {
background-color: #f5f5f5;
display: flex;
padding: 0.75em;
height: 100%;
padding: 0em 0.75em;
border-radius: 0.3em;
transition: .1s ease all;
align-items: center;
@@ -134,10 +135,25 @@ header .menu-button {
z-index: 1;
}
body.rtl #search #result {
direction: ltr;
}
#search #result>div>*:first-child {
margin-top: 0;
}
body.rtl #search #result {
direction: rtl;
text-align: right;
}
/*** RTL - Keep search result LTR because it has paths (in english) ***/
body.rtl #search #result ul>* {
direction: ltr;
text-align: left;
}
#search.active #result {
padding: .5em;
height: calc(100% - 4em);
@@ -223,6 +239,10 @@ header .menu-button {
padding: .5em;
}
body.rtl #search .boxes h3 {
text-align: right;
}
#search .boxes>div {
display: flex;
flex-wrap: wrap;

View File

@@ -0,0 +1,205 @@
/* Icons */
/* General */
.file-icons [aria-label^="."] { opacity: 0.33 }
.file-icons [aria-label$=".bak"] { opacity: 0.33 }
.file-icons [data-type=audio] i::before { content: 'volume_up' }
.file-icons [data-type=blob] i::before { content: 'insert_drive_file' }
.file-icons [data-type=image] i::before { content: 'image' }
.file-icons [data-type=pdf] i::before { content: 'description' }
.file-icons [data-type=text] i::before { content: 'description' }
.file-icons [data-type=video] i::before { content: 'movie' }
.file-icons [data-type=invalid_link] i::before { content: 'link_off' }
/* #f90 - Image */
.file-icons [aria-label$=".ai"] i::before,
.file-icons [aria-label$=".odg"] i::before,
.file-icons [aria-label$=".xcf"] i::before
{ content: 'image' }
/* #f90 - Presentation */
.file-icons [aria-label$=".odp"] i::before,
.file-icons [aria-label$=".ppt"] i::before,
.file-icons [aria-label$=".pptx"] i::before
{ content: 'slideshow' }
/* #0f0 - Spreadsheet/Database */
.file-icons [aria-label$=".csv"] i::before,
.file-icons [aria-label$=".db"] i::before,
.file-icons [aria-label$=".odb"] i::before,
.file-icons [aria-label$=".ods"] i::before,
.file-icons [aria-label$=".xls"] i::before,
.file-icons [aria-label$=".xlsx"] i::before
{ content: 'border_all' }
/* #00f - Document */
.file-icons [aria-label$=".doc"] i::before,
.file-icons [aria-label$=".docx"] i::before,
.file-icons [aria-label$=".log"] i::before,
.file-icons [aria-label$=".odt"] i::before,
.file-icons [aria-label$=".rtf"] i::before
{ content: 'description' }
/* #999 - Code */
.file-icons [aria-label$=".c"] i::before,
.file-icons [aria-label$=".cpp"] i::before,
.file-icons [aria-label$=".cs"] i::before,
.file-icons [aria-label$=".css"] i::before,
.file-icons [aria-label$=".go"] i::before,
.file-icons [aria-label$=".h"] i::before,
.file-icons [aria-label$=".html"] i::before,
.file-icons [aria-label$=".java"] i::before,
.file-icons [aria-label$=".js"] i::before,
.file-icons [aria-label$=".json"] i::before,
.file-icons [aria-label$=".kt"] i::before,
.file-icons [aria-label$=".php"] i::before,
.file-icons [aria-label$=".py"] i::before,
.file-icons [aria-label$=".rb"] i::before,
.file-icons [aria-label$=".rs"] i::before,
.file-icons [aria-label$=".vue"] i::before,
.file-icons [aria-label$=".xml"] i::before,
.file-icons [aria-label$=".yml"] i::before
{ content: 'code' }
/* #999 - Executable */
.file-icons [aria-label$=".apk"] i::before,
.file-icons [aria-label$=".bat"] i::before,
.file-icons [aria-label$=".exe"] i::before,
.file-icons [aria-label$=".jar"] i::before,
.file-icons [aria-label$=".ps1"] i::before,
.file-icons [aria-label$=".sh"] i::before
{ content: 'web_asset' }
/* #999 - Installer */
.file-icons [aria-label$=".deb"] i::before,
.file-icons [aria-label$=".msi"] i::before,
.file-icons [aria-label$=".pkg"] i::before,
.file-icons [aria-label$=".rpm"] i::before
{ content: 'archive' }
/* #999 - Compressed */
.file-icons [aria-label$=".7z"] i::before,
.file-icons [aria-label$=".bz2"] i::before,
.file-icons [aria-label$=".cab"] i::before,
.file-icons [aria-label$=".gz"] i::before,
.file-icons [aria-label$=".rar"] i::before,
.file-icons [aria-label$=".tar"] i::before,
.file-icons [aria-label$=".xz"] i::before,
.file-icons [aria-label$=".zip"] i::before,
.file-icons [aria-label$=".zst"] i::before
{ content: 'folder_zip' }
/* #999 - Disk */
.file-icons [aria-label$=".ccd"] i::before,
.file-icons [aria-label$=".dmg"] i::before,
.file-icons [aria-label$=".iso"] i::before,
.file-icons [aria-label$=".mdf"] i::before,
.file-icons [aria-label$=".vdi"] i::before,
.file-icons [aria-label$=".vhd"] i::before,
.file-icons [aria-label$=".vmdk"] i::before,
.file-icons [aria-label$=".wim"] i::before
{ content: 'album' }
/* #999 - Font */
.file-icons [aria-label$=".otf"] i::before,
.file-icons [aria-label$=".ttf"] i::before,
.file-icons [aria-label$=".woff"] i::before,
.file-icons [aria-label$=".woff2"] i::before
{ content: 'font_download' }
/* Colors */
/* General */
.file-icons [data-type=audio] i { color: var(--icon-yellow) }
.file-icons [data-type=image] i { color: var(--icon-orange) }
.file-icons [data-type=video] i { color: var(--icon-violet) }
.file-icons [data-type=invalid_link] i { color: var(--icon-red) }
/* #f00 - Adobe/Oracle */
.file-icons [aria-label$=".ai"] i,
.file-icons [aria-label$=".java"] i,
.file-icons [aria-label$=".jar"] i,
.file-icons [aria-label$=".psd"] i,
.file-icons [aria-label$=".rb"] i,
.file-icons [data-type=pdf] i
{ color: var(--icon-red) }
/* #f90 - Image/Presentation */
.file-icons [aria-label$=".html"] i,
.file-icons [aria-label$=".odg"] i,
.file-icons [aria-label$=".odp"] i,
.file-icons [aria-label$=".ppt"] i,
.file-icons [aria-label$=".pptx"] i,
.file-icons [aria-label$=".vue"] i,
.file-icons [aria-label$=".xcf"] i
{ color: var(--icon-orange) }
/* #ff0 - Various */
.file-icons [aria-label$=".css"] i,
.file-icons [aria-label$=".js"] i,
.file-icons [aria-label$=".json"] i,
.file-icons [aria-label$=".zip"] i
{ color: var(--icon-yellow) }
/* #0f0 - Spreadsheet/Google */
.file-icons [aria-label$=".apk"] i,
.file-icons [aria-label$=".dex"] i,
.file-icons [aria-label$=".go"] i,
.file-icons [aria-label$=".ods"] i,
.file-icons [aria-label$=".xls"] i,
.file-icons [aria-label$=".xlsx"] i
{ color: var(--icon-green) }
/* #00f - Document/Microsoft/Apple/Closed */
.file-icons [aria-label$=".aac"] i,
.file-icons [aria-label$=".bat"] i,
.file-icons [aria-label$=".cab"] i,
.file-icons [aria-label$=".cs"] i,
.file-icons [aria-label$=".dmg"] i,
.file-icons [aria-label$=".doc"] i,
.file-icons [aria-label$=".docx"] i,
.file-icons [aria-label$=".emf"] i,
.file-icons [aria-label$=".exe"] i,
.file-icons [aria-label$=".ico"] i,
.file-icons [aria-label$=".mp2"] i,
.file-icons [aria-label$=".mp3"] i,
.file-icons [aria-label$=".mp4"] i,
.file-icons [aria-label$=".mpg"] i,
.file-icons [aria-label$=".msi"] i,
.file-icons [aria-label$=".odt"] i,
.file-icons [aria-label$=".ps1"] i,
.file-icons [aria-label$=".rtf"] i,
.file-icons [aria-label$=".vob"] i,
.file-icons [aria-label$=".wim"] i
{ color: var(--icon-blue) }
/* #60f - Various */
.file-icons [aria-label$=".iso"] i,
.file-icons [aria-label$=".php"] i,
.file-icons [aria-label$=".rar"] i
{ color: var(--icon-violet) }
/* Overrides */
.file-icons [data-dir=true] i { color: var(--icon-blue) }
.file-icons [data-dir=true] i::before { content: 'folder' }
.file-icons [aria-selected=true] i { color: var(--item-selected) }

View File

@@ -1,3 +1,11 @@
#listing {
--item-selected: white;
}
body.rtl #listing {
margin-right: 16em;
}
#listing h2 {
margin: 0 0 0 0.5em;
font-size: .9em;
@@ -106,6 +114,41 @@
width: calc(100% - 5vw);
}
#listing.mosaic.gallery .item div:first-of-type {
width: 100%;
height: 12em;
}
#listing.mosaic.gallery .item div:last-of-type {
position: absolute;
bottom: 0.5em;
padding: 1em;
width: calc(100% - 1em);
text-align: center;
}
#listing.mosaic.gallery .item[data-type=image] div:last-of-type {
color: white;
background: linear-gradient(#0000, #0009);
}
#listing.mosaic.gallery .item i {
width: 100%;
margin-right: 0;
font-size: 8em;
text-align: center;
}
#listing.mosaic.gallery .item img {
width: 100%;
height: 100%;
}
#listing.gallery .size,
#listing.gallery .modified {
display: none;
}
#listing.list {
flex-direction: column;
width: 100%;
@@ -127,7 +170,7 @@
#listing .item[aria-selected=true] {
background: var(--blue) !important;
color: #fff !important;
color: var(--item-selected) !important;
}
#listing.list .item div:first-of-type {
@@ -238,5 +281,5 @@
#listing #multiple-selection p,
#listing #multiple-selection i {
color: #fff;
color: var(--item-selected);
}

View File

@@ -40,6 +40,13 @@
transform-origin: top right;
z-index: 99999;
}
body.rtl #dropdown {
right: unset;
left: 1em;
transform-origin: top left;
}
#dropdown > div {
display: block;
}
@@ -95,9 +102,24 @@
transition: .1s ease left;
left: -17em;
}
body.rtl nav {
left: unset;
right: -17em;
}
nav.active {
left: 0;
}
body.rtl nav.active {
left: unset;
right: 0;
}
.shell__divider {
height: 12px;
}
header .search-button,
header .menu-button {
display: inherit;
@@ -108,6 +130,23 @@
#listing {
margin-bottom: 5em;
}
body.rtl #listing {
margin-right: unset;
}
body.rtl .breadcrumbs {
transform: translateX(16em);
}
body.rtl #nav .wrapper {
margin-right: unset;
}
body.rtl .dashboard .row {
margin-right: unset;
}
main {
margin: 0 1em;
width: calc(100% - 2em);

View File

@@ -1,6 +1,6 @@
@import "~normalize.css/normalize.css";
@import "~noty/lib/noty.css";
@import "~noty/lib/themes/mint.css";
@import "normalize.css/normalize.css";
@import "noty/lib/noty.css";
@import "noty/lib/themes/mint.css";
@import "./_variables.css";
@import "./_buttons.css";
@import "./_inputs.css";
@@ -10,8 +10,11 @@
@import "./base.css";
@import "./header.css";
@import "./listing.css";
@import "./listing-icons.css";
@import "./upload-files.css";
@import "./dashboard.css";
@import "./login.css";
@import "./mobile.css";
.link {
color: var(--blue);
@@ -25,9 +28,9 @@ main .spinner {
}
main .spinner > div {
width: .8em;
height: .8em;
margin: 0 .1em;
width: 0.8em;
height: 0.8em;
margin: 0 0.1em;
font-size: 1em;
background-color: rgba(0, 0, 0, 0.3);
border-radius: 100%;
@@ -69,7 +72,7 @@ main .spinner .bounce2 {
transition: 0.2s ease all;
border: 0;
margin: 0;
color: #546E7A;
color: #546e7a;
border-radius: 50%;
background: transparent;
padding: 0;
@@ -86,12 +89,12 @@ main .spinner .bounce2 {
.action i {
padding: 0.4em;
transition: .1s ease-in-out all;
transition: 0.1s ease-in-out all;
border-radius: 50%;
}
.action:hover {
background-color: rgba(0, 0, 0, .1);
background-color: rgba(0, 0, 0, 0.1);
}
.action ul {
@@ -107,8 +110,8 @@ main .spinner .bounce2 {
.action ul li {
line-height: 1;
padding: .7em;
transition: .1s ease background-color;
padding: 0.7em;
transition: 0.1s ease background-color;
}
.action ul li:hover {
@@ -126,7 +129,7 @@ main .spinner .bounce2 {
}
#click-overlay.active {
display: block;
visibility: visible;
}
.action .counter {
@@ -137,7 +140,7 @@ main .spinner .bounce2 {
background: var(--blue);
color: #fff;
border-radius: 50%;
font-size: .75em;
font-size: 0.75em;
width: 1.8em;
height: 1.8em;
text-align: center;
@@ -146,12 +149,10 @@ main .spinner .bounce2 {
border: 2px solid white;
}
/* PREVIEWER */
#previewer {
background-color: rgba(0, 0, 0, 0.9);
padding-top: 4em;
background-color: rgba(0, 0, 0, 0.99);
position: fixed;
top: 0;
left: 0;
@@ -164,20 +165,30 @@ main .spinner .bounce2 {
#previewer header {
background: none;
color: #fff;
border-bottom: 0px;
box-shadow: 0px 0px 0px;
z-index: 19999;
}
#previewer header > .action i {
color: #fff;
text-shadow: 1px 1px 1px #000000;
}
#previewer header > title {
white-space: nowrap;
text-shadow: 1px 1px 1px #000000;
}
@media (min-width: 738px) {
#previewer header #dropdown .action i {
color: #fff;
text-shadow: 1px 1px 1px #000000;
}
}
#previewer header .action:hover {
background-color: rgba(255, 255, 255, 0.3)
background-color: rgba(255, 255, 255, 0.3);
}
#previewer header .action span {
@@ -186,7 +197,7 @@ main .spinner .bounce2 {
#previewer .preview {
text-align: center;
height: calc(100vh - 4em);
height: 100%;
}
#previewer .preview pre {
@@ -201,25 +212,59 @@ main .spinner .bounce2 {
margin: 0;
}
#previewer .preview audio {
width: 95%;
height: 88%;
}
#previewer .preview video {
height: 100%;
}
#previewer .preview .info {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 1.5em;
color: #fff;
}
#previewer .preview .info .title {
margin-bottom: 1em;
}
#previewer .preview .info .title i {
display: block;
margin-bottom: 0.1em;
font-size: 4em;
}
#previewer .preview .info .button {
display: inline-block;
}
#previewer .preview .info .button:hover {
background-color: rgba(255, 255, 255, 0.2);
}
#previewer .preview .info .button i {
display: block;
margin-bottom: 4px;
font-size: 1.3em;
}
#previewer .pdf {
width: 100%;
height: 100%;
}
#previewer h2.message {
color: rgba(255, 255, 255, 0.5)
color: rgba(255, 255, 255, 0.5);
}
#previewer>button {
#previewer > button {
margin: 0;
position: fixed;
top: calc(50% + 1.85em);
top: 50%;
transform: translateY(-50%);
background-color: rgba(80, 80, 80, .5);
background-color: rgba(80, 80, 80, 0.5);
color: white;
border-radius: 50%;
cursor: pointer;
@@ -229,20 +274,20 @@ main .spinner .bounce2 {
transition: 0.2s ease all;
}
#previewer>button.hidden {
#previewer > button.hidden {
opacity: 0;
visibility: hidden;
}
#previewer>button>i {
#previewer > button > i {
padding: 0.4em;
}
#previewer>button:first-of-type {
#previewer > button:first-of-type {
left: 0.5em;
}
#previewer>button:last-of-type {
#previewer > button:last-of-type {
right: 0.5em;
}
@@ -263,18 +308,21 @@ main .spinner .bounce2 {
/* EDITOR */
#editor-container {
display: flex;
flex-direction: column;
background-color: #fafafa;
position: fixed;
padding-top: 4em;
top: 0;
left: 0;
height: 100%;
width: 100%;
z-index: 9999;
overflow: hidden;
}
#editor-container #editor {
height: calc(100vh - 8.4em);
flex: 1;
}
#editor-container .breadcrumbs {
@@ -282,12 +330,17 @@ main .spinner .bounce2 {
padding: 0 1em;
}
/*** RTL - flip and position arrow of path ***/
body.rtl .breadcrumbs .chevron {
transform: scaleX(-1) translateX(16em);
}
#editor-container .breadcrumbs span {
font-size: 12px;
font-size: 0.75rem;
}
#editor-container .breadcrumbs i {
font-size: 16px;
font-size: 1rem;
}
/* * * * * * * * * * * * * * * *
@@ -301,9 +354,9 @@ main .spinner .bounce2 {
.noty_buttons button {
background: rgba(0, 0, 0, 0.05);
border: 1px solid rgba(0,0,0,0.1);
border: 1px solid rgba(0, 0, 0, 0.1);
box-shadow: 0 0 0 0;
font-size: 14px;
font-size: 1rem;
}
/* * * * * * * * * * * * * * * *
@@ -318,7 +371,7 @@ main .spinner .bounce2 {
.credits > span {
display: block;
margin: .3em 0;
margin: 0.3em 0;
}
.credits a,
@@ -327,17 +380,26 @@ main .spinner .bounce2 {
cursor: pointer;
}
/* * * * * * * * * * * * * * * *
* ANIMATIONS *
* * * * * * * * * * * * * * * */
@keyframes spin {
100% {
transform: rotate(-360deg);
transform: rotate(360deg);
}
}
/* * * * * * * * * * * * * * * *
* SETTINGS TUS *
* * * * * * * * * * * * * * * */
.tusConditionalSettings input:disabled {
background-color: #ddd;
color: #999;
cursor: not-allowed;
}
/* * * * * * * * * * * * * * * *
* SETTINGS RULES *
* * * * * * * * * * * * * * * */
@@ -345,20 +407,20 @@ main .spinner .bounce2 {
.rules > div {
display: flex;
align-items: center;
margin: .5rem 0;
margin: 0.5rem 0;
}
.rules input[type="checkbox"] {
margin-right: .2rem;
margin-right: 0.2rem;
}
.rules input[type="text"] {
border: 1px solid#ddd;
padding: .2rem;
padding: 0.2rem;
}
.rules label {
margin-right: .5rem;
margin-right: 0.5rem;
}
.rules button {
@@ -366,8 +428,25 @@ main .spinner .bounce2 {
}
.rules button.delete {
padding: .2rem .5rem;
margin-left: .5rem;
padding: 0.2rem 0.5rem;
margin-left: 0.5rem;
}
@import './mobile.css';
/* * * * * * * * * * * * * * * *
* RTL overrides *
* * * * * * * * * * * * * * * */
body.rtl .card-content textarea {
direction: ltr;
text-align: left;
}
body.rtl .card-content .small + input {
direction: ltr;
text-align: left;
}
body.rtl .card.floating .card-content .file-list {
direction: ltr;
text-align: left;
}

View File

@@ -0,0 +1,61 @@
.upload-files .card.floating {
left: auto;
top: auto;
margin: 0;
right: 0;
bottom: 0;
transform: none;
}
.upload-files .file {
margin-bottom: 8px;
}
.upload-files .file .file-name {
font-size: 1.1em;
display: flex;
align-items: center;
}
.upload-files .file .file-name i {
margin-right: 5px;
}
.upload-files .file .file-progress {
margin-top: 2px;
width: 100%;
height: 5px;
}
.upload-files .file .file-progress div {
height: 100%;
background-color: #40c4ff;
width: 0;
transition: 0.2s ease width;
border-radius: 10px;
}
.upload-files.closed .card-content {
display: none;
padding: 0em 1em 1em 1em;
}
.upload-files .card .card-title {
display: flex;
align-items: center;
justify-content: center;
font-size: 0.8em;
padding: 1em 1em 0em;
}
.upload-files.closed .card-title {
font-size: 0.7em;
padding: 0.5em 1em;
}
@media (max-width: 450px) {
.upload-files .card.floating {
max-width: 100%;
width: 100%;
}
}

View File

@@ -5,10 +5,13 @@
"copy": "نسخ",
"copyFile": "نسخ الملف",
"copyToClipboard": "نسخ الى الحافظة",
"copyDownloadLinkToClipboard": "نسخ رابط التحميل الى الحافظة",
"create": "إنشاء",
"delete": "حذف",
"download": "تحميل",
"hideDotfiles": "",
"file": "ملف",
"folder": "مجلد",
"hideDotfiles": "إخفاء ملفات النقطة",
"info": "معلومات",
"more": "المزيد",
"move": "نقل",
@@ -16,7 +19,7 @@
"new": "جديد",
"next": "التالي",
"ok": "موافق",
"permalink": "الحصول على لنك دائم",
"permalink": "الحصول على رابط دائم",
"previous": "السابق",
"publish": "نشر",
"rename": "إعادة تسمية",
@@ -28,21 +31,28 @@
"select": "تحديد",
"selectMultiple": "تحديد متعدد",
"share": "مشاركة",
"shell": "Toggle shell",
"shell": "تفعيل/إغلاق واجهة اﻷوامر (shell)",
"submit": "تسليم",
"switchView": "تغيير العرض",
"toggleSidebar": "تبديل الشريط الجانبي",
"update": "تحديث",
"upload": "رفع"
"upload": "رفع",
"openFile": "فتح الملف",
"continue": "متابعة"
},
"download": {
"downloadFile": "Download File",
"downloadFolder": "Download Folder",
"downloadSelected": ""
"downloadFile": "تحميل الملف",
"downloadFolder": "تحميل المجلد",
"downloadSelected": "تحميل الملفات المحددة"
},
"upload": {
"abortUpload": "هل تريد بالتاكيد إلغاء الرفع؟"
},
"errors": {
"forbidden": "You don't have permissions to access this.",
"forbidden": "ليست لديك الصلاحيات للوصول لهذا المحتوى.",
"internal": "لقد حدث خطأ ما.",
"notFound": "لا يمكن الوصول لهذا المحتوى."
"notFound": "لا يمكن الوصول لهذا المحتوى.",
"connection": "لا يمكن اﻹتصال بالخادم."
},
"files": {
"body": "الصفحة",
@@ -50,17 +60,18 @@
"closePreview": "إغلاق العرض",
"files": "الملفات",
"folders": "المجلدات",
"home": "الصفحة الاولى",
"home": "الصفحة الرئيسية",
"lastModified": "آخر تعديل",
"loading": "جاري التحميل...",
"lonely": "تبدو وحيدا هنا...",
"metadata": "بيانات تعريفية",
"metadata": "بيانات وصفية",
"multipleSelectionEnabled": "التحديد المتعدد مفعل",
"name": "الإسم",
"name": "اسم",
"size": "الحجم",
"sortByLastModified": "الترتيب بآخر تعديل",
"sortByName": "الترتيب بالإسم",
"sortBySize": "الترتيب بالحجم"
"sortByName": "الترتيب باسم",
"sortBySize": "الترتيب بالحجم",
"noPreview": "لا يوجد عرض مسبق لهذا الملف."
},
"help": {
"click": "حدد الملف أو المجلد",
@@ -71,52 +82,59 @@
},
"del": "حذف البيانات المحددة",
"doubleClick": "فتح المجلد او الملف",
"esc": "مسح التحديد وإغلاق النافذة المنبثقة",
"esc": "مسح التحديد و إغلاق النافذة المنبثقة",
"f1": "هذه المعلومات",
"f2": "إعادة تسمية الملف",
"help": "مساعدة"
},
"languages": {
"he": "עברית",
"hu": "Magyar",
"ar": "العربية",
"de": "Deutsch",
"el": "Ελληνικά",
"en": "English",
"es": "Español",
"fr": "Français",
"is": "",
"is": "Icelandic",
"it": "Italiano",
"ja": "日本語",
"ko": "한국어",
"nlBE": "",
"nlBE": "Dutch (Belgium)",
"pl": "Polski",
"pt": "Português",
"ptBR": "Português (Brasil)",
"ro": "",
"ro": "Romanian",
"ru": "Русский",
"svSE": "",
"sk": "Slovenčina",
"svSE": "Swedish (Sweden)",
"tr": "Türkçe",
"ua": "Українська",
"zhCN": "中文 (简体)",
"zhTW": "中文 (繁體)"
},
"login": {
"createAnAccount": "Create an account",
"loginInstead": "Already have an account",
"createAnAccount": "إنشاء حساب جديد",
"loginInstead": "هل لديك حساب",
"password": "كلمة المرور",
"passwordConfirm": "Password Confirmation",
"passwordsDontMatch": "Passwords don't match",
"signup": "Signup",
"passwordConfirm": "تأكيد كلمة المرور",
"passwordsDontMatch": "كلمة المرور غير متطابقة",
"signup": "إشترك",
"submit": "تسجيل دخول",
"username": "إسم المستخدم",
"usernameTaken": "Username already taken",
"usernameTaken": "إسم المستخدم غير متاح",
"wrongCredentials": "بيانات دخول خاطئة"
},
"permanent": "دائم",
"prompts": {
"copy": "نسخ",
"copyMessage": "رجاء حدد المكان لنسخ ملفاتك فيه:",
"currentlyNavigating": "يتم الإنتقال حاليا إلى:",
"copyMessage": "حدد المكان لنسخ ملفاتك فيه:",
"currentlyNavigating": "يتم انتقال حاليا إلى:",
"deleteMessageMultiple": "هل تريد بالتأكيد حذف {count} ملف؟",
"deleteMessageSingle": "هل تريد بالتأكيد حذف هذا الملف/المجلد؟",
"deleteMessageShare": "هل تريد بالتأكيد إلغاء مشاركة هذا الملف/المجلد ({path})؟",
"deleteTitle": "حذف الملفات",
"displayName": "الإسم:",
"displayName": "عرض اﻹسم:",
"download": "تحميل الملفات",
"downloadMessage": "حدد إمتداد الملف المراد تحميله.",
"error": "لقد حدث خطأ ما",
@@ -125,80 +143,90 @@
"lastModified": "آخر تعديل",
"move": "نقل",
"moveMessage": "إختر مكان جديد للملفات أو المجلدات المراد نقلها:",
"newArchetype": "إنشاء منشور من المنشور الأصلي. الملف سيتم انشاءه في مجلد المحتويات.",
"newArchetype": "إنشاء منشور من المنشور اصلي. الملف سيتم انشاءه في مجلد المحتويات.",
"newDir": "مجلد جديد",
"newDirMessage": "رجاء أدخل اسم المجلد الجديد.",
"newDirMessage": "أدخل اسم المجلد الجديد.",
"newFile": "ملف جديد",
"newFileMessage": "رجاء ادخل اسم الملف الجديد.",
"newFileMessage": "ادخل اسم الملف الجديد.",
"numberDirs": "عدد المجلدات",
"numberFiles": "عدد الملفات",
"rename": "إعادة تسمية",
"renameMessage": "إدراج اسم جديد لـ",
"replace": "إستبدال",
"replaceMessage": "أحد الملفات التي تحاول رفعها يتعارض مع ملف موجود بنفس الإسم. هل تريد إستبدال الملف الموجود؟\n",
"replaceMessage": "أحد الملفات التي تحاول رفعها يتعارض مع ملف موجود بنفس اسم. هل المتابعة مع تخطي هذا الملف ام تريد إستبدال الملف الموجود؟\n",
"schedule": "جدولة",
"scheduleMessage": "أختر الوقت والتاريخ لجدولة نشر هذا المقال.",
"scheduleMessage": "أختر الوقت و التاريخ لجدولة نشر هذا المقال.",
"show": "عرض",
"size": "الحجم",
"upload": "",
"uploadMessage": ""
"upload": "رفع",
"uploadFiles": "يتم رفع {files} ملفات.",
"uploadMessage": "إختر الملفات التي تريد رفعها.",
"optionalPassword": "كلمة مرور إختيارية"
},
"search": {
"images": "الصور",
"music": "الموسيقى",
"pdf": "PDF",
"pressToSearch": "Press enter to search...",
"pressToSearch": "أضغط زر اﻹدخال للبحث...",
"search": "البحث...",
"typeToSearch": "Type to search...",
"types": "الأنواع",
"typeToSearch": "اكتب للبحث...",
"types": "انواع",
"video": "فيديوهات"
},
"settings": {
"admin": "Admin",
"administrator": "Administrator",
"allowCommands": "تنفيذ الأوامر",
"allowEdit": "تعديل، إعادة تسمية وحذف الملفات والمجلدات",
"allowNew": "إنشاء ملفات ومجلدات جديدة",
"allowPublish": "نشر مقالات وصفحات جديدة",
"allowSignup": "Allow users to signup",
"admin": "إدارة",
"administrator": "مدير",
"allowCommands": "تنفيذ اوامر",
"allowEdit": "تعديل، إعادة تسمية و حذف الملفات و المجلدات",
"allowNew": "إنشاء ملفات و مجلدات جديدة",
"allowPublish": "نشر مقالات و صفحات جديدة",
"allowSignup": "اسمح للمستخدمين بالاشتراك",
"avoidChanges": "(أتركه فارغاً إن لم ترد تغييره)",
"branding": "Branding",
"brandingDirectoryPath": "Branding directory path",
"brandingHelp": "You can customize how your File Browser instance looks and feels by changing its name, replacing the logo, adding custom styles and even disable external links to GitHub.\nFor more information about custom branding, please check out the {0}.",
"branding": "الشعار",
"brandingDirectoryPath": "مسار مجلد الشعار",
"brandingHelp": "بإمكانك ان تخصص شكل و مظهر متصفح الملفات الخاص بك عن طريق تغيير اسمه، او تغيير الشعار، او اضافة ستايل مخصص، او حتى تعطيل الروابط الخارجية لـ GitHub.\nلمزيد من المعلومات حول التخصيص، يرجى الاطلاع على {0}.",
"changePassword": "تغيير كلمة المرور",
"commandRunner": "Command runner",
"commandRunnerHelp": "Here you can set commands that are executed in the named events. You must write one per line. The environment variables {0} and {1} will be available, being {0} relative to {1}. For more information about this feature and the available environment variables, please read the {2}.",
"commandsUpdated": "تم تحديث الأوامر",
"createUserDir": "Auto create user home dir while adding new user",
"commandRunner": "منفذ اﻷوامر",
"commandRunnerHelp": "هنا بإمكانك تعيين اﻷوامر التي سيتم تنفيذها في اﻷحداث المسماة. يجب كتابة أمر واحد في كل سطر. ستكون المتغيرات البيئية (env) {0} و {1} متاحة، حيث {0} نسبي لـ {1}. لمزيد من المعلومات حول هذه الميزة و المتغيرات البيئية المتاحة، يرجى قراءة {2}.",
"commandsUpdated": "تم تحديث اوامر",
"createUserDir": "إنشاء مجلد المستخدم (home) تلقائياً عند إنشاء مستخدم جديد",
"tusUploads": "التحميلات المتقطعة",
"tusUploadsHelp": "يدعم متصفح الملفات تحميل الملفات المتقطعة، مما يسمح بتحميلات الملفات بشكل فعال و موثوق و قابلة للمتابغة و متقطعة حتى على الشبكات غير الموثوقة.",
"tusUploadsChunkSize": "يشير إلى الحد اﻷقصى لحجم الطلب (سيتم استخدام التحميل المباشر للتحميلات صغيرة الخحم). يمكنك إدخال عدد صحيح عادي يدل على الحجم بوحدة البايت أو نمظ مثل10MB, 1GB, إلخ.",
"tusUploadsRetryCount": "عدد مرات إعادة المحاولة إذا فشلت عملية تحميل القطعة.",
"userHomeBasePath": "المسار الرئيسي لمجلد المستخدم (home)",
"userScopeGenerationPlaceholder": "سيتم تعيين نطاق المستخدم تلقائياً",
"createUserHomeDirectory": "إنشاء مجلد المستخدم (home)",
"customStylesheet": "ستايل مخصص",
"defaultUserDescription": "This are the default settings for new users.",
"disableExternalLinks": "Disable external links (except documentation)",
"documentation": "documentation",
"defaultUserDescription": "هذه اﻹعدادات اﻹفتراضية للمستخدمين الجدد.",
"disableExternalLinks": "تعطيل الروابط الخارجية (بإسثناء الوثائق)",
"disableUsedDiskPercentage": "تعطيل الرسم البياني لنسبة القرص المستخدم",
"documentation": "التوثيق",
"examples": "أمثلة",
"executeOnShell": "Execute on shell",
"executeOnShellDescription": "By default, File Browser executes the commands by calling their binaries directly. If you want to run them on a shell instead (such as Bash or PowerShell), you can define it here with the required arguments and flags. If set, the command you execute will be appended as an argument. This apply to both user commands and event hooks.",
"globalRules": "This is a global set of allow and disallow rules. They apply to every user. You can define specific rules on each user's settings to override this ones.",
"executeOnShell": "نفيذ اﻷمر على الواجهة (shell)",
"executeOnShellDescription": "يقوم متصفح الملفات بتنفيذ اﻷوامر عن طريق استدعاء البرامج المنفذة مباشرة. إذا كنت تريد تشغيلها عن ظريق واجهة اﻷوامر (shell) مثل Bash أو PowerShell، يمكنك تعريفها هنا مع الوسائظ (arguments) المطلوبة. إذا تم تعيينها، سيتم إضافة اﻷمر الذي تقوم بتنفيذه كوسيط. ينطبق هذا على كل من أوامر المستخدم روابظ الحدث (hooks).",
"globalRules": "هذه مجموعة من القواعد العامة للسماح و المنع. تطبق على كل المستخدمين. يمكنك تحديد قواعد محددة لكل مستخدم لتجاوز القواعد الغامة.",
"globalSettings": "إعدادات عامة",
"hideDotfiles": "",
"insertPath": "Insert the path",
"insertRegex": "Insert regex expression",
"instanceName": "Instance name",
"hideDotfiles": "إخفاء ملفات النقطة",
"insertPath": "ادخل المسار",
"insertRegex": "ادخل تعبيراً منطقياً (regex)",
"instanceName": "اسم النسخة",
"language": "اللغة",
"lockPassword": "منع المستخدم من تغيير كلمة المرور",
"newPassword": "كلمة المرور الجديدة",
"newPasswordConfirm": "تأكيد كلمة المرور",
"newUser": "مستخدم جديد",
"password": "كلمة المرور",
"passwordUpdated": "تم تغيير كلمة المرور",
"path": "",
"passwordUpdated": "تم تغيير كلمة المرور!",
"path": "المسار",
"perm": {
"create": "Create files and directories",
"delete": "Delete files and directories",
"download": "Download",
"execute": "Execute commands",
"modify": "Edit files",
"rename": "Rename or move files and directories",
"share": "Share files"
"create": "إنشاء ملفات و مجلدات جديدة",
"delete": "حذف ملفات و مجلدات",
"download": "تحميل",
"execute": "تنفيذ اﻷوامر",
"modify": "تعديل محتويات الملفات",
"rename": "إعادة تسمية او نقل ملفات و مجلدات",
"share": "مشاركة ملفات"
},
"permissions": "الصلاحيات",
"permissionsHelp": "يمكنك تعيين المستخدم كـ \"مدير\" أو تحديد الصلاحيات بشكل منفرد.\n إذا قمت بتحديد المستخدم كـ \"مدير\"، باقي الخيارات سيتم تحديدها تلقائياً.\n إدارة المستخدمين تبقى صلاحية فريدة للـ \"مدير\" فقط.\n",
@@ -206,22 +234,24 @@
"ruleExample1": "منع الوصول إلى الملفات التي تبدأ بنقطة مثل (.git، و .gitignore) في كل مجلد.\n",
"ruleExample2": "منع الوصول إلى الملف المسمى Caddyfile في نطاق الجذر.",
"rules": "المجموعات",
"rulesHelp": "يمكنك هنا تحديد مجموعة من شروط السماح والمنع لهذا المستخدم. الملفات الممنوعة لن تظهر ضمن القائمة لهذا المستخدم ولن يستطيع الوصول لها. هنا ندعم الـ regex والـ relative path لنطاق المستخدمين.\n",
"rulesHelp": "يمكنك هنا تحديد مجموعة من شروط السماح و المنع لهذا المستخدم. الملفات الممنوعة لن تظهر ضمن القائمة لهذا المستخدم و لن يستطيع الوصول لها. هنا ندعم الـ regex و الـ relative path لنطاق المستخدمين.\n",
"scope": "نطاق",
"settingsUpdated": "تم تعديل الإعدادات",
"shareDuration": "",
"shareManagement": "",
"singleClick": "",
"setDateFormat": "حدد تنسيق التاريخ",
"settingsUpdated": "تم تعديل اﻹعدادات",
"shareDuration": "مدة المشاركة",
"shareManagement": "إدارة المشاركات",
"shareDeleted": "تم حذف المشاركة!",
"singleClick": "استخدم النقرة الواحدة لفتح الملفات",
"themes": {
"dark": "",
"light": "",
"title": ""
"dark": "غامق",
"light": "فاتح",
"title": "موضوع"
},
"user": "المستخدم",
"userCommands": "الأوامر",
"userCommandsHelp": "الأوامر المتاحة لهذا المستخدم مفصولة فيما بينها بمسافة. مثال:\n",
"userCommands": "اوامر",
"userCommandsHelp": "اوامر المتاحة لهذا المستخدم مفصولة فيما بينها بمسافة. مثال:\n",
"userCreated": "تم إنشاء المستخدم",
"userDefaults": "User default settings",
"userDefaults": "إعدادات المستخدم اﻹفتراضية",
"userDeleted": "تم حذف المستخدم",
"userManagement": "إدارة المستخدمين",
"userUpdated": "تم تعديل المستخدم",
@@ -231,14 +261,14 @@
"sidebar": {
"help": "مساعدة",
"hugoNew": "هيوجو جديد",
"login": "Login",
"login": "تسجيل دخول",
"logout": "تسجيل خروج",
"myFiles": "ملفاتي",
"newFile": "ملف جديد",
"newFolder": "مجلد جديد",
"preview": "معاينة",
"settings": "الإعدادات",
"signup": "Signup",
"preview": "عرض مسبق",
"settings": "اعدادات",
"signup": "إشتراك",
"siteSettings": "إعدادات الموقع"
},
"success": {
@@ -252,3 +282,4 @@
"unit": "وحدة الوقت"
}
}

View File

@@ -7,8 +7,10 @@
"copyToClipboard": "In Zwischenablage kopieren",
"create": "Neu",
"delete": "Löschen",
"download": "Downloaden",
"hideDotfiles": "",
"download": "Herunterladen",
"file": "Datei",
"folder": "Ordner",
"hideDotfiles": "Versteckte Dateien ausblenden",
"info": "Info",
"more": "mehr",
"move": "Verschieben",
@@ -29,24 +31,28 @@
"selectMultiple": "Mehrfachauswahl",
"share": "Teilen",
"shell": "Kommandozeile ein/ausschalten",
"submit": "Absenden",
"switchView": "Ansicht wechseln",
"toggleSidebar": "Seitenleiste anzeigen",
"update": "Update",
"upload": "Upload"
"upload": "Upload",
"openFile": "Datei öffnen",
"continue": "Fortfahren"
},
"download": {
"downloadFile": "Download Datei",
"downloadFolder": "Download Ordner",
"downloadSelected": ""
"downloadSelected": "Auswahl herunterladen"
},
"errors": {
"forbidden": "Sie haben keine Berechtigung dies abzurufen.",
"internal": "Etwas ist schief gelaufen.",
"notFound": "Dieser Ort kann nicht angezeigt werden."
"notFound": "Dieser Ort kann nicht angezeigt werden.",
"connection": "Der Server ist nicht erreichbar."
},
"files": {
"body": "Body",
"clear": "Clear",
"clear": "Schließen",
"closePreview": "Vorschau schließen",
"files": "Dateien",
"folders": "Ordner",
@@ -55,44 +61,50 @@
"loading": "Lade...",
"lonely": "Hier scheint nichts zu sein...",
"metadata": "Metadaten",
"multipleSelectionEnabled": "Mehrfachauswahl ausgewählt",
"multipleSelectionEnabled": "Mehrfachauswahl aktiviert",
"name": "Name",
"size": "Größe",
"sortByLastModified": "Nach Änderungsdatum sortieren",
"sortByName": "Nach Namen sortieren",
"sortBySize": "Nach Größe sortieren"
"sortBySize": "Nach Größe sortieren",
"noPreview": "Für diese Datei ist keine Vorschau verfügbar."
},
"help": {
"click": "wähle Datei oder Ordner",
"click": "Wähle Datei oder Ordner",
"ctrl": {
"click": "markiere mehrere Dateien oder Ordner",
"f": "öffnet eine neue Suche",
"s": "speichert eine Datei oder einen Ordner am akutellen Ort"
"click": "Markiere mehrere Dateien oder Ordner",
"f": "Öffnet eine neue Suche",
"s": "Speichert eine Datei oder einen Ordner am akutellen Ort"
},
"del": "löscht die ausgewählten Elemente",
"doubleClick": "öffnet eine Datei oder einen Ordner",
"del": "Löscht die ausgewählten Elemente",
"doubleClick": "Öffnet eine Datei oder einen Ordner",
"esc": "Auswahl zurücksetzen und/oder Dialog schließen",
"f1": "diese Informationsseite",
"f1": "Diese Informationsseite",
"f2": "Datei umbenennen",
"help": "Hilfe"
},
"languages": {
"he": "עברית",
"hu": "Magyar",
"ar": "العربية",
"de": "Deutsch",
"en": "English",
"es": "Español",
"fr": "Français",
"is": "",
"is": "Icelandic",
"it": "Italiano",
"ja": "日本語",
"ko": "한국어",
"nlBE": "",
"nlBE": "Dutch (Belgium)",
"pl": "Polski",
"pt": "Português",
"ptBR": "Português (Brasil)",
"ro": "",
"ro": "Romanian",
"ru": "Русский",
"svSE": "",
"sk": "Slovenčina",
"svSE": "Swedish (Sweden)",
"tr": "Türkçe",
"ua": "Українська",
"zhCN": "中文 (简体)",
"zhTW": "中文 (繁體)"
},
@@ -115,16 +127,17 @@
"currentlyNavigating": "Aktueller Ort:",
"deleteMessageMultiple": "Sind Sie sicher, dass Sie {count} Datei(en) löschen möchten?",
"deleteMessageSingle": "Sind Sie sicher, dass Sie diesen Ordner/diese Datei löschen möchten?",
"deleteMessageShare": "Sind Sie sicher, dass Sie diese Freigabe löschen möchten ({path})?",
"deleteTitle": "Lösche Dateien",
"displayName": "Display Name:",
"displayName": "Anzeigename:",
"download": "Lade Dateien",
"downloadMessage": "Wählen Sie ein Format zum downloaden aus.",
"downloadMessage": "Wählen Sie ein Format zum Herunterladen aus.",
"error": "Etwas ist schief gelaufen",
"fileInfo": "Dateiinformation",
"filesSelected": "{count} Dateien ausgewählt.",
"lastModified": "Zuletzt geändert",
"move": "Verschieben",
"moveMessage": "Wählen sie einen neuen Platz für ihre Datei(en)/Ordner:",
"moveMessage": "Wählen Sie einen neuen Platz für ihre Datei(en)/Ordner:",
"newArchetype": "Erstelle neuen Beitrag auf dem Archetyp. Ihre Datei wird im Inhalteordner erstellt.",
"newDir": "Neuer Ordner",
"newDirMessage": "Geben Sie den Namen des neuen Ordners an.",
@@ -135,21 +148,23 @@
"rename": "Umbenennen",
"renameMessage": "Fügen Sie einen Namen ein für",
"replace": "Ersetzen",
"replaceMessage": "Eine der Datei mit dem gleichen Namen, wie die Sie hochladen wollen, existiert bereits. Soll die vorhandene Datei ersetzt werden ?\n",
"replaceMessage": "Eine der Datei mit dem gleichen Namen, wie die Sie hochladen wollen, existiert bereits. Soll die vorhandene Datei übersprungen oder ersetzt werden?\n",
"schedule": "Plan",
"scheduleMessage": "Wählen Sie ein Datum und eine Zeit für die Veröffentlichung dieses Beitrags.",
"show": "Anzeigen",
"size": "Größe",
"upload": "",
"uploadMessage": ""
"upload": "Upload",
"uploadFiles": "Upload von {files} Dateien...",
"uploadMessage": "Wählen Sie eine Upload-Methode",
"optionalPassword": "Optionales Passwort"
},
"search": {
"images": "Bilder",
"music": "Musik",
"pdf": "PDF",
"pressToSearch": "Drücken sie Enter um zu suchen...",
"pressToSearch": "Drücken Sie Enter um zu suchen...",
"search": "Suche...",
"typeToSearch": "Tippe um zu suchen...",
"typeToSearch": "Tippen um zu suchen...",
"types": "Typen",
"video": "Video"
},
@@ -162,26 +177,31 @@
"allowPublish": "Veröffentlichen von neuen Beiträgen und Seiten",
"allowSignup": "Erlaube Benutzern sich zu registrieren",
"avoidChanges": "(leer lassen um Änderungen zu vermeiden)",
"branding": "Marke",
"brandingDirectoryPath": "Markenverzeichnispfad",
"brandingHelp": "Sie können das Erscheinungsbild ihres File Browser anpassen, in dem sie den Namen ändern, das Logo austauchsen oder eigene Stile definieren und sogar externe Links zu GitHub deaktivieren.\nUm mehr Informationen zum Anpassen an ihre Marke zu bekommen, gehen sie bitte zu {0}.",
"changePassword": "Ändere das Passwort",
"branding": "Design",
"brandingDirectoryPath": "Designverzeichnispfad",
"brandingHelp": "Sie können das Erscheinungsbild Ihres File Browser anpassen, in dem Sie den Namen ändern, das Logo austauchsen oder eigene Stile definieren und sogar externe Links zu GitHub deaktivieren.\nUm mehr Informationen zum Anpassen des Designs zu bekommen, gehen Sie bitte zu {0}.",
"changePassword": "Passwort ändern",
"commandRunner": "Befehlseingabe",
"commandRunnerHelp": "Hier könne sie Befehle eintragen die bei benannten Aktionen ausgeführt werden. Sie müssen pro Zeile jeweils einen eingeben. Die Umgebungsvariable {0} und {1} sind verfügbar, wobei {0} relative zu {1} ist. Für mehr Informationen über diese Funktion und die verfügbaren Umgebungsvariablen, lesen sie bitte das {2}.",
"commandRunnerHelp": "Hier könne Sie Befehle eintragen, welche bei den benannten Aktionen ausgeführt werden. Sie müssen pro Zeile jeweils einen Befehl eingeben. Die Umgebungsvariable {0} und {1} sind verfügbar, wobei {0} relative zu {1} ist. Für mehr Informationen über diese Funktion und die verfügbaren Umgebungsvariablen, lesen Sie bitte die {2}.",
"commandsUpdated": "Befehle aktualisiert!",
"createUserDir": "Auto create user home dir while adding new user",
"createUserDir": "Automatisches Erstellen des Home-Verzeichnisses beim Anlegen neuer Benutzer",
"tusUploads": "Gestückelter Upload",
"tusUploadsHelp": "File Browser unterstützt das Hochladen von gestückelten Dateien und ermöglicht so einen effizienten, zuverlässigen, fortsetzbaren und gestückelten Datei-Upload auch in unzuverlässigen Netzwerken.",
"tusUploadsChunkSize": "Gibt die maximale Größe pro Anfrage an (direkte Uploads werden für kleinere Uploads verwendet). Bitte geben Sie eine Byte-Angabe oder eine Zeichenfolge wie 10 MB, 1 GB usw. an",
"tusUploadsRetryCount": "Anzahl der Wiederholungsversuche, wenn das Hochladen eines Stückes fehlschlägt.",
"customStylesheet": "Individuelles Stylesheet",
"defaultUserDescription": "Das sind die Standard Einstellunge für Benutzer",
"defaultUserDescription": "Das sind die Standardeinstellung für Benutzer",
"disableExternalLinks": "Externe Links deaktivieren (außer Dokumentation)",
"disableUsedDiskPercentage": "Diagramm zur Festplattennutzung deaktivieren",
"documentation": "Dokumentation",
"examples": "Beispiele",
"executeOnShell": "In shell ausführen",
"executeOnShellDescription": "Es ist voreingestellt das der File Brower Befehle ausführt in dem er die Befehlsdatein direkt auf ruft. Wenn sie wollen das sie auf einer Kommandozeile (wo Bash oder PowerShell) laufen, könne sie das hier definieren mit allen bennötigten Argumenten und Optionen. Wenn gesetzt, wird das Kommando das ausgeführt werden soll als Parameter angehängt. Das gilt für Benuzerkommandos sowie auch für Ereignisse.",
"globalRules": "Das ist ein globales Set von Regeln die erlauben oder nicht erlauben. Die sind für alle Benutzer zutreffend. Es können spezielle Regeln in den Einstellungen der Benutzer definiert werden die diese übersteuern.",
"executeOnShell": "In Shell ausführen",
"executeOnShellDescription": "Es ist voreingestellt das der File Brower Befehle ausführt in dem er die Befehlsdateien direkt aufruft. Wenn Sie wollen, dass sie über einer Kommandozeile (wie Bash oder PowerShell) laufen, könne Sie diese hier definieren mit allen bennötigten Argumenten und Optionen. Wenn gesetzt, wird das Kommando das ausgeführt werden soll als Parameter angehängt. Das gilt für Benuzerkommandos sowie auch für Ereignisse.",
"globalRules": "Das ist ein globales Set von Regeln die erlauben oder nicht erlauben. Die sind für alle Benutzer zutreffend. Es können spezielle Regeln in den Einstellungen der Benutzer definiert werden, die diese überschreiben.",
"globalSettings": "Globale Einstellungen",
"hideDotfiles": "",
"hideDotfiles": "Versteckte Dateien ausblenden",
"insertPath": "Pfad einfügen",
"insertRegex": "Regex Ausdruck einfügen",
"insertRegex": "Regulären Ausdruck (Regex) einfügen",
"instanceName": "Instanzname",
"language": "Sprache",
"lockPassword": "Verhindere, dass der Benutzer sein Passwort ändert",
@@ -190,7 +210,7 @@
"newUser": "Neuer Benutzer",
"password": "Passwort",
"passwordUpdated": "Passwort aktualisiert!",
"path": "",
"path": "Pfad",
"perm": {
"create": "Dateien und Ordner erstellen",
"delete": "Dateien und Ordner löschen",
@@ -203,23 +223,25 @@
"permissions": "Berechtigungen",
"permissionsHelp": "Sie können einem Benutzer Administratorrechte einräumen oder die Berechtigunen individuell festlegen. Wenn Sie \"Administrator\" auswählen, werden alle anderen Rechte automatisch vergeben. Die Nutzerverwaltung kann nur durch einen Administrator erfolgen.\n",
"profileSettings": "Profileinstellungen",
"ruleExample1": "Verhindert den Zugang zu dot Dateien (dot Files, wie .git, .gitignore) in allen Ordnern\n",
"ruleExample2": "blockiert den Zugang auf Dateien mit dem Namen Caddyfile in der Wurzel/Basis des scopes.",
"ruleExample1": "Verhindert den Zugang zu versteckten Dateien (dot-Files, wie .git, .gitignore) in allen Ordnern\n",
"ruleExample2": "blockiert den Zugang auf Dateien mit dem Namen Caddyfile in der Wurzel/Basis des Scopes.",
"rules": "Regeln",
"rulesHelp": "Hier können Sie erlaubte und verbotene Aktionen für einen einzelnen Benutzer festlegen. Bockierte Dateien werden nicht im Listing angezeigt und sind nicht erreichbar für den Nutzer. Wir unterstützen reguläre Ausdrücke (Regex) und Pfade die relativ zum Benutzerordner sind. \n",
"rulesHelp": "Hier können Sie erlaubte und verbotene Aktionen für einen einzelnen Benutzer festlegen. Blockierte Dateien werden nicht im Listing angezeigt und sind nicht erreichbar für den Nutzer. Wir unterstützen reguläre Ausdrücke (Regex) und Pfade die relativ zum Benutzerordner sind. \n",
"scope": "Scope",
"setDateFormat": "Exaktes Datumsformat setzen",
"settingsUpdated": "Einstellungen aktualisiert!",
"shareDuration": "",
"shareManagement": "",
"singleClick": "",
"shareDuration": "Dauer",
"shareManagement": "Freigaben verwalten",
"shareDeleted": "Freigabe gelöscht!",
"singleClick": "Einfacher Klick zum Öffnen von Dateien und Ordnern",
"themes": {
"dark": "",
"light": "",
"title": ""
"dark": "Dunkel",
"light": "Hell",
"title": "Erscheinungsbild"
},
"user": "Benutzer",
"userCommands": "Befehle",
"userCommandsHelp": "Eine Liste, mit einem Leerzeichen als Trennung, mit den für diesen Nutzer verfügbaren Befehlen. Example:\n",
"userCommandsHelp": "Eine Liste, mit einem Leerzeichen als Trennung, mit den für diesen Nutzer verfügbaren Befehlen. Beispiel:\n",
"userCreated": "Benutzer angelegt!",
"userDefaults": "Benutzer Standard Einstellungen",
"userDeleted": "Benutzer gelöscht!",
@@ -232,7 +254,7 @@
"help": "Hilfe",
"hugoNew": "Hugo Neu",
"login": "Anmelden",
"logout": "Logout",
"logout": "Abmelden",
"myFiles": "Meine Dateien",
"newFile": "Neue Datei",
"newFolder": "Neuer Ordner",

282
frontend/src/i18n/el.json Normal file
View File

@@ -0,0 +1,282 @@
{
"buttons": {
"cancel": "Ακύρωση",
"close": "Κλείσιμο",
"copy": "Αντιγραφή",
"copyFile": "Αντιγραφή αρχείου",
"copyToClipboard": "Αντιγραφή στο πρόχειρο",
"copyDownloadLinkToClipboard": "Αντιγραφή συνδέσμου λήψης στο πρόχειρο",
"create": "Δημιουργία",
"delete": "Διαγραφή",
"download": "Λήψη",
"file": "Αρχείο",
"folder": "Φάκελος",
"hideDotfiles": "Απόκρυψη κρυφών αρχείων",
"info": "Πληροφορίες",
"more": "Περισσότερα",
"move": "Μετακίνηση",
"moveFile": "Μετακίνηση αρχείου",
"new": "Νέο",
"next": "Επόμενο",
"ok": "Εντάξει",
"permalink": "Λήψη μόνιμου συνδέσμου",
"previous": "Προηγούμενο",
"publish": "Δημοσίευση",
"rename": "Μετονομασία",
"replace": "Αντικατάσταση",
"reportIssue": "Αναφορά προβλήματος",
"save": "Αποθήκευση",
"schedule": "Προγραμματισμός",
"search": "Αναζήτηση",
"select": "Επιλογή",
"selectMultiple": "Επιλογή πολλαπλών",
"share": "Κοινοποίηση",
"submit": "Υποβολή",
"switchView": "Εναλλαγή προβολής",
"toggleSidebar": "(Απ-)ενεργοποίησης της πλευρικής μπάρας",
"update": "Ενημέρωση",
"upload": "Μεταφόρτωση",
"openFile": "Άνοιγμα αρχείου",
"continue": "Συνέχεια"
},
"download": {
"downloadFile": "Λήψη αρχείου",
"downloadFolder": "Λήψη φακέλου",
"downloadSelected": "Λήψη επιλεγμένων"
},
"upload": {
"abortUpload": "Είστε σίγουροι ότι θέλετε να διακόψετε τη μεταφόρτωση;"
},
"errors": {
"forbidden": "Δεν έχετε άδεια πρόσβασης σε αυτό.",
"internal": "Προέκυψε εσωτερικό σφάλμα.",
"notFound": "Αυτή η τοποθεσία δεν μπορεί να βρεθεί.",
"connection": "Ο διακομιστής δεν είναι διαθέσιμος."
},
"files": {
"body": "Περιεχόμενο",
"clear": "Καθαρισμός",
"closePreview": "Κλείσιμο προεπισκόπησης",
"files": "Αρχεία",
"folders": "Φάκελοι",
"home": "Αρχική",
"lastModified": "Τελευταία τροποποίηση",
"loading": "Φορτώνει…",
"lonely": "Δεν υπάρχει τίποτα εδώ (ακόμη)…",
"metadata": "Μεταδεδομένα",
"multipleSelectionEnabled": "Ενεργοποιημένη επιλογή πολλαπλών",
"name": "Όνομα",
"size": "Μέγεθος",
"sortByLastModified": "Ταξινόμηση κατά πρόσφατη τροποποίηση",
"sortByName": "Ταξινόμηση κατά όνομα",
"sortBySize": "Ταξινόμηση κατά μέγεθος",
"noPreview": "Η προεπισκόπηση δεν είναι διαθέσιμη για αυτό το αρχείο."
},
"help": {
"click": "επιλέξτε αρχείο ή φάκελο",
"ctrl": {
"click": "επιλογή πολλαπλών αρχείων ή φακέλων",
"f": "ανοίγει την αναζήτηση",
"s": "αποθηκεύει ένα αρχείο ή εκκινεί λήψη του φακέλου στον οποίο βρίσκεστε"
},
"del": "διαγραφή επιλεγμένων στοιχείων",
"doubleClick": "ανοίγει ένα αρχείο ή φάκελο",
"esc": "καθαρίζει την επιλογή ή/και κλείνει το παράθυρο",
"f1": "αυτή η πληροφορία",
"f2": "μετονομασία αρχείου",
"help": "Βοήθεια"
},
"languages": {
"he": "עברית",
"hu": "Magyar",
"ar": "العربية",
"de": "Deutsch",
"en": "English",
"es": "Español",
"el": "Ελληνικά",
"fr": "Français",
"is": "Icelandic",
"it": "Italiano",
"ja": "日本語",
"ko": "한국어",
"nlBE": "Dutch (Belgium)",
"pl": "Polski",
"pt": "Português",
"ptBR": "Português (Brasil)",
"ro": "Romanian",
"ru": "Русский",
"sk": "Slovenčina",
"svSE": "Swedish (Sweden)",
"tr": "Türkçe",
"ua": "Українська",
"zhCN": "中文 (简体)",
"zhTW": "中文 (繁體)"
},
"login": {
"createAnAccount": "Δημιουργία λογαριασμού",
"loginInstead": "Έχετε ήδη λογαριασμό",
"password": "Κωδικός πρόσβασης",
"passwordConfirm": "Επιβεβαίωση κωδικού πρόσβασης",
"passwordsDontMatch": "Οι κωδικοί πρόσβασης δεν ταιριάζουν",
"signup": "Εγγραφή",
"submit": "Είσοδος",
"username": "Όνομα χρήστη",
"usernameTaken": "Το όνομα χρήστη χρησιμοποιείται ήδη",
"wrongCredentials": "Λάθος όνομα ή/και κωδικός πρόσβασης"
},
"permanent": "Μόνιμο",
"prompts": {
"copy": "Αντιγραφή",
"copyMessage": "Επιλέξτε τοποθεσία για αντιγραφή των αρχείων σας:",
"deleteMessageMultiple": "Είστε σίγουροι ότι θέλετε να διαγράψετε {count} αρχεία;",
"deleteMessageSingle": "Είστε σίγουροι ότι θέλετε να διαγράψετε αυτό το αρχείο/φάκελο;",
"deleteMessageShare": "Είστε σίγουροι ότι θέλετε να διαγράψετε αυτή την κοινοποίηση ({path});",
"deleteTitle": "Διαγραφή αρχείων",
"displayName": "Εμφάνιση ονόματος:",
"download": "Λήψη αρχείων",
"downloadMessage": "Επιλέξτε τη μορφή που θέλετε να λάβετε.",
"error": "Προέκυψε κάποιο σφάλμα",
"fileInfo": "Πληροφορίες αρχείου",
"filesSelected": "Επιλέχθηκαν {count} αρχεία.",
"lastModified": "Τελευταία τροποποίηση",
"move": "Μετακίνηση",
"moveMessage": "Επιλέξτε νέα τοποθεσία για τα αρχεία / τους φακέλους σας:",
"newArchetype": "Δημιουργία νέας ανάρτησης με βάση έναν αρχέτυπο. Το αρχείο σας θα δημιουργηθεί στο φάκελο περιεχομένου.",
"newDir": "Νέος φάκελος",
"newDirMessage": "Γράψτε το όνομα του νέου φακέλου.",
"newFile": "Νέο αρχείο",
"newFileMessage": "Γράψτε το όνομα του νέου αρχείου.",
"numberDirs": "Αριθμός φακέλων",
"numberFiles": "Αριθμός αρχείων",
"rename": "Μετονομασία",
"renameMessage": "Εισαγάγετε ένα νέο όνομα για το",
"replace": "Αντικατάσταση",
"replaceMessage": "Ένα από τα αρχεία που προσπαθείτε να μεταφορτώσετε δημιουργεί σύγκρουση με υπάρχον αρχείο λόγω του ονόματός του. Θέλετε να συνεχίσετε τη μεταφόρτωση ή να αντικαταστήσετε το υπάρχον;\n",
"schedule": "Προγραμματισμός",
"scheduleMessage": "Επιλέξτε μια ημερομηνία και ώρα για τον προγραμματισμό της δημοσίευσης αυτής της ανάρτησης.",
"show": "Εμφάνιση",
"size": "Μέγεθος",
"upload": "Μεταφόρτωση",
"uploadFiles": "Μεταφόρτωση {files} αρχείων…",
"uploadMessage": "Επιλέξτε μια επιλογή για τη μεταφόρτωση.",
"optionalPassword": "Προαιρετικός κωδικός πρόσβασης"
},
"search": {
"images": "Εικόνες",
"music": "Μουσική",
"pdf": "PDF",
"pressToSearch": "Πατήστε Enter για αναζήτηση…",
"search": "Αναζήτηση…",
"typeToSearch": "Πληκτρολογήστε για αναζήτηση…",
"types": "Τύποι",
"video": "Βίντεο"
},
"settings": {
"admin": "Διαχειριστής",
"administrator": "Διαχειριστής",
"allowCommands": "Εκτέλεση εντολών",
"allowEdit": "Επεξεργασία, μετονομασία και διαγραφή αρχείων ή φακέλων",
"allowNew": "Δημιουργία νέων αρχείων και φακέλων",
"allowPublish": "Δημοσίευση νέων αναρτήσεων και σελίδων",
"allowSignup": "Να επιτρέπεται η εγγραφή νέων χρηστών",
"avoidChanges": "(αφήστε το κενό για αποφυγή αλλαγών)",
"branding": "Εξατομίκευση",
"brandingDirectoryPath": "Διαδρομή φακέλου εξατομίκευσης",
"brandingHelp": "Μπορείτε να προσαρμόσετε την εμφάνισης της εφαρμογής File Browser αλλάζοντας το όνομά της, αντικαθιστώντας το λογότυπό της, προσθέτοντας προσαρμοσμένα στυλ και ακόμα και απενεργοποιώντας εξωτερικούς συνδέσμους προς το GitHub.\nΓια περισσότερες πληροφορίες σχετικά με αυτές τις προσαρμογές, ελέγξτε το {0}.",
"changePassword": "Αλλαγή κωδικού πρόσβασης",
"commandRunner": "Εκτέλεση εντολών",
"commandRunnerHelp": "Εδώ μπορείτε να ορίσετε εντολές που εκτελούνται στα ονομασμένα γεγονότα και δραστηριότητες. Πρέπει να γράψετε μία εντολή ανά γραμμή. Οι μεταβλητές περιβάλλοντος {0} και {1} θα είναι διαθέσιμες, και θα είναι {0} σχετικές με το {1}. Για περισσότερες πληροφορίες σχετικά με αυτή τη λειτουργία και τις διαθέσιμες μεταβλητές περιβάλλοντος, παρακαλώ διαβάστε το {2}.",
"commandsUpdated": "Οι εντολές ενημερώθηκαν!",
"createUserDir": "Αυτόματη δημιουργία φακέλου χρήστη κατά την προσθήκη νέου χρήστη",
"tusUploads": "Τμηματικές μεταφορές αρχείων",
"tusUploadsHelp": "Η εφαρμογή File Browser υποστηρίζει τμηματικές μεταφορτώσεις αρχείων, επιτρέποντας την αποδοτική, αξιόπιστη και συνεχιζόμενη μεταφόρτωση αρχείων ακόμα και σε ασταθείς συνδέσεις δικτύου.",
"tusUploadsChunkSize": "Υποδεικνύει το μέγιστο μέγεθος ενός αιτήματος μεταφόρτωσης (για μικρότερες μεταφορές αρχείων θα χρησιμοποιηθούν απευθείας και όχι τμηματικές μεταφορτώσεις). Μπορείτε να εισάγετε έναν ακέραιο αριθμό που υποδηλώνει το μέγεθος σε bytes, ή κείμενο με αριθμό και μονάδα μέτρησης μεγέθους δεδομένων, όπως 10MB, 1GB κλπ.",
"tusUploadsRetryCount": "Αριθμός επαναληπτικών δοκιμών που θα πραγματοποιηθούν αν αποτύχει η μεταφόρτωση ενός τμήματος.",
"userHomeBasePath": "Βασική διαδρομή αρχείων για τους φακέλους των χρηστών",
"userScopeGenerationPlaceholder": "Η εμβέλεια εφαρμογής θα δημιουργηθεί αυτόματα",
"createUserHomeDirectory": "Δημιουργία φακέλου χρήστη",
"customStylesheet": "Προσαρμοσμένο στυλ εμφάνισης (stylesheet)",
"defaultUserDescription": "Αυτές είναι οι προεπιλεγμένες ρυθμίσεις για νέους χρήστες.",
"disableExternalLinks": "Απενεργοποίηση εξωτερικών συνδέσμων (εκτός από συνδέσμους προς τις οδηγίες χρήσης)",
"disableUsedDiskPercentage": "Απενεργοποίηση γραφήματος ποσοστού χρήσης χώρου αποθήκευσης",
"documentation": "οδηγίες χρήσης",
"examples": "Παραδείγματα",
"executeOnShell": "Εκτέλεση στο κέλυφος",
"executeOnShellDescription": "Από προεπιλογή, η εφαρμογή File Browser εκτελεί τις εντολές καλώντας τα προγράμματα των εντολών απευθείας. Αν θέλετε να τις εκτελέσετε σε ένα κέλυφος (όπως το Bash ή το PowerShell), μπορείτε να το καθορίσετε εδώ με τις απαιτούμενες παραμέτρους. Εάν οριστεί, η εντολή που εκτελείτε θα προστίθεται ως παράμετρος. Αυτό ισχύει τόσο για τις εντολές χρήστη όσο και για τους αγκίστρους συμβάντων (event hooks).",
"globalRules": "Πρόκειται για ένα γενικό σύνολο κανόνων που επιτρέπουν και απαγορεύουν διάφορες λειτουργίες και ισχύουν για κάθε χρήστη. Μπορείτε να καθορίσετε συγκεκριμένους κανόνες στις ρυθμίσεις κάθε χρήστη για να παρακάμψετε τους γενικούς κανόνες.",
"globalSettings": "Γενικές ρυθμίσεις",
"hideDotfiles": "Απόκρυψη κρυφών αρχείων (dotfiles)",
"insertPath": "Εισάγετε διαδρομή",
"insertRegex": "Εισάγετε έκφραση regex",
"instanceName": "Όνομα περιβάλλοντος",
"language": "Γλώσσα",
"lockPassword": "Αποτρέψτε τον χρήστη από την αλλαγή του κωδικού πρόσβασης",
"newPassword": "Νέος κωδικός πρόσβασης",
"newPasswordConfirm": "Επιβεβαιώστε τον νέο κωδικό πρόσβασης",
"newUser": "Νέος χρήστης",
"password": "Κωδικός πρόσβασης",
"passwordUpdated": "Ο κωδικός πρόσβασης ενημερώθηκε!",
"path": "Διαδρομή",
"perm": {
"create": "Δημιουργία αρχείων και φακέλων",
"delete": "Διαγραφή αρχείων και φακέλων",
"download": "Λήψη",
"execute": "Εκτέλεση εντολών",
"modify": "Επεξεργασία αρχείων",
"rename": "Μετονομασία ή μετακίνηση αρχείων και φακέλων",
"share": "Κοινοποίηση αρχείων"
},
"permissions": "Δικαιώματα",
"permissionsHelp": "Μπορείτε να ορίσετε τον χρήστη ως διαχειριστή ή να επιλέξετε τα δικαιώματα μεμονωμένα. Αν επιλέξετε \"Διαχειριστής\", όλες οι υπόλοιπες επιλογές θα είναι αυτόματα επιλεγμένες. Η διαχείριση χρηστών παραμένει προνόμιο ενός χρήστη με τον ρόλο του διαχειριστή.\n",
"profileSettings": "Ρυθμίσεις προφίλ",
"ruleExample1": "αποκλείει την πρόσβαση σε οποιοδήποτε κρυφό αρχείο (όπως .git, .gitignore) σε κάθε φάκελο.\n",
"ruleExample2": "αποκλείει την πρόσβαση στο αρχείο με το όνομα Caddyfile στον ριζικό φάκελο της εμβέλειας του κανόνα.",
"rules": "Κανόνες",
"rulesHelp": "Εδώ μπορείτε να ορίσετε ένα σύνολο κανόνων που επιτρέπουν και απαγορεύουν διάφορες λειτουργίες για τον συγκεκριμένο χρήστη. Τα αποκλεισμένα αρχεία δεν θα εμφανίζονται στα περιεχόμενα των αντίστοιχων φακέλων και δεν θα είναι προσβάσιμα από τον χρήστη. Υποστηρίζονται εκφράσεις regex και διαδρομές σχετικές με την εμβέλεια αρχείων των χρηστών.\n",
"scope": "Εμβέλεια",
"setDateFormat": "Ορισμός ακριβούς μορφής ημερομηνίας",
"settingsUpdated": "Οι ρυθμίσεις ενημερώθηκαν!",
"shareDuration": "Διάρκεια κοινοποίησης",
"shareManagement": "Διαχείριση κοινοποίησης",
"shareDeleted": "Η κοινοποίηση διαγράφηκε!",
"singleClick": "Χρήση μονού κλικ για να ανοίξετε αρχεία και φακέλους",
"themes": {
"dark": "Σκοτεινό",
"light": "Φωτεινό",
"title": "Μοτίβο"
},
"user": "Χρήστης",
"userCommands": "Εντολές χρήστη",
"userCommandsHelp": "Μια λίστα με τις διαθέσιμες εντολές για αυτόν το χρήστη, χωρισμένες μεταξύ τους με κενά. Παράδειγμα:\n",
"userCreated": "Ο χρήστης δημιουργήθηκε!",
"userDefaults": "Προεπιλεγμένες ρυθμίσεις χρήστη",
"userDeleted": "Ο χρήστης διαγράφηκε!",
"userManagement": "Διαχείριση χρηστών",
"userUpdated": "Ο χρήστης ενημερώθηκε!",
"username": "Όνομα χρήστη",
"users": "Χρήστες"
},
"sidebar": {
"help": "Βοήθεια",
"hugoNew": "Νέο Hugo",
"login": "Σύνδεση",
"logout": "Αποσύνδεση",
"myFiles": "Τα αρχεία μου",
"newFile": "Νέο αρχείο",
"newFolder": "Νέος φάκελος",
"preview": "Προεπισκόπηση",
"settings": "Ρυθμίσεις",
"signup": "Εγγραφή",
"siteSettings": "Ρυθμίσεις ιστότοπου"
},
"success": {
"linkCopied": "Ο σύνδεσμος αντιγράφηκε!"
},
"time": {
"days": "Ημέρες",
"hours": "Ώρες",
"minutes": "Λεπτά",
"seconds": "Δευτερόλεπτα",
"unit": "Μονάδα χρόνου"
}
}

View File

@@ -5,9 +5,12 @@
"copy": "Copy",
"copyFile": "Copy file",
"copyToClipboard": "Copy to clipboard",
"copyDownloadLinkToClipboard": "Copy download link to clipboard",
"create": "Create",
"delete": "Delete",
"download": "Download",
"file": "File",
"folder": "Folder",
"hideDotfiles": "Hide dotfiles",
"info": "Info",
"more": "More",
@@ -34,13 +37,18 @@
"toggleSidebar": "Toggle sidebar",
"update": "Update",
"upload": "Upload",
"openFile": "Open file"
"openFile": "Open file",
"continue": "Continue",
"discardChanges": "Discard"
},
"download": {
"downloadFile": "Download File",
"downloadFolder": "Download Folder",
"downloadSelected": "Download Selected"
},
"upload": {
"abortUpload": "Are you sure you wish to abort?"
},
"errors": {
"forbidden": "You don't have permissions to access this.",
"internal": "Something really went wrong.",
@@ -63,7 +71,8 @@
"size": "Size",
"sortByLastModified": "Sort by last modified",
"sortByName": "Sort by name",
"sortBySize": "Sort by size"
"sortBySize": "Sort by size",
"noPreview": "Preview is not available for this file."
},
"help": {
"click": "select file or directory",
@@ -80,8 +89,11 @@
"help": "Help"
},
"languages": {
"he": "עברית",
"hu": "Magyar",
"ar": "العربية",
"de": "Deutsch",
"el": "Ελληνικά",
"en": "English",
"es": "Español",
"fr": "Français",
@@ -95,7 +107,10 @@
"ptBR": "Português (Brasil)",
"ro": "Romanian",
"ru": "Русский",
"sk": "Slovenčina",
"svSE": "Swedish (Sweden)",
"tr": "Türkçe",
"ua": "Українська",
"zhCN": "中文 (简体)",
"zhTW": "中文 (繁體)"
},
@@ -114,39 +129,42 @@
"permanent": "Permanent",
"prompts": {
"copy": "Copy",
"copyMessage": "Choose the place to copy your files:",
"copyMessage": "Choose the location to copy your files to:",
"currentlyNavigating": "Currently navigating on:",
"deleteMessageMultiple": "Are you sure you want to delete {count} file(s)?",
"deleteMessageSingle": "Are you sure you want to delete this file/folder?",
"deleteMessageShare": "Are you sure you want to delete this share({path})?",
"deleteMessageMultiple": "Are you sure you wish to delete {count} file(s)?",
"deleteMessageSingle": "Are you sure you wish to delete this file/folder?",
"deleteMessageShare": "Are you sure you wish to delete this share({path})?",
"deleteTitle": "Delete files",
"displayName": "Display Name:",
"download": "Download files",
"downloadMessage": "Choose the format you want to download.",
"downloadMessage": "Choose the format you wish to download.",
"error": "Something went wrong",
"fileInfo": "File information",
"filesSelected": "{count} files selected.",
"lastModified": "Last Modified",
"move": "Move",
"moveMessage": "Choose new house for your file(s)/folder(s):",
"moveMessage": "Choose new home for your file(s)/folder(s):",
"newArchetype": "Create a new post based on an archetype. Your file will be created on content folder.",
"newDir": "New directory",
"newDirMessage": "Write the name of the new directory.",
"newDirMessage": "Name your new directory.",
"newFile": "New file",
"newFileMessage": "Write the name of the new file.",
"newFileMessage": "Name your new file.",
"numberDirs": "Number of directories",
"numberFiles": "Number of files",
"rename": "Rename",
"renameMessage": "Insert a new name for",
"replace": "Replace",
"replaceMessage": "One of the files you're trying to upload is conflicting because of its name. Do you wish to replace the existing one?\n",
"replaceMessage": "One of the files you're trying to upload has a conflicting name. Do you wish to skip this file and continue to upload or replace the existing one?\n",
"schedule": "Schedule",
"scheduleMessage": "Pick a date and time to schedule the publication of this post.",
"show": "Show",
"size": "Size",
"upload": "Upload",
"uploadFiles": "Uploading {files} files...",
"uploadMessage": "Select an option to upload.",
"optionalPassword": "Optional password"
"optionalPassword": "Optional password",
"resolution": "Resolution",
"discardEditorChanges": "Are you sure you wish to discard the changes you've made?"
},
"search": {
"images": "Images",
@@ -175,14 +193,22 @@
"commandRunnerHelp": "Here you can set commands that are executed in the named events. You must write one per line. The environment variables {0} and {1} will be available, being {0} relative to {1}. For more information about this feature and the available environment variables, please read the {2}.",
"commandsUpdated": "Commands updated!",
"createUserDir": "Auto create user home dir while adding new user",
"tusUploads": "Chunked Uploads",
"tusUploadsHelp": "File Browser supports chunked file uploads, allowing for the creation of efficient, reliable, resumable and chunked file uploads even on unreliable networks.",
"tusUploadsChunkSize": "Indicates to maximum size of a request (direct uploads will be used for smaller uploads). You may input a plain integer denoting byte size input or a string like 10MB, 1GB etc.",
"tusUploadsRetryCount": "Number of retries to perform if a chunk fails to upload.",
"userHomeBasePath": "Base path for user home directories",
"userScopeGenerationPlaceholder": "The scope will be auto generated",
"createUserHomeDirectory": "Create user home directory",
"customStylesheet": "Custom Stylesheet",
"defaultUserDescription": "This are the default settings for new users.",
"defaultUserDescription": "These are the default settings for new users.",
"disableExternalLinks": "Disable external links (except documentation)",
"disableUsedDiskPercentage": "Disable used disk percentage graph",
"documentation": "documentation",
"examples": "Examples",
"executeOnShell": "Execute on shell",
"executeOnShellDescription": "By default, File Browser executes the commands by calling their binaries directly. If you want to run them on a shell instead (such as Bash or PowerShell), you can define it here with the required arguments and flags. If set, the command you execute will be appended as an argument. This apply to both user commands and event hooks.",
"globalRules": "This is a global set of allow and disallow rules. They apply to every user. You can define specific rules on each user's settings to override this ones.",
"executeOnShellDescription": "By default, File Browser executes the commands by calling their binaries directly. If you wish to run them on a shell instead (such as Bash or PowerShell), you can define it here with the required arguments and flags. If set, the command you execute will be appended as an argument. This applies to both user commands and event hooks.",
"globalRules": "This is a global set of allow and disallow rules. They apply to every user. You can define specific rules on each user's settings to override these ones.",
"globalSettings": "Global Settings",
"hideDotfiles": "Hide dotfiles",
"insertPath": "Insert the path",
@@ -208,11 +234,12 @@
"permissions": "Permissions",
"permissionsHelp": "You can set the user to be an administrator or choose the permissions individually. If you select \"Administrator\", all of the other options will be automatically checked. The management of users remains a privilege of an administrator.\n",
"profileSettings": "Profile Settings",
"ruleExample1": "prevents the access to any dot file (such as .git, .gitignore) in every folder.\n",
"ruleExample1": "prevents the access to any dotfile (such as .git, .gitignore) in every folder.\n",
"ruleExample2": "blocks the access to the file named Caddyfile on the root of the scope.",
"rules": "Rules",
"rulesHelp": "Here you can define a set of allow and disallow rules for this specific user. The blocked files won't show up in the listings and they wont be accessible to the user. We support regex and paths relative to the users scope.\n",
"scope": "Scope",
"setDateFormat": "Set exact date format",
"settingsUpdated": "Settings updated!",
"shareDuration": "Share Duration",
"shareManagement": "Share Management",

Some files were not shown because too many files have changed in this diff Show More