Compare commits

...

41 Commits

Author SHA1 Message Date
Henrique Dias
c18afcddc4 chore(release): 2.44.2 2025-10-22 10:39:43 +02:00
Henrique Dias
57db25d08a fix(http): remove auth query parameter 2025-10-22 10:38:30 +02:00
dependabot[bot]
b8f64a1c1b build(deps-dev): bump vite from 6.3.6 to 6.4.1 in /frontend
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 6.3.6 to 6.4.1.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/create-vite@6.4.1/packages/vite)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-22 08:54:36 +02:00
Henrique Dias
de35dee1c5 chore(release): 2.44.1 2025-10-17 17:41:27 +02:00
MSomnium Studios
dd883985bb fix(auth): prevent integer overflow in logout timer using safeTimeout (#5470) 2025-10-17 17:38:57 +02:00
rocksload
97b8911ba8 refactor: use slices.Contains to simplify code (#5483) 2025-10-17 16:45:47 +02:00
Ryan
a397e7305d fix: editor discard prompt doesn't save nor discard
Co-authored-by: Ryan Miller <ryan.miller@infinitetactics.com>
2025-10-17 16:45:36 +02:00
Ryan
d0039afbb7 fix: wrong url on settings branding link 2025-10-03 10:42:24 +02:00
Henrique Dias
878cdfbc52 chore(release): 2.44.0 2025-09-25 17:20:12 +02:00
transifex-integration[bot]
1165f00bd4 feat: Updates for project File Browser (#5457)
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-09-25 17:19:21 +02:00
Henrique Dias
949ddffef2 fix: some formatting issues with i18n files 2025-09-25 17:13:30 +02:00
Henrique Dias
c4725428e0 fix: computation of file path 2025-09-25 17:09:16 +02:00
MSomnium Studios
d29ad356d1 feat: Improved path display in the new file and directory modal (#5451) 2025-09-25 16:57:30 +02:00
MSomnium Studios
692ca5eaf0 fix(upload): throttle upload speed calculation to 100ms to avoid Infinity MB/s (#5456)
Co-authored-by: Henrique Dias <mail@hacdias.com>
2025-09-25 16:54:28 +02:00
Adam
b9787c78f3 feat: allow setting ace editor theme (#3826)
Co-authored-by: Henrique Dias <mail@hacdias.com>
2025-09-25 16:47:00 +02:00
transifex-integration[bot]
dec7a02737 feat: Translate frontend/src/i18n/en.json in no
100% translated source file: 'frontend/src/i18n/en.json'
on 'no'.
2025-09-25 16:46:45 +02:00
transifex-integration[bot]
0eade717ce feat: Updates for project File Browser (#5450)
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-09-19 21:32:15 +02:00
MSomnium Studios
e6c674b3c6 fix: show login when session token expires 2025-09-19 15:09:26 +02:00
transifex-integration[bot]
4ff247e134 feat: Updates for project File Browser (#5446)
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-09-18 13:10:27 +02:00
Henrique Dias
2f0c1f5fa2 chore(release): 2.43.0 2025-09-13 09:04:12 +02:00
Henrique Dias
07692653ff revert: build(deps): bump github.com/ulikunitz/xz from 0.5.12 to 0.5.14 2025-09-13 09:03:12 +02:00
Henrique Dias
82dc57ad43 chore(release): 2.43.0 2025-09-13 08:44:52 +02:00
Jorge
84e8632b98 feat: "save changes" button to discard changes dialog 2025-09-13 08:07:05 +02:00
transifex-integration[bot]
571ce6cb0d feat: Translate frontend/src/i18n/en.json in es
94% of minimum 50% translated source file: 'frontend/src/i18n/en.json'
on 'es'.

Sync of partially translated files: 
untranslated content is included with an empty translation 
or source language content depending on file format
2025-09-13 07:59:33 +02:00
wuwenbin
783503aece fix: optimize markdown preview height 2025-09-13 07:58:43 +02:00
cui
b482a9bf0d refactor: to use strings.Lines 2025-09-13 07:57:18 +02:00
dependabot[bot]
36c6cc203e build(deps-dev): bump vite from 6.1.6 to 6.3.6 in /frontend
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 6.1.6 to 6.3.6.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v6.3.6/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v6.3.6/packages/vite)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-10 14:27:17 +02:00
transifex-integration[bot]
8950585141 feat: Updates for project File Browser (#5427) 2025-09-08 07:48:31 +02:00
dependabot[bot]
950028abeb build(deps): bump github.com/ulikunitz/xz from 0.5.12 to 0.5.14
Bumps [github.com/ulikunitz/xz](https://github.com/ulikunitz/xz) from 0.5.12 to 0.5.14.
- [Commits](https://github.com/ulikunitz/xz/compare/v0.5.12...v0.5.14)

---
updated-dependencies:
- dependency-name: github.com/ulikunitz/xz
  dependency-version: 0.5.14
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-30 08:00:45 +02:00
dependabot[bot]
280fa562a6 build(deps): bump github.com/go-viper/mapstructure/v2 in /tools
Bumps [github.com/go-viper/mapstructure/v2](https://github.com/go-viper/mapstructure) from 2.3.0 to 2.4.0.
- [Release notes](https://github.com/go-viper/mapstructure/releases)
- [Changelog](https://github.com/go-viper/mapstructure/blob/main/CHANGELOG.md)
- [Commits](https://github.com/go-viper/mapstructure/compare/v2.3.0...v2.4.0)

---
updated-dependencies:
- dependency-name: github.com/go-viper/mapstructure/v2
  dependency-version: 2.4.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-22 09:02:02 +02:00
transifex-integration[bot]
6b1fa87ad3 feat: Translate frontend/src/i18n/en.json in fr
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-08-20 14:33:09 +02:00
Henrique Dias
cacfb2bc08 chore(release): 2.42.5 2025-08-16 09:42:55 +02:00
Jagadam Dinesh Reddy
3107ae4147 fix: "new folder" button not working in the move and copy popup (#5368) 2025-08-16 09:42:05 +02:00
Henrique Dias
c182114883 chore(release): 2.42.4 2025-08-16 08:05:47 +02:00
Henrique Dias
342b239ac6 fix: add libcap to Dockerfile.s6 2025-08-16 08:01:18 +02:00
Henrique Dias
0f41aac20b chore(release): 2.42.3 2025-08-09 08:46:10 +02:00
wx-11
cd51a59e72 fix: add missing CLI flags for user management (#5351) 2025-08-09 07:42:42 +02:00
Henrique Dias
c829330b53 chore(release): 2.42.2 2025-08-06 16:48:24 +02:00
Ramires Viana
c14cf86f83 refactor: upload progress calculation (#5350) 2025-08-06 16:47:48 +02:00
Henrique Dias
6d620c00a1 docs: reword configuration intro 2025-08-04 08:11:40 +02:00
Ramires Viana
06e8713fa5 fix: show file upload errors 2025-08-01 18:44:38 +02:00
77 changed files with 1409 additions and 886 deletions

View File

@@ -2,6 +2,144 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
### [2.44.2](https://github.com/filebrowser/filebrowser/compare/v2.44.1...v2.44.2) (2025-10-22)
### Bug Fixes
* **http:** remove auth query parameter ([57db25d](https://github.com/filebrowser/filebrowser/commit/57db25d08a1ef2cd0b41f34e312b7b7c35c7ed38))
### Build
* **deps-dev:** bump vite from 6.3.6 to 6.4.1 in /frontend ([b8f64a1](https://github.com/filebrowser/filebrowser/commit/b8f64a1c1bc235df784d7f52abd3a9e84c6db6ce))
### [2.44.1](https://github.com/filebrowser/filebrowser/compare/v2.44.0...v2.44.1) (2025-10-17)
### Bug Fixes
* **auth:** prevent integer overflow in logout timer using safeTimeout ([#5470](https://github.com/filebrowser/filebrowser/issues/5470)) ([dd88398](https://github.com/filebrowser/filebrowser/commit/dd883985bb484af9dfea2677a40d56999fdc72f3))
* editor discard prompt doesn't save nor discard ([a397e73](https://github.com/filebrowser/filebrowser/commit/a397e7305d1572baf67823413f97a29eea38f0cc))
* wrong url on settings branding link ([d0039af](https://github.com/filebrowser/filebrowser/commit/d0039afbb76a9364c1e6ac9715ccc3c239dc8cb6))
### Refactorings
* use slices.Contains to simplify code ([#5483](https://github.com/filebrowser/filebrowser/issues/5483)) ([97b8911](https://github.com/filebrowser/filebrowser/commit/97b8911ba8a65456091cbec0202f6b5209fcf363))
## [2.44.0](https://github.com/filebrowser/filebrowser/compare/v2.43.0...v2.44.0) (2025-09-25)
### Features
* allow setting ace editor theme ([#3826](https://github.com/filebrowser/filebrowser/issues/3826)) ([b9787c7](https://github.com/filebrowser/filebrowser/commit/b9787c78f3889171f94db19e7655dce68c64b6fb))
* Improved path display in the new file and directory modal ([#5451](https://github.com/filebrowser/filebrowser/issues/5451)) ([d29ad35](https://github.com/filebrowser/filebrowser/commit/d29ad356d1067c87b2821debab91286549f512a0))
* Translate frontend/src/i18n/en.json in no ([dec7a02](https://github.com/filebrowser/filebrowser/commit/dec7a027378fbc6948d203199c44a640a141bcad))
* Updates for project File Browser ([#5446](https://github.com/filebrowser/filebrowser/issues/5446)) ([4ff247e](https://github.com/filebrowser/filebrowser/commit/4ff247e134e4d61668ee656a258ed67f71414e18))
* Updates for project File Browser ([#5450](https://github.com/filebrowser/filebrowser/issues/5450)) ([0eade71](https://github.com/filebrowser/filebrowser/commit/0eade717ce9d04bf48051922f11d983edbc7c2d0))
* Updates for project File Browser ([#5457](https://github.com/filebrowser/filebrowser/issues/5457)) ([1165f00](https://github.com/filebrowser/filebrowser/commit/1165f00bd4dcb0dcfbc084f54f51902ba4b4a714))
### Bug Fixes
* computation of file path ([c472542](https://github.com/filebrowser/filebrowser/commit/c4725428e07da72b855009e2c13c6ed91d32e0b7))
* show login when session token expires ([e6c674b](https://github.com/filebrowser/filebrowser/commit/e6c674b3c616831942c4d4aacab0907d58003e23))
* some formatting issues with i18n files ([949ddff](https://github.com/filebrowser/filebrowser/commit/949ddffef20e38169902c5fd74dca4815dcecf11))
* **upload:** throttle upload speed calculation to 100ms to avoid Infinity MB/s ([#5456](https://github.com/filebrowser/filebrowser/issues/5456)) ([692ca5e](https://github.com/filebrowser/filebrowser/commit/692ca5eaf01e4dcf346ba03f82c5dbd50cce246b))
## [2.43.0](https://github.com/filebrowser/filebrowser/compare/v2.42.5...v2.43.0) (2025-09-13)
### Features
* "save changes" button to discard changes dialog ([84e8632](https://github.com/filebrowser/filebrowser/commit/84e8632b98e315bfef2da77dd7d1049daec99241))
* Translate frontend/src/i18n/en.json in es ([571ce6c](https://github.com/filebrowser/filebrowser/commit/571ce6cb0d7c8725d1cc1a3238ea506ddc72b060))
* Translate frontend/src/i18n/en.json in fr ([6b1fa87](https://github.com/filebrowser/filebrowser/commit/6b1fa87ad38ebbb1a9c5d0e5fc88ba796c148bcf))
* Updates for project File Browser ([#5427](https://github.com/filebrowser/filebrowser/issues/5427)) ([8950585](https://github.com/filebrowser/filebrowser/commit/89505851414bfcee6b9ff02087eb4cec51c330f6))
### Bug Fixes
* optimize markdown preview height ([783503a](https://github.com/filebrowser/filebrowser/commit/783503aece7fca9e26f7e849b0e7478aba976acb))
### Reverts
* build(deps): bump github.com/ulikunitz/xz from 0.5.12 to 0.5.14 ([0769265](https://github.com/filebrowser/filebrowser/commit/07692653ffe0ea5e517e6dc1fd3961172e931843))
### Build
* **deps-dev:** bump vite from 6.1.6 to 6.3.6 in /frontend ([36c6cc2](https://github.com/filebrowser/filebrowser/commit/36c6cc203e10947439519a0413d5817921a1690d))
* **deps:** bump github.com/go-viper/mapstructure/v2 in /tools ([280fa56](https://github.com/filebrowser/filebrowser/commit/280fa562a67824887ae6e2530a3b73739d6e1bb4))
* **deps:** bump github.com/ulikunitz/xz from 0.5.12 to 0.5.14 ([950028a](https://github.com/filebrowser/filebrowser/commit/950028abebe2898bac4ecfd8715c0967246310cb))
### Refactorings
* to use strings.Lines ([b482a9b](https://github.com/filebrowser/filebrowser/commit/b482a9bf0d292ec6542d2145a4408971e4c985f1))
## [2.43.0](https://github.com/filebrowser/filebrowser/compare/v2.42.5...v2.43.0) (2025-09-13)
### Features
* "save changes" button to discard changes dialog ([84e8632](https://github.com/filebrowser/filebrowser/commit/84e8632b98e315bfef2da77dd7d1049daec99241))
* Translate frontend/src/i18n/en.json in es ([571ce6c](https://github.com/filebrowser/filebrowser/commit/571ce6cb0d7c8725d1cc1a3238ea506ddc72b060))
* Translate frontend/src/i18n/en.json in fr ([6b1fa87](https://github.com/filebrowser/filebrowser/commit/6b1fa87ad38ebbb1a9c5d0e5fc88ba796c148bcf))
* Updates for project File Browser ([#5427](https://github.com/filebrowser/filebrowser/issues/5427)) ([8950585](https://github.com/filebrowser/filebrowser/commit/89505851414bfcee6b9ff02087eb4cec51c330f6))
### Bug Fixes
* optimize markdown preview height ([783503a](https://github.com/filebrowser/filebrowser/commit/783503aece7fca9e26f7e849b0e7478aba976acb))
### Build
* **deps-dev:** bump vite from 6.1.6 to 6.3.6 in /frontend ([36c6cc2](https://github.com/filebrowser/filebrowser/commit/36c6cc203e10947439519a0413d5817921a1690d))
* **deps:** bump github.com/go-viper/mapstructure/v2 in /tools ([280fa56](https://github.com/filebrowser/filebrowser/commit/280fa562a67824887ae6e2530a3b73739d6e1bb4))
* **deps:** bump github.com/ulikunitz/xz from 0.5.12 to 0.5.14 ([950028a](https://github.com/filebrowser/filebrowser/commit/950028abebe2898bac4ecfd8715c0967246310cb))
### Refactorings
* to use strings.Lines ([b482a9b](https://github.com/filebrowser/filebrowser/commit/b482a9bf0d292ec6542d2145a4408971e4c985f1))
### [2.42.5](https://github.com/filebrowser/filebrowser/compare/v2.42.4...v2.42.5) (2025-08-16)
### Bug Fixes
* "new folder" button not working in the move and copy popup ([#5368](https://github.com/filebrowser/filebrowser/issues/5368)) ([3107ae4](https://github.com/filebrowser/filebrowser/commit/3107ae41475ae9383c3af414d25a133e549f8087))
### [2.42.4](https://github.com/filebrowser/filebrowser/compare/v2.42.3...v2.42.4) (2025-08-16)
### Bug Fixes
* add libcap to Dockerfile.s6 ([342b239](https://github.com/filebrowser/filebrowser/commit/342b239ac6f4af2453d5f7aa27f7f0093024dd72))
### [2.42.3](https://github.com/filebrowser/filebrowser/compare/v2.42.2...v2.42.3) (2025-08-09)
### Bug Fixes
* add missing CLI flags for user management ([#5351](https://github.com/filebrowser/filebrowser/issues/5351)) ([cd51a59](https://github.com/filebrowser/filebrowser/commit/cd51a59e72c72560fce7bcc9b12aaf02646b699c))
### [2.42.2](https://github.com/filebrowser/filebrowser/compare/v2.42.1...v2.42.2) (2025-08-06)
### Bug Fixes
* show file upload errors ([06e8713](https://github.com/filebrowser/filebrowser/commit/06e8713fa55065d38f02499d3e8d39fc86926cab))
### Refactorings
* upload progress calculation ([#5350](https://github.com/filebrowser/filebrowser/issues/5350)) ([c14cf86](https://github.com/filebrowser/filebrowser/commit/c14cf86f8304e01d804e01a7eef5ea093627ef37))
### [2.42.1](https://github.com/filebrowser/filebrowser/compare/v2.42.0...v2.42.1) (2025-07-31) ### [2.42.1](https://github.com/filebrowser/filebrowser/compare/v2.42.0...v2.42.1) (2025-07-31)

View File

@@ -1,7 +1,7 @@
FROM ghcr.io/linuxserver/baseimage-alpine:3.22 FROM ghcr.io/linuxserver/baseimage-alpine:3.22
RUN apk update && \ RUN apk update && \
apk --no-cache add ca-certificates mailcap jq apk --no-cache add ca-certificates mailcap jq libcap
# Make user and create necessary directories # Make user and create necessary directories
RUN mkdir -p /config /database /srv && \ RUN mkdir -p /config /database /srv && \
@@ -12,7 +12,8 @@ COPY filebrowser /bin/filebrowser
COPY docker/common/ / COPY docker/common/ /
COPY docker/s6/ / COPY docker/s6/ /
RUN chown -R abc:abc /bin/filebrowser /defaults healthcheck.sh RUN chown -R abc:abc /bin/filebrowser /defaults healthcheck.sh && \
setcap 'cap_net_bind_service=+ep' /bin/filebrowser
# Define healthcheck script # Define healthcheck script
HEALTHCHECK --start-period=2s --interval=5s --timeout=3s CMD /healthcheck.sh HEALTHCHECK --start-period=2s --interval=5s --timeout=3s CMD /healthcheck.sh

View File

@@ -8,6 +8,7 @@ import (
"net/http" "net/http"
"os" "os"
"os/exec" "os/exec"
"slices"
"strings" "strings"
fbErrors "github.com/filebrowser/filebrowser/v2/errors" fbErrors "github.com/filebrowser/filebrowser/v2/errors"
@@ -123,7 +124,7 @@ func (a *HookAuth) GetValues(s string) {
s = strings.ReplaceAll(s, "\r\n", "\n") s = strings.ReplaceAll(s, "\r\n", "\n")
// iterate input lines // iterate input lines
for _, val := range strings.Split(s, "\n") { for val := range strings.Lines(s) {
v := strings.SplitN(val, "=", 2) v := strings.SplitN(val, "=", 2)
// skips non key and value format // skips non key and value format
@@ -266,13 +267,7 @@ var validHookFields = []string{
// IsValid checks if the provided field is on the valid fields list // IsValid checks if the provided field is on the valid fields list
func (hf *hookFields) IsValid(field string) bool { func (hf *hookFields) IsValid(field string) bool {
for _, val := range validHookFields { return slices.Contains(validHookFields, field)
if field == val {
return true
}
}
return false
} }
// GetString returns the string value or provided default // GetString returns the string value or provided default

View File

@@ -221,6 +221,7 @@ func printSettings(ser *settings.Server, set *settings.Settings, auther auth.Aut
fmt.Fprintf(w, "\tFile Creation Mode:\t%O\n", set.FileMode) 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, "\tDirectory Creation Mode:\t%O\n", set.DirMode)
fmt.Fprintf(w, "\tCommands:\t%s\n", strings.Join(set.Defaults.Commands, " ")) fmt.Fprintf(w, "\tCommands:\t%s\n", strings.Join(set.Defaults.Commands, " "))
fmt.Fprintf(w, "\tAce editor syntax highlighting theme:\t%s\n", set.Defaults.AceEditorTheme)
fmt.Fprintf(w, "\tSorting:\n") fmt.Fprintf(w, "\tSorting:\n")
fmt.Fprintf(w, "\t\tBy:\t%s\n", set.Defaults.Sorting.By) fmt.Fprintf(w, "\t\tBy:\t%s\n", set.Defaults.Sorting.By)
fmt.Fprintf(w, "\t\tAsc:\t%t\n", set.Defaults.Sorting.Asc) fmt.Fprintf(w, "\t\tAsc:\t%t\n", set.Defaults.Sorting.Asc)

View File

@@ -424,9 +424,10 @@ func quickSetup(flags *pflag.FlagSet, d pythonData) error {
MinimumPasswordLength: settings.DefaultMinimumPasswordLength, MinimumPasswordLength: settings.DefaultMinimumPasswordLength,
UserHomeBasePath: settings.DefaultUsersHomeBasePath, UserHomeBasePath: settings.DefaultUsersHomeBasePath,
Defaults: settings.UserDefaults{ Defaults: settings.UserDefaults{
Scope: ".", Scope: ".",
Locale: "en", Locale: "en",
SingleClick: false, SingleClick: false,
AceEditorTheme: getStringParam(flags, "defaults.aceEditorTheme"),
Perm: users.Permissions{ Perm: users.Permissions{
Admin: false, Admin: false,
Execute: true, Execute: true,

View File

@@ -77,6 +77,9 @@ func addUserFlags(flags *pflag.FlagSet) {
flags.String("locale", "en", "locale for users") flags.String("locale", "en", "locale for users")
flags.String("viewMode", string(users.ListViewMode), "view mode for users") flags.String("viewMode", string(users.ListViewMode), "view mode for users")
flags.Bool("singleClick", false, "use single clicks only") flags.Bool("singleClick", false, "use single clicks only")
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")
} }
func getViewMode(flags *pflag.FlagSet) (users.ViewMode, error) { func getViewMode(flags *pflag.FlagSet) (users.ViewMode, error) {
@@ -108,6 +111,8 @@ func getUserDefaults(flags *pflag.FlagSet, defaults *settings.UserDefaults, all
defaults.ViewMode, err = getViewMode(flags) defaults.ViewMode, err = getViewMode(flags)
case "singleClick": case "singleClick":
defaults.SingleClick, err = getBool(flags, flag.Name) defaults.SingleClick, err = getBool(flags, flag.Name)
case "aceEditorTheme":
defaults.AceEditorTheme, err = getString(flags, flag.Name)
case "perm.admin": case "perm.admin":
defaults.Perm.Admin, err = getBool(flags, flag.Name) defaults.Perm.Admin, err = getBool(flags, flag.Name)
case "perm.execute": case "perm.execute":

View File

@@ -36,10 +36,22 @@ var usersAddCmd = &cobra.Command{
return err return err
} }
dateFormat, err := getBool(cmd.Flags(), "dateFormat")
if err != nil {
return err
}
hideDotfiles, err := getBool(cmd.Flags(), "hideDotfiles")
if err != nil {
return err
}
user := &users.User{ user := &users.User{
Username: args[0], Username: args[0],
Password: password, Password: password,
LockPassword: lockPassword, LockPassword: lockPassword,
DateFormat: dateFormat,
HideDotfiles: hideDotfiles,
} }
s.Defaults.Apply(user) s.Defaults.Apply(user)

View File

@@ -76,6 +76,14 @@ options you want to change.`,
if err != nil { if err != nil {
return err return err
} }
user.DateFormat, err = getBool(flags, "dateFormat")
if err != nil {
return err
}
user.HideDotfiles, err = getBool(flags, "hideDotfiles")
if err != nil {
return err
}
if newUsername != "" { if newUsername != "" {
user.Username = newUsername user.Username = newUsername

View File

@@ -71,7 +71,7 @@
"postcss": "^8.5.6", "postcss": "^8.5.6",
"prettier": "^3.6.2", "prettier": "^3.6.2",
"terser": "^5.43.1", "terser": "^5.43.1",
"vite": "^6.1.6", "vite": "^6.4.1",
"vite-plugin-compression2": "^1.0.0", "vite-plugin-compression2": "^1.0.0",
"vue-tsc": "^2.2.0" "vue-tsc": "^2.2.0"
}, },

490
frontend/pnpm-lock.yaml generated
View File

@@ -101,7 +101,7 @@ importers:
devDependencies: devDependencies:
'@intlify/unplugin-vue-i18n': '@intlify/unplugin-vue-i18n':
specifier: ^6.0.8 specifier: ^6.0.8
version: 6.0.8(@vue/compiler-dom@3.5.17)(eslint@9.31.0)(rollup@4.40.1)(typescript@5.6.3)(vue-i18n@11.1.10(vue@3.5.17(typescript@5.6.3)))(vue@3.5.17(typescript@5.6.3)) version: 6.0.8(@vue/compiler-dom@3.5.17)(eslint@9.31.0)(rollup@4.52.5)(typescript@5.6.3)(vue-i18n@11.1.10(vue@3.5.17(typescript@5.6.3)))(vue@3.5.17(typescript@5.6.3))
'@playwright/test': '@playwright/test':
specifier: ^1.54.1 specifier: ^1.54.1
version: 1.54.1 version: 1.54.1
@@ -119,10 +119,10 @@ importers:
version: 8.37.0(@typescript-eslint/parser@8.37.0(eslint@9.31.0)(typescript@5.6.3))(eslint@9.31.0)(typescript@5.6.3) version: 8.37.0(@typescript-eslint/parser@8.37.0(eslint@9.31.0)(typescript@5.6.3))(eslint@9.31.0)(typescript@5.6.3)
'@vitejs/plugin-legacy': '@vitejs/plugin-legacy':
specifier: ^6.0.0 specifier: ^6.0.0
version: 6.0.0(terser@5.43.1)(vite@6.1.6(@types/node@22.10.10)(terser@5.43.1)(yaml@2.7.0)) version: 6.0.0(terser@5.43.1)(vite@6.4.1(@types/node@22.10.10)(terser@5.43.1)(yaml@2.7.0))
'@vitejs/plugin-vue': '@vitejs/plugin-vue':
specifier: ^5.0.4 specifier: ^5.0.4
version: 5.2.1(vite@6.1.6(@types/node@22.10.10)(terser@5.43.1)(yaml@2.7.0))(vue@3.5.17(typescript@5.6.3)) version: 5.2.1(vite@6.4.1(@types/node@22.10.10)(terser@5.43.1)(yaml@2.7.0))(vue@3.5.17(typescript@5.6.3))
'@vue/eslint-config-prettier': '@vue/eslint-config-prettier':
specifier: ^10.2.0 specifier: ^10.2.0
version: 10.2.0(eslint@9.31.0)(prettier@3.6.2) version: 10.2.0(eslint@9.31.0)(prettier@3.6.2)
@@ -163,11 +163,11 @@ importers:
specifier: ^5.43.1 specifier: ^5.43.1
version: 5.43.1 version: 5.43.1
vite: vite:
specifier: ^6.1.6 specifier: ^6.4.1
version: 6.1.6(@types/node@22.10.10)(terser@5.43.1)(yaml@2.7.0) version: 6.4.1(@types/node@22.10.10)(terser@5.43.1)(yaml@2.7.0)
vite-plugin-compression2: vite-plugin-compression2:
specifier: ^1.0.0 specifier: ^1.0.0
version: 1.3.3(rollup@4.40.1)(vite@6.1.6(@types/node@22.10.10)(terser@5.43.1)(yaml@2.7.0)) version: 1.3.3(rollup@4.52.5)(vite@6.4.1(@types/node@22.10.10)(terser@5.43.1)(yaml@2.7.0))
vue-tsc: vue-tsc:
specifier: ^2.2.0 specifier: ^2.2.0
version: 2.2.0(typescript@5.6.3) version: 2.2.0(typescript@5.6.3)
@@ -737,152 +737,158 @@ packages:
resolution: {integrity: sha512-UJnjoFsmxfKUdNYdWgOB0mWUypuLvAfQPH1+pyvRJs6euowbFkFC6P13w1l8mJyi3vxYMxc9kld5jZEGRQs6bw==} resolution: {integrity: sha512-UJnjoFsmxfKUdNYdWgOB0mWUypuLvAfQPH1+pyvRJs6euowbFkFC6P13w1l8mJyi3vxYMxc9kld5jZEGRQs6bw==}
engines: {node: '>=18'} engines: {node: '>=18'}
'@esbuild/aix-ppc64@0.24.2': '@esbuild/aix-ppc64@0.25.11':
resolution: {integrity: sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==} resolution: {integrity: sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg==}
engines: {node: '>=18'} engines: {node: '>=18'}
cpu: [ppc64] cpu: [ppc64]
os: [aix] os: [aix]
'@esbuild/android-arm64@0.24.2': '@esbuild/android-arm64@0.25.11':
resolution: {integrity: sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==} resolution: {integrity: sha512-9slpyFBc4FPPz48+f6jyiXOx/Y4v34TUeDDXJpZqAWQn/08lKGeD8aDp9TMn9jDz2CiEuHwfhRmGBvpnd/PWIQ==}
engines: {node: '>=18'} engines: {node: '>=18'}
cpu: [arm64] cpu: [arm64]
os: [android] os: [android]
'@esbuild/android-arm@0.24.2': '@esbuild/android-arm@0.25.11':
resolution: {integrity: sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==} resolution: {integrity: sha512-uoa7dU+Dt3HYsethkJ1k6Z9YdcHjTrSb5NUy66ZfZaSV8hEYGD5ZHbEMXnqLFlbBflLsl89Zke7CAdDJ4JI+Gg==}
engines: {node: '>=18'} engines: {node: '>=18'}
cpu: [arm] cpu: [arm]
os: [android] os: [android]
'@esbuild/android-x64@0.24.2': '@esbuild/android-x64@0.25.11':
resolution: {integrity: sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==} resolution: {integrity: sha512-Sgiab4xBjPU1QoPEIqS3Xx+R2lezu0LKIEcYe6pftr56PqPygbB7+szVnzoShbx64MUupqoE0KyRlN7gezbl8g==}
engines: {node: '>=18'} engines: {node: '>=18'}
cpu: [x64] cpu: [x64]
os: [android] os: [android]
'@esbuild/darwin-arm64@0.24.2': '@esbuild/darwin-arm64@0.25.11':
resolution: {integrity: sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==} resolution: {integrity: sha512-VekY0PBCukppoQrycFxUqkCojnTQhdec0vevUL/EDOCnXd9LKWqD/bHwMPzigIJXPhC59Vd1WFIL57SKs2mg4w==}
engines: {node: '>=18'} engines: {node: '>=18'}
cpu: [arm64] cpu: [arm64]
os: [darwin] os: [darwin]
'@esbuild/darwin-x64@0.24.2': '@esbuild/darwin-x64@0.25.11':
resolution: {integrity: sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==} resolution: {integrity: sha512-+hfp3yfBalNEpTGp9loYgbknjR695HkqtY3d3/JjSRUyPg/xd6q+mQqIb5qdywnDxRZykIHs3axEqU6l1+oWEQ==}
engines: {node: '>=18'} engines: {node: '>=18'}
cpu: [x64] cpu: [x64]
os: [darwin] os: [darwin]
'@esbuild/freebsd-arm64@0.24.2': '@esbuild/freebsd-arm64@0.25.11':
resolution: {integrity: sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==} resolution: {integrity: sha512-CmKjrnayyTJF2eVuO//uSjl/K3KsMIeYeyN7FyDBjsR3lnSJHaXlVoAK8DZa7lXWChbuOk7NjAc7ygAwrnPBhA==}
engines: {node: '>=18'} engines: {node: '>=18'}
cpu: [arm64] cpu: [arm64]
os: [freebsd] os: [freebsd]
'@esbuild/freebsd-x64@0.24.2': '@esbuild/freebsd-x64@0.25.11':
resolution: {integrity: sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==} resolution: {integrity: sha512-Dyq+5oscTJvMaYPvW3x3FLpi2+gSZTCE/1ffdwuM6G1ARang/mb3jvjxs0mw6n3Lsw84ocfo9CrNMqc5lTfGOw==}
engines: {node: '>=18'} engines: {node: '>=18'}
cpu: [x64] cpu: [x64]
os: [freebsd] os: [freebsd]
'@esbuild/linux-arm64@0.24.2': '@esbuild/linux-arm64@0.25.11':
resolution: {integrity: sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==} resolution: {integrity: sha512-Qr8AzcplUhGvdyUF08A1kHU3Vr2O88xxP0Tm8GcdVOUm25XYcMPp2YqSVHbLuXzYQMf9Bh/iKx7YPqECs6ffLA==}
engines: {node: '>=18'} engines: {node: '>=18'}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
'@esbuild/linux-arm@0.24.2': '@esbuild/linux-arm@0.25.11':
resolution: {integrity: sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==} resolution: {integrity: sha512-TBMv6B4kCfrGJ8cUPo7vd6NECZH/8hPpBHHlYI3qzoYFvWu2AdTvZNuU/7hsbKWqu/COU7NIK12dHAAqBLLXgw==}
engines: {node: '>=18'} engines: {node: '>=18'}
cpu: [arm] cpu: [arm]
os: [linux] os: [linux]
'@esbuild/linux-ia32@0.24.2': '@esbuild/linux-ia32@0.25.11':
resolution: {integrity: sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==} resolution: {integrity: sha512-TmnJg8BMGPehs5JKrCLqyWTVAvielc615jbkOirATQvWWB1NMXY77oLMzsUjRLa0+ngecEmDGqt5jiDC6bfvOw==}
engines: {node: '>=18'} engines: {node: '>=18'}
cpu: [ia32] cpu: [ia32]
os: [linux] os: [linux]
'@esbuild/linux-loong64@0.24.2': '@esbuild/linux-loong64@0.25.11':
resolution: {integrity: sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==} resolution: {integrity: sha512-DIGXL2+gvDaXlaq8xruNXUJdT5tF+SBbJQKbWy/0J7OhU8gOHOzKmGIlfTTl6nHaCOoipxQbuJi7O++ldrxgMw==}
engines: {node: '>=18'} engines: {node: '>=18'}
cpu: [loong64] cpu: [loong64]
os: [linux] os: [linux]
'@esbuild/linux-mips64el@0.24.2': '@esbuild/linux-mips64el@0.25.11':
resolution: {integrity: sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==} resolution: {integrity: sha512-Osx1nALUJu4pU43o9OyjSCXokFkFbyzjXb6VhGIJZQ5JZi8ylCQ9/LFagolPsHtgw6himDSyb5ETSfmp4rpiKQ==}
engines: {node: '>=18'} engines: {node: '>=18'}
cpu: [mips64el] cpu: [mips64el]
os: [linux] os: [linux]
'@esbuild/linux-ppc64@0.24.2': '@esbuild/linux-ppc64@0.25.11':
resolution: {integrity: sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==} resolution: {integrity: sha512-nbLFgsQQEsBa8XSgSTSlrnBSrpoWh7ioFDUmwo158gIm5NNP+17IYmNWzaIzWmgCxq56vfr34xGkOcZ7jX6CPw==}
engines: {node: '>=18'} engines: {node: '>=18'}
cpu: [ppc64] cpu: [ppc64]
os: [linux] os: [linux]
'@esbuild/linux-riscv64@0.24.2': '@esbuild/linux-riscv64@0.25.11':
resolution: {integrity: sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==} resolution: {integrity: sha512-HfyAmqZi9uBAbgKYP1yGuI7tSREXwIb438q0nqvlpxAOs3XnZ8RsisRfmVsgV486NdjD7Mw2UrFSw51lzUk1ww==}
engines: {node: '>=18'} engines: {node: '>=18'}
cpu: [riscv64] cpu: [riscv64]
os: [linux] os: [linux]
'@esbuild/linux-s390x@0.24.2': '@esbuild/linux-s390x@0.25.11':
resolution: {integrity: sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==} resolution: {integrity: sha512-HjLqVgSSYnVXRisyfmzsH6mXqyvj0SA7pG5g+9W7ESgwA70AXYNpfKBqh1KbTxmQVaYxpzA/SvlB9oclGPbApw==}
engines: {node: '>=18'} engines: {node: '>=18'}
cpu: [s390x] cpu: [s390x]
os: [linux] os: [linux]
'@esbuild/linux-x64@0.24.2': '@esbuild/linux-x64@0.25.11':
resolution: {integrity: sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==} resolution: {integrity: sha512-HSFAT4+WYjIhrHxKBwGmOOSpphjYkcswF449j6EjsjbinTZbp8PJtjsVK1XFJStdzXdy/jaddAep2FGY+wyFAQ==}
engines: {node: '>=18'} engines: {node: '>=18'}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
'@esbuild/netbsd-arm64@0.24.2': '@esbuild/netbsd-arm64@0.25.11':
resolution: {integrity: sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==} resolution: {integrity: sha512-hr9Oxj1Fa4r04dNpWr3P8QKVVsjQhqrMSUzZzf+LZcYjZNqhA3IAfPQdEh1FLVUJSiu6sgAwp3OmwBfbFgG2Xg==}
engines: {node: '>=18'} engines: {node: '>=18'}
cpu: [arm64] cpu: [arm64]
os: [netbsd] os: [netbsd]
'@esbuild/netbsd-x64@0.24.2': '@esbuild/netbsd-x64@0.25.11':
resolution: {integrity: sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==} resolution: {integrity: sha512-u7tKA+qbzBydyj0vgpu+5h5AeudxOAGncb8N6C9Kh1N4n7wU1Xw1JDApsRjpShRpXRQlJLb9wY28ELpwdPcZ7A==}
engines: {node: '>=18'} engines: {node: '>=18'}
cpu: [x64] cpu: [x64]
os: [netbsd] os: [netbsd]
'@esbuild/openbsd-arm64@0.24.2': '@esbuild/openbsd-arm64@0.25.11':
resolution: {integrity: sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==} resolution: {integrity: sha512-Qq6YHhayieor3DxFOoYM1q0q1uMFYb7cSpLD2qzDSvK1NAvqFi8Xgivv0cFC6J+hWVw2teCYltyy9/m/14ryHg==}
engines: {node: '>=18'} engines: {node: '>=18'}
cpu: [arm64] cpu: [arm64]
os: [openbsd] os: [openbsd]
'@esbuild/openbsd-x64@0.24.2': '@esbuild/openbsd-x64@0.25.11':
resolution: {integrity: sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==} resolution: {integrity: sha512-CN+7c++kkbrckTOz5hrehxWN7uIhFFlmS/hqziSFVWpAzpWrQoAG4chH+nN3Be+Kzv/uuo7zhX716x3Sn2Jduw==}
engines: {node: '>=18'} engines: {node: '>=18'}
cpu: [x64] cpu: [x64]
os: [openbsd] os: [openbsd]
'@esbuild/sunos-x64@0.24.2': '@esbuild/openharmony-arm64@0.25.11':
resolution: {integrity: sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==} resolution: {integrity: sha512-rOREuNIQgaiR+9QuNkbkxubbp8MSO9rONmwP5nKncnWJ9v5jQ4JxFnLu4zDSRPf3x4u+2VN4pM4RdyIzDty/wQ==}
engines: {node: '>=18'}
cpu: [arm64]
os: [openharmony]
'@esbuild/sunos-x64@0.25.11':
resolution: {integrity: sha512-nq2xdYaWxyg9DcIyXkZhcYulC6pQ2FuCgem3LI92IwMgIZ69KHeY8T4Y88pcwoLIjbed8n36CyKoYRDygNSGhA==}
engines: {node: '>=18'} engines: {node: '>=18'}
cpu: [x64] cpu: [x64]
os: [sunos] os: [sunos]
'@esbuild/win32-arm64@0.24.2': '@esbuild/win32-arm64@0.25.11':
resolution: {integrity: sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==} resolution: {integrity: sha512-3XxECOWJq1qMZ3MN8srCJ/QfoLpL+VaxD/WfNRm1O3B4+AZ/BnLVgFbUV3eiRYDMXetciH16dwPbbHqwe1uU0Q==}
engines: {node: '>=18'} engines: {node: '>=18'}
cpu: [arm64] cpu: [arm64]
os: [win32] os: [win32]
'@esbuild/win32-ia32@0.24.2': '@esbuild/win32-ia32@0.25.11':
resolution: {integrity: sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==} resolution: {integrity: sha512-3ukss6gb9XZ8TlRyJlgLn17ecsK4NSQTmdIXRASVsiS2sQ6zPPZklNJT5GR5tE/MUarymmy8kCEf5xPCNCqVOA==}
engines: {node: '>=18'} engines: {node: '>=18'}
cpu: [ia32] cpu: [ia32]
os: [win32] os: [win32]
'@esbuild/win32-x64@0.24.2': '@esbuild/win32-x64@0.25.11':
resolution: {integrity: sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==} resolution: {integrity: sha512-D7Hpz6A2L4hzsRpPaCYkQnGOotdUpDzSGRIv9I+1ITdHROSFUWW95ZPZWQmGka1Fg7W3zFJowyn9WGwMJ0+KPA==}
engines: {node: '>=18'} engines: {node: '>=18'}
cpu: [x64] cpu: [x64]
os: [win32] os: [win32]
@@ -1082,103 +1088,113 @@ packages:
rollup: rollup:
optional: true optional: true
'@rollup/rollup-android-arm-eabi@4.40.1': '@rollup/rollup-android-arm-eabi@4.52.5':
resolution: {integrity: sha512-kxz0YeeCrRUHz3zyqvd7n+TVRlNyTifBsmnmNPtk3hQURUyG9eAB+usz6DAwagMusjx/zb3AjvDUvhFGDAexGw==} resolution: {integrity: sha512-8c1vW4ocv3UOMp9K+gToY5zL2XiiVw3k7f1ksf4yO1FlDFQ1C2u72iACFnSOceJFsWskc2WZNqeRhFRPzv+wtQ==}
cpu: [arm] cpu: [arm]
os: [android] os: [android]
'@rollup/rollup-android-arm64@4.40.1': '@rollup/rollup-android-arm64@4.52.5':
resolution: {integrity: sha512-PPkxTOisoNC6TpnDKatjKkjRMsdaWIhyuMkA4UsBXT9WEZY4uHezBTjs6Vl4PbqQQeu6oION1w2voYZv9yquCw==} resolution: {integrity: sha512-mQGfsIEFcu21mvqkEKKu2dYmtuSZOBMmAl5CFlPGLY94Vlcm+zWApK7F/eocsNzp8tKmbeBP8yXyAbx0XHsFNA==}
cpu: [arm64] cpu: [arm64]
os: [android] os: [android]
'@rollup/rollup-darwin-arm64@4.40.1': '@rollup/rollup-darwin-arm64@4.52.5':
resolution: {integrity: sha512-VWXGISWFY18v/0JyNUy4A46KCFCb9NVsH+1100XP31lud+TzlezBbz24CYzbnA4x6w4hx+NYCXDfnvDVO6lcAA==} resolution: {integrity: sha512-takF3CR71mCAGA+v794QUZ0b6ZSrgJkArC+gUiG6LB6TQty9T0Mqh3m2ImRBOxS2IeYBo4lKWIieSvnEk2OQWA==}
cpu: [arm64] cpu: [arm64]
os: [darwin] os: [darwin]
'@rollup/rollup-darwin-x64@4.40.1': '@rollup/rollup-darwin-x64@4.52.5':
resolution: {integrity: sha512-nIwkXafAI1/QCS7pxSpv/ZtFW6TXcNUEHAIA9EIyw5OzxJZQ1YDrX+CL6JAIQgZ33CInl1R6mHet9Y/UZTg2Bw==} resolution: {integrity: sha512-W901Pla8Ya95WpxDn//VF9K9u2JbocwV/v75TE0YIHNTbhqUTv9w4VuQ9MaWlNOkkEfFwkdNhXgcLqPSmHy0fA==}
cpu: [x64] cpu: [x64]
os: [darwin] os: [darwin]
'@rollup/rollup-freebsd-arm64@4.40.1': '@rollup/rollup-freebsd-arm64@4.52.5':
resolution: {integrity: sha512-BdrLJ2mHTrIYdaS2I99mriyJfGGenSaP+UwGi1kB9BLOCu9SR8ZpbkmmalKIALnRw24kM7qCN0IOm6L0S44iWw==} resolution: {integrity: sha512-QofO7i7JycsYOWxe0GFqhLmF6l1TqBswJMvICnRUjqCx8b47MTo46W8AoeQwiokAx3zVryVnxtBMcGcnX12LvA==}
cpu: [arm64] cpu: [arm64]
os: [freebsd] os: [freebsd]
'@rollup/rollup-freebsd-x64@4.40.1': '@rollup/rollup-freebsd-x64@4.52.5':
resolution: {integrity: sha512-VXeo/puqvCG8JBPNZXZf5Dqq7BzElNJzHRRw3vjBE27WujdzuOPecDPc/+1DcdcTptNBep3861jNq0mYkT8Z6Q==} resolution: {integrity: sha512-jr21b/99ew8ujZubPo9skbrItHEIE50WdV86cdSoRkKtmWa+DDr6fu2c/xyRT0F/WazZpam6kk7IHBerSL7LDQ==}
cpu: [x64] cpu: [x64]
os: [freebsd] os: [freebsd]
'@rollup/rollup-linux-arm-gnueabihf@4.40.1': '@rollup/rollup-linux-arm-gnueabihf@4.52.5':
resolution: {integrity: sha512-ehSKrewwsESPt1TgSE/na9nIhWCosfGSFqv7vwEtjyAqZcvbGIg4JAcV7ZEh2tfj/IlfBeZjgOXm35iOOjadcg==} resolution: {integrity: sha512-PsNAbcyv9CcecAUagQefwX8fQn9LQ4nZkpDboBOttmyffnInRy8R8dSg6hxxl2Re5QhHBf6FYIDhIj5v982ATQ==}
cpu: [arm] cpu: [arm]
os: [linux] os: [linux]
'@rollup/rollup-linux-arm-musleabihf@4.40.1': '@rollup/rollup-linux-arm-musleabihf@4.52.5':
resolution: {integrity: sha512-m39iO/aaurh5FVIu/F4/Zsl8xppd76S4qoID8E+dSRQvTyZTOI2gVk3T4oqzfq1PtcvOfAVlwLMK3KRQMaR8lg==} resolution: {integrity: sha512-Fw4tysRutyQc/wwkmcyoqFtJhh0u31K+Q6jYjeicsGJJ7bbEq8LwPWV/w0cnzOqR2m694/Af6hpFayLJZkG2VQ==}
cpu: [arm] cpu: [arm]
os: [linux] os: [linux]
'@rollup/rollup-linux-arm64-gnu@4.40.1': '@rollup/rollup-linux-arm64-gnu@4.52.5':
resolution: {integrity: sha512-Y+GHnGaku4aVLSgrT0uWe2o2Rq8te9hi+MwqGF9r9ORgXhmHK5Q71N757u0F8yU1OIwUIFy6YiJtKjtyktk5hg==} resolution: {integrity: sha512-a+3wVnAYdQClOTlyapKmyI6BLPAFYs0JM8HRpgYZQO02rMR09ZcV9LbQB+NL6sljzG38869YqThrRnfPMCDtZg==}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
'@rollup/rollup-linux-arm64-musl@4.40.1': '@rollup/rollup-linux-arm64-musl@4.52.5':
resolution: {integrity: sha512-jEwjn3jCA+tQGswK3aEWcD09/7M5wGwc6+flhva7dsQNRZZTe30vkalgIzV4tjkopsTS9Jd7Y1Bsj6a4lzz8gQ==} resolution: {integrity: sha512-AvttBOMwO9Pcuuf7m9PkC1PUIKsfaAJ4AYhy944qeTJgQOqJYJ9oVl2nYgY7Rk0mkbsuOpCAYSs6wLYB2Xiw0Q==}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
'@rollup/rollup-linux-loongarch64-gnu@4.40.1': '@rollup/rollup-linux-loong64-gnu@4.52.5':
resolution: {integrity: sha512-ySyWikVhNzv+BV/IDCsrraOAZ3UaC8SZB67FZlqVwXwnFhPihOso9rPOxzZbjp81suB1O2Topw+6Ug3JNegejQ==} resolution: {integrity: sha512-DkDk8pmXQV2wVrF6oq5tONK6UHLz/XcEVow4JTTerdeV1uqPeHxwcg7aFsfnSm9L+OO8WJsWotKM2JJPMWrQtA==}
cpu: [loong64] cpu: [loong64]
os: [linux] os: [linux]
'@rollup/rollup-linux-powerpc64le-gnu@4.40.1': '@rollup/rollup-linux-ppc64-gnu@4.52.5':
resolution: {integrity: sha512-BvvA64QxZlh7WZWqDPPdt0GH4bznuL6uOO1pmgPnnv86rpUpc8ZxgZwcEgXvo02GRIZX1hQ0j0pAnhwkhwPqWg==} resolution: {integrity: sha512-W/b9ZN/U9+hPQVvlGwjzi+Wy4xdoH2I8EjaCkMvzpI7wJUs8sWJ03Rq96jRnHkSrcHTpQe8h5Tg3ZzUPGauvAw==}
cpu: [ppc64] cpu: [ppc64]
os: [linux] os: [linux]
'@rollup/rollup-linux-riscv64-gnu@4.40.1': '@rollup/rollup-linux-riscv64-gnu@4.52.5':
resolution: {integrity: sha512-EQSP+8+1VuSulm9RKSMKitTav89fKbHymTf25n5+Yr6gAPZxYWpj3DzAsQqoaHAk9YX2lwEyAf9S4W8F4l3VBQ==} resolution: {integrity: sha512-sjQLr9BW7R/ZiXnQiWPkErNfLMkkWIoCz7YMn27HldKsADEKa5WYdobaa1hmN6slu9oWQbB6/jFpJ+P2IkVrmw==}
cpu: [riscv64] cpu: [riscv64]
os: [linux] os: [linux]
'@rollup/rollup-linux-riscv64-musl@4.40.1': '@rollup/rollup-linux-riscv64-musl@4.52.5':
resolution: {integrity: sha512-n/vQ4xRZXKuIpqukkMXZt9RWdl+2zgGNx7Uda8NtmLJ06NL8jiHxUawbwC+hdSq1rrw/9CghCpEONor+l1e2gA==} resolution: {integrity: sha512-hq3jU/kGyjXWTvAh2awn8oHroCbrPm8JqM7RUpKjalIRWWXE01CQOf/tUNWNHjmbMHg/hmNCwc/Pz3k1T/j/Lg==}
cpu: [riscv64] cpu: [riscv64]
os: [linux] os: [linux]
'@rollup/rollup-linux-s390x-gnu@4.40.1': '@rollup/rollup-linux-s390x-gnu@4.52.5':
resolution: {integrity: sha512-h8d28xzYb98fMQKUz0w2fMc1XuGzLLjdyxVIbhbil4ELfk5/orZlSTpF/xdI9C8K0I8lCkq+1En2RJsawZekkg==} resolution: {integrity: sha512-gn8kHOrku8D4NGHMK1Y7NA7INQTRdVOntt1OCYypZPRt6skGbddska44K8iocdpxHTMMNui5oH4elPH4QOLrFQ==}
cpu: [s390x] cpu: [s390x]
os: [linux] os: [linux]
'@rollup/rollup-linux-x64-gnu@4.40.1': '@rollup/rollup-linux-x64-gnu@4.52.5':
resolution: {integrity: sha512-XiK5z70PEFEFqcNj3/zRSz/qX4bp4QIraTy9QjwJAb/Z8GM7kVUsD0Uk8maIPeTyPCP03ChdI+VVmJriKYbRHQ==} resolution: {integrity: sha512-hXGLYpdhiNElzN770+H2nlx+jRog8TyynpTVzdlc6bndktjKWyZyiCsuDAlpd+j+W+WNqfcyAWz9HxxIGfZm1Q==}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
'@rollup/rollup-linux-x64-musl@4.40.1': '@rollup/rollup-linux-x64-musl@4.52.5':
resolution: {integrity: sha512-2BRORitq5rQ4Da9blVovzNCMaUlyKrzMSvkVR0D4qPuOy/+pMCrh1d7o01RATwVy+6Fa1WBw+da7QPeLWU/1mQ==} resolution: {integrity: sha512-arCGIcuNKjBoKAXD+y7XomR9gY6Mw7HnFBv5Rw7wQRvwYLR7gBAgV7Mb2QTyjXfTveBNFAtPt46/36vV9STLNg==}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
'@rollup/rollup-win32-arm64-msvc@4.40.1': '@rollup/rollup-openharmony-arm64@4.52.5':
resolution: {integrity: sha512-b2bcNm9Kbde03H+q+Jjw9tSfhYkzrDUf2d5MAd1bOJuVplXvFhWz7tRtWvD8/ORZi7qSCy0idW6tf2HgxSXQSg==} resolution: {integrity: sha512-QoFqB6+/9Rly/RiPjaomPLmR/13cgkIGfA40LHly9zcH1S0bN2HVFYk3a1eAyHQyjs3ZJYlXvIGtcCs5tko9Cw==}
cpu: [arm64]
os: [openharmony]
'@rollup/rollup-win32-arm64-msvc@4.52.5':
resolution: {integrity: sha512-w0cDWVR6MlTstla1cIfOGyl8+qb93FlAVutcor14Gf5Md5ap5ySfQ7R9S/NjNaMLSFdUnKGEasmVnu3lCMqB7w==}
cpu: [arm64] cpu: [arm64]
os: [win32] os: [win32]
'@rollup/rollup-win32-ia32-msvc@4.40.1': '@rollup/rollup-win32-ia32-msvc@4.52.5':
resolution: {integrity: sha512-DfcogW8N7Zg7llVEfpqWMZcaErKfsj9VvmfSyRjCyo4BI3wPEfrzTtJkZG6gKP/Z92wFm6rz2aDO7/JfiR/whA==} resolution: {integrity: sha512-Aufdpzp7DpOTULJCuvzqcItSGDH73pF3ko/f+ckJhxQyHtp67rHw3HMNxoIdDMUITJESNE6a8uh4Lo4SLouOUg==}
cpu: [ia32] cpu: [ia32]
os: [win32] os: [win32]
'@rollup/rollup-win32-x64-msvc@4.40.1': '@rollup/rollup-win32-x64-gnu@4.52.5':
resolution: {integrity: sha512-ECyOuDeH3C1I8jH2MK1RtBJW+YPMvSfT0a5NN0nHfQYnDSJ6tUiZH3gzwVP5/Kfh/+Tt7tpWVF9LXNTnhTJ3kA==} resolution: {integrity: sha512-UGBUGPFp1vkj6p8wCRraqNhqwX/4kNQPS57BCFc8wYh0g94iVIW33wJtQAx3G7vrjjNtRaxiMUylM0ktp/TRSQ==}
cpu: [x64]
os: [win32]
'@rollup/rollup-win32-x64-msvc@4.52.5':
resolution: {integrity: sha512-TAcgQh2sSkykPRWLrdyy2AiceMckNf5loITqXxFI5VuQjS5tSuw3WlwdN8qv8vzjLAUTvYaH/mVjSFpbkFbpTg==}
cpu: [x64] cpu: [x64]
os: [win32] os: [win32]
@@ -1191,6 +1207,9 @@ packages:
'@types/estree@1.0.7': '@types/estree@1.0.7':
resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==} resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==}
'@types/estree@1.0.8':
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
'@types/json-schema@7.0.15': '@types/json-schema@7.0.15':
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
@@ -1709,8 +1728,8 @@ packages:
resolution: {integrity: sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==} resolution: {integrity: sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==}
engines: {node: '>=0.12'} engines: {node: '>=0.12'}
esbuild@0.24.2: esbuild@0.25.11:
resolution: {integrity: sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==} resolution: {integrity: sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q==}
engines: {node: '>=18'} engines: {node: '>=18'}
hasBin: true hasBin: true
@@ -1852,6 +1871,15 @@ packages:
fastq@1.18.0: fastq@1.18.0:
resolution: {integrity: sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw==} resolution: {integrity: sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw==}
fdir@6.5.0:
resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
engines: {node: '>=12.0.0'}
peerDependencies:
picomatch: ^3 || ^4
peerDependenciesMeta:
picomatch:
optional: true
file-entry-cache@8.0.0: file-entry-cache@8.0.0:
resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==}
engines: {node: '>=16.0.0'} engines: {node: '>=16.0.0'}
@@ -2270,8 +2298,8 @@ packages:
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
engines: {node: '>=8.6'} engines: {node: '>=8.6'}
picomatch@4.0.2: picomatch@4.0.3:
resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==}
engines: {node: '>=12'} engines: {node: '>=12'}
pinia@2.3.1: pinia@2.3.1:
@@ -2403,8 +2431,8 @@ packages:
resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
engines: {iojs: '>=1.0.0', node: '>=0.10.0'} engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
rollup@4.40.1: rollup@4.52.5:
resolution: {integrity: sha512-C5VvvgCCyfyotVITIAv+4efVytl5F7wt+/I2i9q9GZcEXW9BP52YYOXC58igUi+LFZVHukErIIqQSWwv/M3WRw==} resolution: {integrity: sha512-3GuObel8h7Kqdjt0gxkEzaifHTqLVW56Y/bjN7PSQtkKr0w3V/QYSdt6QWYtd7A1xUtYQigtdUfgj1RvWVtorw==}
engines: {node: '>=18.0.0', npm: '>=8.0.0'} engines: {node: '>=18.0.0', npm: '>=8.0.0'}
hasBin: true hasBin: true
@@ -2513,6 +2541,10 @@ packages:
engines: {node: '>=10'} engines: {node: '>=10'}
hasBin: true hasBin: true
tinyglobby@0.2.15:
resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==}
engines: {node: '>=12.0.0'}
tldts-core@6.1.74: tldts-core@6.1.74:
resolution: {integrity: sha512-gTwtY6L2GfuxiL4CWpLknv9JDYYqBvKCk/BT5uAaAvCA0s6pzX7lr2IrkQZSUlnSjRHIjTl8ZwKCVXJ7XNRWYw==} resolution: {integrity: sha512-gTwtY6L2GfuxiL4CWpLknv9JDYYqBvKCk/BT5uAaAvCA0s6pzX7lr2IrkQZSUlnSjRHIjTl8ZwKCVXJ7XNRWYw==}
@@ -2657,8 +2689,8 @@ packages:
peerDependencies: peerDependencies:
vite: ^2.0.0||^3.0.0||^4.0.0||^5.0.0 ||^6.0.0 vite: ^2.0.0||^3.0.0||^4.0.0||^5.0.0 ||^6.0.0
vite@6.1.6: vite@6.4.1:
resolution: {integrity: sha512-u+jokLMwHVFUoUkfL+m/1hzucejL2639g9QXcrRdtN3WPHfW7imI83V96Oh1R0xVZqDjvcgp+7S8bSQpdVlmPA==} resolution: {integrity: sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==}
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
hasBin: true hasBin: true
peerDependencies: peerDependencies:
@@ -3582,79 +3614,82 @@ snapshots:
'@csstools/css-tokenizer@3.0.3': {} '@csstools/css-tokenizer@3.0.3': {}
'@esbuild/aix-ppc64@0.24.2': '@esbuild/aix-ppc64@0.25.11':
optional: true optional: true
'@esbuild/android-arm64@0.24.2': '@esbuild/android-arm64@0.25.11':
optional: true optional: true
'@esbuild/android-arm@0.24.2': '@esbuild/android-arm@0.25.11':
optional: true optional: true
'@esbuild/android-x64@0.24.2': '@esbuild/android-x64@0.25.11':
optional: true optional: true
'@esbuild/darwin-arm64@0.24.2': '@esbuild/darwin-arm64@0.25.11':
optional: true optional: true
'@esbuild/darwin-x64@0.24.2': '@esbuild/darwin-x64@0.25.11':
optional: true optional: true
'@esbuild/freebsd-arm64@0.24.2': '@esbuild/freebsd-arm64@0.25.11':
optional: true optional: true
'@esbuild/freebsd-x64@0.24.2': '@esbuild/freebsd-x64@0.25.11':
optional: true optional: true
'@esbuild/linux-arm64@0.24.2': '@esbuild/linux-arm64@0.25.11':
optional: true optional: true
'@esbuild/linux-arm@0.24.2': '@esbuild/linux-arm@0.25.11':
optional: true optional: true
'@esbuild/linux-ia32@0.24.2': '@esbuild/linux-ia32@0.25.11':
optional: true optional: true
'@esbuild/linux-loong64@0.24.2': '@esbuild/linux-loong64@0.25.11':
optional: true optional: true
'@esbuild/linux-mips64el@0.24.2': '@esbuild/linux-mips64el@0.25.11':
optional: true optional: true
'@esbuild/linux-ppc64@0.24.2': '@esbuild/linux-ppc64@0.25.11':
optional: true optional: true
'@esbuild/linux-riscv64@0.24.2': '@esbuild/linux-riscv64@0.25.11':
optional: true optional: true
'@esbuild/linux-s390x@0.24.2': '@esbuild/linux-s390x@0.25.11':
optional: true optional: true
'@esbuild/linux-x64@0.24.2': '@esbuild/linux-x64@0.25.11':
optional: true optional: true
'@esbuild/netbsd-arm64@0.24.2': '@esbuild/netbsd-arm64@0.25.11':
optional: true optional: true
'@esbuild/netbsd-x64@0.24.2': '@esbuild/netbsd-x64@0.25.11':
optional: true optional: true
'@esbuild/openbsd-arm64@0.24.2': '@esbuild/openbsd-arm64@0.25.11':
optional: true optional: true
'@esbuild/openbsd-x64@0.24.2': '@esbuild/openbsd-x64@0.25.11':
optional: true optional: true
'@esbuild/sunos-x64@0.24.2': '@esbuild/openharmony-arm64@0.25.11':
optional: true optional: true
'@esbuild/win32-arm64@0.24.2': '@esbuild/sunos-x64@0.25.11':
optional: true optional: true
'@esbuild/win32-ia32@0.24.2': '@esbuild/win32-arm64@0.25.11':
optional: true optional: true
'@esbuild/win32-x64@0.24.2': '@esbuild/win32-ia32@0.25.11':
optional: true
'@esbuild/win32-x64@0.25.11':
optional: true optional: true
'@eslint-community/eslint-utils@4.4.1(eslint@9.31.0)': '@eslint-community/eslint-utils@4.4.1(eslint@9.31.0)':
@@ -3754,13 +3789,13 @@ snapshots:
'@intlify/shared@11.1.7': {} '@intlify/shared@11.1.7': {}
'@intlify/unplugin-vue-i18n@6.0.8(@vue/compiler-dom@3.5.17)(eslint@9.31.0)(rollup@4.40.1)(typescript@5.6.3)(vue-i18n@11.1.10(vue@3.5.17(typescript@5.6.3)))(vue@3.5.17(typescript@5.6.3))': '@intlify/unplugin-vue-i18n@6.0.8(@vue/compiler-dom@3.5.17)(eslint@9.31.0)(rollup@4.52.5)(typescript@5.6.3)(vue-i18n@11.1.10(vue@3.5.17(typescript@5.6.3)))(vue@3.5.17(typescript@5.6.3))':
dependencies: dependencies:
'@eslint-community/eslint-utils': 4.4.1(eslint@9.31.0) '@eslint-community/eslint-utils': 4.4.1(eslint@9.31.0)
'@intlify/bundle-utils': 10.0.1(vue-i18n@11.1.10(vue@3.5.17(typescript@5.6.3))) '@intlify/bundle-utils': 10.0.1(vue-i18n@11.1.10(vue@3.5.17(typescript@5.6.3)))
'@intlify/shared': 11.1.7 '@intlify/shared': 11.1.7
'@intlify/vue-i18n-extensions': 8.0.0(@intlify/shared@11.1.7)(@vue/compiler-dom@3.5.17)(vue-i18n@11.1.10(vue@3.5.17(typescript@5.6.3)))(vue@3.5.17(typescript@5.6.3)) '@intlify/vue-i18n-extensions': 8.0.0(@intlify/shared@11.1.7)(@vue/compiler-dom@3.5.17)(vue-i18n@11.1.10(vue@3.5.17(typescript@5.6.3)))(vue@3.5.17(typescript@5.6.3))
'@rollup/pluginutils': 5.1.4(rollup@4.40.1) '@rollup/pluginutils': 5.1.4(rollup@4.52.5)
'@typescript-eslint/scope-manager': 8.21.0 '@typescript-eslint/scope-manager': 8.21.0
'@typescript-eslint/typescript-estree': 8.21.0(typescript@5.6.3) '@typescript-eslint/typescript-estree': 8.21.0(typescript@5.6.3)
debug: 4.4.0 debug: 4.4.0
@@ -3836,80 +3871,86 @@ snapshots:
dependencies: dependencies:
playwright: 1.54.1 playwright: 1.54.1
'@rollup/pluginutils@5.1.3(rollup@4.40.1)': '@rollup/pluginutils@5.1.3(rollup@4.52.5)':
dependencies: dependencies:
'@types/estree': 1.0.6 '@types/estree': 1.0.6
estree-walker: 2.0.2 estree-walker: 2.0.2
picomatch: 4.0.2 picomatch: 4.0.3
optionalDependencies: optionalDependencies:
rollup: 4.40.1 rollup: 4.52.5
'@rollup/pluginutils@5.1.4(rollup@4.40.1)': '@rollup/pluginutils@5.1.4(rollup@4.52.5)':
dependencies: dependencies:
'@types/estree': 1.0.7 '@types/estree': 1.0.7
estree-walker: 2.0.2 estree-walker: 2.0.2
picomatch: 4.0.2 picomatch: 4.0.3
optionalDependencies: optionalDependencies:
rollup: 4.40.1 rollup: 4.52.5
'@rollup/rollup-android-arm-eabi@4.40.1': '@rollup/rollup-android-arm-eabi@4.52.5':
optional: true optional: true
'@rollup/rollup-android-arm64@4.40.1': '@rollup/rollup-android-arm64@4.52.5':
optional: true optional: true
'@rollup/rollup-darwin-arm64@4.40.1': '@rollup/rollup-darwin-arm64@4.52.5':
optional: true optional: true
'@rollup/rollup-darwin-x64@4.40.1': '@rollup/rollup-darwin-x64@4.52.5':
optional: true optional: true
'@rollup/rollup-freebsd-arm64@4.40.1': '@rollup/rollup-freebsd-arm64@4.52.5':
optional: true optional: true
'@rollup/rollup-freebsd-x64@4.40.1': '@rollup/rollup-freebsd-x64@4.52.5':
optional: true optional: true
'@rollup/rollup-linux-arm-gnueabihf@4.40.1': '@rollup/rollup-linux-arm-gnueabihf@4.52.5':
optional: true optional: true
'@rollup/rollup-linux-arm-musleabihf@4.40.1': '@rollup/rollup-linux-arm-musleabihf@4.52.5':
optional: true optional: true
'@rollup/rollup-linux-arm64-gnu@4.40.1': '@rollup/rollup-linux-arm64-gnu@4.52.5':
optional: true optional: true
'@rollup/rollup-linux-arm64-musl@4.40.1': '@rollup/rollup-linux-arm64-musl@4.52.5':
optional: true optional: true
'@rollup/rollup-linux-loongarch64-gnu@4.40.1': '@rollup/rollup-linux-loong64-gnu@4.52.5':
optional: true optional: true
'@rollup/rollup-linux-powerpc64le-gnu@4.40.1': '@rollup/rollup-linux-ppc64-gnu@4.52.5':
optional: true optional: true
'@rollup/rollup-linux-riscv64-gnu@4.40.1': '@rollup/rollup-linux-riscv64-gnu@4.52.5':
optional: true optional: true
'@rollup/rollup-linux-riscv64-musl@4.40.1': '@rollup/rollup-linux-riscv64-musl@4.52.5':
optional: true optional: true
'@rollup/rollup-linux-s390x-gnu@4.40.1': '@rollup/rollup-linux-s390x-gnu@4.52.5':
optional: true optional: true
'@rollup/rollup-linux-x64-gnu@4.40.1': '@rollup/rollup-linux-x64-gnu@4.52.5':
optional: true optional: true
'@rollup/rollup-linux-x64-musl@4.40.1': '@rollup/rollup-linux-x64-musl@4.52.5':
optional: true optional: true
'@rollup/rollup-win32-arm64-msvc@4.40.1': '@rollup/rollup-openharmony-arm64@4.52.5':
optional: true optional: true
'@rollup/rollup-win32-ia32-msvc@4.40.1': '@rollup/rollup-win32-arm64-msvc@4.52.5':
optional: true optional: true
'@rollup/rollup-win32-x64-msvc@4.40.1': '@rollup/rollup-win32-ia32-msvc@4.52.5':
optional: true
'@rollup/rollup-win32-x64-gnu@4.52.5':
optional: true
'@rollup/rollup-win32-x64-msvc@4.52.5':
optional: true optional: true
'@tsconfig/node22@22.0.2': {} '@tsconfig/node22@22.0.2': {}
@@ -3918,6 +3959,8 @@ snapshots:
'@types/estree@1.0.7': {} '@types/estree@1.0.7': {}
'@types/estree@1.0.8': {}
'@types/json-schema@7.0.15': {} '@types/json-schema@7.0.15': {}
'@types/localforage@0.0.34': '@types/localforage@0.0.34':
@@ -4080,7 +4123,7 @@ snapshots:
global: 4.4.0 global: 4.4.0
is-function: 1.0.2 is-function: 1.0.2
'@vitejs/plugin-legacy@6.0.0(terser@5.43.1)(vite@6.1.6(@types/node@22.10.10)(terser@5.43.1)(yaml@2.7.0))': '@vitejs/plugin-legacy@6.0.0(terser@5.43.1)(vite@6.4.1(@types/node@22.10.10)(terser@5.43.1)(yaml@2.7.0))':
dependencies: dependencies:
'@babel/core': 7.26.0 '@babel/core': 7.26.0
'@babel/preset-env': 7.26.0(@babel/core@7.26.0) '@babel/preset-env': 7.26.0(@babel/core@7.26.0)
@@ -4091,13 +4134,13 @@ snapshots:
regenerator-runtime: 0.14.1 regenerator-runtime: 0.14.1
systemjs: 6.15.1 systemjs: 6.15.1
terser: 5.43.1 terser: 5.43.1
vite: 6.1.6(@types/node@22.10.10)(terser@5.43.1)(yaml@2.7.0) vite: 6.4.1(@types/node@22.10.10)(terser@5.43.1)(yaml@2.7.0)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@vitejs/plugin-vue@5.2.1(vite@6.1.6(@types/node@22.10.10)(terser@5.43.1)(yaml@2.7.0))(vue@3.5.17(typescript@5.6.3))': '@vitejs/plugin-vue@5.2.1(vite@6.4.1(@types/node@22.10.10)(terser@5.43.1)(yaml@2.7.0))(vue@3.5.17(typescript@5.6.3))':
dependencies: dependencies:
vite: 6.1.6(@types/node@22.10.10)(terser@5.43.1)(yaml@2.7.0) vite: 6.4.1(@types/node@22.10.10)(terser@5.43.1)(yaml@2.7.0)
vue: 3.5.17(typescript@5.6.3) vue: 3.5.17(typescript@5.6.3)
'@volar/language-core@2.4.11': '@volar/language-core@2.4.11':
@@ -4513,33 +4556,34 @@ snapshots:
d: 1.0.2 d: 1.0.2
ext: 1.7.0 ext: 1.7.0
esbuild@0.24.2: esbuild@0.25.11:
optionalDependencies: optionalDependencies:
'@esbuild/aix-ppc64': 0.24.2 '@esbuild/aix-ppc64': 0.25.11
'@esbuild/android-arm': 0.24.2 '@esbuild/android-arm': 0.25.11
'@esbuild/android-arm64': 0.24.2 '@esbuild/android-arm64': 0.25.11
'@esbuild/android-x64': 0.24.2 '@esbuild/android-x64': 0.25.11
'@esbuild/darwin-arm64': 0.24.2 '@esbuild/darwin-arm64': 0.25.11
'@esbuild/darwin-x64': 0.24.2 '@esbuild/darwin-x64': 0.25.11
'@esbuild/freebsd-arm64': 0.24.2 '@esbuild/freebsd-arm64': 0.25.11
'@esbuild/freebsd-x64': 0.24.2 '@esbuild/freebsd-x64': 0.25.11
'@esbuild/linux-arm': 0.24.2 '@esbuild/linux-arm': 0.25.11
'@esbuild/linux-arm64': 0.24.2 '@esbuild/linux-arm64': 0.25.11
'@esbuild/linux-ia32': 0.24.2 '@esbuild/linux-ia32': 0.25.11
'@esbuild/linux-loong64': 0.24.2 '@esbuild/linux-loong64': 0.25.11
'@esbuild/linux-mips64el': 0.24.2 '@esbuild/linux-mips64el': 0.25.11
'@esbuild/linux-ppc64': 0.24.2 '@esbuild/linux-ppc64': 0.25.11
'@esbuild/linux-riscv64': 0.24.2 '@esbuild/linux-riscv64': 0.25.11
'@esbuild/linux-s390x': 0.24.2 '@esbuild/linux-s390x': 0.25.11
'@esbuild/linux-x64': 0.24.2 '@esbuild/linux-x64': 0.25.11
'@esbuild/netbsd-arm64': 0.24.2 '@esbuild/netbsd-arm64': 0.25.11
'@esbuild/netbsd-x64': 0.24.2 '@esbuild/netbsd-x64': 0.25.11
'@esbuild/openbsd-arm64': 0.24.2 '@esbuild/openbsd-arm64': 0.25.11
'@esbuild/openbsd-x64': 0.24.2 '@esbuild/openbsd-x64': 0.25.11
'@esbuild/sunos-x64': 0.24.2 '@esbuild/openharmony-arm64': 0.25.11
'@esbuild/win32-arm64': 0.24.2 '@esbuild/sunos-x64': 0.25.11
'@esbuild/win32-ia32': 0.24.2 '@esbuild/win32-arm64': 0.25.11
'@esbuild/win32-x64': 0.24.2 '@esbuild/win32-ia32': 0.25.11
'@esbuild/win32-x64': 0.25.11
escalade@3.2.0: {} escalade@3.2.0: {}
@@ -4711,6 +4755,10 @@ snapshots:
dependencies: dependencies:
reusify: 1.0.4 reusify: 1.0.4
fdir@6.5.0(picomatch@4.0.3):
optionalDependencies:
picomatch: 4.0.3
file-entry-cache@8.0.0: file-entry-cache@8.0.0:
dependencies: dependencies:
flat-cache: 4.0.1 flat-cache: 4.0.1
@@ -5100,7 +5148,7 @@ snapshots:
picomatch@2.3.1: {} picomatch@2.3.1: {}
picomatch@4.0.2: {} picomatch@4.0.3: {}
pinia@2.3.1(typescript@5.6.3)(vue@3.5.17(typescript@5.6.3)): pinia@2.3.1(typescript@5.6.3)(vue@3.5.17(typescript@5.6.3)):
dependencies: dependencies:
@@ -5226,30 +5274,32 @@ snapshots:
reusify@1.0.4: {} reusify@1.0.4: {}
rollup@4.40.1: rollup@4.52.5:
dependencies: dependencies:
'@types/estree': 1.0.7 '@types/estree': 1.0.8
optionalDependencies: optionalDependencies:
'@rollup/rollup-android-arm-eabi': 4.40.1 '@rollup/rollup-android-arm-eabi': 4.52.5
'@rollup/rollup-android-arm64': 4.40.1 '@rollup/rollup-android-arm64': 4.52.5
'@rollup/rollup-darwin-arm64': 4.40.1 '@rollup/rollup-darwin-arm64': 4.52.5
'@rollup/rollup-darwin-x64': 4.40.1 '@rollup/rollup-darwin-x64': 4.52.5
'@rollup/rollup-freebsd-arm64': 4.40.1 '@rollup/rollup-freebsd-arm64': 4.52.5
'@rollup/rollup-freebsd-x64': 4.40.1 '@rollup/rollup-freebsd-x64': 4.52.5
'@rollup/rollup-linux-arm-gnueabihf': 4.40.1 '@rollup/rollup-linux-arm-gnueabihf': 4.52.5
'@rollup/rollup-linux-arm-musleabihf': 4.40.1 '@rollup/rollup-linux-arm-musleabihf': 4.52.5
'@rollup/rollup-linux-arm64-gnu': 4.40.1 '@rollup/rollup-linux-arm64-gnu': 4.52.5
'@rollup/rollup-linux-arm64-musl': 4.40.1 '@rollup/rollup-linux-arm64-musl': 4.52.5
'@rollup/rollup-linux-loongarch64-gnu': 4.40.1 '@rollup/rollup-linux-loong64-gnu': 4.52.5
'@rollup/rollup-linux-powerpc64le-gnu': 4.40.1 '@rollup/rollup-linux-ppc64-gnu': 4.52.5
'@rollup/rollup-linux-riscv64-gnu': 4.40.1 '@rollup/rollup-linux-riscv64-gnu': 4.52.5
'@rollup/rollup-linux-riscv64-musl': 4.40.1 '@rollup/rollup-linux-riscv64-musl': 4.52.5
'@rollup/rollup-linux-s390x-gnu': 4.40.1 '@rollup/rollup-linux-s390x-gnu': 4.52.5
'@rollup/rollup-linux-x64-gnu': 4.40.1 '@rollup/rollup-linux-x64-gnu': 4.52.5
'@rollup/rollup-linux-x64-musl': 4.40.1 '@rollup/rollup-linux-x64-musl': 4.52.5
'@rollup/rollup-win32-arm64-msvc': 4.40.1 '@rollup/rollup-openharmony-arm64': 4.52.5
'@rollup/rollup-win32-ia32-msvc': 4.40.1 '@rollup/rollup-win32-arm64-msvc': 4.52.5
'@rollup/rollup-win32-x64-msvc': 4.40.1 '@rollup/rollup-win32-ia32-msvc': 4.52.5
'@rollup/rollup-win32-x64-gnu': 4.52.5
'@rollup/rollup-win32-x64-msvc': 4.52.5
fsevents: 2.3.3 fsevents: 2.3.3
rrweb-cssom@0.8.0: {} rrweb-cssom@0.8.0: {}
@@ -5340,6 +5390,11 @@ snapshots:
commander: 2.20.3 commander: 2.20.3
source-map-support: 0.5.21 source-map-support: 0.5.21
tinyglobby@0.2.15:
dependencies:
fdir: 6.5.0(picomatch@4.0.3)
picomatch: 4.0.3
tldts-core@6.1.74: {} tldts-core@6.1.74: {}
tldts@6.1.74: tldts@6.1.74:
@@ -5481,19 +5536,22 @@ snapshots:
dependencies: dependencies:
global: 4.4.0 global: 4.4.0
vite-plugin-compression2@1.3.3(rollup@4.40.1)(vite@6.1.6(@types/node@22.10.10)(terser@5.43.1)(yaml@2.7.0)): vite-plugin-compression2@1.3.3(rollup@4.52.5)(vite@6.4.1(@types/node@22.10.10)(terser@5.43.1)(yaml@2.7.0)):
dependencies: dependencies:
'@rollup/pluginutils': 5.1.3(rollup@4.40.1) '@rollup/pluginutils': 5.1.3(rollup@4.52.5)
tar-mini: 0.2.0 tar-mini: 0.2.0
vite: 6.1.6(@types/node@22.10.10)(terser@5.43.1)(yaml@2.7.0) vite: 6.4.1(@types/node@22.10.10)(terser@5.43.1)(yaml@2.7.0)
transitivePeerDependencies: transitivePeerDependencies:
- rollup - rollup
vite@6.1.6(@types/node@22.10.10)(terser@5.43.1)(yaml@2.7.0): vite@6.4.1(@types/node@22.10.10)(terser@5.43.1)(yaml@2.7.0):
dependencies: dependencies:
esbuild: 0.24.2 esbuild: 0.25.11
fdir: 6.5.0(picomatch@4.0.3)
picomatch: 4.0.3
postcss: 8.5.6 postcss: 8.5.6
rollup: 4.40.1 rollup: 4.52.5
tinyglobby: 0.2.15
optionalDependencies: optionalDependencies:
'@types/node': 22.10.10 '@types/node': 22.10.10
fsevents: 2.3.3 fsevents: 2.3.3

View File

@@ -13,7 +13,7 @@ export default async function search(base: string, query: string) {
let data = await res.json(); let data = await res.json();
data = data.map((item: UploadItem) => { data = data.map((item: ResourceItem & { dir: boolean }) => {
item.url = `/files${base}` + url.encodePath(item.path); item.url = `/files${base}` + url.encodePath(item.path);
if (item.dir) { if (item.dir) {

View File

@@ -1,17 +1,11 @@
import * as tus from "tus-js-client"; import * as tus from "tus-js-client";
import { baseURL, tusEndpoint, tusSettings, origin } from "@/utils/constants"; import { baseURL, tusEndpoint, tusSettings, origin } from "@/utils/constants";
import { useAuthStore } from "@/stores/auth"; import { useAuthStore } from "@/stores/auth";
import { useUploadStore } from "@/stores/upload";
import { removePrefix } from "@/api/utils"; import { removePrefix } from "@/api/utils";
const RETRY_BASE_DELAY = 1000; const RETRY_BASE_DELAY = 1000;
const RETRY_MAX_DELAY = 20000; const RETRY_MAX_DELAY = 20000;
const SPEED_UPDATE_INTERVAL = 1000; const CURRENT_UPLOAD_LIST: { [key: string]: tus.Upload } = {};
const ALPHA = 0.2;
const ONE_MINUS_ALPHA = 1 - ALPHA;
const RECENT_SPEEDS_LIMIT = 5;
const MB_DIVISOR = 1024 * 1024;
const CURRENT_UPLOAD_LIST: CurrentUploadList = {};
export async function upload( export async function upload(
filePath: string, filePath: string,
@@ -55,48 +49,35 @@ export async function upload(
return true; return true;
}, },
onError: function (error) { onError: function (error: Error | tus.DetailedError) {
if (CURRENT_UPLOAD_LIST[filePath].interval) {
clearInterval(CURRENT_UPLOAD_LIST[filePath].interval);
}
delete CURRENT_UPLOAD_LIST[filePath]; delete CURRENT_UPLOAD_LIST[filePath];
reject(new Error(`Upload failed: ${error.message}`));
if (error.message === "Upload aborted") {
return reject(error);
}
const message =
error instanceof tus.DetailedError
? error.originalResponse === null
? "000 No connection"
: error.originalResponse.getBody()
: "Upload failed";
console.error(error);
reject(new Error(message));
}, },
onProgress: function (bytesUploaded) { onProgress: function (bytesUploaded) {
const fileData = CURRENT_UPLOAD_LIST[filePath];
fileData.currentBytesUploaded = bytesUploaded;
if (!fileData.hasStarted) {
fileData.hasStarted = true;
fileData.lastProgressTimestamp = Date.now();
fileData.interval = window.setInterval(() => {
calcProgress(filePath);
}, SPEED_UPDATE_INTERVAL);
}
if (typeof onupload === "function") { if (typeof onupload === "function") {
onupload({ loaded: bytesUploaded }); onupload({ loaded: bytesUploaded });
} }
}, },
onSuccess: function () { onSuccess: function () {
if (CURRENT_UPLOAD_LIST[filePath].interval) {
clearInterval(CURRENT_UPLOAD_LIST[filePath].interval);
}
delete CURRENT_UPLOAD_LIST[filePath]; delete CURRENT_UPLOAD_LIST[filePath];
resolve(); resolve();
}, },
}); });
CURRENT_UPLOAD_LIST[filePath] = { CURRENT_UPLOAD_LIST[filePath] = upload;
upload: upload,
recentSpeeds: [],
initialBytesUploaded: 0,
currentBytesUploaded: 0,
currentAverageSpeed: 0,
lastProgressTimestamp: null,
sumOfRecentSpeeds: 0,
hasStarted: false,
interval: undefined,
};
upload.start(); upload.start();
}); });
} }
@@ -128,76 +109,11 @@ function isTusSupported() {
return tus.isSupported === true; return tus.isSupported === true;
} }
function computeETA(speed?: number) {
const state = useUploadStore();
if (state.speedMbyte === 0) {
return Infinity;
}
const totalSize = state.sizes.reduce(
(acc: number, size: number) => acc + size,
0
);
const uploadedSize = state.progress.reduce((a, b) => a + b, 0);
const remainingSize = totalSize - uploadedSize;
const speedBytesPerSecond = (speed ?? state.speedMbyte) * 1024 * 1024;
return remainingSize / speedBytesPerSecond;
}
function computeGlobalSpeedAndETA() {
let totalSpeed = 0;
let totalCount = 0;
for (const filePath in CURRENT_UPLOAD_LIST) {
totalSpeed += CURRENT_UPLOAD_LIST[filePath].currentAverageSpeed;
totalCount++;
}
if (totalCount === 0) return { speed: 0, eta: Infinity };
const averageSpeed = totalSpeed / totalCount;
const averageETA = computeETA(averageSpeed);
return { speed: averageSpeed, eta: averageETA };
}
function calcProgress(filePath: string) {
const uploadStore = useUploadStore();
const fileData = CURRENT_UPLOAD_LIST[filePath];
const elapsedTime =
(Date.now() - (fileData.lastProgressTimestamp ?? 0)) / 1000;
const bytesSinceLastUpdate =
fileData.currentBytesUploaded - fileData.initialBytesUploaded;
const currentSpeed = bytesSinceLastUpdate / MB_DIVISOR / elapsedTime;
if (fileData.recentSpeeds.length >= RECENT_SPEEDS_LIMIT) {
fileData.sumOfRecentSpeeds -= fileData.recentSpeeds.shift() ?? 0;
}
fileData.recentSpeeds.push(currentSpeed);
fileData.sumOfRecentSpeeds += currentSpeed;
const avgRecentSpeed =
fileData.sumOfRecentSpeeds / fileData.recentSpeeds.length;
fileData.currentAverageSpeed =
ALPHA * avgRecentSpeed + ONE_MINUS_ALPHA * fileData.currentAverageSpeed;
const { speed, eta } = computeGlobalSpeedAndETA();
uploadStore.setUploadSpeed(speed);
uploadStore.setETA(eta);
fileData.initialBytesUploaded = fileData.currentBytesUploaded;
fileData.lastProgressTimestamp = Date.now();
}
export function abortAllUploads() { export function abortAllUploads() {
for (const filePath in CURRENT_UPLOAD_LIST) { for (const filePath in CURRENT_UPLOAD_LIST) {
if (CURRENT_UPLOAD_LIST[filePath].interval) { if (CURRENT_UPLOAD_LIST[filePath]) {
clearInterval(CURRENT_UPLOAD_LIST[filePath].interval); CURRENT_UPLOAD_LIST[filePath].abort(true);
} CURRENT_UPLOAD_LIST[filePath].options!.onError!(
if (CURRENT_UPLOAD_LIST[filePath].upload) {
CURRENT_UPLOAD_LIST[filePath].upload.abort(true);
CURRENT_UPLOAD_LIST[filePath].upload.options!.onError!(
new Error("Upload aborted") new Error("Upload aborted")
); );
} }

View File

@@ -91,3 +91,21 @@ export function createURL(endpoint: string, searchParams = {}): string {
return url.toString(); return url.toString();
} }
export function setSafeTimeout(callback: () => void, delay: number): number {
const MAX_DELAY = 86_400_000;
let remaining = delay;
function scheduleNext(): number {
if (remaining <= MAX_DELAY) {
return window.setTimeout(callback, remaining);
} else {
return window.setTimeout(() => {
remaining -= MAX_DELAY;
scheduleNext();
}, MAX_DELAY);
}
}
return scheduleNext();
}

View File

@@ -132,7 +132,6 @@ import {
import { files as api } from "@/api"; import { files as api } from "@/api";
import ProgressBar from "@/components/ProgressBar.vue"; import ProgressBar from "@/components/ProgressBar.vue";
import prettyBytes from "pretty-bytes"; import prettyBytes from "pretty-bytes";
import { StatusError } from "@/api/utils.js";
const USAGE_DEFAULT = { used: "0 B", total: "0 B", usedPercentage: 0 }; const USAGE_DEFAULT = { used: "0 B", total: "0 B", usedPercentage: 0 };
@@ -181,13 +180,9 @@ export default {
total: prettyBytes(usage.total, { binary: true }), total: prettyBytes(usage.total, { binary: true }),
usedPercentage: Math.round((usage.used / usage.total) * 100), usedPercentage: Math.round((usage.used / usage.total) * 100),
}; };
} catch (error) { } finally {
if (error instanceof StatusError && error.is_canceled) { return Object.assign(this.usage, usageStats);
return;
}
this.$showError(error);
} }
return Object.assign(this.usage, usageStats);
}, },
toRoot() { toRoot() {
this.$router.push({ path: "/files" }); this.$router.push({ path: "/files" });

View File

@@ -0,0 +1,86 @@
<template>
<div>
<div class="path-container" ref="container">
<template v-for="(item, index) in path" :key="index">
/
<span class="path-item">
<span
v-if="isDir === true || index < path.length - 1"
class="material-icons"
>folder
</span>
<span v-else class="material-icons">insert_drive_file</span>
{{ item }}
</span>
</template>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, computed, watch, nextTick, defineProps } from "vue";
import { useRoute } from "vue-router";
import { useFileStore } from "@/stores/file";
import url from "@/utils/url";
const fileStore = useFileStore();
const route = useRoute();
const props = defineProps({
name: {
type: String,
required: true,
},
isDir: {
type: Boolean,
default: false,
},
});
const container = ref<HTMLElement | null>(null);
const path = computed(() => {
let basePath = fileStore.isFiles ? route.path : url.removeLastDir(route.path);
if (!basePath.endsWith("/")) {
basePath += "/";
}
basePath += props.name;
return basePath.split("/").filter(Boolean).splice(1);
});
watch(path, () => {
nextTick(() => {
const lastItem = container.value?.lastElementChild;
lastItem?.scrollIntoView({ behavior: "auto", inline: "end" });
});
});
</script>
<style scoped>
.path-container {
display: flex;
align-items: center;
margin: 0.2em 0;
gap: 0.25em;
overflow-x: auto;
max-width: 100%;
scrollbar-width: none;
opacity: 0.5;
}
.path-container::-webkit-scrollbar {
display: none;
}
.path-item {
display: flex;
align-items: center;
margin: 0.2em 0;
gap: 0.25em;
white-space: nowrap;
}
.path-item > span {
font-size: 0.9em;
}
</style>

View File

@@ -11,17 +11,26 @@
@click="closeHovers" @click="closeHovers"
:aria-label="$t('buttons.cancel')" :aria-label="$t('buttons.cancel')"
:title="$t('buttons.cancel')" :title="$t('buttons.cancel')"
tabindex="2" tabindex="3"
> >
{{ $t("buttons.cancel") }} {{ $t("buttons.cancel") }}
</button> </button>
<button
class="button button--flat button--blue"
@click="currentPrompt.saveAction"
:aria-label="$t('buttons.saveChanges')"
:title="$t('buttons.saveChanges')"
tabindex="1"
>
{{ $t("buttons.saveChanges") }}
</button>
<button <button
id="focus-prompt" id="focus-prompt"
@click="currentPrompt.confirm" @click="currentPrompt.confirm"
class="button button--flat button--red" class="button button--flat button--red"
:aria-label="$t('buttons.discardChanges')" :aria-label="$t('buttons.discardChanges')"
:title="$t('buttons.discardChanges')" :title="$t('buttons.discardChanges')"
tabindex="1" tabindex="2"
> >
{{ $t("buttons.discardChanges") }} {{ $t("buttons.discardChanges") }}
</button> </button>
@@ -30,8 +39,8 @@
</template> </template>
<script> <script>
import { mapState, mapActions } from "pinia";
import { useLayoutStore } from "@/stores/layout"; import { useLayoutStore } from "@/stores/layout";
import { mapActions, mapState } from "pinia";
export default { export default {
name: "discardEditorChanges", name: "discardEditorChanges",

View File

@@ -25,9 +25,10 @@
</template> </template>
<script> <script>
import { mapState } from "pinia"; import { mapState, mapActions } from "pinia";
import { useAuthStore } from "@/stores/auth"; import { useAuthStore } from "@/stores/auth";
import { useFileStore } from "@/stores/file"; import { useFileStore } from "@/stores/file";
import { useLayoutStore } from "@/stores/layout";
import url from "@/utils/url"; import url from "@/utils/url";
import { files } from "@/api"; import { files } from "@/api";
@@ -68,6 +69,7 @@ export default {
this.abortOngoingNext(); this.abortOngoingNext();
}, },
methods: { methods: {
...mapActions(useLayoutStore, ["showHover"]),
abortOngoingNext() { abortOngoingNext() {
this.nextAbortController.abort(); this.nextAbortController.abort();
}, },
@@ -163,7 +165,7 @@ export default {
this.$emit("update:selected", this.selected); this.$emit("update:selected", this.selected);
}, },
createDir: async function () { createDir: async function () {
this.$store.commit("showHover", { this.showHover({
prompt: "newDir", prompt: "newDir",
action: null, action: null,
confirm: null, confirm: null,

View File

@@ -14,6 +14,7 @@
v-model.trim="name" v-model.trim="name"
tabindex="1" tabindex="1"
/> />
<CreateFilePath :name="name" :is-dir="true" />
</div> </div>
<div class="card-action"> <div class="card-action">
@@ -48,6 +49,7 @@ import { files as api } from "@/api";
import url from "@/utils/url"; import url from "@/utils/url";
import { useRoute, useRouter } from "vue-router"; import { useRoute, useRouter } from "vue-router";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import CreateFilePath from "@/components/prompts/CreateFilePath.vue";
const $showError = inject<IToastError>("$showError")!; const $showError = inject<IToastError>("$showError")!;

View File

@@ -13,6 +13,7 @@
@keyup.enter="submit" @keyup.enter="submit"
v-model.trim="name" v-model.trim="name"
/> />
<CreateFilePath :name="name" />
</div> </div>
<div class="card-action"> <div class="card-action">
@@ -42,6 +43,7 @@ import { useI18n } from "vue-i18n";
import { useRoute, useRouter } from "vue-router"; import { useRoute, useRouter } from "vue-router";
import { useFileStore } from "@/stores/file"; import { useFileStore } from "@/stores/file";
import { useLayoutStore } from "@/stores/layout"; import { useLayoutStore } from "@/stores/layout";
import CreateFilePath from "@/components/prompts/CreateFilePath.vue";
import { files as api } from "@/api"; import { files as api } from "@/api";
import url from "@/utils/url"; import url from "@/utils/url";

View File

@@ -1,20 +1,25 @@
<template> <template>
<div <div
v-if="filesInUploadCount > 0" v-if="uploadStore.activeUploads.size > 0"
class="upload-files" class="upload-files"
v-bind:class="{ closed: !open }" v-bind:class="{ closed: !open }"
> >
<div class="card floating"> <div class="card floating">
<div class="card-title"> <div class="card-title">
<h2>{{ $t("prompts.uploadFiles", { files: filesInUploadCount }) }}</h2> <h2>
{{
$t("prompts.uploadFiles", {
files: uploadStore.pendingUploadCount,
})
}}
</h2>
<div class="upload-info"> <div class="upload-info">
<div class="upload-speed">{{ uploadSpeed.toFixed(2) }} MB/s</div> <div class="upload-speed">{{ speedText }}/s</div>
<div class="upload-eta">{{ formattedETA }} remaining</div> <div class="upload-eta">{{ formattedETA }} remaining</div>
<div class="upload-percentage"> <div class="upload-percentage">{{ sentPercent }}% Completed</div>
{{ getProgressDecimal }}% Completed
</div>
<div class="upload-fraction"> <div class="upload-fraction">
{{ getTotalProgressBytes }} / {{ getTotalSize }} {{ sentMbytes }} /
{{ totalMbytes }}
</div> </div>
</div> </div>
<button <button
@@ -40,17 +45,21 @@
<div class="card-content file-icons"> <div class="card-content file-icons">
<div <div
class="file" class="file"
v-for="file in filesInUpload" v-for="upload in uploadStore.activeUploads"
:key="file.id" :key="upload.path"
:data-dir="file.isDir" :data-dir="upload.type === 'dir'"
:data-type="file.type" :data-type="upload.type"
:aria-label="file.name" :aria-label="upload.name"
> >
<div class="file-name"> <div class="file-name">
<i class="material-icons"></i> {{ file.name }} <i class="material-icons"></i> {{ upload.name }}
</div> </div>
<div class="file-progress"> <div class="file-progress">
<div v-bind:style="{ width: file.progress + '%' }"></div> <div
v-bind:style="{
width: (upload.sentBytes / upload.totalBytes) * 100 + '%',
}"
></div>
</div> </div>
</div> </div>
</div> </div>
@@ -58,63 +67,149 @@
</div> </div>
</template> </template>
<script> <script setup lang="ts">
import { mapState, mapWritableState, mapActions } from "pinia";
import { useUploadStore } from "@/stores/upload";
import { useFileStore } from "@/stores/file"; import { useFileStore } from "@/stores/file";
import { abortAllUploads } from "@/api/tus"; import { useUploadStore } from "@/stores/upload";
import { storeToRefs } from "pinia";
import { computed, ref, watch } from "vue";
import buttons from "@/utils/buttons"; import buttons from "@/utils/buttons";
import { useI18n } from "vue-i18n";
import { partial } from "filesize";
export default { const { t } = useI18n({});
name: "uploadFiles",
data: function () {
return {
open: false,
};
},
computed: {
...mapState(useUploadStore, [
"filesInUpload",
"filesInUploadCount",
"uploadSpeed",
"getETA",
"getProgress",
"getProgressDecimal",
"getTotalProgressBytes",
"getTotalSize",
]),
...mapWritableState(useFileStore, ["reload"]),
formattedETA() {
if (!this.getETA || this.getETA === Infinity) {
return "--:--:--";
}
let totalSeconds = this.getETA; const open = ref<boolean>(false);
const hours = Math.floor(totalSeconds / 3600); const speed = ref<number>(0);
totalSeconds %= 3600; const eta = ref<number>(Infinity);
const minutes = Math.floor(totalSeconds / 60);
const seconds = Math.round(totalSeconds % 60);
return `${hours.toString().padStart(2, "0")}:${minutes const fileStore = useFileStore();
.toString() const uploadStore = useUploadStore();
.padStart(2, "0")}:${seconds.toString().padStart(2, "0")}`;
}, const { sentBytes, totalBytes } = storeToRefs(uploadStore);
},
methods: { const byteToMbyte = partial({ exponent: 2 });
...mapActions(useUploadStore, ["reset"]), // Mapping reset action from upload store const byteToKbyte = partial({ exponent: 1 });
toggle: function () {
this.open = !this.open; const sentPercent = computed(() =>
}, ((uploadStore.sentBytes / uploadStore.totalBytes) * 100).toFixed(2)
abortAll() { );
if (confirm(this.$t("upload.abortUpload"))) {
abortAllUploads(); const sentMbytes = computed(() => byteToMbyte(uploadStore.sentBytes));
buttons.done("upload"); const totalMbytes = computed(() => byteToMbyte(uploadStore.totalBytes));
this.open = false; const speedText = computed(() => {
this.reset(); // Resetting the upload store state const bytes = speed.value;
this.reload = true; // Trigger reload in the file store
} if (bytes < 1024 * 1024) {
}, const kb = parseFloat(byteToKbyte(bytes));
}, return `${kb.toFixed(2)} KB`;
} else {
const mb = parseFloat(byteToMbyte(bytes));
return `${mb.toFixed(2)} MB`;
}
});
let lastSpeedUpdate: number = 0;
let recentSpeeds: number[] = [];
let lastThrottleTime = 0;
const throttledCalculateSpeed = (sentBytes: number, oldSentBytes: number) => {
const now = Date.now();
if (now - lastThrottleTime < 100) {
return;
}
lastThrottleTime = now;
calculateSpeed(sentBytes, oldSentBytes);
};
const calculateSpeed = (sentBytes: number, oldSentBytes: number) => {
// Reset the state when the uploads batch is complete
if (sentBytes === 0) {
lastSpeedUpdate = 0;
recentSpeeds = [];
eta.value = Infinity;
speed.value = 0;
return;
}
const elapsedTime = (Date.now() - (lastSpeedUpdate ?? 0)) / 1000;
const bytesSinceLastUpdate = sentBytes - oldSentBytes;
const currentSpeed = bytesSinceLastUpdate / elapsedTime;
recentSpeeds.push(currentSpeed);
if (recentSpeeds.length > 5) {
recentSpeeds.shift();
}
const recentSpeedsAverage =
recentSpeeds.reduce((acc, curr) => acc + curr) / recentSpeeds.length;
// Use the current speed for the first update to avoid smoothing lag
if (recentSpeeds.length === 1) {
speed.value = currentSpeed;
}
speed.value = recentSpeedsAverage * 0.2 + speed.value * 0.8;
lastSpeedUpdate = Date.now();
calculateEta();
};
const calculateEta = () => {
if (speed.value === 0) {
eta.value = Infinity;
return Infinity;
}
const remainingSize = uploadStore.totalBytes - uploadStore.sentBytes;
const speedBytesPerSecond = speed.value;
eta.value = remainingSize / speedBytesPerSecond;
};
watch(sentBytes, throttledCalculateSpeed);
watch(totalBytes, (totalBytes, oldTotalBytes) => {
if (oldTotalBytes !== 0) {
return;
}
// Mark the start time of a new upload batch
lastSpeedUpdate = Date.now();
});
const formattedETA = computed(() => {
if (!eta.value || eta.value === Infinity) {
return "--:--:--";
}
let totalSeconds = eta.value;
const hours = Math.floor(totalSeconds / 3600);
totalSeconds %= 3600;
const minutes = Math.floor(totalSeconds / 60);
const seconds = Math.round(totalSeconds % 60);
return `${hours.toString().padStart(2, "0")}:${minutes
.toString()
.padStart(2, "0")}:${seconds.toString().padStart(2, "0")}`;
});
const toggle = () => {
open.value = !open.value;
};
const abortAll = () => {
if (confirm(t("upload.abortUpload"))) {
buttons.done("upload");
open.value = false;
uploadStore.abort();
fileStore.reload = true; // Trigger reload in the file store
}
}; };
</script> </script>

View File

@@ -0,0 +1,24 @@
<template>
<select name="selectAceEditorTheme" v-on:change="change" :value="aceEditorTheme">
<option v-for="theme in themes" :value="theme.theme" :key="theme.theme">
{{ theme.name }}
</option>
</select>
</template>
<script setup lang="ts">
import { type SelectHTMLAttributes } from "vue";
import { themes } from "ace-builds/src-noconflict/ext-themelist";
defineProps<{
aceEditorTheme: string;
}>();
const emit = defineEmits<{
(e: "update:aceEditorTheme", val: string | null): void;
}>();
const change = (event: Event) => {
emit("update:aceEditorTheme", (event.target as SelectHTMLAttributes)?.value);
};
</script>

View File

@@ -45,6 +45,15 @@
animation: 0.2s opac forwards; animation: 0.2s opac forwards;
} }
#login .logout-message {
background: var(--icon-orange);
color: #fff;
padding: 0.5em;
text-align: center;
animation: 0.2s opac forwards;
text-transform: none;
}
@keyframes opac { @keyframes opac {
0% { 0% {
opacity: 0; opacity: 0;

View File

@@ -1,6 +1,4 @@
.md_preview { .md_preview {
overflow-y: auto;
max-height: 80vh;
padding: 1rem; padding: 1rem;
border: 1px solid #000; border: 1px solid #000;
font-size: 20px; font-size: 20px;
@@ -9,5 +7,5 @@
#preview-container { #preview-container {
overflow: auto; overflow: auto;
max-height: 80vh; /* Match the max-height of md_preview for scrolling */ flex: 1;
} }

View File

@@ -42,7 +42,8 @@
"update": "تحديث", "update": "تحديث",
"upload": "رفع", "upload": "رفع",
"openFile": "فتح الملف", "openFile": "فتح الملف",
"discardChanges": "إلغاء التغييرات" "discardChanges": "إلغاء التغييرات",
"saveChanges": "Save changes"
}, },
"download": { "download": {
"downloadFile": "تحميل الملف", "downloadFile": "تحميل الملف",
@@ -100,7 +101,10 @@
"submit": "تسجيل دخول", "submit": "تسجيل دخول",
"username": "إسم المستخدم", "username": "إسم المستخدم",
"usernameTaken": "إسم المستخدم غير متاح", "usernameTaken": "إسم المستخدم غير متاح",
"wrongCredentials": "بيانات دخول خاطئة" "wrongCredentials": "بيانات دخول خاطئة",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
}, },
"permanent": "دائم", "permanent": "دائم",
"prompts": { "prompts": {
@@ -154,6 +158,7 @@
"video": "فيديوهات" "video": "فيديوهات"
}, },
"settings": { "settings": {
"aceEditorTheme": "Ace editor theme",
"admin": "إدارة", "admin": "إدارة",
"administrator": "مدير", "administrator": "مدير",
"allowCommands": "تنفيذ اﻷوامر", "allowCommands": "تنفيذ اﻷوامر",

View File

@@ -42,7 +42,8 @@
"update": "Actualitzar", "update": "Actualitzar",
"upload": "Pujar", "upload": "Pujar",
"openFile": "Obrir fitxer", "openFile": "Obrir fitxer",
"discardChanges": "Descartar" "discardChanges": "Descartar",
"saveChanges": "Save changes"
}, },
"download": { "download": {
"downloadFile": "Descarregar fitxer", "downloadFile": "Descarregar fitxer",
@@ -100,7 +101,10 @@
"submit": "Iniciar sessió", "submit": "Iniciar sessió",
"username": "Usuari", "username": "Usuari",
"usernameTaken": "Nom d'usuari no disponible", "usernameTaken": "Nom d'usuari no disponible",
"wrongCredentials": "Usuari i/o contrasenya incorrectes" "wrongCredentials": "Usuari i/o contrasenya incorrectes",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
}, },
"permanent": "Permanent", "permanent": "Permanent",
"prompts": { "prompts": {
@@ -154,6 +158,7 @@
"video": "Vídeo" "video": "Vídeo"
}, },
"settings": { "settings": {
"aceEditorTheme": "Ace editor theme",
"admin": "Admin", "admin": "Admin",
"administrator": "Administrador", "administrator": "Administrador",
"allowCommands": "Executar comandes", "allowCommands": "Executar comandes",

View File

@@ -42,7 +42,8 @@
"update": "Aktualizovat", "update": "Aktualizovat",
"upload": "Nahrát", "upload": "Nahrát",
"openFile": "Otevřít soubor", "openFile": "Otevřít soubor",
"discardChanges": "Zrušit změny" "discardChanges": "Zrušit změny",
"saveChanges": "Save changes"
}, },
"download": { "download": {
"downloadFile": "Stáhnout soubor", "downloadFile": "Stáhnout soubor",
@@ -100,7 +101,10 @@
"submit": "Přihlásit se", "submit": "Přihlásit se",
"username": "Uživatelské jméno", "username": "Uživatelské jméno",
"usernameTaken": "Uživatelské jméno již existuje", "usernameTaken": "Uživatelské jméno již existuje",
"wrongCredentials": "Nesprávné přihlašovací údaje" "wrongCredentials": "Nesprávné přihlašovací údaje",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
}, },
"permanent": "Trvalý", "permanent": "Trvalý",
"prompts": { "prompts": {
@@ -154,6 +158,7 @@
"video": "Video" "video": "Video"
}, },
"settings": { "settings": {
"aceEditorTheme": "Ace editor theme",
"admin": "Admin", "admin": "Admin",
"administrator": "Administrátor", "administrator": "Administrátor",
"allowCommands": "Povolit příkazy", "allowCommands": "Povolit příkazy",

View File

@@ -42,7 +42,8 @@
"update": "Update", "update": "Update",
"upload": "Upload", "upload": "Upload",
"openFile": "Datei öffnen", "openFile": "Datei öffnen",
"discardChanges": "Verwerfen" "discardChanges": "Verwerfen",
"saveChanges": "Save changes"
}, },
"download": { "download": {
"downloadFile": "Download Datei", "downloadFile": "Download Datei",
@@ -100,7 +101,10 @@
"submit": "Login", "submit": "Login",
"username": "Benutzername", "username": "Benutzername",
"usernameTaken": "Benutzername ist bereits vergeben", "usernameTaken": "Benutzername ist bereits vergeben",
"wrongCredentials": "Falsche Zugangsdaten" "wrongCredentials": "Falsche Zugangsdaten",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
}, },
"permanent": "Permanent", "permanent": "Permanent",
"prompts": { "prompts": {
@@ -154,6 +158,7 @@
"video": "Video" "video": "Video"
}, },
"settings": { "settings": {
"aceEditorTheme": "Ace editor theme",
"admin": "Admin", "admin": "Admin",
"administrator": "Administrator", "administrator": "Administrator",
"allowCommands": "Befehle ausführen", "allowCommands": "Befehle ausführen",

View File

@@ -42,7 +42,8 @@
"update": "Ενημέρωση", "update": "Ενημέρωση",
"upload": "Μεταφόρτωση", "upload": "Μεταφόρτωση",
"openFile": "Άνοιγμα αρχείου", "openFile": "Άνοιγμα αρχείου",
"discardChanges": "Discard" "discardChanges": "Discard",
"saveChanges": "Save changes"
}, },
"download": { "download": {
"downloadFile": "Λήψη αρχείου", "downloadFile": "Λήψη αρχείου",
@@ -100,7 +101,10 @@
"submit": "Είσοδος", "submit": "Είσοδος",
"username": "Όνομα χρήστη", "username": "Όνομα χρήστη",
"usernameTaken": "Το όνομα χρήστη χρησιμοποιείται ήδη", "usernameTaken": "Το όνομα χρήστη χρησιμοποιείται ήδη",
"wrongCredentials": "Λάθος όνομα ή/και κωδικός πρόσβασης" "wrongCredentials": "Λάθος όνομα ή/και κωδικός πρόσβασης",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
}, },
"permanent": "Μόνιμο", "permanent": "Μόνιμο",
"prompts": { "prompts": {
@@ -154,6 +158,7 @@
"video": "Βίντεο" "video": "Βίντεο"
}, },
"settings": { "settings": {
"aceEditorTheme": "Ace editor theme",
"admin": "Διαχειριστής", "admin": "Διαχειριστής",
"administrator": "Διαχειριστής", "administrator": "Διαχειριστής",
"allowCommands": "Εκτέλεση εντολών", "allowCommands": "Εκτέλεση εντολών",

View File

@@ -42,7 +42,8 @@
"update": "Update", "update": "Update",
"upload": "Upload", "upload": "Upload",
"openFile": "Open file", "openFile": "Open file",
"discardChanges": "Discard" "discardChanges": "Discard",
"saveChanges": "Save changes"
}, },
"download": { "download": {
"downloadFile": "Download File", "downloadFile": "Download File",
@@ -100,7 +101,10 @@
"submit": "Login", "submit": "Login",
"username": "Username", "username": "Username",
"usernameTaken": "Username already taken", "usernameTaken": "Username already taken",
"wrongCredentials": "Wrong credentials" "wrongCredentials": "Wrong credentials",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
}, },
"permanent": "Permanent", "permanent": "Permanent",
"prompts": { "prompts": {
@@ -154,6 +158,7 @@
"video": "Video" "video": "Video"
}, },
"settings": { "settings": {
"aceEditorTheme": "Ace editor theme",
"admin": "Admin", "admin": "Admin",
"administrator": "Administrator", "administrator": "Administrator",
"allowCommands": "Execute commands", "allowCommands": "Execute commands",

View File

@@ -7,7 +7,7 @@
"copy": "Copiar", "copy": "Copiar",
"copyFile": "Copiar archivo", "copyFile": "Copiar archivo",
"copyToClipboard": "Copiar al portapapeles", "copyToClipboard": "Copiar al portapapeles",
"copyDownloadLinkToClipboard": "Copy download link to clipboard", "copyDownloadLinkToClipboard": "Copiar enlace de descarga al portapapeles",
"create": "Crear", "create": "Crear",
"delete": "Borrar", "delete": "Borrar",
"download": "Descargar", "download": "Descargar",
@@ -42,7 +42,8 @@
"update": "Actualizar", "update": "Actualizar",
"upload": "Subir", "upload": "Subir",
"openFile": "Abrir archivo", "openFile": "Abrir archivo",
"discardChanges": "Discard" "discardChanges": "Discard",
"saveChanges": "Guardar cambios"
}, },
"download": { "download": {
"downloadFile": "Descargar fichero", "downloadFile": "Descargar fichero",
@@ -100,7 +101,10 @@
"submit": "Iniciar sesión", "submit": "Iniciar sesión",
"username": "Usuario", "username": "Usuario",
"usernameTaken": "Nombre usuario no disponible", "usernameTaken": "Nombre usuario no disponible",
"wrongCredentials": "Usuario y/o contraseña incorrectos" "wrongCredentials": "Usuario y/o contraseña incorrectos",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
}, },
"permanent": "Permanente", "permanent": "Permanente",
"prompts": { "prompts": {
@@ -154,6 +158,7 @@
"video": "Vídeo" "video": "Vídeo"
}, },
"settings": { "settings": {
"aceEditorTheme": "Ace editor theme",
"admin": "Admin", "admin": "Admin",
"administrator": "Administrador", "administrator": "Administrador",
"allowCommands": "Ejecutar comandos", "allowCommands": "Ejecutar comandos",

View File

@@ -42,7 +42,8 @@
"update": "به روز سانی", "update": "به روز سانی",
"upload": "آپلود", "upload": "آپلود",
"openFile": "باز کردن فایل", "openFile": "باز کردن فایل",
"discardChanges": "لغو کردن" "discardChanges": "لغو کردن",
"saveChanges": "Save changes"
}, },
"download": { "download": {
"downloadFile": "دانلود فایل", "downloadFile": "دانلود فایل",
@@ -100,7 +101,10 @@
"submit": "ورود", "submit": "ورود",
"username": "نام کاربری", "username": "نام کاربری",
"usernameTaken": "نام کاربری تکراری", "usernameTaken": "نام کاربری تکراری",
"wrongCredentials": "خطا در اعتبارسنجی" "wrongCredentials": "خطا در اعتبارسنجی",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
}, },
"permanent": "دائمی", "permanent": "دائمی",
"prompts": { "prompts": {
@@ -154,6 +158,7 @@
"video": "ویدئو " "video": "ویدئو "
}, },
"settings": { "settings": {
"aceEditorTheme": "Ace editor theme",
"admin": "Admin", "admin": "Admin",
"administrator": "Administrator", "administrator": "Administrator",
"allowCommands": "اجرای دستورات", "allowCommands": "اجرای دستورات",

View File

@@ -42,7 +42,8 @@
"update": "Mettre à jour", "update": "Mettre à jour",
"upload": "Importer", "upload": "Importer",
"openFile": "Ouvrir le fichier", "openFile": "Ouvrir le fichier",
"discardChanges": "Annuler" "discardChanges": "Annuler",
"saveChanges": "Save changes"
}, },
"download": { "download": {
"downloadFile": "Télécharger le fichier", "downloadFile": "Télécharger le fichier",
@@ -77,14 +78,14 @@
"noPreview": "L'aperçu n'est pas disponible pour ce fichier." "noPreview": "L'aperçu n'est pas disponible pour ce fichier."
}, },
"help": { "help": {
"click": "Sélectionner un élément", "click": "Sélectionner un fichier ou dossier",
"ctrl": { "ctrl": {
"click": "Sélectionner plusieurs éléments", "click": "Sélectionner plusieurs fichiers ou dossiers",
"f": "Ouvrir l'invité de recherche", "f": "Ouvrir l'invité de recherche",
"s": "Télécharger l'élément actuel" "s": "Enregistrer un fichier ou télécharger le dossier actuel"
}, },
"del": "Supprimer les éléments sélectionnés", "del": "Supprimer les éléments sélectionnés",
"doubleClick": "Ouvrir un élément", "doubleClick": "Ouvrir un fichier ou dossier",
"esc": "Désélectionner et/ou fermer la boîte de dialogue", "esc": "Désélectionner et/ou fermer la boîte de dialogue",
"f1": "Ouvrir l'aide", "f1": "Ouvrir l'aide",
"f2": "Renommer le fichier", "f2": "Renommer le fichier",
@@ -98,9 +99,12 @@
"passwordsDontMatch": "Les mots de passe ne concordent pas", "passwordsDontMatch": "Les mots de passe ne concordent pas",
"signup": "S'inscrire", "signup": "S'inscrire",
"submit": "Se connecter", "submit": "Se connecter",
"username": "Utilisateur", "username": "Utilisateur·ice",
"usernameTaken": "Le nom d'utilisateur est déjà pris", "usernameTaken": "Le nom d'utilisateur·ice est déjà pris",
"wrongCredentials": "Identifiants incorrects !" "wrongCredentials": "Identifiants incorrects !",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
}, },
"permanent": "Permanent", "permanent": "Permanent",
"prompts": { "prompts": {
@@ -110,7 +114,7 @@
"deleteMessageMultiple": "Êtes-vous sûr de vouloir supprimer ces {count} élément(s) ?", "deleteMessageMultiple": "Êtes-vous sûr de vouloir supprimer ces {count} élément(s) ?",
"deleteMessageSingle": "Êtes-vous sûr de vouloir supprimer cet élément ?", "deleteMessageSingle": "Êtes-vous sûr de vouloir supprimer cet élément ?",
"deleteMessageShare": "Êtes-vous sûr de vouloir supprimer ce partage ({path}) ?", "deleteMessageShare": "Êtes-vous sûr de vouloir supprimer ce partage ({path}) ?",
"deleteUser": "Êtes-vous sûr de vouloir supprimer cet utilisateur ?", "deleteUser": "Êtes-vous sûr de vouloir supprimer cet·te utilisateur·ice ?",
"deleteTitle": "Supprimer", "deleteTitle": "Supprimer",
"displayName": "Nom :", "displayName": "Nom :",
"download": "Télécharger", "download": "Télécharger",
@@ -120,7 +124,7 @@
"filesSelected": "{count} éléments sélectionnés", "filesSelected": "{count} éléments sélectionnés",
"lastModified": "Dernière modification", "lastModified": "Dernière modification",
"move": "Déplacer", "move": "Déplacer",
"moveMessage": "Choisissez l'emplacement où déplacer la sélection :", "moveMessage": "Choisissez un nouveau dossier principal pour vos fichier(s)/dossier(s) :",
"newArchetype": "Créer un nouveau post basé sur un archétype. Votre fichier sera créé dans le dossier de contenu.", "newArchetype": "Créer un nouveau post basé sur un archétype. Votre fichier sera créé dans le dossier de contenu.",
"newDir": "Nouveau dossier", "newDir": "Nouveau dossier",
"newDirMessage": "Nom du nouveau dossier :", "newDirMessage": "Nom du nouveau dossier :",
@@ -154,13 +158,14 @@
"video": "Vidéo" "video": "Vidéo"
}, },
"settings": { "settings": {
"aceEditorTheme": "Ace editor theme",
"admin": "Admin", "admin": "Admin",
"administrator": "Administrateur", "administrator": "Administrateur·ice",
"allowCommands": "Exécuter des commandes", "allowCommands": "Exécuter des commandes",
"allowEdit": "Éditer, renommer et supprimer des fichiers ou des dossiers", "allowEdit": "Éditer, renommer et supprimer des fichiers ou des dossiers",
"allowNew": "Créer de nouveaux fichiers et dossiers", "allowNew": "Créer de nouveaux fichiers et dossiers",
"allowPublish": "Publier de nouveaux posts et pages", "allowPublish": "Publier de nouveaux posts et pages",
"allowSignup": "Autoriser les utilisateurs à s'inscrire", "allowSignup": "Autoriser les utilisateur·ices à s'inscrire",
"avoidChanges": "(Laisser vide pour conserver l'actuel)", "avoidChanges": "(Laisser vide pour conserver l'actuel)",
"branding": "Image de marque", "branding": "Image de marque",
"brandingDirectoryPath": "Chemin du dossier d'image de marque", "brandingDirectoryPath": "Chemin du dossier d'image de marque",
@@ -169,17 +174,17 @@
"commandRunner": "Exécuteur de commandes", "commandRunner": "Exécuteur de commandes",
"commandRunnerHelp": "Ici, vous pouvez définir les commandes qui seront exécutées lors des événements nommés précédemments. Vous devez en écrire une par ligne. Les variables d'environnement {0} et {1} seront disponibles, {0} étant relatif à {1}. Pour plus d'informations sur cette fonctionnalité et les variables d'environnement disponibles, veuillez lire la {2}.", "commandRunnerHelp": "Ici, vous pouvez définir les commandes qui seront exécutées lors des événements nommés précédemments. Vous devez en écrire une par ligne. Les variables d'environnement {0} et {1} seront disponibles, {0} étant relatif à {1}. Pour plus d'informations sur cette fonctionnalité et les variables d'environnement disponibles, veuillez lire la {2}.",
"commandsUpdated": "Commandes mises à jour !", "commandsUpdated": "Commandes mises à jour !",
"createUserDir": "Créer automatiquement un dossier pour l'utilisateur", "createUserDir": "Créer automatiquement un dossier pour l'utilisateur·ice",
"minimumPasswordLength": "Minimum password length", "minimumPasswordLength": "Taille minimale du mot de passe",
"tusUploads": "Uploads segmentés", "tusUploads": "Uploads segmentés",
"tusUploadsHelp": "File Browser prend en charge les uploads segmentés afin de permettre une gestion efficace, fiable et reprenable sur des réseaux instables.", "tusUploadsHelp": "File Browser prend en charge les uploads segmentés afin de permettre une gestion efficace, fiable et reprenable sur des réseaux instables.",
"tusUploadsChunkSize": "Taille maximale autorisée par segment (les uploads directs seront utilisés pour les fichiers plus petits). Vous pouvez entrer un entier en octets ou une chaîne telle que 10MB, 1GB, etc.", "tusUploadsChunkSize": "Taille maximale autorisée par segment (les uploads directs seront utilisés pour les fichiers plus petits). Vous pouvez entrer un entier en octets ou une chaîne telle que 10MB, 1GB, etc.",
"tusUploadsRetryCount": "Nombre de tentatives en cas d'échec d'un segment.", "tusUploadsRetryCount": "Nombre de tentatives en cas d'échec d'un segment.",
"userHomeBasePath": "Chemin de base pour les répertoires personnels des utilisateurs", "userHomeBasePath": "Chemin de base pour les dossiers personnels des utilisateur·ices",
"userScopeGenerationPlaceholder": "Le périmètre sera généré automatiquement", "userScopeGenerationPlaceholder": "Le périmètre sera généré automatiquement",
"createUserHomeDirectory": "Créer le répertoire personnel de l'utilisateur", "createUserHomeDirectory": "Créer le dossier personnel de l'utilisateur·ice",
"customStylesheet": "Feuille de style personnalisée", "customStylesheet": "Feuille de style personnalisée",
"defaultUserDescription": "Paramètres par défaut pour les nouveaux utilisateurs.", "defaultUserDescription": "Paramètres par défaut pour les nouveaux utilisateur·ices.",
"disableExternalLinks": "Désactiver les liens externes (sauf la documentation)", "disableExternalLinks": "Désactiver les liens externes (sauf la documentation)",
"disableUsedDiskPercentage": "Désactiver le graphique de pourcentage d'utilisation du disque", "disableUsedDiskPercentage": "Désactiver le graphique de pourcentage d'utilisation du disque",
"documentation": "documentation", "documentation": "documentation",
@@ -188,12 +193,12 @@
"executeOnShellDescription": "Par défaut, File Browser exécute les commandes en appelant directement leurs binaires. Si vous voulez les exécuter sur un shell à la place (comme Bash ou PowerShell), vous pouvez le définir ici avec les arguments et les drapeaux requis. S'il est défini, la commande que vous exécutez sera ajoutée en tant qu'argument. Cela s'applique à la fois aux commandes utilisateur et aux crochets d'événements.", "executeOnShellDescription": "Par défaut, File Browser exécute les commandes en appelant directement leurs binaires. Si vous voulez les exécuter sur un shell à la place (comme Bash ou PowerShell), vous pouvez le définir ici avec les arguments et les drapeaux requis. S'il est défini, la commande que vous exécutez sera ajoutée en tant qu'argument. Cela s'applique à la fois aux commandes utilisateur et aux crochets d'événements.",
"globalRules": "Il s'agit d'un ensemble global de règles d'autorisation et d'interdiction. Elles s'appliquent à tous les utilisateurs. Vous pouvez définir des règles spécifiques sur les paramètres de chaque utilisateur pour remplacer celles-ci.", "globalRules": "Il s'agit d'un ensemble global de règles d'autorisation et d'interdiction. Elles s'appliquent à tous les utilisateurs. Vous pouvez définir des règles spécifiques sur les paramètres de chaque utilisateur pour remplacer celles-ci.",
"globalSettings": "Paramètres globaux", "globalSettings": "Paramètres globaux",
"hideDotfiles": "Cacher les fichiers de configuration utilisateur (dotfiles)", "hideDotfiles": "Cacher les fichiers de configuration commançant par un point",
"insertPath": "Insérer le chemin", "insertPath": "Insérer le chemin",
"insertRegex": "Insérer une expression régulière", "insertRegex": "Insérer une expression régulière",
"instanceName": "Nom de l'instance", "instanceName": "Nom de l'instance",
"language": "Langue", "language": "Langue",
"lockPassword": "Empêcher l'utilisateur de changer son mot de passe", "lockPassword": "Empêcher l'utilisateur·ice de changer son mot de passe",
"newPassword": "Votre nouveau mot de passe", "newPassword": "Votre nouveau mot de passe",
"newPasswordConfirm": "Confirmation du nouveau mot de passe", "newPasswordConfirm": "Confirmation du nouveau mot de passe",
"newUser": "Nouvel utilisateur", "newUser": "Nouvel utilisateur",
@@ -210,13 +215,13 @@
"share": "Partager des fichiers" "share": "Partager des fichiers"
}, },
"permissions": "Permissions", "permissions": "Permissions",
"permissionsHelp": "Vous pouvez définir l'utilisateur comme étant un administrateur ou encore choisir les permissions individuellement. Si vous sélectionnez \"Administrateur\", toutes les autres options seront automatiquement activées. La gestion des utilisateurs est un privilège que seul l'administrateur possède.\n", "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", "profileSettings": "Paramètres du profil",
"ruleExample1": "Bloque l'accès à tous les fichiers commençant par un point (comme par exemple .git, .gitignore) dans tous les dossiers", "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", "ruleExample2": "Bloque l'accès au fichier nommé \"Caddyfile\" à la racine du dossier utilisateur·ice.",
"rules": "Règles", "rules": "Règles",
"rulesHelp": "Vous pouvez définir ici un ensemble de règles pour cet utilisateur. Les fichiers bloqués ne seront pas affichés et ne seront pas accessibles par l'utilisateur. Les expressions régulières sont supportées et les chemins d'accès sont relatifs par rapport au dossier de l'utilisateur.\n", "rulesHelp": "Vous pouvez définir ici un ensemble de règles pour cet utilisateur·ice. Les fichiers bloqués ne seront pas affichés et ne seront pas accessibles par l'utilisateur·ice. Les expressions régulières sont supportées et les chemins d'accès sont relatifs par rapport au dossier de l'utilisateur·ice.\n",
"scope": "Portée du dossier utilisateur", "scope": "Portée du dossier utilisateur·ice",
"setDateFormat": "Définir le format de la date", "setDateFormat": "Définir le format de la date",
"settingsUpdated": "Les paramètres ont été mis à jour !", "settingsUpdated": "Les paramètres ont été mis à jour !",
"shareDuration": "Durée du partage", "shareDuration": "Durée du partage",
@@ -224,21 +229,21 @@
"shareDeleted": "Partage supprimé !", "shareDeleted": "Partage supprimé !",
"singleClick": "Utiliser un simple clic pour ouvrir les fichiers et les dossiers", "singleClick": "Utiliser un simple clic pour ouvrir les fichiers et les dossiers",
"themes": { "themes": {
"default": "System default", "default": "Par défaut du système",
"dark": "Sombre", "dark": "Sombre",
"light": "Clair", "light": "Clair",
"title": "Thème" "title": "Thème"
}, },
"user": "Utilisateur", "user": "Utilisateur·ice",
"userCommands": "Commandes", "userCommands": "Commandes",
"userCommandsHelp": "Une liste séparée par des espaces des commandes permises pour l'utilisateur. Exemple :\n", "userCommandsHelp": "Une liste séparée par des espaces des commandes permises pour l'utilisateur·ice. Exemple :\n",
"userCreated": "Utilisateur créé !", "userCreated": "Utilisateur·ice créé !",
"userDefaults": "Paramètres par défaut de l'utilisateur", "userDefaults": "Paramètres par défaut de l'utilisateur.ice",
"userDeleted": "Utilisateur supprimé !", "userDeleted": "Utilisateur·ice supprimé !",
"userManagement": "Gestion des utilisateurs", "userManagement": "Gestion des utilisateur·ices",
"userUpdated": "Utilisateur mis à jour !", "userUpdated": "Utilisateur·ice mis à jour !",
"username": "Nom d'utilisateur", "username": "Nom d'utilisateur·ice",
"users": "Utilisateurs" "users": "Utilisateur·ices"
}, },
"sidebar": { "sidebar": {
"help": "Aide", "help": "Aide",

View File

@@ -42,7 +42,8 @@
"update": "עדכון", "update": "עדכון",
"upload": "העלאה", "upload": "העלאה",
"openFile": "פתח קובץ", "openFile": "פתח קובץ",
"discardChanges": "זריקת השינויים" "discardChanges": "זריקת השינויים",
"saveChanges": "Save changes"
}, },
"download": { "download": {
"downloadFile": "הורד קובץ", "downloadFile": "הורד קובץ",
@@ -100,7 +101,10 @@
"submit": "התחברות", "submit": "התחברות",
"username": "שם משתמש", "username": "שם משתמש",
"usernameTaken": "שם המשתמש כבר קיים", "usernameTaken": "שם המשתמש כבר קיים",
"wrongCredentials": "פרטי התחברות שגויים" "wrongCredentials": "פרטי התחברות שגויים",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
}, },
"permanent": "קבוע", "permanent": "קבוע",
"prompts": { "prompts": {
@@ -154,6 +158,7 @@
"video": "וידאו" "video": "וידאו"
}, },
"settings": { "settings": {
"aceEditorTheme": "Ace editor theme",
"admin": "מנהל", "admin": "מנהל",
"administrator": "מנהל ראשי", "administrator": "מנהל ראשי",
"allowCommands": "הפעלת פקודות", "allowCommands": "הפעלת פקודות",

View File

@@ -42,7 +42,8 @@
"update": "Frissítés", "update": "Frissítés",
"upload": "Feltöltés", "upload": "Feltöltés",
"openFile": "Fájl megnyitása", "openFile": "Fájl megnyitása",
"discardChanges": "Discard" "discardChanges": "Discard",
"saveChanges": "Save changes"
}, },
"download": { "download": {
"downloadFile": "Fájl letöltése", "downloadFile": "Fájl letöltése",
@@ -100,7 +101,10 @@
"submit": "Belépés", "submit": "Belépés",
"username": "Felhasználói név", "username": "Felhasználói név",
"usernameTaken": "A felhasználói név már foglalt", "usernameTaken": "A felhasználói név már foglalt",
"wrongCredentials": "Hibás hitelesítő adatok" "wrongCredentials": "Hibás hitelesítő adatok",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
}, },
"permanent": "Állandó", "permanent": "Állandó",
"prompts": { "prompts": {
@@ -154,6 +158,7 @@
"video": "Videó" "video": "Videó"
}, },
"settings": { "settings": {
"aceEditorTheme": "Ace editor theme",
"admin": "Admin", "admin": "Admin",
"administrator": "Adminisztrátor", "administrator": "Adminisztrátor",
"allowCommands": "Parancsok futtatása", "allowCommands": "Parancsok futtatása",

View File

@@ -42,7 +42,8 @@
"update": "Vista", "update": "Vista",
"upload": "Hlaða upp", "upload": "Hlaða upp",
"openFile": "Open file", "openFile": "Open file",
"discardChanges": "Discard" "discardChanges": "Discard",
"saveChanges": "Save changes"
}, },
"download": { "download": {
"downloadFile": "Sækja skjal", "downloadFile": "Sækja skjal",
@@ -100,7 +101,10 @@
"submit": "Innskráning", "submit": "Innskráning",
"username": "Notendanafn", "username": "Notendanafn",
"usernameTaken": "Þetta norendanafn er þegar í notkun", "usernameTaken": "Þetta norendanafn er þegar í notkun",
"wrongCredentials": "Rangar notendaupplýsingar" "wrongCredentials": "Rangar notendaupplýsingar",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
}, },
"permanent": "Varanlegt", "permanent": "Varanlegt",
"prompts": { "prompts": {
@@ -154,6 +158,7 @@
"video": "Myndbönd" "video": "Myndbönd"
}, },
"settings": { "settings": {
"aceEditorTheme": "Ace editor theme",
"admin": "Stjórnandi", "admin": "Stjórnandi",
"administrator": "Stjórnandi", "administrator": "Stjórnandi",
"allowCommands": "Senda skipanir", "allowCommands": "Senda skipanir",

View File

@@ -7,13 +7,13 @@
"copy": "Copia", "copy": "Copia",
"copyFile": "Copia file", "copyFile": "Copia file",
"copyToClipboard": "Copia negli appunti", "copyToClipboard": "Copia negli appunti",
"copyDownloadLinkToClipboard": "Copy download link to clipboard", "copyDownloadLinkToClipboard": "Copia link di scarica negli appunti",
"create": "Crea", "create": "Crea",
"delete": "Elimina", "delete": "Elimina",
"download": "Scarica", "download": "Scarica",
"file": "File", "file": "File",
"folder": "Folder", "folder": "Cartella",
"fullScreen": "Toggle full screen", "fullScreen": "Abilita schermo intero",
"hideDotfiles": "Nascondi dotfile", "hideDotfiles": "Nascondi dotfile",
"info": "Informazioni", "info": "Informazioni",
"more": "Altro", "more": "Altro",
@@ -24,7 +24,7 @@
"ok": "OK", "ok": "OK",
"permalink": "Ottieni link permanente", "permalink": "Ottieni link permanente",
"previous": "Precedente", "previous": "Precedente",
"preview": "Preview", "preview": "Anteprima",
"publish": "Publica", "publish": "Publica",
"rename": "Rinomina", "rename": "Rinomina",
"replace": "Sostituisci", "replace": "Sostituisci",
@@ -36,13 +36,14 @@
"selectMultiple": "Seleziona molteplici", "selectMultiple": "Seleziona molteplici",
"share": "Condividi", "share": "Condividi",
"shell": "Mostra/nascondi shell", "shell": "Mostra/nascondi shell",
"submit": "Submit", "submit": "Invia",
"switchView": "Cambia vista", "switchView": "Cambia vista",
"toggleSidebar": "Mostra/nascondi la barra laterale", "toggleSidebar": "Mostra/nascondi la barra laterale",
"update": "Aggiorna", "update": "Aggiorna",
"upload": "Carica", "upload": "Carica",
"openFile": "Open file", "openFile": "Apri file",
"discardChanges": "Discard" "discardChanges": "Ignora",
"saveChanges": "Save changes"
}, },
"download": { "download": {
"downloadFile": "Scarica file", "downloadFile": "Scarica file",
@@ -50,13 +51,13 @@
"downloadSelected": "Scarica selezionati" "downloadSelected": "Scarica selezionati"
}, },
"upload": { "upload": {
"abortUpload": "Are you sure you wish to abort?" "abortUpload": "Sei sicuro di voler abortire la procedura?"
}, },
"errors": { "errors": {
"forbidden": "Non hai i permessi per accedere a questo file.", "forbidden": "Non hai i permessi per accedere a questo file.",
"internal": "Qualcosa è andato veramente male.", "internal": "Qualcosa è andato veramente male.",
"notFound": "Questo percorso non può essere raggiunto.", "notFound": "Questo percorso non può essere raggiunto.",
"connection": "The server can't be reached." "connection": "Il server non è raggiungibile"
}, },
"files": { "files": {
"body": "Contenuto", "body": "Contenuto",
@@ -74,7 +75,7 @@
"sortByLastModified": "Ordina per ultima modifica", "sortByLastModified": "Ordina per ultima modifica",
"sortByName": "Ordina per nome", "sortByName": "Ordina per nome",
"sortBySize": "Ordina per dimensione", "sortBySize": "Ordina per dimensione",
"noPreview": "Preview is not available for this file." "noPreview": "L'anteprima non è disponibile per questo file."
}, },
"help": { "help": {
"click": "seleziona un file o una cartella", "click": "seleziona un file o una cartella",
@@ -100,7 +101,10 @@
"submit": "Entra", "submit": "Entra",
"username": "Nome utente", "username": "Nome utente",
"usernameTaken": "Username già usato", "usernameTaken": "Username già usato",
"wrongCredentials": "Credenziali errate" "wrongCredentials": "Credenziali errate",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
}, },
"permanent": "Permanente", "permanent": "Permanente",
"prompts": { "prompts": {
@@ -109,8 +113,8 @@
"currentlyNavigating": "Attualmente navigando su:", "currentlyNavigating": "Attualmente navigando su:",
"deleteMessageMultiple": "Sei sicuro di voler eliminare {count} file?", "deleteMessageMultiple": "Sei sicuro di voler eliminare {count} file?",
"deleteMessageSingle": "Sei sicuro di voler eliminare questo file/cartella?", "deleteMessageSingle": "Sei sicuro di voler eliminare questo file/cartella?",
"deleteMessageShare": "Are you sure you wish to delete this share({path})?", "deleteMessageShare": "Sei sicuro di voler eliminare questo percorso condiviso ({path})?",
"deleteUser": "Are you sure you want to delete this user?", "deleteUser": "Sei sicuro di voler eliminare questo utente?",
"deleteTitle": "Elimina", "deleteTitle": "Elimina",
"displayName": "Nome visualizzato:", "displayName": "Nome visualizzato:",
"download": "Scarica files", "download": "Scarica files",
@@ -137,11 +141,11 @@
"show": "Mostra", "show": "Mostra",
"size": "Dimensione", "size": "Dimensione",
"upload": "Carica", "upload": "Carica",
"uploadFiles": "Uploading {files} files...", "uploadFiles": "Inviando {files} file...",
"uploadMessage": "Seleziona un'opzione per il caricamento.", "uploadMessage": "Seleziona un'opzione per il caricamento.",
"optionalPassword": "Optional password", "optionalPassword": "Password opzionale",
"resolution": "Resolution", "resolution": "Risoluzione",
"discardEditorChanges": "Are you sure you wish to discard the changes you've made?" "discardEditorChanges": "Sei sicuro di voler scartare le modifiche apportate?"
}, },
"search": { "search": {
"images": "Immagini", "images": "Immagini",
@@ -154,6 +158,7 @@
"video": "Video" "video": "Video"
}, },
"settings": { "settings": {
"aceEditorTheme": "Ace editor theme",
"admin": "Admin", "admin": "Admin",
"administrator": "Amministratore", "administrator": "Amministratore",
"allowCommands": "Esegui comandi", "allowCommands": "Esegui comandi",
@@ -170,14 +175,14 @@
"commandRunnerHelp": "Qui puoi impostare i comandi da eseguire negli eventi nominati. Ne devi scrivere uno per riga. Le variabili d'ambiente {0} e {1} sono disponibili, essendo {0} relativo a {1}. Per altre informazioni su questa funzionalità e sulle variabili d'ambiente utilizzabili, leggi la {2}.", "commandRunnerHelp": "Qui puoi impostare i comandi da eseguire negli eventi nominati. Ne devi scrivere uno per riga. Le variabili d'ambiente {0} e {1} sono disponibili, essendo {0} relativo a {1}. Per altre informazioni su questa funzionalità e sulle variabili d'ambiente utilizzabili, leggi la {2}.",
"commandsUpdated": "Comandi aggiornati!", "commandsUpdated": "Comandi aggiornati!",
"createUserDir": "Crea automaticamente la home directory dell'utente quando lo aggiungi", "createUserDir": "Crea automaticamente la home directory dell'utente quando lo aggiungi",
"minimumPasswordLength": "Minimum password length", "minimumPasswordLength": "Lunghezza minima della password",
"tusUploads": "Chunked Uploads", "tusUploads": "Tranci di invii",
"tusUploadsHelp": "File Browser supports chunked file uploads, allowing for the creation of efficient, reliable, resumable and chunked file uploads even on unreliable networks.", "tusUploadsHelp": "File Browser supporta tranci di invii fornendo così la possibilità di inviare efficientemente i file anche su reti instabili.",
"tusUploadsChunkSize": "Indicates to maximum size of a request (direct uploads will be used for smaller uploads). You may input a plain integer denoting byte size input or a string like 10MB, 1GB etc.", "tusUploadsChunkSize": "Indica la dimensione massima di una richiesta (invii diretti saranno usati per piccoli invii). Puoi inserire un numero intero per indicare la dimensione in byte, oppure una stringa con l'unità di misura come in 10MB, 1GB, etc.",
"tusUploadsRetryCount": "Number of retries to perform if a chunk fails to upload.", "tusUploadsRetryCount": "Numero di tentativi da effettuare se un trancio di file fallisce.",
"userHomeBasePath": "Base path for user home directories", "userHomeBasePath": "Percorso base per le cartelle utente",
"userScopeGenerationPlaceholder": "The scope will be auto generated", "userScopeGenerationPlaceholder": "La portata verrà autogenerata",
"createUserHomeDirectory": "Create user home directory", "createUserHomeDirectory": "Crea cartella utente",
"customStylesheet": "Foglio di stile personalizzato", "customStylesheet": "Foglio di stile personalizzato",
"defaultUserDescription": "Queste sono le impostazioni predefinite per i nuovi utenti.", "defaultUserDescription": "Queste sono le impostazioni predefinite per i nuovi utenti.",
"disableExternalLinks": "Disabilita link esterni (tranne per la documentazione)", "disableExternalLinks": "Disabilita link esterni (tranne per la documentazione)",
@@ -217,14 +222,14 @@
"rules": "Regole", "rules": "Regole",
"rulesHelp": "Qui è possibile definire una serie di regole e permessi per questo specifico utente. I file bloccati non appariranno negli elenchi e non saranno accessibili dagli utenti. all'utente. Sia regex che i percorsi relativi all'ambito di applicazione degli utenti sono supportati.\n", "rulesHelp": "Qui è possibile definire una serie di regole e permessi per questo specifico utente. I file bloccati non appariranno negli elenchi e non saranno accessibili dagli utenti. all'utente. Sia regex che i percorsi relativi all'ambito di applicazione degli utenti sono supportati.\n",
"scope": "Scope", "scope": "Scope",
"setDateFormat": "Set exact date format", "setDateFormat": "Fissa il formato di data esatto",
"settingsUpdated": "Impostazioni aggiornate!", "settingsUpdated": "Impostazioni aggiornate!",
"shareDuration": "Durata della condivisione", "shareDuration": "Durata della condivisione",
"shareManagement": "Gestione delle condivisioni", "shareManagement": "Gestione delle condivisioni",
"shareDeleted": "Share deleted!", "shareDeleted": "Percorso condiviso eliminato!",
"singleClick": "Usa un singolo click per aprire file e cartelle", "singleClick": "Usa un singolo click per aprire file e cartelle",
"themes": { "themes": {
"default": "System default", "default": "Impostazione predefinita del sistema",
"dark": "Scuro", "dark": "Scuro",
"light": "Chiaro", "light": "Chiaro",
"title": "Tema" "title": "Tema"

View File

@@ -42,7 +42,8 @@
"update": "更新", "update": "更新",
"upload": "アップロード", "upload": "アップロード",
"openFile": "ファイルを開く", "openFile": "ファイルを開く",
"discardChanges": "Discard" "discardChanges": "Discard",
"saveChanges": "Save changes"
}, },
"download": { "download": {
"downloadFile": "ファイルのダウンロード", "downloadFile": "ファイルのダウンロード",
@@ -100,7 +101,10 @@
"submit": "ログイン", "submit": "ログイン",
"username": "ユーザー名", "username": "ユーザー名",
"usernameTaken": "ユーザー名はすでに取得されています", "usernameTaken": "ユーザー名はすでに取得されています",
"wrongCredentials": "ユーザー名またはパスワードが間違っています" "wrongCredentials": "ユーザー名またはパスワードが間違っています",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
}, },
"permanent": "永久", "permanent": "永久",
"prompts": { "prompts": {
@@ -154,6 +158,7 @@
"video": "動画" "video": "動画"
}, },
"settings": { "settings": {
"aceEditorTheme": "Ace editor theme",
"admin": "管理者", "admin": "管理者",
"administrator": "管理者", "administrator": "管理者",
"allowCommands": "コマンドの実行", "allowCommands": "コマンドの実行",

View File

@@ -3,17 +3,17 @@
"cancel": "취소", "cancel": "취소",
"clear": "지우기", "clear": "지우기",
"close": "닫기", "close": "닫기",
"continue": "Continue", "continue": "계속",
"copy": "복사", "copy": "복사",
"copyFile": "파일 복사", "copyFile": "파일 복사",
"copyToClipboard": "클립보드 복사", "copyToClipboard": "클립보드 복사",
"copyDownloadLinkToClipboard": "Copy download link to clipboard", "copyDownloadLinkToClipboard": "다운로드 링크 복사",
"create": "생성", "create": "생성",
"delete": "삭제", "delete": "삭제",
"download": "다운로드", "download": "다운로드",
"file": "File", "file": "파일",
"folder": "Folder", "folder": "폴더",
"fullScreen": "Toggle full screen", "fullScreen": "전체 화면 전환",
"hideDotfiles": "숨김파일(dotfile)을 표시 안함", "hideDotfiles": "숨김파일(dotfile)을 표시 안함",
"info": "정보", "info": "정보",
"more": "더보기", "more": "더보기",
@@ -24,7 +24,7 @@
"ok": "확인", "ok": "확인",
"permalink": "링크 얻기", "permalink": "링크 얻기",
"previous": "이전", "previous": "이전",
"preview": "Preview", "preview": "미리보기",
"publish": "게시", "publish": "게시",
"rename": "이름 바꾸기", "rename": "이름 바꾸기",
"replace": "대체", "replace": "대체",
@@ -36,13 +36,14 @@
"selectMultiple": "다중 선택", "selectMultiple": "다중 선택",
"share": "공유", "share": "공유",
"shell": "쉘 전환", "shell": "쉘 전환",
"submit": "Submit", "submit": "제출",
"switchView": "보기 전환", "switchView": "보기 전환",
"toggleSidebar": "사이드바 전환", "toggleSidebar": "사이드바 전환",
"update": "업데이트", "update": "업데이트",
"upload": "업로드", "upload": "업로드",
"openFile": "Open file", "openFile": "파일 열기",
"discardChanges": "Discard" "discardChanges": "변경 사항 취소",
"saveChanges": "변경사항 저장"
}, },
"download": { "download": {
"downloadFile": "파일 다운로드", "downloadFile": "파일 다운로드",
@@ -50,13 +51,13 @@
"downloadSelected": "선택 항목 다운로드" "downloadSelected": "선택 항목 다운로드"
}, },
"upload": { "upload": {
"abortUpload": "Are you sure you wish to abort?" "abortUpload": "업로드를 중단하시겠습니까?"
}, },
"errors": { "errors": {
"forbidden": "접근 권한이 없습니다.", "forbidden": "접근 권한이 없습니다.",
"internal": "오류가 발생하였습니다.", "internal": "오류가 발생하였습니다.",
"notFound": "해당 경로를 찾을 수 없습니다.", "notFound": "해당 경로를 찾을 수 없습니다.",
"connection": "The server can't be reached." "connection": "서버에 연결할 수 없습니다."
}, },
"files": { "files": {
"body": "본문", "body": "본문",
@@ -74,7 +75,7 @@
"sortByLastModified": "수정시간순 정렬", "sortByLastModified": "수정시간순 정렬",
"sortByName": "이름순", "sortByName": "이름순",
"sortBySize": "크기순", "sortBySize": "크기순",
"noPreview": "Preview is not available for this file." "noPreview": "미리 보기가 지원되지 않는 파일 유형입니다."
}, },
"help": { "help": {
"click": "파일이나 디렉토리를 선택해주세요.", "click": "파일이나 디렉토리를 선택해주세요.",
@@ -100,7 +101,10 @@
"submit": "로그인", "submit": "로그인",
"username": "사용자 이름", "username": "사용자 이름",
"usernameTaken": "사용자 이름이 존재합니다", "usernameTaken": "사용자 이름이 존재합니다",
"wrongCredentials": "사용자 이름 또는 비밀번호를 확인하십시오" "wrongCredentials": "사용자 이름 또는 비밀번호를 확인하십시오",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
}, },
"permanent": "영구", "permanent": "영구",
"prompts": { "prompts": {
@@ -109,8 +113,8 @@
"currentlyNavigating": "현재 위치:", "currentlyNavigating": "현재 위치:",
"deleteMessageMultiple": "{count} 개의 파일을 삭제하시겠습니까?", "deleteMessageMultiple": "{count} 개의 파일을 삭제하시겠습니까?",
"deleteMessageSingle": "파일 혹은 디렉토리를 삭제하시겠습니까?", "deleteMessageSingle": "파일 혹은 디렉토리를 삭제하시겠습니까?",
"deleteMessageShare": "Are you sure you wish to delete this share({path})?", "deleteMessageShare": "이 공유({path})를 삭제하시겠습니까?",
"deleteUser": "Are you sure you want to delete this user?", "deleteUser": "이 계정을 삭제하시겠습니까?",
"deleteTitle": "파일 삭제", "deleteTitle": "파일 삭제",
"displayName": "게시 이름:", "displayName": "게시 이름:",
"download": "파일 다운로드", "download": "파일 다운로드",
@@ -137,11 +141,11 @@
"show": "보기", "show": "보기",
"size": "크기", "size": "크기",
"upload": "업로드", "upload": "업로드",
"uploadFiles": "Uploading {files} files...", "uploadFiles": "{files}개의 파일 업로드 중...",
"uploadMessage": "업로드 옵션을 선택하세요.", "uploadMessage": "업로드 옵션을 선택하세요.",
"optionalPassword": "Optional password", "optionalPassword": "비밀번호 (선택)",
"resolution": "Resolution", "resolution": "해상도",
"discardEditorChanges": "Are you sure you wish to discard the changes you've made?" "discardEditorChanges": "변경 사항을 취소하시겠습니까?"
}, },
"search": { "search": {
"images": "이미지", "images": "이미지",
@@ -154,6 +158,7 @@
"video": "비디오" "video": "비디오"
}, },
"settings": { "settings": {
"aceEditorTheme": "Ace editor theme",
"admin": "관리자", "admin": "관리자",
"administrator": "관리자", "administrator": "관리자",
"allowCommands": "명령 실행", "allowCommands": "명령 실행",
@@ -170,14 +175,14 @@
"commandRunnerHelp": "이벤트에 해당하는 명령을 설정하세요. 줄당 1개의 명령을 적으세요. 환경 변수{0} 와 {1}이 사용가능하며, {0} 은 {1}에 상대 경로 입니다. 자세한 사항은 {2} 를 참조하세요.", "commandRunnerHelp": "이벤트에 해당하는 명령을 설정하세요. 줄당 1개의 명령을 적으세요. 환경 변수{0} 와 {1}이 사용가능하며, {0} 은 {1}에 상대 경로 입니다. 자세한 사항은 {2} 를 참조하세요.",
"commandsUpdated": "명령 수정됨!", "commandsUpdated": "명령 수정됨!",
"createUserDir": "Auto create user home dir while adding new user", "createUserDir": "Auto create user home dir while adding new user",
"minimumPasswordLength": "Minimum password length", "minimumPasswordLength": "최소 비밀번호 길이",
"tusUploads": "Chunked Uploads", "tusUploads": "분할 업로드",
"tusUploadsHelp": "File Browser supports chunked file uploads, allowing for the creation of efficient, reliable, resumable and chunked file uploads even on unreliable networks.", "tusUploadsHelp": "File Browser는 불안정한 네트워크에서도 효율적이고 신뢰성 있는 분할 업로드를 지원합니다.",
"tusUploadsChunkSize": "Indicates to maximum size of a request (direct uploads will be used for smaller uploads). You may input a plain integer denoting byte size input or a string like 10MB, 1GB etc.", "tusUploadsChunkSize": "업로드 요청의 최대 크기 (예: 10MB, 1GB)",
"tusUploadsRetryCount": "Number of retries to perform if a chunk fails to upload.", "tusUploadsRetryCount": "업로드 실패 시 재시도 횟수",
"userHomeBasePath": "Base path for user home directories", "userHomeBasePath": "사용자 홈 폴더 기본 경로",
"userScopeGenerationPlaceholder": "The scope will be auto generated", "userScopeGenerationPlaceholder": "범위는 자동으로 생성됩니다.",
"createUserHomeDirectory": "Create user home directory", "createUserHomeDirectory": "사용자 홈 폴더 생성",
"customStylesheet": "커스텀 스타일시트", "customStylesheet": "커스텀 스타일시트",
"defaultUserDescription": "아래 사항은 신규 사용자들에 대한 기본 설정입니다.", "defaultUserDescription": "아래 사항은 신규 사용자들에 대한 기본 설정입니다.",
"disableExternalLinks": "외부 링크 감추기", "disableExternalLinks": "외부 링크 감추기",
@@ -217,14 +222,14 @@
"rules": "룰", "rules": "룰",
"rulesHelp": "사용자별로 규칙을 허용/방지를 지정할 수 있습니다. 방지된 파일은 보이지 않고 사용자들은 접근할 수 없습니다. 사용자의 접근 허용 범위와 관련해 정규표현식(regex)과 경로를 지원합니다.\n", "rulesHelp": "사용자별로 규칙을 허용/방지를 지정할 수 있습니다. 방지된 파일은 보이지 않고 사용자들은 접근할 수 없습니다. 사용자의 접근 허용 범위와 관련해 정규표현식(regex)과 경로를 지원합니다.\n",
"scope": "범위", "scope": "범위",
"setDateFormat": "Set exact date format", "setDateFormat": "날짜 형식 설정",
"settingsUpdated": "설정 수정됨!", "settingsUpdated": "설정 수정됨!",
"shareDuration": "공유 기간", "shareDuration": "공유 기간",
"shareManagement": "공유 내역 관리", "shareManagement": "공유 내역 관리",
"shareDeleted": "Share deleted!", "shareDeleted": "공유 삭제됨!",
"singleClick": "한번 클릭으로 파일과 폴더를 열도록 합니다.", "singleClick": "한번 클릭으로 파일과 폴더를 열도록 합니다.",
"themes": { "themes": {
"default": "System default", "default": "시스템 기본값",
"dark": "다크테마", "dark": "다크테마",
"light": "라이트테마", "light": "라이트테마",
"title": "테마" "title": "테마"

View File

@@ -42,7 +42,8 @@
"update": "Updaten", "update": "Updaten",
"upload": "Uploaden", "upload": "Uploaden",
"openFile": "Open file", "openFile": "Open file",
"discardChanges": "Discard" "discardChanges": "Discard",
"saveChanges": "Save changes"
}, },
"download": { "download": {
"downloadFile": "Bestand downloaden", "downloadFile": "Bestand downloaden",
@@ -100,7 +101,10 @@
"submit": "Log in", "submit": "Log in",
"username": "Gebruikersnaam", "username": "Gebruikersnaam",
"usernameTaken": "Gebruikersnaam reeds in gebruik", "usernameTaken": "Gebruikersnaam reeds in gebruik",
"wrongCredentials": "Verkeerde inloggegevens" "wrongCredentials": "Verkeerde inloggegevens",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
}, },
"permanent": "Permanent", "permanent": "Permanent",
"prompts": { "prompts": {
@@ -154,6 +158,7 @@
"video": "Video" "video": "Video"
}, },
"settings": { "settings": {
"aceEditorTheme": "Ace editor theme",
"admin": "Admin", "admin": "Admin",
"administrator": "Administrator", "administrator": "Administrator",
"allowCommands": "Commando's uitvoeren", "allowCommands": "Commando's uitvoeren",

View File

@@ -42,7 +42,8 @@
"update": "Opptater", "update": "Opptater",
"upload": "Last opp", "upload": "Last opp",
"openFile": "Open file", "openFile": "Open file",
"discardChanges": "Slett" "discardChanges": "Slett",
"saveChanges": "Lagre Endringane "
}, },
"download": { "download": {
"downloadFile": "Nedlast filen", "downloadFile": "Nedlast filen",
@@ -100,7 +101,10 @@
"submit": "Logg inn", "submit": "Logg inn",
"username": "Brukernavn", "username": "Brukernavn",
"usernameTaken": "Brukernavn er allerede i bruk", "usernameTaken": "Brukernavn er allerede i bruk",
"wrongCredentials": "Feil legitimasjon" "wrongCredentials": "Feil legitimasjon",
"logout_reasons": {
"inactivity": "Du har blitt logget ut på grunn av inaktivitet"
}
}, },
"permanent": "Permanent", "permanent": "Permanent",
"prompts": { "prompts": {
@@ -154,6 +158,7 @@
"video": "Video" "video": "Video"
}, },
"settings": { "settings": {
"aceEditorTheme": "Ace editor theme",
"admin": "Admin", "admin": "Admin",
"administrator": "Administrator", "administrator": "Administrator",
"allowCommands": "Utfør kommandoer", "allowCommands": "Utfør kommandoer",

View File

@@ -42,7 +42,8 @@
"update": "Aktualizuj", "update": "Aktualizuj",
"upload": "Wyślij", "upload": "Wyślij",
"openFile": "Otwórz plik", "openFile": "Otwórz plik",
"discardChanges": "Odrzuć" "discardChanges": "Odrzuć",
"saveChanges": "Zapisz zmiany"
}, },
"download": { "download": {
"downloadFile": "Pobierz plik", "downloadFile": "Pobierz plik",
@@ -100,7 +101,10 @@
"submit": "Zaloguj", "submit": "Zaloguj",
"username": "Nazwa użytkownika", "username": "Nazwa użytkownika",
"usernameTaken": "Ta nazwa użytkownika jest zajęta", "usernameTaken": "Ta nazwa użytkownika jest zajęta",
"wrongCredentials": "Błędne dane logowania" "wrongCredentials": "Błędne dane logowania",
"logout_reasons": {
"inactivity": "Wylogowano z powodu braku aktywności."
}
}, },
"permanent": "Permanentny", "permanent": "Permanentny",
"prompts": { "prompts": {
@@ -154,6 +158,7 @@
"video": "Wideo" "video": "Wideo"
}, },
"settings": { "settings": {
"aceEditorTheme": "Ace editor theme",
"admin": "Admin", "admin": "Admin",
"administrator": "Administrator", "administrator": "Administrator",
"allowCommands": "Wykonaj polecenie", "allowCommands": "Wykonaj polecenie",

View File

@@ -42,7 +42,8 @@
"update": "Atualizar", "update": "Atualizar",
"upload": "Enviar", "upload": "Enviar",
"openFile": "Abrir", "openFile": "Abrir",
"discardChanges": "Discard" "discardChanges": "Discard",
"saveChanges": "Save changes"
}, },
"download": { "download": {
"downloadFile": "Baixar arquivo", "downloadFile": "Baixar arquivo",
@@ -100,7 +101,10 @@
"submit": "Login", "submit": "Login",
"username": "Nome do usuário", "username": "Nome do usuário",
"usernameTaken": "Nome de usuário já existe", "usernameTaken": "Nome de usuário já existe",
"wrongCredentials": "Ops! Dados incorretos." "wrongCredentials": "Ops! Dados incorretos.",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
}, },
"permanent": "Permanente", "permanent": "Permanente",
"prompts": { "prompts": {
@@ -154,6 +158,7 @@
"video": "Vídeos" "video": "Vídeos"
}, },
"settings": { "settings": {
"aceEditorTheme": "Ace editor theme",
"admin": "Admin", "admin": "Admin",
"administrator": "Administrador", "administrator": "Administrador",
"allowCommands": "Executar comandos", "allowCommands": "Executar comandos",

View File

@@ -42,7 +42,8 @@
"update": "Atualizar", "update": "Atualizar",
"upload": "Enviar", "upload": "Enviar",
"openFile": "Open file", "openFile": "Open file",
"discardChanges": "Discard" "discardChanges": "Discard",
"saveChanges": "Save changes"
}, },
"download": { "download": {
"downloadFile": "Descarregar ficheiro", "downloadFile": "Descarregar ficheiro",
@@ -100,7 +101,10 @@
"submit": "Entrar na conta", "submit": "Entrar na conta",
"username": "Nome de utilizador", "username": "Nome de utilizador",
"usernameTaken": "O nome de utilizador já está registado", "usernameTaken": "O nome de utilizador já está registado",
"wrongCredentials": "Dados errados" "wrongCredentials": "Dados errados",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
}, },
"permanent": "Permanente", "permanent": "Permanente",
"prompts": { "prompts": {
@@ -154,6 +158,7 @@
"video": "Vídeos" "video": "Vídeos"
}, },
"settings": { "settings": {
"aceEditorTheme": "Ace editor theme",
"admin": "Admin", "admin": "Admin",
"administrator": "Administrador", "administrator": "Administrador",
"allowCommands": "Executar comandos", "allowCommands": "Executar comandos",

View File

@@ -42,7 +42,8 @@
"update": "Actualizează", "update": "Actualizează",
"upload": "Încarcă", "upload": "Încarcă",
"openFile": "Open file", "openFile": "Open file",
"discardChanges": "Discard" "discardChanges": "Discard",
"saveChanges": "Save changes"
}, },
"download": { "download": {
"downloadFile": "Descarcă fișier", "downloadFile": "Descarcă fișier",
@@ -100,7 +101,10 @@
"submit": "Autentificare", "submit": "Autentificare",
"username": "Utilizator", "username": "Utilizator",
"usernameTaken": "Utilizatorul există", "usernameTaken": "Utilizatorul există",
"wrongCredentials": "Informații greșite" "wrongCredentials": "Informații greșite",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
}, },
"permanent": "Permanent", "permanent": "Permanent",
"prompts": { "prompts": {
@@ -154,6 +158,7 @@
"video": "Video" "video": "Video"
}, },
"settings": { "settings": {
"aceEditorTheme": "Ace editor theme",
"admin": "Admin", "admin": "Admin",
"administrator": "Administrator", "administrator": "Administrator",
"allowCommands": "Execută comenzi", "allowCommands": "Execută comenzi",

View File

@@ -42,7 +42,8 @@
"update": "Обновить", "update": "Обновить",
"upload": "Загрузить", "upload": "Загрузить",
"openFile": "Открыть файл", "openFile": "Открыть файл",
"discardChanges": "Отказаться" "discardChanges": "Отказаться",
"saveChanges": "Save changes"
}, },
"download": { "download": {
"downloadFile": "Скачать файл", "downloadFile": "Скачать файл",
@@ -100,7 +101,10 @@
"submit": "Войти", "submit": "Войти",
"username": "Имя пользователя", "username": "Имя пользователя",
"usernameTaken": "Данное имя пользователя уже занято", "usernameTaken": "Данное имя пользователя уже занято",
"wrongCredentials": "Неверные данные" "wrongCredentials": "Неверные данные",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
}, },
"permanent": "Постоянный", "permanent": "Постоянный",
"prompts": { "prompts": {
@@ -154,6 +158,7 @@
"video": "Видео" "video": "Видео"
}, },
"settings": { "settings": {
"aceEditorTheme": "Ace editor theme",
"admin": "Админ", "admin": "Админ",
"administrator": "Администратор", "administrator": "Администратор",
"allowCommands": "Запуск команд", "allowCommands": "Запуск команд",

View File

@@ -42,7 +42,8 @@
"update": "Aktualizovať", "update": "Aktualizovať",
"upload": "Nahrať", "upload": "Nahrať",
"openFile": "Otvoriť súbor", "openFile": "Otvoriť súbor",
"discardChanges": "Zahodiť" "discardChanges": "Zahodiť",
"saveChanges": "Save changes"
}, },
"download": { "download": {
"downloadFile": "Stiahnuť súbor", "downloadFile": "Stiahnuť súbor",
@@ -100,7 +101,10 @@
"submit": "Prihlásiť", "submit": "Prihlásiť",
"username": "Používateľské meno", "username": "Používateľské meno",
"usernameTaken": "Meno je už obsadené", "usernameTaken": "Meno je už obsadené",
"wrongCredentials": "Nesprávne prihlasovacie údaje" "wrongCredentials": "Nesprávne prihlasovacie údaje",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
}, },
"permanent": "Trvalé", "permanent": "Trvalé",
"prompts": { "prompts": {
@@ -154,6 +158,7 @@
"video": "Video" "video": "Video"
}, },
"settings": { "settings": {
"aceEditorTheme": "Ace editor theme",
"admin": "Admin", "admin": "Admin",
"administrator": "Administrátor", "administrator": "Administrátor",
"allowCommands": "Vykonávať príkazy", "allowCommands": "Vykonávať príkazy",

View File

@@ -42,7 +42,8 @@
"update": "Uppdatera", "update": "Uppdatera",
"upload": "Ladda upp", "upload": "Ladda upp",
"openFile": "Open file", "openFile": "Open file",
"discardChanges": "Discard" "discardChanges": "Discard",
"saveChanges": "Save changes"
}, },
"download": { "download": {
"downloadFile": "Ladda ner fil", "downloadFile": "Ladda ner fil",
@@ -100,7 +101,10 @@
"submit": "Logga in", "submit": "Logga in",
"username": "Användarnamn", "username": "Användarnamn",
"usernameTaken": "Användarnamn upptaget", "usernameTaken": "Användarnamn upptaget",
"wrongCredentials": "Fel inloggning" "wrongCredentials": "Fel inloggning",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
}, },
"permanent": "Permanent", "permanent": "Permanent",
"prompts": { "prompts": {
@@ -154,6 +158,7 @@
"video": "Video" "video": "Video"
}, },
"settings": { "settings": {
"aceEditorTheme": "Ace editor theme",
"admin": "Admin", "admin": "Admin",
"administrator": "Administratör", "administrator": "Administratör",
"allowCommands": "Exekvera kommandon", "allowCommands": "Exekvera kommandon",

View File

@@ -42,7 +42,8 @@
"update": "Güncelle", "update": "Güncelle",
"upload": "Yükle", "upload": "Yükle",
"openFile": "Dosyayı aç", "openFile": "Dosyayı aç",
"discardChanges": "Discard" "discardChanges": "Discard",
"saveChanges": "Save changes"
}, },
"download": { "download": {
"downloadFile": "Dosyayı indir", "downloadFile": "Dosyayı indir",
@@ -100,7 +101,10 @@
"submit": "Giriş", "submit": "Giriş",
"username": "Kullanıcı adı", "username": "Kullanıcı adı",
"usernameTaken": "Kullanıcı adı mevcut", "usernameTaken": "Kullanıcı adı mevcut",
"wrongCredentials": "Yanlış hesap bilgileri" "wrongCredentials": "Yanlış hesap bilgileri",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
}, },
"permanent": "Kalıcı", "permanent": "Kalıcı",
"prompts": { "prompts": {
@@ -154,6 +158,7 @@
"video": "Video" "video": "Video"
}, },
"settings": { "settings": {
"aceEditorTheme": "Ace editor theme",
"admin": "Yönetim", "admin": "Yönetim",
"administrator": "Yönetici", "administrator": "Yönetici",
"allowCommands": "Komutları çalıştır", "allowCommands": "Komutları çalıştır",

View File

@@ -42,7 +42,8 @@
"update": "Оновити", "update": "Оновити",
"upload": "Вивантажити", "upload": "Вивантажити",
"openFile": "Відкрити файл", "openFile": "Відкрити файл",
"discardChanges": "Скасувати" "discardChanges": "Скасувати",
"saveChanges": "Save changes"
}, },
"download": { "download": {
"downloadFile": "Завантажити файл", "downloadFile": "Завантажити файл",
@@ -100,7 +101,10 @@
"submit": "Увійти", "submit": "Увійти",
"username": "Ім'я користувача", "username": "Ім'я користувача",
"usernameTaken": "Ім'я користувача вже використовується", "usernameTaken": "Ім'я користувача вже використовується",
"wrongCredentials": "Неправильне ім'я користувача або пароль" "wrongCredentials": "Неправильне ім'я користувача або пароль",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
}, },
"permanent": "Постійний", "permanent": "Постійний",
"prompts": { "prompts": {
@@ -154,6 +158,7 @@
"video": "Відео" "video": "Відео"
}, },
"settings": { "settings": {
"aceEditorTheme": "Ace editor theme",
"admin": "Адмін", "admin": "Адмін",
"administrator": "Адміністратор", "administrator": "Адміністратор",
"allowCommands": "Запуск команд", "allowCommands": "Запуск команд",
@@ -173,15 +178,15 @@
"minimumPasswordLength": "Мінімальна довжина паролю", "minimumPasswordLength": "Мінімальна довжина паролю",
"tusUploads": "Фрагментовані завантаження", "tusUploads": "Фрагментовані завантаження",
"tusUploadsHelp": "File Browser підтримує завантаження частинами, дозволяючи створення ефективних, надійних, відновлюваних та фрагментованих завантажень навіть при ненадійному з'єднанні.", "tusUploadsHelp": "File Browser підтримує завантаження частинами, дозволяючи створення ефективних, надійних, відновлюваних та фрагментованих завантажень навіть при ненадійному з'єднанні.",
"tusUploadsChunkSize": "Вказує на максимальний розмір запиту (для менших завантажень використовуватиметься пряме завантаження). Ви можете ввести цілочисельне значення у байтах або ж рядок на кшталт 10MB, 1GB тощо.", "tusUploadsChunkSize": "Максимальний розмір запиту (для менших завантажень використовуватиметься пряме завантаження). Ви можете ввести цілочисельне значення у байтах або ж рядок на кшталт 10MB, 1GB тощо",
"tusUploadsRetryCount": "Кількість повторних спроб які потрібно виконати, якщо фрагмент не вдалося завантажити.", "tusUploadsRetryCount": "Кількість повторних спроб які потрібно виконати, якщо фрагмент не вдалося завантажити",
"userHomeBasePath": "Основний шлях для домашніх каталогів користувачів", "userHomeBasePath": "Основний шлях для домашніх каталогів користувачів",
"userScopeGenerationPlaceholder": "Кореневий каталог буде згенеровано автоматично", "userScopeGenerationPlaceholder": "Кореневий каталог буде згенеровано автоматично",
"createUserHomeDirectory": "Створити домашній каталог користувача", "createUserHomeDirectory": "Створити домашній каталог користувача",
"customStylesheet": "Свій стиль", "customStylesheet": "Свій стиль",
"defaultUserDescription": "Це налаштування за замовчуванням для нових користувачів.", "defaultUserDescription": "Це налаштування за замовчуванням для нових користувачів.",
"disableExternalLinks": "Вимкнути зовнішні посилання (крім документації)", "disableExternalLinks": "Вимкнути зовнішні посилання (крім документації)",
"disableUsedDiskPercentage": "Disable used disk percentage graph", "disableUsedDiskPercentage": "Вимкнути графік використання диску",
"documentation": "документація", "documentation": "документація",
"examples": "Приклади", "examples": "Приклади",
"executeOnShell": "Виконати в командному рядку", "executeOnShell": "Виконати в командному рядку",
@@ -231,7 +236,7 @@
}, },
"user": "Користувач", "user": "Користувач",
"userCommands": "Команди", "userCommands": "Команди",
"userCommandsHelp": "Список команд, доступних користувачу, розділений пробілами. Приклад:\n", "userCommandsHelp": "Список команд, доступних користувачу, розділений пробілами. Наприклад:\n",
"userCreated": "Користувача створено!", "userCreated": "Користувача створено!",
"userDefaults": "Налаштування користувача за замовчуванням", "userDefaults": "Налаштування користувача за замовчуванням",
"userDeleted": "Користувача видалено!", "userDeleted": "Користувача видалено!",

View File

@@ -42,7 +42,8 @@
"update": "Cập nhật", "update": "Cập nhật",
"upload": "Tải lên", "upload": "Tải lên",
"openFile": "Mở tệp", "openFile": "Mở tệp",
"discardChanges": "Hủy bỏ thay đổi" "discardChanges": "Hủy bỏ thay đổi",
"saveChanges": "Save changes"
}, },
"download": { "download": {
"downloadFile": "Tải xuống tệp tin", "downloadFile": "Tải xuống tệp tin",
@@ -100,7 +101,10 @@
"submit": "Đăng nhập", "submit": "Đăng nhập",
"username": "Tên người dùng", "username": "Tên người dùng",
"usernameTaken": "Tên người dùng đã tồn tại", "usernameTaken": "Tên người dùng đã tồn tại",
"wrongCredentials": "Thông tin đăng nhập không đúng" "wrongCredentials": "Thông tin đăng nhập không đúng",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
}, },
"permanent": "Vĩnh viễn", "permanent": "Vĩnh viễn",
"prompts": { "prompts": {
@@ -154,6 +158,7 @@
"video": "Video" "video": "Video"
}, },
"settings": { "settings": {
"aceEditorTheme": "Ace editor theme",
"admin": "Quản trị viên", "admin": "Quản trị viên",
"administrator": "Người quản trị", "administrator": "Người quản trị",
"allowCommands": "Thực thi lệnh", "allowCommands": "Thực thi lệnh",

View File

@@ -42,7 +42,8 @@
"update": "更新", "update": "更新",
"upload": "上传", "upload": "上传",
"openFile": "打开文件", "openFile": "打开文件",
"discardChanges": "放弃更改" "discardChanges": "放弃更改",
"saveChanges": "Save changes"
}, },
"download": { "download": {
"downloadFile": "下载文件", "downloadFile": "下载文件",
@@ -100,7 +101,10 @@
"submit": "登录", "submit": "登录",
"username": "用户名", "username": "用户名",
"usernameTaken": "用户名已经被使用", "usernameTaken": "用户名已经被使用",
"wrongCredentials": "用户名或密码错误" "wrongCredentials": "用户名或密码错误",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
}, },
"permanent": "永久", "permanent": "永久",
"prompts": { "prompts": {
@@ -154,6 +158,7 @@
"video": "视频" "video": "视频"
}, },
"settings": { "settings": {
"aceEditorTheme": "Ace editor theme",
"admin": "管理员", "admin": "管理员",
"administrator": "管理员", "administrator": "管理员",
"allowCommands": "执行命令Shell 命令)", "allowCommands": "执行命令Shell 命令)",

View File

@@ -42,7 +42,8 @@
"update": "更新", "update": "更新",
"upload": "上傳", "upload": "上傳",
"openFile": "開啟檔案", "openFile": "開啟檔案",
"discardChanges": "放棄變更" "discardChanges": "放棄變更",
"saveChanges": "Save changes"
}, },
"download": { "download": {
"downloadFile": "下載檔案", "downloadFile": "下載檔案",
@@ -100,7 +101,10 @@
"submit": "登入", "submit": "登入",
"username": "帳號", "username": "帳號",
"usernameTaken": "用戶名已存在", "usernameTaken": "用戶名已存在",
"wrongCredentials": "帳號或密碼錯誤" "wrongCredentials": "帳號或密碼錯誤",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
}, },
"permanent": "永久", "permanent": "永久",
"prompts": { "prompts": {
@@ -154,6 +158,7 @@
"video": "影片" "video": "影片"
}, },
"settings": { "settings": {
"aceEditorTheme": "Ace editor theme",
"admin": "管理員", "admin": "管理員",
"administrator": "管理員", "administrator": "管理員",
"allowCommands": "執行命令", "allowCommands": "執行命令",

View File

@@ -7,9 +7,11 @@ export const useAuthStore = defineStore("auth", {
state: (): { state: (): {
user: IUser | null; user: IUser | null;
jwt: string; jwt: string;
logoutTimer: number | null;
} => ({ } => ({
user: null, user: null,
jwt: "", jwt: "",
logoutTimer: null,
}), }),
getters: { getters: {
// user and jwt getter removed, no longer needed // user and jwt getter removed, no longer needed
@@ -37,5 +39,8 @@ export const useAuthStore = defineStore("auth", {
clearUser() { clearUser() {
this.$reset(); this.$reset();
}, },
setLogoutTimer(logoutTimer: number | null) {
this.logoutTimer = logoutTimer;
},
}, },
}); });

View File

@@ -41,6 +41,7 @@ export const useLayoutStore = defineStore("layout", {
prompt: value, prompt: value,
confirm: null, confirm: null,
action: undefined, action: undefined,
saveAction: undefined,
props: null, props: null,
close: null, close: null,
}); });
@@ -51,6 +52,7 @@ export const useLayoutStore = defineStore("layout", {
prompt: value.prompt, prompt: value.prompt,
confirm: value?.confirm, confirm: value?.confirm,
action: value?.action, action: value?.action,
saveAction: value?.saveAction,
props: value?.props, props: value?.props,
close: value?.close, close: value?.close,
}); });

View File

@@ -1,8 +1,9 @@
import { defineStore } from "pinia"; import { defineStore } from "pinia";
import { useFileStore } from "./file"; import { useFileStore } from "./file";
import { files as api } from "@/api"; import { files as api } from "@/api";
import { throttle } from "lodash-es";
import buttons from "@/utils/buttons"; import buttons from "@/utils/buttons";
import { computed, inject, markRaw, ref } from "vue";
import * as tus from "@/api/tus";
// TODO: make this into a user setting // TODO: make this into a user setting
const UPLOADS_LIMIT = 5; const UPLOADS_LIMIT = 5;
@@ -13,208 +14,167 @@ const beforeUnload = (event: Event) => {
// event.returnValue = ""; // event.returnValue = "";
}; };
// Utility function to format bytes into a readable string export const useUploadStore = defineStore("upload", () => {
function formatSize(bytes: number): string { const $showError = inject<IToastError>("$showError")!;
if (bytes === 0) return "0.00 Bytes";
const k = 1024; let progressInterval: number | null = null;
const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
const i = Math.floor(Math.log(bytes) / Math.log(k));
// Return the rounded size with two decimal places //
return (bytes / k ** i).toFixed(2) + " " + sizes[i]; // STATE
} //
export const useUploadStore = defineStore("upload", { const allUploads = ref<Upload[]>([]);
// convert to a function const activeUploads = ref<Set<Upload>>(new Set());
state: (): { const lastUpload = ref<number>(-1);
id: number; const totalBytes = ref<number>(0);
sizes: number[]; const sentBytes = ref<number>(0);
progress: number[];
queue: UploadItem[]; //
uploads: Uploads; // ACTIONS
speedMbyte: number; //
eta: number;
error: Error | null; const upload = (
} => ({ path: string,
id: 0, name: string,
sizes: [], file: File | null,
progress: [], overwrite: boolean,
queue: [], type: ResourceType
uploads: {}, ) => {
speedMbyte: 0, if (!hasActiveUploads() && !hasPendingUploads()) {
eta: 0, window.addEventListener("beforeunload", beforeUnload);
error: null, buttons.loading("upload");
}), }
getters: {
// user and jwt getter removed, no longer needed const upload: Upload = {
getProgress: (state) => { path,
if (state.progress.length === 0) { name,
return 0; file,
overwrite,
type,
totalBytes: file?.size || 1,
sentBytes: 0,
// Stores rapidly changing sent bytes value without causing component re-renders
rawProgress: markRaw({
sentBytes: 0,
}),
};
totalBytes.value += upload.totalBytes;
allUploads.value.push(upload);
processUploads();
};
const abort = () => {
// Resets the state by preventing the processing of the remaning uploads
lastUpload.value = Infinity;
tus.abortAllUploads();
};
//
// GETTERS
//
const pendingUploadCount = computed(
() =>
allUploads.value.length -
(lastUpload.value + 1) +
activeUploads.value.size
);
//
// PRIVATE FUNCTIONS
//
const hasActiveUploads = () => activeUploads.value.size > 0;
const hasPendingUploads = () =>
allUploads.value.length > lastUpload.value + 1;
const isActiveUploadsOnLimit = () => activeUploads.value.size < UPLOADS_LIMIT;
const processUploads = async () => {
if (!hasActiveUploads() && !hasPendingUploads()) {
const fileStore = useFileStore();
window.removeEventListener("beforeunload", beforeUnload);
buttons.success("upload");
reset();
fileStore.reload = true;
}
if (isActiveUploadsOnLimit() && hasPendingUploads()) {
if (!hasActiveUploads()) {
// Update the state in a fixed time interval
progressInterval = window.setInterval(syncState, 1000);
} }
const totalSize = state.sizes.reduce((a, b) => a + b, 0); const upload = nextUpload();
const sum = state.progress.reduce((a, b) => a + b, 0);
return Math.ceil((sum / totalSize) * 100); if (upload.type === "dir") {
}, await api.post(upload.path).catch($showError);
getProgressDecimal: (state) => { } else {
if (state.progress.length === 0) { const onUpload = (event: ProgressEvent) => {
return 0; upload.rawProgress.sentBytes = event.loaded;
};
await api
.post(upload.path, upload.file!, upload.overwrite, onUpload)
.catch((err) => err.message !== "Upload aborted" && $showError(err));
} }
const totalSize = state.sizes.reduce((a, b) => a + b, 0); finishUpload(upload);
const sum = state.progress.reduce((a, b) => a + b, 0); }
return ((sum / totalSize) * 100).toFixed(2); };
},
getTotalProgressBytes: (state) => {
if (state.progress.length === 0 || state.sizes.length === 0) {
return "0 Bytes";
}
const sum = state.progress.reduce((a, b) => a + b, 0);
return formatSize(sum);
},
getTotalSize: (state) => {
if (state.sizes.length === 0) {
return "0 Bytes";
}
const totalSize = state.sizes.reduce((a, b) => a + b, 0);
return formatSize(totalSize);
},
filesInUploadCount: (state) => {
return Object.keys(state.uploads).length + state.queue.length;
},
filesInUpload: (state) => {
const files = [];
for (const index in state.uploads) { const nextUpload = (): Upload => {
const upload = state.uploads[index]; lastUpload.value++;
const id = upload.id;
const type = upload.type;
const name = upload.file.name;
const size = state.sizes[id];
const isDir = upload.file.isDir;
const progress = isDir
? 100
: Math.ceil((state.progress[id] / size) * 100);
files.push({ const upload = allUploads.value[lastUpload.value];
id, activeUploads.value.add(upload);
name,
progress,
type,
isDir,
});
}
return files.sort((a, b) => a.progress - b.progress); return upload;
}, };
uploadSpeed: (state) => {
return state.speedMbyte;
},
getETA: (state) => state.eta,
},
actions: {
// no context as first argument, use `this` instead
setProgress({ id, loaded }: { id: number; loaded: number }) {
this.progress[id] = loaded;
},
setError(error: Error) {
this.error = error;
},
reset() {
this.id = 0;
this.sizes = [];
this.progress = [];
this.queue = [];
this.uploads = {};
this.speedMbyte = 0;
this.eta = 0;
this.error = null;
},
addJob(item: UploadItem) {
this.queue.push(item);
this.sizes[this.id] = item.file.size;
this.id++;
},
moveJob() {
const item = this.queue[0];
this.queue.shift();
this.uploads[item.id] = item;
},
removeJob(id: number) {
delete this.uploads[id];
},
upload(item: UploadItem) {
const uploadsCount = Object.keys(this.uploads).length;
const isQueueEmpty = this.queue.length == 0; const finishUpload = (upload: Upload) => {
const isUploadsEmpty = uploadsCount == 0; sentBytes.value += upload.totalBytes - upload.sentBytes;
upload.sentBytes = upload.totalBytes;
upload.file = null;
if (isQueueEmpty && isUploadsEmpty) { activeUploads.value.delete(upload);
window.addEventListener("beforeunload", beforeUnload); processUploads();
buttons.loading("upload"); };
}
this.addJob(item); const syncState = () => {
this.processUploads(); for (const upload of activeUploads.value) {
}, sentBytes.value += upload.rawProgress.sentBytes - upload.sentBytes;
finishUpload(item: UploadItem) { upload.sentBytes = upload.rawProgress.sentBytes;
this.setProgress({ id: item.id, loaded: item.file.size }); }
this.removeJob(item.id); };
this.processUploads();
},
async processUploads() {
const uploadsCount = Object.keys(this.uploads).length;
const isBelowLimit = uploadsCount < UPLOADS_LIMIT; const reset = () => {
const isQueueEmpty = this.queue.length == 0; if (progressInterval !== null) {
const isUploadsEmpty = uploadsCount == 0; clearInterval(progressInterval);
progressInterval = null;
}
const isFinished = isQueueEmpty && isUploadsEmpty; allUploads.value = [];
const canProcess = isBelowLimit && !isQueueEmpty; activeUploads.value = new Set();
lastUpload.value = -1;
totalBytes.value = 0;
sentBytes.value = 0;
};
if (isFinished) { return {
const fileStore = useFileStore(); // STATE
window.removeEventListener("beforeunload", beforeUnload); activeUploads,
buttons.success("upload"); totalBytes,
this.reset(); sentBytes,
fileStore.reload = true;
}
if (canProcess) { // ACTIONS
const item = this.queue[0]; upload,
this.moveJob(); abort,
if (item.file.isDir) { // GETTERS
await api.post(item.path).catch(this.setError); pendingUploadCount,
} else { };
const onUpload = throttle(
(event: ProgressEvent) =>
this.setProgress({
id: item.id,
loaded: event.loaded,
}),
100,
{ leading: true, trailing: false }
);
await api
.post(item.path, item.file.file as File, item.overwrite, onUpload)
.catch(this.setError);
}
this.finishUpload(item);
}
},
setUploadSpeed(value: number) {
this.speedMbyte = value;
},
setETA(value: number) {
this.eta = value;
},
// easily reset state using `$reset`
clearUpload() {
this.$reset();
},
},
}); });

View File

@@ -29,6 +29,7 @@ interface ResourceItem extends ResourceBase {
} }
type ResourceType = type ResourceType =
| "dir"
| "video" | "video"
| "audio" | "audio"
| "image" | "image"

View File

@@ -2,6 +2,7 @@ interface PopupProps {
prompt: string; prompt: string;
confirm?: any; confirm?: any;
action?: PopupAction; action?: PopupAction;
saveAction?: () => void;
props?: any; props?: any;
close?: (() => Promise<string>) | null; close?: (() => Promise<string>) | null;
} }

View File

@@ -21,6 +21,7 @@ interface SettingsDefaults {
commands: any[]; commands: any[];
hideDotfiles: boolean; hideDotfiles: boolean;
dateFormat: boolean; dateFormat: boolean;
aceEditorTheme: string;
} }
interface SettingsBranding { interface SettingsBranding {

View File

@@ -1,22 +1,15 @@
interface Uploads { type Upload = {
[key: number]: Upload;
}
interface Upload {
id: number;
file: UploadEntry;
type?: ResourceType;
}
interface UploadItem {
id: number;
url?: string;
path: string; path: string;
file: UploadEntry; name: string;
dir?: boolean; file: File | null;
overwrite?: boolean; type: ResourceType;
type?: ResourceType; overwrite: boolean;
} totalBytes: number;
sentBytes: number;
rawProgress: {
sentBytes: number;
};
};
interface UploadEntry { interface UploadEntry {
name: string; name: string;
@@ -27,17 +20,3 @@ interface UploadEntry {
} }
type UploadList = UploadEntry[]; type UploadList = UploadEntry[];
type CurrentUploadList = {
[key: string]: {
upload: import("tus-js-client").Upload;
recentSpeeds: number[];
initialBytesUploaded: number;
currentBytesUploaded: number;
currentAverageSpeed: number;
lastProgressTimestamp: number | null;
sumOfRecentSpeeds: number;
hasStarted: boolean;
interval: number | undefined;
};
};

View File

@@ -13,6 +13,7 @@ interface IUser {
dateFormat: boolean; dateFormat: boolean;
viewMode: ViewModeType; viewMode: ViewModeType;
sorting?: Sorting; sorting?: Sorting;
aceEditorTheme: string;
} }
type ViewModeType = "list" | "mosaic" | "mosaic gallery"; type ViewModeType = "list" | "mosaic" | "mosaic gallery";

View File

@@ -4,6 +4,7 @@ import type { JwtPayload } from "jwt-decode";
import { jwtDecode } from "jwt-decode"; import { jwtDecode } from "jwt-decode";
import { baseURL, noAuth } from "./constants"; import { baseURL, noAuth } from "./constants";
import { StatusError } from "@/api/utils"; import { StatusError } from "@/api/utils";
import { setSafeTimeout } from "@/api/utils";
export function parseToken(token: string) { export function parseToken(token: string) {
// falsy or malformed jwt will throw InvalidTokenError // falsy or malformed jwt will throw InvalidTokenError
@@ -16,6 +17,18 @@ export function parseToken(token: string) {
const authStore = useAuthStore(); const authStore = useAuthStore();
authStore.jwt = token; authStore.jwt = token;
authStore.setUser(data.user); authStore.setUser(data.user);
if (authStore.logoutTimer) {
clearTimeout(authStore.logoutTimer);
}
const expiresAt = new Date(data.exp! * 1000);
const timeout = expiresAt.getTime() - Date.now();
authStore.setLogoutTimer(
setSafeTimeout(() => {
logout("inactivity");
}, timeout)
);
} }
export async function validateLogin() { export async function validateLogin() {
@@ -92,7 +105,7 @@ export async function signup(username: string, password: string) {
} }
} }
export function logout() { export function logout(reason?: string) {
document.cookie = "auth=; Max-Age=0; Path=/; SameSite=Strict;"; document.cookie = "auth=; Max-Age=0; Path=/; SameSite=Strict;";
const authStore = useAuthStore(); const authStore = useAuthStore();
@@ -102,6 +115,15 @@ export function logout() {
if (noAuth) { if (noAuth) {
window.location.reload(); window.location.reload();
} else { } else {
router.push({ path: "/login" }); if (typeof reason === "string" && reason.trim() !== "") {
router.push({
path: "/login",
query: { "logout-reason": reason },
});
} else {
router.push({
path: "/login",
});
}
} }
} }

View File

@@ -1,4 +1,6 @@
import { theme } from "./constants"; import { theme } from "./constants";
import "ace-builds";
import { themesByName } from "ace-builds/src-noconflict/ext-themelist";
export const getTheme = (): UserTheme => { export const getTheme = (): UserTheme => {
return (document.documentElement.className as UserTheme) || theme; return (document.documentElement.className as UserTheme) || theme;
@@ -32,3 +34,17 @@ export const getMediaPreference = (): UserTheme => {
return "light"; return "light";
} }
}; };
export const getEditorTheme = (themeName: string) => {
if (!themeName.startsWith("ace/theme/")) {
themeName = `ace/theme/${themeName}`;
}
const themeKey = themeName.replace("ace/theme/", "");
if (themesByName[themeKey] !== undefined) {
return themeName;
} else if (getTheme() === "dark") {
return "ace/theme/twilight";
} else {
return "ace/theme/chrome";
}
};

View File

@@ -132,7 +132,6 @@ export function handleFiles(
layoutStore.closeHovers(); layoutStore.closeHovers();
for (const file of files) { for (const file of files) {
const id = uploadStore.id;
let path = base; let path = base;
if (file.fullPath !== undefined) { if (file.fullPath !== undefined) {
@@ -145,14 +144,8 @@ export function handleFiles(
path += "/"; path += "/";
} }
const item: UploadItem = { const type = file.isDir ? "dir" : detectType((file.file as File).type);
id,
path,
file,
overwrite,
...(!file.isDir && { type: detectType((file.file as File).type) }),
};
uploadStore.upload(item); uploadStore.upload(path, file.name, file.file ?? null, overwrite, type);
} }
} }

View File

@@ -36,7 +36,6 @@ import { files as api } from "@/api";
import { storeToRefs } from "pinia"; import { storeToRefs } from "pinia";
import { useFileStore } from "@/stores/file"; import { useFileStore } from "@/stores/file";
import { useLayoutStore } from "@/stores/layout"; import { useLayoutStore } from "@/stores/layout";
import { useUploadStore } from "@/stores/upload";
import HeaderBar from "@/components/header/HeaderBar.vue"; import HeaderBar from "@/components/header/HeaderBar.vue";
import Breadcrumbs from "@/components/Breadcrumbs.vue"; import Breadcrumbs from "@/components/Breadcrumbs.vue";
@@ -52,10 +51,8 @@ const Preview = defineAsyncComponent(() => import("@/views/files/Preview.vue"));
const layoutStore = useLayoutStore(); const layoutStore = useLayoutStore();
const fileStore = useFileStore(); const fileStore = useFileStore();
const uploadStore = useUploadStore();
const { reload } = storeToRefs(fileStore); const { reload } = storeToRefs(fileStore);
const { error: uploadError } = storeToRefs(uploadStore);
const route = useRoute(); const route = useRoute();
@@ -108,9 +105,6 @@ watch(route, () => {
watch(reload, (newValue) => { watch(reload, (newValue) => {
newValue && fetchData(); newValue && fetchData();
}); });
watch(uploadError, (newValue) => {
newValue && layoutStore.showError();
});
// Define functions // Define functions

View File

@@ -1,7 +1,11 @@
<template> <template>
<div> <div>
<div v-if="uploadStore.getProgress" class="progress"> <div v-if="uploadStore.totalBytes" class="progress">
<div v-bind:style="{ width: uploadStore.getProgress + '%' }"></div> <div
v-bind:style="{
width: sentPercent + '%',
}"
></div>
</div> </div>
<sidebar></sidebar> <sidebar></sidebar>
<main> <main>
@@ -27,7 +31,7 @@ import Prompts from "@/components/prompts/Prompts.vue";
import Shell from "@/components/Shell.vue"; import Shell from "@/components/Shell.vue";
import UploadFiles from "@/components/prompts/UploadFiles.vue"; import UploadFiles from "@/components/prompts/UploadFiles.vue";
import { enableExec } from "@/utils/constants"; import { enableExec } from "@/utils/constants";
import { watch } from "vue"; import { computed, watch } from "vue";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
const layoutStore = useLayoutStore(); const layoutStore = useLayoutStore();
@@ -36,6 +40,10 @@ const fileStore = useFileStore();
const uploadStore = useUploadStore(); const uploadStore = useUploadStore();
const route = useRoute(); const route = useRoute();
const sentPercent = computed(() =>
((uploadStore.sentBytes / uploadStore.totalBytes) * 100).toFixed(2)
);
watch(route, () => { watch(route, () => {
fileStore.selected = []; fileStore.selected = [];
fileStore.multiple = false; fileStore.multiple = false;

View File

@@ -3,6 +3,9 @@
<form @submit="submit"> <form @submit="submit">
<img :src="logoURL" alt="File Browser" /> <img :src="logoURL" alt="File Browser" />
<h1>{{ name }}</h1> <h1>{{ name }}</h1>
<p v-if="reason != null" class="logout-message">
{{ t(`login.logout_reasons.${reason}`) }}
</p>
<div v-if="error !== ''" class="wrong">{{ error }}</div> <div v-if="error !== ''" class="wrong">{{ error }}</div>
<input <input
@@ -70,6 +73,8 @@ const toggleMode = () => (createMode.value = !createMode.value);
const $showError = inject<IToastError>("$showError")!; const $showError = inject<IToastError>("$showError")!;
const reason = route.query["logout-reason"] ?? null;
const submit = async (event: Event) => { const submit = async (event: Event) => {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();

View File

@@ -1,5 +1,5 @@
<template> <template>
<div id="editor-container" @wheel.prevent.stop> <div id="editor-container">
<header-bar> <header-bar>
<action icon="close" :label="t('buttons.close')" @action="close()" /> <action icon="close" :label="t('buttons.close')" @action="close()" />
<title>{{ fileStore.req?.name ?? "" }}</title> <title>{{ fileStore.req?.name ?? "" }}</title>
@@ -69,7 +69,7 @@ import HeaderBar from "@/components/header/HeaderBar.vue";
import { useAuthStore } from "@/stores/auth"; import { useAuthStore } from "@/stores/auth";
import { useFileStore } from "@/stores/file"; import { useFileStore } from "@/stores/file";
import { useLayoutStore } from "@/stores/layout"; import { useLayoutStore } from "@/stores/layout";
import { getTheme } from "@/utils/theme"; import { getEditorTheme } from "@/utils/theme";
import { marked } from "marked"; import { marked } from "marked";
import { inject, onBeforeUnmount, onMounted, ref, watchEffect } from "vue"; import { inject, onBeforeUnmount, onMounted, ref, watchEffect } from "vue";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
@@ -97,7 +97,6 @@ const isMarkdownFile =
onMounted(() => { onMounted(() => {
window.addEventListener("keydown", keyEvent); window.addEventListener("keydown", keyEvent);
window.addEventListener("wheel", handleScroll);
window.addEventListener("beforeunload", handlePageChange); window.addEventListener("beforeunload", handlePageChange);
const fileContent = fileStore.req?.content || ""; const fileContent = fileStore.req?.content || "";
@@ -111,13 +110,6 @@ onMounted(() => {
console.error("Failed to convert content to HTML:", error); console.error("Failed to convert content to HTML:", error);
previewContent.value = ""; previewContent.value = "";
} }
const previewContainer = document.getElementById("preview-container");
if (previewContainer) {
previewContainer.addEventListener("wheel", handleScroll, {
capture: true,
});
}
} }
}); });
@@ -130,7 +122,7 @@ onMounted(() => {
value: fileContent, value: fileContent,
showPrintMargin: false, showPrintMargin: false,
readOnly: fileStore.req?.type === "textImmutable", readOnly: fileStore.req?.type === "textImmutable",
theme: "ace/theme/chrome", theme: getEditorTheme(authStore.user?.aceEditorTheme ?? ""),
mode: modelist.getModeForPath(fileStore.req!.name).mode, mode: modelist.getModeForPath(fileStore.req!.name).mode,
wrap: true, wrap: true,
enableBasicAutocompletion: true, enableBasicAutocompletion: true,
@@ -138,17 +130,12 @@ onMounted(() => {
enableSnippets: true, enableSnippets: true,
}); });
if (getTheme() === "dark") {
editor.value!.setTheme("ace/theme/twilight");
}
editor.value.setFontSize(fontSize.value); editor.value.setFontSize(fontSize.value);
editor.value.focus(); editor.value.focus();
}); });
onBeforeUnmount(() => { onBeforeUnmount(() => {
window.removeEventListener("keydown", keyEvent); window.removeEventListener("keydown", keyEvent);
window.removeEventListener("wheel", handleScroll);
window.removeEventListener("beforeunload", handlePageChange); window.removeEventListener("beforeunload", handlePageChange);
editor.value?.destroy(); editor.value?.destroy();
}); });
@@ -166,6 +153,10 @@ onBeforeRouteUpdate((to, from, next) => {
event.preventDefault(); event.preventDefault();
next(); next();
}, },
saveAction: async () => {
await save();
next();
},
}); });
}); });
@@ -186,13 +177,6 @@ const keyEvent = (event: KeyboardEvent) => {
save(); save();
}; };
const handleScroll = (event: WheelEvent) => {
const editorContainer = document.getElementById("preview-container");
if (editorContainer) {
editorContainer.scrollTop += event.deltaY;
}
};
const handlePageChange = (event: BeforeUnloadEvent) => { const handlePageChange = (event: BeforeUnloadEvent) => {
if (!editor.value?.session.getUndoManager().isClean()) { if (!editor.value?.session.getUndoManager().isClean()) {
event.preventDefault(); event.preventDefault();
@@ -231,6 +215,25 @@ const decreaseFontSize = () => {
}; };
const close = () => { const close = () => {
if (!editor.value?.session.getUndoManager().isClean()) {
layoutStore.showHover({
prompt: "discardEditorChanges",
confirm: (event: Event) => {
event.preventDefault();
finishClose();
},
saveAction: async () => {
await save();
finishClose();
},
});
return;
}
finishClose();
};
const finishClose = () => {
fileStore.updateRequest(null);
const uri = url.removeLastDir(route.path) + "/"; const uri = url.removeLastDir(route.path) + "/";
router.push({ path: uri }); router.push({ path: uri });
}; };

View File

@@ -65,7 +65,7 @@
<a <a
class="link" class="link"
target="_blank" target="_blank"
href="https://filebrowser.org/configuration.html#command-runner" href="https://filebrowser.org/configuration.html#custom-branding"
>{{ t("settings.documentation") }}</a >{{ t("settings.documentation") }}</a
> >
</i18n-t> </i18n-t>

View File

@@ -24,6 +24,13 @@
class="input input--block" class="input input--block"
v-model:locale="locale" v-model:locale="locale"
></languages> ></languages>
<h3>{{ t("settings.aceEditorTheme") }}</h3>
<AceEditorTheme
class="input input--block"
v-model:aceEditorTheme="aceEditorTheme"
id="aceTheme"
></AceEditorTheme>
</div> </div>
<div class="card-action"> <div class="card-action">
@@ -81,6 +88,7 @@
import { useAuthStore } from "@/stores/auth"; import { useAuthStore } from "@/stores/auth";
import { useLayoutStore } from "@/stores/layout"; import { useLayoutStore } from "@/stores/layout";
import { users as api } from "@/api"; import { users as api } from "@/api";
import AceEditorTheme from "@/components/settings/AceEditorTheme.vue";
import Languages from "@/components/settings/Languages.vue"; import Languages from "@/components/settings/Languages.vue";
import { computed, inject, onMounted, ref } from "vue"; import { computed, inject, onMounted, ref } from "vue";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
@@ -98,6 +106,7 @@ const hideDotfiles = ref<boolean>(false);
const singleClick = ref<boolean>(false); const singleClick = ref<boolean>(false);
const dateFormat = ref<boolean>(false); const dateFormat = ref<boolean>(false);
const locale = ref<string>(""); const locale = ref<string>("");
const aceEditorTheme = ref<string>("");
const passwordClass = computed(() => { const passwordClass = computed(() => {
const baseClass = "input input--block"; const baseClass = "input input--block";
@@ -113,13 +122,14 @@ const passwordClass = computed(() => {
return `${baseClass} input--red`; return `${baseClass} input--red`;
}); });
onMounted(() => { onMounted(async () => {
layoutStore.loading = true; layoutStore.loading = true;
if (authStore.user === null) return false; if (authStore.user === null) return false;
locale.value = authStore.user.locale; locale.value = authStore.user.locale;
hideDotfiles.value = authStore.user.hideDotfiles; hideDotfiles.value = authStore.user.hideDotfiles;
singleClick.value = authStore.user.singleClick; singleClick.value = authStore.user.singleClick;
dateFormat.value = authStore.user.dateFormat; dateFormat.value = authStore.user.dateFormat;
aceEditorTheme.value = authStore.user.aceEditorTheme;
layoutStore.loading = false; layoutStore.loading = false;
return true; return true;
}); });
@@ -163,6 +173,7 @@ const updateSettings = async (event: Event) => {
hideDotfiles: hideDotfiles.value, hideDotfiles: hideDotfiles.value,
singleClick: singleClick.value, singleClick: singleClick.value,
dateFormat: dateFormat.value, dateFormat: dateFormat.value,
aceEditorTheme: aceEditorTheme.value,
}; };
await api.update(data, [ await api.update(data, [
@@ -170,6 +181,7 @@ const updateSettings = async (event: Event) => {
"hideDotfiles", "hideDotfiles",
"singleClick", "singleClick",
"dateFormat", "dateFormat",
"aceEditorTheme",
]); ]);
authStore.updateUser(data); authStore.updateUser(data);
$showSuccess(t("settings.settingsUpdated")); $showSuccess(t("settings.settingsUpdated"));

View File

@@ -9,7 +9,6 @@
"src/components/prompts/Delete.vue", "src/components/prompts/Delete.vue",
"src/components/prompts/FileList.vue", "src/components/prompts/FileList.vue",
"src/components/prompts/Rename.vue", "src/components/prompts/Rename.vue",
"src/components/prompts/Share.vue", "src/components/prompts/Share.vue"
"src/components/prompts/UploadFiles.vue"
] ]
} }

View File

@@ -21,16 +21,17 @@ const (
) )
type userInfo struct { type userInfo struct {
ID uint `json:"id"` ID uint `json:"id"`
Locale string `json:"locale"` Locale string `json:"locale"`
ViewMode users.ViewMode `json:"viewMode"` ViewMode users.ViewMode `json:"viewMode"`
SingleClick bool `json:"singleClick"` SingleClick bool `json:"singleClick"`
Perm users.Permissions `json:"perm"` Perm users.Permissions `json:"perm"`
Commands []string `json:"commands"` Commands []string `json:"commands"`
LockPassword bool `json:"lockPassword"` LockPassword bool `json:"lockPassword"`
HideDotfiles bool `json:"hideDotfiles"` HideDotfiles bool `json:"hideDotfiles"`
DateFormat bool `json:"dateFormat"` DateFormat bool `json:"dateFormat"`
Username string `json:"username"` Username string `json:"username"`
AceEditorTheme string `json:"aceEditorTheme"`
} }
type authToken struct { type authToken struct {
@@ -50,11 +51,6 @@ func (e extractor) ExtractToken(r *http.Request) (string, error) {
return token, nil return token, nil
} }
auth := r.URL.Query().Get("auth")
if auth != "" && strings.Count(auth, ".") == 2 {
return auth, nil
}
if r.Method == http.MethodGet { if r.Method == http.MethodGet {
cookie, _ := r.Cookie("auth") cookie, _ := r.Cookie("auth")
if cookie != nil && strings.Count(cookie.Value, ".") == 2 { if cookie != nil && strings.Count(cookie.Value, ".") == 2 {
@@ -190,16 +186,17 @@ func renewHandler(tokenExpireTime time.Duration) handleFunc {
func printToken(w http.ResponseWriter, _ *http.Request, d *data, user *users.User, tokenExpirationTime time.Duration) (int, error) { func printToken(w http.ResponseWriter, _ *http.Request, d *data, user *users.User, tokenExpirationTime time.Duration) (int, error) {
claims := &authToken{ claims := &authToken{
User: userInfo{ User: userInfo{
ID: user.ID, ID: user.ID,
Locale: user.Locale, Locale: user.Locale,
ViewMode: user.ViewMode, ViewMode: user.ViewMode,
SingleClick: user.SingleClick, SingleClick: user.SingleClick,
Perm: user.Perm, Perm: user.Perm,
LockPassword: user.LockPassword, LockPassword: user.LockPassword,
Commands: user.Commands, Commands: user.Commands,
HideDotfiles: user.HideDotfiles, HideDotfiles: user.HideDotfiles,
DateFormat: user.DateFormat, DateFormat: user.DateFormat,
Username: user.Username, Username: user.Username,
AceEditorTheme: user.AceEditorTheme,
}, },
RegisteredClaims: jwt.RegisteredClaims{ RegisteredClaims: jwt.RegisteredClaims{
IssuedAt: jwt.NewNumericDate(time.Now()), IssuedAt: jwt.NewNumericDate(time.Now()),

View File

@@ -8,15 +8,16 @@ import (
// UserDefaults is a type that holds the default values // UserDefaults is a type that holds the default values
// for some fields on User. // for some fields on User.
type UserDefaults struct { type UserDefaults struct {
Scope string `json:"scope"` Scope string `json:"scope"`
Locale string `json:"locale"` Locale string `json:"locale"`
ViewMode users.ViewMode `json:"viewMode"` ViewMode users.ViewMode `json:"viewMode"`
SingleClick bool `json:"singleClick"` SingleClick bool `json:"singleClick"`
Sorting files.Sorting `json:"sorting"` Sorting files.Sorting `json:"sorting"`
Perm users.Permissions `json:"perm"` Perm users.Permissions `json:"perm"`
Commands []string `json:"commands"` Commands []string `json:"commands"`
HideDotfiles bool `json:"hideDotfiles"` HideDotfiles bool `json:"hideDotfiles"`
DateFormat bool `json:"dateFormat"` DateFormat bool `json:"dateFormat"`
AceEditorTheme string `json:"aceEditorTheme"`
} }
// Apply applies the default options to a user. // Apply applies the default options to a user.
@@ -30,4 +31,5 @@ func (d *UserDefaults) Apply(u *users.User) {
u.Commands = d.Commands u.Commands = d.Commands
u.HideDotfiles = d.HideDotfiles u.HideDotfiles = d.HideDotfiles
u.DateFormat = d.DateFormat u.DateFormat = d.DateFormat
u.AceEditorTheme = d.AceEditorTheme
} }

View File

@@ -69,7 +69,7 @@ require (
github.com/go-toolsmith/astp v1.1.0 // indirect github.com/go-toolsmith/astp v1.1.0 // indirect
github.com/go-toolsmith/strparse v1.1.0 // indirect github.com/go-toolsmith/strparse v1.1.0 // indirect
github.com/go-toolsmith/typep v1.1.0 // indirect github.com/go-toolsmith/typep v1.1.0 // indirect
github.com/go-viper/mapstructure/v2 v2.3.0 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
github.com/go-xmlfmt/xmlfmt v1.1.3 // indirect github.com/go-xmlfmt/xmlfmt v1.1.3 // indirect
github.com/gobwas/glob v0.2.3 // indirect github.com/gobwas/glob v0.2.3 // indirect
github.com/gofrs/flock v0.12.1 // indirect github.com/gofrs/flock v0.12.1 // indirect

View File

@@ -207,8 +207,8 @@ github.com/go-toolsmith/strparse v1.1.0 h1:GAioeZUK9TGxnLS+qfdqNbA4z0SSm5zVNtCQi
github.com/go-toolsmith/strparse v1.1.0/go.mod h1:7ksGy58fsaQkGQlY8WVoBFNyEPMGuJin1rfoPS4lBSQ= github.com/go-toolsmith/strparse v1.1.0/go.mod h1:7ksGy58fsaQkGQlY8WVoBFNyEPMGuJin1rfoPS4lBSQ=
github.com/go-toolsmith/typep v1.1.0 h1:fIRYDyF+JywLfqzyhdiHzRop/GQDxxNhLGQ6gFUNHus= github.com/go-toolsmith/typep v1.1.0 h1:fIRYDyF+JywLfqzyhdiHzRop/GQDxxNhLGQ6gFUNHus=
github.com/go-toolsmith/typep v1.1.0/go.mod h1:fVIw+7zjdsMxDA3ITWnH1yOiw1rnTQKCsF/sk2H/qig= github.com/go-toolsmith/typep v1.1.0/go.mod h1:fVIw+7zjdsMxDA3ITWnH1yOiw1rnTQKCsF/sk2H/qig=
github.com/go-viper/mapstructure/v2 v2.3.0 h1:27XbWsHIqhbdR5TIC911OfYvgSaW93HM+dX7970Q7jk= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
github.com/go-viper/mapstructure/v2 v2.3.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/go-xmlfmt/xmlfmt v1.1.3 h1:t8Ey3Uy7jDSEisW2K3somuMKIpzktkWptA0iFCnRUWY= github.com/go-xmlfmt/xmlfmt v1.1.3 h1:t8Ey3Uy7jDSEisW2K3somuMKIpzktkWptA0iFCnRUWY=
github.com/go-xmlfmt/xmlfmt v1.1.3/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= github.com/go-xmlfmt/xmlfmt v1.1.3/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM=
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=

View File

@@ -3,5 +3,6 @@
"@commitlint/cli": "^15.0.0", "@commitlint/cli": "^15.0.0",
"@commitlint/config-conventional": "^15.0.0", "@commitlint/config-conventional": "^15.0.0",
"standard-version": "^9.3.2" "standard-version": "^9.3.2"
} },
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
} }

View File

@@ -20,21 +20,22 @@ const (
// User describes a user. // User describes a user.
type User struct { type User struct {
ID uint `storm:"id,increment" json:"id"` ID uint `storm:"id,increment" json:"id"`
Username string `storm:"unique" json:"username"` Username string `storm:"unique" json:"username"`
Password string `json:"password"` Password string `json:"password"`
Scope string `json:"scope"` Scope string `json:"scope"`
Locale string `json:"locale"` Locale string `json:"locale"`
LockPassword bool `json:"lockPassword"` LockPassword bool `json:"lockPassword"`
ViewMode ViewMode `json:"viewMode"` ViewMode ViewMode `json:"viewMode"`
SingleClick bool `json:"singleClick"` SingleClick bool `json:"singleClick"`
Perm Permissions `json:"perm"` Perm Permissions `json:"perm"`
Commands []string `json:"commands"` Commands []string `json:"commands"`
Sorting files.Sorting `json:"sorting"` Sorting files.Sorting `json:"sorting"`
Fs afero.Fs `json:"-" yaml:"-"` Fs afero.Fs `json:"-" yaml:"-"`
Rules []rules.Rule `json:"rules"` Rules []rules.Rule `json:"rules"`
HideDotfiles bool `json:"hideDotfiles"` HideDotfiles bool `json:"hideDotfiles"`
DateFormat bool `json:"dateFormat"` DateFormat bool `json:"dateFormat"`
AceEditorTheme string `json:"aceEditorTheme"`
} }
// GetRules implements rules.Provider. // GetRules implements rules.Provider.

View File

@@ -1,6 +1,6 @@
# Configuration # Configuration
Most of the configuration can be understood through our Command Line Interface documentation. Although there are some specific topics that we want to cover on this section. Most of the configuration can be understood through the command line interface documentation. To access it, you need to install File Browser and run `filebrowser --help`. In this page, we cover some specific, more complex, topics.
## Custom Branding ## Custom Branding