Compare commits

..

66 Commits

Author SHA1 Message Date
Henrique Dias
dbdbbab4d7 chore(release): 2.33.3 2025-06-22 17:57:34 +02:00
Henrique Dias
7c0c7820ef fix: keep command behavior in Dockerfile 2025-06-22 17:55:57 +02:00
Arion2000
2741616473 fix: update search hotkey in help prompt (#5178) 2025-06-22 12:45:21 +02:00
Henrique Dias
ffb858e4ef chore(release): 2.33.2 2025-06-21 10:37:30 +02:00
Henrique Dias
0ca8059d8d fix: create user dir on signup 2025-06-21 10:32:50 +02:00
Henrique Dias
8ca080422f chore(release): 2.33.1 2025-06-21 09:25:18 +02:00
Henrique Dias
cbb712484d fix: remove auth query parameter from download and preview links
macOS saves the download URL in the metadata of the downloaded file.
This means that the downloaded file contains a metadata item with the JWT
token of the user. If the user were to share this file with someone else,
they would have access to their account using the JWT in the metadata
during the validity of the JWT.

The JWT has been removed from the URLs. Since the user is logged in, there
is an authentication cookie set. A JWT in the URL is not necessary.
2025-06-21 09:21:39 +02:00
Patrick Wang
8a14018861 fix: downloadUrl of file preview (#3728) 2025-06-21 09:21:17 +02:00
Henrique Dias
a493ec90ff docs: add more docker notes 2025-06-21 08:45:53 +02:00
Henrique Dias
33113036cd docs: update security.md 2025-06-20 21:41:46 +02:00
contributor
a02b2972eb fix: search uses ctrl+shift+f instead of hijacking browser's ctrl+f (#4638) 2025-06-19 21:57:57 +02:00
Henrique Dias
e9bb3dc243 chore(release): 2.33.0 2025-06-18 21:58:42 +02:00
Henrique Dias
2e26393a02 feat: improved docker image volumes and permissions (#5160) 2025-06-18 21:53:02 +02:00
Henrique Dias
04a13f086f chore(release): 2.32.3 2025-06-17 16:47:53 +02:00
Henrique Dias
1cc539eb8a ci: fix the post install tap command 2025-06-17 16:47:34 +02:00
Henrique Dias
6ebfdcceaa chore(release): 2.32.2 2025-06-17 16:34:37 +02:00
Henrique Dias
db671c227b ci: update gorelease homebrew 2025-06-17 16:34:04 +02:00
Henrique Dias
4aee14de44 ci: add @hacdias as codeowner 2025-06-17 16:30:02 +02:00
Henrique Dias
0cca7d8dc0 docs: move most docs to main repository (#5141) 2025-06-17 11:37:15 +02:00
transifex-integration[bot]
c34c0afecf feat: updated for project File Browser (#5159)
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-06-17 09:05:21 +02:00
Henrique Dias
56a0f9244b chore(release): 2.32.1 2025-06-16 20:18:42 +02:00
michioxd
56b80b6d9b feat: add Vietnamese translation (#3840) 2025-06-16 18:47:20 +02:00
Dev_Nergis
d9ebd65ffc feat: update translation ko.json (#3852) 2025-06-16 18:35:50 +02:00
SOMA
a882fb6c85 feat: improve pt-br translations with new keys and refinements (#4903) 2025-06-16 17:39:57 +02:00
Henrique Dias
5daae69a6d chore: revert only translated mode to transifex 2025-06-15 21:05:30 +02:00
Henrique Dias
54a1ae0fa0 chore: add only translated mode to transifex 2025-06-15 20:48:01 +02:00
Henrique Dias
b6b4fb5da7 ci: remove manual .tx config 2025-06-15 20:13:21 +02:00
Henrique Dias
6d82a27f9a ci: add transifex.yml 2025-06-15 20:13:03 +02:00
Henrique Dias
31a326606d chore: updated readme and template 2025-06-13 22:46:22 +02:00
Henrique Dias
abbf203bdd chore: updated readme and templates 2025-06-13 22:46:22 +02:00
Henrique Dias
e82e2392a4 chore: update Go dependencies 2025-06-11 18:51:01 +02:00
Henrique Dias
f4a8420bf3 docs: add maintenance warning to readme 2025-06-11 17:44:32 +02:00
Simon
71a8f5662c fix: set videojs locale (#3742)
Co-authored-by: Oleg Lobanov <oleg@lobanov.me>
2025-06-05 15:53:29 +02:00
Henrique Dias
48f894740f chore: remove stale bot 2025-06-04 19:08:43 +02:00
Henrique Dias
b883e287a0 chore: migrate transifex settings 2025-06-04 18:58:48 +02:00
Henrique Dias
5d9f0977d6 Merge pull request #3675 from bo0tzz/fix/random-password 2025-06-04 17:39:32 +02:00
bo0tzz
c606a01a2d fix: err shadowing lint 2025-06-04 17:36:55 +02:00
bo0tzz
54b91b8ff0 fix: imports lint 2025-06-04 17:36:55 +02:00
bo0tzz
a46acba5f9 fix: generate random admin password on quick setup
This should help mitigate issues like #3646
2025-06-04 17:36:55 +02:00
Henrique Dias
1d14798653 Merge pull request #3776 from Matthaiks/pl 2025-06-04 17:35:00 +02:00
Matthaiks
6d55cc59f7 chore: Update Polish translation 2025-06-04 17:32:41 +02:00
Matthaiks
495e731ee7 Update Polish translation 2025-06-04 17:32:41 +02:00
Henrique Dias
ff1579b950 Merge pull request #3793 from Kcchouette/patch-1 2025-06-04 17:24:12 +02:00
Kcchouette
7a48fd0c3e Merge branch 'master' into patch-1 2025-05-20 11:23:27 +00:00
dependabot[bot]
cfea84fd5e build(deps): bump golang.org/x/net from 0.33.0 to 0.38.0 (#3869) 2025-05-19 12:27:04 +00:00
dependabot[bot]
0ba9505a19 build(deps): bump golang.org/x/crypto from 0.31.0 to 0.35.0 (#3865)
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.31.0 to 0.35.0.
- [Commits](https://github.com/golang/crypto/compare/v0.31.0...v0.35.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-19 14:24:09 +02:00
dependabot[bot]
5355629fd1 build(deps-dev): bump vite from 6.0.11 to 6.1.6 in /frontend (#3886)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 6.0.11 to 6.1.6.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v6.1.6/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v6.1.6/packages/vite)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-19 13:49:42 +02:00
Kcchouette
f8a16a6aca Merge branch 'master' into patch-1 2025-04-19 09:22:44 +00:00
dependabot[bot]
35d1c09243 build(deps): bump vue-i18n from 11.0.1 to 11.1.2 in /frontend (#3786)
Bumps [vue-i18n](https://github.com/intlify/vue-i18n/tree/HEAD/packages/vue-i18n) from 11.0.1 to 11.1.2.
- [Release notes](https://github.com/intlify/vue-i18n/releases)
- [Changelog](https://github.com/intlify/vue-i18n/blob/master/CHANGELOG.md)
- [Commits](https://github.com/intlify/vue-i18n/commits/v11.1.2/packages/vue-i18n)

---
updated-dependencies:
- dependency-name: vue-i18n
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-19 17:03:45 +01:00
Kcchouette
99c64c12ed Update french translation 2025-03-10 21:04:12 +00:00
Oleg Lobanov
3d6c5152fe chore(release): 2.32.0 2025-01-31 09:48:22 +01:00
Oleg Lobanov
ba797cda31 build: fix go releaser 2025-01-31 09:48:08 +01:00
Arran Hobson Sayers
5300d00d2e fix: Fix user creation on proxy auth (#3666)
* Fix user creation on proxy auth

* Refactoring

---------

Co-authored-by: Oleg Lobanov <oleg@lobanov.me>
2025-01-30 11:28:19 +01:00
elmodor
bbdd313705 fix: disk usage refreshing (#3692)
Co-authored-by: Oleg Lobanov <oleg@lobanov.me>
2025-01-30 10:32:05 +01:00
Eden Yemini
045064f8b8 fix: add proper healthcheck for S6 containers (#3691)
Co-authored-by: Oleg Lobanov <oleg@lobanov.me>
2025-01-30 10:29:14 +01:00
정성민
252f0a7533 chore: update ko.json (#3688) 2025-01-30 10:24:44 +01:00
dependabot[bot]
1194cfe009 build(deps): bump golang.org/x/net from 0.23.0 to 0.33.0 (#3712)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.23.0 to 0.33.0.
- [Commits](https://github.com/golang/net/compare/v0.23.0...v0.33.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-30 10:22:04 +01:00
kloon15
0201f9c5c4 refactor: Fix eslint warnings (#3698)
* Update dependencies and remove typescript version pinning (fixed upstream)

* Fix esling warnings (disabled any and script lang checks)
Rewrote clipboard copy (Fixes #3407)
Run prettier

---------

Co-authored-by: Oleg Lobanov <oleg@lobanov.me>
2025-01-30 10:18:48 +01:00
Juan Bernárdez
cc331383fb chore: add translation for the "Hide dot files setting" in "es" (Spanish) language (#3704) 2025-01-30 10:16:40 +01:00
Ryan
d1c84a8412 fix: prompts disappearing on copy / move / upload (#3537)
---------

Co-authored-by: Ryan Miller <ryan.miller@infinitetactics.com>
Co-authored-by: Oleg Lobanov <oleg@lobanov.me>
2025-01-21 00:05:59 +01:00
dependabot[bot]
e92dbb4bb8 build(deps): bump golang.org/x/crypto from 0.26.0 to 0.31.0 (#3634)
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.26.0 to 0.31.0.
- [Commits](https://github.com/golang/crypto/compare/v0.26.0...v0.31.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-16 22:07:57 +01:00
Arran Hobson Sayers
209acf2429 feat: create user on proxy authentication if user does not exist (#3569)
---------

Co-authored-by: Oleg Lobanov <oleg@lobanov.me>
2024-12-16 22:05:13 +01:00
dependabot[bot]
25372edb5c build(deps): bump cross-spawn from 7.0.3 to 7.0.6 in /tools (#3601)
Bumps [cross-spawn](https://github.com/moxystudio/node-cross-spawn) from 7.0.3 to 7.0.6.
- [Changelog](https://github.com/moxystudio/node-cross-spawn/blob/master/CHANGELOG.md)
- [Commits](https://github.com/moxystudio/node-cross-spawn/compare/v7.0.3...v7.0.6)

---
updated-dependencies:
- dependency-name: cross-spawn
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-12 18:02:05 +01:00
kloon15
d51a343820 build: update to node 22 and pnpm (#3616)
This commit brings the project to support node 22 which became LTS and
fixes broken builds with typescript 5.7+ until vue-tsc is updated and
replaces npm with pnpm.

- Update tsconfig for node 22
- Pin typescript to 5.6.x to not break vue-tsc
- Replace npm with pnpm (corepack recommended)
- Update Makefile and main workflow for pnpm
- Migrate to eslint 9 flat config
- Fix broken imports
- Exclude non-TS vue files for vue-tsc
2024-12-09 12:27:18 +01:00
dependabot[bot]
065959451d build(deps): bump vue-i18n from 9.10.2 to 9.14.2 in /frontend (#3618)
Bumps [vue-i18n](https://github.com/intlify/vue-i18n/tree/HEAD/packages/vue-i18n) from 9.10.2 to 9.14.2.
- [Release notes](https://github.com/intlify/vue-i18n/releases)
- [Changelog](https://github.com/intlify/vue-i18n/blob/master/CHANGELOG.md)
- [Commits](https://github.com/intlify/vue-i18n/commits/v9.14.2/packages/vue-i18n)

---
updated-dependencies:
- dependency-name: vue-i18n
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-03 12:54:38 +01:00
dependabot[bot]
2fdea73430 build(deps): bump github.com/golang-jwt/jwt/v4 from 4.5.0 to 4.5.1 (#3574) 2024-11-05 06:49:45 +01:00
110 changed files with 7394 additions and 8881 deletions

View File

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

2
.github/CODEOWNERS vendored
View File

@@ -2,4 +2,4 @@
# Unless a later match takes precedence, @o1egl will be requested for
# review when someone opens a pull request.
* @o1egl
* @o1egl @hacdias

View File

@@ -1,22 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
---
**Description**
<!-- A clear and concise description of what the issue is about. What are you trying to do? -->
**Expected behaviour**
<!-- What did you expect to happen? -->
**What is happening instead?**
<!-- Please, give full error messages and/or log. -->
**Additional context**
<!-- Add any other context about the problem here. If applicable, add screenshots to help explain your problem. -->
**How to reproduce?**
<!-- Tell us how to reproduce this issue. How can someone who is starting from scratch reproduce this behaviour as minimally as possible? -->
**Files**
<!-- A list of relevant files for this issue. Large files can be uploaded one-by-one or in a tarball/zipfile. -->

43
.github/ISSUE_TEMPLATE/bug_report.yml vendored Normal file
View File

@@ -0,0 +1,43 @@
name: Bug Report
description: Report a bug in FileBrowser.
labels: [bug, triage]
body:
- type: checkboxes
attributes:
label: Checklist
description: Please verify that you've followed these steps
options:
- label: This is a bug report, not a question.
required: true
- label: I have searched on the [issue tracker](https://github.com/filebrowser/filebrowser/issues?q=is%3Aissue) for my bug.
required: true
- label: I am running the latest [FileBrowser version](https://github.com/filebrowser/filebrowser/releases) or have an issue updating.
required: true
- type: textarea
id: version
attributes:
label: Version
render: Text
description: |
Enter the version of FileBrowser you are using.
- type: textarea
attributes:
label: Description
description: |
A clear and concise description of what the issue is about. What are you trying to do?
- type: textarea
attributes:
label: What did you expect to happen?
- type: textarea
attributes:
label: What actually happened?
- type: textarea
attributes:
label: Reproduction Steps
description: |
Tell us how to reproduce this issue. How can someone who is starting from scratch reproduce this behavior as minimally as possible?
- type: textarea
attributes:
label: Files
description: |
A list of relevant files for this issue. Large files can be uploaded one-by-one or in a tarball/zipfile.

5
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: GitHub Discussions
url: https://github.com/filebrowser/filebrowser/discussions
about: Please ask questions and discuss features here.

View File

@@ -1,16 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
---
**Is your feature request related to a problem? Please describe.**
<!-- Add a clear and concise description of what the problem is. E.g. *I'm always frustrated when [...]* -->
**Describe the solution you'd like**
<!-- Add a clear and concise description of what you want to happen. -->
**Describe alternatives you've considered**
<!-- Add a clear and concise description of any alternative solutions or features you've considered. -->
**Additional context**
<!-- Add any other context or screenshots about the feature request here. -->

View File

@@ -1,19 +1,16 @@
**Description**
<!--
Please explain the changes you made here.
If the feature changes current behaviour, explain why your solution is better.
-->
## Description
:rotating_light: Before submitting your PR, please indicate which issues are either fixed or closed by this PR. See [GitHub Help: Closing issues using keywords](https://help.github.com/articles/closing-issues-via-commit-messages/).
<!-- Please explain the changes you made here. -->
- [ ] DO make sure you are requesting to **pull a topic/feature/bugfix branch** (right side). Don't request your master!
- [ ] DO make sure you are making a pull request against the **master branch** (left side). Also you should start *your branch* off *our master*.
- [ ] DO make sure that File Browser can be successfully built. See [builds](https://github.com/filebrowser/community/blob/master/builds.md) and [development](https://github.com/filebrowser/community/blob/master/development.md).
- [ ] AVOID breaking the continuous integration build.
## Additional Information
**Further comments**
<!--
If this is a relatively large or complex change, kick off the discussion by explaining why you chose the solution you did, what alternatives you considered, etc.
<!-- If it is a relatively large or complex change, please add more information to explain what you did, how you did it, if you considered any alternatives, etc. -->
:heart: Thank you!
-->
## Checklist
Before submitting your PR, please indicate which issues are either fixed or closed by this PR. See [GitHub Help: Closing issues using keywords](https://help.github.com/articles/closing-issues-via-commit-messages/).
- [ ] I am aware the project is currently in maintenance-only mode. See [README](https://github.com/filebrowser/community/blob/master/README.md)
- [ ] I am aware that translations MUST be made through [Transifex](https://app.transifex.com/file-browser/file-browser/) and that this PR is NOT a translation update
- [ ] I am making a PR against the `master` branch.
- [ ] I am sure File Browser can be successfully built. See [builds](https://github.com/filebrowser/community/blob/master/builds.md) and [development](https://github.com/filebrowser/community/blob/master/development.md).

View File

@@ -3,20 +3,25 @@ name: main
on:
push:
branches:
- 'master'
- "master"
tags:
- 'v*'
- "v*"
pull_request:
jobs:
# linters
# linters
lint-frontend:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
package_json_file: "frontend/package.json"
- uses: actions/setup-node@v4
with:
node-version: '18'
node-version: "22.x"
cache: "pnpm"
cache-dependency-path: "frontend/pnpm-lock.yaml"
- run: make lint-frontend
lint-backend:
runs-on: ubuntu-latest
@@ -32,14 +37,19 @@ jobs:
steps:
- run: echo "done"
# tests
# tests
test-frontend:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
package_json_file: "frontend/package.json"
- uses: actions/setup-node@v4
with:
node-version: '18'
node-version: "22.x"
cache: "pnpm"
cache-dependency-path: "frontend/pnpm-lock.yaml"
- run: make test-frontend
test-backend:
runs-on: ubuntu-latest
@@ -55,7 +65,7 @@ jobs:
steps:
- run: echo "done"
# release
# release
release:
runs-on: ubuntu-latest
needs: [lint, test]
@@ -67,9 +77,14 @@ jobs:
- uses: actions/setup-go@v5
with:
go-version: 1.23.0
- uses: pnpm/action-setup@v4
with:
package_json_file: "frontend/package.json"
- uses: actions/setup-node@v4
with:
node-version: '18'
node-version: "22.x"
cache: "pnpm"
cache-dependency-path: "frontend/pnpm-lock.yaml"
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx

View File

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

View File

@@ -19,31 +19,30 @@ builds:
- freebsd
goarch:
- amd64
- 386
- "386"
- arm
- arm64
- riscv64
goarm:
- 5
- 6
- 7
- "5"
- "6"
- "7"
ignore:
- goos: darwin
goarch: 386
goarch: "386"
- goos: freebsd
goarch: arm
archives:
-
name_template: "{{.Os}}-{{.Arch}}{{if .Arm}}v{{.Arm}}{{end}}-{{ .ProjectName }}"
format: tar.gz
- name_template: "{{.Os}}-{{.Arch}}{{if .Arm}}v{{.Arm}}{{end}}-{{ .ProjectName }}"
formats: ["tar.gz"]
format_overrides:
- goos: windows
format: zip
formats: ["zip"]
dockers:
-
dockerfile: Dockerfile
# Alpine docker images
- dockerfile: Dockerfile
use: buildx
build_flag_templates:
- "--pull"
@@ -59,10 +58,8 @@ dockers:
- "filebrowser/filebrowser:{{ .Tag }}-amd64"
- "filebrowser/filebrowser:v{{ .Major }}-amd64"
extra_files:
- docker_config.json
- healthcheck.sh
-
dockerfile: Dockerfile
- docker
- dockerfile: Dockerfile
use: buildx
build_flag_templates:
- "--pull"
@@ -78,10 +75,8 @@ dockers:
- "filebrowser/filebrowser:{{ .Tag }}-arm64"
- "filebrowser/filebrowser:v{{ .Major }}-arm64"
extra_files:
- docker_config.json
- healthcheck.sh
-
dockerfile: Dockerfile
- docker
- dockerfile: Dockerfile
use: buildx
build_flag_templates:
- "--pull"
@@ -93,15 +88,13 @@ dockers:
- "--platform=linux/arm/v6"
goos: linux
goarch: arm
goarm: '6'
goarm: "6"
image_templates:
- "filebrowser/filebrowser:{{ .Tag }}-armv6"
- "filebrowser/filebrowser:v{{ .Major }}-armv6"
extra_files:
- docker_config.json
- healthcheck.sh
-
dockerfile: Dockerfile
- docker
- dockerfile: Dockerfile
use: buildx
build_flag_templates:
- "--pull"
@@ -113,16 +106,15 @@ dockers:
- "--platform=linux/arm/v7"
goos: linux
goarch: arm
goarm: '7'
goarm: "7"
image_templates:
- "filebrowser/filebrowser:{{ .Tag }}-armv7"
- "filebrowser/filebrowser:v{{ .Major }}-armv7"
extra_files:
- docker_config.json
- healthcheck.sh
## s6 based docker images
-
dockerfile: Dockerfile.s6
- docker
## s6-overlay docker images
- dockerfile: Dockerfile.s6
use: buildx
build_flag_templates:
- "--pull"
@@ -138,9 +130,8 @@ dockers:
- "filebrowser/filebrowser:{{ .Tag }}-amd64-s6"
- "filebrowser/filebrowser:v{{ .Major }}-amd64-s6"
extra_files:
- docker/root
-
dockerfile: Dockerfile.s6.aarch64
- docker
- dockerfile: Dockerfile.s6.aarch64
use: buildx
build_flag_templates:
- "--pull"
@@ -156,7 +147,8 @@ dockers:
- "filebrowser/filebrowser:{{ .Tag }}-arm64-s6"
- "filebrowser/filebrowser:v{{ .Major }}-arm64-s6"
extra_files:
- docker/root
- docker
docker_manifests:
- name_template: "filebrowser/filebrowser:latest"
image_templates:
@@ -173,7 +165,7 @@ docker_manifests:
- "filebrowser/filebrowser:v{{ .Major }}-amd64"
- "filebrowser/filebrowser:v{{ .Major }}-arm64"
- "filebrowser/filebrowser:v{{ .Major }}-armv7"
## s6 image manifests
## s6 image manifests
- name_template: "filebrowser/filebrowser:s6"
image_templates:
- "filebrowser/filebrowser:{{ .Tag }}-amd64-s6"
@@ -186,15 +178,20 @@ docker_manifests:
image_templates:
- "filebrowser/filebrowser:v{{ .Major }}-amd64-s6"
- "filebrowser/filebrowser:v{{ .Major }}-arm64-s6"
brews:
homebrew_casks:
- name: filebrowser
repository:
owner: filebrowser
name: homebrew-tap
directory: Formula
homepage: https://filebrowser.org
commit_author:
name: FileBrowser Robot
email: robot@filebrowser.org
homepage: https://github.com/filebrowser/filebrowser
description: File Browser is a create-your-own-cloud-kind of software where you can install it on a server, direct it to a path and then access your files through a nice web interface
license: "MIT"
hooks:
post:
install: |
if system_command("/usr/bin/xattr", args: ["-h"]).exit_status == 0
system_command "/usr/bin/xattr", args: ["-dr", "com.apple.quarantine", "#{staged_path}/filebrowser"]
end

View File

@@ -1,10 +0,0 @@
[main]
host = https://www.transifex.com
lang_map = pt_BR: pt-br, zh_CN: zh-cn, zh_HK: zh-hk, zh_TW: zh-tw, nl_BE: nl-be, sv_SE: sv-se, cz-CS: cz_cs
[file-browser.file-browser]
file_filter = frontend/src/i18n/<lang>.json
minimum_perc = 50
source_file = frontend/src/i18n/en.json
source_lang = en
type = KEYVALUEJSON

View File

@@ -2,6 +2,102 @@
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.33.3](https://github.com/filebrowser/filebrowser/compare/v2.33.2...v2.33.3) (2025-06-22)
### Bug Fixes
* keep command behavior in Dockerfile ([7c0c782](https://github.com/filebrowser/filebrowser/commit/7c0c7820efbbed2f0499353cc76ecb85d00ff7c3))
* update search hotkey in help prompt ([#5178](https://github.com/filebrowser/filebrowser/issues/5178)) ([2741616](https://github.com/filebrowser/filebrowser/commit/2741616473636d40b7e9f14c9906ada08d328c3c))
### [2.33.2](https://github.com/filebrowser/filebrowser/compare/v2.33.1...v2.33.2) (2025-06-21)
### Bug Fixes
* create user dir on signup ([0ca8059](https://github.com/filebrowser/filebrowser/commit/0ca8059d8dea4fe079146471ce4f24acc96021f2))
### [2.33.1](https://github.com/filebrowser/filebrowser/compare/v2.33.0...v2.33.1) (2025-06-21)
### Bug Fixes
* downloadUrl of file preview ([#3728](https://github.com/filebrowser/filebrowser/issues/3728)) ([8a14018](https://github.com/filebrowser/filebrowser/commit/8a14018861fe581672bbd27cdc3ae5691f70a108))
* remove auth query parameter from download and preview links ([cbb7124](https://github.com/filebrowser/filebrowser/commit/cbb712484d3bdabc033acaf3b696ef4f5865813d))
* search uses ctrl+shift+f instead of hijacking browser's ctrl+f ([#4638](https://github.com/filebrowser/filebrowser/issues/4638)) ([a02b297](https://github.com/filebrowser/filebrowser/commit/a02b2972ebde2a58806ad1377bad46e748b63166))
## [2.33.0](https://github.com/filebrowser/filebrowser/compare/v2.32.3...v2.33.0) (2025-06-18)
### Features
* improved docker image volumes and permissions ([#5160](https://github.com/filebrowser/filebrowser/issues/5160)) ([2e26393](https://github.com/filebrowser/filebrowser/commit/2e26393a022df0eaa9e08727407aba8b997aa728))
### [2.32.3](https://github.com/filebrowser/filebrowser/compare/v2.32.2...v2.32.3) (2025-06-17)
### [2.32.2](https://github.com/filebrowser/filebrowser/compare/v2.32.1...v2.32.2) (2025-06-17)
### Features
* updated for project File Browser ([#5159](https://github.com/filebrowser/filebrowser/issues/5159)) ([c34c0af](https://github.com/filebrowser/filebrowser/commit/c34c0afecf3242b16ad5d5584cd90a6ad323361c))
### [2.32.1](https://github.com/filebrowser/filebrowser/compare/v2.32.0...v2.32.1) (2025-06-16)
### Features
* add Vietnamese translation ([#3840](https://github.com/filebrowser/filebrowser/issues/3840)) ([56b80b6](https://github.com/filebrowser/filebrowser/commit/56b80b6d9b4710538765ba7df5da1f03898f6b81))
* improve pt-br translations with new keys and refinements ([#4903](https://github.com/filebrowser/filebrowser/issues/4903)) ([a882fb6](https://github.com/filebrowser/filebrowser/commit/a882fb6c85ab6ccc845ed0bf3908d8e5e60ce346))
* update translation ko.json ([#3852](https://github.com/filebrowser/filebrowser/issues/3852)) ([d9ebd65](https://github.com/filebrowser/filebrowser/commit/d9ebd65ffcf9b2166fec708d51849796d12b16e0))
### Bug Fixes
* err shadowing lint ([c606a01](https://github.com/filebrowser/filebrowser/commit/c606a01a2d20932fb32ee896234d57631f8c47e4))
* generate random admin password on quick setup ([a46acba](https://github.com/filebrowser/filebrowser/commit/a46acba5f92ee044661880d6ae349e289d984328)), closes [#3646](https://github.com/filebrowser/filebrowser/issues/3646)
* imports lint ([54b91b8](https://github.com/filebrowser/filebrowser/commit/54b91b8ff0b8ee1f02f72425ab97d27a5d942fc3))
* set videojs locale ([#3742](https://github.com/filebrowser/filebrowser/issues/3742)) ([71a8f56](https://github.com/filebrowser/filebrowser/commit/71a8f5662c207e3cd4ee714a5b5a961121f510cd))
### Build
* **deps-dev:** bump vite from 6.0.11 to 6.1.6 in /frontend ([#3886](https://github.com/filebrowser/filebrowser/issues/3886)) ([5355629](https://github.com/filebrowser/filebrowser/commit/5355629fd1e7bd85ee3222fca22da899ba23ea95))
* **deps:** bump golang.org/x/crypto from 0.31.0 to 0.35.0 ([#3865](https://github.com/filebrowser/filebrowser/issues/3865)) ([0ba9505](https://github.com/filebrowser/filebrowser/commit/0ba9505a19cb369653fc9f8260dc02fcc6587629))
* **deps:** bump golang.org/x/net from 0.33.0 to 0.38.0 ([#3869](https://github.com/filebrowser/filebrowser/issues/3869)) ([cfea84f](https://github.com/filebrowser/filebrowser/commit/cfea84fd5e7ec9c1d2366293e5db12baaa4e3a81))
* **deps:** bump vue-i18n from 11.0.1 to 11.1.2 in /frontend ([#3786](https://github.com/filebrowser/filebrowser/issues/3786)) ([35d1c09](https://github.com/filebrowser/filebrowser/commit/35d1c092434b80b22c89a614a02122e9f5965b39))
## [2.32.0](https://github.com/filebrowser/filebrowser/compare/v2.31.2...v2.32.0) (2025-01-31)
### Features
* create user on proxy authentication if user does not exist ([#3569](https://github.com/filebrowser/filebrowser/issues/3569)) ([209acf2](https://github.com/filebrowser/filebrowser/commit/209acf2429b06e2e8d78218937c59fd7e7edd1be))
### Bug Fixes
* add proper healthcheck for S6 containers ([#3691](https://github.com/filebrowser/filebrowser/issues/3691)) ([045064f](https://github.com/filebrowser/filebrowser/commit/045064f8b8bf9f86058e877448085e38da8b3f2e))
* disk usage refreshing ([#3692](https://github.com/filebrowser/filebrowser/issues/3692)) ([bbdd313](https://github.com/filebrowser/filebrowser/commit/bbdd313705b8d253f0c47ad717a6e47b2f46e719))
* Fix user creation on proxy auth ([#3666](https://github.com/filebrowser/filebrowser/issues/3666)) ([5300d00](https://github.com/filebrowser/filebrowser/commit/5300d00d2e7dbb80a252aff57e100113f02506c3))
* prompts disappearing on copy / move / upload ([#3537](https://github.com/filebrowser/filebrowser/issues/3537)) ([d1c84a8](https://github.com/filebrowser/filebrowser/commit/d1c84a84123c77dede05c023b3697a432b56122c))
### Refactorings
* Fix eslint warnings ([#3698](https://github.com/filebrowser/filebrowser/issues/3698)) ([0201f9c](https://github.com/filebrowser/filebrowser/commit/0201f9c5c4dd2a4d5a3503e59cdb8045e8d3a91f)), closes [#3407](https://github.com/filebrowser/filebrowser/issues/3407)
### Build
* **deps:** bump cross-spawn from 7.0.3 to 7.0.6 in /tools ([#3601](https://github.com/filebrowser/filebrowser/issues/3601)) ([25372ed](https://github.com/filebrowser/filebrowser/commit/25372edb5c0e616e82b76b5f523633af57d347e0))
* **deps:** bump github.com/golang-jwt/jwt/v4 from 4.5.0 to 4.5.1 ([#3574](https://github.com/filebrowser/filebrowser/issues/3574)) ([2fdea73](https://github.com/filebrowser/filebrowser/commit/2fdea73430011846276a1cda52458f1d670f5ea7))
* **deps:** bump golang.org/x/crypto from 0.26.0 to 0.31.0 ([#3634](https://github.com/filebrowser/filebrowser/issues/3634)) ([e92dbb4](https://github.com/filebrowser/filebrowser/commit/e92dbb4bb8b7894264fbf0a48a641712c3b68766))
* **deps:** bump golang.org/x/net from 0.23.0 to 0.33.0 ([#3712](https://github.com/filebrowser/filebrowser/issues/3712)) ([1194cfe](https://github.com/filebrowser/filebrowser/commit/1194cfe0097a70399c1f06cf0f514b9d70fa463c))
* **deps:** bump vue-i18n from 9.10.2 to 9.14.2 in /frontend ([#3618](https://github.com/filebrowser/filebrowser/issues/3618)) ([0659594](https://github.com/filebrowser/filebrowser/commit/065959451d3ba12019c6151274aa4e6904cdca99))
* fix go releaser ([ba797cd](https://github.com/filebrowser/filebrowser/commit/ba797cda3135eddb9b7165dc5ceb932399cb54df))
* update to node 22 and pnpm ([#3616](https://github.com/filebrowser/filebrowser/issues/3616)) ([d51a343](https://github.com/filebrowser/filebrowser/commit/d51a3438201274a1b826be1b775ca1035ade20c5))
### [2.31.2](https://github.com/filebrowser/filebrowser/compare/v2.31.1...v2.31.2) (2024-10-03)

View File

@@ -1,19 +1,32 @@
FROM alpine:latest
RUN apk --update add ca-certificates \
mailcap \
curl \
jq
FROM alpine:3.22
COPY healthcheck.sh /healthcheck.sh
RUN chmod +x /healthcheck.sh # Make the script executable
RUN apk update && \
apk --no-cache add ca-certificates mailcap curl jq tini
HEALTHCHECK --start-period=2s --interval=5s --timeout=3s \
CMD /healthcheck.sh || exit 1
# Make user and create necessary directories
ENV UID=1000
ENV GID=1000
RUN addgroup -g $GID user && \
adduser -D -u $UID -G user user && \
mkdir -p /config /database /srv && \
chown -R user:user /config /database /srv
# Copy files and set permissions
COPY filebrowser /bin/filebrowser
COPY docker/common/ /
COPY docker/alpine/ /
RUN chown -R user:user /bin/filebrowser /defaults healthcheck.sh init.sh
# Define healthcheck script
HEALTHCHECK --start-period=2s --interval=5s --timeout=3s CMD /healthcheck.sh
# Set the user, volumes and exposed ports
USER user
VOLUME /srv /config /database
VOLUME /srv
EXPOSE 80
COPY docker_config.json /.filebrowser.json
COPY filebrowser /filebrowser
ENTRYPOINT [ "/filebrowser" ]
ENTRYPOINT [ "tini", "--", "/init.sh", "filebrowser", "--config", "/config/settings.json" ]

View File

@@ -1,16 +1,23 @@
FROM ghcr.io/linuxserver/baseimage-alpine:3.20
FROM ghcr.io/linuxserver/baseimage-alpine:3.22
RUN apk --update add ca-certificates \
mailcap \
curl
RUN apk update && \
apk --no-cache add ca-certificates mailcap curl jq
HEALTHCHECK --start-period=2s --interval=5s --timeout=3s \
CMD curl -f http://localhost/health || exit 1
# Make user and create necessary directories
RUN mkdir -p /config /database /srv && \
chown -R abc:abc /config /database /srv
# copy local files
COPY docker/root/ /
COPY filebrowser /usr/bin/filebrowser
# Copy files and set permissions
COPY filebrowser /bin/filebrowser
COPY docker/common/ /
COPY docker/s6/ /
# ports and volumes
RUN chown -R abc:abc /bin/filebrowser /defaults healthcheck.sh
# Define healthcheck script
HEALTHCHECK --start-period=2s --interval=5s --timeout=3s CMD /healthcheck.sh
# Set the volumes and exposed ports
VOLUME /srv /config /database
EXPOSE 80
EXPOSE 80

View File

@@ -1,16 +1,23 @@
FROM ghcr.io/linuxserver/baseimage-alpine:arm64v8-3.20
FROM ghcr.io/linuxserver/baseimage-alpine:arm64v8-3.22
RUN apk --update add ca-certificates \
mailcap \
curl
RUN apk update && \
apk --no-cache add ca-certificates mailcap curl jq
HEALTHCHECK --start-period=2s --interval=5s --timeout=3s \
CMD curl -f http://localhost/health || exit 1
# Make user and create necessary directories
RUN mkdir -p /config /database /srv && \
chown -R abc:abc /config /database /srv
# copy local files
COPY docker/root/ /
COPY filebrowser /usr/bin/filebrowser
# Copy files and set permissions
COPY filebrowser /bin/filebrowser
COPY docker/common/ /
COPY docker/s6/ /
# ports and volumes
RUN chown -R abc:abc /bin/filebrowser /defaults healthcheck.sh
# Define healthcheck script
HEALTHCHECK --start-period=2s --interval=5s --timeout=3s CMD /healthcheck.sh
# Set the volumes and exposed ports
VOLUME /srv /config /database
EXPOSE 80
EXPOSE 80

View File

@@ -10,7 +10,7 @@ build: | build-frontend build-backend ## Build binary
.PHONY: build-frontend
build-frontend: ## Build frontend
$Q cd frontend && npm ci && npm run build
$Q cd frontend && pnpm install --frozen-lockfile && pnpm run build
.PHONY: build-backend
build-backend: ## Build backend
@@ -21,6 +21,7 @@ test: | test-frontend test-backend ## Run all tests
.PHONY: test-frontend
test-frontend: ## Run frontend tests
$Q cd frontend && pnpm install --frozen-lockfile && pnpm run typecheck
.PHONY: test-backend
test-backend: ## Run backend tests
@@ -31,7 +32,7 @@ lint: lint-frontend lint-backend ## Run all linters
.PHONY: lint-frontend
lint-frontend: ## Run frontend linters
$Q cd frontend && npm ci && npm run lint
$Q cd frontend && pnpm install --frozen-lockfile && pnpm run lint
.PHONY: lint-backend
lint-backend: | $(golangci-lint) ## Run backend linters
@@ -65,4 +66,4 @@ help: ## Show this help
@awk 'BEGIN {FS = ":.*?## "} { \
if (/^[a-zA-Z_-]+:.*?##.*$$/) {printf " ${YELLOW}%-20s${GREEN}%s${RESET}\n", $$1, $$2} \
else if (/^## .*$$/) {printf " ${CYAN}%s${RESET}\n", substr($$1,4)} \
}' $(MAKEFILE_LIST)
}' $(MAKEFILE_LIST)

View File

@@ -12,28 +12,41 @@
filebrowser provides a file managing interface within a specified directory and it can be used to upload, delete, preview, rename and edit your files. It allows the creation of multiple users and each user can have its own directory. It can be used as a standalone app.
## Demo
> [!WARNING]
>
> This project is currently on **maintenance-only** mode, and is looking for new maintainers. For more information, please read the [discussion #4906](https://github.com/filebrowser/filebrowser/discussions/4906). Therefore, please note the following:
>
> - It can take a while until someone gets back to you. Please be patient.
> - [Issues][issues] are only being used to track bugs. Any unrelated issues will be converted into a [discussion][discussions].
> - No new features will be implemented until further notice. The priority is on triaging issues and merge bug fixes.
>
> If you're interested in maintaining this project, please reach out via the discussion above.
url: https://demo.filebrowser.org/
credentials: `demo`/`demo`
[issues]: https://github.com/filebrowser/filebrowser/issues
[discussions]: https://github.com/filebrowser/filebrowser/discussions
## Features
Please refer to our docs at [https://filebrowser.org/features](https://filebrowser.org/features)
File Browser is a **create-your-own-cloud-kind** of software where you can install it on a server, direct it to a path and then access your files through a nice web interface. You have many available features!
| Easy Login System | Sleek Interface | User Management |
| :----------------------: | :----------------------: | :----------------------: |
| ![](./docs/assets/1.jpg) | ![](./docs/assets/2.jpg) | ![](./docs/assets/3.jpg) |
| File Editing | Custom Commands | Customization |
| :----------------------: | :----------------------: | :----------------------: |
| ![](./docs/assets/4.jpg) | ![](./docs/assets/5.jpg) | ![](./docs/assets/6.jpg) |
## Install
For installation instructions please refer to our docs at [https://filebrowser.org/installation](https://filebrowser.org/installation).
For information on how to install File Browser, please check [docs/installation.md](./docs/installation.md).
## Configuration
[Authentication Method](https://filebrowser.org/configuration/authentication-method) - You can change the way the user authenticates with the filebrowser server
[Command Runner](https://filebrowser.org/configuration/command-runner) - The command runner is a feature that enables you to execute any shell command you want before or after a certain event.
[Custom Branding](https://filebrowser.org/configuration/custom-branding) - You can customize your File Browser installation by change its name to any other you want, by adding a global custom style sheet and by using your own logotype if you want.
For information on how to configure File Browser, please check [docs/configuration.md](./docs/configuration.md).
## Contributing
If you're interested in contributing to this project, our docs are best places to start [https://filebrowser.org/contributing](https://filebrowser.org/contributing).
For information on how to contribute to the project, including how translations are managed, please check [docs/contributing.md](./docs/contributing.md).

View File

@@ -1,26 +0,0 @@
# Security Policy
## Supported Versions
Use this section to tell people about which versions of your project are
currently being supported with security updates.
| Version | Supported |
| ------- | ------------------ |
| 2.x | :white_check_mark: |
| < 2.0 | :x: |
## Reporting a Vulnerability
Vulnerabilities should be reported to filebrowser@googlegroups.com - which is a private, maintainer-only group. Maintainers will attempt to respond to/confirm reports within 2-3 days, but if you believe your report to be "critical" to user safety and security, please note as such in the subject. We have tens of thousands of users using our software, and take security vulnerabilities seriously.
When reporting an issue, where possible, please provide at least:
* The commit version the issue was identified at
* A proof of concept (plaintext; no binaries)
* Steps to reproduce
* Your recommended remediation(s), if any.
The FileBrowser team is a volunteer-only effort, and may reach back out for clarification.
> Note: Please do not open public issues for security issues, as GitHub does not provide facility for private issues, and deleting the issue makes it hard to triage/respond back to the reporter.

View File

@@ -1,9 +1,9 @@
package auth
import (
"crypto/rand"
"errors"
"net/http"
"os"
fbErrors "github.com/filebrowser/filebrowser/v2/errors"
"github.com/filebrowser/filebrowser/v2/settings"
@@ -19,14 +19,49 @@ type ProxyAuth struct {
}
// Auth authenticates the user via an HTTP header.
func (a ProxyAuth) Auth(r *http.Request, usr users.Store, _ *settings.Settings, srv *settings.Server) (*users.User, error) {
func (a ProxyAuth) Auth(r *http.Request, usr users.Store, setting *settings.Settings, srv *settings.Server) (*users.User, error) {
username := r.Header.Get(a.Header)
user, err := usr.Get(srv.Root, username)
if errors.Is(err, fbErrors.ErrNotExist) {
return nil, os.ErrPermission
return a.createUser(usr, setting, srv, username)
}
return user, err
}
func (a ProxyAuth) createUser(usr users.Store, setting *settings.Settings, srv *settings.Server, username string) (*users.User, error) {
const passwordSize = 32
randomPasswordBytes := make([]byte, passwordSize)
_, err := rand.Read(randomPasswordBytes)
if err != nil {
return nil, err
}
return user, err
var hashedRandomPassword string
hashedRandomPassword, err = users.HashPwd(string(randomPasswordBytes))
if err != nil {
return nil, err
}
user := &users.User{
Username: username,
Password: hashedRandomPassword,
LockPassword: true,
}
setting.Defaults.Apply(user)
var userHome string
userHome, err = setting.MakeUserDir(user.Username, user.Scope, srv.Root)
if err != nil {
return nil, err
}
user.Scope = userHome
err = usr.Save(user)
if err != nil {
return nil, err
}
return user, nil
}
// LoginPage tells that proxy auth doesn't require a login page.

View File

@@ -378,7 +378,13 @@ func quickSetup(flags *pflag.FlagSet, d pythonData) {
password := getParam(flags, "password")
if password == "" {
password, err = users.HashPwd("admin")
var pwd string
pwd, err = users.RandomPwd()
checkErr(err)
log.Println("Generated random admin password for quick setup:", pwd)
password, err = users.HashPwd(pwd)
checkErr(err)
}

41
docker/alpine/init.sh Executable file
View File

@@ -0,0 +1,41 @@
#!/bin/sh
set -e
# Backwards compatibility for old Docker image
if [ -f "/.filebrowser.json" ]; then
ln -s /.filebrowser.json /config/settings.json
echo ""
echo "!!!!!!!!!!!!!!!!!!!!! IMPORTANT INFORMATION !!!!!!!!!!!!!!!!!!!!!"
echo "Symlinking /.filebrowser.json to /config/settings.json for backwards compatibility."
echo ""
echo "The volume mount configuration has changed in the latest release."
echo "Please rename .filebrowser.json to settings.json and mount the parent directory to /config".
echo "Read more on https://github.com/filebrowser/filebrowser/blob/master/docs/installation.md#docker"
echo ""
echo "This workaround will be removed in a future release."
echo ""
fi
# Backwards compatibility for old Docker image
if [ -f "/database.db" ]; then
ln -s /database.db /database/filebrowser.db
echo ""
echo "!!!!!!!!!!!!!!!!!!!!! IMPORTANT INFORMATION !!!!!!!!!!!!!!!!!!!!!"
echo ""
echo "The volume mount configuration has changed in the latest release."
echo "Please rename database.db to filebrowser.db and mount the parent directory to /database".
echo "Read more on https://github.com/filebrowser/filebrowser/blob/master/docs/installation.md#docker"
echo ""
echo "This workaround will be removed in a future release."
echo ""
fi
# Ensure configuration exists
if [ ! -f "/config/settings.json" ]; then
cp -a /defaults/settings.json /config/settings.json
fi
exec "$@"

9
docker/common/healthcheck.sh Executable file
View File

@@ -0,0 +1,9 @@
#!/bin/sh
set -e
PORT=${FB_PORT:-$(jq -r .port /config/settings.json)}
ADDRESS=${FB_ADDRESS:-$(jq -r .address /config/settings.json)}
ADDRESS=${ADDRESS:-localhost}
curl -f http://$ADDRESS:$PORT/health || exit 1

View File

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

View File

@@ -1,9 +1,6 @@
#!/usr/bin/with-contenv bash
# make folders
mkdir -p /database
# copy config
# Ensure configuration exists
if [ ! -f "/config/settings.json" ]; then
cp -a /defaults/settings.json /config/settings.json
fi

View File

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

BIN
docs/assets/1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

BIN
docs/assets/2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

BIN
docs/assets/3.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

BIN
docs/assets/4.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 212 KiB

BIN
docs/assets/5.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

BIN
docs/assets/6.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

46
docs/code-of-conduct.md Normal file
View File

@@ -0,0 +1,46 @@
# Code of Conduct
## Contributor Covenant Code of Conduct
### Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
### Our Standards
Examples of behavior that contributes to creating a positive environment include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting
### Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
### Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
### Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at hacdias@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
### Attribution
This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.4, available at [https://contributor-covenant.org/version/1/4](https://contributor-covenant.org/version/1/4).

148
docs/configuration.md Normal file
View File

@@ -0,0 +1,148 @@
# 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.
## Custom Branding
You are able to customize your File Browser installation by changing its name to any other you want, by adding a global custom style sheet and by using your own logotype if you want. To address this, there are three configuration options that can be changed:
* **Name:** which is the instance name that will show up on login and signup pages. This won't replace the version message in the sidebar.
* **Disable external links:** this will disable any external links (except the ones to this documentation).
* **Folder:** is the path to a directory that can contain two items:
* **custom.css**, containing the styles you want to apply to your installation.
* **img** a directory whose files can replace the [default logotypes](../frontend/public/img) in the application.
These options can be either set via the CLI interface using the following command:
```sh
filebrowser config set --branding.name "My Name" \
--branding.files "/abs/path/to/my/dir" \
--branding.disableExternal
```
Or can be set under 'Branding directory path' in **Settings → Global Settings**.
> [!NOTE]
>
> If using Docker then remember to bind this directory, for example as `/home/username/containers/filebrowser/branding:/branding`
For custom icons to be recognized you need to create `img` and `img/icons` directories and place the svg in the `branding/img` directory:
```
- filebrowser
- branding
- img
- icons
- logo.svg
- filebrowser.db
```
To replace the favicon you need to place this in the `img/icons` directory but also note that some of the other PNG icon types will be required too (see the default logotypes link above) as the browser will normally use the highest resolution option available (at a minimum the 16x16 and 32x32 options). You can use the [Real Favicon Generator](https://realfavicongenerator.net/) to generate these for you from your base image.
The icons are cached, to make the new ones appear more quickly open developer tools in your browser, then click on the Application tab, then Storage and then 'Clear Site Data'.
## Authentication Method
Right now, there are three possible authentication methods. Each one of them has its own capabilities and specification. If you are interested in contributing with one more authentication method, please [check the guidelines](./contributing.md).
### JSON Auth (default)
We call it JSON Authentication but it is just the default authentication method and the one that is provided by default if you don't make any changes. It is set by default, but if you've made changes before you can revert to using JSON auth:
```sh
filebrowser config set --auth.method=json
```
This method can also be extended with **reCAPTCHA** verification during login:
```sh
filebrowser config set --auth.method=json \
--recaptcha.key site-key \
--recaptcha.secret private-key
```
By default, we use [Google's reCAPTCHA](https://developers.google.com/recaptcha/docs/display) service. If you live in China, or want to use other provider, you can change the host with the following command:
```sh
filebrowser config set --recaptcha.host https://recaptcha.net
```
Where `https://recaptcha.net` is any provider you want.
> [!CAUTION]
>
> Note that you **always** need to set the `--auth.method` flag when changing authentication configurations and that it will completely overwrite your current settings. [This is a known issue.](https://github.com/filebrowser/filebrowser/issues/715)
### Proxy Header
If you have a reverse proxy you want to use to login your users, you do it via our `proxy` authentication method. To configure this method, your proxy must send an HTTP header containing the username of the logged in user:
```sh
filebrowser config set --auth.method=proxy --auth.header=X-My-Header
```
Where `X-My-Header` is the HTTP header provided by your proxy with the username.
> [!WARNING]
>
> File Browser will blindly trust the provided header. If the proxy can be bypassed, an attacker could simply attach the header and get admin access.
### No Authentication
We also provide a no authentication mechanism for users that want to use File Browser privately such in a home network. By setting this authentication method, the user with **id 1** will be used as the default users. Creating more users won't have any effect.
```sh
filebrowser config set --auth.method=noauth
```
## Command Runner
The command runner is a feature that enables you to execute any shell command you want before or after a certain event. Right now, these are the events:
* Copy
* Rename
* Upload
* Delete
* Save
Also, during the execution of the commands set for those hooks, there will be some environment variables available to help you perform your commands:
* `FILE` with the full absolute path to the changed file.
* `SCOPE` with the path to user's scope.
* `TRIGGER` with the name of the event.
* `USERNAME` with the user's username.
* `DESTINATION` with the absolute path to the destination. Only used for **copy** and **rename.**
At this moment, you can edit the commands via the command line interface, using the following commands \(please check the flag `--help` to know more about them\):
```bash
filebrowser cmds add before_copy "echo $FILE"
filebrowser cmds rm before_copy 0
filebrowser cmds ls
```
Or you can use the web interface to manage them via **Settings****Global Settings**.
## Shell commands
Within Filebrowser you can toggle the shell (`< >` icon at the top right) and this will open a shell command window at the bottom of the screen.
**By default no commands are available as the command list is empty**
To enable commands these need to either be done on a per-user basis (including for the Admin user).
You can do this by adding them in Settings > User Management > (edit user) > Commands or to *apply to all new users created from that point forward* they can be set in Settings > Global Settings
> [!NOTE]
>
> If using a proxy manager then remember to enable websockets support for the Filebrowser proxy
> [!NOTE]
>
> If using Docker and you want to add a new command that is not in the base image then you will need to build a custom Docker image using `filebrowser/filebrowser` as a base image. For example to add 7z:
>
> ```docker
> FROM filebrowser/filebrowser
> RUN sudo apt install p7zip-full
> ```

91
docs/contributing.md Normal file
View File

@@ -0,0 +1,91 @@
# Contributing
If you're interested in contributing to this project, this is the best place to start. Before contributing to this project, please take a bit of time to read our [Code of Conduct](./code-of-conduct.md). Also, note that this project is open-source and licensed under [Apache License 2.0](../LICENSE).
## Project Structure
The backend side of the application is written in [Go](https://golang.org/), while the frontend (located on a subdirectory of the same name) is written in [Vue.js](https://vuejs.org/). Due to the tight coupling required by some features, basic knowledge of both Go and Vue.js is recommended.
* Learn Go: [https://github.com/golang/go/wiki/Learn](https://github.com/golang/go/wiki/Learn)
* Learn Vue.js: [https://vuejs.org/guide/introduction.html](https://vuejs.org/guide/introduction.html)
We encourage you to use git to manage your fork. To clone the main repository, just run:
```bash
git clone https://github.com/filebrowser/filebrowser
```
## Build
### Frontend
We are using [Node.js](https://nodejs.org/en/) on the frontend to manage the build process. The steps to build it are:
```bash
# From the root of the repo, go to frontend/
cd frontend
# Install the dependencies
pnpm install
# Build the frontend
pnpm run build
```
This will install the dependencies and build the frontend so you can then embed it into the Go app. Although, if you want to play with it, you'll get bored of building it after every change you do. So, you can run the command below to watch for changes:
```bash
pnpm run dev
```
### Backend
First of all, you need to download the required dependencies. We are using the built-in `go mod` tool for dependency management. To get the modules, run:
```bash
go mod download
```
The magic of File Browser is that the static assets are bundled into the final binary. For that, we use [Go embed.FS](https://golang.org/pkg/embed/). The files from `frontend/dist` will be embedded during the build process.
To build File Browser is just like any other Go program:
```bash
go build
```
To create a development build use the "dev" tag, this way the content inside the frontend folder will not be embedded in the binary but will be reloaded at every change:
```bash
go build -tags dev
```
## Translations
Translations are managed on Transifex, which is an online website where everyone can contribute and translate strings for our project. It automatically syncs with the main language file \(in English\) and,, for you to contribute, you just need to:
1. Go to our Transifex web page: [app.transifex.com/file-browser/file-browser](https://app.transifex.com/file-browser/file-browser/)
2. Click on **Join the project** and pick your language. We'll accept you as soon as possible. If you're language is not on the list, please request it via the interface.
Translations are automatically pushed to GitHub via an integration.
## Authentication Provider
To build a new authentication provider, you need to implement the [Auther interface](https://github.com/filebrowser/filebrowser/blob/master/auth/auth.go), whose method will be called on the login page after the user has submitted their login data.
```go
// Auther is the authentication interface.
type Auther interface {
// Auth is called to authenticate a request.
Auth(r *http.Request, s *users.Storage, root string) (*users.User, error)
}
```
After implementing the interface you should:
1. Add it to [`auth` directory](https://github.com/filebrowser/filebrowser/blob/master/auth).
2. Add it to the [configuration parser](https://github.com/filebrowser/filebrowser/blob/master/cmd/config.go) for the CLI.
3. Add it to the [`authBackend.Get`](https://github.com/filebrowser/filebrowser/blob/master/storage/bolt/auth.go).
If you need to add more flags, please update the function `addConfigFlags`.

80
docs/installation.md Normal file
View File

@@ -0,0 +1,80 @@
# Installation
File Browser is a single binary and can be used as a standalone executable. Although, some might prefer to use it with [Docker](https://www.docker.com) or [Caddy](https://caddyserver.com), which is a fantastic web server that enables HTTPS by default. Its installation is quite straightforward independently on which system you want to use.
## Quick Setup
The quickest way for beginners to start using File Browser is by opening your terminal and executing the following commands:
### Brew
```sh
brew tap filebrowser/tap
brew install filebrowser
filebrowser -r /path/to/your/files
```
### Unix
```sh
curl -fsSL https://raw.githubusercontent.com/filebrowser/get/master/get.sh | bash
filebrowser -r /path/to/your/files
```
### Windows
```sh
iwr -useb https://raw.githubusercontent.com/filebrowser/get/master/get.ps1 | iex
filebrowser -r /path/to/your/files
```
### Configuring
Done! It will bootstrap a database in which all the configurations and users are stored. Now, you can see on your command line the address in which your instance is running. You just need to go to that URL and use the following credentials:
* Username: `admin`
* Password: (printed in your console)
Although this is the fastest way to bootstrap an instance, we recommend you to take a look at other possible options, by checking `config init --help` and `config set --help`, to make the installation as safe and customized as it can be.
## Docker
File Browser is available as two different Docker images, which can be found on [Docker Hub](https://hub.docker.com/r/filebrowser/filebrowser).
### Alpine
```sh
docker run \
-v /path/to/srv:/srv \
-v /path/to/database:/database \
-v /path/to/config:/config \
-p 8080:80 \
filebrowser/filebrowser
```
The default user has PID 1000 and GID 1000. Please make sure that this user has access to the different mounted volumes. To change the user running inside the Docker image, you need to use the [`--user` flag](https://docs.docker.com/engine/containers/run/#user).
### s6 overlay
The `s6` image is based on LinuxServer and leverages the [s6-overlay](https://github.com/just-containers/s6-overlay) system for a standard, highly customizable image. It should be used as follows:
```shell
docker run \
-v /path/to/srv:/srv \
-v /path/to/database:/database \
-v /path/to/config:/config \
-e PUID=$(id -u) \
-e PGID=$(id -g) \
-p 8080:80 \
filebrowser/filebrowser:s6
```
### Notes
Where:
- `/path/to/srv` contains the files root directory for File Browser
- `/path/to/config` contains a `settings.json` file
- `/path/to/database` contains a `filebrowser.db` file
Both `settings.json` and `filebrowser.db` will automatically be initialized if they don't exist.

26
docs/security.md Normal file
View File

@@ -0,0 +1,26 @@
# Security Policy
## Supported Versions
Use this section to tell people about which versions of your project are
currently being supported with security updates.
| Version | Supported |
| ------- | ------------------ |
| 2.x | :white_check_mark: |
| < 2.0 | :x: |
## Reporting a Vulnerability
Vulnerabilities with critical impact should be reported on the [Security](https://github.com/filebrowser/filebrowser/security) page of this repository, which is a private way of communicating vulnerabilities to maintainers. This project is in maintenance-only mode and it can take a while until someone gets back to you.
If it is not a critical vulnerability, please open an issue and we will categorize it as a security issue. By giving visibility, we can get more help from the community at fixing such issues.
When reporting an issue, where possible, please provide at least:
* The commit version the issue was identified at
* A proof of concept (plaintext; no binaries)
* Steps to reproduce
* Your recommended remediation(s), if any.
The File Browser team is a volunteer-only effort, and may reach back out for clarification.

View File

@@ -1,27 +0,0 @@
{
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/vue3-essential",
"eslint:recommended",
"@vue/eslint-config-typescript",
"@vue/eslint-config-prettier"
],
"rules": {
"vue/multi-word-component-names": "off",
"vue/no-mutating-props": [
"error",
{
"shallowOnly": true
}
]
// no-undef is already included in
// @vue/eslint-config-typescript
},
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
}
}

View File

@@ -1,2 +1,3 @@
# Ignore artifacts:
dist
dist
pnpm-lock.yaml

38
frontend/eslint.config.js Normal file
View File

@@ -0,0 +1,38 @@
import pluginVue from "eslint-plugin-vue";
import vueTsEslintConfig from "@vue/eslint-config-typescript";
import prettierConfig from "@vue/eslint-config-prettier";
export default [
{
name: "app/files-to-lint",
files: ["**/*.{ts,mts,tsx,vue}"],
},
{
name: "app/files-to-ignore",
ignores: ["**/dist/**", "**/dist-ssr/**", "**/coverage/**"],
},
...pluginVue.configs["flat/essential"],
...vueTsEslintConfig(),
prettierConfig,
{
rules: {
// Note: you must disable the base rule as it can report incorrect errors
"no-unused-expressions": "off",
"@typescript-eslint/no-unused-expressions": "off",
// TODO: theres too many of these from before ts
"@typescript-eslint/no-explicit-any": "off",
// TODO: finish the ts conversion
"vue/block-lang": "off",
"vue/multi-word-component-names": "off",
"vue/no-mutating-props": [
"error",
{
shallowOnly: true,
},
],
},
},
];

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -4,70 +4,74 @@
"private": true,
"type": "module",
"engines": {
"npm": ">=7.0.0",
"node": ">=18.0.0"
"node": ">=22.0.0",
"pnpm": ">=9.0.0"
},
"scripts": {
"dev": "vite dev",
"build": "npm run typecheck && vite build",
"build": "pnpm run typecheck && vite build",
"clean": "find ./dist -maxdepth 1 -mindepth 1 ! -name '.gitkeep' -exec rm -r {} +",
"typecheck": "vue-tsc -p ./tsconfig.json --noEmit",
"lint": "npm run typecheck && eslint --ext .vue,.ts src/",
"lint:fix": "eslint --ext .vue,.ts --fix src/",
"typecheck": "vue-tsc -p ./tsconfig.tsc.json --noEmit",
"lint": "eslint src/",
"lint:fix": "eslint --fix src/",
"format": "prettier --write .",
"test": "playwright test"
},
"dependencies": {
"@chenfengyuan/vue-number-input": "^2.0.1",
"@vueuse/core": "^10.9.0",
"@vueuse/integrations": "^10.9.0",
"ace-builds": "^1.32.9",
"core-js": "^3.36.1",
"@vueuse/core": "^12.5.0",
"@vueuse/integrations": "^12.5.0",
"ace-builds": "^1.37.5",
"core-js": "^3.40.0",
"dayjs": "^1.11.10",
"epubjs": "^0.3.93",
"filesize": "^10.1.1",
"js-base64": "^3.7.7",
"jwt-decode": "^4.0.0",
"lodash-es": "^4.17.21",
"material-icons": "^1.13.12",
"marked": "^14.1.0",
"marked": "^15.0.6",
"material-icons": "^1.13.13",
"normalize.css": "^8.0.1",
"pinia": "^2.1.7",
"pinia": "^2.3.1",
"pretty-bytes": "^6.1.1",
"qrcode.vue": "^3.4.1",
"tus-js-client": "^4.1.0",
"tus-js-client": "^4.3.1",
"utif": "^3.1.0",
"video.js": "^8.10.0",
"video.js": "^8.21.0",
"videojs-hotkeys": "^0.2.28",
"videojs-mobile-ui": "^1.1.1",
"vue": "^3.4.21",
"vue-final-modal": "^4.5.4",
"vue-i18n": "^9.10.2",
"vue-i18n": "^11.1.2",
"vue-lazyload": "^3.0.0",
"vue-reader": "^1.2.14",
"vue-reader": "^1.2.17",
"vue-router": "^4.3.0",
"vue-toastification": "^2.0.0-rc.5"
},
"devDependencies": {
"@intlify/unplugin-vue-i18n": "^4.0.0",
"@playwright/test": "^1.42.1",
"@intlify/unplugin-vue-i18n": "^6.0.3",
"@playwright/test": "^1.50.0",
"@tsconfig/node22": "^22.0.0",
"@types/lodash-es": "^4.17.12",
"@types/node": "^20.12.2",
"@typescript-eslint/eslint-plugin": "^7.4.0",
"@vitejs/plugin-legacy": "^5.3.2",
"@types/node": "^22.10.10",
"@typescript-eslint/eslint-plugin": "^8.21.0",
"@vitejs/plugin-legacy": "^6.0.0",
"@vitejs/plugin-vue": "^5.0.4",
"@vue/eslint-config-prettier": "^9.0.0",
"@vue/eslint-config-typescript": "^13.0.0",
"@vue/eslint-config-prettier": "^10.2.0",
"@vue/eslint-config-typescript": "^14.3.0",
"@vue/tsconfig": "^0.7.0",
"autoprefixer": "^10.4.19",
"concurrently": "^8.2.2",
"eslint": "^8.57.0",
"eslint-plugin-prettier": "^5.1.3",
"concurrently": "^9.1.2",
"eslint": "^9.19.0",
"eslint-plugin-prettier": "^5.2.3",
"eslint-plugin-vue": "^9.24.0",
"jsdom": "^24.0.0",
"postcss": "^8.4.38",
"prettier": "^3.2.5",
"terser": "^5.30.0",
"vite": "^5.4.6",
"jsdom": "^26.0.0",
"postcss": "^8.5.1",
"prettier": "^3.4.2",
"terser": "^5.37.0",
"vite": "^6.1.6",
"vite-plugin-compression2": "^1.0.0",
"vue-tsc": "^2.0.7"
}
"vue-tsc": "^2.2.0"
},
"packageManager": "pnpm@9.15.4+sha512.b2dc20e2fc72b3e18848459b37359a32064663e5627a51e4c74b2c29dd8e8e0491483c3abb40789cfd578bf362fb6ba8261b05f0387d76792ed6e23ea3b1b6a0"
}

5426
frontend/pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,8 @@
import { createURL, fetchURL, removePrefix } from "./utils";
import { baseURL } from "@/utils/constants";
import { useAuthStore } from "@/stores/auth";
import { useLayoutStore } from "@/stores/layout";
import { baseURL } from "@/utils/constants";
import { upload as postTus, useTus } from "./tus";
import { createURL, fetchURL, removePrefix } from "./utils";
export async function fetch(url: string) {
url = removePrefix(url);
@@ -74,11 +75,6 @@ export function download(format: any, ...files: string[]) {
url += `algo=${format}&`;
}
const authStore = useAuthStore();
if (authStore.jwt) {
url += `auth=${authStore.jwt}&`;
}
window.open(url);
}
@@ -156,6 +152,7 @@ function moveCopy(
overwrite = false,
rename = false
) {
const layoutStore = useLayoutStore();
const promises = [];
for (const item of items) {
@@ -166,7 +163,7 @@ function moveCopy(
}&destination=${to}&override=${overwrite}&rename=${rename}`;
promises.push(resourceAction(url, "PATCH"));
}
layoutStore.closeHovers();
return Promise.all(promises);
}

View File

@@ -71,5 +71,5 @@ export function getDownloadURL(res: Resource, inline = false) {
...(res.token && { token: res.token }),
};
return createURL("api/public/dl/" + res.hash + res.path, params, false);
return createURL("api/public/dl/" + res.hash + res.path, params);
}

View File

@@ -41,5 +41,5 @@ export async function create(
}
export function getShareURL(share: Share) {
return createURL("share/" + share.hash, {}, false);
return createURL("share/" + share.hash, {});
}

View File

@@ -25,7 +25,7 @@ export async function create(user: IUser) {
throw new StatusError(await res.text(), res.status);
}
export async function update(user: IUser, which = ["all"]) {
export async function update(user: Partial<IUser>, which = ["all"]) {
await fetchURL(`/api/users/${user.id}`, {
method: "PUT",
body: JSON.stringify({

View File

@@ -76,23 +76,13 @@ export function removePrefix(url: string): string {
return url;
}
export function createURL(endpoint: string, params = {}, auth = true): string {
const authStore = useAuthStore();
export function createURL(endpoint: string, searchParams = {}): string {
let prefix = baseURL;
if (!prefix.endsWith("/")) {
prefix = prefix + "/";
}
const url = new URL(prefix + encodePath(endpoint), origin);
const searchParams: SearchParams = {
...(auth && { auth: authStore.jwt }),
...params,
};
for (const key in searchParams) {
url.searchParams.set(key, searchParams[key]);
}
url.search = new URLSearchParams(searchParams).toString();
return url.toString();
}

View File

@@ -34,7 +34,7 @@ const props = defineProps<{
const items = computed(() => {
const relativePath = route.path.replace(props.base, "");
let parts = relativePath.split("/");
const parts = relativePath.split("/");
if (parts[0] === "") {
parts.shift();
@@ -44,7 +44,7 @@ const items = computed(() => {
parts.pop();
}
let breadcrumbs: BreadCrumb[] = [];
const breadcrumbs: BreadCrumb[] = [];
for (let i = 0; i < parts.length; i++) {
if (i === 0) {

View File

@@ -46,7 +46,7 @@ https://raw.githubusercontent.com/dzwillia/vue-simple-progress/master/src/compon
<script>
// We're leaving this untouched as you can read in the beginning
var isNumber = function (n) {
const isNumber = function (n) {
return !isNaN(parseFloat(n)) && isFinite(n);
};
@@ -107,7 +107,7 @@ export default {
},
computed: {
pct() {
var pct = (this.val / this.max) * 100;
let pct = (this.val / this.max) * 100;
pct = pct.toFixed(2);
return Math.min(pct, this.max);
},
@@ -160,7 +160,7 @@ export default {
return isNumber(this.fontSize) ? this.fontSize : 13;
},
progress_style() {
var style = {
const style = {
background: this.bgColor,
};
@@ -177,7 +177,7 @@ export default {
return style;
},
bar_style() {
var style = {
const style = {
background: this.barColor,
width: this.pct + "%",
height: this.size_px + "px",
@@ -198,7 +198,7 @@ export default {
return style;
},
text_style() {
var style = {
const style = {
color: this.textFgColor,
"font-size": this.text_font_size + "px",
"text-align": this.textAlign,

View File

@@ -50,7 +50,7 @@ import { useFileStore } from "@/stores/file";
import { useLayoutStore } from "@/stores/layout";
import { commands } from "@/api";
import { throttle } from "lodash";
import { throttle } from "lodash-es";
import { theme } from "@/utils/constants";
export default {
@@ -163,7 +163,7 @@ export default {
this.canInput = false;
event.target.innerHTML = "";
let results = {
const results = {
text: `${cmd}\n\n`,
};
@@ -180,7 +180,7 @@ export default {
},
() => {
results.text = results.text
// eslint-disable-next-line no-control-regex
.replace(/\u001b\[[0-9;]+m/g, "") // Filter ANSI color for now
.trimEnd();
this.canInput = true;

View File

@@ -101,7 +101,7 @@
href="https://github.com/filebrowser/filebrowser"
>File Browser</a
>
<span> {{ ' ' }} {{ version }}</span>
<span> {{ " " }} {{ version }}</span>
</span>
<span>
<a @click="help">{{ $t("sidebar.help") }}</a>
@@ -158,7 +158,7 @@ export default {
methods: {
...mapActions(useLayoutStore, ["closeHovers", "showHover"]),
async fetchUsage() {
let path = this.$route.path.endsWith("/")
const path = this.$route.path.endsWith("/")
? this.$route.path
: this.$route.path + "/";
let usageStats = USAGE_DEFAULT;
@@ -166,7 +166,7 @@ export default {
return Object.assign(this.usage, usageStats);
}
try {
let usage = await api.usage(path);
const usage = await api.usage(path);
usageStats = {
used: prettyBytes(usage.used, { binary: true }),
total: prettyBytes(usage.total, { binary: true }),
@@ -191,8 +191,13 @@ export default {
logout: auth.logout,
},
watch: {
isFiles(newValue) {
newValue && this.fetchUsage();
$route: {
handler(to) {
if (to.path.includes("/files")) {
this.fetchUsage();
}
},
immediate: true,
},
},
};

View File

@@ -14,15 +14,15 @@
</div>
</template>
<script setup lang="ts">
import throttle from "lodash/throttle";
import { throttle } from "lodash-es";
import UTIF from "utif";
import { onBeforeUnmount, onMounted, ref, watch } from "vue";
interface IProps {
src: string;
moveDisabledTime: number;
classList: any[];
zoomStep: number;
moveDisabledTime?: number;
classList?: any[];
zoomStep?: number;
}
const props = withDefaults(defineProps<IProps>(), {
@@ -102,10 +102,11 @@ const decodeUTIF = () => {
if (document?.location?.pathname === undefined) {
return;
}
let suff = document.location.pathname.split(".")?.pop()?.toLowerCase() ?? "";
const suff =
document.location.pathname.split(".")?.pop()?.toLowerCase() ?? "";
if (sufs.indexOf(suff) == -1) return false;
let xhr = new XMLHttpRequest();
const xhr = new XMLHttpRequest();
UTIF._xhrs.push(xhr);
UTIF._imgs.push(imgex.value);
xhr.open("GET", props.src);
@@ -230,7 +231,7 @@ const touchMove = (event: TouchEvent) => {
if (imgex.value === null) {
return;
}
let step = imgex.value.width / 5;
const step = imgex.value.width / 5;
if (event.targetTouches.length === 2) {
moveDisabled.value = true;
if (disabledTimer.value) clearTimeout(disabledTimer.value);
@@ -239,9 +240,9 @@ const touchMove = (event: TouchEvent) => {
props.moveDisabledTime
);
let p1 = event.targetTouches[0];
let p2 = event.targetTouches[1];
let touchDistance = Math.sqrt(
const p1 = event.targetTouches[0];
const p2 = event.targetTouches[1];
const touchDistance = Math.sqrt(
Math.pow(p2.pageX - p1.pageX, 2) + Math.pow(p2.pageY - p1.pageY, 2)
);
if (!lastTouchDistance.value) {
@@ -253,8 +254,8 @@ const touchMove = (event: TouchEvent) => {
setZoom();
} else if (event.targetTouches.length === 1) {
if (moveDisabled.value) return;
let x = event.targetTouches[0].pageX - (lastX.value ?? 0);
let y = event.targetTouches[0].pageY - (lastY.value ?? 0);
const x = event.targetTouches[0].pageX - (lastX.value ?? 0);
const y = event.targetTouches[0].pageY - (lastY.value ?? 0);
if (Math.abs(x) >= step && Math.abs(y) >= step) return;
lastX.value = event.targetTouches[0].pageX;
lastY.value = event.targetTouches[0].pageY;
@@ -268,8 +269,8 @@ const doMove = (x: number, y: number) => {
}
const style = imgex.value.style;
let posX = pxStringToNumber(style.left) + x;
let posY = pxStringToNumber(style.top) + y;
const posX = pxStringToNumber(style.left) + x;
const posY = pxStringToNumber(style.top) + y;
style.left = posX + "px";
style.top = posY + "px";

View File

@@ -82,7 +82,7 @@ const isDraggable = computed(
const canDrop = computed(() => {
if (!props.isDir || props.readOnly) return false;
for (let i of fileStore.selected) {
for (const i of fileStore.selected) {
if (fileStore.req?.items[i].url === props.url) {
return false;
}
@@ -156,9 +156,9 @@ const drop = async (event: Event) => {
}
}
let items: any[] = [];
const items: any[] = [];
for (let i of fileStore.selected) {
for (const i of fileStore.selected) {
if (fileStore.req) {
items.push({
from: fileStore.req?.items[i].url,
@@ -172,10 +172,10 @@ const drop = async (event: Event) => {
if (el === null) {
return;
}
let path = el.__vue__.url;
let baseItems = (await api.fetch(path)).items;
const path = el.__vue__.url;
const baseItems = (await api.fetch(path)).items;
let action = (overwrite: boolean, rename: boolean) => {
const action = (overwrite: boolean, rename: boolean) => {
api
.move(items, overwrite, rename)
.then(() => {
@@ -184,7 +184,7 @@ const drop = async (event: Event) => {
.catch($showError);
};
let conflict = upload.checkConflict(items, baseItems);
const conflict = upload.checkConflict(items, baseItems);
let overwrite = false;
let rename = false;

View File

@@ -62,7 +62,8 @@ const initVideoPlayer = async () => {
const languagePack = await (
languageImports[lang] || languageImports.en
)?.();
videojs.addLanguage("videoPlayerLocal", languagePack.default);
const code = languageImports[lang] ? lang : "en";
videojs.addLanguage(code, languagePack.default);
sourceType.value = "";
//
@@ -70,14 +71,19 @@ const initVideoPlayer = async () => {
const srcOpt = { sources: { src: props.source, type: sourceType.value } };
//Supporting localized language display.
const langOpt = { language: "videoPlayerLocal" };
const langOpt = { language: code };
// support for playback at different speeds.
const playbackRatesOpt = { playbackRates: [0.5, 1, 1.5, 2, 2.5, 3] };
let options = getOptions(props.options, langOpt, srcOpt, playbackRatesOpt);
const options = getOptions(
props.options,
langOpt,
srcOpt,
playbackRatesOpt
);
player.value = videojs(videoPlayer.value!, options, () => {});
// TODO: need to test on mobile
// @ts-ignore
// @ts-expect-error no ts definition for mobileUi
player.value!.mobileUi();
} catch (error) {
console.error("Error initializing video player:", error);
@@ -120,7 +126,7 @@ const subLabel = (subUrl: string) => {
let url: URL;
try {
url = new URL(subUrl);
} catch (_) {
} catch {
// treat it as a relative url
// we only need this for filename
url = new URL(subUrl, window.location.origin);

View File

@@ -82,10 +82,10 @@ export default {
...mapActions(useLayoutStore, ["showHover", "closeHovers"]),
copy: async function (event) {
event.preventDefault();
let items = [];
const items = [];
// Create a new promise for each file.
for (let item of this.selected) {
for (const item of this.selected) {
items.push({
from: this.req.items[item].url,
to: this.dest + encodeURIComponent(this.req.items[item].name),
@@ -93,7 +93,7 @@ export default {
});
}
let action = async (overwrite, rename) => {
const action = async (overwrite, rename) => {
buttons.loading("copy");
await api
@@ -122,8 +122,8 @@ export default {
return;
}
let dstItems = (await api.fetch(this.dest)).items;
let conflict = upload.checkConflict(items, dstItems);
const dstItems = (await api.fetch(this.dest)).items;
const conflict = upload.checkConflict(items, dstItems);
let overwrite = false;
let rename = false;

View File

@@ -74,8 +74,8 @@ export default {
return;
}
let promises = [];
for (let index of this.selected) {
const promises = [];
for (const index of this.selected) {
promises.push(api.remove(this.req.items[index].url));
}

View File

@@ -43,7 +43,7 @@ export default {
submit: async function () {
this.updateRequest(null);
let uri = url.removeLastDir(this.$route.path) + "/";
const uri = url.removeLastDir(this.$route.path) + "/";
this.$router.push({ path: uri });
},
},

View File

@@ -80,7 +80,7 @@ export default {
// Otherwise we add every directory to the
// move options.
for (let item of req.items) {
for (const item of req.items) {
if (!item.isDir) continue;
this.items.push({
@@ -93,12 +93,12 @@ export default {
// Retrieves the URL of the directory the user
// just clicked in and fill the options with its
// content.
let uri = event.currentTarget.dataset.url;
const uri = event.currentTarget.dataset.url;
files.fetch(uri).then(this.fillOptions).catch(this.$showError);
},
touchstart(event) {
let url = event.currentTarget.dataset.url;
const url = event.currentTarget.dataset.url;
// In 300 milliseconds, we shall reset the count.
setTimeout(() => {

View File

@@ -11,7 +11,7 @@
<li><strong>DEL</strong> - {{ $t("help.del") }}</li>
<li><strong>ESC</strong> - {{ $t("help.esc") }}</li>
<li><strong>CTRL + S</strong> - {{ $t("help.ctrl.s") }}</li>
<li><strong>CTRL + F</strong> - {{ $t("help.ctrl.f") }}</li>
<li><strong>CTRL + SHIFT + F</strong> - {{ $t("help.ctrl.f") }}</li>
<li><strong>CTRL + Click</strong> - {{ $t("help.ctrl.click") }}</li>
<li><strong>Click</strong> - {{ $t("help.click") }}</li>
<li><strong>Double click</strong> - {{ $t("help.doubleClick") }}</li>

View File

@@ -124,7 +124,7 @@ export default {
let sum = 0;
for (let selected of this.selected) {
for (const selected of this.selected) {
sum += this.req.items[selected].size;
}

View File

@@ -81,9 +81,9 @@ export default {
...mapActions(useLayoutStore, ["showHover", "closeHovers"]),
move: async function (event) {
event.preventDefault();
let items = [];
const items = [];
for (let item of this.selected) {
for (const item of this.selected) {
items.push({
from: this.req.items[item].url,
to: this.dest + encodeURIComponent(this.req.items[item].name),
@@ -91,7 +91,7 @@ export default {
});
}
let action = async (overwrite, rename) => {
const action = async (overwrite, rename) => {
buttons.loading("move");
await api
@@ -106,8 +106,8 @@ export default {
});
};
let dstItems = (await api.fetch(this.dest)).items;
let conflict = upload.checkConflict(items, dstItems);
const dstItems = (await api.fetch(this.dest)).items;
const conflict = upload.checkConflict(items, dstItems);
let overwrite = false;
let rename = false;

View File

@@ -3,7 +3,7 @@
</template>
<script setup lang="ts">
import { ref, watch } from "vue";
import { watch } from "vue";
import { ModalsContainer, useModal } from "vue-final-modal";
import { storeToRefs } from "pinia";
import { useLayoutStore } from "@/stores/layout";
@@ -30,8 +30,6 @@ const layoutStore = useLayoutStore();
const { currentPromptName } = storeToRefs(layoutStore);
const closeModal = ref<() => Promise<string>>();
const components = new Map<string, any>([
["info", Info],
["help", Help],
@@ -52,11 +50,6 @@ const components = new Map<string, any>([
]);
watch(currentPromptName, (newValue) => {
if (closeModal.value) {
closeModal.value();
closeModal.value = undefined;
}
const modal = components.get(newValue!);
if (!modal) return;
@@ -67,7 +60,7 @@ watch(currentPromptName, (newValue) => {
},
});
closeModal.value = close;
layoutStore.setCloseOnPrompt(close, newValue!);
open();
});

View File

@@ -196,13 +196,23 @@ export default {
methods: {
...mapActions(useLayoutStore, ["closeHovers"]),
copyToClipboard: function (text) {
copy(text).then(
copy({ text }).then(
() => {
// clipboard successfully set
this.$showSuccess(this.$t("success.linkCopied"));
},
() => {
// clipboard write failed
copy({ text }, { permission: true }).then(
() => {
// clipboard successfully set
this.$showSuccess(this.$t("success.linkCopied"));
},
(e) => {
// clipboard write failed
this.$showError(e);
}
);
}
);
},

View File

@@ -48,12 +48,10 @@ const layoutStore = useLayoutStore();
// TODO: this is a copy of the same function in FileListing.vue
const uploadInput = (event: Event) => {
layoutStore.closeHovers();
let files = (event.currentTarget as HTMLInputElement)?.files;
const files = (event.currentTarget as HTMLInputElement)?.files;
if (files === null) return;
let folder_upload = !!files[0].webkitRelativePath;
const folder_upload = !!files[0].webkitRelativePath;
const uploadFiles: UploadList = [];
for (let i = 0; i < files.length; i++) {
@@ -68,8 +66,8 @@ const uploadInput = (event: Event) => {
});
}
let path = route.path.endsWith("/") ? route.path : route.path + "/";
let conflict = upload.checkConflict(uploadFiles, fileStore.req!.items);
const path = route.path.endsWith("/") ? route.path : route.path + "/";
const conflict = upload.checkConflict(uploadFiles, fileStore.req!.items);
if (conflict) {
layoutStore.showHover({

View File

@@ -13,7 +13,7 @@ export default {
name: "languages",
props: ["locale"],
data() {
let dataObj = {};
const dataObj = {};
const locales = {
he: "עברית",
hu: "Magyar",
@@ -38,6 +38,7 @@ export default {
"sv-se": "Swedish (Sweden)",
tr: "Türkçe",
uk: "Українська",
vi: "Tiếng Việt",
"zh-cn": "中文 (简体)",
"zh-tw": "中文 (繁體)",
};

View File

@@ -39,7 +39,7 @@ export default {
methods: {
remove(event, index) {
event.preventDefault();
let rules = [...this.rules];
const rules = [...this.rules];
rules.splice(index, 1);
this.$emit("update:rules", [...rules]);
},

View File

@@ -7,7 +7,7 @@
</template>
<script setup lang="ts">
import { SelectHTMLAttributes } from "vue";
import type { SelectHTMLAttributes } from "vue";
import { useI18n } from "vue-i18n";
const { t } = useI18n();
@@ -17,7 +17,6 @@ defineProps<{
}>();
const emit = defineEmits<{
// eslint-disable-next-line @typescript-eslint/no-unused-vars
(e: "update:theme", val: string | null): void;
}>();

View File

@@ -116,7 +116,7 @@ watch(createUserDirData, () => {
if (props.user?.scope) {
props.user.scope = createUserDirData.value
? ""
: originalUserScope.value ?? "";
: (originalUserScope.value ?? "");
}
});
</script>

View File

@@ -63,8 +63,8 @@
local("Roboto"),
local("Roboto-Regular"),
url(../assets/fonts/roboto/normal-latin-ext.woff2) format("woff2");
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F,
U+A720-A7FF;
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF,
U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
@@ -142,8 +142,8 @@
local("Roboto Medium"),
local("Roboto-Medium"),
url(../assets/fonts/roboto/medium-latin-ext.woff2) format("woff2");
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F,
U+A720-A7FF;
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF,
U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
@@ -221,8 +221,8 @@
local("Roboto Bold"),
local("Roboto-Bold"),
url(../assets/fonts/roboto/bold-latin-ext.woff2) format("woff2");
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F,
U+A720-A7FF;
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF,
U+2C60-2C7F, U+A720-A7FF;
}
@font-face {

View File

@@ -173,7 +173,7 @@
"executeOnShellDescription": "Por defecto, FileBrowser ejecuta los comandos llamando directamente a sus binarios. Si quieres ejecutarlos en un shell en su lugar (como Bash o PowerShell), puedes definirlo aquí con los argumentos y banderas (flags) necesarios. Si se define, el comando que se ejecuta se añadirá como argumento. Esto se aplica tanto a los comandos de usuario como a los ganchos de eventos.",
"globalRules": "Se trata de un conjunto global de reglas de permiso y rechazo. Se aplican a todos los usuarios. Puedes definir reglas específicas en la configuración de cada usuario para anular estas.",
"globalSettings": "Ajustes globales",
"hideDotfiles": "",
"hideDotfiles": "Ocultar archivos empezados por punto",
"insertPath": "Introduce la ruta",
"insertRegex": "Introducir expresión regular",
"instanceName": "Nombre de la instancia",

View File

@@ -14,7 +14,7 @@
"file": "Fichier",
"folder": "Dossier",
"fullScreen": "Plein écran",
"hideDotfiles": "Masquer les dotfiles",
"hideDotfiles": "Masquer les fichiers cachés",
"info": "Info",
"more": "Plus",
"move": "Déplacer",
@@ -22,15 +22,16 @@
"new": "Nouveau",
"next": "Suivant",
"ok": "OK",
"permalink": "Obtenir un lien permanent",
"permalink": "Obtenir le lien permanent",
"previous": "Précédent",
"preview": "Prévisualiser",
"publish": "Publier",
"rename": "Renommer",
"replace": "Remplacer",
"reportIssue": "Rapport d'erreur",
"reportIssue": "Signaler un problème",
"save": "Enregistrer",
"schedule": "Fixer la date",
"search": "Chercher",
"schedule": "Planifier",
"search": "Rechercher",
"select": "Sélectionner",
"selectMultiple": "Sélection multiple",
"share": "Partager",
@@ -40,18 +41,22 @@
"toggleSidebar": "Afficher/Masquer la barre latérale",
"update": "Mettre à jour",
"upload": "Importer",
"openFile": "Ouvrir le fichier"
"openFile": "Ouvrir le fichier",
"discardChanges": "Annuler"
},
"download": {
"downloadFile": "Télécharger le fichier",
"downloadFolder": "Télécharger le dossier",
"downloadSelected": "Télécharger la selection"
"downloadSelected": "Télécharger la sélection"
},
"upload": {
"abortUpload": "Êtes-vous sûr de vouloir annuler ?"
},
"errors": {
"forbidden": "Vous n'avez pas la permission d'accéder à cela.",
"internal": "Aïe ! Quelque chose s'est mal passé.",
"notFound": "Impossible d'accéder à cet emplacement.",
"connection": "Le serveur n'est pas accessible."
"connection": "Le serveur est injoignable."
},
"files": {
"body": "Corps",
@@ -61,15 +66,15 @@
"home": "Accueil",
"lastModified": "Dernière modification",
"loading": "Chargement...",
"lonely": "Il semble qu'il n'y ait rien par ici...",
"metadata": "Metadonnées",
"lonely": "C'est un peu désert ici...",
"metadata": "Métadonnées",
"multipleSelectionEnabled": "Sélection multiple activée",
"name": "Nom",
"size": "Taille",
"sortByLastModified": "Trier par date de dernière modification",
"sortByLastModified": "Trier par date de modification",
"sortByName": "Trier par nom",
"sortBySize": "Trier par taille",
"noPreview": "Il n'y a pas de prévisualisation pour ce fichier."
"noPreview": "L'aperçu n'est pas disponible pour ce fichier."
},
"help": {
"click": "Sélectionner un élément",
@@ -105,6 +110,7 @@
"deleteMessageMultiple": "Êtes-vous sûr de vouloir supprimer ces {count} élément(s) ?",
"deleteMessageSingle": "Êtes-vous sûr de vouloir supprimer cet élément ?",
"deleteMessageShare": "Êtes-vous sûr de vouloir supprimer ce partage ({path}) ?",
"deleteUser": "Êtes-vous sûr de vouloir supprimer cet utilisateur ?",
"deleteTitle": "Supprimer",
"displayName": "Nom :",
"download": "Télécharger",
@@ -125,31 +131,33 @@
"rename": "Renommer",
"renameMessage": "Nouveau nom pour",
"replace": "Remplacer",
"replaceMessage": "Un des fichiers que vous êtes en train d'importer a le même nom qu'un autre déjà présent. Voulez-vous remplacer le fichier actuel par le nouveau ?\n",
"schedule": "Fixer la date",
"replaceMessage": "L'un des fichiers que vous êtes en train d'importer a le même nom qu'un autre déjà présent. Voulez-vous remplacer le fichier actuel par le nouveau ?\n",
"schedule": "Planifier",
"scheduleMessage": "Choisissez une date pour planifier la publication de ce post",
"show": "Montrer",
"size": "Taille",
"upload": "Importer",
"uploadFiles": "Importation de {files} fichiers...",
"uploadMessage": "Séléctionnez une option d'import.",
"optionalPassword": "Mot de passe optionnel"
"uploadMessage": "Sélectionnez une option d'import.",
"optionalPassword": "Mot de passe optionnel",
"resolution": "Résolution",
"discardEditorChanges": "Êtes-vous sûr de vouloir annuler les modifications apportées ?"
},
"search": {
"images": "Images",
"music": "Musique",
"pdf": "PDF",
"pressToSearch": "Appuyez du entrée pour chercher...",
"pressToSearch": "Appuyez sur Entrée pour rechercher...",
"search": "Recherche en cours...",
"typeToSearch": "Écrivez pour chercher...",
"typeToSearch": "Écrivez pour rechercher...",
"types": "Types",
"video": "Video"
"video": "Vidéo"
},
"settings": {
"admin": "Admin",
"administrator": "Administrateur",
"allowCommands": "Exécuter des commandes",
"allowEdit": "Editer, 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",
"allowPublish": "Publier de nouveaux posts et pages",
"allowSignup": "Autoriser les utilisateurs à s'inscrire",
@@ -158,32 +166,39 @@
"brandingDirectoryPath": "Chemin du dossier d'image de marque",
"brandingHelp": "Vous pouvez personnaliser l'apparence de votre instance de File Browser en changeant son nom, en remplaçant le logo, en ajoutant des styles personnalisés et même en désactivant les liens externes vers GitHub.\nPour plus d'informations sur la personnalisation de l'image de marque, veuillez consulter la {0}.",
"changePassword": "Modifier le mot de passe",
"commandRunner": "Command runner",
"commandRunnerHelp": "Ici, vous pouvez définir les commandes qui sont exécutées pour les é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}.",
"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}.",
"commandsUpdated": "Commandes mises à jour !",
"createUserDir": "Créer automatiquement un dossier pour l'utilisateur",
"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.",
"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.",
"userHomeBasePath": "Chemin de base pour les répertoires personnels des utilisateurs",
"userScopeGenerationPlaceholder": "Le périmètre sera généré automatiquement",
"createUserHomeDirectory": "Créer le répertoire personnel de l'utilisateur",
"customStylesheet": "Feuille de style personnalisée",
"defaultUserDescription": "Paramètres par défaut pour les nouveaux utilisateurs.",
"disableExternalLinks": "Désactiver les liens externes (sauf la documentation)",
"disableUsedDiskPercentage": "Disable used disk percentage graph",
"disableUsedDiskPercentage": "Désactiver le graphique de pourcentage d'utilisation du disque",
"documentation": "documentation",
"examples": "Exemples",
"executeOnShell": "Exécuter dans le shell",
"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.",
"globalSettings": "Paramètres généraux",
"globalSettings": "Paramètres globaux",
"hideDotfiles": "Cacher les fichiers de configuration utilisateur (dotfiles)",
"insertPath": "Insérez le chemin",
"insertRegex": "Insérez l'expression régulière",
"insertPath": "Insérer le chemin",
"insertRegex": "Insérer une expression régulière",
"instanceName": "Nom de l'instance",
"language": "Langue",
"lockPassword": "Empêcher l'utilisateur de changer son mot de passe",
"newPassword": "Votre nouveau mot de passe",
"newPasswordConfirm": "Confirmation du nouveau mot de passe",
"newUser": "Nouvel Utilisateur",
"newUser": "Nouvel utilisateur",
"password": "Mot de passe",
"passwordUpdated": "Mot de passe mis à jour !",
"path": "",
"path": "Chemin",
"perm": {
"create": "Créer des fichiers et des dossiers",
"delete": "Supprimer des fichiers et des dossiers",
@@ -209,14 +224,14 @@
"singleClick": "Utiliser un simple clic pour ouvrir les fichiers et les dossiers",
"themes": {
"dark": "Sombre",
"light": "Lumineux",
"light": "Clair",
"title": "Thème"
},
"user": "Utilisateur",
"userCommands": "Commandes",
"userCommandsHelp": "Une liste séparée par des espaces des commandes permises pour l'utilisateur. Exemple :",
"userCommandsHelp": "Une liste séparée par des espaces des commandes permises pour l'utilisateur. Exemple :\n",
"userCreated": "Utilisateur créé !",
"userDefaults": "User default settings",
"userDefaults": "Paramètres par défaut de l'utilisateur",
"userDeleted": "Utilisateur supprimé !",
"userManagement": "Gestion des utilisateurs",
"userUpdated": "Utilisateur mis à jour !",
@@ -237,7 +252,7 @@
"siteSettings": "Paramètres du site"
},
"success": {
"linkCopied": "Lien copié!"
"linkCopied": "Lien copié !"
},
"time": {
"days": "Jours",

View File

@@ -23,6 +23,7 @@ import("dayjs/locale/sk");
import("dayjs/locale/sv");
import("dayjs/locale/tr");
import("dayjs/locale/uk");
import("dayjs/locale/vi");
import("dayjs/locale/zh-cn");
import("dayjs/locale/zh-tw");
@@ -103,6 +104,9 @@ export function detectLocale() {
case /^uk\b/.test(locale):
locale = "uk";
break;
case /^vi\b/.test(locale):
locale = "vi";
break;
case /^sv-se\b/.test(locale):
case /^sv\b/.test(locale):
locale = "sv";
@@ -142,7 +146,7 @@ export const i18n = createI18n({
export const isRtl = (locale?: string) => {
// see below
// @ts-ignore
// @ts-expect-error incorrect type when legacy
return rtlLanguages.includes(locale || i18n.global.locale.value);
};
@@ -150,7 +154,7 @@ export function setLocale(locale: string) {
dayjs.locale(locale);
// according to doc u only need .value if legacy: false but they lied
// https://vue-i18n.intlify.dev/guide/essentials/scope.html#local-scope-1
//@ts-ignore
// @ts-expect-error incorrect type when legacy
i18n.global.locale.value = locale;
}

View File

@@ -3,47 +3,60 @@
"cancel": "취소",
"clear": "지우기",
"close": "닫기",
"continue": "계속",
"copy": "복사",
"copyFile": "파일 복사",
"copyToClipboard": "클립보드 복사",
"copyToClipboard": "클립보드 복사",
"copyDownloadLinkToClipboard": "다운로드 링크 클립보드에 복사",
"create": "생성",
"delete": "삭제",
"download": "다운로드",
"hideDotfiles": "",
"file": "파일",
"folder": "폴더",
"fullScreen": "전체 화면 전환",
"hideDotfiles": "숨김 파일 숨기기",
"info": "정보",
"more": "더보기",
"more": "더 보기",
"move": "이동",
"moveFile": "파일 이동",
"new": "신규",
"new": "새로 만들기",
"next": "다음",
"ok": "확인",
"permalink": "링크 기",
"permalink": "영구 링크 기",
"previous": "이전",
"preview": "미리보기",
"publish": "게시",
"rename": "이름 바꾸기",
"replace": "대체",
"reportIssue": "이슈 보내기",
"replace": "바꾸기",
"reportIssue": "문제 보고",
"save": "저장",
"schedule": "일정",
"schedule": "예약",
"search": "검색",
"select": "선택",
"selectMultiple": "다중 선택",
"share": "공유",
"shell": " 전환",
"shell": " 전환",
"submit": "제출",
"switchView": "보기 전환",
"toggleSidebar": "사이드바 전환",
"update": "업데이트",
"upload": "업로드"
"upload": "업로드",
"openFile": "파일 열기",
"discardChanges": "변경 사항 취소"
},
"download": {
"downloadFile": "파일 다운로드",
"downloadFolder": "폴더 다운로드",
"downloadSelected": ""
"downloadSelected": "선택 항목 다운로드"
},
"upload": {
"abortUpload": "업로드를 중단하시겠습니까?"
},
"errors": {
"forbidden": "접근 권한이 없습니다.",
"internal": "오류가 발생하였습니다.",
"notFound": "해당 경로를 찾을 수 없습니다."
"forbidden": "이곳에 접근 권한이 없습니다.",
"internal": "문제가 발생습니다.",
"notFound": "이 위치에 접근할 수 없습니다.",
"connection": "서버에 연결할 수 없습니다."
},
"files": {
"body": "본문",
@@ -51,175 +64,192 @@
"files": "파일",
"folders": "폴더",
"home": "홈",
"lastModified": "최종 수정",
"loading": "로딩중...",
"lonely": "폴더가 비어 있습니다...",
"lastModified": "마지막 수정",
"loading": "로딩 중...",
"lonely": "여기에 아무것도 없네요...",
"metadata": "메타데이터",
"multipleSelectionEnabled": "다중 선택 켜짐",
"multipleSelectionEnabled": "다중 선택 활성화됨",
"name": "이름",
"size": "크기",
"sortByLastModified": "수정시간순 정렬",
"sortByName": "이름",
"sortBySize": "크기순"
"sortByLastModified": "마지막 수정일 순 정렬",
"sortByName": "이름 순 정렬",
"sortBySize": "크기 순 정렬",
"noPreview": "이 파일은 미리보기를 사용할 수 없습니다."
},
"help": {
"click": "파일이나 디렉토리를 선택해주세요.",
"click": "파일 또는 디렉터리 선택",
"ctrl": {
"click": "여러 개의 파일이나 디렉토리를 선택해주세요.",
"f": "검색 열기",
"s": "파일 또는 디렉리 다운로드"
"click": "여러 파일 또는 디렉터리 선택",
"f": "검색 열기",
"s": "파일 저장 또는 현재 디렉리 다운로드"
},
"del": "선택된 파일 삭제",
"doubleClick": "파일 또는 디렉리 열기",
"esc": "선택 취소/프롬프트 닫기",
"f1": "정보",
"f2": "파일 이름 변경",
"del": "선택한 항목 삭제",
"doubleClick": "파일 또는 디렉리 열기",
"esc": "선택 취소 및/또는 프롬프트 닫기",
"f1": "정보",
"f2": "파일 이름 바꾸기",
"help": "도움말"
},
"login": {
"createAnAccount": "계정 생성",
"createAnAccount": "계정 만들기",
"loginInstead": "이미 계정이 있습니다",
"password": "비밀번호",
"passwordConfirm": "비밀번호 확인",
"passwordsDontMatch": "비밀번호가 일치하지 않습니다",
"signup": "가입하기",
"signup": "가입",
"submit": "로그인",
"username": "사용자 이름",
"usernameTaken": "사용자 이름이 존재합니다",
"wrongCredentials": "사용자 이름 또는 비밀번호를 확인하십시오"
"usernameTaken": "이미 사용 중인 사용자 이름니다",
"wrongCredentials": "잘못된 자격 증명"
},
"permanent": "영구",
"prompts": {
"copy": "복사",
"copyMessage": "복사할 디렉토리:",
"currentlyNavigating": "현재 위치:",
"deleteMessageMultiple": "{count} 개의 파일을 삭제하시겠습니까?",
"deleteMessageSingle": "파일 혹은 디렉토리를 삭제하시겠습니까?",
"copyMessage": "파일을 복사할 위치를 선택하세요:",
"currentlyNavigating": "현재 탐색 중:",
"deleteMessageMultiple": "{count}개의 파일을 삭제하시겠습니까?",
"deleteMessageSingle": "이 파일/폴더를 삭제하시겠습니까?",
"deleteMessageShare": "이 공유({path})를 삭제하시겠습니까?",
"deleteUser": "이 사용자를 삭제하시겠습니까?",
"deleteTitle": "파일 삭제",
"displayName": "시 이름:",
"displayName": "시 이름:",
"download": "파일 다운로드",
"downloadMessage": "다운로드 포맷 설정.",
"error": "에러 발생!",
"downloadMessage": "다운로드할 형식을 선택하세요.",
"error": "문제가 발생했습니다",
"fileInfo": "파일 정보",
"filesSelected": "{count} 개의 파일 선택되었습니다.",
"lastModified": "최종 수정",
"filesSelected": "{count}개의 파일 선택.",
"lastModified": "마지막 수정",
"move": "이동",
"moveMessage": "이동할 화일 또는 디렉토리를 선택하세요:",
"newArchetype": "원형을 유지하는 포스트를 생성합니다. 파일은 컨텐트 폴더에 생성됩니다.",
"newDir": "새 디렉리",
"newDirMessage": "새 디렉리 이름을 입력해주세요.",
"moveMessage": "파일/폴더의 새 위치를 선택하세요:",
"newArchetype": "아키타입을 기반으로 새 게시물을 만듭니다. 파일은 content 폴더에 생성됩니다.",
"newDir": "새 디렉리",
"newDirMessage": "새 디렉리 이름을 지정하세요.",
"newFile": "새 파일",
"newFileMessage": "새 파일 이름을 입력해주세요.",
"numberDirs": "디렉리 수",
"newFileMessage": "새 파일 이름을 지정하세요.",
"numberDirs": "디렉리 수",
"numberFiles": "파일 수",
"rename": "이름 변경",
"renameMessage": "새로운 이름을 입력하세요.",
"replace": "대체하기",
"replaceMessage": "동일한 파일 이름이 존재합니다. 현재 파일을 덮어쓸까요?\n",
"schedule": "일정",
"scheduleMessage": "이 글을 공개할 시간을 알려주세요.",
"show": "보기",
"rename": "이름 바꾸기",
"renameMessage": "새 이름을 입력하세요:",
"replace": "바꾸기",
"replaceMessage": "업로드하려는 파일 이름이 충돌하는 파일이 있습니다. 이 파일을 건너뛰고 업로드를 계속하거나 기존 파일을 바꾸시겠습니까?\n",
"schedule": "예약",
"scheduleMessage": "이 게시물의 게시를 예약할 날짜와 시간을 선택하세요.",
"show": "표시",
"size": "크기",
"upload": "",
"uploadMessage": ""
"upload": "업로드",
"uploadFiles": "{files}개의 파일 업로드 중...",
"uploadMessage": "업로드할 옵션을 선택하세요.",
"optionalPassword": "선택적 비밀번호",
"resolution": "해상도",
"discardEditorChanges": "변경 사항을 취소하시겠습니까?"
},
"search": {
"images": "이미지",
"music": "음악",
"pdf": "PDF",
"pressToSearch": "검색하려면 엔터를 입력하세요",
"pressToSearch": "Enter 키를 눌러 검색...",
"search": "검색...",
"typeToSearch": "검색어 입력...",
"types": "Types",
"types": "유형",
"video": "비디오"
},
"settings": {
"admin": "관리자",
"administrator": "관리자",
"allowCommands": "명령 실행",
"allowEdit": "파일/디렉토리의 수정/변경/삭제 허용",
"allowNew": "파일/디렉리 생성 허용",
"allowPublish": "새 포스트/페이지 생성 허용",
"allowCommands": "명령 실행 허용",
"allowEdit": "파일 또는 디렉터리 편집, 이름 바꾸기, 삭제 허용",
"allowNew": "새 파일 및 디렉리 생성 허용",
"allowPublish": "새 게시물 및 페이지 게시 허용",
"allowSignup": "사용자 가입 허용",
"avoidChanges": "(수정하지 않으면 비워두세요)",
"avoidChanges": "(변경하지 않으면 비워두세요)",
"branding": "브랜딩",
"brandingDirectoryPath": "브랜 디렉리 경로",
"brandingHelp": "File Browser 인스턴스 이름, 로고, 스타일 등을 변경할 수 있습니다. 자세한 사항은 여기{0}에서 확인하세요.",
"brandingDirectoryPath": "브랜 디렉리 경로",
"brandingHelp": "File Browser 인스턴스 이름 변경, 로고 교체, 사용자 정의 스타일 추가, GitHub 외부 링크 비활성화를 통해 모양과 느낌을 사용자 지정할 수 있습니다.\n사용자 정의 브랜딩에 대한 자세한 내용은 {0}을(를) 확인하세요.",
"changePassword": "비밀번호 변경",
"commandRunner": "명령 실행기",
"commandRunnerHelp": "이벤트에 해당하는 명령 설정하세요. 줄당 1개의 명령을 적으세요. 환경 변수{0} {1}이 사용가능하며, {0} 은 {1}에 상대 경로 입니다. 자세한 사항은 {2} 를 참조하세요.",
"commandsUpdated": "명령 수정됨!",
"createUserDir": "Auto create user home dir while adding new user",
"customStylesheet": "커스텀 스타일시트",
"defaultUserDescription": "아래 사항은 신규 사용자들에 대한 기본 설정입니다.",
"disableExternalLinks": "외부 링크 감추기",
"disableUsedDiskPercentage": "Disable used disk percentage graph",
"commandRunner": "명령 실행기",
"commandRunnerHelp": "여기서 지정된 이벤트에서 실행될 명령어를 설정할 수 있습니다. 한 줄에 하나씩 작성해야 합니다. 환경 변수 {0} {1}을(를) 사용할 수 있으며, {0}은(는) {1}에 상대입니다. 이 기능과 사용 가능한 환경 변수에 대한 자세한 내용은 {2}을(를) 읽어보세요.",
"commandsUpdated": "명령어가 업데이트되었습니다!",
"createUserDir": "새 사용자 추가 시 사용자 홈 디렉터리 자동 생성",
"tusUploads": "청크 업로드",
"tusUploadsHelp": "File Browser는 청크 파일 업로드를 지원하여 불안정한 네트워크에서도 효율적이고 안정적이며 재개 가능하고 분할된 파일 업로드를 가능하게 합니다.",
"tusUploadsChunkSize": "요청의 최대 크기를 나타냅니다 (더 작은 업로드에는 직접 업로드가 사용됩니다). 바이트 크기를 나타내는 일반 정수 또는 10MB, 1GB 등과 같은 문자열을 입력할 수 있습니다.",
"tusUploadsRetryCount": "청크 업로드 실패 시 재시도 횟수.",
"userHomeBasePath": "사용자 홈 디렉터리의 기본 경로",
"userScopeGenerationPlaceholder": "범위가 자동으로 생성됩니다",
"createUserHomeDirectory": "사용자 홈 디렉터리 생성",
"customStylesheet": "사용자 정의 스타일시트",
"defaultUserDescription": "새 사용자의 기본 설정입니다.",
"disableExternalLinks": "외부 링크 비활성화 (문서 제외)",
"disableUsedDiskPercentage": "사용된 디스크 비율 그래프 비활성화",
"documentation": "문서",
"examples": "예",
"executeOnShell": "에서 실행",
"executeOnShellDescription": "기본적으로 File Browser 는 바이너리를 명령어로 호출하여 실행합니다. 쉘을 통해 실행하기를 원한다면, Bash 또는 PowerShell 필요한 인수 플래그를 설정하세요. 사용자 명령어와 이벤트 훅에 모두 적용됩니다.",
"globalRules": "규칙에 대한 전역설정으로 모든 사용자에게 적용됩니다. 지정된 규칙은 사용자 설정을 덮어쓰기 합니다.",
"examples": "예",
"executeOnShell": "에서 실행",
"executeOnShellDescription": "기본적으로 File Browser는 바이너리를 직접 호출하여 명령을 실행합니다. 대신 셸(예: Bash 또는 PowerShell)에서 실행하려면 필요한 인수 플래그와 함께 여기에 정의할 수 있습니다. 설정된 경우 실행하는 명령이 인수로 추가됩니다. 이는 사용자 명령 이벤트 후크 모두 적용됩니다.",
"globalRules": "이것은 전역 허용 및 차단 규칙 세트입니다. 모든 사용자에게 적용됩니다. 각 사용자 설정에서 특정 규칙을 정의하여 이 규칙을 재정의할 수 있습니다.",
"globalSettings": "전역 설정",
"hideDotfiles": "",
"insertPath": "경로 입",
"insertRegex": "정규식 입",
"hideDotfiles": "숨김 파일 숨기기",
"insertPath": "경로 입",
"insertRegex": "정규식 표현 삽입",
"instanceName": "인스턴스 이름",
"language": "언어",
"lockPassword": "사용자에 의한 비밀번호 변경을 허용하지 않음",
"newPassword": "새로운 비밀번호",
"newPasswordConfirm": "새로운 비밀번호 확인",
"newUser": "새로운 사용자",
"lockPassword": "사용자 비밀번호 변경하지 못하도록 잠금",
"newPassword": "새 비밀번호",
"newPasswordConfirm": "새 비밀번호 확인",
"newUser": "새 사용자",
"password": "비밀번호",
"passwordUpdated": "비밀번호 수정 완료!",
"path": "",
"passwordUpdated": "비밀번호가 업데이트되었습니다!",
"path": "경로",
"perm": {
"create": "파일이나 디렉리 생성하기",
"delete": "화일이나 디렉리 삭제하기",
"create": "파일 디렉리 생성",
"delete": "파일 및 디렉리 삭제",
"download": "다운로드",
"execute": "명령 실행",
"modify": "파일 편집",
"rename": "파일 이름 변경 또는 디렉토리 이동",
"share": "파일 공유하기"
"rename": "파일 및 디렉터리 이름 바꾸기 또는 이동",
"share": "파일 공유"
},
"permissions": "권한",
"permissionsHelp": "사용자를 관리자로 만들거나 권한을 부여할 수 있습니다. 관리자를 선택하면, 모든 옵션이 자동으로 선택됩니다. 사용자 관리는 현재 관리자만 할 수 있습니다.\n",
"permissionsHelp": "사용자를 관리자로 설정하거나 개별적으로 권한을 선택할 수 있습니다. \"관리자\"를 선택하면 다른 모든 옵션이 자동으로 선택됩니다. 사용자 관리는 관리자의 권한으로 유지됩니다.\n",
"profileSettings": "프로필 설정",
"ruleExample1": "점(.)으로 시작하는 모든 파일의 접근을 방지합니다.(예 .git, .gitignore)\n",
"ruleExample2": "Caddyfile파일의 접근을 방지합니다.",
"rules": "",
"rulesHelp": "사용자별로 규칙을 허용/방지를 지정할 수 있습니다. 방지된 파일은 보이지 않 사용자들은 접근할 수 없습니다. 사용자의 접근 허용 범위와 관련해 정규표현식(regex)과 경로를 지원합니다.\n",
"ruleExample1": "모든 폴더에서 모든 숨김 파일(예: .git, .gitignore)에 대한 액세스를 방지합니다.\n",
"ruleExample2": "범위의 루트에 있는 Caddyfile이라는 파일에 대한 액세스를 차단합니다.",
"rules": "규칙",
"rulesHelp": "여기서 이 특정 사용자에 대한 허용 및 차단 규칙 세트를 정의할 수 있습니다. 차단된 파일은 목록에 표시되지 않으며 사용자가 액세스할 수 없습니다. 사용자의 범위에 상대적인 정규식 및 경로를 지원합니다.\n",
"scope": "범위",
"settingsUpdated": "설정 수정됨!",
"shareDuration": "",
"shareManagement": "",
"singleClick": "",
"setDateFormat": "정확한 날짜 형식 설정",
"settingsUpdated": "설정이 업데이트되었습니다!",
"shareDuration": "공유 기간",
"shareManagement": "공유 관리",
"shareDeleted": "공유가 삭제되었습니다!",
"singleClick": "파일 및 디렉터리를 열 때 한 번 클릭 사용",
"themes": {
"dark": "",
"light": "",
"title": ""
"default": "시스템 기본값",
"dark": "어둡게",
"light": "밝게",
"title": "테마"
},
"user": "사용자",
"userCommands": "명령어",
"userCommandsHelp": "사용에게 허용할 명령어를 공백으로 구분하여 입력하세요. 예:\n",
"userCreated": "사용자 생성!",
"userCommandsHelp": "이 사용자가 사용할 수 있는 명령어 목록 (공백으로 구분). 예:\n",
"userCreated": "사용자 생성되었습니다!",
"userDefaults": "사용자 기본 설정",
"userDeleted": "사용자 삭제!",
"userDeleted": "사용자 삭제되었습니다!",
"userManagement": "사용자 관리",
"userUpdated": "사용자 수정됨!",
"userUpdated": "사용자가 업데이트되었습니다!",
"username": "사용자 이름",
"users": "사용자"
},
"sidebar": {
"help": "도움말",
"hugoNew": "Hugo New",
"hugoNew": "Hugo 새로 만들기",
"login": "로그인",
"logout": "로그아웃",
"myFiles": "내 파일",
"newFile": "새로운 파일",
"newFolder": "새로운 폴더",
"newFile": "새 파일",
"newFolder": "새 폴더",
"preview": "미리보기",
"settings": "설정",
"signup": "가입하기",
"signup": "가입",
"siteSettings": "사이트 설정"
},
"success": {
@@ -227,9 +257,9 @@
},
"time": {
"days": "일",
"hours": "시",
"hours": "시",
"minutes": "분",
"seconds": "초",
"unit": "Time Unit"
"unit": "시간 단위"
}
}

View File

@@ -3,133 +3,153 @@
"cancel": "Anuluj",
"clear": "Wyczyść",
"close": "Zamknij",
"continue": "Kontynuuj",
"copy": "Kopiuj",
"copyFile": "Kopiuj plik",
"copyToClipboard": "kopiuj do schowka",
"copyToClipboard": "Kopiuj do schowka",
"copyDownloadLinkToClipboard": "Kopiuj link pobierania do schowka",
"create": "Utwórz",
"delete": "Usuń",
"download": "Pobierz",
"hideDotfiles": "",
"info": "Informacja",
"more": "Więce",
"file": "Plik",
"folder": "Folder",
"fullScreen": "Przełącz tryb pełnoekranowy",
"hideDotfiles": "Ukryj pliki poprzedzone kropką",
"info": "Informacje",
"more": "Więcej",
"move": "Przenieś",
"moveFile": "Przenieś plik",
"new": "Nowy",
"next": "Następny",
"ok": "OK",
"permalink": "Uzyskaj link bezpośredni (permalink)",
"permalink": "Uzyskaj stały link",
"previous": "Poprzedni",
"preview": "Podgląd",
"publish": "Opublikuj",
"rename": "Zmień nazwę",
"replace": "Zamień",
"reportIssue": "Zgłoś problem",
"save": "Zapisz",
"schedule": "Grafik",
"schedule": "Harmonogram",
"search": "Szukaj",
"select": "Wybierz",
"select": "Zaznacz",
"selectMultiple": "Zaznacz wiele",
"share": "Udostępnij",
"shell": "Pokaż/ukryj powłokę",
"shell": "Przełącz powłokę",
"submit": "Prześlij",
"switchView": "Zmień widok",
"toggleSidebar": "Pokaż/ukryj panel boczny",
"toggleSidebar": "Przełącz pasek boczny",
"update": "Aktualizuj",
"upload": "Wgraj"
"upload": "Wyślij",
"openFile": "Otwórz plik",
"discardChanges": "Odrzuć"
},
"download": {
"downloadFile": "Pobierz plik",
"downloadFolder": "Pobierz folder",
"downloadSelected": "Pobierz zaznaczone"
},
"upload": {
"abortUpload": "Czy na pewno chcesz przerwać?"
},
"errors": {
"forbidden": "Nie posiadasz uprawnień potrzebnych, by uzyskać do tego dostęp.",
"forbidden": "Nie masz zezwolenia na dostęp do tego.",
"internal": "Pojawił się poważny problem.",
"notFound": "Ten adres nie jest poprawny."
"notFound": "Ta lokalizacja jest nieosiągalna.",
"connection": "Serwer jest nieosiągalny."
},
"files": {
"body": "Body",
"closePreview": "Zamknij poprzednie",
"body": "Zawartość",
"closePreview": "Zamknij podgląd",
"files": "Pliki",
"folders": "Foldery",
"home": "Katalog domowy",
"lastModified": "Ostatnio modyfikowane",
"home": "Główny",
"lastModified": "Ostatnio zmodyfikowano",
"loading": "Ładowanie...",
"lonely": "Smutno gdy tak pusto...",
"lonely": "Smutno, gdy tak pusto...",
"metadata": "Metadane",
"multipleSelectionEnabled": "Zaznaczenie wielu włączone",
"multipleSelectionEnabled": "Włączono zaznaczenie wielokrotne",
"name": "Nazwa",
"size": "Rozmiar",
"sortByLastModified": "Sortuj wg. daty modyfikacji",
"sortByName": "Sortuj wg. nazwy",
"sortBySize": "Sortuj wg. rozmiaru"
"sortByLastModified": "Sortuj wg ostatniej modyfikacji",
"sortByName": "Sortuj wg nazwy",
"sortBySize": "Sortuj wg rozmiaru",
"noPreview": "Podgląd tego pliku jest niedostępny."
},
"help": {
"click": "wybierz plik lub foler",
"click": "zaznacz plik lub folder",
"ctrl": {
"click": "wybierz wiele plików lub folderów",
"click": "zaznacz wiele plików lub folderów",
"f": "otwórz wyszukiwarkę",
"s": "pobierz aktywny plik lub folder"
},
"del": "usuń zaznaczone",
"del": "usuń zaznaczone elementy",
"doubleClick": "otwórz plik lub folder",
"esc": "wyczyść zaznaczenie i/lub zamknij okno z powiadomieniem",
"f1": "ta informacja",
"esc": "wyczyść zaznaczenie i/lub zamknij monit",
"f1": "te informacje",
"f2": "zmień nazwę pliku",
"help": "Pomoc"
},
"login": {
"createAnAccount": "Utwórz konto",
"loginInstead": "Takie konto już istnieje",
"loginInstead": "Mam już konto",
"password": "Hasło",
"passwordConfirm": "Potwierdzenie hasła",
"passwordsDontMatch": "Hasła różnią się",
"passwordsDontMatch": "Hasła nie pasują do siebie",
"signup": "Rejestracja",
"submit": "Logowanie",
"submit": "Zaloguj",
"username": "Nazwa użytkownika",
"usernameTaken": "Nazwa użytkownika j zajęta",
"usernameTaken": "Ta nazwa użytkownika jest zajęta",
"wrongCredentials": "Błędne dane logowania"
},
"permanent": "Permanentny",
"prompts": {
"copy": "Kopiuj",
"copyMessage": "Wybierz lokalizację do której mają być skopiowane wybrane pliki",
"currentlyNavigating": "Obecnie przeglądasz:",
"deleteMessageMultiple": "Czy jesteś pewien że chcesz usunąć {count} plik(ów)?",
"deleteMessageSingle": "Czy jesteś pewien, że chcesz usunąć ten plik/folder?",
"copyMessage": "Wybierz lokalizację docelową:",
"currentlyNavigating": "Aktualnie poruszasz się po:",
"deleteMessageMultiple": "Czy na pewno chcesz usunąć pliki: {count}?",
"deleteMessageSingle": "Czy na pewno chcesz usunąć ten plik/folder?",
"deleteMessageShare": "Czy na pewno chcesz usunąć ten udział ({path})?",
"deleteUser": "Czy na pewno chcesz usunąć tego użytkownika?",
"deleteTitle": "Usuń pliki",
"displayName": "Wyświetlana Nazwa:",
"displayName": "Wyświetlana nazwa:",
"download": "Pobierz pliki",
"downloadMessage": "Wybierz format, jaki chesz pobrać.",
"error": "Pojawił się nieznany błąd",
"fileInfo": "Informacje o pliku",
"filesSelected": "{count} plików zostało zaznaczonych.",
"lastModified": "Osatnio Zmodyfikowane",
"downloadMessage": "Wybierz format, w którym chcesz pobrać.",
"error": "Pojawił się jakiś błąd",
"fileInfo": "Informacje o pliku",
"filesSelected": "Zaznaczone pliki: {count}",
"lastModified": "Ostatnio zmodyfikowano",
"move": "Przenieś",
"moveMessage": "Wybierz nową lokalizację dla swoich plik(ów)/folder(ów):",
"newArchetype": "Utwórz nowy wpis na bazie wybranego wzorca. Twój plik będzie utworzony w wybranym folderze.",
"moveMessage": "Wybierz nową lokalizację dla swoich plików/folderów:",
"newArchetype": "Utwórz nowy wpis na bazie wybranego wzorca. Twój plik będzie utworzony w wybranym folderze.",
"newDir": "Nowy folder",
"newDirMessage": "Podaj nazwę tworzonego folderu.",
"newDirMessage": "Nazwij nowy folder.",
"newFile": "Nowy plik",
"newFileMessage": "Podaj nazwętworzonego pliku.",
"numberDirs": "Ilość katalogów",
"numberFiles": "Ilość plików",
"newFileMessage": "Nazwij nowy plik.",
"numberDirs": "Liczba folderów",
"numberFiles": "Liczba plików",
"rename": "Zmień nazwę",
"renameMessage": "Podaj nową nazwę dla",
"replace": "Zamień",
"replaceMessage": "Jednen z plików który próbujesz wrzucić próbje nadpisać plik o tej samej nazwie. Czy chcesz nadpisać poprzedni plik?\n",
"schedule": "Grafi",
"scheduleMessage": "Wybierz datę i czas dla publikacji tego wpisu.",
"replaceMessage": "Jeden z przesyłanych plików chce nadpisać istniejący plik o tej samej nazwie. Chcesz pominąć ten plik i kontynuować przesyłanie reszty plików, czy nadpisać istniejący plik?\n",
"schedule": "Grafik",
"scheduleMessage": "Wybierz datę i czas dla publikacji tego wpisu.",
"show": "Pokaż",
"size": "Rozmiar",
"upload": "Prześlij",
"uploadMessage": "Proszę wybrać metodę przesyłania"
"upload": "Wyślij",
"uploadFiles": "Wysyłam pliki: {files}...",
"uploadMessage": "Wybierz opcję przesyłania.",
"optionalPassword": "Opcjonalne hasło",
"resolution": "Rozdzielczość",
"discardEditorChanges": "Czy na pewno chcesz odrzucić wprowadzone zmiany?"
},
"search": {
"images": "Zdjęcia",
"images": "Obrazy",
"music": "Muzyka",
"pdf": "PDF",
"pressToSearch": "Wciśnij enter, aby wyszukać...",
"pressToSearch": "Naciśnij Enter, aby wyszukać...",
"search": "Szukaj...",
"typeToSearch": "Zacznij pisać, aby wyszukać...",
"typeToSearch": "Typ plików do wyszukania...",
"types": "Typy",
"video": "Wideo"
},
@@ -137,70 +157,80 @@
"admin": "Admin",
"administrator": "Administrator",
"allowCommands": "Wykonaj polecenie",
"allowEdit": "Edycja, zmiana nazwy i usuniecie plików lub folderów",
"allowEdit": "Edycja, zmiana nazwy i usuniecie plików lub folderów",
"allowNew": "Tworzenie nowych plików lub folderów",
"allowPublish": "Tworzenie nowych wpisów i stron",
"allowSignup": "Zezwól na rejestrację użytkowników",
"avoidChanges": "(pozostaw puste aby nie zosatało zmienione)",
"branding": "Branding",
"brandingDirectoryPath": "Folder brandingowy",
"brandingHelp": "Możesz dostosować wygląd i doznania użytkownika swojej instancji File Browser poprzez zmianę jej nazwy, zmianę logo, dodanie własnych stylów, a nawet wyłączyć linki zewnętrzne do GitHuba.\nW celu pozyskania większej ilości informacji nt. osobistego brandingu, zapoznaj się z {0}.",
"changePassword": "Zmień Hasło",
"allowPublish": "Tworzenie nowych wpisów i stron",
"allowSignup": "Pozwól użytkownikom na rejestrację",
"avoidChanges": "(pozostaw puste, aby uniknąć zmian)",
"branding": "Personalizacja",
"brandingDirectoryPath": "Ścieżka do folderu personalizacji",
"brandingHelp": "Możesz zmodyfikować wygląd instancji File Browser poprzez zmianę nazwy, logo, dodanie własnych stylów graficznych, a nawet usunięcia linków do serwisu GitHub. Więcej informacji o modyfikacji wyglądu znajdziesz w {0}.",
"changePassword": "Zmień hasło",
"commandRunner": "Narzędzie do wykonywania poleceń",
"commandRunnerHelp": "Tu możesz ustawić komendy, które będą wykonywane przy danych zdarzeniach. Musisz wpisywać po jednej na linjkę. Zmienne środowiskowe {0} i {1} będą dostępne, gdzie {0} jest względne wobec {1}. Więcej informacji o tej funkcji i dostępnych zmiennych środowiskowych znajdziesz tutaj: {2}.",
"commandRunnerHelp": "Tu możesz ustawić polecenia, które będą wykonywane przy danych zdarzeniach. Musisz wpisywać po jednym na wiersz. Zmienne środowiskowe {0} i {1} będą dostępne, gdzie {0} jest względne wobec {1}. Więcej informacji o tej funkcji i dostępnych zmiennych środowiskowych znajdziesz w {2}.",
"commandsUpdated": "Polecenie zaktualizowane!",
"createUserDir": "Automatycznie utwórz katalog domowy użytkownika podczas dodania nowego użytkownika",
"customStylesheet": "Własny arkusz stylów",
"defaultUserDescription": "Oto domyślne ustawienia dla nowych użytkowników.",
"disableExternalLinks": "Wyłącz linki zewnętrzne (z wyjątkiem dokumentacji)",
"disableUsedDiskPercentage": "Disable used disk percentage graph",
"documentation": "dokumentacja",
"createUserDir": "Automatycznie twórz katalog domowy podczas dodawania użytkownika",
"tusUploads": "Przesyłanie we fragmentach",
"tusUploadsHelp": "File Browser wspiera przesyłanie plików we fragmentach, co pozwala na proces przesyłania, który jest wydajny, pewny i możliwy do wznowienia nawet w sieciach o wątpliwej stabilności przesyłu danych.",
"tusUploadsChunkSize": "Oznacza maksymalny rozmiar przesyłanych plików (dla mniejszych plików użyte zostanie przesyłanie bezpośrednie). Możesz ustawić tę wartość zarówno zapisaną samymi cyframi w bajtach, jak i podać ją w formie skróconej, np. poprzez 10MB, 1GB itp.",
"tusUploadsRetryCount": "Liczba prób ponowienia transferu w przypadku wystapienia problemu z przesyłem.",
"userHomeBasePath": "Ścieżka podstawowa dla katalogów domowych użytkowników",
"userScopeGenerationPlaceholder": "Zakres zostanie wygenerowany automatycznie",
"createUserHomeDirectory": "Utwórz katalog domowy użytkownika",
"customStylesheet": "Własny arkusz stylu",
"defaultUserDescription": "To są domyślne ustawienia dla nowych użytkowników.",
"disableExternalLinks": "Wyłącz linki zewnętrzne (z wyjątkiem dokumentacji)",
"disableUsedDiskPercentage": "Wyłącz wykres procentowy używanego dysku",
"documentation": "dokumentacji",
"examples": "Przykłady",
"executeOnShell": "Wykonaj w powłoce",
"executeOnShellDescription": "Domyślnie File Browser wykonuje polecenia wywołując ich pliki binarne bezpośrednio. Jesli preferujesz wykonywanie ich w powłoce (jak np. Bash czy PowerShell), możesz zdefiniować to tutaj wraz z wymaganymi flagami i argumentami. Jeśli to ustawienie jest aktywne, polecenie które wykonarz zostanie dodane jako argument. Stosuje się to zarówno do poleceń użytkownika jak i zaczepów zdarzeń.",
"globalRules": "To jest globalne zestawienie reguł zezwalających i zabraniających. Stosują się one do każdego użytkownika. Możesz zdefiniować indywidualne zasady w ustawieniach każdego użytkownika, by zignorować te reguły.",
"globalSettings": "Ustawienia Globalne",
"hideDotfiles": "Ukryj ukryte pliki",
"executeOnShell": "Wykonaj w powłoce",
"executeOnShellDescription": "Domyślnie File Browser wykonuje polecenia poprzez bezpośrednie uruchomienie odpowiednich plików binarnych. Jeśli chcesz uruchamiać polecenia z poziomu powłoki (np. Bash lub PowerShell), możesz zdefiniować je tutaj, z wykorzystaniem odpowiednich argumentów i flag. Gdy się na to zdecydujesz, wykonywane polecenie będzie załączone jako argument. Tyczy się to tak poleceń użytkownika, jak i zaczepów zdarzeń.",
"globalRules": "Globalny zestaw reguł zezwalających i zakazujących. Dotyczą każdego użytkownika. Aby zastąpić ustawienia globalne, możesz zdefiniować określone reguły indywidualnie dla każdego użytkownika.",
"globalSettings": "Ustawienia globalne",
"hideDotfiles": "Ukryj pliki poprzedzone kropką",
"insertPath": "Wstaw ścieżkę",
"insertRegex": "Wstaw wyrażenie regularne",
"instanceName": "Nazwa instancji",
"language": "Język",
"lockPassword": "Zablokuj użytkownikowi możliwość zmiany hasła",
"newPassword": "Twoje nowe hasło",
"newPasswordConfirm": "Potwierdź swoje hasło",
"newUser": "Nowy Użytkownik",
"newPassword": "Nowe hasło",
"newPasswordConfirm": "Potwierdź nowe hasło",
"newUser": "Nowy użytkownik",
"password": "Hasło",
"passwordUpdated": "Hasło zostało zapisane!",
"passwordUpdated": "Hasło zostało zaktualizowane!",
"path": "Ścieżka",
"perm": {
"create": "Tworzenie plików i katalogów",
"delete": "Usuwanie plików i katalogów",
"create": "Tworzenie plików i folderów",
"delete": "Usuwanie plików i folderów",
"download": "Pobieranie",
"execute": "Wykonywanie poleceń",
"modify": "Edycja plików",
"rename": "Zmiana nazw lub przenoszenie plików i katalogów",
"modify": "Edytowanie plików",
"rename": "Zmienianie nazwy lub przenoszenie plików i katalogów",
"share": "Udostępnianie plików"
},
"permissions": "Uprawnienia",
"permissionsHelp": "Możesz uczynić użytkownika administratorem, lub wybrać uprawnienia indywidualnie. Jeśli zaznaczysz opcję \"Administrator\", wszystkie pozostałe opcje zostaną automatycznie zaznaczone. Zarządzanie użytkownikami pozostaje przywilejem administratora.\n",
"permissionsHelp": "Możesz ustawić użytkownika jako administratora lub wybrać uprawnienia indywidualnie. Jeśli wybierzesz „Administrator, wszystkie pozostałe opcje zostaną automatycznie zaznaczone. Zarządzanie użytkownikami pozostaje przywilejem administratora.\n",
"profileSettings": "Twój profil",
"ruleExample1": "uniemożliwia dostęp do któregokolwiek z ukrytych plików (takich jak .git, .gitignore) w każdym folderze.\n",
"ruleExample2": "blokuje dostęp do pliku Caddyfile w głównym katalogu zakresu.",
"ruleExample1": "uniemożliwia dostęp do plików poprzedzonych kropką (takich jak .git, .gitignore) we wszystkich folderach.\n",
"ruleExample2": "blokuje dostęp do pliku o nazwie Caddyfile w katalogu głównym zakresu.",
"rules": "Uprawnienia",
"rulesHelp": "Tu możesz zdefiniować zestawienie reguł zezwalających i zabraniających dla tego konkretnego użytkownika. Zablokowane pliki nie będą widoczne na listach i nie będą dostępne dla użytkownika. Wspierane są wyrażenia regularne i ścieżki względne wobec zakresu użytkownika.\n",
"rulesHelp": "Tutaj możesz zdefiniować zestaw reguł zezwalających i zakazujących dla tego użytkownika. Zablokowane pliki nie pojawią się na listach i nie będą dostępne dla użytkownika. Obsługujemy wyrażenia regularne i ścieżki względne w stosunku do zakresu użytkownika.\n",
"scope": "Zakres",
"settingsUpdated": "Uprawnienia Zapisane!",
"setDateFormat": "Ustaw dokładny format daty",
"settingsUpdated": "Ustawienia zaktualizowane!",
"shareDuration": "Okres udostępniania",
"shareManagement": "Zarządzanie udostępnianiem",
"singleClick": "Pojedyncze kliknięcie",
"shareDeleted": "Udostępnienie usunięte!",
"singleClick": "Używaj pojedynczych kliknięć, aby otwierać pliki i foldery",
"themes": {
"dark": "ciemny",
"light": "jasny",
"title": "Motywy"
"default": "Domyślny systemowy",
"dark": "Ciemny",
"light": "Jasny",
"title": "Motyw"
},
"user": "Użytkownik",
"userCommands": "Polecenia",
"userCommandsHelp": "Lista oddzielonych spacjami poleceń dostępnych dla tego użytkownika. Przykład:\n",
"userCommandsHelp": "Oddzielona spacjami lista z dostępnymi poleceniami dla tego użytkownika. Przykład:\n",
"userCreated": "Użytkownik zapisany!",
"userDefaults": "Domyślne ustawienia użytkownika",
"userDeleted": "Użytkownik usunięty!",
@@ -211,8 +241,8 @@
},
"sidebar": {
"help": "Pomoc",
"hugoNew": "Hugo New",
"login": "Login",
"hugoNew": "Nowy Hugo",
"login": "Zaloguj",
"logout": "Wyloguj",
"myFiles": "Moje pliki",
"newFile": "Nowy plik",
@@ -220,10 +250,10 @@
"preview": "Podgląd",
"settings": "Ustawienia",
"signup": "Rejestracja",
"siteSettings": "Ustawienia Strony"
"siteSettings": "Ustawienia strony"
},
"success": {
"linkCopied": "Link Skopiowany!"
"linkCopied": "Link skopiowany!"
},
"time": {
"days": "Dni",

View File

@@ -38,13 +38,20 @@
"toggleSidebar": "Alternar barra lateral",
"update": "Atualizar",
"upload": "Enviar",
"openFile": "Abrir"
"openFile": "Abrir",
"copyDownloadLinkToClipboard": "Copiar link de download para a área de transferência",
"fullScreen": "Alternar tela cheia",
"preview": "Pré-visualizar",
"discardChanges": "Descartar"
},
"download": {
"downloadFile": "Baixar arquivo",
"downloadFolder": "Baixar pasta",
"downloadSelected": "Baixar selecionado"
},
"upload": {
"abortUpload": "Tem certeza de que deseja abortar o upload?"
},
"errors": {
"forbidden": "Você não tem permissões para acessar isto.",
"internal": "Ops! Algum erro ocorreu.",
@@ -58,8 +65,8 @@
"folders": "Pastas",
"home": "Início",
"lastModified": "Última modificação",
"loading": "Carregando. Aguarde, por favor.",
"lonely": "Não existe nada aqui.",
"loading": "Carregando...",
"lonely": "Não nada aqui...",
"metadata": "Metadados",
"multipleSelectionEnabled": "Seleção múltipla ativada",
"name": "Nome",
@@ -73,12 +80,12 @@
"click": "selecionar pasta ou arquivo",
"ctrl": {
"click": "selecionar várias pastas e arquivos",
"f": "pesquisar",
"f": "abrir pesquisa",
"s": "salvar um arquivo ou baixar a pasta que você está"
},
"del": "apagar os arquivos selecionados",
"doubleClick": "abrir pasta ou arquivo",
"esc": "limpar seleção e/ou fechar menu",
"esc": "limpar seleção e/ou fechar prompt",
"f1": "esta informação",
"f2": "renomear arquivo",
"help": "Ajuda"
@@ -123,7 +130,7 @@
"rename": "Renomear",
"renameMessage": "Insira um novo nome para",
"replace": "Substituir",
"replaceMessage": "Já existe um arquivo com nome igual a um dos que está tentando enviar. Deseja substituir?\n",
"replaceMessage": "Um dos arquivos que você está tentando enviar possui um nome conflitante. Deseja pular este arquivo e continuar o envio ou substituir o existente?\n",
"schedule": "Agendar",
"scheduleMessage": "Escolha uma data para agendar a publicação deste post.",
"show": "Mostrar",
@@ -131,7 +138,10 @@
"upload": "Enviar",
"uploadFiles": "Enviando {files} arquivos...",
"uploadMessage": "Selecione uma opção para enviar.",
"optionalPassword": "Senha opcional"
"optionalPassword": "Senha opcional",
"deleteUser": "Tem certeza de que deseja apagar este usuário?",
"resolution": "Resolução",
"discardEditorChanges": "Tem certeza de que deseja descartar as alterações feitas?"
},
"search": {
"images": "Imagens",
@@ -159,7 +169,7 @@
"commandRunner": "Execução de comandos",
"commandRunnerHelp": "Aqui você pode definir comandos que serão executados nos eventos descritos. Escreva um por linha. As variáveis de ambiente {0} e {1} estão disponíveis, sendo {0} relativo a {1}. Para mais informações sobre esta função e as variáveis de ambiente disponíveis, leia a {2}.",
"commandsUpdated": "Comandos atualizados!",
"createUserDir": "Criar diretório Home para novos usuários",
"createUserDir": "Criar diretório Home do usuário automaticamente ao adicionar novo usuário",
"userHomeBasePath": "Caminho base para diretórios de usuários",
"userScopeGenerationPlaceholder": "O escopo será gerado automaticamente",
"createUserHomeDirectory": "Criar diretório Home de usuário",
@@ -184,7 +194,7 @@
"newUser": "Novo usuário",
"password": "Senha",
"passwordUpdated": "Senha atualizada!",
"path": "",
"path": "Caminho",
"perm": {
"create": "Criar arquivos e diretórios",
"delete": "Apagar arquivos e diretórios",
@@ -209,6 +219,7 @@
"shareDeleted": "Compartilhamento apagado!",
"singleClick": "Usar clique único para abrir arquivos e diretórios",
"themes": {
"default": "Padrão do sistema",
"dark": "Escuro",
"light": "Claro",
"title": "Tema"
@@ -229,7 +240,7 @@
"hugoNew": "Hugo New",
"login": "Login",
"logout": "Sair",
"myFiles": "Arquivos",
"myFiles": "Meus arquivos",
"newFile": "Novo arquivo",
"newFolder": "Nova pasta",
"preview": "Pré-visualizar",
@@ -245,6 +256,6 @@
"hours": "Horas",
"minutes": "Minutos",
"seconds": "Segundos",
"unit": "Unidades de Tempo"
"unit": "Unidade de tempo"
}
}

View File

@@ -3,14 +3,17 @@
"cancel": "Отмена",
"clear": "Очистить",
"close": "Закрыть",
"continue": "Продолжить",
"copy": "Копировать",
"copyFile": "Скопировать файл",
"copyToClipboard": "Скопировать в буфер",
"copyDownloadLinkToClipboard": "Скопировать ссылку в буфер",
"create": "Создать",
"delete": "Удалить",
"download": "Скачать",
"file": "Файл",
"folder": "Папка",
"fullScreen": " Развернуть на весь экран",
"hideDotfiles": "Скрыть точечные файлы",
"info": "Инфо",
"more": "Еще",
@@ -21,6 +24,7 @@
"ok": "OK",
"permalink": "Получить постоянную ссылку",
"previous": "Назад",
"preview": "Предпросмотр",
"publish": "Опубликовать",
"rename": "Переименовать",
"replace": "Перезаписать",
@@ -37,13 +41,17 @@
"toggleSidebar": "Боковая панель",
"update": "Обновить",
"upload": "Загрузить",
"openFile": "Открыть файл"
"openFile": "Открыть файл",
"discardChanges": "Отказаться"
},
"download": {
"downloadFile": "Скачать файл",
"downloadFolder": "Загрузить папку",
"downloadSelected": "Скачать выбранное"
},
"upload": {
"abortUpload": "Вы действительно, что хотите прервать операцию?"
},
"errors": {
"forbidden": "У вас нет прав доступа к этому.",
"internal": "Что-то пошло не так.",
@@ -72,7 +80,7 @@
"click": "выбрать файл или каталог",
"ctrl": {
"click": "выбрать несколько файлов или каталогов",
"f": "открыть поиск",
"f": "открытые поиски",
"s": "скачать файл или текущий каталог"
},
"del": "удалить выбранные элементы",
@@ -102,6 +110,7 @@
"deleteMessageMultiple": "Удалить эти файлы ({count})?",
"deleteMessageSingle": "Удалить этот файл/каталог?",
"deleteMessageShare": "Удалить этот общий файл/каталог ({path})?",
"deleteUser": "Вы действительно, хотите удалить пользователя?",
"deleteTitle": "Удалить файлы",
"displayName": "Отображаемое имя:",
"download": "Скачать файлы",
@@ -111,7 +120,7 @@
"filesSelected": "Файлов выбрано: {count}.",
"lastModified": "Последнее изменение",
"move": "Переместить",
"moveMessage": "Переместить в:",
"moveMessage": "Выберите новый домашний каталог для ваших файлов/папок:",
"newArchetype": "Создайте новую запись на основе архетипа. Файл будет создан в каталоге.",
"newDir": "Новый каталог",
"newDirMessage": "Имя нового каталога.",
@@ -128,8 +137,11 @@
"show": "Показать",
"size": "Размер",
"upload": "Загрузить",
"uploadFiles": "Загружаю {files} файлы...",
"uploadMessage": "Выберите вариант для загрузки.",
"optionalPassword": "Необязательный пароль"
"optionalPassword": "Необязательный пароль",
"resolution": "Разрешение",
"discardEditorChanges": "Вы действительно желаете отменить ваши правки?"
},
"search": {
"images": "Изображения",
@@ -158,6 +170,13 @@
"commandRunnerHelp": "Здесь вы можете установить команды, которые будут выполняться в указанных событиях. Вы должны указать по одной команде в каждой строке. Переменные среды {0} и {1} будут доступны, будучи {0} относительно {1}. Дополнительные сведения об этой функции и доступных переменных среды см. В {2}.",
"commandsUpdated": "Команды обновлены!",
"createUserDir": "Автоматическое создание домашнего каталога пользователя при добавлении нового пользователя",
"tusUploads": "Загруженные файлы",
"tusUploadsHelp": " File Browser поддерживает загрузку файлов по частям, что позволяет работать в сетях низкого качества.",
"tusUploadsChunkSize": "Указывает максимальный размер запроса (мелкие загрузки пойдут напрямую). Вы можете ввести простое целое число, обозначающее размер ввода в байтах, или строку, например 10MB, 1GB и т. д.",
"tusUploadsRetryCount": "Количество повторных попыток, которые необходимо выполнить, если фрагмент не удалось загрузить.",
"userHomeBasePath": "Путь к домашнему каталогу пользователя",
"userScopeGenerationPlaceholder": "Область действия будет сгенерирована автоматически",
"createUserHomeDirectory": "Создать домашний каталог пользователя",
"customStylesheet": "Свой стиль",
"defaultUserDescription": "Это настройки по умолчанию для новых пользователей.",
"disableExternalLinks": "Отключить внешние ссылки (кроме документации)",
@@ -196,7 +215,7 @@
"ruleExample2": "блокирует доступ к файлу с именем Caddyfile в корневой области.",
"rules": "Права",
"rulesHelp": "Здесь вы можете определить набор разрешающих и запрещающих правил для этого конкретного пользователь. Блокированные файлы не будут отображаться в списках, и не будут доступны для пользователя. Есть поддержка регулярных выражений и относительных путей.\n",
"scope": "Корень",
"scope": "Область",
"setDateFormat": "Установить точный формат даты",
"settingsUpdated": "Настройки применены!",
"shareDuration": "Время расшаренной ссылки",
@@ -204,6 +223,7 @@
"shareDeleted": "Расшаренная ссылка удалена!",
"singleClick": "Открытие файлов и каталогов одним кликом",
"themes": {
"default": " Системные настройки по умолчанию",
"dark": "Темная",
"light": "Светлая",
"title": "Тема"

265
frontend/src/i18n/vi.json Normal file
View File

@@ -0,0 +1,265 @@
{
"buttons": {
"cancel": "Hủy",
"clear": "Xóa",
"close": "Đóng",
"continue": "Tiếp tục",
"copy": "Sao chép",
"copyFile": "Sao chép tập tin",
"copyToClipboard": "Sao chép vào clipboard",
"copyDownloadLinkToClipboard": "Sao chép liên kết tải xuống vào clipboard",
"create": "Tạo",
"delete": "Xóa",
"download": "Tải xuống",
"file": "Tập tin",
"folder": "Thư mục",
"fullScreen": "Toàn màn hình",
"hideDotfiles": "Ẩn tập tin ẩn",
"info": "Thông tin",
"more": "Thêm",
"move": "Di chuyển",
"moveFile": "Di chuyển tập tin",
"new": "Mới",
"next": "Tiếp theo",
"ok": "OK",
"permalink": "Lấy liên kết vĩnh viễn",
"previous": "Trước",
"preview": "Xem trước",
"publish": "Xuất bản",
"rename": "Đổi tên",
"replace": "Thay thế",
"reportIssue": "Báo cáo sự cố",
"save": "Lưu",
"schedule": "Lên lịch",
"search": "Tìm kiếm",
"select": "Chọn",
"selectMultiple": "Chọn nhiều",
"share": "Chia sẻ",
"shell": "Chuyển đổi shell",
"submit": "Gửi",
"switchView": "Chuyển chế độ xem",
"toggleSidebar": "Thanh bên",
"update": "Cập nhật",
"upload": "Tải lên",
"openFile": "Mở tệp",
"discardChanges": "Hủy bỏ thay đổi"
},
"download": {
"downloadFile": "Tải xuống tệp tin",
"downloadFolder": "Tải xuống thư mục",
"downloadSelected": "Tải xuống đã chọn"
},
"upload": {
"abortUpload": "Bạn có chắc chắn muốn hủy tải lên không?"
},
"errors": {
"forbidden": "Bạn không có quyền truy cập vào nội dung này.",
"internal": "Đã xảy ra lỗi nghiêm trọng.",
"notFound": "Không thể truy cập vị trí này.",
"connection": "Không thể kết nối đến máy chủ."
},
"files": {
"body": "Nội dung",
"closePreview": "Đóng xem trước",
"files": "Tập tin",
"folders": "Thư mục",
"home": "Trang chủ",
"lastModified": "Sửa đổi lần cuối",
"loading": "Đang tải...",
"lonely": "Không có gì ở đây...",
"metadata": "Siêu dữ liệu",
"multipleSelectionEnabled": "Đã bật chọn nhiều",
"name": "Tên",
"size": "Kích thước",
"sortByLastModified": "Sắp xếp theo ngày sửa đổi",
"sortByName": "Sắp xếp theo tên",
"sortBySize": "Sắp xếp theo kích thước",
"noPreview": "Không có bản xem trước cho tập tin này."
},
"help": {
"click": "chọn tập tin hoặc thư mục",
"ctrl": {
"click": "chọn nhiều tập tin hoặc thư mục",
"f": "mở tìm kiếm",
"s": "lưu tập tin hoặc tải thư mục hiện tại"
},
"del": "xóa các mục đã chọn",
"doubleClick": "mở tập tin hoặc thư mục",
"esc": "hủy chọn và/hoặc đóng hộp thoại",
"f1": "mở trợ giúp này",
"f2": "đổi tên tập tin",
"help": "Trợ giúp"
},
"login": {
"createAnAccount": "Tạo tài khoản",
"loginInstead": "Đã có tài khoản",
"password": "Mật khẩu",
"passwordConfirm": "Xác nhận mật khẩu",
"passwordsDontMatch": "Mật khẩu không khớp",
"signup": "Đăng ký",
"submit": "Đăng nhập",
"username": "Tên người dùng",
"usernameTaken": "Tên người dùng đã tồn tại",
"wrongCredentials": "Thông tin đăng nhập không đúng"
},
"permanent": "Vĩnh viễn",
"prompts": {
"copy": "Sao chép",
"copyMessage": "Chọn vị trí để sao chép tệp của bạn:",
"currentlyNavigating": "Đang điều hướng tại:",
"deleteMessageMultiple": "Bạn có chắc chắn muốn xóa {count} tệp không?",
"deleteMessageSingle": "Bạn có chắc chắn muốn xóa tệp/thư mục này không?",
"deleteMessageShare": "Bạn có chắc chắn muốn xóa chia sẻ này ({path}) không?",
"deleteUser": "Bạn có chắc chắn muốn xóa người dùng này không?",
"deleteTitle": "Xóa tệp",
"displayName": "Tên hiển thị:",
"download": "Tải xuống tệp",
"downloadMessage": "Chọn định dạng bạn muốn tải xuống.",
"error": "Đã xảy ra lỗi",
"fileInfo": "Thông tin tệp",
"filesSelected": "{count} tệp đã được chọn.",
"lastModified": "Chỉnh sửa lần cuối",
"move": "Di chuyển",
"moveMessage": "Chọn vị trí mới cho tệp/thư mục của bạn:",
"newArchetype": "Tạo một bài viết mới dựa trên nguyên mẫu. Tệp của bạn sẽ được tạo trong thư mục nội dung.",
"newDir": "Thư mục mới",
"newDirMessage": "Đặt tên cho thư mục mới của bạn.",
"newFile": "Tệp mới",
"newFileMessage": "Đặt tên cho tệp mới của bạn.",
"numberDirs": "Số lượng thư mục",
"numberFiles": "Số lượng tệp",
"rename": "Đổi tên",
"renameMessage": "Nhập tên mới cho",
"replace": "Thay thế",
"replaceMessage": "Một trong những tệp bạn đang cố tải lên có tên trùng lặp. Bạn có muốn bỏ qua tệp này và tiếp tục tải lên hay thay thế tệp hiện có?\n",
"schedule": "Lên lịch",
"scheduleMessage": "Chọn ngày và giờ để lên lịch xuất bản bài viết này.",
"show": "Hiển thị",
"size": "Kích thước",
"upload": "Tải lên",
"uploadFiles": "Đang tải lên {files} tệp...",
"uploadMessage": "Chọn một tùy chọn để tải lên.",
"optionalPassword": "Mật khẩu tùy chọn",
"resolution": "Độ phân giải",
"discardEditorChanges": "Bạn có chắc chắn muốn hủy bỏ các thay đổi đã thực hiện không?"
},
"search": {
"images": "Hình ảnh",
"music": "Nhạc",
"pdf": "PDF",
"pressToSearch": "Nhấn Enter để tìm kiếm...",
"search": "Tìm kiếm...",
"typeToSearch": "Nhập để tìm kiếm...",
"types": "Loại",
"video": "Video"
},
"settings": {
"admin": "Quản trị viên",
"administrator": "Người quản trị",
"allowCommands": "Thực thi lệnh",
"allowEdit": "Chỉnh sửa, đổi tên và xóa tệp hoặc thư mục",
"allowNew": "Tạo tệp và thư mục mới",
"allowPublish": "Xuất bản bài viết và trang mới",
"allowSignup": "Cho phép người dùng đăng ký",
"avoidChanges": "(để trống để tránh thay đổi)",
"branding": "Thương hiệu",
"brandingDirectoryPath": "Đường dẫn thư mục thương hiệu",
"brandingHelp": "Bạn có thể tùy chỉnh giao diện và trải nghiệm của File Browser bằng cách thay đổi tên, thay thế logo, thêm kiểu tùy chỉnh và thậm chí vô hiệu hóa các liên kết bên ngoài đến GitHub.\nĐể biết thêm thông tin về tùy chỉnh thương hiệu, vui lòng xem {0}.",
"changePassword": "Đổi mật khẩu",
"commandRunner": "Trình chạy lệnh",
"commandRunnerHelp": "Tại đây, bạn có thể thiết lập các lệnh được thực thi trong các sự kiện đã định. Bạn phải viết một lệnh trên mỗi dòng. Các biến môi trường {0} và {1} sẽ có sẵn, trong đó {0} tương đối với {1}. Để biết thêm thông tin về tính năng này và các biến môi trường có sẵn, vui lòng đọc {2}.",
"commandsUpdated": "Lệnh đã được cập nhật!",
"createUserDir": "Tự động tạo thư mục chính của người dùng khi thêm người dùng mới",
"tusUploads": "Tải lên theo phân đoạn",
"tusUploadsHelp": "File Browser hỗ trợ tải lên tệp theo phân đoạn, giúp việc tải lên trở nên hiệu quả, đáng tin cậy, có thể tiếp tục và phù hợp với mạng không ổn định.",
"tusUploadsChunkSize": "Kích thước tối đa của một yêu cầu (tải lên trực tiếp sẽ được sử dụng cho các tệp nhỏ hơn). Bạn có thể nhập một số nguyên biểu thị kích thước theo byte hoặc một chuỗi như 10MB, 1GB, v.v.",
"tusUploadsRetryCount": "Số lần thử lại nếu một phân đoạn tải lên thất bại.",
"userHomeBasePath": "Đường dẫn cơ bản của thư mục chính người dùng",
"userScopeGenerationPlaceholder": "Phạm vi sẽ được tạo tự động",
"createUserHomeDirectory": "Tạo thư mục chính của người dùng",
"customStylesheet": "Bảng định dạng tùy chỉnh",
"defaultUserDescription": "Đây là cài đặt mặc định cho người dùng mới.",
"disableExternalLinks": "Vô hiệu hóa các liên kết bên ngoài (trừ tài liệu)",
"disableUsedDiskPercentage": "Vô hiệu hóa biểu đồ phần trăm dung lượng đã sử dụng",
"documentation": "tài liệu",
"examples": "Ví dụ",
"executeOnShell": "Thực thi trên shell",
"executeOnShellDescription": "Theo mặc định, File Browser thực thi lệnh bằng cách gọi trực tiếp các tệp nhị phân của chúng. Nếu bạn muốn chạy chúng trên shell (chẳng hạn như Bash hoặc PowerShell), bạn có thể định nghĩa tại đây cùng với các tham số và cờ cần thiết. Nếu được đặt, lệnh bạn thực thi sẽ được thêm làm đối số. Điều này áp dụng cho cả lệnh người dùng và hook sự kiện.",
"globalRules": "Đây là tập hợp quy tắc chung về quyền cho phép và từ chối. Chúng áp dụng cho mọi người dùng. Bạn có thể đặt quy tắc riêng cho từng người dùng để ghi đè các quy tắc chung này.",
"globalSettings": "Cài đặt chung",
"hideDotfiles": "Ẩn tệp ẩn (dotfiles)",
"insertPath": "Nhập đường dẫn",
"insertRegex": "Nhập biểu thức regex",
"instanceName": "Tên phiên bản",
"language": "Ngôn ngữ",
"lockPassword": "Ngăn người dùng thay đổi mật khẩu",
"newPassword": "Mật khẩu mới của bạn",
"newPasswordConfirm": "Xác nhận mật khẩu mới",
"newUser": "Người dùng mới",
"password": "Mật khẩu",
"passwordUpdated": "Mật khẩu đã được cập nhật!",
"path": "Đường dẫn",
"perm": {
"create": "Tạo tệp và thư mục",
"delete": "Xóa tệp và thư mục",
"download": "Tải xuống",
"execute": "Thực thi lệnh",
"modify": "Chỉnh sửa tệp",
"rename": "Đổi tên hoặc di chuyển tệp và thư mục",
"share": "Chia sẻ tệp"
},
"permissions": "Quyền",
"permissionsHelp": "Bạn có thể đặt người dùng làm quản trị viên hoặc chọn quyền riêng lẻ. Nếu chọn \"Người quản trị\", tất cả các tùy chọn khác sẽ tự động được chọn. Việc quản lý người dùng vẫn là đặc quyền của quản trị viên.\n",
"profileSettings": "Cài đặt hồ sơ",
"ruleExample1": "ngăn truy cập vào bất kỳ tệp ẩn nào (chẳng hạn như .git, .gitignore) trong mọi thư mục.\n",
"ruleExample2": "chặn truy cập vào tệp có tên Caddyfile trong thư mục gốc của phạm vi.",
"rules": "Quy tắc",
"rulesHelp": "Tại đây, bạn có thể xác định một tập hợp quy tắc cho phép hoặc từ chối cho người dùng cụ thể này. Các tệp bị chặn sẽ không hiển thị trong danh sách và người dùng không thể truy cập chúng. Chúng tôi hỗ trợ regex và đường dẫn tương đối với phạm vi của người dùng.\n",
"scope": "Phạm vi",
"setDateFormat": "Đặt định dạng ngày chính xác",
"settingsUpdated": "Cài đặt đã được cập nhật!",
"shareDuration": "Thời gian chia sẻ",
"shareManagement": "Quản lý chia sẻ",
"shareDeleted": "Chia sẻ đã bị xóa!",
"singleClick": "Dùng một lần nhấp để mở tệp và thư mục",
"themes": {
"default": "Mặc định hệ thống",
"dark": "Tối",
"light": "Sáng",
"title": "Chủ đề"
},
"user": "Người dùng",
"userCommands": "Lệnh",
"userCommandsHelp": "Danh sách lệnh được phân tách bằng khoảng trắng dành cho người dùng này. Ví dụ:\n",
"userCreated": "Người dùng đã được tạo!",
"userDefaults": "Cài đặt mặc định của người dùng",
"userDeleted": "Người dùng đã bị xóa!",
"userManagement": "Quản lý người dùng",
"userUpdated": "Người dùng đã được cập nhật!",
"username": "Tên người dùng",
"users": "Người dùng"
},
"sidebar": {
"help": "Trợ giúp",
"hugoNew": "Hugo New",
"login": "Đăng nhập",
"logout": "Đăng xuất",
"myFiles": "Tập tin của tôi",
"newFile": "Tập tin mới",
"newFolder": "Thư mục mới",
"preview": "Xem trước",
"settings": "Cài đặt",
"signup": "Đăng ký",
"siteSettings": "Cài đặt trang"
},
"success": {
"linkCopied": "Liên kết đã được sao chép!"
},
"time": {
"days": "Ngày",
"hours": "Giờ",
"minutes": "Phút",
"seconds": "Giây",
"unit": "Đơn vị"
}
}

View File

@@ -4,7 +4,7 @@ import VueNumberInput from "@chenfengyuan/vue-number-input";
import VueLazyload from "vue-lazyload";
import { createVfm } from "vue-final-modal";
import Toast, { POSITION, useToast } from "vue-toastification";
import {
import type {
ToastOptions,
PluginOptions,
} from "vue-toastification/dist/types/types";

View File

@@ -1,4 +1,5 @@
import { RouteLocation, createRouter, createWebHistory } from "vue-router";
import type { RouteLocation } from "vue-router";
import { createRouter, createWebHistory } from "vue-router";
import Login from "@/views/Login.vue";
import Layout from "@/views/Layout.vue";
import Files from "@/views/Files.vue";

View File

@@ -1,6 +1,6 @@
import { createPinia as _createPinia } from "pinia";
import { markRaw } from "vue";
import { Router } from "vue-router";
import type { Router } from "vue-router";
export default function createPinia(router: Router) {
const pinia = _createPinia();

View File

@@ -29,6 +29,12 @@ export const useLayoutStore = defineStore("layout", {
toggleShell() {
this.showShell = !this.showShell;
},
setCloseOnPrompt(closeFunction: () => Promise<string>, onPrompt: string) {
const prompt = this.prompts.find((prompt) => prompt.prompt === onPrompt);
if (prompt) {
prompt.close = closeFunction;
}
},
showHover(value: PopupProps | string) {
if (typeof value !== "object") {
this.prompts.push({
@@ -36,6 +42,7 @@ export const useLayoutStore = defineStore("layout", {
confirm: null,
action: undefined,
props: null,
close: null,
});
return;
}
@@ -45,6 +52,7 @@ export const useLayoutStore = defineStore("layout", {
confirm: value?.confirm,
action: value?.action,
props: value?.props,
close: value?.close,
});
},
showError() {
@@ -53,6 +61,7 @@ export const useLayoutStore = defineStore("layout", {
confirm: null,
action: undefined,
props: null,
close: null,
});
},
showSuccess() {
@@ -61,10 +70,11 @@ export const useLayoutStore = defineStore("layout", {
confirm: null,
action: undefined,
props: null,
close: null,
});
},
closeHovers() {
this.prompts.pop();
this.prompts.shift()?.close?.();
},
// easily reset state using `$reset`
clearLayout() {

View File

@@ -1,7 +1,7 @@
import { defineStore } from "pinia";
import { useFileStore } from "./file";
import { files as api } from "@/api";
import throttle from "lodash/throttle";
import { throttle } from "lodash-es";
import buttons from "@/utils/buttons";
// TODO: make this into a user setting

View File

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

View File

@@ -1,6 +1,7 @@
import { useAuthStore } from "@/stores/auth";
import router from "@/router";
import { JwtPayload, jwtDecode } from "jwt-decode";
import type { JwtPayload } from "jwt-decode";
import { jwtDecode } from "jwt-decode";
import { baseURL, noAuth } from "./constants";
import { StatusError } from "@/api/utils";
@@ -23,7 +24,7 @@ export async function validateLogin() {
await renew(<string>localStorage.getItem("jwt"));
}
} catch (error) {
console.warn("Invalid JWT token in storage"); // eslint-disable-line
console.warn("Invalid JWT token in storage");
throw error;
}
}

View File

@@ -4,7 +4,7 @@ function loading(button: string) {
);
if (el === undefined || el === null) {
console.log("Error getting button " + button); // eslint-disable-line
console.log("Error getting button " + button);
return;
}
@@ -30,7 +30,7 @@ function done(button: string) {
);
if (el === undefined || el === null) {
console.log("Error getting button " + button); // eslint-disable-line
console.log("Error getting button " + button);
return;
}
@@ -51,7 +51,7 @@ function success(button: string) {
);
if (el === undefined || el === null) {
console.log("Error getting button " + button); // eslint-disable-line
console.log("Error getting button " + button);
return;
}

View File

@@ -1,39 +1,36 @@
// Based on code by the following links:
// https://stackoverflow.com/a/74528564
// https://web.dev/articles/async-clipboard
export function copy(text: string) {
interface ClipboardArgs {
text?: string;
data?: ClipboardItems;
}
interface ClipboardOpts {
permission?: boolean;
}
export function copy(data: ClipboardArgs, opts?: ClipboardOpts) {
return new Promise<void>((resolve, reject) => {
if (
// Clipboard API requires secure context
window.isSecureContext &&
typeof navigator.clipboard !== "undefined" &&
// @ts-ignore
navigator.permissions !== "undefined"
typeof navigator.clipboard !== "undefined"
) {
navigator.permissions
// @ts-ignore
.query({ name: "clipboard-write" })
.then((permission) => {
if (permission.state === "granted" || permission.state === "prompt") {
// simple writeText should work for all modern browsers
navigator.clipboard.writeText(text).then(resolve).catch(reject);
} else {
reject(new Error("Permission not granted!"));
}
})
.catch((e) => {
// Firefox doesn't support clipboard-write permission
if (navigator.userAgent.indexOf("Firefox") != -1) {
navigator.clipboard.writeText(text).then(resolve).catch(reject);
} else {
reject(e);
}
});
if (opts?.permission) {
getPermission("clipboard-write")
.then(() => writeToClipboard(data).then(resolve).catch(reject))
.catch(reject);
} else {
writeToClipboard(data).then(resolve).catch(reject);
}
} else if (
document.queryCommandSupported &&
document.queryCommandSupported("copy")
document.queryCommandSupported("copy") &&
data.text // old method only supports text
) {
const textarea = createTemporaryTextarea(text);
const textarea = createTemporaryTextarea(data.text);
const body = document.activeElement || document.body;
try {
body.appendChild(textarea);
@@ -54,6 +51,35 @@ export function copy(text: string) {
});
}
function getPermission(name: string) {
return new Promise<void>((resolve, reject) => {
typeof navigator.permissions !== "undefined" &&
navigator.permissions
// @ts-expect-error chrome specific api
.query({ name })
.then((permission) => {
if (permission.state === "granted" || permission.state === "prompt") {
resolve();
} else {
reject(new Error("Permission denied!"));
}
});
});
}
function writeToClipboard(data: ClipboardArgs) {
if (data.text) {
return navigator.clipboard.writeText(data.text);
}
if (data.data) {
return navigator.clipboard.write(data.data);
}
return new Promise<void>((resolve, reject) => {
reject(new Error("No data was supplied!"));
});
}
const styles = {
fontSize: "12pt",
position: "fixed",
@@ -69,10 +95,10 @@ const styles = {
background: "transparent",
};
const createTemporaryTextarea = (text: string) => {
function createTemporaryTextarea(text: string) {
const textarea = document.createElement("textarea");
textarea.value = text;
textarea.setAttribute("readonly", "");
Object.assign(textarea.style, styles);
return textarea;
};
}

View File

@@ -6,13 +6,16 @@ export default function getRule(rules: string[]) {
let result = null;
const find = Array.prototype.find;
find.call(document.styleSheets, (styleSheet) => {
result = find.call(styleSheet.cssRules, (cssRule) => {
find.call(document.styleSheets, (styleSheet: CSSStyleSheet) => {
result = find.call(styleSheet.cssRules, (cssRule: CSSRule) => {
let found = false;
if (cssRule instanceof window.CSSStyleRule) {
// faster than checking instanceof for every element
if (cssRule.constructor.name === "CSSStyleRule") {
for (let i = 0; i < rules.length; i++) {
if (cssRule.selectorText.toLowerCase() === rules[i]) {
if (
(cssRule as CSSStyleRule).selectorText.toLowerCase() === rules[i]
) {
found = true;
}
}
@@ -24,5 +27,5 @@ export default function getRule(rules: string[]) {
return result != null;
});
return result;
return result as CSSStyleRule | null;
}

View File

@@ -1,3 +1,4 @@
import { useLayoutStore } from "@/stores/layout";
import { useUploadStore } from "@/stores/upload";
import url from "@/utils/url";
@@ -126,6 +127,9 @@ export function handleFiles(
overwrite = false
) {
const uploadStore = useUploadStore();
const layoutStore = useLayoutStore();
layoutStore.closeHovers();
for (const file of files) {
const id = uploadStore.id;

View File

@@ -325,6 +325,7 @@ const token = ref<string>("");
const audio = ref<HTMLAudioElement>();
const tag = ref<boolean>(false);
const $showError = inject<IToastError>("$showError")!;
const $showSuccess = inject<IToastSuccess>("$showSuccess")!;
const { t } = useI18n({});
@@ -463,9 +464,9 @@ const download = () => {
if (req.value === null) return false;
layoutStore.closeHovers();
let files: string[] = [];
const files: string[] = [];
for (let i of fileStore.selected) {
for (const i of fileStore.selected) {
files.push(req.value.items[i].path);
}
@@ -488,13 +489,23 @@ const linkSelected = () => {
};
const copyToClipboard = (text: string) => {
copy(text).then(
copy({ text }).then(
() => {
// clipboard successfully set
$showSuccess(t("success.linkCopied"));
},
() => {
// clipboard write failed
copy({ text }, { permission: true }).then(
() => {
// clipboard successfully set
$showSuccess(t("success.linkCopied"));
},
(e) => {
// clipboard write failed
$showError(e);
}
);
}
);
};

View File

@@ -108,7 +108,7 @@ onMounted(() => {
showPrintMargin: false,
readOnly: fileStore.req?.type === "textImmutable",
theme: "ace/theme/chrome",
mode: modelist.getModeForPath(fileStore.req?.name).mode,
mode: modelist.getModeForPath(fileStore.req!.name).mode,
wrap: true,
enableBasicAutocompletion: true,
enableLiveAutocompletion: true,
@@ -173,7 +173,7 @@ const close = () => {
fileStore.updateRequest(null);
let uri = url.removeLastDir(route.path) + "/";
const uri = url.removeLastDir(route.path) + "/";
router.push({ path: uri });
};

View File

@@ -285,7 +285,7 @@ import { users, files as api } from "@/api";
import { enableExec } from "@/utils/constants";
import * as upload from "@/utils/upload";
import css from "@/utils/css";
import throttle from "lodash/throttle";
import { throttle } from "lodash-es";
import { Base64 } from "js-base64";
import HeaderBar from "@/components/header/HeaderBar.vue";
@@ -511,8 +511,11 @@ const keyEvent = (event: KeyboardEvent) => {
switch (event.key) {
case "f":
event.preventDefault();
layoutStore.showHover("search");
case "F":
if (event.shiftKey) {
event.preventDefault();
layoutStore.showHover("search");
}
break;
case "c":
case "x":
@@ -523,12 +526,12 @@ const keyEvent = (event: KeyboardEvent) => {
break;
case "a":
event.preventDefault();
for (let file of items.value.files) {
for (const file of items.value.files) {
if (fileStore.selected.indexOf(file.index) === -1) {
fileStore.selected.push(file.index);
}
}
for (let dir of items.value.dirs) {
for (const dir of items.value.dirs) {
if (fileStore.selected.indexOf(dir.index) === -1) {
fileStore.selected.push(dir.index);
}
@@ -551,9 +554,9 @@ const copyCut = (event: Event | KeyboardEvent): void => {
if (fileStore.req === null) return;
let items = [];
const items = [];
for (let i of fileStore.selected) {
for (const i of fileStore.selected) {
items.push({
from: fileStore.req.items[i].url,
name: fileStore.req.items[i].name,
@@ -575,9 +578,9 @@ const paste = (event: Event) => {
if ((event.target as HTMLElement).tagName?.toLowerCase() === "input") return;
// TODO router location should it be
let items: any[] = [];
const items: any[] = [];
for (let item of clipboardStore.items) {
for (const item of clipboardStore.items) {
const from = item.from.endsWith("/") ? item.from.slice(0, -1) : item.from;
const to = route.path + encodeURIComponent(item.name);
items.push({ from, to, name: item.name });
@@ -614,7 +617,7 @@ const paste = (event: Event) => {
return;
}
let conflict = upload.checkConflict(items, fileStore.req!.items);
const conflict = upload.checkConflict(items, fileStore.req!.items);
let overwrite = false;
let rename = false;
@@ -640,14 +643,13 @@ const paste = (event: Event) => {
const colunmsResize = () => {
// Update the columns size based on the window width.
let items_ = css(["#listing.mosaic .item", ".mosaic#listing .item"]);
const items_ = css(["#listing.mosaic .item", ".mosaic#listing .item"]);
if (items_ === null) return;
let columns = Math.floor(
(document.querySelector("main")?.offsetWidth ?? 0) / columnWidth.value
);
if (columns === 0) columns = 1;
// @ts-ignore never type error
items_.style.width = `calc(${100 / columns}% - 1em)`;
};
@@ -677,11 +679,10 @@ const dragEnter = () => {
// When the user starts dragging an item, put every
// file on the listing with 50% opacity.
let items = document.getElementsByClassName("item");
const items = document.getElementsByClassName("item");
// @ts-ignore
Array.from(items).forEach((file: HTMLElement) => {
file.style.opacity = "0.5";
Array.from(items).forEach((file: Element) => {
(file as HTMLElement).style.opacity = "0.5";
});
};
@@ -698,7 +699,7 @@ const drop = async (event: DragEvent) => {
dragCounter.value = 0;
resetOpacity();
let dt = event.dataTransfer;
const dt = event.dataTransfer;
let el: HTMLElement | null = event.target as HTMLElement;
if (fileStore.req === null || dt === null || dt.files.length <= 0) return;
@@ -709,7 +710,7 @@ const drop = async (event: DragEvent) => {
}
}
let files: UploadList = (await upload.scanFiles(dt)) as UploadList;
const files: UploadList = (await upload.scanFiles(dt)) as UploadList;
let items = fileStore.req.items;
let path = route.path.endsWith("/") ? route.path : route.path + "/";
@@ -729,7 +730,7 @@ const drop = async (event: DragEvent) => {
}
}
let conflict = upload.checkConflict(files, items);
const conflict = upload.checkConflict(files, items);
if (conflict) {
layoutStore.showHover({
@@ -753,12 +754,10 @@ const drop = async (event: DragEvent) => {
};
const uploadInput = (event: Event) => {
layoutStore.closeHovers();
let files = (event.currentTarget as HTMLInputElement)?.files;
const files = (event.currentTarget as HTMLInputElement)?.files;
if (files === null) return;
let folder_upload = !!files[0].webkitRelativePath;
const folder_upload = !!files[0].webkitRelativePath;
const uploadFiles: UploadList = [];
for (let i = 0; i < files.length; i++) {
@@ -773,8 +772,8 @@ const uploadInput = (event: Event) => {
});
}
let path = route.path.endsWith("/") ? route.path : route.path + "/";
let conflict = upload.checkConflict(uploadFiles, fileStore.req!.items);
const path = route.path.endsWith("/") ? route.path : route.path + "/";
const conflict = upload.checkConflict(uploadFiles, fileStore.req!.items);
if (conflict) {
layoutStore.showHover({
@@ -798,7 +797,7 @@ const uploadInput = (event: Event) => {
};
const resetOpacity = () => {
let items = document.getElementsByClassName("item");
const items = document.getElementsByClassName("item");
Array.from(items).forEach((file: Element) => {
(file as HTMLElement).style.opacity = "1";
@@ -824,7 +823,6 @@ const sort = async (by: string) => {
try {
if (authStore.user?.id) {
// @ts-ignore
await users.update({ id: authStore.user?.id, sorting: { by, asc } }, [
"sorting",
]);
@@ -875,10 +873,10 @@ const download = () => {
confirm: (format: any) => {
layoutStore.closeHovers();
let files = [];
const files = [];
if (fileStore.selectedCount > 0 && fileStore.req !== null) {
for (let i of fileStore.selected) {
for (const i of fileStore.selected) {
files.push(fileStore.req.items[i].url);
}
} else {
@@ -901,13 +899,12 @@ const switchView = async () => {
const data = {
id: authStore.user?.id,
viewMode: modes[authStore.user?.viewMode ?? "list"] || "list",
viewMode: (modes[authStore.user?.viewMode ?? "list"] ||
"list") as ViewModeType,
};
// @ts-ignore
users.update(data, ["viewMode"]).catch($showError);
// @ts-ignore
authStore.updateUser(data);
setItemWeight();

View File

@@ -168,7 +168,7 @@ import { files as api } from "@/api";
import { createURL } from "@/api/utils";
import { resizePreview } from "@/utils/constants";
import url from "@/utils/url";
import throttle from "lodash/throttle";
import { throttle } from "lodash-es";
import HeaderBar from "@/components/header/HeaderBar.vue";
import Action from "@/components/header/Action.vue";
import ExtendedImage from "@/components/files/ExtendedImage.vue";
@@ -253,7 +253,7 @@ const hasPrevious = computed(() => previousLink.value !== "");
const hasNext = computed(() => nextLink.value !== "");
const downloadUrl = computed(() =>
fileStore.req ? api.getDownloadURL(fileStore.req, true) : ""
fileStore.req ? api.getDownloadURL(fileStore.req, false) : ""
);
const raw = computed(() => {
@@ -262,7 +262,7 @@ const raw = computed(() => {
}
if (isEpub.value) {
return createURL("api/raw" + fileStore.req?.path, {}, false);
return createURL("api/raw" + fileStore.req?.path, {});
}
return downloadUrl.value;
@@ -353,7 +353,7 @@ const updatePreview = async () => {
autoPlay.value = false;
}
let dirs = route.fullPath.split("/");
const dirs = route.fullPath.split("/");
name.value = decodeURIComponent(dirs[dirs.length - 1]);
if (!listing.value) {
@@ -422,7 +422,7 @@ const toggleNavigation = throttle(function () {
const close = () => {
fileStore.updateRequest(null);
let uri = url.removeLastDir(route.path) + "/";
const uri = url.removeLastDir(route.path) + "/";
router.push({ path: uri });
};

View File

@@ -53,7 +53,7 @@
<a
class="link"
target="_blank"
href="https://filebrowser.org/configuration/custom-branding"
href="https://github.com/filebrowser/filebrowser/blob/master/docs/configuration.md#custom-branding"
>{{ t("settings.documentation") }}</a
>
</i18n-t>
@@ -192,7 +192,7 @@
<a
class="link"
target="_blank"
href="https://filebrowser.org/configuration/command-runner"
href="https://github.com/filebrowser/filebrowser/blob/master/docs/configuration.md#command-runner"
>{{ t("settings.documentation") }}</a
>
</i18n-t>
@@ -282,7 +282,7 @@ const formattedChunkSize = computed({
// Define funcs
const capitalize = (name: string, where: string | RegExp = "_") => {
if (where === "caps") where = /(?=[A-Z])/;
let split = name.split(where);
const split = name.split(where);
name = "";
for (let i = 0; i < split.length; i++) {
@@ -294,7 +294,7 @@ const capitalize = (name: string, where: string | RegExp = "_") => {
const save = async () => {
if (settings.value === null) return false;
let newSettings: ISettings = {
const newSettings: ISettings = {
...settings.value,
shell:
settings.value?.shell
@@ -376,7 +376,7 @@ onMounted(async () => {
try {
layoutStore.loading = true;
const original: ISettings = await api.get();
let newSettings: ISettings = { ...original, commands: {} };
const newSettings: ISettings = { ...original, commands: {} };
const keys = Object.keys(original.commands) as Array<keyof SettingsCommand>;
for (const key of keys) {

View File

@@ -87,12 +87,12 @@ onMounted(async () => {
layoutStore.loading = true;
try {
let newLinks = await api.list();
const newLinks = await api.list();
if (authStore.user?.perm.admin) {
let userMap = new Map<number, string>();
for (let user of await users.getAll())
const userMap = new Map<number, string>();
for (const user of await users.getAll())
userMap.set(user.id, user.username);
for (let link of newLinks) {
for (const link of newLinks) {
if (link.userID && userMap.has(link.userID))
link.username = userMap.get(link.userID);
}
@@ -108,13 +108,23 @@ onMounted(async () => {
});
const copyToClipboard = (text: string) => {
copy(text).then(
copy({ text }).then(
() => {
// clipboard successfully set
$showSuccess(t("success.linkCopied"));
},
() => {
// clipboard write failed
copy({ text }, { permission: true }).then(
() => {
// clipboard successfully set
$showSuccess(t("success.linkCopied"));
},
(e) => {
// clipboard write failed
$showError(e);
}
);
}
);
};

View File

@@ -90,7 +90,7 @@ const fetchData = async () => {
try {
if (isNew.value) {
let { defaults, createUserDir: _createUserDir } = await settings.get();
const { defaults, createUserDir: _createUserDir } = await settings.get();
createUserDir.value = _createUserDir;
user.value = {
...defaults,

View File

@@ -0,0 +1,13 @@
{
"extends": "@vue/tsconfig/tsconfig.dom.json",
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
"exclude": ["src/**/__tests__/*"],
"compilerOptions": {
"composite": true,
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"types": ["vite/client", "@intlify/unplugin-vue-i18n/messages"],
"paths": {
"@/*": ["./src/*"]
}
}
}

View File

@@ -1,24 +1,11 @@
{
"compilerOptions": {
"baseUrl": ".",
"allowJs": true,
"target": "ESNext",
"useDefineForClassFields": true,
"module": "ESNext",
"moduleResolution": "Node10",
"strict": true,
"sourceMap": true,
"noImplicitReturns": true,
"resolveJsonModule": true,
"isolatedModules": true,
"esModuleInterop": true,
"lib": ["ESNext", "DOM"],
"skipLibCheck": true,
"types": ["vite/client", "@intlify/unplugin-vue-i18n/messages"],
"paths": {
"@/*": ["./src/*"]
"files": [],
"references": [
{
"path": "./tsconfig.node.json"
},
{
"path": "./tsconfig.app.json"
}
},
"include": ["src/**/*.ts", "src/**/*.vue"],
"exclude": ["node_modules", "dist"]
]
}

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