Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7e78ad97ad | ||
|
|
0467326d5c | ||
|
|
63a76ef18c | ||
|
|
3cad9a2b0e | ||
|
|
804b14b698 | ||
|
|
95e6ed75a7 | ||
|
|
b09960e538 | ||
|
|
5e8f5be245 | ||
|
|
e5bc0d3cce | ||
|
|
f67bccf8c5 | ||
|
|
88b97def9e | ||
|
|
1f7904dad2 | ||
|
|
5feaf66575 | ||
|
|
c94870fcfe | ||
|
|
6a76dfeba9 | ||
|
|
e193d43278 | ||
|
|
489af403a1 | ||
|
|
ff2f00498c | ||
|
|
2957b4605b | ||
|
|
099dfb0ae8 | ||
|
|
a4289011ef | ||
|
|
942d59848a | ||
|
|
854e5371b6 | ||
|
|
b9df030e6e | ||
|
|
2b82612e3f | ||
|
|
08d7a1504c | ||
|
|
b8da36e630 | ||
|
|
a8fe32f4aa | ||
|
|
8fee2561af | ||
|
|
d441b28f43 | ||
|
|
87cfead033 | ||
|
|
3a08949c7f | ||
|
|
b594d4d4e2 | ||
|
|
1053aace8c | ||
|
|
004488c15b | ||
|
|
3032a1fade | ||
|
|
87f1d00fd7 | ||
|
|
f0f2f1ff06 | ||
|
|
08c8ede587 | ||
|
|
1154b49974 | ||
|
|
785b7abb7b | ||
|
|
550a73b6ba | ||
|
|
e7ea1ad27d | ||
|
|
24781badd4 | ||
|
|
4094fb359b | ||
|
|
cfa6c5864e | ||
|
|
59ca0c340a | ||
|
|
037e29a708 | ||
|
|
fda8a99292 | ||
|
|
208535a8cc | ||
|
|
464b581953 | ||
|
|
20312ff18e | ||
|
|
219582c0b0 | ||
|
|
4fd18a382c | ||
|
|
94ec786d34 | ||
|
|
25e9b85259 | ||
|
|
ffa893e9ac | ||
|
|
b8151a038a | ||
|
|
943e5340d0 | ||
|
|
88aa56f53b | ||
|
|
a12a612970 | ||
|
|
a2d80c62c1 | ||
|
|
1faa21844f | ||
|
|
7a93b2a062 | ||
|
|
032d6c7520 | ||
|
|
9595f3939c | ||
|
|
60b1ee8bb9 | ||
|
|
79d1aa9229 | ||
|
|
20bfd131c6 | ||
|
|
f89975603e | ||
|
|
2d3b64ecf6 | ||
|
|
579756dbb5 |
@@ -34,7 +34,7 @@ jobs:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: "1.25.x"
|
||||
go-version: "1.26.x"
|
||||
- uses: golangci/golangci-lint-action@v9
|
||||
with:
|
||||
version: "latest"
|
||||
@@ -46,7 +46,7 @@ jobs:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: "1.25.x"
|
||||
go-version: "1.26.x"
|
||||
- run: go test --race ./...
|
||||
|
||||
build:
|
||||
@@ -58,7 +58,7 @@ jobs:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: '1.25'
|
||||
go-version: '1.26'
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
package_json_file: "frontend/package.json"
|
||||
@@ -82,7 +82,7 @@ jobs:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: '1.25'
|
||||
go-version: '1.26'
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
package_json_file: "frontend/package.json"
|
||||
|
||||
@@ -17,6 +17,7 @@ builds:
|
||||
- linux
|
||||
- windows
|
||||
- freebsd
|
||||
- openbsd
|
||||
goarch:
|
||||
- amd64
|
||||
- "386"
|
||||
@@ -30,6 +31,12 @@ builds:
|
||||
ignore:
|
||||
- goos: darwin
|
||||
goarch: "386"
|
||||
# Experimental, may not work properly
|
||||
- goos: openbsd
|
||||
goarch: riscv64
|
||||
# Broken as of Go 1.24, deprecated as of Go 1.26
|
||||
- goos: windows
|
||||
goarch: arm
|
||||
- goos: freebsd
|
||||
goarch: arm
|
||||
|
||||
|
||||
+122
@@ -2,6 +2,128 @@
|
||||
|
||||
All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines.
|
||||
|
||||
## [2.59.0](https://github.com/filebrowser/filebrowser/compare/v2.58.0...v2.59.0) (2026-02-15)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add 'Open direct' button to images ([#5678](https://github.com/filebrowser/filebrowser/issues/5678)) ([804b14b](https://github.com/filebrowser/filebrowser/commit/804b14b698aa218fa5c2aaba687e72c5f7617f0f))
|
||||
* Updates for project File Browser ([#5760](https://github.com/filebrowser/filebrowser/issues/5760)) ([63a76ef](https://github.com/filebrowser/filebrowser/commit/63a76ef18c51121e08634810a894c1e22a870428))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* render equations in markdown preview ([#5745](https://github.com/filebrowser/filebrowser/issues/5745)) ([0467326](https://github.com/filebrowser/filebrowser/commit/0467326d5c082c42c0ede88ee2d3472f5fb65600))
|
||||
|
||||
## [2.58.0](https://github.com/filebrowser/filebrowser/compare/v2.57.1...v2.58.0) (2026-02-14)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* nederlands ([88b97de](https://github.com/filebrowser/filebrowser/commit/88b97def9ee72fe6e8094209aebb71830b7305be))
|
||||
* support for multiple encodings in CSV files ([#5756](https://github.com/filebrowser/filebrowser/issues/5756)) ([f67bccf](https://github.com/filebrowser/filebrowser/commit/f67bccf8c5470cb280fe854d92aa2666c270bcf5))
|
||||
* Updates for project File Browser ([#5749](https://github.com/filebrowser/filebrowser/issues/5749)) ([c94870f](https://github.com/filebrowser/filebrowser/commit/c94870fcfe1b4acb2db9ab897b9f7d35e3b75770))
|
||||
* Updates for project File Browser ([#5759](https://github.com/filebrowser/filebrowser/issues/5759)) ([5e8f5be](https://github.com/filebrowser/filebrowser/commit/5e8f5be245fd0126545ef5ca61c2d428ac128ad5))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **frontend:** pnpm lock ([b09960e](https://github.com/filebrowser/filebrowser/commit/b09960e538387ff29371c80be1584720f65181e7))
|
||||
* ignore version.go ([1f7904d](https://github.com/filebrowser/filebrowser/commit/1f7904dad21a87f04e1543ee10b60ce79e5eebe9))
|
||||
* respect Accept-Encoding for pre-compressed JS ([#5750](https://github.com/filebrowser/filebrowser/issues/5750)) ([6a76dfe](https://github.com/filebrowser/filebrowser/commit/6a76dfeba9254a938e320928c67d110f73f83715))
|
||||
* wrap response text in Error before reject ([#5753](https://github.com/filebrowser/filebrowser/issues/5753)) ([e5bc0d3](https://github.com/filebrowser/filebrowser/commit/e5bc0d3cce18fa7b069688b176b99efbb67382d2))
|
||||
|
||||
## [2.57.1](https://github.com/filebrowser/filebrowser/compare/v2.57.0...v2.57.1) (2026-02-08)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* normalize fields capitalization ([ff2f004](https://github.com/filebrowser/filebrowser/commit/ff2f00498cff151e2fb1f5f0b16963bf33c3d6d4))
|
||||
* remove skip clean ([489af40](https://github.com/filebrowser/filebrowser/commit/489af403a19057f6b6b4b1dc0e48cbb26a202ef9))
|
||||
|
||||
## [2.57.0](https://github.com/filebrowser/filebrowser/compare/v2.56.0...v2.57.0) (2026-02-01)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Add Redis upload cache for multi-replica deployments ([#5724](https://github.com/filebrowser/filebrowser/issues/5724)) ([08d7a15](https://github.com/filebrowser/filebrowser/commit/08d7a1504c42c115fdd82d3845694fe87147f1db))
|
||||
* Updates for project File Browser ([#5725](https://github.com/filebrowser/filebrowser/issues/5725)) ([8fee256](https://github.com/filebrowser/filebrowser/commit/8fee2561afbf968ed577bc4139562a42b2278243))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* adjust yaml config decodification to yaml.v3 ([#5722](https://github.com/filebrowser/filebrowser/issues/5722)) ([b594d4d](https://github.com/filebrowser/filebrowser/commit/b594d4d4e28a1b35e69d81d2c35948fe0d629888))
|
||||
* avoid 409 conflict when renaming files differing only by case ([#5729](https://github.com/filebrowser/filebrowser/issues/5729)) ([d441b28](https://github.com/filebrowser/filebrowser/commit/d441b28f432c3448a29ac828400321f1f4ed32d9))
|
||||
|
||||
## [2.56.0](https://github.com/filebrowser/filebrowser/compare/v2.55.0...v2.56.0) (2026-01-24)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Updates for project File Browser ([#5698](https://github.com/filebrowser/filebrowser/issues/5698)) ([f0f2f1f](https://github.com/filebrowser/filebrowser/commit/f0f2f1ff069aae566d8bf25ec275da59f29a96bc))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* adjust columns of the table from the "users ls" command ([#5716](https://github.com/filebrowser/filebrowser/issues/5716)) ([3032a1f](https://github.com/filebrowser/filebrowser/commit/3032a1fade43737c51c49b5ccda34f336394c2ed))
|
||||
* avoid clearing selection when clicking elements outside the empty area ([#5715](https://github.com/filebrowser/filebrowser/issues/5715)) ([004488c](https://github.com/filebrowser/filebrowser/commit/004488c15b3c30784e1ea564b3ca9feec7bcad08))
|
||||
|
||||
## [2.55.0](https://github.com/filebrowser/filebrowser/compare/v2.54.0...v2.55.0) (2026-01-18)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* added cut, copy, paste and show command palette functions in header ([#5648](https://github.com/filebrowser/filebrowser/issues/5648)) ([785b7ab](https://github.com/filebrowser/filebrowser/commit/785b7abb7ba7a86cc0deae1052c319ff714c222c))
|
||||
* update translations ([#5677](https://github.com/filebrowser/filebrowser/issues/5677)) ([e7ea1ad](https://github.com/filebrowser/filebrowser/commit/e7ea1ad27d3d17e249489d3338be40bfea15e2a1))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* prevent context menu clicks from clearing file selection ([#5681](https://github.com/filebrowser/filebrowser/issues/5681)) ([59ca0c3](https://github.com/filebrowser/filebrowser/commit/59ca0c340afc7774747c70ede9a5a5a3c9349d6b))
|
||||
* request current password when deleting users ([#5667](https://github.com/filebrowser/filebrowser/issues/5667)) ([cfa6c58](https://github.com/filebrowser/filebrowser/commit/cfa6c5864e5e7673aa9f3180e4964e0db92cc4da))
|
||||
* retain file selection when closing the editor ([#5693](https://github.com/filebrowser/filebrowser/issues/5693)) ([4094fb3](https://github.com/filebrowser/filebrowser/commit/4094fb359babac70e88d0ed4bfe3bd100744aad6))
|
||||
|
||||
## [2.54.0](https://github.com/filebrowser/filebrowser/compare/v2.53.1...v2.54.0) (2026-01-10)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add "redirect after copy/move" user setting ([#5662](https://github.com/filebrowser/filebrowser/issues/5662)) ([fda8a99](https://github.com/filebrowser/filebrowser/commit/fda8a992929b1466e75fb2813f2c4e293c12d244))
|
||||
* force file sync while uploading file ([#5668](https://github.com/filebrowser/filebrowser/issues/5668)) ([4fd18a3](https://github.com/filebrowser/filebrowser/commit/4fd18a382c31bbe7059d6733ffa371e70051865b))
|
||||
* update translations ([#5659](https://github.com/filebrowser/filebrowser/issues/5659)) ([464b581](https://github.com/filebrowser/filebrowser/commit/464b581953139c17e3276b774e381e4052827125))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* clear selection by clicking on empty area ([#5663](https://github.com/filebrowser/filebrowser/issues/5663)) ([208535a](https://github.com/filebrowser/filebrowser/commit/208535a8cc23254de0013dfab9008486707ee6c2))
|
||||
* hide "change password form" in noauth setting ([#5652](https://github.com/filebrowser/filebrowser/issues/5652)) ([219582c](https://github.com/filebrowser/filebrowser/commit/219582c0b03fd90979b1d1398dba7919d086a23f))
|
||||
|
||||
## [2.53.1](https://github.com/filebrowser/filebrowser/compare/v2.53.0...v2.53.1) (2026-01-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* download path encoding file paths ([#5655](https://github.com/filebrowser/filebrowser/issues/5655)) ([ffa893e](https://github.com/filebrowser/filebrowser/commit/ffa893e9ac387a49dba5917a41df7c3b7ce120fc))
|
||||
* request a password to change sensitive user data ([#5629](https://github.com/filebrowser/filebrowser/issues/5629)) ([b8151a0](https://github.com/filebrowser/filebrowser/commit/b8151a038a1ea55afae8073b439b74e364cac12f))
|
||||
|
||||
## [2.53.0](https://github.com/filebrowser/filebrowser/compare/v2.52.0...v2.53.0) (2025-12-29)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add "disable image resolution calculation" flag ([#5638](https://github.com/filebrowser/filebrowser/issues/5638)) ([a2d80c6](https://github.com/filebrowser/filebrowser/commit/a2d80c62c1c17962e566f68fb7cac6960ed3e4cb))
|
||||
* support streaming response for search results ([#5630](https://github.com/filebrowser/filebrowser/issues/5630)) ([20bfd13](https://github.com/filebrowser/filebrowser/commit/20bfd131c6a4fca48a645b52171c2d1cc3ce92b7))
|
||||
* update translations ([a12a612](https://github.com/filebrowser/filebrowser/commit/a12a612970d6cc3dfbca1b35ef3a60a887a4effb))
|
||||
* update translations ([#5626](https://github.com/filebrowser/filebrowser/issues/5626)) ([f899756](https://github.com/filebrowser/filebrowser/commit/f89975603e29b9f1fc05aec58afb42bbd56ed696))
|
||||
* update translations ([#5631](https://github.com/filebrowser/filebrowser/issues/5631)) ([032d6c7](https://github.com/filebrowser/filebrowser/commit/032d6c7520a64686c9d9b1218562256f629b4703))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* conversion of backslashes in file paths for archive creation ([#5637](https://github.com/filebrowser/filebrowser/issues/5637)) ([9595f39](https://github.com/filebrowser/filebrowser/commit/9595f3939c1c129ed875a47adcc4fbcfad9a0e65))
|
||||
* Don't crash on invalid config import ([#5640](https://github.com/filebrowser/filebrowser/issues/5640)) ([79d1aa9](https://github.com/filebrowser/filebrowser/commit/79d1aa9229b076ee8e3b71d6cf061fc90738f4da))
|
||||
* fix nil deref in config set command ([#5641](https://github.com/filebrowser/filebrowser/issues/5641)) ([60b1ee8](https://github.com/filebrowser/filebrowser/commit/60b1ee8bb9e18b21d7f2c04cb1cc90046cecd3e1))
|
||||
|
||||
## [2.52.0](https://github.com/filebrowser/filebrowser/compare/v2.51.2...v2.52.0) (2025-12-13)
|
||||
|
||||
|
||||
|
||||
+20
-17
@@ -158,16 +158,17 @@ func (a *HookAuth) SaveUser() (*users.User, error) {
|
||||
|
||||
// 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,
|
||||
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,
|
||||
RedirectAfterCopyMove: a.Settings.Defaults.RedirectAfterCopyMove,
|
||||
Sorting: a.Settings.Defaults.Sorting,
|
||||
Perm: a.Settings.Defaults.Perm,
|
||||
Commands: a.Settings.Defaults.Commands,
|
||||
HideDotfiles: a.Settings.Defaults.HideDotfiles,
|
||||
}
|
||||
u = a.GetUser(d)
|
||||
|
||||
@@ -219,13 +220,14 @@ func (a *HookAuth) GetUser(d *users.User) *users.User {
|
||||
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),
|
||||
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),
|
||||
RedirectAfterCopyMove: a.Fields.GetBoolean("user.redirectAfterCopyMove", d.RedirectAfterCopyMove),
|
||||
Sorting: files.Sorting{
|
||||
Asc: a.Fields.GetBoolean("user.sorting.asc", d.Sorting.Asc),
|
||||
By: a.Fields.GetString("user.sorting.by", d.Sorting.By),
|
||||
@@ -251,6 +253,7 @@ var validHookFields = []string{
|
||||
"user.locale",
|
||||
"user.viewMode",
|
||||
"user.singleClick",
|
||||
"user.redirectAfterCopyMove",
|
||||
"user.sorting.by",
|
||||
"user.sorting.asc",
|
||||
"user.commands",
|
||||
|
||||
+15
-1
@@ -14,6 +14,10 @@ import (
|
||||
// MethodJSONAuth is used to identify json auth.
|
||||
const MethodJSONAuth settings.AuthMethod = "json"
|
||||
|
||||
// dummyHash is used to prevent user enumeration timing attacks.
|
||||
// It MUST be a valid bcrypt hash.
|
||||
const dummyHash = "$2a$10$O4mEMeOL/nit6zqe.WQXauLRbRlzb3IgLHsa26Pf0N/GiU9b.wK1m"
|
||||
|
||||
type jsonCred struct {
|
||||
Password string `json:"password"`
|
||||
Username string `json:"username"`
|
||||
@@ -52,7 +56,17 @@ func (a JSONAuth) Auth(r *http.Request, usr users.Store, _ *settings.Settings, s
|
||||
}
|
||||
|
||||
u, err := usr.Get(srv.Root, cred.Username)
|
||||
if err != nil || !users.CheckPwd(cred.Password, u.Password) {
|
||||
|
||||
hash := dummyHash
|
||||
if err == nil {
|
||||
hash = u.Password
|
||||
}
|
||||
|
||||
if !users.CheckPwd(cred.Password, hash) {
|
||||
return nil, os.ErrPermission
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, os.ErrPermission
|
||||
}
|
||||
|
||||
|
||||
+5
-1
@@ -99,7 +99,7 @@ func getProxyAuth(flags *pflag.FlagSet, defaultAuther map[string]interface{}) (a
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if header == "" {
|
||||
if header == "" && defaultAuther != nil {
|
||||
header = defaultAuther["header"].(string)
|
||||
}
|
||||
|
||||
@@ -240,6 +240,7 @@ func printSettings(ser *settings.Server, set *settings.Settings, auther auth.Aut
|
||||
fmt.Fprintf(w, "\tLocale:\t%s\n", set.Defaults.Locale)
|
||||
fmt.Fprintf(w, "\tView mode:\t%s\n", set.Defaults.ViewMode)
|
||||
fmt.Fprintf(w, "\tSingle Click:\t%t\n", set.Defaults.SingleClick)
|
||||
fmt.Fprintf(w, "\tRedirect after Copy/Move:\t%t\n", set.Defaults.RedirectAfterCopyMove)
|
||||
fmt.Fprintf(w, "\tFile Creation Mode:\t%O\n", set.FileMode)
|
||||
fmt.Fprintf(w, "\tDirectory Creation Mode:\t%O\n", set.DirMode)
|
||||
fmt.Fprintf(w, "\tCommands:\t%s\n", strings.Join(set.Defaults.Commands, " "))
|
||||
@@ -308,6 +309,9 @@ func getSettings(flags *pflag.FlagSet, set *settings.Settings, ser *settings.Ser
|
||||
case "disableTypeDetectionByHeader":
|
||||
ser.TypeDetectionByHeader, err = flags.GetBool(flag.Name)
|
||||
ser.TypeDetectionByHeader = !ser.TypeDetectionByHeader
|
||||
case "disableImageResolutionCalc":
|
||||
ser.ImageResolutionCal, err = flags.GetBool(flag.Name)
|
||||
ser.ImageResolutionCal = !ser.ImageResolutionCal
|
||||
|
||||
// Settings flags from [addConfigFlags]
|
||||
case "signup":
|
||||
|
||||
@@ -3,7 +3,6 @@ package cmd
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
@@ -53,6 +52,10 @@ The path must be for a json or yaml file.`,
|
||||
return err
|
||||
}
|
||||
|
||||
if file.Settings == nil || file.Server == nil {
|
||||
return errors.New("invalid configuration file: 'settings' or 'server' fields are missing. Please ensure you are importing a file generated by the 'config export' command")
|
||||
}
|
||||
|
||||
file.Settings.Key = key
|
||||
err = st.Settings.Save(file.Settings)
|
||||
if err != nil {
|
||||
@@ -64,12 +67,7 @@ The path must be for a json or yaml file.`,
|
||||
return err
|
||||
}
|
||||
|
||||
var rawAuther interface{}
|
||||
if filepath.Ext(args[0]) != ".json" {
|
||||
rawAuther = cleanUpInterfaceMap(file.Auther.(map[interface{}]interface{}))
|
||||
} else {
|
||||
rawAuther = file.Auther
|
||||
}
|
||||
var rawAuther = file.Auther
|
||||
|
||||
var auther auth.Auther
|
||||
var autherErr error
|
||||
|
||||
+25
-5
@@ -46,6 +46,7 @@ var (
|
||||
"disable-type-detection-by-header": "disableTypeDetectionByHeader",
|
||||
"img-processors": "imageProcessors",
|
||||
"cache-dir": "cacheDir",
|
||||
"redis-cache-url": "redisCacheUrl",
|
||||
"token-expiration-time": "tokenExpirationTime",
|
||||
"baseurl": "baseURL",
|
||||
}
|
||||
@@ -88,6 +89,7 @@ func init() {
|
||||
flags.String("password", "", "hashed password for the first user when using quick setup")
|
||||
flags.Uint32("socketPerm", 0666, "unix socket file permissions")
|
||||
flags.String("cacheDir", "", "file cache directory (disabled if empty)")
|
||||
flags.String("redisCacheUrl", "", "redis cache URL (for multi-instance deployments), e.g. redis://user:pass@host:port")
|
||||
flags.Int("imageProcessors", 4, "image processors count")
|
||||
addServerFlags(flags)
|
||||
}
|
||||
@@ -108,6 +110,7 @@ func addServerFlags(flags *pflag.FlagSet) {
|
||||
flags.Bool("disablePreviewResize", false, "disable resize of image previews")
|
||||
flags.Bool("disableExec", true, "disables Command Runner feature")
|
||||
flags.Bool("disableTypeDetectionByHeader", false, "disables type detection by reading file headers")
|
||||
flags.Bool("disableImageResolutionCalc", false, "disables image resolution calculation by reading image files")
|
||||
}
|
||||
|
||||
var rootCmd = &cobra.Command{
|
||||
@@ -135,6 +138,11 @@ file named .filebrowser.{json, toml, yaml, yml} in the following directories:
|
||||
- $HOME/
|
||||
- /etc/filebrowser/
|
||||
|
||||
**Note:** Only the options listed below can be set via the config file or
|
||||
environment variables. Other configuration options live exclusively in the
|
||||
database and so they must be set by the "config set" or "config
|
||||
import" commands.
|
||||
|
||||
The precedence of the configuration values are as follows:
|
||||
|
||||
- Flags
|
||||
@@ -170,6 +178,12 @@ user created with the credentials from options "username" and "password".`,
|
||||
fileCache = diskcache.New(afero.NewOsFs(), cacheDir)
|
||||
}
|
||||
|
||||
redisCacheURL := v.GetString("redisCacheUrl")
|
||||
uploadCache, err := fbhttp.NewUploadCache(redisCacheURL)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to initialize upload cache: %w", err)
|
||||
}
|
||||
|
||||
server, err := getServerSettings(v, st.Storage)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -221,7 +235,7 @@ user created with the credentials from options "username" and "password".`,
|
||||
panic(err)
|
||||
}
|
||||
|
||||
handler, err := fbhttp.NewHandler(imageService, fileCache, st.Storage, server, assetsFs)
|
||||
handler, err := fbhttp.NewHandler(imageService, fileCache, uploadCache, st.Storage, server, assetsFs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -331,6 +345,10 @@ func getServerSettings(v *viper.Viper, st *storage.Storage) (*settings.Server, e
|
||||
server.TypeDetectionByHeader = !v.GetBool("disableTypeDetectionByHeader")
|
||||
}
|
||||
|
||||
if v.IsSet("disableImageResolutionCalc") {
|
||||
server.ImageResolutionCal = !v.GetBool("disableImageResolutionCalc")
|
||||
}
|
||||
|
||||
if v.IsSet("disableExec") {
|
||||
server.EnableExec = !v.GetBool("disableExec")
|
||||
}
|
||||
@@ -383,10 +401,11 @@ func quickSetup(v *viper.Viper, s *storage.Storage) error {
|
||||
MinimumPasswordLength: settings.DefaultMinimumPasswordLength,
|
||||
UserHomeBasePath: settings.DefaultUsersHomeBasePath,
|
||||
Defaults: settings.UserDefaults{
|
||||
Scope: ".",
|
||||
Locale: "en",
|
||||
SingleClick: false,
|
||||
AceEditorTheme: v.GetString("defaults.aceEditorTheme"),
|
||||
Scope: ".",
|
||||
Locale: "en",
|
||||
SingleClick: false,
|
||||
RedirectAfterCopyMove: true,
|
||||
AceEditorTheme: v.GetString("defaults.aceEditorTheme"),
|
||||
Perm: users.Permissions{
|
||||
Admin: false,
|
||||
Execute: true,
|
||||
@@ -439,6 +458,7 @@ func quickSetup(v *viper.Viper, s *storage.Storage) error {
|
||||
ResizePreview: !v.GetBool("disablePreviewResize"),
|
||||
EnableExec: !v.GetBool("disableExec"),
|
||||
TypeDetectionByHeader: !v.GetBool("disableTypeDetectionByHeader"),
|
||||
ImageResolutionCal: !v.GetBool("disableImageResolutionCalc"),
|
||||
}
|
||||
|
||||
err = s.Settings.SaveServer(ser)
|
||||
|
||||
+6
-2
@@ -27,16 +27,17 @@ var usersCmd = &cobra.Command{
|
||||
|
||||
func printUsers(usrs []*users.User) {
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
||||
fmt.Fprintln(w, "ID\tUsername\tScope\tLocale\tV. Mode\tS.Click\tAdmin\tExecute\tCreate\tRename\tModify\tDelete\tShare\tDownload\tPwd Lock")
|
||||
fmt.Fprintln(w, "ID\tUsername\tScope\tLocale\tV. Mode\tS.Click\tRed. After C/M\tAdmin\tExecute\tCreate\tRename\tModify\tDelete\tShare\tDownload\tPwd Lock")
|
||||
|
||||
for _, u := range usrs {
|
||||
fmt.Fprintf(w, "%d\t%s\t%s\t%s\t%s\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t\n",
|
||||
fmt.Fprintf(w, "%d\t%s\t%s\t%s\t%s\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t\n",
|
||||
u.ID,
|
||||
u.Username,
|
||||
u.Scope,
|
||||
u.Locale,
|
||||
u.ViewMode,
|
||||
u.SingleClick,
|
||||
u.RedirectAfterCopyMove,
|
||||
u.Perm.Admin,
|
||||
u.Perm.Execute,
|
||||
u.Perm.Create,
|
||||
@@ -77,6 +78,7 @@ func addUserFlags(flags *pflag.FlagSet) {
|
||||
flags.String("locale", "en", "locale for users")
|
||||
flags.String("viewMode", string(users.ListViewMode), "view mode for users")
|
||||
flags.Bool("singleClick", false, "use single clicks only")
|
||||
flags.Bool("redirectAfterCopyMove", false, "redirect to destination after copy/move")
|
||||
flags.Bool("dateFormat", false, "use date format (true for absolute time, false for relative)")
|
||||
flags.Bool("hideDotfiles", false, "hide dotfiles")
|
||||
flags.String("aceEditorTheme", "", "ace editor's syntax highlighting theme for users")
|
||||
@@ -110,6 +112,8 @@ func getUserDefaults(flags *pflag.FlagSet, defaults *settings.UserDefaults, all
|
||||
defaults.ViewMode, err = getAndParseViewMode(flags)
|
||||
case "singleClick":
|
||||
defaults.SingleClick, err = flags.GetBool(flag.Name)
|
||||
case "redirectAfterCopyMove":
|
||||
defaults.RedirectAfterCopyMove, err = flags.GetBool(flag.Name)
|
||||
case "aceEditorTheme":
|
||||
defaults.AceEditorTheme, err = flags.GetString(flag.Name)
|
||||
case "perm.admin":
|
||||
|
||||
+9
-7
@@ -52,13 +52,14 @@ options you want to change.`,
|
||||
}
|
||||
|
||||
defaults := settings.UserDefaults{
|
||||
Scope: user.Scope,
|
||||
Locale: user.Locale,
|
||||
ViewMode: user.ViewMode,
|
||||
SingleClick: user.SingleClick,
|
||||
Perm: user.Perm,
|
||||
Sorting: user.Sorting,
|
||||
Commands: user.Commands,
|
||||
Scope: user.Scope,
|
||||
Locale: user.Locale,
|
||||
ViewMode: user.ViewMode,
|
||||
SingleClick: user.SingleClick,
|
||||
RedirectAfterCopyMove: user.RedirectAfterCopyMove,
|
||||
Perm: user.Perm,
|
||||
Sorting: user.Sorting,
|
||||
Commands: user.Commands,
|
||||
}
|
||||
|
||||
err = getUserDefaults(flags, &defaults, false)
|
||||
@@ -70,6 +71,7 @@ options you want to change.`,
|
||||
user.Locale = defaults.Locale
|
||||
user.ViewMode = defaults.ViewMode
|
||||
user.SingleClick = defaults.SingleClick
|
||||
user.RedirectAfterCopyMove = defaults.RedirectAfterCopyMove
|
||||
user.Perm = defaults.Perm
|
||||
user.Commands = defaults.Commands
|
||||
user.Sorting = defaults.Sorting
|
||||
|
||||
@@ -3,7 +3,6 @@ package cmd
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"log"
|
||||
"os"
|
||||
@@ -249,33 +248,6 @@ func jsonYamlArg(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
}
|
||||
|
||||
func cleanUpInterfaceMap(in map[interface{}]interface{}) map[string]interface{} {
|
||||
result := make(map[string]interface{})
|
||||
for k, v := range in {
|
||||
result[fmt.Sprintf("%v", k)] = cleanUpMapValue(v)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func cleanUpInterfaceArray(in []interface{}) []interface{} {
|
||||
result := make([]interface{}, len(in))
|
||||
for i, v := range in {
|
||||
result[i] = cleanUpMapValue(v)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func cleanUpMapValue(v interface{}) interface{} {
|
||||
switch v := v.(type) {
|
||||
case []interface{}:
|
||||
return cleanUpInterfaceArray(v)
|
||||
case map[interface{}]interface{}:
|
||||
return cleanUpInterfaceMap(v)
|
||||
default:
|
||||
return v
|
||||
}
|
||||
}
|
||||
|
||||
// convertCmdStrToCmdArray checks if cmd string is blank (whitespace included)
|
||||
// then returns empty string array, else returns the split word array of cmd.
|
||||
// This is to ensure the result will never be []string{""}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
# Run using:
|
||||
# docker compose -f compose.yaml -f compose.redis.yaml up --build
|
||||
|
||||
services:
|
||||
redis:
|
||||
container_name: redis
|
||||
image: redis:latest
|
||||
networks:
|
||||
- filebrowser
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- |
|
||||
cat > /tmp/users.acl <<EOF
|
||||
user default on >filebrowser ~* +@all
|
||||
EOF
|
||||
redis-server --aclfile /tmp/users.acl
|
||||
@@ -0,0 +1,37 @@
|
||||
# Run using:
|
||||
# docker compose up --build
|
||||
|
||||
services:
|
||||
filebrowser:
|
||||
container_name: filebrowser
|
||||
build:
|
||||
dockerfile: Dockerfile
|
||||
context: .
|
||||
networks:
|
||||
- filebrowser
|
||||
ports:
|
||||
- 8000:80
|
||||
volumes:
|
||||
- filebrowser:/flux/vault
|
||||
environment:
|
||||
- REDIS_CACHE_URL=redis://default:filebrowser@redis:6379 # Use rediss:// for ssl
|
||||
|
||||
redis:
|
||||
container_name: redis
|
||||
image: redis:latest
|
||||
networks:
|
||||
- filebrowser
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- |
|
||||
cat > /tmp/users.acl <<EOF
|
||||
user default on >filebrowser ~* +@all
|
||||
EOF
|
||||
redis-server --aclfile /tmp/users.acl
|
||||
|
||||
networks:
|
||||
filebrowser:
|
||||
|
||||
volumes:
|
||||
filebrowser:
|
||||
+17
-16
@@ -6,22 +6,23 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
ErrEmptyKey = errors.New("empty key")
|
||||
ErrExist = errors.New("the resource already exists")
|
||||
ErrNotExist = errors.New("the resource does not exist")
|
||||
ErrEmptyPassword = errors.New("password is empty")
|
||||
ErrEasyPassword = errors.New("password is too easy")
|
||||
ErrEmptyUsername = errors.New("username is empty")
|
||||
ErrEmptyRequest = errors.New("empty request")
|
||||
ErrScopeIsRelative = errors.New("scope is a relative path")
|
||||
ErrInvalidDataType = errors.New("invalid data type")
|
||||
ErrIsDirectory = errors.New("file is directory")
|
||||
ErrInvalidOption = errors.New("invalid option")
|
||||
ErrInvalidAuthMethod = errors.New("invalid auth method")
|
||||
ErrPermissionDenied = errors.New("permission denied")
|
||||
ErrInvalidRequestParams = errors.New("invalid request params")
|
||||
ErrSourceIsParent = errors.New("source is parent")
|
||||
ErrRootUserDeletion = errors.New("user with id 1 can't be deleted")
|
||||
ErrEmptyKey = errors.New("empty key")
|
||||
ErrExist = errors.New("the resource already exists")
|
||||
ErrNotExist = errors.New("the resource does not exist")
|
||||
ErrEmptyPassword = errors.New("password is empty")
|
||||
ErrEasyPassword = errors.New("password is too easy")
|
||||
ErrEmptyUsername = errors.New("username is empty")
|
||||
ErrEmptyRequest = errors.New("empty request")
|
||||
ErrScopeIsRelative = errors.New("scope is a relative path")
|
||||
ErrInvalidDataType = errors.New("invalid data type")
|
||||
ErrIsDirectory = errors.New("file is directory")
|
||||
ErrInvalidOption = errors.New("invalid option")
|
||||
ErrInvalidAuthMethod = errors.New("invalid auth method")
|
||||
ErrPermissionDenied = errors.New("permission denied")
|
||||
ErrInvalidRequestParams = errors.New("invalid request params")
|
||||
ErrSourceIsParent = errors.New("source is parent")
|
||||
ErrRootUserDeletion = errors.New("user with id 1 can't be deleted")
|
||||
ErrCurrentPasswordIncorrect = errors.New("the current password is incorrect")
|
||||
)
|
||||
|
||||
type ErrShortPassword struct {
|
||||
|
||||
+14
-11
@@ -60,6 +60,7 @@ type FileOptions struct {
|
||||
Modify bool
|
||||
Expand bool
|
||||
ReadHeader bool
|
||||
CalcImgRes bool
|
||||
Token string
|
||||
Checker rules.Checker
|
||||
Content bool
|
||||
@@ -90,13 +91,13 @@ func NewFileInfo(opts *FileOptions) (*FileInfo, error) {
|
||||
|
||||
if opts.Expand {
|
||||
if file.IsDir {
|
||||
if err := file.readListing(opts.Checker, opts.ReadHeader); err != nil {
|
||||
if err := file.readListing(opts.Checker, opts.ReadHeader, opts.CalcImgRes); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return file, nil
|
||||
}
|
||||
|
||||
err = file.detectType(opts.Modify, opts.Content, true)
|
||||
err = file.detectType(opts.Modify, opts.Content, true, opts.CalcImgRes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -218,7 +219,7 @@ func (i *FileInfo) RealPath() string {
|
||||
return i.Path
|
||||
}
|
||||
|
||||
func (i *FileInfo) detectType(modify, saveContent, readHeader bool) error {
|
||||
func (i *FileInfo) detectType(modify, saveContent, readHeader bool, calcImgRes bool) error {
|
||||
if IsNamedPipe(i.Mode) {
|
||||
i.Type = "blob"
|
||||
return nil
|
||||
@@ -249,11 +250,13 @@ 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
|
||||
if calcImgRes {
|
||||
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"):
|
||||
@@ -387,7 +390,7 @@ func (i *FileInfo) addSubtitle(fPath string) {
|
||||
i.Subtitles = append(i.Subtitles, fPath)
|
||||
}
|
||||
|
||||
func (i *FileInfo) readListing(checker rules.Checker, readHeader bool) error {
|
||||
func (i *FileInfo) readListing(checker rules.Checker, readHeader bool, calcImgRes bool) error {
|
||||
afs := &afero.Afero{Fs: i.Fs}
|
||||
dir, err := afs.ReadDir(i.Path)
|
||||
if err != nil {
|
||||
@@ -434,7 +437,7 @@ func (i *FileInfo) readListing(checker rules.Checker, readHeader bool) error {
|
||||
currentDir: dir,
|
||||
}
|
||||
|
||||
if !file.IsDir && strings.HasPrefix(mime.TypeByExtension(file.Extension), "image/") {
|
||||
if !file.IsDir && strings.HasPrefix(mime.TypeByExtension(file.Extension), "image/") && calcImgRes {
|
||||
resolution, err := calculateImageResolution(file.Fs, file.Path)
|
||||
if err != nil {
|
||||
log.Printf("Error calculating resolution for image %s: %v", file.Path, err)
|
||||
@@ -451,7 +454,7 @@ func (i *FileInfo) readListing(checker rules.Checker, readHeader bool) error {
|
||||
if isInvalidLink {
|
||||
file.Type = "invalid_link"
|
||||
} else {
|
||||
err := file.detectType(true, false, readHeader)
|
||||
err := file.detectType(true, false, readHeader, calcImgRes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
"@vueuse/core": "^14.0.0",
|
||||
"@vueuse/integrations": "^14.0.0",
|
||||
"ace-builds": "^1.43.2",
|
||||
"csv-parse": "^6.1.0",
|
||||
"dayjs": "^1.11.13",
|
||||
"dompurify": "^3.2.6",
|
||||
"epubjs": "^0.3.93",
|
||||
@@ -29,6 +30,7 @@
|
||||
"jwt-decode": "^4.0.0",
|
||||
"lodash-es": "^4.17.21",
|
||||
"marked": "^17.0.0",
|
||||
"marked-katex-extension": "^5.1.6",
|
||||
"material-icons": "^1.13.14",
|
||||
"normalize.css": "^8.0.1",
|
||||
"pinia": "^3.0.4",
|
||||
@@ -44,7 +46,7 @@
|
||||
"vue-i18n": "^11.1.10",
|
||||
"vue-lazyload": "^3.0.0",
|
||||
"vue-reader": "^1.2.17",
|
||||
"vue-router": "^4.5.1",
|
||||
"vue-router": "^5.0.0",
|
||||
"vue-toastification": "^2.0.0-rc.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -59,7 +61,7 @@
|
||||
"@vue/eslint-config-typescript": "^14.6.0",
|
||||
"@vue/tsconfig": "^0.8.1",
|
||||
"autoprefixer": "^10.4.21",
|
||||
"eslint": "^9.31.0",
|
||||
"eslint": "^10.0.0",
|
||||
"eslint-config-prettier": "^10.1.5",
|
||||
"eslint-plugin-prettier": "^5.5.1",
|
||||
"eslint-plugin-vue": "^10.5.1",
|
||||
@@ -71,5 +73,5 @@
|
||||
"vite-plugin-compression2": "^2.3.1",
|
||||
"vue-tsc": "^3.1.3"
|
||||
},
|
||||
"packageManager": "pnpm@10.25.0+sha512.5e82639027af37cf832061bcc6d639c219634488e0f2baebe785028a793de7b525ffcd3f7ff574f5e9860654e098fe852ba8ac5dd5cefe1767d23a020a92f501"
|
||||
"packageManager": "pnpm@10.29.3+sha512.498e1fb4cca5aa06c1dcf2611e6fafc50972ffe7189998c409e90de74566444298ffe43e6cd2acdc775ba1aa7cc5e092a8b7054c811ba8c5770f84693d33d2dc"
|
||||
}
|
||||
|
||||
Generated
+1755
-1521
File diff suppressed because it is too large
Load Diff
@@ -3,14 +3,25 @@ import { useLayoutStore } from "@/stores/layout";
|
||||
import { baseURL } from "@/utils/constants";
|
||||
import { upload as postTus, useTus } from "./tus";
|
||||
import { createURL, fetchURL, removePrefix, StatusError } from "./utils";
|
||||
import { isEncodableResponse, makeRawResource } from "@/utils/encodings";
|
||||
|
||||
export async function fetch(url: string, signal?: AbortSignal) {
|
||||
const encoding = isEncodableResponse(url);
|
||||
url = removePrefix(url);
|
||||
const res = await fetchURL(`/api/resources${url}`, { signal });
|
||||
const res = await fetchURL(`/api/resources${url}`, {
|
||||
signal,
|
||||
headers: {
|
||||
"X-Encoding": encoding ? "true" : "false",
|
||||
},
|
||||
});
|
||||
|
||||
let data: Resource;
|
||||
try {
|
||||
data = (await res.json()) as Resource;
|
||||
if (res.headers.get("Content-Type") == "application/octet-stream") {
|
||||
data = await makeRawResource(res, url);
|
||||
} else {
|
||||
data = (await res.json()) as Resource;
|
||||
}
|
||||
} catch (e) {
|
||||
// Check if the error is an intentional cancellation
|
||||
if (e instanceof Error && e.name === "AbortError") {
|
||||
@@ -140,9 +151,9 @@ async function postResources(
|
||||
if (request.status === 200) {
|
||||
resolve(request.responseText);
|
||||
} else if (request.status === 409) {
|
||||
reject(request.status);
|
||||
reject(new Error(request.status.toString()));
|
||||
} else {
|
||||
reject(request.responseText);
|
||||
reject(new Error(request.responseText));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -41,12 +41,12 @@ export function download(
|
||||
let url = `${baseURL}/api/public/dl/${hash}`;
|
||||
|
||||
if (files.length === 1) {
|
||||
url += encodeURIComponent(files[0]) + "?";
|
||||
url += files[0] + "?";
|
||||
} else {
|
||||
let arg = "";
|
||||
|
||||
for (const file of files) {
|
||||
arg += encodeURIComponent(file) + ",";
|
||||
arg += file + ",";
|
||||
}
|
||||
|
||||
arg = arg.substring(0, arg.length - 1);
|
||||
|
||||
+61
-15
@@ -1,7 +1,12 @@
|
||||
import { fetchURL, removePrefix } from "./utils";
|
||||
import { fetchURL, removePrefix, StatusError } from "./utils";
|
||||
import url from "../utils/url";
|
||||
|
||||
export default async function search(base: string, query: string) {
|
||||
export default async function search(
|
||||
base: string,
|
||||
query: string,
|
||||
signal: AbortSignal,
|
||||
callback: (item: ResourceItem) => void
|
||||
) {
|
||||
base = removePrefix(base);
|
||||
query = encodeURIComponent(query);
|
||||
|
||||
@@ -9,19 +14,60 @@ export default async function search(base: string, query: string) {
|
||||
base += "/";
|
||||
}
|
||||
|
||||
const res = await fetchURL(`/api/search${base}?query=${query}`, {});
|
||||
const res = await fetchURL(`/api/search${base}?query=${query}`, { signal });
|
||||
if (!res.body) {
|
||||
throw new StatusError("000 No connection", 0);
|
||||
}
|
||||
try {
|
||||
// Try streaming approach first (modern browsers)
|
||||
if (res.body && typeof res.body.pipeThrough === "function") {
|
||||
const reader = res.body.pipeThrough(new TextDecoderStream()).getReader();
|
||||
let buffer = "";
|
||||
while (true) {
|
||||
const { done, value } = await reader.read();
|
||||
if (value) {
|
||||
buffer += value;
|
||||
}
|
||||
const lines = buffer.split(/\n/);
|
||||
let lastLine = lines.pop();
|
||||
// Save incomplete last line
|
||||
if (!lastLine) {
|
||||
lastLine = "";
|
||||
}
|
||||
buffer = lastLine;
|
||||
|
||||
let data = await res.json();
|
||||
|
||||
data = data.map((item: ResourceItem & { dir: boolean }) => {
|
||||
item.url = `/files${base}` + url.encodePath(item.path);
|
||||
|
||||
if (item.dir) {
|
||||
item.url += "/";
|
||||
for (const line of lines) {
|
||||
if (line) {
|
||||
const item = JSON.parse(line) as ResourceItem;
|
||||
item.url = `/files${base}` + url.encodePath(item.path);
|
||||
if (item.isDir) {
|
||||
item.url += "/";
|
||||
}
|
||||
callback(item);
|
||||
}
|
||||
}
|
||||
if (done) break;
|
||||
}
|
||||
} else {
|
||||
// Fallback for browsers without streaming support (e.g., Safari)
|
||||
const text = await res.text();
|
||||
const lines = text.split(/\n/);
|
||||
for (const line of lines) {
|
||||
if (line) {
|
||||
const item = JSON.parse(line) as ResourceItem;
|
||||
item.url = `/files${base}` + url.encodePath(item.path);
|
||||
if (item.isDir) {
|
||||
item.url += "/";
|
||||
}
|
||||
callback(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return item;
|
||||
});
|
||||
|
||||
return data;
|
||||
} catch (e) {
|
||||
// Check if the error is an intentional cancellation
|
||||
if (e instanceof Error && e.name === "AbortError") {
|
||||
throw new StatusError("000 No connection", 0, true);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,12 +8,13 @@ export async function get(id: number) {
|
||||
return fetchJSON<IUser>(`/api/users/${id}`, {});
|
||||
}
|
||||
|
||||
export async function create(user: IUser) {
|
||||
export async function create(user: IUser, currentPassword: string) {
|
||||
const res = await fetchURL(`/api/users`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
what: "user",
|
||||
which: [],
|
||||
current_password: currentPassword,
|
||||
data: user,
|
||||
}),
|
||||
});
|
||||
@@ -25,19 +26,30 @@ export async function create(user: IUser) {
|
||||
throw new StatusError(await res.text(), res.status);
|
||||
}
|
||||
|
||||
export async function update(user: Partial<IUser>, which = ["all"]) {
|
||||
export async function update(
|
||||
user: Partial<IUser>,
|
||||
which = ["all"],
|
||||
currentPassword: string | null = null
|
||||
) {
|
||||
await fetchURL(`/api/users/${user.id}`, {
|
||||
method: "PUT",
|
||||
body: JSON.stringify({
|
||||
what: "user",
|
||||
which: which,
|
||||
...(currentPassword != null ? { current_password: currentPassword } : {}),
|
||||
data: user,
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
export async function remove(id: number) {
|
||||
export async function remove(
|
||||
id: number,
|
||||
currentPassword: string | null = null
|
||||
) {
|
||||
await fetchURL(`/api/users/${id}`, {
|
||||
method: "DELETE",
|
||||
body: JSON.stringify({
|
||||
...(currentPassword != null ? { current_password: currentPassword } : {}),
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -5,10 +5,11 @@
|
||||
v-if="active"
|
||||
class="action"
|
||||
@click="close"
|
||||
:aria-label="$t('buttons.close')"
|
||||
:title="$t('buttons.close')"
|
||||
:aria-label="closeButtonTitle"
|
||||
:title="closeButtonTitle"
|
||||
>
|
||||
<i class="material-icons">arrow_back</i>
|
||||
<i v-if="ongoing" class="material-icons">stop_circle</i>
|
||||
<i v-else class="material-icons">arrow_back</i>
|
||||
</button>
|
||||
<i v-else class="material-icons">search</i>
|
||||
<input
|
||||
@@ -21,6 +22,15 @@
|
||||
:aria-label="$t('search.search')"
|
||||
:placeholder="$t('search.search')"
|
||||
/>
|
||||
<i
|
||||
v-show="ongoing"
|
||||
class="material-icons spin"
|
||||
style="display: inline-block"
|
||||
>autorenew
|
||||
</i>
|
||||
<span style="margin-top: 5px" v-show="results.length > 0">
|
||||
{{ results.length }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div id="result" ref="result">
|
||||
@@ -57,9 +67,6 @@
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<p id="renew">
|
||||
<i class="material-icons spin">autorenew</i>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -70,10 +77,11 @@ import { useLayoutStore } from "@/stores/layout";
|
||||
|
||||
import url from "@/utils/url";
|
||||
import { search } from "@/api";
|
||||
import { computed, inject, onMounted, ref, watch } from "vue";
|
||||
import { computed, inject, onMounted, ref, watch, onUnmounted } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useRoute } from "vue-router";
|
||||
import { storeToRefs } from "pinia";
|
||||
import { StatusError } from "@/api/utils";
|
||||
|
||||
const boxes = {
|
||||
image: { label: "images", icon: "insert_photo" },
|
||||
@@ -84,6 +92,7 @@ const boxes = {
|
||||
|
||||
const layoutStore = useLayoutStore();
|
||||
const fileStore = useFileStore();
|
||||
let searchAbortController = new AbortController();
|
||||
|
||||
const { currentPromptName } = storeToRefs(layoutStore);
|
||||
|
||||
@@ -124,9 +133,7 @@ watch(currentPromptName, (newVal, oldVal) => {
|
||||
});
|
||||
|
||||
watch(prompt, () => {
|
||||
if (results.value.length) {
|
||||
reset();
|
||||
}
|
||||
reset();
|
||||
});
|
||||
|
||||
// ...mapState(useFileStore, ["isListing"]),
|
||||
@@ -149,6 +156,10 @@ const filteredResults = computed(() => {
|
||||
return results.value.slice(0, resultsCount.value);
|
||||
});
|
||||
|
||||
const closeButtonTitle = computed(() => {
|
||||
return ongoing.value ? t("buttons.stopSearch") : t("buttons.close");
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
if (result.value === null) {
|
||||
return;
|
||||
@@ -164,14 +175,23 @@ onMounted(() => {
|
||||
});
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
abortLastSearch();
|
||||
});
|
||||
|
||||
const open = () => {
|
||||
!active.value && layoutStore.showHover("search");
|
||||
};
|
||||
|
||||
const close = (event: Event) => {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
layoutStore.closeHovers();
|
||||
if (ongoing.value) {
|
||||
abortLastSearch();
|
||||
ongoing.value = false;
|
||||
} else {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
layoutStore.closeHovers();
|
||||
}
|
||||
};
|
||||
|
||||
const keyup = (event: KeyboardEvent) => {
|
||||
@@ -188,11 +208,16 @@ const init = (string: string) => {
|
||||
};
|
||||
|
||||
const reset = () => {
|
||||
abortLastSearch();
|
||||
ongoing.value = false;
|
||||
resultsCount.value = 50;
|
||||
results.value = [];
|
||||
};
|
||||
|
||||
const abortLastSearch = () => {
|
||||
searchAbortController.abort();
|
||||
};
|
||||
|
||||
const submit = async (event: Event) => {
|
||||
event.preventDefault();
|
||||
|
||||
@@ -208,8 +233,16 @@ const submit = async (event: Event) => {
|
||||
ongoing.value = true;
|
||||
|
||||
try {
|
||||
results.value = await search(path, prompt.value);
|
||||
abortLastSearch();
|
||||
searchAbortController = new AbortController();
|
||||
results.value = [];
|
||||
await search(path, prompt.value, searchAbortController.signal, (item) =>
|
||||
results.value.push(item)
|
||||
);
|
||||
} catch (error: any) {
|
||||
if (error instanceof StatusError && error.is_canceled) {
|
||||
return;
|
||||
}
|
||||
$showError(error);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,35 +4,13 @@
|
||||
<i class="material-icons">error</i>
|
||||
<p>{{ displayError }}</p>
|
||||
</div>
|
||||
<div v-else-if="data.headers.length === 0" class="csv-empty">
|
||||
<div v-else-if="parsed.headers.length === 0" class="csv-empty">
|
||||
<i class="material-icons">description</i>
|
||||
<p>{{ $t("files.lonely") }}</p>
|
||||
</div>
|
||||
<div v-else class="csv-table-container" @wheel.stop @touchmove.stop>
|
||||
<table class="csv-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th v-for="(header, index) in data.headers" :key="index">
|
||||
{{ header || `Column ${index + 1}` }}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(row, rowIndex) in data.rows" :key="rowIndex">
|
||||
<td v-for="(cell, cellIndex) in row" :key="cellIndex">
|
||||
{{ cell }}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="csv-footer">
|
||||
<div class="csv-info" v-if="data.rows.length > 100">
|
||||
<i class="material-icons">info</i>
|
||||
<span>
|
||||
{{ $t("files.showingRows", { count: data.rows.length }) }}</span
|
||||
>
|
||||
</div>
|
||||
<div class="column-separator">
|
||||
<div class="csv-header">
|
||||
<div class="header-select">
|
||||
<label for="columnSeparator">{{ $t("files.columnSeparator") }}</label>
|
||||
<select
|
||||
id="columnSeparator"
|
||||
@@ -50,17 +28,61 @@
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="header-select" v-if="isEncodedContent">
|
||||
<label for="fileEncoding">{{ $t("files.fileEncoding") }}</label>
|
||||
<select
|
||||
id="fileEncoding"
|
||||
class="input input--block"
|
||||
v-model="selectedEncoding"
|
||||
>
|
||||
<option
|
||||
v-for="encoding in availableEncodings"
|
||||
:value="encoding"
|
||||
:key="encoding"
|
||||
>
|
||||
{{ encoding }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<table class="csv-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th v-for="(header, index) in parsed.headers" :key="index">
|
||||
{{ header || `Column ${index + 1}` }}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(row, rowIndex) in parsed.rows" :key="rowIndex">
|
||||
<td v-for="(cell, cellIndex) in row" :key="cellIndex">
|
||||
{{ cell }}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="csv-footer">
|
||||
<div class="csv-info" v-if="parsed.rows.length > 100">
|
||||
<i class="material-icons">info</i>
|
||||
<span>
|
||||
{{ $t("files.showingRows", { count: parsed.rows.length }) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { parseCSV, type CsvData } from "@/utils/csv";
|
||||
import { computed, ref } from "vue";
|
||||
import { computed, ref, watchEffect } from "vue";
|
||||
import { parse } from "csv-parse/browser/esm";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { availableEncodings, decode } from "@/utils/encodings";
|
||||
|
||||
const { t } = useI18n({});
|
||||
|
||||
interface Props {
|
||||
content: string;
|
||||
content: ArrayBuffer | string;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
@@ -68,31 +90,43 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
error: "",
|
||||
});
|
||||
|
||||
const columnSeparator = ref([","]);
|
||||
const columnSeparator = ref([",", ";"]);
|
||||
|
||||
const data = computed<CsvData>(() => {
|
||||
try {
|
||||
return parseCSV(props.content, columnSeparator.value);
|
||||
} catch (e) {
|
||||
console.error("Failed to parse CSV:", e);
|
||||
return { headers: [], rows: [] };
|
||||
}
|
||||
const selectedEncoding = ref("utf-8");
|
||||
|
||||
const parsed = ref<CsvData>({ headers: [], rows: [] });
|
||||
|
||||
const displayError = ref<string | null>(null);
|
||||
|
||||
const isEncodedContent = computed(() => {
|
||||
return props.content instanceof ArrayBuffer;
|
||||
});
|
||||
|
||||
const displayError = computed(() => {
|
||||
// External error takes priority (e.g., file too large)
|
||||
if (props.error) {
|
||||
return props.error;
|
||||
watchEffect(() => {
|
||||
if (props.content !== "" && columnSeparator.value.length > 0) {
|
||||
const content = isEncodedContent.value
|
||||
? decode(props.content as ArrayBuffer, selectedEncoding.value)
|
||||
: props.content;
|
||||
parse(
|
||||
content as string,
|
||||
{ delimiter: columnSeparator.value, skip_empty_lines: true },
|
||||
(error, output) => {
|
||||
if (error) {
|
||||
console.error("Failed to parse CSV:", error);
|
||||
parsed.value = { headers: [], rows: [] };
|
||||
displayError.value = t("files.csvLoadFailed", {
|
||||
error: error.toString(),
|
||||
});
|
||||
} else {
|
||||
parsed.value = {
|
||||
headers: output[0],
|
||||
rows: output.slice(1),
|
||||
};
|
||||
displayError.value = null;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
// Check for parse errors
|
||||
if (
|
||||
props.content &&
|
||||
props.content.trim().length > 0 &&
|
||||
data.value.headers.length === 0
|
||||
) {
|
||||
return "Failed to parse CSV file";
|
||||
}
|
||||
return null;
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -213,10 +247,6 @@ const displayError = computed(() => {
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
.csv-footer > :only-child {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.csv-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -230,18 +260,25 @@ const displayError = computed(() => {
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.column-separator {
|
||||
.csv-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 0.25rem;
|
||||
}
|
||||
|
||||
.header-select {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.column-separator > label {
|
||||
.header-select > label {
|
||||
font-size: small;
|
||||
text-align: end;
|
||||
max-width: 80px;
|
||||
}
|
||||
|
||||
.column-separator > select {
|
||||
.header-select > select {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -109,7 +109,8 @@ export default {
|
||||
return;
|
||||
}
|
||||
|
||||
this.$router.push({ path: this.dest });
|
||||
if (this.user.redirectAfterCopyMove)
|
||||
this.$router.push({ path: this.dest });
|
||||
})
|
||||
.catch((e) => {
|
||||
buttons.done("copy");
|
||||
|
||||
@@ -79,7 +79,7 @@ export default {
|
||||
computed: {
|
||||
...mapState(useFileStore, ["req", "selected"]),
|
||||
...mapState(useAuthStore, ["user"]),
|
||||
...mapWritableState(useFileStore, ["preselect"]),
|
||||
...mapWritableState(useFileStore, ["reload", "preselect"]),
|
||||
excludedFolders() {
|
||||
return this.selected
|
||||
.filter((idx) => this.req.items[idx].isDir)
|
||||
@@ -108,7 +108,9 @@ export default {
|
||||
.then(() => {
|
||||
buttons.success("move");
|
||||
this.preselect = removePrefix(items[0].to);
|
||||
this.$router.push({ path: this.dest });
|
||||
if (this.user.redirectAfterCopyMove)
|
||||
this.$router.push({ path: this.dest });
|
||||
else this.reload = true;
|
||||
})
|
||||
.catch((e) => {
|
||||
buttons.done("move");
|
||||
|
||||
@@ -32,7 +32,8 @@ export default {
|
||||
ja: "日本語",
|
||||
ko: "한국어",
|
||||
no: "Norsk",
|
||||
"nl-be": "Dutch (Belgium)",
|
||||
nl: "Nederlands (Nederland)",
|
||||
"nl-be": "Nederlands (België)",
|
||||
pl: "Polski",
|
||||
"pt-br": "Português (Brasil)",
|
||||
pt: "Português (Portugal)",
|
||||
|
||||
@@ -185,3 +185,7 @@ html[dir="rtl"] .breadcrumbs a {
|
||||
.vfm-modal {
|
||||
z-index: 9999999 !important;
|
||||
}
|
||||
|
||||
body > div[style*="z-index: 9990"] {
|
||||
z-index: 10000 !important;
|
||||
}
|
||||
|
||||
+17
-12
@@ -24,7 +24,7 @@
|
||||
"ok": "موافق",
|
||||
"permalink": "الحصول على رابط دائم",
|
||||
"previous": "السابق",
|
||||
"preview": "Preview",
|
||||
"preview": "معاينة",
|
||||
"publish": "نشر",
|
||||
"rename": "إعادة تسمية",
|
||||
"replace": "استبدال",
|
||||
@@ -42,11 +42,13 @@
|
||||
"update": "تحديث",
|
||||
"upload": "رفع",
|
||||
"openFile": "فتح الملف",
|
||||
"openDirect": "View raw",
|
||||
"discardChanges": "إلغاء التغييرات",
|
||||
"saveChanges": "Save changes",
|
||||
"editAsText": "Edit as Text",
|
||||
"increaseFontSize": "Increase font size",
|
||||
"decreaseFontSize": "Decrease font size"
|
||||
"stopSearch": "توقف عن البحث",
|
||||
"saveChanges": "حفظ التغييرات",
|
||||
"editAsText": "تعديل على شكل نص",
|
||||
"increaseFontSize": "زيادة حجم الخط",
|
||||
"decreaseFontSize": "تصغير حجم الخط"
|
||||
},
|
||||
"download": {
|
||||
"downloadFile": "تحميل الملف",
|
||||
@@ -79,7 +81,7 @@
|
||||
"sortByName": "الترتيب باﻹسم",
|
||||
"sortBySize": "الترتيب بالحجم",
|
||||
"noPreview": "لا يوجد عرض مسبق لهذا الملف.",
|
||||
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
|
||||
"csvTooLarge": "حجم الملف اكبر من (<5MB), يرجى تحميل الملف للمعاينة",
|
||||
"csvLoadFailed": "Failed to load CSV file.",
|
||||
"showingRows": "Showing {count} row(s)",
|
||||
"columnSeparator": "Column Separator",
|
||||
@@ -87,7 +89,8 @@
|
||||
"comma": "Comma (,)",
|
||||
"semicolon": "Semicolon (;)",
|
||||
"both": "Both (,) and (;)"
|
||||
}
|
||||
},
|
||||
"fileEncoding": "File Encoding"
|
||||
},
|
||||
"help": {
|
||||
"click": "حدد الملف أو المجلد",
|
||||
@@ -137,7 +140,7 @@
|
||||
"filesSelected": "تم تحديد {count} ملفات.",
|
||||
"lastModified": "آخر تعديل",
|
||||
"move": "نقل",
|
||||
"moveMessage": "إختر مكان جديد للملفات أو المجلدات المراد نقلها:",
|
||||
"moveMessage": "اختر منزلاً جديداً لملفك (ملفاتك)/مجلدك (مجلداتك):",
|
||||
"newArchetype": "إنشاء منشور من المنشور اﻷصلي. الملف سيتم انشاءه في مجلد المحتويات.",
|
||||
"newDir": "مجلد جديد",
|
||||
"newDirMessage": "أدخل اسم المجلد الجديد.",
|
||||
@@ -188,15 +191,15 @@
|
||||
"commandRunner": "منفذ اﻷوامر",
|
||||
"commandRunnerHelp": "هنا بإمكانك تعيين اﻷوامر التي سيتم تنفيذها في اﻷحداث المسماة. يجب كتابة أمر واحد في كل سطر. ستكون المتغيرات البيئية (env) {0} و {1} متاحة، حيث {0} نسبي لـ {1}. لمزيد من المعلومات حول هذه الميزة و المتغيرات البيئية المتاحة، يرجى قراءة {2}.",
|
||||
"commandsUpdated": "تم تحديث اﻷوامر",
|
||||
"createUserDir": "إنشاء مجلد المستخدم (home) تلقائياً عند إنشاء مستخدم جديد",
|
||||
"createUserDir": "إنشاء مجلد المستخدم الرئيسي تلقائياً عند إنشاء مستخدم جديد",
|
||||
"minimumPasswordLength": "Minimum password length",
|
||||
"tusUploads": "التحميلات المتقطعة",
|
||||
"tusUploadsHelp": "يدعم متصفح الملفات تحميل الملفات المتقطعة، مما يسمح بتحميلات الملفات بشكل فعال و موثوق و قابلة للمتابغة و متقطعة حتى على الشبكات غير الموثوقة.",
|
||||
"tusUploadsChunkSize": "يشير إلى الحد اﻷقصى لحجم الطلب (سيتم استخدام التحميل المباشر للتحميلات صغيرة الخحم). يمكنك إدخال عدد صحيح عادي يدل على الحجم بوحدة البايت أو نمظ مثل10MB, 1GB, إلخ.",
|
||||
"tusUploadsRetryCount": "عدد مرات إعادة المحاولة إذا فشلت عملية تحميل القطعة.",
|
||||
"userHomeBasePath": "المسار الرئيسي لمجلد المستخدم (home)",
|
||||
"userHomeBasePath": "المسار الرئيسي لمجلد المستخدم الرئيسي",
|
||||
"userScopeGenerationPlaceholder": "سيتم تعيين نطاق المستخدم تلقائياً",
|
||||
"createUserHomeDirectory": "إنشاء مجلد المستخدم (home)",
|
||||
"createUserHomeDirectory": "إنشاء مجلد المستخدم الرئيسي",
|
||||
"customStylesheet": "ستايل مخصص",
|
||||
"defaultUserDescription": "هذه اﻹعدادات اﻹفتراضية للمستخدمين الجدد.",
|
||||
"disableExternalLinks": "تعطيل الروابط الخارجية (بإسثناء الوثائق)",
|
||||
@@ -231,6 +234,7 @@
|
||||
"permissions": "الصلاحيات",
|
||||
"permissionsHelp": "يمكنك تعيين المستخدم كـ \"مدير\" أو تحديد الصلاحيات بشكل منفرد.\n إذا قمت بتحديد المستخدم كـ \"مدير\"، باقي الخيارات سيتم تحديدها تلقائياً.\n إدارة المستخدمين تبقى صلاحية فريدة للـ \"مدير\" فقط.\n",
|
||||
"profileSettings": "إعدادات الحساب",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "منع الوصول إلى الملفات التي تبدأ بنقطة مثل (.git، و .gitignore) في كل مجلد.\n",
|
||||
"ruleExample2": "منع الوصول إلى الملف المسمى Caddyfile في نطاق الجذر.",
|
||||
"rules": "المجموعات",
|
||||
@@ -257,7 +261,8 @@
|
||||
"userManagement": "إدارة المستخدمين",
|
||||
"userUpdated": "تم تعديل المستخدم",
|
||||
"username": "إسم المستخدم",
|
||||
"users": "المستخدمين"
|
||||
"users": "المستخدمين",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "مساعدة",
|
||||
|
||||
@@ -42,7 +42,9 @@
|
||||
"update": "Обнови",
|
||||
"upload": "Качи",
|
||||
"openFile": "Отвори файл",
|
||||
"openDirect": "View raw",
|
||||
"discardChanges": "Изчисти",
|
||||
"stopSearch": "Stop searching",
|
||||
"saveChanges": "Запиши промените",
|
||||
"editAsText": "Edit as Text",
|
||||
"increaseFontSize": "Increase font size",
|
||||
@@ -87,7 +89,8 @@
|
||||
"comma": "Comma (,)",
|
||||
"semicolon": "Semicolon (;)",
|
||||
"both": "Both (,) and (;)"
|
||||
}
|
||||
},
|
||||
"fileEncoding": "File Encoding"
|
||||
},
|
||||
"help": {
|
||||
"click": "избери файл или директория",
|
||||
@@ -231,6 +234,7 @@
|
||||
"permissions": "Разрешения",
|
||||
"permissionsHelp": "Можете да зададете потребител да бъде администратор или да изберете разрешения индивидуално. Ако изберете \"Администратор\" всички други опции ще бъдат автоматично отметнати. Управлението на потребителите е привилегия на администратор.\n",
|
||||
"profileSettings": "Настройки на Профила",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "предотвратете достъпа до всеки файл започващ с точка (като .git, .gitignore) във всяка папка.\n",
|
||||
"ruleExample2": "блокира достъпа до файл именуван Caddyfile поставен в началото за обхвата.",
|
||||
"rules": "Правила",
|
||||
@@ -257,7 +261,8 @@
|
||||
"userManagement": "Управление на потребители",
|
||||
"userUpdated": "Потребителя е обновен!",
|
||||
"username": "Потребителско име",
|
||||
"users": "Потребители"
|
||||
"users": "Потребители",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Помощ",
|
||||
|
||||
@@ -42,7 +42,9 @@
|
||||
"update": "Actualitzar",
|
||||
"upload": "Pujar",
|
||||
"openFile": "Obrir fitxer",
|
||||
"openDirect": "View raw",
|
||||
"discardChanges": "Descartar",
|
||||
"stopSearch": "Stop searching",
|
||||
"saveChanges": "Save changes",
|
||||
"editAsText": "Edit as Text",
|
||||
"increaseFontSize": "Increase font size",
|
||||
@@ -87,7 +89,8 @@
|
||||
"comma": "Comma (,)",
|
||||
"semicolon": "Semicolon (;)",
|
||||
"both": "Both (,) and (;)"
|
||||
}
|
||||
},
|
||||
"fileEncoding": "File Encoding"
|
||||
},
|
||||
"help": {
|
||||
"click": "seleccionar fitxer o carpeta",
|
||||
@@ -231,6 +234,7 @@
|
||||
"permissions": "Permisos",
|
||||
"permissionsHelp": "Pots nomenar l'usuari com a administrador o triar els permisos individualment. Si selecciones \"Administrador\", totes les altres opcions s'activaran automàticament. L'administració d'usuaris és un privilegi d'administrador.\n",
|
||||
"profileSettings": "Ajustos del perfil",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "prevé l'accés a una extensió de fitxer (Com .git) en cada carpeta.\n",
|
||||
"ruleExample2": "bloqueja l'accés al fitxer anomenat Caddyfile a la carpeta arrel.",
|
||||
"rules": "Regles",
|
||||
@@ -257,7 +261,8 @@
|
||||
"userManagement": "Administració d'usuaris",
|
||||
"userUpdated": "Usuari actualitzat!",
|
||||
"username": "Usuari",
|
||||
"users": "Usuaris"
|
||||
"users": "Usuaris",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Ajuda",
|
||||
|
||||
@@ -42,7 +42,9 @@
|
||||
"update": "Aktualizovat",
|
||||
"upload": "Nahrát",
|
||||
"openFile": "Otevřít soubor",
|
||||
"openDirect": "View raw",
|
||||
"discardChanges": "Zrušit změny",
|
||||
"stopSearch": "Stop searching",
|
||||
"saveChanges": "Save changes",
|
||||
"editAsText": "Edit as Text",
|
||||
"increaseFontSize": "Increase font size",
|
||||
@@ -87,7 +89,8 @@
|
||||
"comma": "Comma (,)",
|
||||
"semicolon": "Semicolon (;)",
|
||||
"both": "Both (,) and (;)"
|
||||
}
|
||||
},
|
||||
"fileEncoding": "File Encoding"
|
||||
},
|
||||
"help": {
|
||||
"click": "vyberte soubor nebo adresář",
|
||||
@@ -231,6 +234,7 @@
|
||||
"permissions": "Oprávnění",
|
||||
"permissionsHelp": "Můžete nastavit uživatele jako administrátora nebo zvolit jednotlivá oprávnění. Pokud vyberete \"Administrátor\", všechny ostatní možnosti budou automaticky zaškrtnuty. Správa uživatelů zůstává výsadou administrátora.\n",
|
||||
"profileSettings": "Nastavení profilu",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "zabraňuje přístupu k jakémukoli skrytému souboru (např. .git, .gitignore) v každé složce.\n",
|
||||
"ruleExample2": "blokuje přístup k souboru s názvem Caddyfile v kořenovém adresáři.",
|
||||
"rules": "Pravidla",
|
||||
@@ -257,7 +261,8 @@
|
||||
"userManagement": "Správa uživatelů",
|
||||
"userUpdated": "Uživatel aktualizován!",
|
||||
"username": "Uživatelské jméno",
|
||||
"users": "Uživatelé"
|
||||
"users": "Uživatelé",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Nápověda",
|
||||
|
||||
+141
-136
@@ -1,263 +1,268 @@
|
||||
{
|
||||
"buttons": {
|
||||
"cancel": "Abbrechen",
|
||||
"clear": "Schließen",
|
||||
"clear": "Leeren",
|
||||
"close": "Schließen",
|
||||
"continue": "Fortfahren",
|
||||
"continue": "Weiter",
|
||||
"copy": "Kopieren",
|
||||
"copyFile": "Kopiere Datei",
|
||||
"copyFile": "Datei kopieren",
|
||||
"copyToClipboard": "In Zwischenablage kopieren",
|
||||
"copyDownloadLinkToClipboard": "Download-Link in die Zwischenablage kopieren",
|
||||
"create": "Neu",
|
||||
"copyDownloadLinkToClipboard": "Download-Link in Zwischenablage kopieren",
|
||||
"create": "Erstellen",
|
||||
"delete": "Löschen",
|
||||
"download": "Herunterladen",
|
||||
"file": "Datei",
|
||||
"folder": "Ordner",
|
||||
"fullScreen": "Vollbildmodus umschalten",
|
||||
"fullScreen": "Vollbild umschalten",
|
||||
"hideDotfiles": "Versteckte Dateien ausblenden",
|
||||
"info": "Info",
|
||||
"more": "mehr",
|
||||
"more": "Mehr",
|
||||
"move": "Verschieben",
|
||||
"moveFile": "Verschiebe Datei",
|
||||
"moveFile": "Datei verschieben",
|
||||
"new": "Neu",
|
||||
"next": "nächste",
|
||||
"next": "Weiter",
|
||||
"ok": "OK",
|
||||
"permalink": "permanenten Verweis anzeigen",
|
||||
"previous": "vorherige",
|
||||
"permalink": "Permanentlink abrufen",
|
||||
"previous": "Zurück",
|
||||
"preview": "Vorschau",
|
||||
"publish": "Veröffentlichen",
|
||||
"rename": "umbenennen",
|
||||
"rename": "Umbenennen",
|
||||
"replace": "Ersetzen",
|
||||
"reportIssue": "Fehler melden",
|
||||
"reportIssue": "Problem melden",
|
||||
"save": "Speichern",
|
||||
"schedule": "Planung",
|
||||
"schedule": "Planen",
|
||||
"search": "Suchen",
|
||||
"select": "Auswählen",
|
||||
"selectMultiple": "Mehrfachauswahl",
|
||||
"share": "Teilen",
|
||||
"shell": "Kommandozeile ein/ausschalten",
|
||||
"shell": "Shell umschalten",
|
||||
"submit": "Absenden",
|
||||
"switchView": "Ansicht wechseln",
|
||||
"toggleSidebar": "Seitenleiste anzeigen",
|
||||
"update": "Update",
|
||||
"upload": "Upload",
|
||||
"toggleSidebar": "Seitenleiste umschalten",
|
||||
"update": "Aktualisieren",
|
||||
"upload": "Hochladen",
|
||||
"openFile": "Datei öffnen",
|
||||
"openDirect": "View raw",
|
||||
"discardChanges": "Verwerfen",
|
||||
"stopSearch": "Suche beenden",
|
||||
"saveChanges": "Änderungen speichern",
|
||||
"editAsText": "Als Text bearbeiten",
|
||||
"increaseFontSize": "Increase font size",
|
||||
"decreaseFontSize": "Decrease font size"
|
||||
"increaseFontSize": "Schrift vergrößern",
|
||||
"decreaseFontSize": "Schrift verkleinern"
|
||||
},
|
||||
"download": {
|
||||
"downloadFile": "Download Datei",
|
||||
"downloadFolder": "Download Ordner",
|
||||
"downloadFile": "Datei herunterladen",
|
||||
"downloadFolder": "Ordner herunterladen",
|
||||
"downloadSelected": "Auswahl herunterladen"
|
||||
},
|
||||
"upload": {
|
||||
"abortUpload": "Sind Sie sicher, dass Sie den Vorgang abbrechen möchten?"
|
||||
"abortUpload": "Upload wirklich abbrechen?"
|
||||
},
|
||||
"errors": {
|
||||
"forbidden": "Sie haben keine Berechtigung dies abzurufen.",
|
||||
"internal": "Etwas ist schiefgelaufen.",
|
||||
"notFound": "Dieser Ort kann nicht angezeigt werden.",
|
||||
"forbidden": "Du hast keine Berechtigung für diesen Zugriff.",
|
||||
"internal": "Da ist etwas schiefgelaufen.",
|
||||
"notFound": "Dieser Ort ist nicht erreichbar.",
|
||||
"connection": "Der Server ist nicht erreichbar."
|
||||
},
|
||||
"files": {
|
||||
"body": "Body",
|
||||
"body": "Inhalt",
|
||||
"closePreview": "Vorschau schließen",
|
||||
"files": "Dateien",
|
||||
"folders": "Ordner",
|
||||
"home": "Home",
|
||||
"lastModified": "zuletzt verändert",
|
||||
"loading": "Lade...",
|
||||
"lonely": "Hier scheint nichts zu sein...",
|
||||
"home": "Startseite",
|
||||
"lastModified": "Zuletzt geändert",
|
||||
"loading": "Wird geladen …",
|
||||
"lonely": "Hier ist es ganz schön leer …",
|
||||
"metadata": "Metadaten",
|
||||
"multipleSelectionEnabled": "Mehrfachauswahl aktiviert",
|
||||
"name": "Name",
|
||||
"size": "Größe",
|
||||
"sortByLastModified": "Nach Änderungsdatum sortieren",
|
||||
"sortByName": "Nach Namen sortieren",
|
||||
"sortByName": "Nach Name sortieren",
|
||||
"sortBySize": "Nach Größe sortieren",
|
||||
"noPreview": "Für diese Datei ist keine Vorschau verfügbar.",
|
||||
"csvTooLarge": "Die CSV-Datei ist zu groß für die Vorschau (>5 MB). Bitte herunterladen, um sie anzuzeigen.",
|
||||
"csvLoadFailed": "Fehler beim Laden der CSV-Datei.",
|
||||
"showingRows": "Showing {count} row(s)",
|
||||
"columnSeparator": "Column Separator",
|
||||
"csvTooLarge": "Die CSV-Datei ist zu groß für die Vorschau (> 5 MB). Bitte herunterladen, um sie anzuzeigen.",
|
||||
"csvLoadFailed": "CSV-Datei konnte nicht geladen werden.",
|
||||
"showingRows": "{count} Zeile(n) angezeigt",
|
||||
"columnSeparator": "Spaltentrennzeichen",
|
||||
"csvSeparators": {
|
||||
"comma": "Comma (,)",
|
||||
"semicolon": "Semicolon (;)",
|
||||
"both": "Both (,) and (;)"
|
||||
}
|
||||
"comma": "Komma (,)",
|
||||
"semicolon": "Semikolon (;)",
|
||||
"both": "Beides (,) und (;)"
|
||||
},
|
||||
"fileEncoding": "Dateikodierung"
|
||||
},
|
||||
"help": {
|
||||
"click": "Wähle Datei oder Ordner",
|
||||
"click": "Datei oder Verzeichnis auswählen",
|
||||
"ctrl": {
|
||||
"click": "Markiere mehrere Dateien oder Ordner",
|
||||
"f": "Öffnet eine neue Suche",
|
||||
"s": "Speichert eine Datei oder einen Ordner am aktuellen Ort"
|
||||
"click": "mehrere Dateien oder Verzeichnisse auswählen",
|
||||
"f": "Suche öffnen",
|
||||
"s": "Datei speichern oder aktuelles Verzeichnis herunterladen"
|
||||
},
|
||||
"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",
|
||||
"del": "ausgewählte Elemente löschen",
|
||||
"doubleClick": "Datei oder Verzeichnis öffnen",
|
||||
"esc": "Auswahl aufheben und/oder Dialog schließen",
|
||||
"f1": "diese Hilfe anzeigen",
|
||||
"f2": "Datei umbenennen",
|
||||
"help": "Hilfe"
|
||||
},
|
||||
"login": {
|
||||
"createAnAccount": "Account erstellen",
|
||||
"loginInstead": "Account besteht bereits",
|
||||
"createAnAccount": "Konto erstellen",
|
||||
"loginInstead": "Bereits ein Konto vorhanden",
|
||||
"password": "Passwort",
|
||||
"passwordConfirm": "Passwort Bestätigung",
|
||||
"passwordConfirm": "Passwort bestätigen",
|
||||
"passwordsDontMatch": "Passwörter stimmen nicht überein",
|
||||
"signup": "Registrieren",
|
||||
"submit": "Login",
|
||||
"submit": "Anmelden",
|
||||
"username": "Benutzername",
|
||||
"usernameTaken": "Benutzername ist bereits vergeben",
|
||||
"wrongCredentials": "Falsche Zugangsdaten",
|
||||
"usernameTaken": "Benutzername bereits vergeben",
|
||||
"wrongCredentials": "Falsche Anmeldedaten",
|
||||
"passwordTooShort": "Passwort muss mindestens {min} Zeichen lang sein",
|
||||
"logout_reasons": {
|
||||
"inactivity": "Du wurdest aufgrund von Inaktivität abgemeldet."
|
||||
"inactivity": "Du wurdest wegen Inaktivität abgemeldet."
|
||||
}
|
||||
},
|
||||
"permanent": "Permanent",
|
||||
"prompts": {
|
||||
"copy": "Kopieren",
|
||||
"copyMessage": "Wählen Sie einen Zielort zum Kopieren:",
|
||||
"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})?",
|
||||
"deleteUser": "Sind Sie sicher, dass Sie diesen Benutzer löschen möchten?",
|
||||
"deleteTitle": "Lösche Dateien",
|
||||
"copyMessage": "Wähle den Zielort für deine Dateien:",
|
||||
"currentlyNavigating": "Aktueller Pfad:",
|
||||
"deleteMessageMultiple": "Möchtest du wirklich {count} Datei(en) löschen?",
|
||||
"deleteMessageSingle": "Möchtest du diese Datei/diesen Ordner wirklich löschen?",
|
||||
"deleteMessageShare": "Möchtest du diese Freigabe ({path}) wirklich löschen?",
|
||||
"deleteUser": "Möchtest du diesen Benutzer wirklich löschen?",
|
||||
"deleteTitle": "Dateien löschen",
|
||||
"displayName": "Anzeigename:",
|
||||
"download": "Lade Dateien",
|
||||
"downloadMessage": "Wählen Sie ein Format zum Herunterladen aus.",
|
||||
"download": "Dateien herunterladen",
|
||||
"downloadMessage": "Wähle das gewünschte Download-Format.",
|
||||
"error": "Etwas ist schiefgelaufen",
|
||||
"fileInfo": "Dateiinformation",
|
||||
"fileInfo": "Dateiinformationen",
|
||||
"filesSelected": "{count} Dateien ausgewählt.",
|
||||
"lastModified": "Zuletzt geändert",
|
||||
"move": "Verschieben",
|
||||
"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.",
|
||||
"moveMessage": "Wähle den neuen Speicherort für deine Datei(en)/Ordner:",
|
||||
"newArchetype": "Neuen Beitrag basierend auf einem Archetyp erstellen. Die Datei wird im Content-Ordner erstellt.",
|
||||
"newDir": "Neues Verzeichnis",
|
||||
"newDirMessage": "Gib einen Namen für das neue Verzeichnis ein.",
|
||||
"newFile": "Neue Datei",
|
||||
"newFileMessage": "Geben Sie den Namen der neuen Datei an.",
|
||||
"numberDirs": "Anzahl der Ordner",
|
||||
"newFileMessage": "Gib einen Namen für die neue Datei ein.",
|
||||
"numberDirs": "Anzahl der Verzeichnisse",
|
||||
"numberFiles": "Anzahl der Dateien",
|
||||
"rename": "Umbenennen",
|
||||
"renameMessage": "Fügen Sie einen Namen ein für",
|
||||
"renameMessage": "Neuen Namen eingeben für",
|
||||
"replace": "Ersetzen",
|
||||
"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.",
|
||||
"replaceMessage": "Eine der hochzuladenden Dateien hat einen Namenskonflikt. Möchtest du diese Datei überspringen und mit dem Upload fortfahren oder die vorhandene Datei ersetzen?\n",
|
||||
"schedule": "Planen",
|
||||
"scheduleMessage": "Wähle Datum und Uhrzeit für die geplante Veröffentlichung dieses Beitrags.",
|
||||
"show": "Anzeigen",
|
||||
"size": "Größe",
|
||||
"upload": "Upload",
|
||||
"uploadFiles": "Upload von {files} Dateien...",
|
||||
"uploadMessage": "Wählen Sie eine Upload-Methode",
|
||||
"upload": "Hochladen",
|
||||
"uploadFiles": "{files} Dateien werden hochgeladen …",
|
||||
"uploadMessage": "Wähle eine Upload-Option.",
|
||||
"optionalPassword": "Optionales Passwort",
|
||||
"resolution": "Auflösung",
|
||||
"discardEditorChanges": "Möchten Sie die vorgenommenen Änderungen wirklich verwerfen?"
|
||||
"discardEditorChanges": "Möchtest du deine Änderungen wirklich verwerfen?"
|
||||
},
|
||||
"search": {
|
||||
"images": "Bilder",
|
||||
"music": "Musik",
|
||||
"pdf": "PDF",
|
||||
"pressToSearch": "Drücken Sie Enter um zu suchen...",
|
||||
"search": "Suche...",
|
||||
"typeToSearch": "Tippen um zu suchen...",
|
||||
"pressToSearch": "Eingabetaste drücken zum Suchen …",
|
||||
"search": "Suchen …",
|
||||
"typeToSearch": "Suchbegriff eingeben …",
|
||||
"types": "Typen",
|
||||
"video": "Video"
|
||||
},
|
||||
"settings": {
|
||||
"aceEditorTheme": "Ace Editor Theme",
|
||||
"aceEditorTheme": "Ace-Editor-Theme",
|
||||
"admin": "Admin",
|
||||
"administrator": "Administrator",
|
||||
"allowCommands": "Befehle ausführen",
|
||||
"allowEdit": "Bearbeiten, Umbenennen und Löschen von Dateien oder Ordnern",
|
||||
"allowNew": "Erstellen neuer Dateien und Ordner",
|
||||
"allowPublish": "Veröffentlichen von neuen Beiträgen und Seiten",
|
||||
"allowSignup": "Erlaube Benutzern sich zu registrieren",
|
||||
"hideLoginButton": "Den Login-Button auf öffentlichen Seiten ausblenden",
|
||||
"avoidChanges": "(leer lassen, um Änderungen zu vermeiden)",
|
||||
"branding": "Design",
|
||||
"brandingDirectoryPath": "Designverzeichnispfad",
|
||||
"brandingHelp": "Sie können das Erscheinungsbild Ihres File Browser anpassen, in dem Sie den Namen ändern, das Logo austauschen 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}.",
|
||||
"allowEdit": "Dateien und Verzeichnisse bearbeiten, umbenennen und löschen",
|
||||
"allowNew": "Neue Dateien und Verzeichnisse erstellen",
|
||||
"allowPublish": "Neue Beiträge und Seiten veröffentlichen",
|
||||
"allowSignup": "Registrierung erlauben",
|
||||
"hideLoginButton": "Anmelde-Button auf öffentlichen Seiten ausblenden",
|
||||
"avoidChanges": "(leer lassen, um keine Änderungen vorzunehmen)",
|
||||
"branding": "Branding",
|
||||
"brandingDirectoryPath": "Branding-Verzeichnispfad",
|
||||
"brandingHelp": "Du kannst das Erscheinungsbild deiner File-Browser-Instanz anpassen, indem du den Namen änderst, das Logo ersetzt, eigene Styles hinzufügst und sogar externe Links zu GitHub deaktivierst.\nWeitere Informationen zum Branding findest du in der {0}.",
|
||||
"changePassword": "Passwort ändern",
|
||||
"commandRunner": "Befehlseingabe",
|
||||
"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}.",
|
||||
"commandRunner": "Befehlsausführung",
|
||||
"commandRunnerHelp": "Hier kannst du Befehle festlegen, die bei bestimmten Ereignissen ausgeführt werden. Schreibe einen Befehl pro Zeile. Die Umgebungsvariablen {0} und {1} sind verfügbar, wobei {0} relativ zu {1} ist. Weitere Informationen zu dieser Funktion und den verfügbaren Umgebungsvariablen findest du in der {2}.",
|
||||
"commandsUpdated": "Befehle aktualisiert!",
|
||||
"createUserDir": "Automatisches Erstellen des Home-Verzeichnisses beim Anlegen neuer Benutzer",
|
||||
"minimumPasswordLength": "Mindestlänge für Passwörter",
|
||||
"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.",
|
||||
"userHomeBasePath": "Basispfad für Benutzer-Home-Verzeichnisse",
|
||||
"userScopeGenerationPlaceholder": "Scope wird automatisch generiert",
|
||||
"createUserHomeDirectory": "Benutzer-Home-Verzeichnis erstellen",
|
||||
"customStylesheet": "Individuelles Stylesheet",
|
||||
"defaultUserDescription": "Das sind die Standardeinstellung für Benutzer",
|
||||
"createUserDir": "Benutzerverzeichnis beim Erstellen neuer Benutzer automatisch anlegen",
|
||||
"minimumPasswordLength": "Mindestlänge des Passworts",
|
||||
"tusUploads": "Uploads in Teilen",
|
||||
"tusUploadsHelp": "File Browser unterstützt das Hochladen von Dateien in Teilen. So sind effiziente, zuverlässige und fortsetzbare Uploads auch bei instabilen Netzwerkverbindungen möglich.",
|
||||
"tusUploadsChunkSize": "Gibt die maximale Größe einer Anfrage an (kleinere Dateien werden direkt hochgeladen). Du kannst eine Zahl in Bytes oder einen String wie 10MB, 1GB usw. eingeben.",
|
||||
"tusUploadsRetryCount": "Anzahl der Wiederholungsversuche bei fehlgeschlagenem Teil-Upload.",
|
||||
"userHomeBasePath": "Basispfad für Benutzerverzeichnisse",
|
||||
"userScopeGenerationPlaceholder": "Der Bereich wird automatisch generiert",
|
||||
"createUserHomeDirectory": "Benutzerverzeichnis erstellen",
|
||||
"customStylesheet": "Eigenes Stylesheet",
|
||||
"defaultUserDescription": "Dies sind die Standardeinstellungen für neue Benutzer.",
|
||||
"disableExternalLinks": "Externe Links deaktivieren (außer Dokumentation)",
|
||||
"disableUsedDiskPercentage": "Diagramm zur Festplattennutzung deaktivieren",
|
||||
"disableUsedDiskPercentage": "Speicherplatzanzeige deaktivieren",
|
||||
"documentation": "Dokumentation",
|
||||
"examples": "Beispiele",
|
||||
"executeOnShell": "In Shell ausführen",
|
||||
"executeOnShellDescription": "Es ist voreingestellt, dass der File Brower Befehle ausführt, indem 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 benötigten Argumenten und Optionen. Wenn gesetzt, wird das Kommando das ausgeführt werden soll als Parameter angehängt. Das gilt für Benutzerkommandos 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.",
|
||||
"executeOnShellDescription": "Standardmäßig führt File Browser Befehle durch direkten Aufruf der Binärdateien aus. Wenn du sie stattdessen in einer Shell (wie Bash oder PowerShell) ausführen möchtest, kannst du diese hier mit den erforderlichen Argumenten und Flags angeben. Der auszuführende Befehl wird dann als Argument angehängt. Dies gilt sowohl für Benutzerbefehle als auch für Event-Hooks.",
|
||||
"globalRules": "Dies ist ein globaler Satz von Erlauben- und Verbieten-Regeln. Sie gelten für alle Benutzer. Du kannst in den Einstellungen einzelner Benutzer spezifische Regeln festlegen, um diese zu überschreiben.",
|
||||
"globalSettings": "Globale Einstellungen",
|
||||
"hideDotfiles": "Versteckte Dateien ausblenden",
|
||||
"insertPath": "Pfad einfügen",
|
||||
"insertRegex": "Regulären Ausdruck (Regex) einfügen",
|
||||
"insertPath": "Pfad eingeben",
|
||||
"insertRegex": "Regulären Ausdruck eingeben",
|
||||
"instanceName": "Instanzname",
|
||||
"language": "Sprache",
|
||||
"lockPassword": "Verhindere, dass der Benutzer sein Passwort ändert",
|
||||
"newPassword": "Ihr neues Passwort.",
|
||||
"newPasswordConfirm": "Bestätigen Sie Ihr neues Passwort",
|
||||
"lockPassword": "Benutzer daran hindern, das Passwort zu ändern",
|
||||
"newPassword": "Dein neues Passwort",
|
||||
"newPasswordConfirm": "Neues Passwort bestätigen",
|
||||
"newUser": "Neuer Benutzer",
|
||||
"password": "Passwort",
|
||||
"passwordUpdated": "Passwort aktualisiert!",
|
||||
"path": "Pfad",
|
||||
"perm": {
|
||||
"create": "Dateien und Ordner erstellen",
|
||||
"delete": "Dateien und Ordner löschen",
|
||||
"download": "Download",
|
||||
"create": "Dateien und Verzeichnisse erstellen",
|
||||
"delete": "Dateien und Verzeichnisse löschen",
|
||||
"download": "Herunterladen",
|
||||
"execute": "Befehle ausführen",
|
||||
"modify": "Dateien editieren",
|
||||
"rename": "Umbenennen oder Verschieben von Dateien oder Ordnern",
|
||||
"share": "Datei teilen"
|
||||
"modify": "Dateien bearbeiten",
|
||||
"rename": "Dateien und Verzeichnisse umbenennen oder verschieben",
|
||||
"share": "Dateien teilen"
|
||||
},
|
||||
"permissions": "Berechtigungen",
|
||||
"permissionsHelp": "Sie können einem Benutzer Administratorrechte einräumen oder die Berechtigungen individuell festlegen. Wenn Sie \"Administrator\" auswählen, werden alle anderen Rechte automatisch vergeben. Die Nutzerverwaltung kann nur durch einen Administrator erfolgen.\n",
|
||||
"permissionsHelp": "Du kannst den Benutzer zum Administrator machen oder die Berechtigungen einzeln festlegen. Wenn du \"Administrator\" wählst, werden automatisch alle anderen Optionen aktiviert. Die Benutzerverwaltung bleibt ein Administratorrecht.\n",
|
||||
"profileSettings": "Profileinstellungen",
|
||||
"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.",
|
||||
"redirectAfterCopyMove": "Nach Kopieren/Verschieben zum Ziel wechseln",
|
||||
"ruleExample1": "verhindert den Zugriff auf alle versteckten Dateien (wie .git, .gitignore) in jedem Ordner.\n",
|
||||
"ruleExample2": "blockiert den Zugriff auf die Datei namens Caddyfile im Stammverzeichnis des Bereichs.",
|
||||
"rules": "Regeln",
|
||||
"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",
|
||||
"rulesHelp": "Hier kannst du Erlauben- und Verbieten-Regeln für diesen Benutzer festlegen. Blockierte Dateien werden nicht in den Auflistungen angezeigt und sind für den Benutzer nicht zugänglich. Wir unterstützen Regex und Pfade relativ zum Benutzerbereich.\n",
|
||||
"scope": "Bereich",
|
||||
"setDateFormat": "Genaues Datumsformat festlegen",
|
||||
"settingsUpdated": "Einstellungen aktualisiert!",
|
||||
"shareDuration": "Dauer",
|
||||
"shareManagement": "Freigaben verwalten",
|
||||
"shareDuration": "Freigabedauer",
|
||||
"shareManagement": "Freigabeverwaltung",
|
||||
"shareDeleted": "Freigabe gelöscht!",
|
||||
"singleClick": "Einfacher Klick zum Öffnen von Dateien und Ordnern",
|
||||
"singleClick": "Einfacher Klick zum Öffnen von Dateien und Verzeichnissen",
|
||||
"themes": {
|
||||
"default": "Systemstandard",
|
||||
"dark": "Dunkel",
|
||||
"light": "Hell",
|
||||
"title": "Erscheinungsbild"
|
||||
"title": "Design"
|
||||
},
|
||||
"user": "Benutzer",
|
||||
"userCommands": "Befehle",
|
||||
"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",
|
||||
"userCommandsHelp": "Eine durch Leerzeichen getrennte Liste der verfügbaren Befehle für diesen Benutzer. Beispiel:\n",
|
||||
"userCreated": "Benutzer erstellt!",
|
||||
"userDefaults": "Standardeinstellungen für Benutzer",
|
||||
"userDeleted": "Benutzer gelöscht!",
|
||||
"userManagement": "Benutzerverwaltung",
|
||||
"userUpdated": "Benutzer aktualisiert!",
|
||||
"username": "Nutzername",
|
||||
"users": "Nutzer"
|
||||
"username": "Benutzername",
|
||||
"users": "Benutzer",
|
||||
"currentPassword": "Dein aktuelles Passwort"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Hilfe",
|
||||
@@ -270,10 +275,10 @@
|
||||
"preview": "Vorschau",
|
||||
"settings": "Einstellungen",
|
||||
"signup": "Registrieren",
|
||||
"siteSettings": "Seiteneinstellungen"
|
||||
"siteSettings": "Website-Einstellungen"
|
||||
},
|
||||
"success": {
|
||||
"linkCopied": "Verweis wurde kopiert!"
|
||||
"linkCopied": "Link kopiert!"
|
||||
},
|
||||
"time": {
|
||||
"days": "Tage",
|
||||
|
||||
@@ -42,7 +42,9 @@
|
||||
"update": "Ενημέρωση",
|
||||
"upload": "Μεταφόρτωση",
|
||||
"openFile": "Άνοιγμα αρχείου",
|
||||
"openDirect": "View raw",
|
||||
"discardChanges": "Discard",
|
||||
"stopSearch": "Stop searching",
|
||||
"saveChanges": "Save changes",
|
||||
"editAsText": "Edit as Text",
|
||||
"increaseFontSize": "Increase font size",
|
||||
@@ -87,7 +89,8 @@
|
||||
"comma": "Comma (,)",
|
||||
"semicolon": "Semicolon (;)",
|
||||
"both": "Both (,) and (;)"
|
||||
}
|
||||
},
|
||||
"fileEncoding": "File Encoding"
|
||||
},
|
||||
"help": {
|
||||
"click": "επιλέξτε αρχείο ή φάκελο",
|
||||
@@ -231,6 +234,7 @@
|
||||
"permissions": "Δικαιώματα",
|
||||
"permissionsHelp": "Μπορείτε να ορίσετε τον χρήστη ως διαχειριστή ή να επιλέξετε τα δικαιώματα μεμονωμένα. Αν επιλέξετε \"Διαχειριστής\", όλες οι υπόλοιπες επιλογές θα είναι αυτόματα επιλεγμένες. Η διαχείριση χρηστών παραμένει προνόμιο ενός χρήστη με τον ρόλο του διαχειριστή.\n",
|
||||
"profileSettings": "Ρυθμίσεις προφίλ",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "αποκλείει την πρόσβαση σε οποιοδήποτε κρυφό αρχείο (όπως .git, .gitignore) σε κάθε φάκελο.\n",
|
||||
"ruleExample2": "αποκλείει την πρόσβαση στο αρχείο με το όνομα Caddyfile στον ριζικό φάκελο της εμβέλειας του κανόνα.",
|
||||
"rules": "Κανόνες",
|
||||
@@ -257,7 +261,8 @@
|
||||
"userManagement": "Διαχείριση χρηστών",
|
||||
"userUpdated": "Ο χρήστης ενημερώθηκε!",
|
||||
"username": "Όνομα χρήστη",
|
||||
"users": "Χρήστες"
|
||||
"users": "Χρήστες",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Βοήθεια",
|
||||
|
||||
@@ -42,7 +42,9 @@
|
||||
"update": "Update",
|
||||
"upload": "Upload",
|
||||
"openFile": "Open file",
|
||||
"openDirect": "View raw",
|
||||
"discardChanges": "Discard",
|
||||
"stopSearch": "Stop searching",
|
||||
"saveChanges": "Save changes",
|
||||
"editAsText": "Edit as Text",
|
||||
"increaseFontSize": "Increase font size",
|
||||
@@ -87,7 +89,8 @@
|
||||
"comma": "Comma (,)",
|
||||
"semicolon": "Semicolon (;)",
|
||||
"both": "Both (,) and (;)"
|
||||
}
|
||||
},
|
||||
"fileEncoding": "File Encoding"
|
||||
},
|
||||
"help": {
|
||||
"click": "select file or directory",
|
||||
@@ -231,6 +234,7 @@
|
||||
"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",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"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",
|
||||
@@ -257,7 +261,8 @@
|
||||
"userManagement": "User Management",
|
||||
"userUpdated": "User updated!",
|
||||
"username": "Username",
|
||||
"users": "Users"
|
||||
"users": "Users",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Help",
|
||||
|
||||
@@ -42,7 +42,9 @@
|
||||
"update": "Actualizar",
|
||||
"upload": "Subir",
|
||||
"openFile": "Abrir archivo",
|
||||
"openDirect": "View raw",
|
||||
"discardChanges": "Discard",
|
||||
"stopSearch": "Stop searching",
|
||||
"saveChanges": "Guardar cambios",
|
||||
"editAsText": "Edit as Text",
|
||||
"increaseFontSize": "Increase font size",
|
||||
@@ -87,7 +89,8 @@
|
||||
"comma": "Comma (,)",
|
||||
"semicolon": "Semicolon (;)",
|
||||
"both": "Both (,) and (;)"
|
||||
}
|
||||
},
|
||||
"fileEncoding": "File Encoding"
|
||||
},
|
||||
"help": {
|
||||
"click": "seleccionar archivo o carpeta",
|
||||
@@ -231,6 +234,7 @@
|
||||
"permissions": "Permisos",
|
||||
"permissionsHelp": "Puedes nombrar al usuario como administrador o elegir los permisos individualmente. Si seleccionas \"Administrador\", todas las otras opciones serán activadas automáticamente. La administración de usuarios es un privilegio de administrador.\n",
|
||||
"profileSettings": "Ajustes del perfil",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "previene el acceso a una extensión de archivo (Como .git) en cada carpeta.\n",
|
||||
"ruleExample2": "bloquea el acceso al archivo llamado Caddyfile en la carpeta raíz.",
|
||||
"rules": "Reglas",
|
||||
@@ -257,7 +261,8 @@
|
||||
"userManagement": "Administración de usuarios",
|
||||
"userUpdated": "¡Usuario actualizado!",
|
||||
"username": "Usuario",
|
||||
"users": "Usuarios"
|
||||
"users": "Usuarios",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Ayuda",
|
||||
|
||||
@@ -42,7 +42,9 @@
|
||||
"update": "به روز سانی",
|
||||
"upload": "آپلود",
|
||||
"openFile": "باز کردن فایل",
|
||||
"openDirect": "View raw",
|
||||
"discardChanges": "لغو کردن",
|
||||
"stopSearch": "Stop searching",
|
||||
"saveChanges": "Save changes",
|
||||
"editAsText": "Edit as Text",
|
||||
"increaseFontSize": "Increase font size",
|
||||
@@ -87,7 +89,8 @@
|
||||
"comma": "Comma (,)",
|
||||
"semicolon": "Semicolon (;)",
|
||||
"both": "Both (,) and (;)"
|
||||
}
|
||||
},
|
||||
"fileEncoding": "File Encoding"
|
||||
},
|
||||
"help": {
|
||||
"click": "انتخاب فایل یا پوشه",
|
||||
@@ -231,6 +234,7 @@
|
||||
"permissions": "دسترسی ها",
|
||||
"permissionsHelp": "شما میتوانید کاربر را به عنوان مدیر تنظیم کنید یا دسترسیها را به صورت جداگانه انتخاب کنید. اگر \"مدیر\" را انتخاب کنید، تمام گزینههای دیگر به طور خودکار اعمال میشوند. مدیریت کاربران همچنان از اختیارات مدیر است.",
|
||||
"profileSettings": "تنظیمات ناحیه کاربری",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "از دسترسی به هرگونه فایل نقطهای (مانند .git، .gitignore) در هر پوشه جلوگیری میکند.",
|
||||
"ruleExample2": "دسترسی به فایلی به نام Caddyfile را در ریشه دامنه مسدود میکند.",
|
||||
"rules": "قواعد",
|
||||
@@ -257,7 +261,8 @@
|
||||
"userManagement": "مدیریت کاربران",
|
||||
"userUpdated": "کاربر به روز شد!",
|
||||
"username": "نام کاربری",
|
||||
"users": "کاربران"
|
||||
"users": "کاربران",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "راهنما",
|
||||
|
||||
+22
-17
@@ -42,11 +42,13 @@
|
||||
"update": "Mettre à jour",
|
||||
"upload": "Importer",
|
||||
"openFile": "Ouvrir le fichier",
|
||||
"openDirect": "View raw",
|
||||
"discardChanges": "Annuler",
|
||||
"saveChanges": "Save changes",
|
||||
"editAsText": "Edit as Text",
|
||||
"increaseFontSize": "Increase font size",
|
||||
"decreaseFontSize": "Decrease font size"
|
||||
"stopSearch": "Arrêter recherche",
|
||||
"saveChanges": "Enregistrer changements",
|
||||
"editAsText": "Editer comme Texte",
|
||||
"increaseFontSize": "Augmenter taille police",
|
||||
"decreaseFontSize": "Réduire taille police"
|
||||
},
|
||||
"download": {
|
||||
"downloadFile": "Télécharger le fichier",
|
||||
@@ -79,15 +81,16 @@
|
||||
"sortByName": "Trier par nom",
|
||||
"sortBySize": "Trier par taille",
|
||||
"noPreview": "L'aperçu n'est pas disponible pour ce fichier.",
|
||||
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
|
||||
"csvLoadFailed": "Failed to load CSV file.",
|
||||
"showingRows": "Showing {count} row(s)",
|
||||
"columnSeparator": "Column Separator",
|
||||
"csvTooLarge": "Le fichier CSV est trop volumineux pour être prévisualisé (>5MB). Veuillez le télécharger pour le voir.",
|
||||
"csvLoadFailed": "Impossible de charger le fichier CSV.",
|
||||
"showingRows": "Affichage de {count} ligne(s)",
|
||||
"columnSeparator": "Séparateur de Colonnes",
|
||||
"csvSeparators": {
|
||||
"comma": "Comma (,)",
|
||||
"semicolon": "Semicolon (;)",
|
||||
"both": "Both (,) and (;)"
|
||||
}
|
||||
"comma": "Virgule (,)",
|
||||
"semicolon": "Point-virgule (;)",
|
||||
"both": "Les (,) et (;)"
|
||||
},
|
||||
"fileEncoding": "File Encoding"
|
||||
},
|
||||
"help": {
|
||||
"click": "Sélectionner un fichier ou dossier",
|
||||
@@ -114,9 +117,9 @@
|
||||
"username": "Utilisateur·ice",
|
||||
"usernameTaken": "Le nom d'utilisateur·ice est déjà pris",
|
||||
"wrongCredentials": "Identifiants incorrects !",
|
||||
"passwordTooShort": "Password must be at least {min} characters",
|
||||
"passwordTooShort": "Le mot de passe doit contenir au moins {min} caractères",
|
||||
"logout_reasons": {
|
||||
"inactivity": "You have been logged out due to inactivity."
|
||||
"inactivity": "Vous avez été déconnecté(e) en raison d'une inactivité prolongée."
|
||||
}
|
||||
},
|
||||
"permanent": "Permanent",
|
||||
@@ -171,7 +174,7 @@
|
||||
"video": "Vidéo"
|
||||
},
|
||||
"settings": {
|
||||
"aceEditorTheme": "Ace editor theme",
|
||||
"aceEditorTheme": "Éditeur de Thème Ace",
|
||||
"admin": "Admin",
|
||||
"administrator": "Administrateur·ice",
|
||||
"allowCommands": "Exécuter des commandes",
|
||||
@@ -179,7 +182,7 @@
|
||||
"allowNew": "Créer de nouveaux fichiers et dossiers",
|
||||
"allowPublish": "Publier de nouveaux posts et pages",
|
||||
"allowSignup": "Autoriser les utilisateur·ices à s'inscrire",
|
||||
"hideLoginButton": "Hide the login button from public pages",
|
||||
"hideLoginButton": "Cacher le bouton d’identification sur les pages publiques",
|
||||
"avoidChanges": "(Laisser vide pour conserver l'actuel)",
|
||||
"branding": "Image de marque",
|
||||
"brandingDirectoryPath": "Chemin du dossier d'image de marque",
|
||||
@@ -231,6 +234,7 @@
|
||||
"permissions": "Permissions",
|
||||
"permissionsHelp": "Vous pouvez définir l'utilisateur·ice comme étant administrateur·ice ou encore choisir les permissions individuellement. Si vous sélectionnez \"Administrateur·ice\", toutes les autres options seront automatiquement activées. La gestion des utilisateur·ices est un privilège que seul l'administrateur·ice possède.\n",
|
||||
"profileSettings": "Paramètres du profil",
|
||||
"redirectAfterCopyMove": "Rediriger vers la destination après une copie/déplacement",
|
||||
"ruleExample1": "Bloque l'accès à tous les fichiers commençant par un point (comme par exemple .git, .gitignore) dans tous les dossiers.\n",
|
||||
"ruleExample2": "Bloque l'accès au fichier nommé \"Caddyfile\" à la racine du dossier utilisateur·ice.",
|
||||
"rules": "Règles",
|
||||
@@ -257,7 +261,8 @@
|
||||
"userManagement": "Gestion des utilisateur·ices",
|
||||
"userUpdated": "Utilisateur·ice mis à jour !",
|
||||
"username": "Nom d'utilisateur·ice",
|
||||
"users": "Utilisateur·ices"
|
||||
"users": "Utilisateur·ices",
|
||||
"currentPassword": "Mot de Passe Actuel"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Aide",
|
||||
|
||||
@@ -42,7 +42,9 @@
|
||||
"update": "עדכון",
|
||||
"upload": "העלאה",
|
||||
"openFile": "פתח קובץ",
|
||||
"openDirect": "View raw",
|
||||
"discardChanges": "זריקת השינויים",
|
||||
"stopSearch": "Stop searching",
|
||||
"saveChanges": "Save changes",
|
||||
"editAsText": "Edit as Text",
|
||||
"increaseFontSize": "Increase font size",
|
||||
@@ -87,7 +89,8 @@
|
||||
"comma": "Comma (,)",
|
||||
"semicolon": "Semicolon (;)",
|
||||
"both": "Both (,) and (;)"
|
||||
}
|
||||
},
|
||||
"fileEncoding": "File Encoding"
|
||||
},
|
||||
"help": {
|
||||
"click": "בחר קובץ או תיקייה",
|
||||
@@ -231,6 +234,7 @@
|
||||
"permissions": "הרשאות",
|
||||
"permissionsHelp": "אתה יכול להגדיר את המשתמש להיות מנהל מערכת או לבחור את ההרשאות בנפרד. אם תבחר \"מנהל מערכת\", כל ההרשאות יינתנו אוטומטית. ניהול המשתמשים נשאר הרשאה של מנהל מערכת.\n",
|
||||
"profileSettings": "הגדרות פרופיל",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "מנע גישה לקבצים נסתרים (כל קובץ/תיקייה שמתחיל בנקודה, לדוגמא .git)",
|
||||
"ruleExample2": "חסימת גישה לקובץ בשם Caddyfile בהיקף הראשי.",
|
||||
"rules": "חוקים",
|
||||
@@ -257,7 +261,8 @@
|
||||
"userManagement": "ניהול משתמש",
|
||||
"userUpdated": "המשתמש עודכן!",
|
||||
"username": "שם משתמש",
|
||||
"users": "משתמשים"
|
||||
"users": "משתמשים",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "עזרה",
|
||||
|
||||
+17
-12
@@ -42,11 +42,13 @@
|
||||
"update": "Ažuriraj",
|
||||
"upload": "Prenesi",
|
||||
"openFile": "Otvori datoteku",
|
||||
"openDirect": "View raw",
|
||||
"discardChanges": "Odbaci",
|
||||
"stopSearch": "Stop searching",
|
||||
"saveChanges": "Spremi promjene",
|
||||
"editAsText": "Edit as Text",
|
||||
"increaseFontSize": "Increase font size",
|
||||
"decreaseFontSize": "Decrease font size"
|
||||
"editAsText": "Uredi kao tekst",
|
||||
"increaseFontSize": "Povećaj veličinu fonta",
|
||||
"decreaseFontSize": "Smanji veličinu fonta"
|
||||
},
|
||||
"download": {
|
||||
"downloadFile": "Preuzmi Datoteku",
|
||||
@@ -79,15 +81,16 @@
|
||||
"sortByName": "Sortiraj po nazivu",
|
||||
"sortBySize": "Sortiraj po veličini",
|
||||
"noPreview": "Pregled nije dostupan za ovu datoteku.",
|
||||
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
|
||||
"csvLoadFailed": "Failed to load CSV file.",
|
||||
"showingRows": "Showing {count} row(s)",
|
||||
"columnSeparator": "Column Separator",
|
||||
"csvTooLarge": "CSV datoteka je prevelika za pregled (>5MB). Molimo preuzmite da bi ste ju pregledali.",
|
||||
"csvLoadFailed": "Neuspješno učitavanje CSV datoteke.",
|
||||
"showingRows": "Prikazuje se {count} red(ova)",
|
||||
"columnSeparator": "Separator stupaca",
|
||||
"csvSeparators": {
|
||||
"comma": "Comma (,)",
|
||||
"semicolon": "Semicolon (;)",
|
||||
"both": "Both (,) and (;)"
|
||||
}
|
||||
"comma": "Zarez (,)",
|
||||
"semicolon": "Točka zarez (;)",
|
||||
"both": "I (,) i (;)"
|
||||
},
|
||||
"fileEncoding": "File Encoding"
|
||||
},
|
||||
"help": {
|
||||
"click": "odaberi datoteku ili mapu",
|
||||
@@ -231,6 +234,7 @@
|
||||
"permissions": "Dopuštenja",
|
||||
"permissionsHelp": "Korisnika možete postaviti administratorom ili odabrati dopuštenja individualno. Odabirom na \"Administrator\", sve druge opcije bit će automatski odabrane. Upravljanje korisnicima ostaje privilegija administratora.\n",
|
||||
"profileSettings": "Postavke profila",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "onemogućava pristup svakoj datoteci koja započinje točkom (poput .git, .gitignore) u svakoj mapi.\n",
|
||||
"ruleExample2": "blokira pristup datoteci naziva Caddyfile na korijenu opsega.",
|
||||
"rules": "Pravila",
|
||||
@@ -257,7 +261,8 @@
|
||||
"userManagement": "Upravljanje Korisnicima",
|
||||
"userUpdated": "Korisnik ažuriran!",
|
||||
"username": "Korisničko ime",
|
||||
"users": "Korisnici"
|
||||
"users": "Korisnici",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Pomoć",
|
||||
|
||||
@@ -42,7 +42,9 @@
|
||||
"update": "Frissítés",
|
||||
"upload": "Feltöltés",
|
||||
"openFile": "Fájl megnyitása",
|
||||
"openDirect": "View raw",
|
||||
"discardChanges": "Discard",
|
||||
"stopSearch": "Stop searching",
|
||||
"saveChanges": "Save changes",
|
||||
"editAsText": "Edit as Text",
|
||||
"increaseFontSize": "Increase font size",
|
||||
@@ -87,7 +89,8 @@
|
||||
"comma": "Comma (,)",
|
||||
"semicolon": "Semicolon (;)",
|
||||
"both": "Both (,) and (;)"
|
||||
}
|
||||
},
|
||||
"fileEncoding": "File Encoding"
|
||||
},
|
||||
"help": {
|
||||
"click": "mappa vagy fájl kijelölése",
|
||||
@@ -231,6 +234,7 @@
|
||||
"permissions": "Jogosultságok",
|
||||
"permissionsHelp": "A felhasználót beállíthatja rendszergazdának, vagy egyénileg is kiválaszthatja a jogosultságokat. Ha a \"Rendszergazda\" lehetőséget választja, az összes többi opció automatikusan be lesz jelölve. A felhasználók kezelése továbbra is a rendszergazda kiváltsága marad.\n",
|
||||
"profileSettings": "Profilbeállítások",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "megakadályozza a hozzáférést bármely rejtett fájlhoz (pl. .git, .gitignore) bármely mappában.\n",
|
||||
"ruleExample2": "blokkolja a hozzáférést a Caddyfile nevű fájlhoz a hatókör gyökerében.",
|
||||
"rules": "Szabályok",
|
||||
@@ -257,7 +261,8 @@
|
||||
"userManagement": "Felhasználókezelés",
|
||||
"userUpdated": "Felhasználó frissítve!",
|
||||
"username": "Felhasználói név",
|
||||
"users": "Felhasználók"
|
||||
"users": "Felhasználók",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Súgó",
|
||||
|
||||
@@ -17,6 +17,7 @@ import("dayjs/locale/it");
|
||||
import("dayjs/locale/ja");
|
||||
import("dayjs/locale/ko");
|
||||
import("dayjs/locale/nb");
|
||||
import("dayjs/locale/nl");
|
||||
import("dayjs/locale/nl-be");
|
||||
import("dayjs/locale/pl");
|
||||
import("dayjs/locale/pt-br");
|
||||
@@ -110,7 +111,6 @@ export function detectLocale() {
|
||||
case /^uk\b/.test(locale):
|
||||
locale = "uk";
|
||||
break;
|
||||
|
||||
case /^vi\b/.test(locale):
|
||||
locale = "vi";
|
||||
break;
|
||||
@@ -118,6 +118,9 @@ export function detectLocale() {
|
||||
case /^sv\b/.test(locale):
|
||||
locale = "sv";
|
||||
break;
|
||||
case /^nl\b/.test(locale):
|
||||
locale = "nl";
|
||||
break;
|
||||
case /^nl-be\b/.test(locale):
|
||||
locale = "nl-be";
|
||||
break;
|
||||
|
||||
@@ -42,7 +42,9 @@
|
||||
"update": "Vista",
|
||||
"upload": "Hlaða upp",
|
||||
"openFile": "Open file",
|
||||
"openDirect": "View raw",
|
||||
"discardChanges": "Discard",
|
||||
"stopSearch": "Stop searching",
|
||||
"saveChanges": "Save changes",
|
||||
"editAsText": "Edit as Text",
|
||||
"increaseFontSize": "Increase font size",
|
||||
@@ -87,7 +89,8 @@
|
||||
"comma": "Comma (,)",
|
||||
"semicolon": "Semicolon (;)",
|
||||
"both": "Both (,) and (;)"
|
||||
}
|
||||
},
|
||||
"fileEncoding": "File Encoding"
|
||||
},
|
||||
"help": {
|
||||
"click": "velja skjal eða möppu",
|
||||
@@ -231,6 +234,7 @@
|
||||
"permissions": "Heimildir",
|
||||
"permissionsHelp": "Þú getur stillt notenda sem stjórnanda eða valið einstaklingsbundnar heimildir. Ef þú velur \"Stjórnandi\", þá verða allir aðrir valmöguleikar valdir sjálfrafa. Aðgangstýring notenda er á hendi stjórnenda. \n",
|
||||
"profileSettings": "Stilla prófíl",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "kemur í veg fyrir aðgang að dot-skjali (t.d. .git, .gitignore) í öllum möppum. \n",
|
||||
"ruleExample2": "kemur í veg fyrir aðgang að Caddyfile-skjalinu í root-möppu í sýn notandans. ",
|
||||
"rules": "Reglur",
|
||||
@@ -257,7 +261,8 @@
|
||||
"userManagement": "Notendastýring",
|
||||
"userUpdated": "Notandastillingar vistaðar!",
|
||||
"username": "Notendanafn",
|
||||
"users": "Notendur"
|
||||
"users": "Notendur",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Hjálp",
|
||||
|
||||
@@ -42,7 +42,9 @@
|
||||
"update": "Aggiorna",
|
||||
"upload": "Carica",
|
||||
"openFile": "Apri file",
|
||||
"openDirect": "View raw",
|
||||
"discardChanges": "Ignora",
|
||||
"stopSearch": "Stop searching",
|
||||
"saveChanges": "Save changes",
|
||||
"editAsText": "Edit as Text",
|
||||
"increaseFontSize": "Increase font size",
|
||||
@@ -87,7 +89,8 @@
|
||||
"comma": "Comma (,)",
|
||||
"semicolon": "Semicolon (;)",
|
||||
"both": "Both (,) and (;)"
|
||||
}
|
||||
},
|
||||
"fileEncoding": "File Encoding"
|
||||
},
|
||||
"help": {
|
||||
"click": "seleziona un file o una cartella",
|
||||
@@ -231,6 +234,7 @@
|
||||
"permissions": "Permessi",
|
||||
"permissionsHelp": "È possibile impostare l'utente come amministratore o scegliere i permessi singolarmente. Se si seleziona \"Amministratore\", tutte le altre opzioni saranno automaticamente assegnate. La gestione degli utenti rimane un privilegio di un amministratore.\n",
|
||||
"profileSettings": "Impostazioni del profilo",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "impedisci l'accesso a qualsiasi file avente come prefisso un punto\n (ad esempio .git, .gitignore) presente in ogni cartella.\n",
|
||||
"ruleExample2": "blocca l'accesso al file denominato Caddyfile nella radice del campo di applicazione.",
|
||||
"rules": "Regole",
|
||||
@@ -257,7 +261,8 @@
|
||||
"userManagement": "Gestione degli utenti",
|
||||
"userUpdated": "Utente aggiornato!",
|
||||
"username": "Nome utente",
|
||||
"users": "Utenti"
|
||||
"users": "Utenti",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Aiuto",
|
||||
|
||||
@@ -42,7 +42,9 @@
|
||||
"update": "更新",
|
||||
"upload": "アップロード",
|
||||
"openFile": "ファイルを開く",
|
||||
"openDirect": "View raw",
|
||||
"discardChanges": "Discard",
|
||||
"stopSearch": "Stop searching",
|
||||
"saveChanges": "Save changes",
|
||||
"editAsText": "Edit as Text",
|
||||
"increaseFontSize": "Increase font size",
|
||||
@@ -87,7 +89,8 @@
|
||||
"comma": "Comma (,)",
|
||||
"semicolon": "Semicolon (;)",
|
||||
"both": "Both (,) and (;)"
|
||||
}
|
||||
},
|
||||
"fileEncoding": "File Encoding"
|
||||
},
|
||||
"help": {
|
||||
"click": "ファイルやフォルダーを選択",
|
||||
@@ -231,6 +234,7 @@
|
||||
"permissions": "権限",
|
||||
"permissionsHelp": "ユーザーを管理者に設定するか、その他の権限を個別に選択することができます。「管理者」を選択すると、他のオプションはすべて自動的にチェックされます。ユーザーを管理するには管理者権限が必要です。\n",
|
||||
"profileSettings": "プロフィール設定",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": ".git や .gitignore のようなドットから始まるファイルへのアクセスを禁止します。\n",
|
||||
"ruleExample2": "スコープのルートにある Caddyfile という名前のファイルへのアクセスを禁止します。",
|
||||
"rules": "ルール",
|
||||
@@ -257,7 +261,8 @@
|
||||
"userManagement": "ユーザー管理",
|
||||
"userUpdated": "ユーザーを更新しました!",
|
||||
"username": "ユーザー名",
|
||||
"users": "ユーザー"
|
||||
"users": "ユーザー",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "ヘルプ",
|
||||
|
||||
+89
-84
@@ -14,7 +14,7 @@
|
||||
"file": "파일",
|
||||
"folder": "폴더",
|
||||
"fullScreen": "전체 화면 전환",
|
||||
"hideDotfiles": "숨김파일(dotfile)을 표시 안함",
|
||||
"hideDotfiles": "숨김파일(dotfile)을 표시 안 함",
|
||||
"info": "정보",
|
||||
"more": "더보기",
|
||||
"move": "이동",
|
||||
@@ -28,25 +28,27 @@
|
||||
"publish": "게시",
|
||||
"rename": "이름 바꾸기",
|
||||
"replace": "대체",
|
||||
"reportIssue": "이슈 보내기",
|
||||
"reportIssue": "문제 보고",
|
||||
"save": "저장",
|
||||
"schedule": "일정",
|
||||
"search": "검색",
|
||||
"select": "선택",
|
||||
"selectMultiple": "다중 선택",
|
||||
"share": "공유",
|
||||
"shell": "쉘 전환",
|
||||
"shell": "셸 전환",
|
||||
"submit": "제출",
|
||||
"switchView": "보기 전환",
|
||||
"toggleSidebar": "사이드바 전환",
|
||||
"update": "업데이트",
|
||||
"upload": "업로드",
|
||||
"openFile": "파일 열기",
|
||||
"openDirect": "View raw",
|
||||
"discardChanges": "변경 사항 취소",
|
||||
"stopSearch": "검색 중단",
|
||||
"saveChanges": "변경사항 저장",
|
||||
"editAsText": "Edit as Text",
|
||||
"increaseFontSize": "Increase font size",
|
||||
"decreaseFontSize": "Decrease font size"
|
||||
"editAsText": "텍스트로 편집",
|
||||
"increaseFontSize": "글꼴 크기 증가",
|
||||
"decreaseFontSize": "글꼴 크기 감소"
|
||||
},
|
||||
"download": {
|
||||
"downloadFile": "파일 다운로드",
|
||||
@@ -69,36 +71,37 @@
|
||||
"folders": "폴더",
|
||||
"home": "홈",
|
||||
"lastModified": "최종 수정",
|
||||
"loading": "로딩중...",
|
||||
"lonely": "폴더가 비어 있습니다...",
|
||||
"loading": "불러오는 중...",
|
||||
"lonely": "외로워요... (비어 있음)",
|
||||
"metadata": "메타데이터",
|
||||
"multipleSelectionEnabled": "다중 선택 켜짐",
|
||||
"name": "이름",
|
||||
"size": "크기",
|
||||
"sortByLastModified": "수정시간순 정렬",
|
||||
"sortByName": "이름순",
|
||||
"sortBySize": "크기순",
|
||||
"noPreview": "미리 보기가 지원되지 않는 파일 유형입니다.",
|
||||
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
|
||||
"csvLoadFailed": "Failed to load CSV file.",
|
||||
"showingRows": "Showing {count} row(s)",
|
||||
"columnSeparator": "Column Separator",
|
||||
"sortByLastModified": "수정 시간으로 정렬",
|
||||
"sortByName": "이름으로 정렬",
|
||||
"sortBySize": "크기로 정렬",
|
||||
"noPreview": "미리 볼 수 없는 파일입니다.",
|
||||
"csvTooLarge": "CSV 파일이 너무 커서 미리 볼 수 없습니다(5MB 초과). 다운로드 후 보시기 바랍니다.",
|
||||
"csvLoadFailed": "CSV 파일을 불러오는 데 실패했습니다.",
|
||||
"showingRows": "{count}개의 행 보기",
|
||||
"columnSeparator": "열 구분자",
|
||||
"csvSeparators": {
|
||||
"comma": "Comma (,)",
|
||||
"semicolon": "Semicolon (;)",
|
||||
"both": "Both (,) and (;)"
|
||||
}
|
||||
"comma": "반점 (,)",
|
||||
"semicolon": "쌍반점 (;)",
|
||||
"both": "(,) 및 (;) 모두"
|
||||
},
|
||||
"fileEncoding": "파일 인코딩"
|
||||
},
|
||||
"help": {
|
||||
"click": "파일이나 디렉토리를 선택해주세요.",
|
||||
"click": "파일 또는 디렉터리 선택",
|
||||
"ctrl": {
|
||||
"click": "여러 개의 파일이나 디렉토리를 선택해주세요.",
|
||||
"click": "여러 개의 파일 또는 디렉터리 선택",
|
||||
"f": "검색창 열기",
|
||||
"s": "파일 또는 디렉토리 다운로드"
|
||||
"s": "파일을 저장하거나 디렉터리를 다운로드"
|
||||
},
|
||||
"del": "선택된 파일 삭제",
|
||||
"doubleClick": "파일 또는 디렉토리 열기",
|
||||
"esc": "선택 취소/프롬프트 닫기",
|
||||
"doubleClick": "파일 또는 디렉터리 열기",
|
||||
"esc": "선택을 취소하고/또는 프롬프트 닫기",
|
||||
"f1": "정보",
|
||||
"f2": "파일 이름 변경",
|
||||
"help": "도움말"
|
||||
@@ -108,49 +111,49 @@
|
||||
"loginInstead": "이미 계정이 있습니다",
|
||||
"password": "비밀번호",
|
||||
"passwordConfirm": "비밀번호 확인",
|
||||
"passwordsDontMatch": "비밀번호가 일치하지 않습니다",
|
||||
"passwordsDontMatch": "비밀번호가 일치하지 않음",
|
||||
"signup": "가입하기",
|
||||
"submit": "로그인",
|
||||
"username": "사용자 이름",
|
||||
"usernameTaken": "사용자 이름이 존재합니다",
|
||||
"wrongCredentials": "사용자 이름 또는 비밀번호를 확인하십시오",
|
||||
"passwordTooShort": "Password must be at least {min} characters",
|
||||
"usernameTaken": "사용자 이름이 존재함",
|
||||
"wrongCredentials": "사용자 이름 또는 비밀번호를 확인",
|
||||
"passwordTooShort": "비밀번호는 최소 {min}자 이상이어야 함",
|
||||
"logout_reasons": {
|
||||
"inactivity": "You have been logged out due to inactivity."
|
||||
"inactivity": "활동이 없어 로그아웃 되었습니다."
|
||||
}
|
||||
},
|
||||
"permanent": "영구",
|
||||
"prompts": {
|
||||
"copy": "복사",
|
||||
"copyMessage": "복사할 디렉토리:",
|
||||
"copyMessage": "파일을 복사할 위치:",
|
||||
"currentlyNavigating": "현재 위치:",
|
||||
"deleteMessageMultiple": "{count} 개의 파일을 삭제하시겠습니까?",
|
||||
"deleteMessageSingle": "파일 혹은 디렉토리를 삭제하시겠습니까?",
|
||||
"deleteMessageMultiple": "정말 {count}개의 파일을 삭제하시겠습니까?",
|
||||
"deleteMessageSingle": "파일 혹은 디렉터리를 삭제하시겠습니까?",
|
||||
"deleteMessageShare": "이 공유({path})를 삭제하시겠습니까?",
|
||||
"deleteUser": "이 계정을 삭제하시겠습니까?",
|
||||
"deleteTitle": "파일 삭제",
|
||||
"displayName": "게시 이름:",
|
||||
"displayName": "표시 이름:",
|
||||
"download": "파일 다운로드",
|
||||
"downloadMessage": "다운로드 포맷 설정.",
|
||||
"error": "에러 발생!",
|
||||
"downloadMessage": "다운로드 할 형식을 선택하십시오.",
|
||||
"error": "에러 발생",
|
||||
"fileInfo": "파일 정보",
|
||||
"filesSelected": "{count} 개의 파일이 선택되었습니다.",
|
||||
"filesSelected": "{count}개의 파일을 선택했습니다.",
|
||||
"lastModified": "최종 수정",
|
||||
"move": "이동",
|
||||
"moveMessage": "이동할 화일 또는 디렉토리를 선택하세요:",
|
||||
"newArchetype": "원형을 유지하는 포스트를 생성합니다. 파일은 컨텐트 폴더에 생성됩니다.",
|
||||
"newDir": "새 디렉토리",
|
||||
"newDirMessage": "새 디렉토리 이름을 입력해주세요.",
|
||||
"moveMessage": "파일 및 폴더의 새로운 위치를 선택:",
|
||||
"newArchetype": "원형을 유지하는 새 포스트를 생성합니다. 파일은 콘텐츠 폴더에 생성됩니다.",
|
||||
"newDir": "새 디렉터리",
|
||||
"newDirMessage": "새 디렉터리의 이름을 입력해주세요.",
|
||||
"newFile": "새 파일",
|
||||
"newFileMessage": "새 파일 이름을 입력해주세요.",
|
||||
"numberDirs": "디렉토리 수",
|
||||
"newFileMessage": "새 파일의 이름을 입력해주세요.",
|
||||
"numberDirs": "디렉터리 수",
|
||||
"numberFiles": "파일 수",
|
||||
"rename": "이름 변경",
|
||||
"renameMessage": "새로운 이름을 입력하세요.",
|
||||
"renameMessage": "새 이름을 입력:",
|
||||
"replace": "대체하기",
|
||||
"replaceMessage": "동일한 파일 이름이 존재합니다. 현재 파일을 덮어쓸까요?\n",
|
||||
"replaceMessage": "업로드하려는 파일 중 하나의 이름이 충돌합니다. 해당 파일을 건너뛰고 계속 업로드하시겠습니까, 아니면 기존 파일을 교체하시겠습니까?\n",
|
||||
"schedule": "일정",
|
||||
"scheduleMessage": "이 글을 공개할 시간을 알려주세요.",
|
||||
"scheduleMessage": "이 포스트를 공개할 날짜와 시간을 선택하십시오.",
|
||||
"show": "보기",
|
||||
"size": "크기",
|
||||
"upload": "업로드",
|
||||
@@ -164,47 +167,47 @@
|
||||
"images": "이미지",
|
||||
"music": "음악",
|
||||
"pdf": "PDF",
|
||||
"pressToSearch": "검색하려면 엔터를 입력하세요",
|
||||
"pressToSearch": "엔터를 눌러 검색...",
|
||||
"search": "검색...",
|
||||
"typeToSearch": "검색어 입력...",
|
||||
"types": "Types",
|
||||
"types": "유형",
|
||||
"video": "비디오"
|
||||
},
|
||||
"settings": {
|
||||
"aceEditorTheme": "Ace editor theme",
|
||||
"aceEditorTheme": "ACE 편집기 테마",
|
||||
"admin": "관리자",
|
||||
"administrator": "관리자",
|
||||
"allowCommands": "명령 실행",
|
||||
"allowEdit": "파일/디렉토리의 수정/변경/삭제 허용",
|
||||
"allowNew": "파일/디렉토리 생성 허용",
|
||||
"allowPublish": "새 포스트/페이지 생성 허용",
|
||||
"allowEdit": "파일 또는 디렉터리의 수정, 이름 변경, 삭제를 허용",
|
||||
"allowNew": "파일 및 디렉터리 생성 허용",
|
||||
"allowPublish": "새 포스트 및 페이지 생성 허용",
|
||||
"allowSignup": "사용자 가입 허용",
|
||||
"hideLoginButton": "Hide the login button from public pages",
|
||||
"avoidChanges": "(수정하지 않으면 비워두세요)",
|
||||
"hideLoginButton": "공개 화면에서 로그인 버튼 숨기기",
|
||||
"avoidChanges": "(수정하지 않으려면 비워둠)",
|
||||
"branding": "브랜딩",
|
||||
"brandingDirectoryPath": "브랜드 디렉토리 경로",
|
||||
"brandingHelp": "File Browser 인스턴스는 이름, 로고, 스타일 등을 변경할 수 있습니다. 자세한 사항은 여기{0}에서 확인하세요.",
|
||||
"brandingDirectoryPath": "브랜드 디렉터리 경로",
|
||||
"brandingHelp": "File Browser의 이름을 변경하고, 로고를 바꾸고, 사용자 지정 스타일을 추가하고, GitHub에 대한 외부 링크를 비활성화 하는 등 인스턴스의 모양과 느낌을 사용자화 할 수 있습니다.\n사용자 지정 브랜딩에 대한 자세한 내용은 {0}을(를) 참조하십시오.",
|
||||
"changePassword": "비밀번호 변경",
|
||||
"commandRunner": "명령 실행기",
|
||||
"commandRunnerHelp": "이벤트에 해당하는 명령을 설정하세요. 줄당 1개의 명령을 적으세요. 환경 변수{0} 와 {1}이 사용가능하며, {0} 은 {1}에 상대 경로 입니다. 자세한 사항은 {2} 를 참조하세요.",
|
||||
"commandRunnerHelp": "여기서는 명명된 이벤트에서 실행될 명령을 설정할 수 있습니다. 한 줄에 하나씩 작성해야 합니다. 환경 변수 {0} 및 {1}을(를) 사용할 수 있으며, {0}은(는) {1}을 기준으로 합니다. 이 기능 및 사용 가능한 환경 변수에 대한 자세한 내용은 {2}을(를) 참조하십시오.",
|
||||
"commandsUpdated": "명령 수정됨!",
|
||||
"createUserDir": "Auto create user home dir while adding new user",
|
||||
"createUserDir": "새로운 유저를 추가할 때 사용자 홈 디렉터리 자동 생성",
|
||||
"minimumPasswordLength": "최소 비밀번호 길이",
|
||||
"tusUploads": "분할 업로드",
|
||||
"tusUploadsHelp": "File Browser는 불안정한 네트워크에서도 효율적이고 신뢰성 있는 분할 업로드를 지원합니다.",
|
||||
"tusUploadsChunkSize": "업로드 요청의 최대 크기 (예: 10MB, 1GB)",
|
||||
"tusUploadsRetryCount": "업로드 실패 시 재시도 횟수",
|
||||
"userHomeBasePath": "사용자 홈 폴더 기본 경로",
|
||||
"userScopeGenerationPlaceholder": "범위는 자동으로 생성됩니다.",
|
||||
"createUserHomeDirectory": "사용자 홈 폴더 생성",
|
||||
"customStylesheet": "커스텀 스타일시트",
|
||||
"defaultUserDescription": "아래 사항은 신규 사용자들에 대한 기본 설정입니다.",
|
||||
"disableExternalLinks": "외부 링크 감추기",
|
||||
"disableUsedDiskPercentage": "Disable used disk percentage graph",
|
||||
"tusUploadsHelp": "File Browser는 파일의 분할 업로드를 통해 불안정한 네트워크 환경에서도 효율적이고 안정적이며, 업로드 재개가 가능하도록 합니다.",
|
||||
"tusUploadsChunkSize": "업로드 요청의 최대 크기를 지정합니다(보다 작은 크기의 업로드는 직접 업로드 방식을 사용합니다). 바이트 크기를 나타내는 정수 또는 10MB, 1GB 등과 같은 문자열을 입력할 수 있습니다.",
|
||||
"tusUploadsRetryCount": "분할 업로드를 실패할 경우 다시 시도할 횟수입니다.",
|
||||
"userHomeBasePath": "사용자 홈 디렉터리 기본 경로",
|
||||
"userScopeGenerationPlaceholder": "범위는 자동 생성",
|
||||
"createUserHomeDirectory": "사용자 홈 디렉터리 생성",
|
||||
"customStylesheet": "사용자 지정 스타일시트",
|
||||
"defaultUserDescription": "다음은 신규 사용자들에 대한 기본 설정입니다.",
|
||||
"disableExternalLinks": "외부 링크 비활성화(문서 제외)",
|
||||
"disableUsedDiskPercentage": "사용한 디스크 비율 그래프 비활성화",
|
||||
"documentation": "문서",
|
||||
"examples": "예",
|
||||
"executeOnShell": "쉘에서 실행",
|
||||
"executeOnShellDescription": "기본적으로 File Browser 는 바이너리를 명령어로 호출하여 실행합니다. 쉘을 통해 실행하기를 원한다면, Bash 또는 PowerShell 에 필요한 인수와 플래그를 설정하세요. 사용자 명령어와 이벤트 훅에 모두 적용됩니다.",
|
||||
"examples": "예시",
|
||||
"executeOnShell": "셸에서 실행",
|
||||
"executeOnShellDescription": "기본적으로 File Browser는 명령어를 해당 바이너리 파일로 직접 실행합니다. 만약 Bash나 PowerShell과 같은 셸에서 명령어를 실행하려면, 필요한 인수와 플래그를 설정하여 셸 환경을 정의할 수 있습니다. 플래그가 설정된 경우, 실행하는 명령어가 인수로 추가됩니다. 이는 사용자 명령어와 이벤트 후크 모두에 적용됩니다.",
|
||||
"globalRules": "규칙에 대한 전역설정으로 모든 사용자에게 적용됩니다. 지정된 규칙은 사용자 설정을 덮어쓰기 합니다.",
|
||||
"globalSettings": "전역 설정",
|
||||
"hideDotfiles": "숨김파일(dotfile)을 표시하지 않습니다.",
|
||||
@@ -220,44 +223,46 @@
|
||||
"passwordUpdated": "비밀번호 수정 완료!",
|
||||
"path": "경로",
|
||||
"perm": {
|
||||
"create": "파일이나 디렉토리 생성하기",
|
||||
"delete": "화일이나 디렉토리 삭제하기",
|
||||
"create": "파일 및 디렉터리 생성하기",
|
||||
"delete": "파일 및 디렉터리 삭제하기",
|
||||
"download": "다운로드",
|
||||
"execute": "명령 실행",
|
||||
"modify": "파일 편집",
|
||||
"rename": "파일 이름 변경 또는 디렉토리 이동",
|
||||
"rename": "파일 및 디렉터리의 이름 변경 또는 이동",
|
||||
"share": "파일 공유하기"
|
||||
},
|
||||
"permissions": "권한",
|
||||
"permissionsHelp": "사용자를 관리자로 만들거나 권한을 부여할 수 있습니다. 관리자를 선택하면, 모든 옵션이 자동으로 선택됩니다. 사용자 관리는 현재 관리자만 할 수 있습니다.\n",
|
||||
"permissionsHelp": "사용자를 관리자로 설정하거나 개별적으로 권한을 지정할 수 있습니다. \"관리자\"를 선택하면 다른 모든 옵션이 자동으로 선택됩니다. 사용자 관리는 관리자의 권한입니다.\n",
|
||||
"profileSettings": "프로필 설정",
|
||||
"ruleExample1": "점(.)으로 시작하는 모든 파일의 접근을 방지합니다.(예 .git, .gitignore)\n",
|
||||
"redirectAfterCopyMove": "복사/이동 후 대상 경로로 이동",
|
||||
"ruleExample1": "각 폴더에 점(.)으로 시작하는 모든 파일의 접근을 방지합니다. (예시: .git, .gitignore)\n",
|
||||
"ruleExample2": "Caddyfile파일의 접근을 방지합니다.",
|
||||
"rules": "룰",
|
||||
"rulesHelp": "사용자별로 규칙을 허용/방지를 지정할 수 있습니다. 방지된 파일은 보이지 않고 사용자들은 접근할 수 없습니다. 사용자의 접근 허용 범위와 관련해 정규표현식(regex)과 경로를 지원합니다.\n",
|
||||
"rules": "규칙",
|
||||
"rulesHelp": "여기에서 특정 사용자에 대한 허용 및 차단 규칙 집합을 정의할 수 있습니다. 차단된 파일은 목록에 표시되지 않으며 해당 사용자는 접근할 수 없습니다. 정규 표현식과 사용자 범위에 대한 상대 경로를 지원합니다.\n",
|
||||
"scope": "범위",
|
||||
"setDateFormat": "날짜 형식 설정",
|
||||
"settingsUpdated": "설정 수정됨!",
|
||||
"shareDuration": "공유 기간",
|
||||
"shareManagement": "공유 내역 관리",
|
||||
"shareDeleted": "공유 삭제됨!",
|
||||
"singleClick": "한번 클릭으로 파일과 폴더를 열도록 합니다.",
|
||||
"singleClick": "단일 클릭으로 파일 및 디렉터리 열기",
|
||||
"themes": {
|
||||
"default": "시스템 기본값",
|
||||
"dark": "다크테마",
|
||||
"light": "라이트테마",
|
||||
"dark": "어두운 테마",
|
||||
"light": "밝은 테마",
|
||||
"title": "테마"
|
||||
},
|
||||
"user": "사용자",
|
||||
"userCommands": "명령어",
|
||||
"userCommandsHelp": "사용에게 허용할 명령어를 공백으로 구분하여 입력하세요. 예:\n",
|
||||
"userCommandsHelp": "사용자에게 허용할 명령어를 공백으로 구분하여 입력하세요. 예:\n",
|
||||
"userCreated": "사용자 생성됨!",
|
||||
"userDefaults": "사용자 기본 설정",
|
||||
"userDeleted": "사용자 삭제됨!",
|
||||
"userManagement": "사용자 관리",
|
||||
"userUpdated": "사용자 수정됨!",
|
||||
"username": "사용자 이름",
|
||||
"users": "사용자"
|
||||
"users": "사용자",
|
||||
"currentPassword": "현재 비밀번호"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "도움말",
|
||||
@@ -280,6 +285,6 @@
|
||||
"hours": "시",
|
||||
"minutes": "분",
|
||||
"seconds": "초",
|
||||
"unit": "Time Unit"
|
||||
"unit": "시간 단위"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,290 @@
|
||||
{
|
||||
"buttons": {
|
||||
"cancel": "Atcelt",
|
||||
"clear": "Tīrs",
|
||||
"close": "Aizvērt",
|
||||
"continue": "Turpināt",
|
||||
"copy": "Kopēt",
|
||||
"copyFile": "Kopēt failu",
|
||||
"copyToClipboard": "Kopēt starpliktuvē",
|
||||
"copyDownloadLinkToClipboard": "Kopēt lejupielādes saiti starpliktuvē",
|
||||
"create": "Izveidot",
|
||||
"delete": "Dzēst",
|
||||
"download": "Lejupielādēt",
|
||||
"file": "Fails",
|
||||
"folder": "Mape",
|
||||
"fullScreen": "Pārslēgt pilnekrāna režīmu",
|
||||
"hideDotfiles": "Slēpt punktfailus",
|
||||
"info": "Informācija",
|
||||
"more": "Vairāk",
|
||||
"move": "Pārvietot",
|
||||
"moveFile": "Pārvietot failu",
|
||||
"new": "Jauns",
|
||||
"next": "Nākamais",
|
||||
"ok": "Labi",
|
||||
"permalink": "Iegūt pastāvīgo saiti",
|
||||
"previous": "Iepriekšējais",
|
||||
"preview": "Priekšskatījums",
|
||||
"publish": "Publicēt",
|
||||
"rename": "Pārdēvēt",
|
||||
"replace": "Aizstāt",
|
||||
"reportIssue": "Ziņot par problēmu",
|
||||
"save": "Saglabāt",
|
||||
"schedule": "Grafiks",
|
||||
"search": "Meklēt",
|
||||
"select": "Izvēlieties",
|
||||
"selectMultiple": "Izvēlieties vairākus",
|
||||
"share": "Dalīties",
|
||||
"shell": "Pārslēgt apvalku",
|
||||
"submit": "Iesniegt",
|
||||
"switchView": "Pārslēgt skatu",
|
||||
"toggleSidebar": "Pārslēgt sānjoslu",
|
||||
"update": "Atjaunināt",
|
||||
"upload": "Augšupielādēt",
|
||||
"openFile": "Atvērt failu",
|
||||
"openDirect": "View raw",
|
||||
"discardChanges": "Izmest",
|
||||
"stopSearch": "Stop searching",
|
||||
"saveChanges": "Saglabāt izmaiņas",
|
||||
"editAsText": "Rediģēt kā tekstu",
|
||||
"increaseFontSize": "Palieliniet fonta lielumu",
|
||||
"decreaseFontSize": "Samaziniet fonta lielumu"
|
||||
},
|
||||
"download": {
|
||||
"downloadFile": "Lejupielādēt failu",
|
||||
"downloadFolder": "Lejupielādēt mapi",
|
||||
"downloadSelected": "Lejupielādēt atlasīto"
|
||||
},
|
||||
"upload": {
|
||||
"abortUpload": "Vai tiešām vēlaties pārtraukt?"
|
||||
},
|
||||
"errors": {
|
||||
"forbidden": "Jums nav atļaujas piekļūt šim.",
|
||||
"internal": "Kaut kas tiešām nogāja greizi.",
|
||||
"notFound": "Šo atrašanās vietu nevar sasniegt.",
|
||||
"connection": "Ar serveri nevar sazināties."
|
||||
},
|
||||
"files": {
|
||||
"body": "Ķermenis",
|
||||
"closePreview": "Aizvērt priekšskatījumu",
|
||||
"files": "Faili",
|
||||
"folders": "Mapes",
|
||||
"home": "Sākums",
|
||||
"lastModified": "Pēdējoreiz modificēts",
|
||||
"loading": "Notiek ielāde...",
|
||||
"lonely": "Šeit ir tukša vieta...",
|
||||
"metadata": "Metadati",
|
||||
"multipleSelectionEnabled": "Vairākas atlases ir iespējotas",
|
||||
"name": "Vārds",
|
||||
"size": "Izmērs",
|
||||
"sortByLastModified": "Kārtot pēc pēdējās modifikācijas",
|
||||
"sortByName": "Kārtot pēc nosaukuma",
|
||||
"sortBySize": "Kārtot pēc izmēra",
|
||||
"noPreview": "Šim failam nav pieejams priekšskatījums.",
|
||||
"csvTooLarge": "CSV fails ir pārāk liels priekšskatīšanai (>5 MB). Lūdzu, lejupielādējiet to, lai skatītu",
|
||||
"csvLoadFailed": "Neizdevās ielādēt CSV failu.",
|
||||
"showingRows": "Rāda {count} rindu(as)",
|
||||
"columnSeparator": "Kolonnu atdalītājs",
|
||||
"csvSeparators": {
|
||||
"comma": "Komats (,)",
|
||||
"semicolon": "Semikols (;)",
|
||||
"both": "Gan (,) gan (;)"
|
||||
},
|
||||
"fileEncoding": "File Encoding"
|
||||
},
|
||||
"help": {
|
||||
"click": "atlasiet failu vai direktoriju",
|
||||
"ctrl": {
|
||||
"click": "atlasīt vairākus failus vai direktorijus",
|
||||
"f": "atver meklēšanu",
|
||||
"s": "saglabājiet failu vai lejupielādējiet direktoriju, kurā atrodaties"
|
||||
},
|
||||
"del": "dzēst atlasītos vienumus",
|
||||
"doubleClick": "atvērt failu vai direktoriju",
|
||||
"esc": "notīrīt atlasi un/vai aizvērt uzvedni",
|
||||
"f1": "šo informāciju",
|
||||
"f2": "pārdēvēt failu",
|
||||
"help": "Palīdzība"
|
||||
},
|
||||
"login": {
|
||||
"createAnAccount": "Izveidot kontu",
|
||||
"loginInstead": "Jau ir konts",
|
||||
"password": "Parole",
|
||||
"passwordConfirm": "Paroles apstiprināšana",
|
||||
"passwordsDontMatch": "Paroles nesakrīt",
|
||||
"signup": "Reģistrēšanās",
|
||||
"submit": "Pieteikties",
|
||||
"username": "Lietotājvārds",
|
||||
"usernameTaken": "Lietotājvārds jau aizņemts",
|
||||
"wrongCredentials": "Nepareizi akreditācijas dati",
|
||||
"passwordTooShort": "Parolei jābūt vismaz {min} rakstzīmju garai",
|
||||
"logout_reasons": {
|
||||
"inactivity": "Jūs esat atteicies no sistēmas neaktivitātes dēļ."
|
||||
}
|
||||
},
|
||||
"permanent": "Pastāvīgs",
|
||||
"prompts": {
|
||||
"copy": "Kopēt",
|
||||
"copyMessage": "Izvēlieties atrašanās vietu, uz kuru kopēt failus:",
|
||||
"currentlyNavigating": "Pašlaik navigācija:",
|
||||
"deleteMessageMultiple": "Vai tiešām vēlaties dzēst {count} failu(s)?",
|
||||
"deleteMessageSingle": "Vai tiešām vēlaties dzēst šo failu/mapi?",
|
||||
"deleteMessageShare": "Vai tiešām vēlaties dzēst šo koplietojumu({path})?",
|
||||
"deleteUser": "Vai tiešām vēlaties dzēst šo lietotāju?",
|
||||
"deleteTitle": "Dzēst failus",
|
||||
"displayName": "Displeja nosaukums:",
|
||||
"download": "Lejupielādēt failus",
|
||||
"downloadMessage": "Izvēlieties formātu, kuru vēlaties lejupielādēt.",
|
||||
"error": "Kaut kas nogāja greizi",
|
||||
"fileInfo": "Informācija par failu",
|
||||
"filesSelected": "{count} atlasīti faili",
|
||||
"lastModified": "Pēdējās izmaiņas",
|
||||
"move": "Pārvietot",
|
||||
"moveMessage": "Izvēlieties jaunu mājvietu failam(iem)/mapei(ēm):",
|
||||
"newArchetype": "Izveidojiet jaunu ierakstu, pamatojoties uz arhtipu. Jūsu fails tiks izveidots satura mapē.",
|
||||
"newDir": "Jauna direktorija",
|
||||
"newDirMessage": "Nosaukums savai jaunajai direktorijai.",
|
||||
"newFile": "Jauns fails",
|
||||
"newFileMessage": "Nosauciet savu jauno failu.",
|
||||
"numberDirs": "Katalogu skaits",
|
||||
"numberFiles": "Failu skaits",
|
||||
"rename": "Pārdēvēt",
|
||||
"renameMessage": "Ievietojiet jaunu nosaukumu",
|
||||
"replace": "Aizstāt",
|
||||
"replaceMessage": "Vienam no failiem, kurus mēģināt augšupielādēt, ir konfliktējošs nosaukums. Vai vēlaties izlaist šo failu un turpināt augšupielādi vai aizstāt esošo?\n",
|
||||
"schedule": "Grafiks",
|
||||
"scheduleMessage": "Izvēlieties datumu un laiku, lai ieplānotu šī ieraksta publicēšanu.",
|
||||
"show": "Rādīt",
|
||||
"size": "Izmērs",
|
||||
"upload": "Augšupielādēt",
|
||||
"uploadFiles": "Notiek {files} failu augšupielāde...",
|
||||
"uploadMessage": "Atlasiet augšupielādes opciju.",
|
||||
"optionalPassword": "Izvēles parole",
|
||||
"resolution": "Izšķirtspēja",
|
||||
"discardEditorChanges": "Vai tiešām vēlaties atmest veiktās izmaiņas?"
|
||||
},
|
||||
"search": {
|
||||
"images": "Attēli",
|
||||
"music": "Mūzika",
|
||||
"pdf": "PDF",
|
||||
"pressToSearch": "Nospiediet taustiņu Enter, lai meklētu...",
|
||||
"search": "Meklē...",
|
||||
"typeToSearch": "Ierakstiet, lai meklētu...",
|
||||
"types": "Veidi",
|
||||
"video": "Video"
|
||||
},
|
||||
"settings": {
|
||||
"aceEditorTheme": "Ace redaktora tēma",
|
||||
"admin": "Admin",
|
||||
"administrator": "Administrator",
|
||||
"allowCommands": "Izpildīt komandas",
|
||||
"allowEdit": "Rediģēt, pārdēvēt un dzēst failus vai direktorijus",
|
||||
"allowNew": "Izveidojiet jaunus failus un direktorijus",
|
||||
"allowPublish": "Publicēt jaunus ierakstus un lapas",
|
||||
"allowSignup": "Atļaut lietotājiem reģistrēties",
|
||||
"hideLoginButton": "Paslēpt pieteikšanās pogu publiskajās lapās",
|
||||
"avoidChanges": "(atstājiet tukšu, lai izvairītos no izmaiņām)",
|
||||
"branding": "Zīmols",
|
||||
"brandingDirectoryPath": "Zīmola direktorijas ceļš",
|
||||
"brandingHelp": "Jūs varat pielāgot sava failu pārlūka instances izskatu un darbību, mainot tās nosaukumu, aizstājot logotipu, pievienojot pielāgotus stilus un pat atspējojot ārējās saites uz GitHub.\nLai iegūtu plašāku informāciju par pielāgotu zīmola veidošanu, lūdzu, skatiet {0}.",
|
||||
"changePassword": "Mainīt paroli",
|
||||
"commandRunner": "Komandu skrējējs",
|
||||
"commandRunnerHelp": "Šeit varat iestatīt komandas, kas tiek izpildītas nosauktajos notikumos. Katrā rindā jāraksta pa vienai. Būs pieejami vides mainīgie {0} un {1}, kas ir {0} relatīvi pret {1}. Lai iegūtu plašāku informāciju par šo funkciju un pieejamajiem vides mainīgajiem, lūdzu, izlasiet {2}.",
|
||||
"commandsUpdated": "Komandas atjauninātas!",
|
||||
"createUserDir": "Automātiski izveidot lietotāja mājas direktoriju, pievienojot jaunu lietotāju",
|
||||
"minimumPasswordLength": "Minimālais paroles garums",
|
||||
"tusUploads": "Sadalītas augšupielādes",
|
||||
"tusUploadsHelp": "Failu pārlūks atbalsta failu augšupielādi fragmentos, ļaujot izveidot efektīvu, uzticamu, atsākamu un fragmentos sadalītu failu augšupielādi pat neuzticamos tīklos.",
|
||||
"tusUploadsChunkSize": "Norāda pieprasījuma maksimālo izmēru (mazākiem augšupielādes apjomiem tiks izmantota tieša augšupielāde). Varat ievadīt vienkāršu veselu skaitli, kas apzīmē baitu izmēru, vai virkni, piemēram, 10 MB, 1 GB utt.",
|
||||
"tusUploadsRetryCount": "Atkārtotu mēģinājumu skaits, kas jāveic, ja fragmenta augšupielāde neizdodas.",
|
||||
"userHomeBasePath": "Lietotāja mājas direktoriju bāzes ceļš",
|
||||
"userScopeGenerationPlaceholder": "Darbības joma tiks ģenerēta automātiski",
|
||||
"createUserHomeDirectory": "Izveidojiet lietotāja mājas direktoriju",
|
||||
"customStylesheet": "Pielāgota stila lapa",
|
||||
"defaultUserDescription": "Šie ir noklusējuma iestatījumi jaunajiem lietotājiem.",
|
||||
"disableExternalLinks": "Atspējot ārējās saites (izņemot dokumentāciju)",
|
||||
"disableUsedDiskPercentage": "Atspējot izmantotā diska procentuālās daļas grafiku",
|
||||
"documentation": "dokumentācija",
|
||||
"examples": "Piemēri",
|
||||
"executeOnShell": "Izpildīt uz čaulas",
|
||||
"executeOnShellDescription": "Pēc noklusējuma failu pārlūks izpilda komandas, tieši izsaucot to bināros failus. Ja vēlaties tās palaist čaulā (piemēram, Bash vai PowerShell), varat to definēt šeit ar nepieciešamajiem argumentiem un karodziņiem. Ja tas ir iestatīts, izpildītā komanda tiks pievienota kā arguments. Tas attiecas gan uz lietotāja komandām, gan notikumu piesaistes rīkiem.",
|
||||
"globalRules": "Šis ir globāls atļaušanas un aizliegšanas noteikumu kopums. Tie attiecas uz katru lietotāju. Katra lietotāja iestatījumos varat definēt konkrētus noteikumus, lai tos ignorētu.",
|
||||
"globalSettings": "Globālie iestatījumi",
|
||||
"hideDotfiles": "Slēpt punktfailus",
|
||||
"insertPath": "Ievietojiet ceļu",
|
||||
"insertRegex": "Ievietojiet regex izteiksmi",
|
||||
"instanceName": "Gadījuma nosaukums",
|
||||
"language": "Valoda",
|
||||
"lockPassword": "Neļaut lietotājam mainīt paroli",
|
||||
"newPassword": "Jūsu jaunā parole",
|
||||
"newPasswordConfirm": "Apstipriniet savu jauno paroli",
|
||||
"newUser": "Jauns lietotājs",
|
||||
"password": "Parole",
|
||||
"passwordUpdated": "Parole atjaunināta!",
|
||||
"path": "Ceļš",
|
||||
"perm": {
|
||||
"create": "Izveidojiet failus un direktorijus",
|
||||
"delete": "Dzēst failus un direktorijus",
|
||||
"download": "Lejupielādēt",
|
||||
"execute": "Izpildīt komandas",
|
||||
"modify": "Rediģēt failus",
|
||||
"rename": "Pārdēvēt vai pārvietot failus un direktorijus",
|
||||
"share": "Kopīgojiet failus"
|
||||
},
|
||||
"permissions": "Atļaujas",
|
||||
"permissionsHelp": "Varat iestatīt lietotāju kā administratoru vai izvēlēties atļaujas individuāli. Ja atlasīsiet “Administrators”, visas pārējās opcijas tiks automātiski atzīmētas. Lietotāju pārvaldība joprojām ir administratora privilēģija.\n",
|
||||
"profileSettings": "Profila iestatījumi",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "neļauj piekļūt jebkuram dotfile failam (piemēram, .git, .gitignore) katrā mapē.\n",
|
||||
"ruleExample2": "bloķē piekļuvi failam ar nosaukumu Caddyfile darbības jomas saknē.",
|
||||
"rules": "Noteikumi",
|
||||
"rulesHelp": "Šeit varat definēt atļaušanas un aizliegšanas noteikumu kopu šim konkrētajam lietotājam. Bloķētie faili netiks rādīti sarakstos, un lietotājs tiem nevarēs piekļūt. Mēs atbalstām regulārās izteiksmes un ceļus attiecībā pret lietotāja darbības jomu.\n",
|
||||
"scope": "Darbības joma",
|
||||
"setDateFormat": "Iestatiet precīzu datuma formātu",
|
||||
"settingsUpdated": "Iestatījumi atjaunināti!",
|
||||
"shareDuration": "Kopīgošanas ilgums",
|
||||
"shareManagement": "Kopīgošanas pārvaldība",
|
||||
"shareDeleted": "Kopīgošana ir izdzēsta!",
|
||||
"singleClick": "Failu un direktoriju atvēršanai izmantojiet vienus klikšķi",
|
||||
"themes": {
|
||||
"default": "Sistēmas noklusējums",
|
||||
"dark": "Tumša",
|
||||
"light": "Gaiša",
|
||||
"title": "Tēma"
|
||||
},
|
||||
"user": "Lietotājs",
|
||||
"userCommands": "Komandas",
|
||||
"userCommandsHelp": "Ar atstarpi atdalīts saraksts ar šim lietotājam pieejamajām komandām. Piemērs:\n",
|
||||
"userCreated": "Lietotājs izveidots!",
|
||||
"userDefaults": "Lietotāja noklusējuma iestatījumi",
|
||||
"userDeleted": "Lietotājs izdzēsts!",
|
||||
"userManagement": "Lietotāju pārvaldība",
|
||||
"userUpdated": "Lietotājs atjaunināts!",
|
||||
"username": "Lietotājvārds",
|
||||
"users": "Lietotāji",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Palīdzība",
|
||||
"hugoNew": "Hugo Jauns",
|
||||
"login": "Pieteikties",
|
||||
"logout": "Atteikties",
|
||||
"myFiles": "Mani faili",
|
||||
"newFile": "Jauns fails",
|
||||
"newFolder": "Jauna mape",
|
||||
"preview": "Priekšskatījums",
|
||||
"settings": "Iestatījumi",
|
||||
"signup": "Reģistrēties",
|
||||
"siteSettings": "Vietnes iestatījumi"
|
||||
},
|
||||
"success": {
|
||||
"linkCopied": "Saite nokopēta!"
|
||||
},
|
||||
"time": {
|
||||
"days": "Dienas",
|
||||
"hours": "Stundas",
|
||||
"minutes": "Minūtes",
|
||||
"seconds": "Sekundes",
|
||||
"unit": "Laika vienība"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,290 @@
|
||||
{
|
||||
"buttons": {
|
||||
"cancel": "Atcelt",
|
||||
"clear": "Tīrs",
|
||||
"close": "Aizvērt",
|
||||
"continue": "Turpināt",
|
||||
"copy": "Kopēt",
|
||||
"copyFile": "Kopēt failu",
|
||||
"copyToClipboard": "Kopēt starpliktuvē",
|
||||
"copyDownloadLinkToClipboard": "Kopēt lejupielādes saiti starpliktuvē",
|
||||
"create": "Izveidot",
|
||||
"delete": "Dzēst",
|
||||
"download": "Lejupielādēt",
|
||||
"file": "Fails",
|
||||
"folder": "Mape",
|
||||
"fullScreen": "Pārslēgt pilnekrāna režīmu",
|
||||
"hideDotfiles": "Slēpt punktfailus",
|
||||
"info": "Informācija",
|
||||
"more": "Vairāk",
|
||||
"move": "Pārvietot",
|
||||
"moveFile": "Pārvietot failu",
|
||||
"new": "Jauns",
|
||||
"next": "Nākamais",
|
||||
"ok": "Labi",
|
||||
"permalink": "Iegūt pastāvīgo saiti",
|
||||
"previous": "Iepriekšējais",
|
||||
"preview": "Priekšskatījums",
|
||||
"publish": "Publicēt",
|
||||
"rename": "Pārdēvēt",
|
||||
"replace": "Aizstāt",
|
||||
"reportIssue": "Ziņot par problēmu",
|
||||
"save": "Saglabāt",
|
||||
"schedule": "Grafiks",
|
||||
"search": "Meklēt",
|
||||
"select": "Izvēlieties",
|
||||
"selectMultiple": "Izvēlieties vairākus",
|
||||
"share": "Dalīties",
|
||||
"shell": "Pārslēgt apvalku",
|
||||
"submit": "Iesniegt",
|
||||
"switchView": "Pārslēgt skatu",
|
||||
"toggleSidebar": "Pārslēgt sānjoslu",
|
||||
"update": "Atjaunināt",
|
||||
"upload": "Augšupielādēt",
|
||||
"openFile": "Atvērt failu",
|
||||
"openDirect": "View raw",
|
||||
"discardChanges": "Izmest",
|
||||
"stopSearch": "Beigt meklēšanu",
|
||||
"saveChanges": "Saglabāt izmaiņas",
|
||||
"editAsText": "Rediģēt kā tekstu",
|
||||
"increaseFontSize": "Palieliniet fonta lielumu",
|
||||
"decreaseFontSize": "Samaziniet fonta lielumu"
|
||||
},
|
||||
"download": {
|
||||
"downloadFile": "Lejupielādēt failu",
|
||||
"downloadFolder": "Lejupielādēt mapi",
|
||||
"downloadSelected": "Lejupielādēt atlasīto"
|
||||
},
|
||||
"upload": {
|
||||
"abortUpload": "Vai tiešām vēlaties pārtraukt?"
|
||||
},
|
||||
"errors": {
|
||||
"forbidden": "Jums nav atļaujas piekļūt šim.",
|
||||
"internal": "Kaut kas tiešām nogāja greizi.",
|
||||
"notFound": "Šo atrašanās vietu nevar sasniegt.",
|
||||
"connection": "Ar serveri nevar sazināties."
|
||||
},
|
||||
"files": {
|
||||
"body": "Ķermenis",
|
||||
"closePreview": "Aizvērt priekšskatījumu",
|
||||
"files": "Faili",
|
||||
"folders": "Mapes",
|
||||
"home": "Sākums",
|
||||
"lastModified": "Pēdējoreiz modificēts",
|
||||
"loading": "Notiek ielāde...",
|
||||
"lonely": "Šeit ir tukša vieta...",
|
||||
"metadata": "Metadati",
|
||||
"multipleSelectionEnabled": "Vairākas atlases ir iespējotas",
|
||||
"name": "Vārds",
|
||||
"size": "Izmērs",
|
||||
"sortByLastModified": "Kārtot pēc pēdējās modifikācijas",
|
||||
"sortByName": "Kārtot pēc nosaukuma",
|
||||
"sortBySize": "Kārtot pēc izmēra",
|
||||
"noPreview": "Šim failam nav pieejams priekšskatījums.",
|
||||
"csvTooLarge": "CSV fails ir pārāk liels priekšskatīšanai (>5 MB). Lūdzu, lejupielādējiet to, lai skatītu",
|
||||
"csvLoadFailed": "Neizdevās ielādēt CSV failu.",
|
||||
"showingRows": "Rāda {count} rindu(as)",
|
||||
"columnSeparator": "Kolonnu atdalītājs",
|
||||
"csvSeparators": {
|
||||
"comma": "Komats (,)",
|
||||
"semicolon": "Semikols (;)",
|
||||
"both": "Gan (,) gan (;)"
|
||||
},
|
||||
"fileEncoding": "File Encoding"
|
||||
},
|
||||
"help": {
|
||||
"click": "atlasiet failu vai direktoriju",
|
||||
"ctrl": {
|
||||
"click": "atlasīt vairākus failus vai direktorijus",
|
||||
"f": "atver meklēšanu",
|
||||
"s": "saglabājiet failu vai lejupielādējiet direktoriju, kurā atrodaties"
|
||||
},
|
||||
"del": "dzēst atlasītos vienumus",
|
||||
"doubleClick": "atvērt failu vai direktoriju",
|
||||
"esc": "notīrīt atlasi un/vai aizvērt uzvedni",
|
||||
"f1": "šo informāciju",
|
||||
"f2": "pārdēvēt failu",
|
||||
"help": "Palīdzība"
|
||||
},
|
||||
"login": {
|
||||
"createAnAccount": "Izveidot kontu",
|
||||
"loginInstead": "Jau ir konts",
|
||||
"password": "Parole",
|
||||
"passwordConfirm": "Paroles apstiprināšana",
|
||||
"passwordsDontMatch": "Paroles nesakrīt",
|
||||
"signup": "Reģistrēšanās",
|
||||
"submit": "Pieteikties",
|
||||
"username": "Lietotājvārds",
|
||||
"usernameTaken": "Lietotājvārds jau aizņemts",
|
||||
"wrongCredentials": "Nepareizi akreditācijas dati",
|
||||
"passwordTooShort": "Parolei jābūt vismaz {min} rakstzīmju garai",
|
||||
"logout_reasons": {
|
||||
"inactivity": "Jūs esat atteicies no sistēmas neaktivitātes dēļ."
|
||||
}
|
||||
},
|
||||
"permanent": "Pastāvīgs",
|
||||
"prompts": {
|
||||
"copy": "Kopēt",
|
||||
"copyMessage": "Izvēlieties atrašanās vietu, uz kuru kopēt failus:",
|
||||
"currentlyNavigating": "Pašlaik navigācija:",
|
||||
"deleteMessageMultiple": "Vai tiešām vēlaties dzēst {count} failu(s)?",
|
||||
"deleteMessageSingle": "Vai tiešām vēlaties dzēst šo failu/mapi?",
|
||||
"deleteMessageShare": "Vai tiešām vēlaties dzēst šo koplietojumu({path})?",
|
||||
"deleteUser": "Vai tiešām vēlaties dzēst šo lietotāju?",
|
||||
"deleteTitle": "Dzēst failus",
|
||||
"displayName": "Displeja nosaukums:",
|
||||
"download": "Lejupielādēt failus",
|
||||
"downloadMessage": "Izvēlieties formātu, kuru vēlaties lejupielādēt.",
|
||||
"error": "Kaut kas nogāja greizi",
|
||||
"fileInfo": "Informācija par failu",
|
||||
"filesSelected": "{count} atlasīti faili",
|
||||
"lastModified": "Pēdējās izmaiņas",
|
||||
"move": "Pārvietot",
|
||||
"moveMessage": "Izvēlieties jaunu mājvietu failam(iem)/mapei(ēm):",
|
||||
"newArchetype": "Izveidojiet jaunu ierakstu, pamatojoties uz arhtipu. Jūsu fails tiks izveidots satura mapē.",
|
||||
"newDir": "Jauna direktorija",
|
||||
"newDirMessage": "Nosaukums savai jaunajai direktorijai.",
|
||||
"newFile": "Jauns fails",
|
||||
"newFileMessage": "Nosauciet savu jauno failu.",
|
||||
"numberDirs": "Katalogu skaits",
|
||||
"numberFiles": "Failu skaits",
|
||||
"rename": "Pārdēvēt",
|
||||
"renameMessage": "Ievietojiet jaunu nosaukumu",
|
||||
"replace": "Aizstāt",
|
||||
"replaceMessage": "Vienam no failiem, kurus mēģināt augšupielādēt, ir konfliktējošs nosaukums. Vai vēlaties izlaist šo failu un turpināt augšupielādi vai aizstāt esošo?\n",
|
||||
"schedule": "Grafiks",
|
||||
"scheduleMessage": "Izvēlieties datumu un laiku, lai ieplānotu šī ieraksta publicēšanu.",
|
||||
"show": "Rādīt",
|
||||
"size": "Izmērs",
|
||||
"upload": "Augšupielādēt",
|
||||
"uploadFiles": "Notiek {files} failu augšupielāde...",
|
||||
"uploadMessage": "Atlasiet augšupielādes opciju.",
|
||||
"optionalPassword": "Izvēles parole",
|
||||
"resolution": "Izšķirtspēja",
|
||||
"discardEditorChanges": "Vai tiešām vēlaties atmest veiktās izmaiņas?"
|
||||
},
|
||||
"search": {
|
||||
"images": "Attēli",
|
||||
"music": "Mūzika",
|
||||
"pdf": "PDF",
|
||||
"pressToSearch": "Nospiediet taustiņu Enter, lai meklētu...",
|
||||
"search": "Meklē...",
|
||||
"typeToSearch": "Ierakstiet, lai meklētu...",
|
||||
"types": "Veidi",
|
||||
"video": "Video"
|
||||
},
|
||||
"settings": {
|
||||
"aceEditorTheme": "Ace redaktora tēma",
|
||||
"admin": "Admin",
|
||||
"administrator": "Administrator",
|
||||
"allowCommands": "Izpildīt komandas",
|
||||
"allowEdit": "Rediģēt, pārdēvēt un dzēst failus vai direktorijus",
|
||||
"allowNew": "Izveidojiet jaunus failus un direktorijus",
|
||||
"allowPublish": "Publicēt jaunus ierakstus un lapas",
|
||||
"allowSignup": "Atļaut lietotājiem reģistrēties",
|
||||
"hideLoginButton": "Paslēpt pieteikšanās pogu publiskajās lapās",
|
||||
"avoidChanges": "(atstājiet tukšu, lai izvairītos no izmaiņām)",
|
||||
"branding": "Zīmols",
|
||||
"brandingDirectoryPath": "Zīmola direktorijas ceļš",
|
||||
"brandingHelp": "Jūs varat pielāgot sava failu pārlūka instances izskatu un darbību, mainot tās nosaukumu, aizstājot logotipu, pievienojot pielāgotus stilus un pat atspējojot ārējās saites uz GitHub.\nLai iegūtu plašāku informāciju par pielāgotu zīmola veidošanu, lūdzu, skatiet {0}.",
|
||||
"changePassword": "Mainīt paroli",
|
||||
"commandRunner": "Komandu skrējējs",
|
||||
"commandRunnerHelp": "Šeit varat iestatīt komandas, kas tiek izpildītas nosauktajos notikumos. Katrā rindā jāraksta pa vienai. Būs pieejami vides mainīgie {0} un {1}, kas ir {0} relatīvi pret {1}. Lai iegūtu plašāku informāciju par šo funkciju un pieejamajiem vides mainīgajiem, lūdzu, izlasiet {2}.",
|
||||
"commandsUpdated": "Komandas atjauninātas!",
|
||||
"createUserDir": "Automātiski izveidot lietotāja mājas direktoriju, pievienojot jaunu lietotāju",
|
||||
"minimumPasswordLength": "Minimālais paroles garums",
|
||||
"tusUploads": "Sadalītas augšupielādes",
|
||||
"tusUploadsHelp": "Failu pārlūks atbalsta failu augšupielādi fragmentos, ļaujot izveidot efektīvu, uzticamu, atsākamu un fragmentos sadalītu failu augšupielādi pat neuzticamos tīklos.",
|
||||
"tusUploadsChunkSize": "Norāda pieprasījuma maksimālo izmēru (mazākiem augšupielādes apjomiem tiks izmantota tieša augšupielāde). Varat ievadīt vienkāršu veselu skaitli, kas apzīmē baitu izmēru, vai virkni, piemēram, 10 MB, 1 GB utt.",
|
||||
"tusUploadsRetryCount": "Atkārtotu mēģinājumu skaits, kas jāveic, ja fragmenta augšupielāde neizdodas.",
|
||||
"userHomeBasePath": "Lietotāja mājas direktoriju bāzes ceļš",
|
||||
"userScopeGenerationPlaceholder": "Darbības joma tiks ģenerēta automātiski",
|
||||
"createUserHomeDirectory": "Izveidojiet lietotāja mājas direktoriju",
|
||||
"customStylesheet": "Pielāgota stila lapa",
|
||||
"defaultUserDescription": "Šie ir noklusējuma iestatījumi jaunajiem lietotājiem.",
|
||||
"disableExternalLinks": "Atspējot ārējās saites (izņemot dokumentāciju)",
|
||||
"disableUsedDiskPercentage": "Atspējot izmantotā diska procentuālās daļas grafiku",
|
||||
"documentation": "dokumentācija",
|
||||
"examples": "Piemēri",
|
||||
"executeOnShell": "Izpildīt uz čaulas",
|
||||
"executeOnShellDescription": "Pēc noklusējuma failu pārlūks izpilda komandas, tieši izsaucot to bināros failus. Ja vēlaties tās palaist čaulā (piemēram, Bash vai PowerShell), varat to definēt šeit ar nepieciešamajiem argumentiem un karodziņiem. Ja tas ir iestatīts, izpildītā komanda tiks pievienota kā arguments. Tas attiecas gan uz lietotāja komandām, gan notikumu piesaistes rīkiem.",
|
||||
"globalRules": "Šis ir globāls atļaušanas un aizliegšanas noteikumu kopums. Tie attiecas uz katru lietotāju. Katra lietotāja iestatījumos varat definēt konkrētus noteikumus, lai tos ignorētu.",
|
||||
"globalSettings": "Globālie iestatījumi",
|
||||
"hideDotfiles": "Slēpt punktfailus",
|
||||
"insertPath": "Ievietojiet ceļu",
|
||||
"insertRegex": "Ievietojiet regex izteiksmi",
|
||||
"instanceName": "Gadījuma nosaukums",
|
||||
"language": "Valoda",
|
||||
"lockPassword": "Neļaut lietotājam mainīt paroli",
|
||||
"newPassword": "Jūsu jaunā parole",
|
||||
"newPasswordConfirm": "Apstipriniet savu jauno paroli",
|
||||
"newUser": "Jauns lietotājs",
|
||||
"password": "Parole",
|
||||
"passwordUpdated": "Parole atjaunināta!",
|
||||
"path": "Ceļš",
|
||||
"perm": {
|
||||
"create": "Izveidojiet failus un direktorijus",
|
||||
"delete": "Dzēst failus un direktorijus",
|
||||
"download": "Lejupielādēt",
|
||||
"execute": "Izpildīt komandas",
|
||||
"modify": "Rediģēt failus",
|
||||
"rename": "Pārdēvēt vai pārvietot failus un direktorijus",
|
||||
"share": "Kopīgojiet failus"
|
||||
},
|
||||
"permissions": "Atļaujas",
|
||||
"permissionsHelp": "Varat iestatīt lietotāju kā administratoru vai izvēlēties atļaujas individuāli. Ja atlasīsiet “Administrators”, visas pārējās opcijas tiks automātiski atzīmētas. Lietotāju pārvaldība joprojām ir administratora privilēģija.\n",
|
||||
"profileSettings": "Profila iestatījumi",
|
||||
"redirectAfterCopyMove": "Pārvirzīt uz galapunktu pēc kopēšanas/pārvietošanas",
|
||||
"ruleExample1": "neļauj piekļūt jebkuram dotfile failam (piemēram, .git, .gitignore) katrā mapē.\n",
|
||||
"ruleExample2": "bloķē piekļuvi failam ar nosaukumu Caddyfile darbības jomas saknē.",
|
||||
"rules": "Noteikumi",
|
||||
"rulesHelp": "Šeit varat definēt atļaušanas un aizliegšanas noteikumu kopu šim konkrētajam lietotājam. Bloķētie faili netiks rādīti sarakstos, un lietotājs tiem nevarēs piekļūt. Mēs atbalstām regulārās izteiksmes un ceļus attiecībā pret lietotāja darbības jomu.\n",
|
||||
"scope": "Darbības joma",
|
||||
"setDateFormat": "Iestatiet precīzu datuma formātu",
|
||||
"settingsUpdated": "Iestatījumi atjaunināti!",
|
||||
"shareDuration": "Kopīgošanas ilgums",
|
||||
"shareManagement": "Kopīgošanas pārvaldība",
|
||||
"shareDeleted": "Kopīgojums izdzēsts!",
|
||||
"singleClick": "Failu un direktoriju atvēršanai izmantojiet vienus klikšķi",
|
||||
"themes": {
|
||||
"default": "Sistēmas noklusējums",
|
||||
"dark": "Tumša",
|
||||
"light": "Gaiša",
|
||||
"title": "Tēma"
|
||||
},
|
||||
"user": "Lietotājs",
|
||||
"userCommands": "Komandas",
|
||||
"userCommandsHelp": "Ar atstarpi atdalīts saraksts ar šim lietotājam pieejamajām komandām. Piemērs:\n",
|
||||
"userCreated": "Lietotājs izveidots!",
|
||||
"userDefaults": "Lietotāja noklusējuma iestatījumi",
|
||||
"userDeleted": "Lietotājs izdzēsts!",
|
||||
"userManagement": "Lietotāju pārvaldība",
|
||||
"userUpdated": "Lietotājs atjaunināts!",
|
||||
"username": "Lietotājvārds",
|
||||
"users": "Lietotāji",
|
||||
"currentPassword": "Esošā Parole"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Palīdzība",
|
||||
"hugoNew": "Hugo Jauns",
|
||||
"login": "Pieteikties",
|
||||
"logout": "Atteikties",
|
||||
"myFiles": "Mani faili",
|
||||
"newFile": "Jauns fails",
|
||||
"newFolder": "Jauna mape",
|
||||
"preview": "Priekšskatījums",
|
||||
"settings": "Iestatījumi",
|
||||
"signup": "Reģistrēties",
|
||||
"siteSettings": "Vietnes iestatījumi"
|
||||
},
|
||||
"success": {
|
||||
"linkCopied": "Saite nokopēta!"
|
||||
},
|
||||
"time": {
|
||||
"days": "Dienas",
|
||||
"hours": "Stundas",
|
||||
"minutes": "Minūtes",
|
||||
"seconds": "Sekundes",
|
||||
"unit": "Laika vienība"
|
||||
}
|
||||
}
|
||||
@@ -42,7 +42,9 @@
|
||||
"update": "Updaten",
|
||||
"upload": "Uploaden",
|
||||
"openFile": "Open file",
|
||||
"openDirect": "View raw",
|
||||
"discardChanges": "Discard",
|
||||
"stopSearch": "Stop searching",
|
||||
"saveChanges": "Save changes",
|
||||
"editAsText": "Edit as Text",
|
||||
"increaseFontSize": "Increase font size",
|
||||
@@ -87,7 +89,8 @@
|
||||
"comma": "Comma (,)",
|
||||
"semicolon": "Semicolon (;)",
|
||||
"both": "Both (,) and (;)"
|
||||
}
|
||||
},
|
||||
"fileEncoding": "File Encoding"
|
||||
},
|
||||
"help": {
|
||||
"click": "selecteer bestand of map",
|
||||
@@ -231,6 +234,7 @@
|
||||
"permissions": "Permissies",
|
||||
"permissionsHelp": "U kunt de gebruiker instellen als beheerder of de machtigingen afzonderlijk kiezen. Als u \"Beheerder\" selecteert, worden alle andere opties automatisch gecontroleerd. Het beheer van gebruikers blijft een privilege van een beheerder.\n",
|
||||
"profileSettings": "Profielinstellingen",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "voorkomt de toegang tot elk puntbestand (zoals .git, .gitignore) in elke map.\n",
|
||||
"ruleExample2": "blokkeert de toegang tot het bestand met de naam Caddyfile in de hoofdmap van het bereik.",
|
||||
"rules": "Regels",
|
||||
@@ -257,7 +261,8 @@
|
||||
"userManagement": "Gebruikersbeheer",
|
||||
"userUpdated": "Gebruiker bijgewerkt!",
|
||||
"username": "Gebruikersnaam",
|
||||
"users": "Gebruikers"
|
||||
"users": "Gebruikers",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Help",
|
||||
|
||||
@@ -0,0 +1,290 @@
|
||||
{
|
||||
"buttons": {
|
||||
"cancel": "Annuleren",
|
||||
"clear": "Wissen",
|
||||
"close": "Sluiten",
|
||||
"continue": "Doorgaan",
|
||||
"copy": "Kopiëren",
|
||||
"copyFile": "Bestand kopiëren",
|
||||
"copyToClipboard": "Kopiëren naar klembord",
|
||||
"copyDownloadLinkToClipboard": "Download-link kopiëren naar klembord",
|
||||
"create": "Aanmaken",
|
||||
"delete": "Verwijderen",
|
||||
"download": "Downloaden",
|
||||
"file": "Bestand",
|
||||
"folder": "Map",
|
||||
"fullScreen": "Volledig scherm wisselen",
|
||||
"hideDotfiles": "dot-bestanden verbergen",
|
||||
"info": "Info",
|
||||
"more": "Meer",
|
||||
"move": "Verplaatsen",
|
||||
"moveFile": "Bestand verplaatsen",
|
||||
"new": "Nieuw",
|
||||
"next": "Volgende",
|
||||
"ok": "OK",
|
||||
"permalink": "Permanente link verkrijgen",
|
||||
"previous": "Vorige",
|
||||
"preview": "Voorbeeld",
|
||||
"publish": "Publiceren",
|
||||
"rename": "Hernoemen",
|
||||
"replace": "Vervangen",
|
||||
"reportIssue": "Probleem melden",
|
||||
"save": "Opslaan",
|
||||
"schedule": "Plannen",
|
||||
"search": "Zoeken",
|
||||
"select": "Selecteren",
|
||||
"selectMultiple": "Meervoudige selectie",
|
||||
"share": "Delen",
|
||||
"shell": "Opdrachtvenster wisselen",
|
||||
"submit": "Indienen",
|
||||
"switchView": "Weergave wisselen",
|
||||
"toggleSidebar": "Zijbalk wisselen",
|
||||
"update": "Bijwerken",
|
||||
"upload": "Uploaden",
|
||||
"openFile": "Bestand openen",
|
||||
"openDirect": "View raw",
|
||||
"discardChanges": "Weggooien",
|
||||
"stopSearch": "Stoppen met zoeken",
|
||||
"saveChanges": "Wijzigingen opslaan",
|
||||
"editAsText": "Als tekst bewerken",
|
||||
"increaseFontSize": "Lettertype vergroten",
|
||||
"decreaseFontSize": "Lettertype verkleinen"
|
||||
},
|
||||
"download": {
|
||||
"downloadFile": "Bestand downloaden",
|
||||
"downloadFolder": "Map downloaden",
|
||||
"downloadSelected": "Selectie downloaden"
|
||||
},
|
||||
"upload": {
|
||||
"abortUpload": "Weet u zeker dat u wilt afbreken?"
|
||||
},
|
||||
"errors": {
|
||||
"forbidden": "U hebt hier geen toegangsrechten.",
|
||||
"internal": "Er ging iets mis.",
|
||||
"notFound": "Deze locatie kan niet worden bereikt.",
|
||||
"connection": "De server kan niet worden bereikt."
|
||||
},
|
||||
"files": {
|
||||
"body": "Inoud",
|
||||
"closePreview": "Voorbeeld sluiten",
|
||||
"files": "Bestanden",
|
||||
"folders": "Mappen",
|
||||
"home": "Thuis",
|
||||
"lastModified": "Laatst aangepast",
|
||||
"loading": "Laden...",
|
||||
"lonely": "Het is hier wat leeg...",
|
||||
"metadata": "Metagegevens",
|
||||
"multipleSelectionEnabled": "Meervoudige selectie ingeschakeld",
|
||||
"name": "Naam",
|
||||
"size": "Grootte",
|
||||
"sortByLastModified": "Sorteren op laatst aangepast",
|
||||
"sortByName": "Sorteren op naam",
|
||||
"sortBySize": "Sorteren op grootte",
|
||||
"noPreview": "Geen voorbeeld beschikbaar voor dit bestand.",
|
||||
"csvTooLarge": "CSV-bestand is te groot voor voorbeeld (>5MB). Download het om het te bekijken.",
|
||||
"csvLoadFailed": "Laden van CSV-bestand is mislukt.",
|
||||
"showingRows": "{count} rij(en) weergeven",
|
||||
"columnSeparator": "Kolom-scheidingsteken",
|
||||
"csvSeparators": {
|
||||
"comma": "Komma (,)",
|
||||
"semicolon": "Puntkomma (;)",
|
||||
"both": "Beide (,) en (;)"
|
||||
},
|
||||
"fileEncoding": "Bestandscodering"
|
||||
},
|
||||
"help": {
|
||||
"click": "selecteer bestand of map",
|
||||
"ctrl": {
|
||||
"click": "selecteer meerdere bestanden of mappen",
|
||||
"f": "open zoekopdracht",
|
||||
"s": "sla een bestand op of download de huidige map"
|
||||
},
|
||||
"del": "verwijder geselecteerde items",
|
||||
"doubleClick": "open een bestand of map",
|
||||
"esc": "wis de selectie en/of sluit het opdrachtvenster",
|
||||
"f1": "deze informatie",
|
||||
"f2": "hernoem bestand",
|
||||
"help": "Hulp"
|
||||
},
|
||||
"login": {
|
||||
"createAnAccount": "Account aanmaken",
|
||||
"loginInstead": "Heeft al een account",
|
||||
"password": "Wachtwoord",
|
||||
"passwordConfirm": "Wachtwoord bevestigen",
|
||||
"passwordsDontMatch": "Wachtwoorden komen niet overeen",
|
||||
"signup": "Registeren",
|
||||
"submit": "Inloggen",
|
||||
"username": "Gebruikersnaam",
|
||||
"usernameTaken": "Gebruikersnaam reeds in gebruik",
|
||||
"wrongCredentials": "Inloggegevens zijn incorrect",
|
||||
"passwordTooShort": "Wachtwoord moet minstens {min} tekens bevatten",
|
||||
"logout_reasons": {
|
||||
"inactivity": "U bent uitgelogd vanwege inactiviteit."
|
||||
}
|
||||
},
|
||||
"permanent": "Permanent",
|
||||
"prompts": {
|
||||
"copy": "Kopiëren",
|
||||
"copyMessage": "Kies een locatie om uw bestanden te kopiëren:",
|
||||
"currentlyNavigating": "Navigeren op:",
|
||||
"deleteMessageMultiple": "Weet u zeker dat u {count} bestand(en) wilt verwijderen?",
|
||||
"deleteMessageSingle": "Weet u zeker dat u dit bestand/deze map wilt verwijderen?",
|
||||
"deleteMessageShare": "Weet u zeker dat u deze gedeelde map ({path}) wilt verwijderen?",
|
||||
"deleteUser": "Weet u zeker dat u deze gebruiker wilt verwijderen?",
|
||||
"deleteTitle": "Bestanden verwijderen",
|
||||
"displayName": "Weergavenaam:",
|
||||
"download": "Bestanden downloaden",
|
||||
"downloadMessage": "Kies het formaat dat u wilt downloaden.",
|
||||
"error": "Er ging iets fout",
|
||||
"fileInfo": "Bestandsinformatie",
|
||||
"filesSelected": "{count} geselecteerde bestanden.",
|
||||
"lastModified": "Laatst aangepast",
|
||||
"move": "Verplaatsen",
|
||||
"moveMessage": "Kies een nieuw Thuis voor uw bestand(en)/map(pen):",
|
||||
"newArchetype": "Maak een nieuw bericht op basis van een archetype. Uw bestand wordt aangemaakt in de inhoudsmap.",
|
||||
"newDir": "Nieuwe map",
|
||||
"newDirMessage": "Voer een naam in voor de nieuwe map.",
|
||||
"newFile": "Nieuw bestand",
|
||||
"newFileMessage": "Voer een naam in voor het nieuwe bestand.",
|
||||
"numberDirs": "Aantal mappen",
|
||||
"numberFiles": "Aantal bestanden",
|
||||
"rename": "Hernoemen",
|
||||
"renameMessage": "Voer een nieuwe naam in voor",
|
||||
"replace": "Vervangen",
|
||||
"replaceMessage": "Een van de bestanden die u probeert te uploaden, geeft conflicten i.v.m. de naamgeving. Wilt u de bestaande bestanden vervangen?\n",
|
||||
"schedule": "Plannen",
|
||||
"scheduleMessage": "Kies een datum en tijd om de publicatie van dit bericht in te plannen.",
|
||||
"show": "Weergeven",
|
||||
"size": "Grootte",
|
||||
"upload": "Uploaden",
|
||||
"uploadFiles": "{files} bestanden uploaden...",
|
||||
"uploadMessage": "Kies een optie bij de upload.",
|
||||
"optionalPassword": "Optioneel wachtwoord",
|
||||
"resolution": "Resolutie",
|
||||
"discardEditorChanges": "Weet u zeker dat u de door u aangebrachte wijzigingen wilt weggooien?"
|
||||
},
|
||||
"search": {
|
||||
"images": "Afbeeldingen",
|
||||
"music": "Muziek",
|
||||
"pdf": "PDF",
|
||||
"pressToSearch": "Druk op enter om te zoeken...",
|
||||
"search": "Zoeken...",
|
||||
"typeToSearch": "Typ om te zoeken...",
|
||||
"types": "Types",
|
||||
"video": "Video"
|
||||
},
|
||||
"settings": {
|
||||
"aceEditorTheme": "Ace editor-thema",
|
||||
"admin": "Admin",
|
||||
"administrator": "Beheerder",
|
||||
"allowCommands": "Opdrachten uitvoeren",
|
||||
"allowEdit": "Bestanden of mappen bewerken, hernoemen of verwijderen",
|
||||
"allowNew": "Nieuwe bestanden of mappen aanmaken",
|
||||
"allowPublish": "Nieuwe berichten en pagina's publiceren",
|
||||
"allowSignup": "Gebruikers toestaan om zich te registreren",
|
||||
"hideLoginButton": "De inlogknop verbergen van openbare pagina's",
|
||||
"avoidChanges": "(leeg laten om wijzigingen te voorkomen)",
|
||||
"branding": "Branding",
|
||||
"brandingDirectoryPath": "Pad naar map met Branding",
|
||||
"brandingHelp": "U kunt het uiterlijk van uw File Browser aanpassen door de naam te wijzigen, het logo te vervangen, aangepaste stijlen toe te voegen en zelfs externe links naar GitHub uit te schakelen.\nVoor meer informatie over custom branding, bekijk {0}.",
|
||||
"changePassword": "Wachtwoord wijzigen",
|
||||
"commandRunner": "Opdracht uitvoeren",
|
||||
"commandRunnerHelp": "Hier kunt u opdrachten instellen die worden uitgevoerd in de benoemde gebeurtenissen. Noteer één opdracht per regel. De omgevingsvariabelen {0} en {1} zijn beschikbaar, waarbij {0} relatief is ten opzichte van {1}. Raadpleeg {2} voor meer informatie over deze functie en de beschikbare omgevingsvariabelen.",
|
||||
"commandsUpdated": "Opdrachten bijgewerkt!",
|
||||
"createUserDir": "Maak bij het aanmaken van een nieuwe gebruiker automatisch een thuismap aan",
|
||||
"minimumPasswordLength": "Minimale wachtwoordlengte",
|
||||
"tusUploads": "Uploads in brokken",
|
||||
"tusUploadsHelp": "File Browser ondersteunt bestandsuploads in brokken, waardoor efficiënte, betrouwbare, hervatbare bestandsuploads kunnen worden verricht, zelfs over onbetrouwbare netwerken.",
|
||||
"tusUploadsChunkSize": "Geeft de maximale grootte van een verzoek aan (directe uploads worden gebruikt voor kleinere uploads). U kunt een geheel getal invoeren dat de bytegrootte aangeeft, of een tekenreeks zoals 10MB, 1GB enz.",
|
||||
"tusUploadsRetryCount": "Aantal nieuwe pogingen om uit te voeren als een deel niet kan worden geüpload.",
|
||||
"userHomeBasePath": "Basispad voor Thuismappen van de gebruikers",
|
||||
"userScopeGenerationPlaceholder": "Het bereik wordt automatisch gegenereeerd",
|
||||
"createUserHomeDirectory": "Thuismap voor de gebruiker aanmaken",
|
||||
"customStylesheet": "Aangepaste stylesheet",
|
||||
"defaultUserDescription": "Dit zijn de standaardinstellingen voor nieuwe gebruikers.",
|
||||
"disableExternalLinks": "Externe links uitschakelen (behalve documentatie)",
|
||||
"disableUsedDiskPercentage": "Grafiek van gebruikte schijfruimte uitschakelen",
|
||||
"documentation": "documentatie",
|
||||
"examples": "Voorbeelden",
|
||||
"executeOnShell": "Uitvoeren in opdrachtvenster",
|
||||
"executeOnShellDescription": "File Browser voert de opdrachten standaard uit door het rechtstreeks oproepen van hun hun binaire bestanden. Als u ze in plaats daarvan wilt uitvoeren in een opdrachtvenster (zoals Bash of PowerShell), kunt u dit hier definiëren met de vereiste argumenten en vlaggen. Zo wordt de opdracht die u uitvoert, toegevoegd als een argument. Dit is van toepassing op zowel gebruikersopdrachten als event-hooks.",
|
||||
"globalRules": "Dit is een algemene reeks toestaan/niet toestaan-regels welke van toepassing zijn op alle gebruikers. U kunt voor elke gebruiker specifieke regels definiëren om deze te overschrijven.",
|
||||
"globalSettings": "Algemene instellingen",
|
||||
"hideDotfiles": "dot-bestanden verbergen",
|
||||
"insertPath": "Pad invoegen",
|
||||
"insertRegex": "Regex-expressie invoegen",
|
||||
"instanceName": "Naam van de instantie",
|
||||
"language": "Taal",
|
||||
"lockPassword": "Voorkomen dat de gebruiker het wachtwoord wijzigt",
|
||||
"newPassword": "Uw nieuwe wachtwoord",
|
||||
"newPasswordConfirm": "Uw nieuwe wachtwoord bevestigen",
|
||||
"newUser": "Nieuwe gebruiker",
|
||||
"password": "Wachtwoord",
|
||||
"passwordUpdated": "Wachtwoord bijgewerkt!",
|
||||
"path": "Pad",
|
||||
"perm": {
|
||||
"create": "Bestanden en mappen aanmaken",
|
||||
"delete": "Bestanden en mappen verwijderen",
|
||||
"download": "Downloaden",
|
||||
"execute": "Opdrachten uitvoeren",
|
||||
"modify": "Bestanden bewerken",
|
||||
"rename": "Bestanden of mappen hernoemen of verplaatsen",
|
||||
"share": "Bestanden delen"
|
||||
},
|
||||
"permissions": "Machtigingen",
|
||||
"permissionsHelp": " kunt de gebruiker instellen als beheerder of de machtigingen afzonderlijk kiezen. Als u \"Beheerder\" selecteert, worden alle overige opties automatisch ingeschakeld. Het beheer van gebruikers blijft een privilege van een beheerder.\n",
|
||||
"profileSettings": "Profielinstellingen",
|
||||
"redirectAfterCopyMove": "Doorverwijzen naar bestemming na kopiëren/verplaatsen",
|
||||
"ruleExample1": "voorkomt de toegang tot dot-bestanden (zoals .git, .gitignore) in elke map.\n",
|
||||
"ruleExample2": "blokkeert de toegang tot het bestand met de naam Caddyfile in de hoofdmap van het bereik.",
|
||||
"rules": "Regels",
|
||||
"rulesHelp": "Hier kunt u voor deze specifieke gebruiker een reeks toestaan/niet toestaan-regels definiëren. De geblokkeerde bestanden verschijnen niet in de lijsten en zijn niet toegankelijk voor de gebruiker. Regex wordt ondersteund en paden zijn relatief ten opzichte van het bereik van gebruikers.\n",
|
||||
"scope": "Bereik",
|
||||
"setDateFormat": "Exacte datumformaat instellen",
|
||||
"settingsUpdated": "Instellingen bijgewerkt!",
|
||||
"shareDuration": "Duur van het delen",
|
||||
"shareManagement": "Beheer van gedeelde mappen en bestanden",
|
||||
"shareDeleted": "Delen opheffen!",
|
||||
"singleClick": "Bestanden en mappen met een enkele klik openen",
|
||||
"themes": {
|
||||
"default": "Systeem standaard",
|
||||
"dark": "Donker",
|
||||
"light": "Licht",
|
||||
"title": "Thema"
|
||||
},
|
||||
"user": "Gebruiker",
|
||||
"userCommands": "Opdrachten",
|
||||
"userCommandsHelp": "Een lijst met beschikbare opdrachten voor de gebruiker gescheiden door spaties. Voorbeeld:\n",
|
||||
"userCreated": "Gebruiker aangemaakt!",
|
||||
"userDefaults": "Standaardinstellingen van gebruiker",
|
||||
"userDeleted": "Gebruiker verwijderd!",
|
||||
"userManagement": "Gebruikers beheren",
|
||||
"userUpdated": "Gebruiker bijgewerkt!",
|
||||
"username": "Gebruikersnaam",
|
||||
"users": "Gebruikers",
|
||||
"currentPassword": "Uw huidige wachtwoord"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Hulp",
|
||||
"hugoNew": "Hugo Nieuw",
|
||||
"login": "Inloggen",
|
||||
"logout": "Uitloggen",
|
||||
"myFiles": "Mijn bestanden",
|
||||
"newFile": "Nieuw bestand",
|
||||
"newFolder": "Nieuwe map",
|
||||
"preview": "Voorbeeld",
|
||||
"settings": "Instellingen",
|
||||
"signup": "Registeren",
|
||||
"siteSettings": "Site-instellingen"
|
||||
},
|
||||
"success": {
|
||||
"linkCopied": "Link gekopieerd!"
|
||||
},
|
||||
"time": {
|
||||
"days": "Dagen",
|
||||
"hours": "Uren",
|
||||
"minutes": "Minuten",
|
||||
"seconds": "Seconden",
|
||||
"unit": "Tijdseenheid"
|
||||
}
|
||||
}
|
||||
@@ -42,7 +42,9 @@
|
||||
"update": "Opptater",
|
||||
"upload": "Last opp",
|
||||
"openFile": "Open file",
|
||||
"openDirect": "View raw",
|
||||
"discardChanges": "Slett",
|
||||
"stopSearch": "Stop searching",
|
||||
"saveChanges": "Lagre Endringane ",
|
||||
"editAsText": "Edit as Text",
|
||||
"increaseFontSize": "Increase font size",
|
||||
@@ -87,7 +89,8 @@
|
||||
"comma": "Comma (,)",
|
||||
"semicolon": "Semicolon (;)",
|
||||
"both": "Both (,) and (;)"
|
||||
}
|
||||
},
|
||||
"fileEncoding": "File Encoding"
|
||||
},
|
||||
"help": {
|
||||
"click": "velg fil eller katalog",
|
||||
@@ -231,6 +234,7 @@
|
||||
"permissions": "Tilaterser",
|
||||
"permissionsHelp": "Du kan angi brukeren som administrator eller velge tillatelsene individuelt. Hvis du velger «Administrator», vil alle de andre alternativene bli automatisk avkrysset. Administrasjon av brukere er fortsatt et privilegium for en administrator.\n",
|
||||
"profileSettings": "Profil Innstilinger",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "forhindrer tilgang til noen dotfiler (som .git, .gitignore) i alle mapper.\n",
|
||||
"ruleExample2": "blokkerer tilgangen til filen med navnet Caddyfile på roten av omfanget.",
|
||||
"rules": "Regler",
|
||||
@@ -257,7 +261,8 @@
|
||||
"userManagement": "Brukeradministrasjon",
|
||||
"userUpdated": "Bruker opprettet!",
|
||||
"username": "Brukernavn",
|
||||
"users": "Bruker"
|
||||
"users": "Bruker",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Hjelp",
|
||||
|
||||
@@ -42,7 +42,9 @@
|
||||
"update": "Aktualizuj",
|
||||
"upload": "Wyślij",
|
||||
"openFile": "Otwórz plik",
|
||||
"openDirect": "View raw",
|
||||
"discardChanges": "Odrzuć",
|
||||
"stopSearch": "Zatrzymaj wyszukiwanie",
|
||||
"saveChanges": "Zapisz zmiany",
|
||||
"editAsText": "Edytuj jako tekst",
|
||||
"increaseFontSize": "Zwiększ rozmiar czcionki",
|
||||
@@ -87,7 +89,8 @@
|
||||
"comma": "Przecinek (,)",
|
||||
"semicolon": "Średnik (;)",
|
||||
"both": "Zarówno (,), jak i (;)"
|
||||
}
|
||||
},
|
||||
"fileEncoding": "Kodowanie pliku"
|
||||
},
|
||||
"help": {
|
||||
"click": "zaznacz plik lub folder",
|
||||
@@ -230,7 +233,8 @@
|
||||
},
|
||||
"permissions": "Uprawnienia",
|
||||
"permissionsHelp": "Możesz ustawić użytkownika jako administratora lub wybrać uprawnienia indywidualnie. Jeśli wybierzesz „Administrator”, wszystkie pozostałe opcje zostaną automatycznie zaznaczone. Zarządzanie użytkownikami pozostaje przywilejem administratora.\n",
|
||||
"profileSettings": "Twój profil",
|
||||
"profileSettings": "Ustawienia profilu",
|
||||
"redirectAfterCopyMove": "Przekieruj do miejsca docelowego po skopiowaniu lub przeniesieniu",
|
||||
"ruleExample1": "uniemożliwia dostęp do plików poprzedzonych kropką (takich jak .git, .gitignore) we wszystkich folderach.\n",
|
||||
"ruleExample2": "blokuje dostęp do pliku o nazwie Caddyfile w katalogu głównym zakresu.",
|
||||
"rules": "Uprawnienia",
|
||||
@@ -257,7 +261,8 @@
|
||||
"userManagement": "Zarządzanie użytkownikami",
|
||||
"userUpdated": "Użytkownik zapisany!",
|
||||
"username": "Nazwa użytkownika",
|
||||
"users": "Użytkownicy"
|
||||
"users": "Użytkownicy",
|
||||
"currentPassword": "Twoje aktualne hasło"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Pomoc",
|
||||
|
||||
@@ -42,7 +42,9 @@
|
||||
"update": "Atualizar",
|
||||
"upload": "Enviar",
|
||||
"openFile": "Abrir",
|
||||
"openDirect": "View raw",
|
||||
"discardChanges": "Discard",
|
||||
"stopSearch": "Stop searching",
|
||||
"saveChanges": "Save changes",
|
||||
"editAsText": "Edit as Text",
|
||||
"increaseFontSize": "Increase font size",
|
||||
@@ -87,7 +89,8 @@
|
||||
"comma": "Comma (,)",
|
||||
"semicolon": "Semicolon (;)",
|
||||
"both": "Both (,) and (;)"
|
||||
}
|
||||
},
|
||||
"fileEncoding": "File Encoding"
|
||||
},
|
||||
"help": {
|
||||
"click": "selecionar pasta ou arquivo",
|
||||
@@ -231,6 +234,7 @@
|
||||
"permissions": "Permissões",
|
||||
"permissionsHelp": "Pode definir o usuário como administrador ou escolher as permissões manualmente. Se selecionar a opção \"Administrador\", todas as outras opções serão automaticamente selecionadas. A gestão dos usuários é um privilégio restringido aos administradores.\n",
|
||||
"profileSettings": "Configurações do usuário",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "previne o acesso a qualquer \"dotfile\" (como .git, .gitignore) em qualquer pasta\n",
|
||||
"ruleExample2": "bloqueia o acesso ao arquivo chamado Caddyfile.",
|
||||
"rules": "Regras",
|
||||
@@ -257,7 +261,8 @@
|
||||
"userManagement": "Gerenciamento de usuários",
|
||||
"userUpdated": "Usuário atualizado!",
|
||||
"username": "Nome do usuário",
|
||||
"users": "Usuários"
|
||||
"users": "Usuários",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Ajuda",
|
||||
|
||||
@@ -42,7 +42,9 @@
|
||||
"update": "Atualizar",
|
||||
"upload": "Enviar",
|
||||
"openFile": "Open file",
|
||||
"openDirect": "View raw",
|
||||
"discardChanges": "Discard",
|
||||
"stopSearch": "Stop searching",
|
||||
"saveChanges": "Save changes",
|
||||
"editAsText": "Edit as Text",
|
||||
"increaseFontSize": "Increase font size",
|
||||
@@ -87,7 +89,8 @@
|
||||
"comma": "Comma (,)",
|
||||
"semicolon": "Semicolon (;)",
|
||||
"both": "Both (,) and (;)"
|
||||
}
|
||||
},
|
||||
"fileEncoding": "File Encoding"
|
||||
},
|
||||
"help": {
|
||||
"click": "selecionar pasta ou ficheiro",
|
||||
@@ -231,6 +234,7 @@
|
||||
"permissions": "Permissões",
|
||||
"permissionsHelp": "Pode definir o utilizador como administrador ou escolher as permissões manualmente. Se selecionar a opção \"Administrador\", todas as outras opções serão automaticamente selecionadas. A gestão dos utilizadores é um privilégio restringido aos administradores.\n",
|
||||
"profileSettings": "Configurações do utilizador",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "previne o acesso a qualquer \"dotfile\" (como .git, .gitignore) em qualquer pasta\n",
|
||||
"ruleExample2": "bloqueia o acesso ao ficheiro chamado Caddyfile na raiz.",
|
||||
"rules": "Regras",
|
||||
@@ -257,7 +261,8 @@
|
||||
"userManagement": "Gestão de utilizadores",
|
||||
"userUpdated": "Utilizador atualizado!",
|
||||
"username": "Nome de utilizador",
|
||||
"users": "Utilizadores"
|
||||
"users": "Utilizadores",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Ajuda",
|
||||
|
||||
@@ -42,7 +42,9 @@
|
||||
"update": "Actualizează",
|
||||
"upload": "Încarcă",
|
||||
"openFile": "Open file",
|
||||
"openDirect": "View raw",
|
||||
"discardChanges": "Discard",
|
||||
"stopSearch": "Stop searching",
|
||||
"saveChanges": "Save changes",
|
||||
"editAsText": "Edit as Text",
|
||||
"increaseFontSize": "Increase font size",
|
||||
@@ -87,7 +89,8 @@
|
||||
"comma": "Comma (,)",
|
||||
"semicolon": "Semicolon (;)",
|
||||
"both": "Both (,) and (;)"
|
||||
}
|
||||
},
|
||||
"fileEncoding": "File Encoding"
|
||||
},
|
||||
"help": {
|
||||
"click": "alege fișier sau director",
|
||||
@@ -231,6 +234,7 @@
|
||||
"permissions": "Permisiuni",
|
||||
"permissionsHelp": "Poți alege ca un utilizator să fie administrator sau să-i alegi permisiunile individual. Dacă alegi \"Administrator\", toate celelalte opțiuni vor fi bifate automat. Gestionarea utilizatorilor rămâne un privilegiu exclusiv al administratorilor.\n",
|
||||
"profileSettings": "Setări profil",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "împiedică accesul la fisiere cu punct in față (.), cum ar fi .git, .gitignore în orice director.\n",
|
||||
"ruleExample2": "împiedică accesul la fișierul Caddyfile din rădăcina domeniului.",
|
||||
"rules": "Reguli",
|
||||
@@ -257,7 +261,8 @@
|
||||
"userManagement": "Gestionare utilizatori",
|
||||
"userUpdated": "Utilizator actualizat!",
|
||||
"username": "Utilizator",
|
||||
"users": "Utilizatori"
|
||||
"users": "Utilizatori",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Ajutor",
|
||||
|
||||
+23
-18
@@ -42,11 +42,13 @@
|
||||
"update": "Обновить",
|
||||
"upload": "Загрузить",
|
||||
"openFile": "Открыть файл",
|
||||
"openDirect": "View raw",
|
||||
"discardChanges": "Отказаться",
|
||||
"saveChanges": "Save changes",
|
||||
"editAsText": "Edit as Text",
|
||||
"increaseFontSize": "Increase font size",
|
||||
"decreaseFontSize": "Decrease font size"
|
||||
"stopSearch": "Stop searching",
|
||||
"saveChanges": "Сохранить",
|
||||
"editAsText": "Редактировать как текст",
|
||||
"increaseFontSize": "Увеличить размер шрифта",
|
||||
"decreaseFontSize": "Уменьшить размер шрифта"
|
||||
},
|
||||
"download": {
|
||||
"downloadFile": "Скачать файл",
|
||||
@@ -79,15 +81,16 @@
|
||||
"sortByName": "Сортировка по имени",
|
||||
"sortBySize": "Сортировка по размеру",
|
||||
"noPreview": "Предварительный просмотр для этого файла недоступен.",
|
||||
"csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.",
|
||||
"csvLoadFailed": "Failed to load CSV file.",
|
||||
"showingRows": "Showing {count} row(s)",
|
||||
"columnSeparator": "Column Separator",
|
||||
"csvTooLarge": "Этот CSV файл слишком большой для предпросмотра (>5 МБ). Скачайте и откройте его локально.",
|
||||
"csvLoadFailed": "Не удалось загрузить этот CSV.",
|
||||
"showingRows": "Отображается {count} строк(а)",
|
||||
"columnSeparator": "Разделитель столбцов",
|
||||
"csvSeparators": {
|
||||
"comma": "Comma (,)",
|
||||
"semicolon": "Semicolon (;)",
|
||||
"both": "Both (,) and (;)"
|
||||
}
|
||||
"comma": "Запятая (,)",
|
||||
"semicolon": "Точка с запятой (;)",
|
||||
"both": "Оба варианта — (,) и (;)"
|
||||
},
|
||||
"fileEncoding": "File Encoding"
|
||||
},
|
||||
"help": {
|
||||
"click": "выбрать файл или каталог",
|
||||
@@ -114,9 +117,9 @@
|
||||
"username": "Имя пользователя",
|
||||
"usernameTaken": "Данное имя пользователя уже занято",
|
||||
"wrongCredentials": "Неверные данные",
|
||||
"passwordTooShort": "Password must be at least {min} characters",
|
||||
"passwordTooShort": "Пароль должен состоять как минимум из {min} символов",
|
||||
"logout_reasons": {
|
||||
"inactivity": "You have been logged out due to inactivity."
|
||||
"inactivity": "Сессия завершена после долгого отсутствия."
|
||||
}
|
||||
},
|
||||
"permanent": "Постоянный",
|
||||
@@ -171,7 +174,7 @@
|
||||
"video": "Видео"
|
||||
},
|
||||
"settings": {
|
||||
"aceEditorTheme": "Ace editor theme",
|
||||
"aceEditorTheme": "Тема редактора Ace",
|
||||
"admin": "Админ",
|
||||
"administrator": "Администратор",
|
||||
"allowCommands": "Запуск команд",
|
||||
@@ -179,7 +182,7 @@
|
||||
"allowNew": "Создание новых файлов или каталогов",
|
||||
"allowPublish": "Публикация новых записей и страниц",
|
||||
"allowSignup": "Разрешить пользователям регистрироваться",
|
||||
"hideLoginButton": "Hide the login button from public pages",
|
||||
"hideLoginButton": "Спрятать кнопку входа с публичных страниц",
|
||||
"avoidChanges": "(оставьте поле пустым, чтобы избежать изменений)",
|
||||
"branding": "Брендинг",
|
||||
"brandingDirectoryPath": "Путь к каталогу брендов",
|
||||
@@ -189,7 +192,7 @@
|
||||
"commandRunnerHelp": "Здесь вы можете установить команды, которые будут выполняться в указанных событиях. Вы должны указать по одной команде в каждой строке. Переменные среды {0} и {1} будут доступны, будучи {0} относительно {1}. Дополнительные сведения об этой функции и доступных переменных среды см. В {2}.",
|
||||
"commandsUpdated": "Команды обновлены!",
|
||||
"createUserDir": "Автоматическое создание домашнего каталога пользователя при добавлении нового пользователя",
|
||||
"minimumPasswordLength": "Minimum password length",
|
||||
"minimumPasswordLength": "Минимальная длина пароля",
|
||||
"tusUploads": "Загруженные файлы",
|
||||
"tusUploadsHelp": " File Browser поддерживает загрузку файлов по частям, что позволяет работать в сетях низкого качества.",
|
||||
"tusUploadsChunkSize": "Указывает максимальный размер запроса (мелкие загрузки пойдут напрямую). Вы можете ввести простое целое число, обозначающее размер ввода в байтах, или строку, например 10MB, 1GB и т. д.",
|
||||
@@ -231,6 +234,7 @@
|
||||
"permissions": "Права доступа",
|
||||
"permissionsHelp": "Можно настроить пользователя как администратора или выбрать разрешения индивидуально. При выборе \"Администратор\", все остальные параметры будут автоматически выбраны. Управление пользователями - привилегия администратора.\n",
|
||||
"profileSettings": "Настройки профиля",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "предотвратить доступ к любому скрытому файлу (например: .git, .gitignore) в каждой папке.\n",
|
||||
"ruleExample2": "блокирует доступ к файлу с именем Caddyfile в корневой области.",
|
||||
"rules": "Права",
|
||||
@@ -257,7 +261,8 @@
|
||||
"userManagement": "Управление пользователями",
|
||||
"userUpdated": "Пользователь изменен!",
|
||||
"username": "Имя пользователя",
|
||||
"users": "Пользователи"
|
||||
"users": "Пользователи",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Помощь",
|
||||
|
||||
@@ -42,7 +42,9 @@
|
||||
"update": "Aktualizovať",
|
||||
"upload": "Nahrať",
|
||||
"openFile": "Otvoriť súbor",
|
||||
"openDirect": "View raw",
|
||||
"discardChanges": "Zahodiť",
|
||||
"stopSearch": "Stop searching",
|
||||
"saveChanges": "Uložiť zmeny",
|
||||
"editAsText": "Edit as Text",
|
||||
"increaseFontSize": "Increase font size",
|
||||
@@ -87,7 +89,8 @@
|
||||
"comma": "Comma (,)",
|
||||
"semicolon": "Semicolon (;)",
|
||||
"both": "Both (,) and (;)"
|
||||
}
|
||||
},
|
||||
"fileEncoding": "File Encoding"
|
||||
},
|
||||
"help": {
|
||||
"click": "vyberie súbor alebo priečinok",
|
||||
@@ -231,6 +234,7 @@
|
||||
"permissions": "Práva",
|
||||
"permissionsHelp": "Môžete nastaviť používateľa, aby bol administrátorom alebo vybrať práva jednotlivo. Ak zvolíte \"Administrator\", všetky ďalšie budú automaticky zaškrtnuté. Manažment používateľov ostáva v správe administrátora.\n",
|
||||
"profileSettings": "Nastavenia profilu",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "blokuje prístup ku všetkým súborom začínajúcim bodkou (napríklad .git, .gitignore) v každom priečinku.\n",
|
||||
"ruleExample2": "blokuje prístup k súborom s názvom Caddyfile v koreňovom priečinku.",
|
||||
"rules": "Pravidlá",
|
||||
@@ -257,7 +261,8 @@
|
||||
"userManagement": "Správa používateľov",
|
||||
"userUpdated": "Používateľ upravený!",
|
||||
"username": "Meno používateľa",
|
||||
"users": "Používatelia"
|
||||
"users": "Používatelia",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Pomoc",
|
||||
|
||||
@@ -42,7 +42,9 @@
|
||||
"update": "Uppdatera",
|
||||
"upload": "Ladda upp",
|
||||
"openFile": "Öppna fil",
|
||||
"openDirect": "View raw",
|
||||
"discardChanges": "Förkasta",
|
||||
"stopSearch": "Stop searching",
|
||||
"saveChanges": "Spara ändringar",
|
||||
"editAsText": "Edit as Text",
|
||||
"increaseFontSize": "Increase font size",
|
||||
@@ -87,7 +89,8 @@
|
||||
"comma": "Comma (,)",
|
||||
"semicolon": "Semicolon (;)",
|
||||
"both": "Both (,) and (;)"
|
||||
}
|
||||
},
|
||||
"fileEncoding": "File Encoding"
|
||||
},
|
||||
"help": {
|
||||
"click": "välj fil eller mapp",
|
||||
@@ -231,6 +234,7 @@
|
||||
"permissions": "Rättigheter",
|
||||
"permissionsHelp": "Du kan ange att användaren ska vara administratör eller välja behörigheterna individuellt. Om du väljer \"administratör \" kommer alla andra alternativ att kontrolleras automatiskt. Hanteringen av användare är fortfarande ett privilegium för en administratör.\n",
|
||||
"profileSettings": "Profil inställningar",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "förhindrar åtkomst till en dot-fil (till exempel. git,. gitignore) i varje mapp.\n",
|
||||
"ruleExample2": "blockerar åtkomsten till filen som heter Caddyfilen i roten av scopet.",
|
||||
"rules": "Regler",
|
||||
@@ -257,7 +261,8 @@
|
||||
"userManagement": "Användarehantering",
|
||||
"userUpdated": "Användare uppdaterad!",
|
||||
"username": "Användarnamn",
|
||||
"users": "Användare"
|
||||
"users": "Användare",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Hjälp",
|
||||
|
||||
@@ -42,7 +42,9 @@
|
||||
"update": "Güncelle",
|
||||
"upload": "Yükle",
|
||||
"openFile": "Dosyayı aç",
|
||||
"openDirect": "View raw",
|
||||
"discardChanges": "Discard",
|
||||
"stopSearch": "Stop searching",
|
||||
"saveChanges": "Save changes",
|
||||
"editAsText": "Edit as Text",
|
||||
"increaseFontSize": "Increase font size",
|
||||
@@ -87,7 +89,8 @@
|
||||
"comma": "Comma (,)",
|
||||
"semicolon": "Semicolon (;)",
|
||||
"both": "Both (,) and (;)"
|
||||
}
|
||||
},
|
||||
"fileEncoding": "File Encoding"
|
||||
},
|
||||
"help": {
|
||||
"click": "dosya veya klasör seçin",
|
||||
@@ -231,6 +234,7 @@
|
||||
"permissions": "İzinler",
|
||||
"permissionsHelp": "Kullanıcıyı yönetici olarak ayarlayabilir veya izinleri ayrı ayrı seçebilirsiniz. \"Yönetici\"yi seçerseniz, diğer tüm seçenekler otomatik olarak kontrol edilecektir. Kullanıcıların yönetimi, bir yöneticinin yetkisi olarak kalır.\n",
|
||||
"profileSettings": "Profil ayarları",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "her klasördeki herhangi bir noktalı dosyaya (.git, .gitignore gibi) erişimi engeller.\n",
|
||||
"ruleExample2": "Root erişimidenki CaddyFile dosyalarına erişimi engelle.",
|
||||
"rules": "Kurallar",
|
||||
@@ -257,7 +261,8 @@
|
||||
"userManagement": "Kullanıcı yönetimi",
|
||||
"userUpdated": "Kullanıcı güncellendi!",
|
||||
"username": "Kullanıcı adı",
|
||||
"users": "Kullanıcılar"
|
||||
"users": "Kullanıcılar",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Yardım",
|
||||
|
||||
@@ -42,7 +42,9 @@
|
||||
"update": "Оновити",
|
||||
"upload": "Вивантажити",
|
||||
"openFile": "Відкрити файл",
|
||||
"openDirect": "View raw",
|
||||
"discardChanges": "Скасувати",
|
||||
"stopSearch": "Stop searching",
|
||||
"saveChanges": "Save changes",
|
||||
"editAsText": "Edit as Text",
|
||||
"increaseFontSize": "Increase font size",
|
||||
@@ -87,7 +89,8 @@
|
||||
"comma": "Comma (,)",
|
||||
"semicolon": "Semicolon (;)",
|
||||
"both": "Both (,) and (;)"
|
||||
}
|
||||
},
|
||||
"fileEncoding": "File Encoding"
|
||||
},
|
||||
"help": {
|
||||
"click": "вибрати файл чи каталог",
|
||||
@@ -231,6 +234,7 @@
|
||||
"permissions": "Дозволи",
|
||||
"permissionsHelp": "Можна налаштувати користувача як адміністратора чи вибрати індивідуальні дозволи. При виборі \"Адміністратор\" всі інші параметри будуть автоматично вибрані. Керування користувачами - привілей адміністратора.\n",
|
||||
"profileSettings": "Налаштування профілю",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "запобігти доступу до будь-якого прихованого файлу (наприклад: .git, .gitignore) у кожній папці.\n",
|
||||
"ruleExample2": "блокує доступ до файлу з ім'ям Caddyfile у кореневій області.",
|
||||
"rules": "Права",
|
||||
@@ -257,7 +261,8 @@
|
||||
"userManagement": "Керування користувачами",
|
||||
"userUpdated": "Користувача змінено!",
|
||||
"username": "Ім'я користувача",
|
||||
"users": "Користувачі"
|
||||
"users": "Користувачі",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Допомога",
|
||||
|
||||
@@ -42,7 +42,9 @@
|
||||
"update": "Cập nhật",
|
||||
"upload": "Tải lên",
|
||||
"openFile": "Mở tệp",
|
||||
"openDirect": "View raw",
|
||||
"discardChanges": "Hủy bỏ thay đổi",
|
||||
"stopSearch": "Stop searching",
|
||||
"saveChanges": "Save changes",
|
||||
"editAsText": "Edit as Text",
|
||||
"increaseFontSize": "Increase font size",
|
||||
@@ -87,7 +89,8 @@
|
||||
"comma": "Comma (,)",
|
||||
"semicolon": "Semicolon (;)",
|
||||
"both": "Both (,) and (;)"
|
||||
}
|
||||
},
|
||||
"fileEncoding": "File Encoding"
|
||||
},
|
||||
"help": {
|
||||
"click": "chọn tập tin hoặc thư mục",
|
||||
@@ -231,6 +234,7 @@
|
||||
"permissions": "Quyền",
|
||||
"permissionsHelp": "Bạn có thể đặt người dùng làm quản trị viên hoặc chọn quyền riêng lẻ. Nếu chọn \"Người quản trị\", tất cả các tùy chọn khác sẽ tự động được chọn. Việc quản lý người dùng vẫn là đặc quyền của quản trị viên.\n",
|
||||
"profileSettings": "Cài đặt hồ sơ",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "ngăn truy cập vào bất kỳ tệp ẩn nào (chẳng hạn như .git, .gitignore) trong mọi thư mục.\n",
|
||||
"ruleExample2": "chặn truy cập vào tệp có tên Caddyfile trong thư mục gốc của phạm vi.",
|
||||
"rules": "Quy tắc",
|
||||
@@ -257,7 +261,8 @@
|
||||
"userManagement": "Quản lý người dùng",
|
||||
"userUpdated": "Người dùng đã được cập nhật!",
|
||||
"username": "Tên người dùng",
|
||||
"users": "Người dùng"
|
||||
"users": "Người dùng",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "Trợ giúp",
|
||||
|
||||
@@ -42,7 +42,9 @@
|
||||
"update": "更新",
|
||||
"upload": "上传",
|
||||
"openFile": "打开文件",
|
||||
"openDirect": "View raw",
|
||||
"discardChanges": "放弃更改",
|
||||
"stopSearch": "停止搜索",
|
||||
"saveChanges": "保存更改",
|
||||
"editAsText": "以文本形式编辑",
|
||||
"increaseFontSize": "增大字体大小",
|
||||
@@ -82,12 +84,13 @@
|
||||
"csvTooLarge": "CSV文件大到无法预览(>5MB)。请下载查看。",
|
||||
"csvLoadFailed": "加载 CSV 文件失败。",
|
||||
"showingRows": "正在显示 {count} 行",
|
||||
"columnSeparator": "Column Separator",
|
||||
"columnSeparator": "列分隔符",
|
||||
"csvSeparators": {
|
||||
"comma": "Comma (,)",
|
||||
"semicolon": "Semicolon (;)",
|
||||
"both": "Both (,) and (;)"
|
||||
}
|
||||
"comma": "逗号 (,)",
|
||||
"semicolon": "分号 (;)",
|
||||
"both": "逗号 (,) 和分号 (;)"
|
||||
},
|
||||
"fileEncoding": "File Encoding"
|
||||
},
|
||||
"help": {
|
||||
"click": "选择文件或文件夹",
|
||||
@@ -116,7 +119,7 @@
|
||||
"wrongCredentials": "用户名或密码错误",
|
||||
"passwordTooShort": "密码必须至少包含 {min} 个字符",
|
||||
"logout_reasons": {
|
||||
"inactivity": "由于未活动,您已登出。"
|
||||
"inactivity": "由于未活动,您已登出。"
|
||||
}
|
||||
},
|
||||
"permanent": "永久",
|
||||
@@ -171,7 +174,7 @@
|
||||
"video": "视频"
|
||||
},
|
||||
"settings": {
|
||||
"aceEditorTheme": "Ace editor 主题",
|
||||
"aceEditorTheme": "Ace编辑器主题",
|
||||
"admin": "管理员",
|
||||
"administrator": "管理员",
|
||||
"allowCommands": "执行命令(Shell 命令)",
|
||||
@@ -231,6 +234,7 @@
|
||||
"permissions": "权限",
|
||||
"permissionsHelp": "你可以将该用户设置为管理员或单独选择各项权限。如果你选择了“管理员”,则其他的选项会被自动选中,同时该用户可以管理其他用户。\n",
|
||||
"profileSettings": "个人设置",
|
||||
"redirectAfterCopyMove": "复制/移动后转到目标位置",
|
||||
"ruleExample1": "阻止用户访问所有文件夹下任何以 . 开头的文件(隐藏文件, 例如: .git, .gitignore)。\n",
|
||||
"ruleExample2": "阻止用户访问其目录范围的根目录下名为 Caddyfile 的文件。",
|
||||
"rules": "规则",
|
||||
@@ -257,7 +261,8 @@
|
||||
"userManagement": "用户管理",
|
||||
"userUpdated": "用户已更新!",
|
||||
"username": "用户名",
|
||||
"users": "用户"
|
||||
"users": "用户",
|
||||
"currentPassword": "您当前的密码"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "帮助",
|
||||
|
||||
@@ -42,7 +42,9 @@
|
||||
"update": "更新",
|
||||
"upload": "上傳",
|
||||
"openFile": "開啟檔案",
|
||||
"openDirect": "View raw",
|
||||
"discardChanges": "放棄變更",
|
||||
"stopSearch": "Stop searching",
|
||||
"saveChanges": "Save changes",
|
||||
"editAsText": "Edit as Text",
|
||||
"increaseFontSize": "Increase font size",
|
||||
@@ -87,7 +89,8 @@
|
||||
"comma": "Comma (,)",
|
||||
"semicolon": "Semicolon (;)",
|
||||
"both": "Both (,) and (;)"
|
||||
}
|
||||
},
|
||||
"fileEncoding": "File Encoding"
|
||||
},
|
||||
"help": {
|
||||
"click": "選擇檔案或目錄",
|
||||
@@ -231,6 +234,7 @@
|
||||
"permissions": "權限",
|
||||
"permissionsHelp": "您可以將該使用者設置為管理員,也可以單獨選擇各項權限。如果選擇了“管理員”,則其他的選項會被自動勾上,同時該使用者可以管理其他使用者。",
|
||||
"profileSettings": "個人設定",
|
||||
"redirectAfterCopyMove": "Redirect to destination after copy/move",
|
||||
"ruleExample1": "封鎖使用者存取所有資料夾下任何以 . 開頭的檔案(隱藏文件, 例如: .git, .gitignore)。",
|
||||
"ruleExample2": "封鎖使用者存取其目錄範圍的根目錄下名為 Caddyfile 的檔案。",
|
||||
"rules": "規則",
|
||||
@@ -257,7 +261,8 @@
|
||||
"userManagement": "使用者管理",
|
||||
"userUpdated": "使用者已更新!",
|
||||
"username": "使用者名稱",
|
||||
"users": "使用者"
|
||||
"users": "使用者",
|
||||
"currentPassword": "Your Current Password"
|
||||
},
|
||||
"sidebar": {
|
||||
"help": "幫助",
|
||||
|
||||
Vendored
+6
@@ -21,6 +21,7 @@ interface Resource extends ResourceBase {
|
||||
index: number;
|
||||
subtitles?: string[];
|
||||
content?: string;
|
||||
rawContent?: ArrayBuffer;
|
||||
}
|
||||
|
||||
interface ResourceItem extends ResourceBase {
|
||||
@@ -57,3 +58,8 @@ interface BreadCrumb {
|
||||
name: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
interface CsvData {
|
||||
headers: string[];
|
||||
rows: string[][];
|
||||
}
|
||||
|
||||
Vendored
+2
@@ -5,6 +5,7 @@ interface ISettings {
|
||||
minimumPasswordLength: number;
|
||||
userHomeBasePath: string;
|
||||
defaults: SettingsDefaults;
|
||||
authMethod: string;
|
||||
rules: any[];
|
||||
branding: SettingsBranding;
|
||||
tus: SettingsTus;
|
||||
@@ -17,6 +18,7 @@ interface SettingsDefaults {
|
||||
locale: string;
|
||||
viewMode: ViewModeType;
|
||||
singleClick: boolean;
|
||||
redirectAfterCopyMove: boolean;
|
||||
sorting: Sorting;
|
||||
perm: Permissions;
|
||||
commands: any[];
|
||||
|
||||
Vendored
+2
@@ -10,6 +10,7 @@ interface IUser {
|
||||
lockPassword: boolean;
|
||||
hideDotfiles: boolean;
|
||||
singleClick: boolean;
|
||||
redirectAfterCopyMove: boolean;
|
||||
dateFormat: boolean;
|
||||
viewMode: ViewModeType;
|
||||
sorting?: Sorting;
|
||||
@@ -30,6 +31,7 @@ interface IUserForm {
|
||||
lockPassword?: boolean;
|
||||
hideDotfiles?: boolean;
|
||||
singleClick?: boolean;
|
||||
redirectAfterCopyMove?: boolean;
|
||||
dateFormat?: boolean;
|
||||
}
|
||||
|
||||
|
||||
@@ -51,6 +51,20 @@ export function copy(data: ClipboardArgs, opts?: ClipboardOpts) {
|
||||
});
|
||||
}
|
||||
|
||||
export function read() {
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
if (
|
||||
// Clipboard API requires secure context
|
||||
window.isSecureContext &&
|
||||
typeof navigator.clipboard !== "undefined"
|
||||
) {
|
||||
navigator.clipboard.readText().then(resolve).catch(reject);
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getPermission(name: string) {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
typeof navigator.permissions !== "undefined" &&
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
export interface CsvData {
|
||||
headers: string[];
|
||||
rows: string[][];
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse CSV content into headers and rows
|
||||
* Supports quoted fields and handles commas within quotes
|
||||
*/
|
||||
export function parseCSV(
|
||||
content: string,
|
||||
columnSeparator: Array<string>
|
||||
): CsvData {
|
||||
if (!content || content.trim().length === 0) {
|
||||
return { headers: [], rows: [] };
|
||||
}
|
||||
|
||||
const lines = content.split(/\r?\n/);
|
||||
const result: string[][] = [];
|
||||
|
||||
for (const line of lines) {
|
||||
if (line.trim().length === 0) continue;
|
||||
|
||||
const row: string[] = [];
|
||||
let currentField = "";
|
||||
let inQuotes = false;
|
||||
|
||||
for (let i = 0; i < line.length; i++) {
|
||||
const char = line[i];
|
||||
const nextChar = line[i + 1];
|
||||
|
||||
if (char === '"') {
|
||||
if (inQuotes && nextChar === '"') {
|
||||
// Escaped quote
|
||||
currentField += '"';
|
||||
i++; // Skip next quote
|
||||
} else {
|
||||
// Toggle quote state
|
||||
inQuotes = !inQuotes;
|
||||
}
|
||||
} else if (columnSeparator.includes(char) && !inQuotes) {
|
||||
// Field separator
|
||||
row.push(currentField);
|
||||
currentField = "";
|
||||
} else {
|
||||
currentField += char;
|
||||
}
|
||||
}
|
||||
|
||||
// Add the last field
|
||||
row.push(currentField);
|
||||
result.push(row);
|
||||
}
|
||||
|
||||
if (result.length === 0) {
|
||||
return { headers: [], rows: [] };
|
||||
}
|
||||
|
||||
// First row is headers
|
||||
const headers = result[0];
|
||||
const rows = result.slice(1);
|
||||
|
||||
return { headers, rows };
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
export const availableEncodings = [
|
||||
"utf-8",
|
||||
"ibm866",
|
||||
"iso-8859-2",
|
||||
"iso-8859-3",
|
||||
"iso-8859-4",
|
||||
"iso-8859-5",
|
||||
"iso-8859-6",
|
||||
"iso-8859-7",
|
||||
"iso-8859-8",
|
||||
"iso-8859-8-i",
|
||||
"iso-8859-10",
|
||||
"iso-8859-13",
|
||||
"iso-8859-14",
|
||||
"iso-8859-15",
|
||||
"iso-8859-16",
|
||||
"koi8-r",
|
||||
"koi8-u",
|
||||
"macintosh",
|
||||
"windows-874",
|
||||
"windows-1250",
|
||||
"windows-1251",
|
||||
"windows-1252",
|
||||
"windows-1253",
|
||||
"windows-1254",
|
||||
"windows-1255",
|
||||
"windows-1256",
|
||||
"windows-1257",
|
||||
"windows-1258",
|
||||
"x-mac-cyrillic",
|
||||
"gbk",
|
||||
"gb18030",
|
||||
"big5",
|
||||
"euc-jp",
|
||||
"iso-2022-jp",
|
||||
"shift_jis",
|
||||
"euc-kr",
|
||||
"utf-16be",
|
||||
"utf-16le",
|
||||
];
|
||||
|
||||
export function decode(content: ArrayBuffer, encoding: string): string {
|
||||
const decoder = new TextDecoder(encoding);
|
||||
return decoder.decode(content);
|
||||
}
|
||||
|
||||
export function isEncodableResponse(url: string): boolean {
|
||||
const extensions = [".csv"];
|
||||
|
||||
if (typeof TextDecoder === "undefined") {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const extension of extensions) {
|
||||
if (url.endsWith(extension)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export async function makeRawResource(
|
||||
res: Response,
|
||||
url: string
|
||||
): Promise<Resource> {
|
||||
const buffer = await res.arrayBuffer();
|
||||
return {
|
||||
items: [],
|
||||
numDirs: 0,
|
||||
numFiles: 0,
|
||||
sorting: {} as Sorting,
|
||||
index: 0,
|
||||
extension: getExtension(url),
|
||||
isDir: false,
|
||||
isSymlink: false,
|
||||
path: url,
|
||||
size: buffer.byteLength,
|
||||
modified: new Date().toISOString(),
|
||||
name: url.split("/").pop() || "",
|
||||
type: "text",
|
||||
mode: 0,
|
||||
url: `/files${url}`,
|
||||
rawContent: buffer,
|
||||
content: decode(buffer, "utf-8"),
|
||||
};
|
||||
}
|
||||
|
||||
function getExtension(url: string): string {
|
||||
const lastDotIndex = url.lastIndexOf(".");
|
||||
if (lastDotIndex === -1) {
|
||||
return "";
|
||||
}
|
||||
return url.substring(lastDotIndex);
|
||||
}
|
||||
@@ -41,7 +41,30 @@
|
||||
</div>
|
||||
</div>
|
||||
<template v-else>
|
||||
<Breadcrumbs base="/files" noLink />
|
||||
<div class="editor-header">
|
||||
<Breadcrumbs base="/files" noLink />
|
||||
|
||||
<div>
|
||||
<button
|
||||
:disabled="isSelectionEmpty"
|
||||
@click="executeEditorCommand('copy')"
|
||||
>
|
||||
<span><i class="material-icons">content_copy</i></span>
|
||||
</button>
|
||||
<button
|
||||
:disabled="isSelectionEmpty"
|
||||
@click="executeEditorCommand('cut')"
|
||||
>
|
||||
<span><i class="material-icons">content_cut</i></span>
|
||||
</button>
|
||||
<button @click="executeEditorCommand('paste')">
|
||||
<span><i class="material-icons">content_paste</i></span>
|
||||
</button>
|
||||
<button @click="executeEditorCommand('openCommandPalette')">
|
||||
<span><i class="material-icons">more_vert</i></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-show="isPreview && isMarkdownFile"
|
||||
@@ -71,9 +94,11 @@ import { useFileStore } from "@/stores/file";
|
||||
import { useLayoutStore } from "@/stores/layout";
|
||||
import { getEditorTheme } from "@/utils/theme";
|
||||
import { marked } from "marked";
|
||||
import markedKatex from "marked-katex-extension";
|
||||
import { inject, onBeforeUnmount, onMounted, ref, watchEffect } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { onBeforeRouteUpdate, useRoute, useRouter } from "vue-router";
|
||||
import { read, copy } from "@/utils/clipboard";
|
||||
|
||||
const $showError = inject<IToastError>("$showError")!;
|
||||
|
||||
@@ -94,6 +119,40 @@ const previewContent = ref("");
|
||||
const isMarkdownFile =
|
||||
fileStore.req?.name.endsWith(".md") ||
|
||||
fileStore.req?.name.endsWith(".markdown");
|
||||
const katexOptions = {
|
||||
output: "mathml" as const,
|
||||
throwOnError: false
|
||||
};
|
||||
marked.use(markedKatex(katexOptions));
|
||||
|
||||
const isSelectionEmpty = ref(true);
|
||||
|
||||
const executeEditorCommand = (name: string) => {
|
||||
if (name == "paste") {
|
||||
read()
|
||||
.then((data) => {
|
||||
editor.value?.execCommand("paste", {
|
||||
text: data,
|
||||
});
|
||||
})
|
||||
.catch((e) => {
|
||||
if (
|
||||
document.queryCommandSupported &&
|
||||
document.queryCommandSupported("paste")
|
||||
) {
|
||||
document.execCommand("paste");
|
||||
} else {
|
||||
console.warn("the clipboard api is not supported", e);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (name == "copy" || name == "cut") {
|
||||
const selectedText = editor.value?.getCopyText();
|
||||
copy({ text: selectedText });
|
||||
}
|
||||
editor.value?.execCommand(name);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
window.addEventListener("keydown", keyEvent);
|
||||
@@ -118,20 +177,19 @@ onMounted(() => {
|
||||
`https://cdn.jsdelivr.net/npm/ace-builds@${ace_version}/src-min-noconflict/`
|
||||
);
|
||||
|
||||
editor.value = ace.edit("editor", {
|
||||
value: fileContent,
|
||||
showPrintMargin: false,
|
||||
readOnly: fileStore.req?.type === "textImmutable",
|
||||
theme: getEditorTheme(authStore.user?.aceEditorTheme ?? ""),
|
||||
mode: modelist.getModeForPath(fileStore.req!.name).mode,
|
||||
wrap: true,
|
||||
enableBasicAutocompletion: true,
|
||||
enableLiveAutocompletion: true,
|
||||
enableSnippets: true,
|
||||
});
|
||||
|
||||
editor.value.setFontSize(fontSize.value);
|
||||
editor.value.focus();
|
||||
if (!layoutStore.loading) {
|
||||
initEditor(fileContent);
|
||||
} else {
|
||||
const unwatch = watchEffect(() => {
|
||||
// Initialize editor when layout is loaded
|
||||
if (!layoutStore.loading) {
|
||||
setTimeout(() => {
|
||||
initEditor(fileContent);
|
||||
unwatch();
|
||||
}, 50);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
@@ -160,6 +218,23 @@ onBeforeRouteUpdate((to, from, next) => {
|
||||
});
|
||||
});
|
||||
|
||||
const initEditor = (fileContent: string) => {
|
||||
editor.value = ace.edit("editor", {
|
||||
value: fileContent,
|
||||
showPrintMargin: false,
|
||||
readOnly: fileStore.req?.type === "textImmutable",
|
||||
theme: getEditorTheme(authStore.user?.aceEditorTheme ?? ""),
|
||||
mode: modelist.getModeForPath(fileStore.req!.name).mode,
|
||||
wrap: true,
|
||||
enableBasicAutocompletion: true,
|
||||
enableLiveAutocompletion: true,
|
||||
enableSnippets: true,
|
||||
});
|
||||
|
||||
editor.value.setFontSize(fontSize.value);
|
||||
editor.value.focus();
|
||||
};
|
||||
|
||||
const keyEvent = (event: KeyboardEvent) => {
|
||||
if (event.code === "Escape") {
|
||||
close();
|
||||
@@ -236,7 +311,6 @@ const close = () => {
|
||||
};
|
||||
|
||||
const finishClose = () => {
|
||||
fileStore.updateRequest(null);
|
||||
const uri = url.removeLastDir(route.path) + "/";
|
||||
router.push({ path: uri });
|
||||
};
|
||||
@@ -251,4 +325,32 @@ const preview = () => {
|
||||
margin: 0 0.5em;
|
||||
color: var(--fg);
|
||||
}
|
||||
|
||||
.editor-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.editor-header > div > button {
|
||||
background: transparent;
|
||||
color: var(--action);
|
||||
border: none;
|
||||
outline: none;
|
||||
opacity: 0.8;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.editor-header > div > button:hover:not(:disabled) {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.editor-header > div > button:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.editor-header > div > button > span > i {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -81,7 +81,13 @@
|
||||
</template>
|
||||
</header-bar>
|
||||
|
||||
<div v-if="isMobile" id="file-selection">
|
||||
<div
|
||||
v-if="isMobile"
|
||||
id="file-selection"
|
||||
:class="{
|
||||
'file-selection-margin-bottom': fileStore.multiple,
|
||||
}"
|
||||
>
|
||||
<span v-if="fileStore.selectedCount > 0">
|
||||
{{ t("prompts.filesSelected", fileStore.selectedCount) }}
|
||||
</span>
|
||||
@@ -158,7 +164,9 @@
|
||||
id="listing"
|
||||
ref="listing"
|
||||
class="file-icons"
|
||||
data-clear-on-click="true"
|
||||
:class="authStore.user?.viewMode ?? ''"
|
||||
@click="handleEmptyAreaClick"
|
||||
>
|
||||
<div>
|
||||
<div class="item header">
|
||||
@@ -204,11 +212,12 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2 v-if="fileStore.req?.numDirs ?? false">
|
||||
<h2 data-clear-on-click="true" v-if="fileStore.req?.numDirs ?? false">
|
||||
{{ t("files.folders") }}
|
||||
</h2>
|
||||
<div
|
||||
v-if="fileStore.req?.numDirs ?? false"
|
||||
data-clear-on-click="true"
|
||||
@contextmenu="showContextMenu"
|
||||
>
|
||||
<item
|
||||
@@ -226,11 +235,12 @@
|
||||
</item>
|
||||
</div>
|
||||
|
||||
<h2 v-if="fileStore.req?.numFiles ?? false">
|
||||
<h2 data-clear-on-click="true" v-if="fileStore.req?.numFiles ?? false">
|
||||
{{ t("files.files") }}
|
||||
</h2>
|
||||
<div
|
||||
v-if="fileStore.req?.numFiles ?? false"
|
||||
data-clear-on-click="true"
|
||||
@contextmenu="showContextMenu"
|
||||
>
|
||||
<item
|
||||
@@ -1051,4 +1061,22 @@ const showContextMenu = (event: MouseEvent) => {
|
||||
const hideContextMenu = () => {
|
||||
isContextMenuVisible.value = false;
|
||||
};
|
||||
|
||||
const handleEmptyAreaClick = (e: MouseEvent) => {
|
||||
const target = e.target;
|
||||
if (!(target instanceof HTMLElement)) return;
|
||||
|
||||
if (target.dataset.clearOnClick === "true") {
|
||||
fileStore.selected = [];
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
#listing {
|
||||
min-height: calc(100vh - 8rem);
|
||||
}
|
||||
|
||||
.file-selection-margin-bottom {
|
||||
margin-bottom: 3.5rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -46,6 +46,16 @@
|
||||
:label="$t('buttons.download')"
|
||||
@action="download"
|
||||
/>
|
||||
<action
|
||||
:disabled="layoutStore.loading"
|
||||
v-if="
|
||||
['image', 'audio', 'video'].includes(fileStore.req?.type || '') &&
|
||||
authStore.user?.perm.download
|
||||
"
|
||||
icon="open_in_new"
|
||||
:label="t('buttons.openDirect')"
|
||||
@action="openDirect"
|
||||
/>
|
||||
<action
|
||||
:disabled="layoutStore.loading"
|
||||
icon="info"
|
||||
@@ -253,7 +263,7 @@ const hoverNav = ref<boolean>(false);
|
||||
const autoPlay = ref<boolean>(false);
|
||||
const previousRaw = ref<string>("");
|
||||
const nextRaw = ref<string>("");
|
||||
const csvContent = ref<string>("");
|
||||
const csvContent = ref<ArrayBuffer | string>("");
|
||||
const csvError = ref<string>("");
|
||||
|
||||
const player = ref<HTMLVideoElement | HTMLAudioElement | null>(null);
|
||||
@@ -277,6 +287,10 @@ const downloadUrl = computed(() =>
|
||||
fileStore.req ? api.getDownloadURL(fileStore.req, false) : ""
|
||||
);
|
||||
|
||||
const directUrl = computed(() =>
|
||||
fileStore.req ? api.getDownloadURL(fileStore.req, true) : ""
|
||||
);
|
||||
|
||||
const previewUrl = computed(() => {
|
||||
if (!fileStore.req) {
|
||||
return "";
|
||||
@@ -393,7 +407,11 @@ const updatePreview = async () => {
|
||||
if (fileStore.req.size > CSV_MAX_SIZE) {
|
||||
csvError.value = t("files.csvTooLarge");
|
||||
} else {
|
||||
csvContent.value = fileStore.req.content ?? "";
|
||||
if (fileStore.req.rawContent != null) {
|
||||
csvContent.value = fileStore.req.rawContent;
|
||||
} else {
|
||||
csvContent.value = fileStore.req.content ?? "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -466,6 +484,7 @@ const close = () => {
|
||||
};
|
||||
|
||||
const download = () => window.open(downloadUrl.value);
|
||||
const openDirect = () => window.open(directUrl.value);
|
||||
|
||||
const editAsText = () => {
|
||||
router.push({ path: route.path, query: { edit: "true" } });
|
||||
|
||||
@@ -15,6 +15,14 @@
|
||||
<input type="checkbox" name="singleClick" v-model="singleClick" />
|
||||
{{ t("settings.singleClick") }}
|
||||
</p>
|
||||
<p>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="redirectAfterCopyMove"
|
||||
v-model="redirectAfterCopyMove"
|
||||
/>
|
||||
{{ t("settings.redirectAfterCopyMove") }}
|
||||
</p>
|
||||
<p>
|
||||
<input type="checkbox" name="dateFormat" v-model="dateFormat" />
|
||||
{{ t("settings.setDateFormat") }}
|
||||
@@ -44,7 +52,7 @@
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="column">
|
||||
<div v-if="!noAuth" class="column">
|
||||
<form
|
||||
class="card"
|
||||
v-if="!authStore.user?.lockPassword"
|
||||
@@ -69,6 +77,15 @@
|
||||
v-model="passwordConf"
|
||||
name="passwordConf"
|
||||
/>
|
||||
<input
|
||||
v-if="isCurrentPasswordRequired"
|
||||
:class="passwordClass"
|
||||
type="password"
|
||||
:placeholder="t('settings.currentPassword')"
|
||||
v-model="currentPassword"
|
||||
name="current_password"
|
||||
autocomplete="current-password"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="card-action">
|
||||
@@ -92,6 +109,7 @@ import AceEditorTheme from "@/components/settings/AceEditorTheme.vue";
|
||||
import Languages from "@/components/settings/Languages.vue";
|
||||
import { computed, inject, onMounted, ref } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { authMethod, noAuth } from "@/utils/constants";
|
||||
|
||||
const layoutStore = useLayoutStore();
|
||||
const authStore = useAuthStore();
|
||||
@@ -102,8 +120,11 @@ const $showError = inject<IToastError>("$showError")!;
|
||||
|
||||
const password = ref<string>("");
|
||||
const passwordConf = ref<string>("");
|
||||
const currentPassword = ref<string>("");
|
||||
const isCurrentPasswordRequired = ref<boolean>(false);
|
||||
const hideDotfiles = ref<boolean>(false);
|
||||
const singleClick = ref<boolean>(false);
|
||||
const redirectAfterCopyMove = ref<boolean>(false);
|
||||
const dateFormat = ref<boolean>(false);
|
||||
const locale = ref<string>("");
|
||||
const aceEditorTheme = ref<string>("");
|
||||
@@ -128,9 +149,12 @@ onMounted(async () => {
|
||||
locale.value = authStore.user.locale;
|
||||
hideDotfiles.value = authStore.user.hideDotfiles;
|
||||
singleClick.value = authStore.user.singleClick;
|
||||
redirectAfterCopyMove.value = authStore.user.redirectAfterCopyMove;
|
||||
dateFormat.value = authStore.user.dateFormat;
|
||||
aceEditorTheme.value = authStore.user.aceEditorTheme;
|
||||
layoutStore.loading = false;
|
||||
isCurrentPasswordRequired.value = authMethod == "json";
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
@@ -140,6 +164,7 @@ const updatePassword = async (event: Event) => {
|
||||
if (
|
||||
password.value !== passwordConf.value ||
|
||||
password.value === "" ||
|
||||
currentPassword.value === "" ||
|
||||
authStore.user === null
|
||||
) {
|
||||
return;
|
||||
@@ -151,7 +176,7 @@ const updatePassword = async (event: Event) => {
|
||||
id: authStore.user.id,
|
||||
password: password.value,
|
||||
};
|
||||
await api.update(data, ["password"]);
|
||||
await api.update(data, ["password"], currentPassword.value);
|
||||
authStore.updateUser(data);
|
||||
$showSuccess(t("settings.passwordUpdated"));
|
||||
} catch (e: any) {
|
||||
@@ -172,6 +197,7 @@ const updateSettings = async (event: Event) => {
|
||||
locale: locale.value,
|
||||
hideDotfiles: hideDotfiles.value,
|
||||
singleClick: singleClick.value,
|
||||
redirectAfterCopyMove: redirectAfterCopyMove.value,
|
||||
dateFormat: dateFormat.value,
|
||||
aceEditorTheme: aceEditorTheme.value,
|
||||
};
|
||||
@@ -180,6 +206,7 @@ const updateSettings = async (event: Event) => {
|
||||
"locale",
|
||||
"hideDotfiles",
|
||||
"singleClick",
|
||||
"redirectAfterCopyMove",
|
||||
"dateFormat",
|
||||
"aceEditorTheme",
|
||||
]);
|
||||
|
||||
@@ -15,6 +15,19 @@
|
||||
:isDefault="false"
|
||||
:isNew="isNew"
|
||||
/>
|
||||
|
||||
<p v-if="isCurrentPasswordRequired">
|
||||
<label for="currentPassword">{{
|
||||
t("settings.currentPassword")
|
||||
}}</label>
|
||||
<input
|
||||
class="input input--block"
|
||||
type="password"
|
||||
v-model="currentPassword"
|
||||
id="currentPassword"
|
||||
autocomplete="current-password"
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="card-action">
|
||||
@@ -58,11 +71,14 @@ import { computed, inject, onMounted, ref, watch } from "vue";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { StatusError } from "@/api/utils";
|
||||
import { authMethod } from "@/utils/constants";
|
||||
|
||||
const error = ref<StatusError>();
|
||||
const originalUser = ref<IUser>();
|
||||
const user = ref<IUser>();
|
||||
const createUserDir = ref<boolean>(false);
|
||||
const currentPassword = ref<string>("");
|
||||
const isCurrentPasswordRequired = ref<boolean>(false);
|
||||
|
||||
const $showError = inject<IToastError>("$showError")!;
|
||||
const $showSuccess = inject<IToastSuccess>("$showSuccess")!;
|
||||
@@ -91,6 +107,7 @@ const fetchData = async () => {
|
||||
try {
|
||||
if (isNew.value) {
|
||||
const { defaults, createUserDir: _createUserDir } = await settings.get();
|
||||
isCurrentPasswordRequired.value = authMethod == "json";
|
||||
createUserDir.value = _createUserDir;
|
||||
user.value = {
|
||||
...defaults,
|
||||
@@ -101,6 +118,8 @@ const fetchData = async () => {
|
||||
id: 0,
|
||||
};
|
||||
} else {
|
||||
const { authMethod } = await settings.get();
|
||||
isCurrentPasswordRequired.value = authMethod == "json";
|
||||
const id = Array.isArray(route.params.id)
|
||||
? route.params.id.join("")
|
||||
: route.params.id;
|
||||
@@ -124,7 +143,7 @@ const deleteUser = async (e: Event) => {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
await api.remove(user.value.id);
|
||||
await api.remove(user.value.id, currentPassword.value);
|
||||
router.push({ path: "/settings/users" });
|
||||
$showSuccess(t("settings.userDeleted"));
|
||||
} catch (err) {
|
||||
@@ -151,11 +170,11 @@ const save = async (event: Event) => {
|
||||
...user.value,
|
||||
};
|
||||
|
||||
const loc = await api.create(newUser);
|
||||
const loc = await api.create(newUser, currentPassword.value);
|
||||
router.push({ path: loc || "/settings/users" });
|
||||
$showSuccess(t("settings.userCreated"));
|
||||
} else {
|
||||
await api.update(user.value);
|
||||
await api.update(user.value, ["all"], currentPassword.value);
|
||||
|
||||
if (user.value.id === authStore.user?.id) {
|
||||
authStore.updateUser(user.value);
|
||||
|
||||
@@ -8,25 +8,26 @@ require (
|
||||
github.com/disintegration/imaging v1.6.2
|
||||
github.com/dsoprea/go-exif/v3 v3.0.1
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0
|
||||
github.com/golang-jwt/jwt/v5 v5.3.1
|
||||
github.com/gorilla/mux v1.8.1
|
||||
github.com/gorilla/websocket v1.5.3
|
||||
github.com/jellydator/ttlcache/v3 v3.4.0
|
||||
github.com/maruel/natural v1.2.1
|
||||
github.com/maruel/natural v1.3.0
|
||||
github.com/marusama/semaphore/v2 v2.5.0
|
||||
github.com/mholt/archives v0.1.5
|
||||
github.com/mitchellh/go-homedir v1.1.0
|
||||
github.com/redis/go-redis/v9 v9.17.3
|
||||
github.com/samber/lo v1.52.0
|
||||
github.com/shirou/gopsutil/v4 v4.25.11
|
||||
github.com/shirou/gopsutil/v4 v4.26.1
|
||||
github.com/spf13/afero v1.15.0
|
||||
github.com/spf13/cobra v1.10.2
|
||||
github.com/spf13/pflag v1.0.10
|
||||
github.com/spf13/viper v1.21.0
|
||||
github.com/stretchr/testify v1.11.1
|
||||
github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce
|
||||
golang.org/x/crypto v0.46.0
|
||||
golang.org/x/image v0.34.0
|
||||
golang.org/x/text v0.32.0
|
||||
golang.org/x/crypto v0.48.0
|
||||
golang.org/x/image v0.36.0
|
||||
golang.org/x/text v0.34.0
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
@@ -39,8 +40,10 @@ require (
|
||||
github.com/bodgit/plumbing v1.3.0 // indirect
|
||||
github.com/bodgit/sevenzip v1.6.1 // indirect
|
||||
github.com/bodgit/windows v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 // indirect
|
||||
github.com/dsoprea/go-logging v0.0.0-20200710184922-b02d349568dd // indirect
|
||||
github.com/dsoprea/go-utility/v2 v2.0.0-20221003172846-a3e1774ef349 // indirect
|
||||
@@ -73,9 +76,9 @@ require (
|
||||
go.etcd.io/bbolt v1.4.3 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
go4.org v0.0.0-20230225012048-214862532bf5 // indirect
|
||||
golang.org/x/net v0.47.0 // indirect
|
||||
golang.org/x/net v0.49.0 // indirect
|
||||
golang.org/x/sync v0.19.0 // indirect
|
||||
golang.org/x/sys v0.39.0 // indirect
|
||||
golang.org/x/sys v0.41.0 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
)
|
||||
|
||||
@@ -42,7 +42,13 @@ github.com/bodgit/sevenzip v1.6.1 h1:kikg2pUMYC9ljU7W9SaqHXhym5HyKm8/M/jd31fYan4
|
||||
github.com/bodgit/sevenzip v1.6.1/go.mod h1:GVoYQbEVbOGT8n2pfqCIMRUaRjQ8F9oSqoBEqZh5fQ8=
|
||||
github.com/bodgit/windows v1.0.1 h1:tF7K6KOluPYygXa3Z2594zxlkbKPAOvqr97etrGNIz4=
|
||||
github.com/bodgit/windows v1.0.1/go.mod h1:a6JLwrB4KrTR5hBpp8FI9/9W9jJfeQ2h4XDXU74ZCdM=
|
||||
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
|
||||
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
|
||||
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
|
||||
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
@@ -53,6 +59,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
|
||||
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
|
||||
github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 h1:2tV76y6Q9BB+NEBasnqvs7e49aEBFI8ejC89PSnWH+4=
|
||||
@@ -98,8 +106,8 @@ github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
|
||||
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
|
||||
github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY=
|
||||
github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
|
||||
github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
|
||||
github.com/golang/geo v0.0.0-20200319012246-673a6f80352d/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
|
||||
github.com/golang/geo v0.0.0-20210211234256-740aa86cb551/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
|
||||
@@ -169,8 +177,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/maruel/natural v1.2.1 h1:G/y4pwtTA07lbQsMefvsmEO0VN0NfqpxprxXDM4R/4o=
|
||||
github.com/maruel/natural v1.2.1/go.mod h1:v+Rfd79xlw1AgVBjbO0BEQmptqb5HvL/k9GRHB7ZKEg=
|
||||
github.com/maruel/natural v1.3.0 h1:VsmCsBmEyrR46RomtgHs5hbKADGRVtliHTyCOLFBpsg=
|
||||
github.com/maruel/natural v1.3.0/go.mod h1:v+Rfd79xlw1AgVBjbO0BEQmptqb5HvL/k9GRHB7ZKEg=
|
||||
github.com/marusama/semaphore/v2 v2.5.0 h1:o/1QJD9DBYOWRnDhPwDVAXQn6mQYD0gZaS1Tpx6DJGM=
|
||||
github.com/marusama/semaphore/v2 v2.5.0/go.mod h1:z9nMiNUekt/LTpTUQdpp+4sJeYqUGpwMHfW0Z8V8fnQ=
|
||||
github.com/mholt/archives v0.1.5 h1:Fh2hl1j7VEhc6DZs2DLMgiBNChUux154a1G+2esNvzQ=
|
||||
@@ -194,6 +202,8 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/redis/go-redis/v9 v9.17.3 h1:fN29NdNrE17KttK5Ndf20buqfDZwGNgoUr9qjl1DQx4=
|
||||
github.com/redis/go-redis/v9 v9.17.3/go.mod h1:u410H11HMLoB+TP67dz8rL9s6QW2j76l0//kSOd3370=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
@@ -204,8 +214,8 @@ github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDc
|
||||
github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik=
|
||||
github.com/samber/lo v1.52.0 h1:Rvi+3BFHES3A8meP33VPAxiBZX/Aws5RxrschYGjomw=
|
||||
github.com/samber/lo v1.52.0/go.mod h1:4+MXEGsJzbKGaUEQFKBq2xtfuznW9oz/WrgyzMzRoM0=
|
||||
github.com/shirou/gopsutil/v4 v4.25.11 h1:X53gB7muL9Gnwwo2evPSE+SfOrltMoR6V3xJAXZILTY=
|
||||
github.com/shirou/gopsutil/v4 v4.25.11/go.mod h1:EivAfP5x2EhLp2ovdpKSozecVXn1TmuG7SMzs/Wh4PU=
|
||||
github.com/shirou/gopsutil/v4 v4.26.1 h1:TOkEyriIXk2HX9d4isZJtbjXbEjf5qyKPAzbzY0JWSo=
|
||||
github.com/shirou/gopsutil/v4 v4.26.1/go.mod h1:medLI9/UNAb0dOI9Q3/7yWSqKkj00u+1tgY8nvv41pc=
|
||||
github.com/sorairolake/lzip-go v0.3.8 h1:j5Q2313INdTA80ureWYRhX+1K78mUXfMoPZCw/ivWik=
|
||||
github.com/sorairolake/lzip-go v0.3.8/go.mod h1:JcBqGMV0frlxwrsE9sMWXDjqn3EeVf0/54YPsw66qkU=
|
||||
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw=
|
||||
@@ -266,8 +276,8 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
|
||||
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
|
||||
golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
|
||||
golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@@ -279,8 +289,8 @@ golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EH
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.34.0 h1:33gCkyw9hmwbZJeZkct8XyR11yH889EQt/QH4VmXMn8=
|
||||
golang.org/x/image v0.34.0/go.mod h1:2RNFBZRB+vnwwFil8GkMdRvrJOFd1AzdZI6vOY+eJVU=
|
||||
golang.org/x/image v0.36.0 h1:Iknbfm1afbgtwPTmHnS2gTM/6PPZfH+z2EFuOkSbqwc=
|
||||
golang.org/x/image v0.36.0/go.mod h1:YsWD2TyyGKiIX1kZlu9QfKIsQ4nAAK9bdgdrIsE7xy4=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
@@ -319,8 +329,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
|
||||
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
|
||||
golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o=
|
||||
golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -360,8 +370,8 @@ golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
|
||||
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
|
||||
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
@@ -372,8 +382,8 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
|
||||
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
|
||||
golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=
|
||||
golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
|
||||
+24
-22
@@ -23,17 +23,18 @@ const (
|
||||
)
|
||||
|
||||
type userInfo struct {
|
||||
ID uint `json:"id"`
|
||||
Locale string `json:"locale"`
|
||||
ViewMode users.ViewMode `json:"viewMode"`
|
||||
SingleClick bool `json:"singleClick"`
|
||||
Perm users.Permissions `json:"perm"`
|
||||
Commands []string `json:"commands"`
|
||||
LockPassword bool `json:"lockPassword"`
|
||||
HideDotfiles bool `json:"hideDotfiles"`
|
||||
DateFormat bool `json:"dateFormat"`
|
||||
Username string `json:"username"`
|
||||
AceEditorTheme string `json:"aceEditorTheme"`
|
||||
ID uint `json:"id"`
|
||||
Locale string `json:"locale"`
|
||||
ViewMode users.ViewMode `json:"viewMode"`
|
||||
SingleClick bool `json:"singleClick"`
|
||||
RedirectAfterCopyMove bool `json:"redirectAfterCopyMove"`
|
||||
Perm users.Permissions `json:"perm"`
|
||||
Commands []string `json:"commands"`
|
||||
LockPassword bool `json:"lockPassword"`
|
||||
HideDotfiles bool `json:"hideDotfiles"`
|
||||
DateFormat bool `json:"dateFormat"`
|
||||
Username string `json:"username"`
|
||||
AceEditorTheme string `json:"aceEditorTheme"`
|
||||
}
|
||||
|
||||
type authToken struct {
|
||||
@@ -204,17 +205,18 @@ func renewHandler(tokenExpireTime time.Duration) handleFunc {
|
||||
func printToken(w http.ResponseWriter, _ *http.Request, d *data, user *users.User, tokenExpirationTime time.Duration) (int, error) {
|
||||
claims := &authToken{
|
||||
User: userInfo{
|
||||
ID: user.ID,
|
||||
Locale: user.Locale,
|
||||
ViewMode: user.ViewMode,
|
||||
SingleClick: user.SingleClick,
|
||||
Perm: user.Perm,
|
||||
LockPassword: user.LockPassword,
|
||||
Commands: user.Commands,
|
||||
HideDotfiles: user.HideDotfiles,
|
||||
DateFormat: user.DateFormat,
|
||||
Username: user.Username,
|
||||
AceEditorTheme: user.AceEditorTheme,
|
||||
ID: user.ID,
|
||||
Locale: user.Locale,
|
||||
ViewMode: user.ViewMode,
|
||||
SingleClick: user.SingleClick,
|
||||
RedirectAfterCopyMove: user.RedirectAfterCopyMove,
|
||||
Perm: user.Perm,
|
||||
LockPassword: user.LockPassword,
|
||||
Commands: user.Commands,
|
||||
HideDotfiles: user.HideDotfiles,
|
||||
DateFormat: user.DateFormat,
|
||||
Username: user.Username,
|
||||
AceEditorTheme: user.AceEditorTheme,
|
||||
},
|
||||
RegisteredClaims: jwt.RegisteredClaims{
|
||||
IssuedAt: jwt.NewNumericDate(time.Now()),
|
||||
|
||||
+8
-11
@@ -11,13 +11,15 @@ import (
|
||||
)
|
||||
|
||||
type modifyRequest struct {
|
||||
What string `json:"what"` // Answer to: what data type?
|
||||
Which []string `json:"which"` // Answer to: which fields?
|
||||
What string `json:"what"` // Answer to: what data type?
|
||||
Which []string `json:"which"` // Answer to: which fields?
|
||||
CurrentPassword string `json:"current_password"` // Answer to: user logged password
|
||||
}
|
||||
|
||||
func NewHandler(
|
||||
imgSvc ImgService,
|
||||
fileCache FileCache,
|
||||
uploadCache UploadCache,
|
||||
store *storage.Storage,
|
||||
server *settings.Server,
|
||||
assetsFs fs.FS,
|
||||
@@ -33,11 +35,6 @@ func NewHandler(
|
||||
})
|
||||
index, static := getStaticHandlers(store, server, assetsFs)
|
||||
|
||||
// NOTE: This fixes the issue where it would redirect if people did not put a
|
||||
// trailing slash in the end. I hate this decision since this allows some awful
|
||||
// URLs https://www.gorillatoolkit.org/pkg/mux#Router.SkipClean
|
||||
r = r.SkipClean(true)
|
||||
|
||||
monkey := func(fn handleFunc, prefix string) http.Handler {
|
||||
return handle(fn, prefix, store, server)
|
||||
}
|
||||
@@ -66,10 +63,10 @@ func NewHandler(
|
||||
api.PathPrefix("/resources").Handler(monkey(resourcePutHandler, "/api/resources")).Methods("PUT")
|
||||
api.PathPrefix("/resources").Handler(monkey(resourcePatchHandler(fileCache), "/api/resources")).Methods("PATCH")
|
||||
|
||||
api.PathPrefix("/tus").Handler(monkey(tusPostHandler(), "/api/tus")).Methods("POST")
|
||||
api.PathPrefix("/tus").Handler(monkey(tusHeadHandler(), "/api/tus")).Methods("HEAD", "GET")
|
||||
api.PathPrefix("/tus").Handler(monkey(tusPatchHandler(), "/api/tus")).Methods("PATCH")
|
||||
api.PathPrefix("/tus").Handler(monkey(tusDeleteHandler(), "/api/tus")).Methods("DELETE")
|
||||
api.PathPrefix("/tus").Handler(monkey(tusPostHandler(uploadCache), "/api/tus")).Methods("POST")
|
||||
api.PathPrefix("/tus").Handler(monkey(tusHeadHandler(uploadCache), "/api/tus")).Methods("HEAD", "GET")
|
||||
api.PathPrefix("/tus").Handler(monkey(tusPatchHandler(uploadCache), "/api/tus")).Methods("PATCH")
|
||||
api.PathPrefix("/tus").Handler(monkey(tusDeleteHandler(uploadCache), "/api/tus")).Methods("DELETE")
|
||||
|
||||
api.PathPrefix("/usage").Handler(monkey(diskUsage, "/api/usage")).Methods("GET")
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ var withHashFile = func(fn handleFunc) handleFunc {
|
||||
Modify: d.user.Perm.Modify,
|
||||
Expand: false,
|
||||
ReadHeader: d.server.TypeDetectionByHeader,
|
||||
CalcImgRes: d.server.TypeDetectionByHeader,
|
||||
Checker: d,
|
||||
Token: link.Token,
|
||||
})
|
||||
|
||||
@@ -123,6 +123,7 @@ func getFiles(d *data, path, commonPath string) ([]archives.FileInfo, error) {
|
||||
if path != commonPath {
|
||||
nameInArchive := strings.TrimPrefix(path, commonPath)
|
||||
nameInArchive = strings.TrimPrefix(nameInArchive, string(filepath.Separator))
|
||||
nameInArchive = filepath.ToSlash(nameInArchive)
|
||||
|
||||
archiveFiles = append(archiveFiles, archives.FileInfo{
|
||||
FileInfo: info,
|
||||
|
||||
+45
-13
@@ -36,10 +36,31 @@ var resourceGetHandler = withUser(func(w http.ResponseWriter, r *http.Request, d
|
||||
return errToStatus(err), err
|
||||
}
|
||||
|
||||
encoding := r.Header.Get("X-Encoding")
|
||||
if file.IsDir {
|
||||
file.Sorting = d.user.Sorting
|
||||
file.ApplySort()
|
||||
return renderJSON(w, r, file)
|
||||
} else if encoding == "true" {
|
||||
if file.Type != "text" {
|
||||
return http.StatusUnsupportedMediaType, fmt.Errorf("file is not a text file")
|
||||
}
|
||||
|
||||
f, err := d.user.Fs.Open(r.URL.Path)
|
||||
if err != nil {
|
||||
return errToStatus(err), err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
data, err := io.ReadAll(f)
|
||||
if err != nil {
|
||||
return http.StatusInternalServerError, err
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/octet-stream")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, err = w.Write(data)
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if checksum := r.URL.Query().Get("checksum"); checksum != "" {
|
||||
@@ -206,20 +227,25 @@ func resourcePatchHandler(fileCache FileCache) handleFunc {
|
||||
return http.StatusBadRequest, err
|
||||
}
|
||||
|
||||
override := r.URL.Query().Get("override") == "true"
|
||||
rename := r.URL.Query().Get("rename") == "true"
|
||||
if !override && !rename {
|
||||
if _, err = d.user.Fs.Stat(dst); err == nil {
|
||||
return http.StatusConflict, nil
|
||||
}
|
||||
}
|
||||
if rename {
|
||||
dst = addVersionSuffix(dst, d.user.Fs)
|
||||
}
|
||||
srcInfo, _ := d.user.Fs.Stat(src)
|
||||
dstInfo, _ := d.user.Fs.Stat(dst)
|
||||
same := os.SameFile(srcInfo, dstInfo)
|
||||
|
||||
// Permission for overwriting the file
|
||||
if override && !d.user.Perm.Modify {
|
||||
return http.StatusForbidden, nil
|
||||
if action != "rename" || !same {
|
||||
override := r.URL.Query().Get("override") == "true"
|
||||
rename := r.URL.Query().Get("rename") == "true"
|
||||
if !override && !rename {
|
||||
if _, err = d.user.Fs.Stat(dst); err == nil {
|
||||
return http.StatusConflict, nil
|
||||
}
|
||||
}
|
||||
if rename {
|
||||
dst = addVersionSuffix(dst, d.user.Fs)
|
||||
}
|
||||
|
||||
if override && !d.user.Perm.Modify {
|
||||
return http.StatusForbidden, nil
|
||||
}
|
||||
}
|
||||
|
||||
err = d.RunHook(func() error {
|
||||
@@ -280,6 +306,12 @@ func writeFile(afs afero.Fs, dst string, in io.Reader, fileMode, dirMode fs.File
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Sync the file to ensure all data is written to storage.
|
||||
// to prevent file corruption.
|
||||
if err := file.Sync(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Gets the info about the file.
|
||||
info, err := file.Stat()
|
||||
if err != nil {
|
||||
|
||||
+63
-9
@@ -1,28 +1,82 @@
|
||||
package fbhttp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/filebrowser/filebrowser/v2/search"
|
||||
)
|
||||
|
||||
const searchPingInterval = 5
|
||||
|
||||
var searchHandler = withUser(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
|
||||
response := []map[string]interface{}{}
|
||||
response := make(chan map[string]interface{})
|
||||
ctx, cancel := context.WithCancelCause(r.Context())
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
// Avoid connection timeout
|
||||
timeout := time.NewTimer(searchPingInterval * time.Second)
|
||||
defer timeout.Stop()
|
||||
for {
|
||||
var err error
|
||||
var infoBytes []byte
|
||||
select {
|
||||
case info := <-response:
|
||||
if info == nil {
|
||||
return
|
||||
}
|
||||
infoBytes, err = json.Marshal(info)
|
||||
case <-timeout.C:
|
||||
// Send a heartbeat packet
|
||||
infoBytes = nil
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
cancel(err)
|
||||
return
|
||||
}
|
||||
_, err = w.Write(infoBytes)
|
||||
if err == nil {
|
||||
_, err = w.Write([]byte("\n"))
|
||||
}
|
||||
if err != nil {
|
||||
cancel(err)
|
||||
return
|
||||
}
|
||||
if flusher, ok := w.(http.Flusher); ok {
|
||||
flusher.Flush()
|
||||
}
|
||||
}
|
||||
}()
|
||||
query := r.URL.Query().Get("query")
|
||||
|
||||
err := search.Search(d.user.Fs, r.URL.Path, query, d, func(path string, f os.FileInfo) error {
|
||||
response = append(response, map[string]interface{}{
|
||||
err := search.Search(ctx, d.user.Fs, r.URL.Path, query, d, func(path string, f os.FileInfo) error {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
case response <- map[string]interface{}{
|
||||
"dir": f.IsDir(),
|
||||
"path": path,
|
||||
})
|
||||
|
||||
return nil
|
||||
}:
|
||||
}
|
||||
return context.Cause(ctx)
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
close(response)
|
||||
wg.Wait()
|
||||
if err == nil {
|
||||
err = context.Cause(ctx)
|
||||
}
|
||||
// ignore cancellation errors from user aborts
|
||||
if err != nil && !errors.Is(err, context.Canceled) {
|
||||
return http.StatusInternalServerError, err
|
||||
}
|
||||
|
||||
return renderJSON(w, r, response)
|
||||
return 0, nil
|
||||
})
|
||||
|
||||
@@ -15,6 +15,7 @@ type settingsData struct {
|
||||
MinimumPasswordLength uint `json:"minimumPasswordLength"`
|
||||
UserHomeBasePath string `json:"userHomeBasePath"`
|
||||
Defaults settings.UserDefaults `json:"defaults"`
|
||||
AuthMethod settings.AuthMethod `json:"authMethod"`
|
||||
Rules []rules.Rule `json:"rules"`
|
||||
Branding settings.Branding `json:"branding"`
|
||||
Tus settings.Tus `json:"tus"`
|
||||
@@ -30,6 +31,7 @@ var settingsGetHandler = withAdmin(func(w http.ResponseWriter, r *http.Request,
|
||||
MinimumPasswordLength: d.settings.MinimumPasswordLength,
|
||||
UserHomeBasePath: d.settings.UserHomeBasePath,
|
||||
Defaults: d.settings.Defaults,
|
||||
AuthMethod: d.settings.AuthMethod,
|
||||
Rules: d.settings.Rules,
|
||||
Branding: d.settings.Branding,
|
||||
Tus: d.settings.Tus,
|
||||
|
||||
+23
-5
@@ -5,6 +5,8 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"io"
|
||||
"compress/gzip"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -144,16 +146,32 @@ func getStaticHandlers(store *storage.Storage, server *settings.Server, assetsFs
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
fileContents, err := fs.ReadFile(assetsFs, r.URL.Path+".gz")
|
||||
f, err := assetsFs.Open(r.URL.Path + ".gz")
|
||||
if err != nil {
|
||||
return http.StatusNotFound, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
w.Header().Set("Content-Encoding", "gzip")
|
||||
w.Header().Set("Content-Type", "application/javascript; charset=utf-8")
|
||||
acceptEncoding := r.Header.Get("Accept-Encoding")
|
||||
if strings.Contains(acceptEncoding, "gzip") {
|
||||
w.Header().Set("Content-Encoding", "gzip")
|
||||
w.Header().Set("Content-Type", "application/javascript; charset=utf-8")
|
||||
|
||||
if _, err := w.Write(fileContents); err != nil {
|
||||
return http.StatusInternalServerError, err
|
||||
if _, err := io.Copy(w, f); err != nil {
|
||||
return http.StatusInternalServerError, err
|
||||
}
|
||||
} else {
|
||||
gzReader, err := gzip.NewReader(f)
|
||||
if err != nil {
|
||||
return http.StatusInternalServerError, err
|
||||
}
|
||||
defer gzReader.Close()
|
||||
|
||||
w.Header().Set("Content-Type", "application/javascript; charset=utf-8")
|
||||
|
||||
if _, err := io.Copy(w, gzReader); err != nil {
|
||||
return http.StatusInternalServerError, err
|
||||
}
|
||||
}
|
||||
|
||||
return 0, nil
|
||||
|
||||
+20
-50
@@ -1,7 +1,6 @@
|
||||
package fbhttp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -12,48 +11,13 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/jellydator/ttlcache/v3"
|
||||
"github.com/spf13/afero"
|
||||
|
||||
"github.com/filebrowser/filebrowser/v2/files"
|
||||
)
|
||||
|
||||
const maxUploadWait = 3 * time.Minute
|
||||
|
||||
// Tracks active uploads along with their respective upload lengths
|
||||
var activeUploads = initActiveUploads()
|
||||
|
||||
func initActiveUploads() *ttlcache.Cache[string, int64] {
|
||||
cache := ttlcache.New[string, int64]()
|
||||
cache.OnEviction(func(_ context.Context, reason ttlcache.EvictionReason, item *ttlcache.Item[string, int64]) {
|
||||
if reason == ttlcache.EvictionReasonExpired {
|
||||
fmt.Printf("deleting incomplete upload file: \"%s\"", item.Key())
|
||||
os.Remove(item.Key())
|
||||
}
|
||||
})
|
||||
go cache.Start()
|
||||
|
||||
return cache
|
||||
}
|
||||
|
||||
func registerUpload(filePath string, fileSize int64) {
|
||||
activeUploads.Set(filePath, fileSize, maxUploadWait)
|
||||
}
|
||||
|
||||
func completeUpload(filePath string) {
|
||||
activeUploads.Delete(filePath)
|
||||
}
|
||||
|
||||
func getActiveUploadLength(filePath string) (int64, error) {
|
||||
item := activeUploads.Get(filePath)
|
||||
if item == nil {
|
||||
return 0, fmt.Errorf("no active upload found for the given path")
|
||||
}
|
||||
|
||||
return item.Value(), nil
|
||||
}
|
||||
|
||||
func keepUploadActive(filePath string) func() {
|
||||
// keepUploadActive periodically touches the cache entry to prevent eviction during transfer
|
||||
func keepUploadActive(cache UploadCache, filePath string) func() {
|
||||
stop := make(chan bool)
|
||||
|
||||
go func() {
|
||||
@@ -65,7 +29,7 @@ func keepUploadActive(filePath string) func() {
|
||||
case <-stop:
|
||||
return
|
||||
case <-ticker.C:
|
||||
activeUploads.Touch(filePath)
|
||||
cache.Touch(filePath)
|
||||
}
|
||||
}
|
||||
}()
|
||||
@@ -75,7 +39,7 @@ func keepUploadActive(filePath string) func() {
|
||||
}
|
||||
}
|
||||
|
||||
func tusPostHandler() handleFunc {
|
||||
func tusPostHandler(cache UploadCache) handleFunc {
|
||||
return withUser(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
|
||||
if !d.user.Perm.Create || !d.Check(r.URL.Path) {
|
||||
return http.StatusForbidden, nil
|
||||
@@ -146,7 +110,7 @@ func tusPostHandler() handleFunc {
|
||||
}
|
||||
|
||||
// Enables the user to utilize the PATCH endpoint for uploading file data
|
||||
registerUpload(file.RealPath(), uploadLength)
|
||||
cache.Register(file.RealPath(), uploadLength)
|
||||
|
||||
path, err := url.JoinPath("/", d.server.BaseURL, "/api/tus", r.URL.Path)
|
||||
if err != nil {
|
||||
@@ -158,7 +122,7 @@ func tusPostHandler() handleFunc {
|
||||
})
|
||||
}
|
||||
|
||||
func tusHeadHandler() handleFunc {
|
||||
func tusHeadHandler(cache UploadCache) handleFunc {
|
||||
return withUser(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
|
||||
w.Header().Set("Cache-Control", "no-store")
|
||||
if !d.user.Perm.Create || !d.Check(r.URL.Path) {
|
||||
@@ -177,7 +141,7 @@ func tusHeadHandler() handleFunc {
|
||||
return errToStatus(err), err
|
||||
}
|
||||
|
||||
uploadLength, err := getActiveUploadLength(file.RealPath())
|
||||
uploadLength, err := cache.GetLength(file.RealPath())
|
||||
if err != nil {
|
||||
return http.StatusNotFound, err
|
||||
}
|
||||
@@ -189,7 +153,7 @@ func tusHeadHandler() handleFunc {
|
||||
})
|
||||
}
|
||||
|
||||
func tusPatchHandler() handleFunc {
|
||||
func tusPatchHandler(cache UploadCache) handleFunc {
|
||||
return withUser(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
|
||||
if !d.user.Perm.Create || !d.Check(r.URL.Path) {
|
||||
return http.StatusForbidden, nil
|
||||
@@ -219,13 +183,13 @@ func tusPatchHandler() handleFunc {
|
||||
return errToStatus(err), err
|
||||
}
|
||||
|
||||
uploadLength, err := getActiveUploadLength(file.RealPath())
|
||||
uploadLength, err := cache.GetLength(file.RealPath())
|
||||
if err != nil {
|
||||
return http.StatusNotFound, err
|
||||
}
|
||||
|
||||
// Prevent the upload from being evicted during the transfer
|
||||
stop := keepUploadActive(file.RealPath())
|
||||
stop := keepUploadActive(cache, file.RealPath())
|
||||
defer stop()
|
||||
|
||||
switch {
|
||||
@@ -256,11 +220,17 @@ func tusPatchHandler() handleFunc {
|
||||
return http.StatusInternalServerError, fmt.Errorf("could not write to file: %w", err)
|
||||
}
|
||||
|
||||
// Sync the file to ensure all data is written to storage
|
||||
// to prevent file corruption.
|
||||
if err := openFile.Sync(); err != nil {
|
||||
return http.StatusInternalServerError, fmt.Errorf("could not sync file: %w", err)
|
||||
}
|
||||
|
||||
newOffset := uploadOffset + bytesWritten
|
||||
w.Header().Set("Upload-Offset", strconv.FormatInt(newOffset, 10))
|
||||
|
||||
if newOffset >= uploadLength {
|
||||
completeUpload(file.RealPath())
|
||||
cache.Complete(file.RealPath())
|
||||
_ = d.RunHook(func() error { return nil }, "upload", r.URL.Path, "", d.user)
|
||||
}
|
||||
|
||||
@@ -268,7 +238,7 @@ func tusPatchHandler() handleFunc {
|
||||
})
|
||||
}
|
||||
|
||||
func tusDeleteHandler() handleFunc {
|
||||
func tusDeleteHandler(cache UploadCache) handleFunc {
|
||||
return withUser(func(_ http.ResponseWriter, r *http.Request, d *data) (int, error) {
|
||||
if r.URL.Path == "/" || !d.user.Perm.Create {
|
||||
return http.StatusForbidden, nil
|
||||
@@ -286,7 +256,7 @@ func tusDeleteHandler() handleFunc {
|
||||
return errToStatus(err), err
|
||||
}
|
||||
|
||||
_, err = getActiveUploadLength(file.RealPath())
|
||||
_, err = cache.GetLength(file.RealPath())
|
||||
if err != nil {
|
||||
return http.StatusNotFound, err
|
||||
}
|
||||
@@ -296,7 +266,7 @@ func tusDeleteHandler() handleFunc {
|
||||
return errToStatus(err), err
|
||||
}
|
||||
|
||||
completeUpload(file.RealPath())
|
||||
cache.Complete(file.RealPath())
|
||||
|
||||
return http.StatusNoContent, nil
|
||||
})
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
package fbhttp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/jellydator/ttlcache/v3"
|
||||
)
|
||||
|
||||
const uploadCacheTTL = 3 * time.Minute
|
||||
|
||||
// UploadCache is an interface for tracking active uploads.
|
||||
// Allows for different backends (e.g. in-memory or redis)
|
||||
// to support both single instance and multi replica deployments.
|
||||
type UploadCache interface {
|
||||
// Register stores an upload with its expected file size
|
||||
Register(filePath string, fileSize int64)
|
||||
|
||||
// Complete removes an upload from the cache
|
||||
Complete(filePath string)
|
||||
|
||||
// GetLength returns the expected file size for an active upload
|
||||
GetLength(filePath string) (int64, error)
|
||||
|
||||
// Touch refreshes the TTL for an active upload
|
||||
Touch(filePath string)
|
||||
|
||||
// Close cleans up any resources
|
||||
Close()
|
||||
}
|
||||
|
||||
// memoryUploadCache is an upload cache for single replica deployments
|
||||
type memoryUploadCache struct {
|
||||
cache *ttlcache.Cache[string, int64]
|
||||
}
|
||||
|
||||
func newMemoryUploadCache() *memoryUploadCache {
|
||||
cache := ttlcache.New[string, int64]()
|
||||
cache.OnEviction(func(_ context.Context, reason ttlcache.EvictionReason, item *ttlcache.Item[string, int64]) {
|
||||
if reason == ttlcache.EvictionReasonExpired {
|
||||
fmt.Printf("deleting incomplete upload file: \"%s\"\n", item.Key())
|
||||
os.Remove(item.Key())
|
||||
}
|
||||
})
|
||||
go cache.Start()
|
||||
|
||||
return &memoryUploadCache{cache: cache}
|
||||
}
|
||||
|
||||
func (c *memoryUploadCache) Register(filePath string, fileSize int64) {
|
||||
c.cache.Set(filePath, fileSize, uploadCacheTTL)
|
||||
}
|
||||
|
||||
func (c *memoryUploadCache) Complete(filePath string) {
|
||||
c.cache.Delete(filePath)
|
||||
}
|
||||
|
||||
func (c *memoryUploadCache) GetLength(filePath string) (int64, error) {
|
||||
item := c.cache.Get(filePath)
|
||||
if item == nil {
|
||||
return 0, fmt.Errorf("no active upload found for the given path")
|
||||
}
|
||||
return item.Value(), nil
|
||||
}
|
||||
|
||||
func (c *memoryUploadCache) Touch(filePath string) {
|
||||
c.cache.Touch(filePath)
|
||||
}
|
||||
|
||||
func (c *memoryUploadCache) Close() {
|
||||
c.cache.Stop()
|
||||
}
|
||||
|
||||
// NewUploadCache creates a new upload cache.
|
||||
// If redisURL is empty, an in-memory cache will be used (suitable for single instance deployments).
|
||||
// Otherwise, Redis will be used for the cache (suitable for multi-instance deployments).
|
||||
// The redisURL can include credentials, e.g. redis://user:pass@host:port
|
||||
func NewUploadCache(redisURL string) (UploadCache, error) {
|
||||
if redisURL != "" {
|
||||
return newRedisUploadCache(redisURL)
|
||||
}
|
||||
return newMemoryUploadCache(), nil
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package fbhttp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"strconv"
|
||||
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
// redisUploadCache is an upload cache for multi replica deployments
|
||||
type redisUploadCache struct {
|
||||
client *redis.Client
|
||||
}
|
||||
|
||||
func newRedisUploadCache(redisURL string) (*redisUploadCache, error) {
|
||||
if redisURL == "" {
|
||||
return nil, fmt.Errorf("redis URL is required")
|
||||
}
|
||||
|
||||
opts, err := redis.ParseURL(redisURL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid redis URL: %w", err)
|
||||
}
|
||||
|
||||
client := redis.NewClient(opts)
|
||||
|
||||
// Test connection
|
||||
if err := client.Ping(context.Background()).Err(); err != nil {
|
||||
return nil, fmt.Errorf("failed to connect to redis: %w", err)
|
||||
}
|
||||
|
||||
return &redisUploadCache{client: client}, nil
|
||||
}
|
||||
|
||||
func (c *redisUploadCache) filePathKey(filePath string) string {
|
||||
return "filebrowser:upload:" + filePath
|
||||
}
|
||||
|
||||
func (c *redisUploadCache) Register(filePath string, fileSize int64) {
|
||||
err := c.client.Set(context.Background(), c.filePathKey(filePath), fileSize, uploadCacheTTL).Err()
|
||||
if err != nil {
|
||||
log.Printf("failed to register upload in redis cache: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *redisUploadCache) Complete(filePath string) {
|
||||
err := c.client.Del(context.Background(), c.filePathKey(filePath)).Err()
|
||||
if err != nil {
|
||||
log.Printf("failed to complete upload in redis cache: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *redisUploadCache) GetLength(filePath string) (int64, error) {
|
||||
result, err := c.client.Get(context.Background(), c.filePathKey(filePath)).Result()
|
||||
if err != nil {
|
||||
if errors.Is(err, redis.Nil) {
|
||||
return 0, fmt.Errorf("no active upload found for the given path")
|
||||
}
|
||||
return 0, fmt.Errorf("redis error: %w", err)
|
||||
}
|
||||
|
||||
size, err := strconv.ParseInt(result, 10, 64)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("invalid upload length in cache: %w", err)
|
||||
}
|
||||
|
||||
return size, nil
|
||||
}
|
||||
|
||||
func (c *redisUploadCache) Touch(filePath string) {
|
||||
err := c.client.Expire(context.Background(), c.filePathKey(filePath), uploadCacheTTL).Err()
|
||||
if err != nil {
|
||||
log.Printf("failed to touch upload in redis cache: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *redisUploadCache) Close() {
|
||||
c.client.Close()
|
||||
}
|
||||
+48
-1
@@ -7,11 +7,13 @@ import (
|
||||
"net/http"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"golang.org/x/text/cases"
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/filebrowser/filebrowser/v2/auth"
|
||||
fberrors "github.com/filebrowser/filebrowser/v2/errors"
|
||||
"github.com/filebrowser/filebrowser/v2/users"
|
||||
)
|
||||
@@ -102,7 +104,25 @@ var userGetHandler = withSelfOrAdmin(func(w http.ResponseWriter, r *http.Request
|
||||
return renderJSON(w, r, u)
|
||||
})
|
||||
|
||||
var userDeleteHandler = withSelfOrAdmin(func(_ http.ResponseWriter, _ *http.Request, d *data) (int, error) {
|
||||
var userDeleteHandler = withSelfOrAdmin(func(_ http.ResponseWriter, r *http.Request, d *data) (int, error) {
|
||||
if r.Body == nil {
|
||||
return http.StatusBadRequest, fberrors.ErrEmptyRequest
|
||||
}
|
||||
|
||||
var body struct {
|
||||
CurrentPassword string `json:"current_password"`
|
||||
}
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
|
||||
return http.StatusBadRequest, err
|
||||
}
|
||||
|
||||
if d.settings.AuthMethod == auth.MethodJSONAuth {
|
||||
if !users.CheckPwd(body.CurrentPassword, d.user.Password) {
|
||||
return http.StatusBadRequest, fberrors.ErrCurrentPasswordIncorrect
|
||||
}
|
||||
}
|
||||
|
||||
err := d.store.Users.Delete(d.raw.(uint))
|
||||
if err != nil {
|
||||
return errToStatus(err), err
|
||||
@@ -117,6 +137,12 @@ var userPostHandler = withAdmin(func(w http.ResponseWriter, r *http.Request, d *
|
||||
return http.StatusBadRequest, err
|
||||
}
|
||||
|
||||
if d.settings.AuthMethod == auth.MethodJSONAuth {
|
||||
if !users.CheckPwd(req.CurrentPassword, d.user.Password) {
|
||||
return http.StatusBadRequest, fberrors.ErrCurrentPasswordIncorrect
|
||||
}
|
||||
}
|
||||
|
||||
if len(req.Which) != 0 {
|
||||
return http.StatusBadRequest, nil
|
||||
}
|
||||
@@ -153,6 +179,27 @@ var userPutHandler = withSelfOrAdmin(func(w http.ResponseWriter, r *http.Request
|
||||
return http.StatusBadRequest, err
|
||||
}
|
||||
|
||||
if d.settings.AuthMethod == auth.MethodJSONAuth {
|
||||
var sensibleFields = map[string]struct{}{
|
||||
"all": {},
|
||||
"username": {},
|
||||
"password": {},
|
||||
"scope": {},
|
||||
"lockPassword": {},
|
||||
"commands": {},
|
||||
"perm": {},
|
||||
}
|
||||
|
||||
for _, field := range req.Which {
|
||||
if _, ok := sensibleFields[strings.ToLower(field)]; ok {
|
||||
if !users.CheckPwd(req.CurrentPassword, d.user.Password) {
|
||||
return http.StatusBadRequest, fberrors.ErrCurrentPasswordIncorrect
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if req.Data.ID != d.raw.(uint) {
|
||||
return http.StatusBadRequest, nil
|
||||
}
|
||||
|
||||
+6
-1
@@ -1,6 +1,7 @@
|
||||
package search
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
@@ -18,13 +19,17 @@ type searchOptions struct {
|
||||
}
|
||||
|
||||
// Search searches for a query in a fs.
|
||||
func Search(fs afero.Fs, scope, query string, checker rules.Checker, found func(path string, f os.FileInfo) error) error {
|
||||
func Search(ctx context.Context,
|
||||
fs afero.Fs, scope, query string, checker rules.Checker, found func(path string, f os.FileInfo) error) error {
|
||||
search := parseSearch(query)
|
||||
|
||||
scope = filepath.ToSlash(filepath.Clean(scope))
|
||||
scope = path.Join("/", scope)
|
||||
|
||||
return afero.Walk(fs, scope, func(fPath string, f os.FileInfo, _ error) error {
|
||||
if ctx.Err() != nil {
|
||||
return context.Cause(ctx)
|
||||
}
|
||||
fPath = filepath.ToSlash(filepath.Clean(fPath))
|
||||
fPath = path.Join("/", fPath)
|
||||
relativePath := strings.TrimPrefix(fPath, scope)
|
||||
|
||||
+12
-10
@@ -8,16 +8,17 @@ import (
|
||||
// UserDefaults is a type that holds the default values
|
||||
// for some fields on User.
|
||||
type UserDefaults struct {
|
||||
Scope string `json:"scope"`
|
||||
Locale string `json:"locale"`
|
||||
ViewMode users.ViewMode `json:"viewMode"`
|
||||
SingleClick bool `json:"singleClick"`
|
||||
Sorting files.Sorting `json:"sorting"`
|
||||
Perm users.Permissions `json:"perm"`
|
||||
Commands []string `json:"commands"`
|
||||
HideDotfiles bool `json:"hideDotfiles"`
|
||||
DateFormat bool `json:"dateFormat"`
|
||||
AceEditorTheme string `json:"aceEditorTheme"`
|
||||
Scope string `json:"scope"`
|
||||
Locale string `json:"locale"`
|
||||
ViewMode users.ViewMode `json:"viewMode"`
|
||||
SingleClick bool `json:"singleClick"`
|
||||
RedirectAfterCopyMove bool `json:"redirectAfterCopyMove"`
|
||||
Sorting files.Sorting `json:"sorting"`
|
||||
Perm users.Permissions `json:"perm"`
|
||||
Commands []string `json:"commands"`
|
||||
HideDotfiles bool `json:"hideDotfiles"`
|
||||
DateFormat bool `json:"dateFormat"`
|
||||
AceEditorTheme string `json:"aceEditorTheme"`
|
||||
}
|
||||
|
||||
// Apply applies the default options to a user.
|
||||
@@ -26,6 +27,7 @@ func (d *UserDefaults) Apply(u *users.User) {
|
||||
u.Locale = d.Locale
|
||||
u.ViewMode = d.ViewMode
|
||||
u.SingleClick = d.SingleClick
|
||||
u.RedirectAfterCopyMove = d.RedirectAfterCopyMove
|
||||
u.Perm = d.Perm
|
||||
u.Sorting = d.Sorting
|
||||
u.Commands = d.Commands
|
||||
|
||||
@@ -59,6 +59,7 @@ type Server struct {
|
||||
ResizePreview bool `json:"resizePreview"`
|
||||
EnableExec bool `json:"enableExec"`
|
||||
TypeDetectionByHeader bool `json:"typeDetectionByHeader"`
|
||||
ImageResolutionCal bool `json:"imageResolutionCalculation"`
|
||||
AuthHook string `json:"authHook"`
|
||||
TokenExpirationTime string `json:"tokenExpirationTime"`
|
||||
}
|
||||
|
||||
+17
-16
@@ -20,22 +20,23 @@ const (
|
||||
|
||||
// User describes a user.
|
||||
type User struct {
|
||||
ID uint `storm:"id,increment" json:"id"`
|
||||
Username string `storm:"unique" json:"username"`
|
||||
Password string `json:"password"`
|
||||
Scope string `json:"scope"`
|
||||
Locale string `json:"locale"`
|
||||
LockPassword bool `json:"lockPassword"`
|
||||
ViewMode ViewMode `json:"viewMode"`
|
||||
SingleClick bool `json:"singleClick"`
|
||||
Perm Permissions `json:"perm"`
|
||||
Commands []string `json:"commands"`
|
||||
Sorting files.Sorting `json:"sorting"`
|
||||
Fs afero.Fs `json:"-" yaml:"-"`
|
||||
Rules []rules.Rule `json:"rules"`
|
||||
HideDotfiles bool `json:"hideDotfiles"`
|
||||
DateFormat bool `json:"dateFormat"`
|
||||
AceEditorTheme string `json:"aceEditorTheme"`
|
||||
ID uint `storm:"id,increment" json:"id"`
|
||||
Username string `storm:"unique" json:"username"`
|
||||
Password string `json:"password"`
|
||||
Scope string `json:"scope"`
|
||||
Locale string `json:"locale"`
|
||||
LockPassword bool `json:"lockPassword"`
|
||||
ViewMode ViewMode `json:"viewMode"`
|
||||
SingleClick bool `json:"singleClick"`
|
||||
RedirectAfterCopyMove bool `json:"redirectAfterCopyMove"`
|
||||
Perm Permissions `json:"perm"`
|
||||
Commands []string `json:"commands"`
|
||||
Sorting files.Sorting `json:"sorting"`
|
||||
Fs afero.Fs `json:"-" yaml:"-"`
|
||||
Rules []rules.Rule `json:"rules"`
|
||||
HideDotfiles bool `json:"hideDotfiles"`
|
||||
DateFormat bool `json:"dateFormat"`
|
||||
AceEditorTheme string `json:"aceEditorTheme"`
|
||||
}
|
||||
|
||||
// GetRules implements rules.Provider.
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//nolint:revive
|
||||
package version
|
||||
|
||||
var (
|
||||
|
||||
+115
-1
@@ -40,7 +40,121 @@ Where `X-My-Header` is the HTTP header provided by your proxy with the username.
|
||||
>
|
||||
> File Browser will blindly trust the provided header. If the proxy can be bypassed, an attacker could simply attach the header and get admin access.
|
||||
|
||||
### No Authentication
|
||||
## Hook Authentication
|
||||
|
||||
The Hook Authentication method in FileBrowser allows developers to delegate user authentication to an external script or program. Instead of validating credentials internally, FileBrowser sends the username and password to a custom command defined by the administrator. This command receives the credentials through environment variables and returns key‑value pairs indicating whether the user should be authenticated, blocked, or passed through.
|
||||
|
||||
The hook’s output controls user permissions, scope, locale, and other attributes, making it a powerful and extensible authentication mechanism.
|
||||
|
||||
For example, the following code delegates filebrowser authentication to a PowerShell script on Windows. You can configure any command (for example, a script in Python, Node.js, etc.).
|
||||
|
||||
```sh
|
||||
filebrowser config set --auth.method=hook --auth.command="powershell.exe -File C:\route\to\your\script\auth.ps1"
|
||||
```
|
||||
|
||||
This is the code for the auth.ps1 script
|
||||
|
||||
```sh
|
||||
param()
|
||||
|
||||
# Get FileBrowser credentials from environment variables
|
||||
$username = $env:USERNAME
|
||||
$password = $env:PASSWORD
|
||||
|
||||
# Users dictionary (for testing purposes only)
|
||||
$users = @{
|
||||
"admin" = "kideW48v7-SdE*"
|
||||
"test" = "2sDd3-etrytñK"
|
||||
}
|
||||
|
||||
# Check if the user exists in the dictionary and verify the password
|
||||
if ($users.ContainsKey($username) -and $users[$username] -eq $password) {
|
||||
|
||||
# Successful authentication
|
||||
Write-Output "hook.action=auth" # Hook action (in this case, "auth", is required for successful authentication)
|
||||
|
||||
Write-Output "user.perm.admin=true" # Set admin role (all permissions)
|
||||
#You can also define specific permissions like this:
|
||||
Write-Output "user.perm.execute=true"
|
||||
Write-Output "user.perm.create=true"
|
||||
Write-Output "user.perm.rename=true"
|
||||
Write-Output "user.perm.modify=true"
|
||||
Write-Output "user.perm.delete=true"
|
||||
Write-Output "user.perm.share=true"
|
||||
Write-Output "user.perm.download=true"
|
||||
|
||||
Write-Output "user.locale=es" # Set language
|
||||
Write-Output "user.viewMode=list" # Set view mode
|
||||
Write-Output "user.scope=/" # Set FileBrowser scope
|
||||
Write-Output "user.singleClick=true" # Set single click user configuration
|
||||
Write-Output "user.hideDotfiles=false" # Set hide dot files user configuration
|
||||
|
||||
#Set other configuration
|
||||
} else {
|
||||
# Block authentication
|
||||
Write-Output "hook.action=block"
|
||||
}
|
||||
```
|
||||
|
||||
### Hook Output Format
|
||||
|
||||
A hook authentication script must output a series of key–value pairs, one per line, using the format:
|
||||
|
||||
```
|
||||
key=value
|
||||
```
|
||||
|
||||
FileBrowser reads these lines and applies the corresponding authentication action and user configuration.
|
||||
|
||||
#### Required Fields
|
||||
|
||||
The hook must output one of the following actions:
|
||||
|
||||
| Key | Description |
|
||||
|--------|------------ |
|
||||
| hook.action=auth | Authenticates the user. FileBrowser will create or update the user if needed. |
|
||||
| hook.action=block | Rejects authentication. The login attempt fails. |
|
||||
| hook.action=pass | Delegates authentication to FileBrowser’s internal password validation. |
|
||||
|
||||
For most custom authentication flows, auth or block are used.
|
||||
|
||||
Example of a successful authentication:
|
||||
|
||||
```sh
|
||||
hook.action=auth
|
||||
```
|
||||
|
||||
#### Optional User Fields
|
||||
|
||||
When `hook.action=auth` is returned, the hook may also define additional user attributes. These fields override FileBrowser defaults and allow full customization of the authenticated user.
|
||||
|
||||
1. Permissions
|
||||
```
|
||||
user.perm.admin=true
|
||||
user.perm.execute=true
|
||||
user.perm.create=true
|
||||
user.perm.rename=true
|
||||
user.perm.modify=true
|
||||
user.perm.delete=true
|
||||
user.perm.share=true
|
||||
user.perm.download=true
|
||||
```
|
||||
> Setting user.perm.admin=true automatically enables all permissions.
|
||||
|
||||
2. User Interface and Behavior
|
||||
```
|
||||
user.locale=es
|
||||
user.viewMode=list
|
||||
user.singleClick=true
|
||||
user.hideDotfiles=false
|
||||
```
|
||||
|
||||
3. User Scope
|
||||
```
|
||||
user.scope=/
|
||||
```
|
||||
|
||||
## No Authentication
|
||||
|
||||
We also provide a no authentication mechanism for users that want to use File Browser privately such in a home network. By setting this authentication method, the user with **id 1** will be used as the default users. Creating more users won't have any effect.
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ filebrowser config init [flags]
|
||||
--dateFormat use date format (true for absolute time, false for relative)
|
||||
--dirMode string mode bits that new directories are created with (default "0o750")
|
||||
--disableExec disables Command Runner feature (default true)
|
||||
--disableImageResolutionCalc disables image resolution calculation by reading image files
|
||||
--disablePreviewResize disable resize of image previews
|
||||
--disableThumbnails disable image thumbnails
|
||||
--disableTypeDetectionByHeader disables type detection by reading file headers
|
||||
@@ -60,6 +61,7 @@ filebrowser config init [flags]
|
||||
--recaptcha.host string use another host for ReCAPTCHA. recaptcha.net might be useful in China (default "https://www.google.com")
|
||||
--recaptcha.key string ReCaptcha site key
|
||||
--recaptcha.secret string ReCaptcha secret
|
||||
--redirectAfterCopyMove redirect to destination after copy/move
|
||||
-r, --root string root to prepend to relative paths (default ".")
|
||||
--scope string scope for users (default ".")
|
||||
--shell string shell command to which other commands should be appended
|
||||
|
||||
@@ -33,6 +33,7 @@ filebrowser config set [flags]
|
||||
--dateFormat use date format (true for absolute time, false for relative)
|
||||
--dirMode string mode bits that new directories are created with (default "0o750")
|
||||
--disableExec disables Command Runner feature (default true)
|
||||
--disableImageResolutionCalc disables image resolution calculation by reading image files
|
||||
--disablePreviewResize disable resize of image previews
|
||||
--disableThumbnails disable image thumbnails
|
||||
--disableTypeDetectionByHeader disables type detection by reading file headers
|
||||
@@ -57,6 +58,7 @@ filebrowser config set [flags]
|
||||
--recaptcha.host string use another host for ReCAPTCHA. recaptcha.net might be useful in China (default "https://www.google.com")
|
||||
--recaptcha.key string ReCaptcha site key
|
||||
--recaptcha.secret string ReCaptcha secret
|
||||
--redirectAfterCopyMove redirect to destination after copy/move
|
||||
-r, --root string root to prepend to relative paths (default ".")
|
||||
--scope string scope for users (default ".")
|
||||
--shell string shell command to which other commands should be appended
|
||||
|
||||
@@ -28,6 +28,7 @@ filebrowser users add <username> <password> [flags]
|
||||
--perm.modify modify perm for users (default true)
|
||||
--perm.rename rename perm for users (default true)
|
||||
--perm.share share perm for users (default true)
|
||||
--redirectAfterCopyMove redirect to destination after copy/move
|
||||
--scope string scope for users (default ".")
|
||||
--singleClick use single clicks only
|
||||
--sorting.asc sorting by ascending order
|
||||
|
||||
@@ -30,6 +30,7 @@ filebrowser users update <id|username> [flags]
|
||||
--perm.modify modify perm for users (default true)
|
||||
--perm.rename rename perm for users (default true)
|
||||
--perm.share share perm for users (default true)
|
||||
--redirectAfterCopyMove redirect to destination after copy/move
|
||||
--scope string scope for users (default ".")
|
||||
--singleClick use single clicks only
|
||||
--sorting.asc sorting by ascending order
|
||||
|
||||
@@ -26,6 +26,11 @@ file named .filebrowser.{json, toml, yaml, yml} in the following directories:
|
||||
- $HOME/
|
||||
- /etc/filebrowser/
|
||||
|
||||
**Note:** Only the options listed below can be set via the config file or
|
||||
environment variables. Other configuration options live exclusively in the
|
||||
database and so they must be set by the "config set" or "config
|
||||
import" commands.
|
||||
|
||||
The precedence of the configuration values are as follows:
|
||||
|
||||
- Flags
|
||||
@@ -52,6 +57,7 @@ filebrowser [flags]
|
||||
-c, --config string config file path
|
||||
-d, --database string database path (default "./filebrowser.db")
|
||||
--disableExec disables Command Runner feature (default true)
|
||||
--disableImageResolutionCalc disables image resolution calculation by reading image files
|
||||
--disablePreviewResize disable resize of image previews
|
||||
--disableThumbnails disable image thumbnails
|
||||
--disableTypeDetectionByHeader disables type detection by reading file headers
|
||||
@@ -62,6 +68,7 @@ filebrowser [flags]
|
||||
--noauth use the noauth auther when using quick setup
|
||||
--password string hashed password for the first user when using quick setup
|
||||
-p, --port string port to listen on (default "8080")
|
||||
--redisCacheUrl string redis cache URL (for multi-instance deployments), e.g. redis://user:pass@host:port
|
||||
-r, --root string root to prepend to relative paths (default ".")
|
||||
--socket string socket to listen to (cannot be used with address, port, cert nor key flags)
|
||||
--socketPerm uint32 unix socket file permissions (default 438)
|
||||
|
||||
Reference in New Issue
Block a user