Compare commits
157 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e1f658633d | ||
|
|
9c79105c02 | ||
|
|
6d5ceae8b4 | ||
|
|
381f09087a | ||
|
|
426b38bb33 | ||
|
|
488d98045e | ||
|
|
7955e0720b | ||
|
|
e017a19985 | ||
|
|
f8df76f526 | ||
|
|
11ebaec5f0 | ||
|
|
326b35a7ac | ||
|
|
5bf15548d0 | ||
|
|
6a734c0139 | ||
|
|
81b6f4d6f6 | ||
|
|
0b92d94570 | ||
|
|
fc5506179a | ||
|
|
0fe34ad224 | ||
|
|
54f35701a2 | ||
|
|
a809404ce1 | ||
|
|
fb32e44b47 | ||
|
|
e9c0369062 | ||
|
|
7358b3fe31 | ||
|
|
2a1f759e9e | ||
|
|
2fccb8c367 | ||
|
|
e039d95192 | ||
|
|
0f96031d6f | ||
|
|
6214fc84fa | ||
|
|
47578e02e3 | ||
|
|
35a4379b67 | ||
|
|
23f84642e6 | ||
|
|
edb9e85efd | ||
|
|
2d2c598fa6 | ||
|
|
cf4836dc75 | ||
|
|
d8306559fd | ||
|
|
e8c9d1c539 | ||
|
|
d8f415f8ab | ||
|
|
7b6579ac8a | ||
|
|
057307181e | ||
|
|
4fb832c042 | ||
|
|
e503cb69f2 | ||
|
|
95811e99bc | ||
|
|
62fff5ca60 | ||
|
|
5b28aa0848 | ||
|
|
db5aad8eb6 | ||
|
|
977ec33918 | ||
|
|
1819377897 | ||
|
|
f1b7bd59f6 | ||
|
|
f3afd5cb79 | ||
|
|
e6a5bf116e | ||
|
|
21b5a76fa7 | ||
|
|
b6263eb607 | ||
|
|
c8257e848e | ||
|
|
05bb7c8553 | ||
|
|
b600b11415 | ||
|
|
019ce80fc5 | ||
|
|
8cea2f75b3 | ||
|
|
6914063853 | ||
|
|
43e0d4a856 | ||
|
|
066d8e8d6c | ||
|
|
948e05c083 | ||
|
|
fb5b28d9cb | ||
|
|
677bce376b | ||
|
|
8faa96f5e6 | ||
|
|
f62806f6c9 | ||
|
|
58835b7e53 | ||
|
|
7a5298a755 | ||
|
|
bc4a6462ce | ||
|
|
ac3673e111 | ||
|
|
c746c1931d | ||
|
|
586d198d47 | ||
|
|
9515ceeb42 | ||
|
|
e8b4e9af46 | ||
|
|
10e399b3c3 | ||
|
|
dcbc3286e2 | ||
|
|
b185f9b56e | ||
|
|
7096b3dab9 | ||
|
|
36cacdf598 | ||
|
|
4e48ffc14d | ||
|
|
e119bc55ea | ||
|
|
1ce3068a99 | ||
|
|
d562d1a60d | ||
|
|
9f858398ab | ||
|
|
0ac80e8387 | ||
|
|
0dca0b92d1 | ||
|
|
c9b36ba32e | ||
|
|
f2c4e78381 | ||
|
|
05bff54b71 | ||
|
|
2bd163d92a | ||
|
|
5e27ba5c8c | ||
|
|
5aaeb3b76d | ||
|
|
36fb9f562a | ||
|
|
ad99bf1801 | ||
|
|
4c2a094255 | ||
|
|
97693cc611 | ||
|
|
c6d4fcd08f | ||
|
|
dd7b9ddd85 | ||
|
|
26d62e4117 | ||
|
|
babd7783af | ||
|
|
1529e796df | ||
|
|
d4b904b92b | ||
|
|
12d4177823 | ||
|
|
8142b32f38 | ||
|
|
c5abbb4e1c | ||
|
|
65ac73414f | ||
|
|
ede4213c8e | ||
|
|
b60d291490 | ||
|
|
b9ede79888 | ||
|
|
3d2cb838d1 | ||
|
|
778734419d | ||
|
|
be8683f556 | ||
|
|
c3450f4614 | ||
|
|
5881bc9ab0 | ||
|
|
a2fb499a20 | ||
|
|
411a928fea | ||
|
|
f5d02cdde9 | ||
|
|
c9340af8d0 | ||
|
|
a722bcc13f | ||
|
|
77fe3cfc60 | ||
|
|
470f93cefc | ||
|
|
92fde4dd12 | ||
|
|
95bc92955f | ||
|
|
f2f914221c | ||
|
|
c2d8038c63 | ||
|
|
cb8ac5ebf1 | ||
|
|
aa78e3ab1f | ||
|
|
bc00165094 | ||
|
|
94ef59602f | ||
|
|
14e2f84ceb | ||
|
|
f228fa5540 | ||
|
|
f2d2c1cbf8 | ||
|
|
d9be370e24 | ||
|
|
727c63b98e | ||
|
|
34dfb49b71 | ||
|
|
0b0a704d44 | ||
|
|
2d99d0bf13 | ||
|
|
1790df2090 | ||
|
|
10570ade44 | ||
|
|
43526d9d1a | ||
|
|
2636f876ab | ||
|
|
eed9da1471 | ||
|
|
9a2ebbabe2 | ||
|
|
716396a726 | ||
|
|
0727496601 | ||
|
|
194030fcfc | ||
|
|
b3b644527d | ||
|
|
7e5beeff46 | ||
|
|
a47b69bcec | ||
|
|
6ec6a23861 | ||
|
|
c9cc0d3d5d | ||
|
|
28d2b35718 | ||
|
|
b4f131be50 | ||
|
|
d0b359561f | ||
|
|
453636dfe2 | ||
|
|
b1605aa6d3 | ||
|
|
23503b80a4 | ||
|
|
0d69fbd9a3 | ||
|
|
0d665e528f |
@@ -1,79 +0,0 @@
|
|||||||
version: 2
|
|
||||||
jobs:
|
|
||||||
lint:
|
|
||||||
docker:
|
|
||||||
- image: golangci/golangci-lint:v1.27.0
|
|
||||||
steps:
|
|
||||||
- checkout
|
|
||||||
- run: golangci-lint run -v
|
|
||||||
build-node:
|
|
||||||
docker:
|
|
||||||
- image: circleci/node
|
|
||||||
steps:
|
|
||||||
- checkout
|
|
||||||
- run:
|
|
||||||
name: "Build"
|
|
||||||
command: ./wizard.sh -a
|
|
||||||
- run:
|
|
||||||
name: "Cleanup"
|
|
||||||
command: rm -rf frontend/node_modules
|
|
||||||
- persist_to_workspace:
|
|
||||||
root: .
|
|
||||||
paths:
|
|
||||||
- '*'
|
|
||||||
build-go:
|
|
||||||
docker:
|
|
||||||
- image: circleci/golang:1.14.3
|
|
||||||
steps:
|
|
||||||
- attach_workspace:
|
|
||||||
at: '~/project'
|
|
||||||
- run:
|
|
||||||
name: "Compile"
|
|
||||||
command: GOOS=linux GOARCH=amd64 ./wizard.sh -c
|
|
||||||
- run:
|
|
||||||
name: "Cleanup"
|
|
||||||
command: |
|
|
||||||
rm -rf frontend/build
|
|
||||||
git checkout -- go.sum # TODO: why is it being changed?
|
|
||||||
- persist_to_workspace:
|
|
||||||
root: .
|
|
||||||
paths:
|
|
||||||
- '*'
|
|
||||||
release:
|
|
||||||
docker:
|
|
||||||
- image: circleci/golang:1.14.3
|
|
||||||
steps:
|
|
||||||
- attach_workspace:
|
|
||||||
at: '~/project'
|
|
||||||
- setup_remote_docker
|
|
||||||
- run: docker login -u $DOCKER_USERNAME -p $DOCKER_PASSWORD
|
|
||||||
- run: curl -sL https://git.io/goreleaser | bash
|
|
||||||
- run: docker logout
|
|
||||||
workflows:
|
|
||||||
version: 2
|
|
||||||
build-workflow:
|
|
||||||
jobs:
|
|
||||||
- lint:
|
|
||||||
filters:
|
|
||||||
tags:
|
|
||||||
only: /.*/
|
|
||||||
- build-node:
|
|
||||||
filters:
|
|
||||||
tags:
|
|
||||||
only: /.*/
|
|
||||||
- build-go:
|
|
||||||
filters:
|
|
||||||
tags:
|
|
||||||
only: /.*/
|
|
||||||
requires:
|
|
||||||
- build-node
|
|
||||||
- lint
|
|
||||||
- release:
|
|
||||||
context: deploy
|
|
||||||
requires:
|
|
||||||
- build-go
|
|
||||||
filters:
|
|
||||||
tags:
|
|
||||||
only: /^v.*/
|
|
||||||
branches:
|
|
||||||
ignore: /.*/
|
|
||||||
@@ -1,3 +1,2 @@
|
|||||||
testdata/
|
*
|
||||||
.github/
|
!filebrowser
|
||||||
**.git
|
|
||||||
5
.github/CODEOWNERS
vendored
Normal file
5
.github/CODEOWNERS
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# These owners will be the default owners for everything in the repo.
|
||||||
|
# Unless a later match takes precedence, @o1egl will be requested for
|
||||||
|
# review when someone opens a pull request.
|
||||||
|
|
||||||
|
* @o1egl
|
||||||
66
.github/workflows/main.yaml
vendored
Normal file
66
.github/workflows/main.yaml
vendored
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
name: main
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- 'master'
|
||||||
|
tags:
|
||||||
|
- 'v*'
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
lint:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: actions/setup-go@v2
|
||||||
|
with:
|
||||||
|
go-version: 1.16
|
||||||
|
- uses: actions/setup-node@v2
|
||||||
|
with:
|
||||||
|
node-version: '14'
|
||||||
|
- run: npm i -g commitlint
|
||||||
|
- run: make lint
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: actions/setup-go@v2
|
||||||
|
with:
|
||||||
|
go-version: 1.16
|
||||||
|
- uses: actions/setup-node@v2
|
||||||
|
with:
|
||||||
|
node-version: '14'
|
||||||
|
- run: make test
|
||||||
|
release:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [lint, test]
|
||||||
|
if: startsWith(github.event.ref, 'refs/tags/v')
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- uses: actions/setup-go@v2
|
||||||
|
with:
|
||||||
|
go-version: 1.16
|
||||||
|
- uses: actions/setup-node@v2
|
||||||
|
with:
|
||||||
|
node-version: '14'
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v1
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v1
|
||||||
|
- name: Build fronetend
|
||||||
|
run: make build-frontend
|
||||||
|
- name: Login to Docker Hub
|
||||||
|
uses: docker/login-action@v1
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
- name: Run GoReleaser
|
||||||
|
uses: goreleaser/goreleaser-action@v2
|
||||||
|
with:
|
||||||
|
version: latest
|
||||||
|
args: release --rm-dist
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GH_PAT }}
|
||||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -5,11 +5,9 @@ _old
|
|||||||
rice-box.go
|
rice-box.go
|
||||||
.idea/
|
.idea/
|
||||||
filebrowser
|
filebrowser
|
||||||
dist/
|
|
||||||
|
|
||||||
.DS_Store
|
.DS_Store
|
||||||
node_modules
|
node_modules
|
||||||
/frontend/dist
|
|
||||||
|
|
||||||
# local env files
|
# local env files
|
||||||
.env.local
|
.env.local
|
||||||
@@ -28,3 +26,5 @@ yarn-error.log*
|
|||||||
*.njsproj
|
*.njsproj
|
||||||
*.sln
|
*.sln
|
||||||
*.sw*
|
*.sw*
|
||||||
|
bin/
|
||||||
|
build/
|
||||||
|
|||||||
@@ -63,7 +63,6 @@ linters:
|
|||||||
- goconst
|
- goconst
|
||||||
- gocritic
|
- gocritic
|
||||||
- gocyclo
|
- gocyclo
|
||||||
- gofmt
|
|
||||||
- goimports
|
- goimports
|
||||||
- golint
|
- golint
|
||||||
- gomnd
|
- gomnd
|
||||||
|
|||||||
131
.goreleaser.yml
131
.goreleaser.yml
@@ -3,10 +3,6 @@ project_name: filebrowser
|
|||||||
env:
|
env:
|
||||||
- GO111MODULE=on
|
- GO111MODULE=on
|
||||||
|
|
||||||
before:
|
|
||||||
hooks:
|
|
||||||
- go mod download
|
|
||||||
|
|
||||||
build:
|
build:
|
||||||
env:
|
env:
|
||||||
- CGO_ENABLED=0
|
- CGO_ENABLED=0
|
||||||
@@ -19,10 +15,6 @@ build:
|
|||||||
- linux
|
- linux
|
||||||
- windows
|
- windows
|
||||||
- freebsd
|
- freebsd
|
||||||
- netbsd
|
|
||||||
- openbsd
|
|
||||||
- dragonfly
|
|
||||||
- solaris
|
|
||||||
goarch:
|
goarch:
|
||||||
- amd64
|
- amd64
|
||||||
- 386
|
- 386
|
||||||
@@ -35,14 +27,8 @@ build:
|
|||||||
ignore:
|
ignore:
|
||||||
- goos: darwin
|
- goos: darwin
|
||||||
goarch: 386
|
goarch: 386
|
||||||
- goos: openbsd
|
|
||||||
goarch: arm
|
|
||||||
- goos: freebsd
|
- goos: freebsd
|
||||||
goarch: arm
|
goarch: arm
|
||||||
- goos: netbsd
|
|
||||||
goarch: arm
|
|
||||||
- goos: solaris
|
|
||||||
goarch: arm
|
|
||||||
|
|
||||||
archives:
|
archives:
|
||||||
-
|
-
|
||||||
@@ -55,53 +41,106 @@ archives:
|
|||||||
dockers:
|
dockers:
|
||||||
-
|
-
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
binaries:
|
use_buildx: true
|
||||||
- filebrowser
|
build_flag_templates:
|
||||||
|
- "--pull"
|
||||||
|
- "--label=org.opencontainers.image.created={{.Date}}"
|
||||||
|
- "--label=org.opencontainers.image.name={{.ProjectName}}"
|
||||||
|
- "--label=org.opencontainers.image.revision={{.FullCommit}}"
|
||||||
|
- "--label=org.opencontainers.image.version={{.Version}}"
|
||||||
|
- "--label=org.opencontainers.image.source={{.GitURL}}"
|
||||||
|
- "--platform=linux/amd64"
|
||||||
goos: linux
|
goos: linux
|
||||||
goarch: amd64
|
goarch: amd64
|
||||||
goarm: ''
|
|
||||||
image_templates:
|
image_templates:
|
||||||
- "filebrowser/filebrowser:latest"
|
- "filebrowser/filebrowser:{{ .Tag }}-amd64"
|
||||||
- "filebrowser/filebrowser:{{ .Tag }}"
|
- "filebrowser/filebrowser:v{{ .Major }}-amd64"
|
||||||
- "filebrowser/filebrowser:v{{ .Major }}"
|
|
||||||
extra_files:
|
extra_files:
|
||||||
- .docker.json
|
- .docker.json
|
||||||
-
|
-
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
binaries:
|
use_buildx: true
|
||||||
- filebrowser
|
build_flag_templates:
|
||||||
|
- "--pull"
|
||||||
|
- "--label=org.opencontainers.image.created={{.Date}}"
|
||||||
|
- "--label=org.opencontainers.image.name={{.ProjectName}}"
|
||||||
|
- "--label=org.opencontainers.image.revision={{.FullCommit}}"
|
||||||
|
- "--label=org.opencontainers.image.version={{.Version}}"
|
||||||
|
- "--label=org.opencontainers.image.source={{.GitURL}}"
|
||||||
|
- "--platform=linux/arm64"
|
||||||
|
goos: linux
|
||||||
|
goarch: arm64
|
||||||
|
image_templates:
|
||||||
|
- "filebrowser/filebrowser:{{ .Tag }}-arm64"
|
||||||
|
- "filebrowser/filebrowser:v{{ .Major }}-arm64"
|
||||||
|
extra_files:
|
||||||
|
- .docker.json
|
||||||
|
-
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
use_buildx: true
|
||||||
|
build_flag_templates:
|
||||||
|
- "--pull"
|
||||||
|
- "--label=org.opencontainers.image.created={{.Date}}"
|
||||||
|
- "--label=org.opencontainers.image.name={{.ProjectName}}"
|
||||||
|
- "--label=org.opencontainers.image.revision={{.FullCommit}}"
|
||||||
|
- "--label=org.opencontainers.image.version={{.Version}}"
|
||||||
|
- "--label=org.opencontainers.image.source={{.GitURL}}"
|
||||||
|
- "--platform=linux/arm/v6"
|
||||||
goos: linux
|
goos: linux
|
||||||
goarch: arm
|
goarch: arm
|
||||||
goarm: '5'
|
goarm: '6'
|
||||||
image_templates:
|
image_templates:
|
||||||
- "filebrowser/filebrowser:pi"
|
- "filebrowser/filebrowser:{{ .Tag }}-armv6"
|
||||||
- "filebrowser/filebrowser:{{ .Tag }}-pi"
|
- "filebrowser/filebrowser:v{{ .Major }}-armv6"
|
||||||
- "filebrowser/filebrowser:v{{ .Major }}-pi"
|
|
||||||
extra_files:
|
extra_files:
|
||||||
- .docker.json
|
- .docker.json
|
||||||
-
|
-
|
||||||
dockerfile: Dockerfile.alpine
|
dockerfile: Dockerfile
|
||||||
binaries:
|
use_buildx: true
|
||||||
- filebrowser
|
build_flag_templates:
|
||||||
|
- "--pull"
|
||||||
|
- "--label=org.opencontainers.image.created={{.Date}}"
|
||||||
|
- "--label=org.opencontainers.image.name={{.ProjectName}}"
|
||||||
|
- "--label=org.opencontainers.image.revision={{.FullCommit}}"
|
||||||
|
- "--label=org.opencontainers.image.version={{.Version}}"
|
||||||
|
- "--label=org.opencontainers.image.source={{.GitURL}}"
|
||||||
|
- "--platform=linux/arm/v7"
|
||||||
goos: linux
|
goos: linux
|
||||||
goarch: amd64
|
goarch: arm
|
||||||
goarm: ''
|
goarm: '7'
|
||||||
image_templates:
|
image_templates:
|
||||||
- "filebrowser/filebrowser:alpine"
|
- "filebrowser/filebrowser:{{ .Tag }}-armv7"
|
||||||
- "filebrowser/filebrowser:{{ .Tag }}-alpine"
|
- "filebrowser/filebrowser:v{{ .Major }}-armv7"
|
||||||
- "filebrowser/filebrowser:v{{ .Major }}-alpine"
|
|
||||||
extra_files:
|
extra_files:
|
||||||
- .docker.json
|
- .docker.json
|
||||||
-
|
docker_manifests:
|
||||||
dockerfile: Dockerfile.debian
|
- name_template: "filebrowser/filebrowser:latest"
|
||||||
binaries:
|
|
||||||
- filebrowser
|
|
||||||
goos: linux
|
|
||||||
goarch: amd64
|
|
||||||
goarm: ''
|
|
||||||
image_templates:
|
image_templates:
|
||||||
- "filebrowser/filebrowser:debian"
|
- "filebrowser/filebrowser:{{ .Tag }}-amd64"
|
||||||
- "filebrowser/filebrowser:{{ .Tag }}-debian"
|
- "filebrowser/filebrowser:{{ .Tag }}-arm64"
|
||||||
- "filebrowser/filebrowser:v{{ .Major }}-debian"
|
- "filebrowser/filebrowser:{{ .Tag }}-armv6"
|
||||||
extra_files:
|
- "filebrowser/filebrowser:{{ .Tag }}-armv7"
|
||||||
- .docker.json
|
- name_template: "filebrowser/filebrowser:{{ .Tag }}"
|
||||||
|
image_templates:
|
||||||
|
- "filebrowser/filebrowser:{{ .Tag }}-amd64"
|
||||||
|
- "filebrowser/filebrowser:{{ .Tag }}-arm64"
|
||||||
|
- "filebrowser/filebrowser:{{ .Tag }}-armv6"
|
||||||
|
- "filebrowser/filebrowser:{{ .Tag }}-armv7"
|
||||||
|
- name_template: "filebrowser/filebrowser:v{{ .Major }}"
|
||||||
|
image_templates:
|
||||||
|
- "filebrowser/filebrowser:v{{ .Major }}-amd64"
|
||||||
|
- "filebrowser/filebrowser:v{{ .Major }}-arm64"
|
||||||
|
- "filebrowser/filebrowser:v{{ .Major }}-armv6"
|
||||||
|
- "filebrowser/filebrowser:v{{ .Major }}-armv7"
|
||||||
|
brews:
|
||||||
|
- name: filebrowser
|
||||||
|
tap:
|
||||||
|
owner: filebrowser
|
||||||
|
name: homebrew-tap
|
||||||
|
folder: Formula
|
||||||
|
homepage: https://filebrowser.org
|
||||||
|
commit_author:
|
||||||
|
name: FileBrowser Robot
|
||||||
|
email: robot@filebrowser.org
|
||||||
|
description: File Browser is a create-your-own-cloud-kind of software where you can install it on a server, direct it to a path and then access your files through a nice web interface
|
||||||
|
license: "MIT"
|
||||||
14
.versionrc
Normal file
14
.versionrc
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"types": [
|
||||||
|
{ "type": "feat", "section": "Features" },
|
||||||
|
{ "type": "fix", "section": "Bug Fixes" },
|
||||||
|
{ "type": "perf", "section": "Performance improvements" },
|
||||||
|
{ "type": "revert", "section": "Reverts" },
|
||||||
|
{ "type": "refactor", "section": "Refactorings" },
|
||||||
|
{ "type": "build", "section": "Build" },
|
||||||
|
{ "type": "ci", "hidden": true },
|
||||||
|
{ "type": "test", "hidden": true },
|
||||||
|
{ "type": "chore", "hidden": true },
|
||||||
|
{ "type": "docs", "hidden": true }
|
||||||
|
]
|
||||||
|
}
|
||||||
204
CHANGELOG.md
204
CHANGELOG.md
@@ -2,6 +2,210 @@
|
|||||||
|
|
||||||
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
||||||
|
|
||||||
|
## [2.13.0](https://github.com/filebrowser/filebrowser/compare/v2.12.1...v2.13.0) (2021-03-14)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* dual pane settings view ([db5aad8](https://github.com/filebrowser/filebrowser/commit/db5aad8eb679cfe1b1ace5142cf342951217f0f7))
|
||||||
|
* improved settings navbar ([5b28aa0](https://github.com/filebrowser/filebrowser/commit/5b28aa0848710b9d3ee02a2aa912856395f48bd2))
|
||||||
|
* improved sharing prompt ([1819377](https://github.com/filebrowser/filebrowser/commit/18193778971e27d18b5a35df8c2d0e2953b48111))
|
||||||
|
* increased header button counter size ([4fb832c](https://github.com/filebrowser/filebrowser/commit/4fb832c0422107e16f22b7aa928224f36de4978f))
|
||||||
|
* larger previewer content ([62fff5c](https://github.com/filebrowser/filebrowser/commit/62fff5ca60da1f887c1f95fa4808d3753596dab2))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* archive contains parent path on Windows ([54f3570](https://github.com/filebrowser/filebrowser/commit/54f35701a2bd5cb7ec0628ca9789047072c073db))
|
||||||
|
* check rules on http resource handlers ([5bf1554](https://github.com/filebrowser/filebrowser/commit/5bf15548d0ad147acfad5000277531be2671f7ce))
|
||||||
|
* download current dir on file listing ([488d980](https://github.com/filebrowser/filebrowser/commit/488d98045e7476ed11e53c13d9498a9db3165bbc))
|
||||||
|
* encoded file path on share ([7955e07](https://github.com/filebrowser/filebrowser/commit/7955e0720baef3710106c7e69bbbf078d5489220))
|
||||||
|
* full file path on share ([e017a19](https://github.com/filebrowser/filebrowser/commit/e017a199850e19dd51b960ba59402c215fd8f1af))
|
||||||
|
* header dropdown icon color on previewer ([f8df76f](https://github.com/filebrowser/filebrowser/commit/f8df76f52684f10722ce123fec2c90e321ddf103))
|
||||||
|
* item dragging on file listing ([326b35a](https://github.com/filebrowser/filebrowser/commit/326b35a7ac7871afcdf892ca150349665b7f6379))
|
||||||
|
* modified time on info prompt ([11ebaec](https://github.com/filebrowser/filebrowser/commit/11ebaec5f0671ec02ebe55d4a73a514bce3a6713))
|
||||||
|
* root path name on archive ([426b38b](https://github.com/filebrowser/filebrowser/commit/426b38bb3362d2d477d0d8aa27d880664d537431))
|
||||||
|
* stuck icon on header button ([6a734c0](https://github.com/filebrowser/filebrowser/commit/6a734c01391b437c2842f5d97fb63f29a0017510))
|
||||||
|
* update image cache when replacing ([81b6f4d](https://github.com/filebrowser/filebrowser/commit/81b6f4d6f6a01886583016f61f4f1951a59f244d))
|
||||||
|
* wait for async command exit ([#1326](https://github.com/filebrowser/filebrowser/issues/1326)) ([6d5ceae](https://github.com/filebrowser/filebrowser/commit/6d5ceae8b454edd749b3b65c88aacc0a31ce9215))
|
||||||
|
|
||||||
|
|
||||||
|
### Refactorings
|
||||||
|
|
||||||
|
* migrate from rice to embed.FS ([fc55061](https://github.com/filebrowser/filebrowser/commit/fc5506179a64e9e2f57f7b6d6cce4b95f5ebc235))
|
||||||
|
|
||||||
|
### [2.12.1](https://github.com/filebrowser/filebrowser/compare/v2.12.0...v2.12.1) (2021-03-07)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* add missing default config into the docker image ([7358b3f](https://github.com/filebrowser/filebrowser/commit/7358b3fe3178c20007b4b5ef5c03705badd538c4))
|
||||||
|
|
||||||
|
## [2.12.0](https://github.com/filebrowser/filebrowser/compare/v2.11.0...v2.12.0) (2021-03-04)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add homebrew tap ([2d2c598](https://github.com/filebrowser/filebrowser/commit/2d2c598fa6bd1ecaf39c542182890c8dd9b1cad0))
|
||||||
|
* added tiff files preview support ([#1222](https://github.com/filebrowser/filebrowser/issues/1222)) ([e8c9d1c](https://github.com/filebrowser/filebrowser/commit/e8c9d1c53989b4b52f6fba2a8ac41ae612c03a7c))
|
||||||
|
* allow disabling file detections by reading header ([#1175](https://github.com/filebrowser/filebrowser/issues/1175)) ([6914063](https://github.com/filebrowser/filebrowser/commit/6914063853a8a3f3cecfa4b21f223820c2a0b7df))
|
||||||
|
* allow to password protect shares ([#1252](https://github.com/filebrowser/filebrowser/issues/1252)) ([d8f415f](https://github.com/filebrowser/filebrowser/commit/d8f415f8abd0c4301803bd968c54429dd3fe4b59))
|
||||||
|
* build multi-arch docker images ([cf4836d](https://github.com/filebrowser/filebrowser/commit/cf4836dc757ef79ad615179bb7a6c7bbd3b09c2c))
|
||||||
|
* share management delete confirm ([#1212](https://github.com/filebrowser/filebrowser/issues/1212)) ([b600b11](https://github.com/filebrowser/filebrowser/commit/b600b11415fd1fb90ff2f5136be95a9c737ae1cb))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* don't allow to remove root user ([019ce80](https://github.com/filebrowser/filebrowser/commit/019ce80fc529a0437984fdc3d1ab6916f34dd594))
|
||||||
|
* double click to zoom pics in phone's browser ([#1274](https://github.com/filebrowser/filebrowser/issues/1274)) ([f1b7bd5](https://github.com/filebrowser/filebrowser/commit/f1b7bd59f67e719b7bfd203b0d7ec016fd21ab49))
|
||||||
|
* environmental variables not expanded in command ([#1241](https://github.com/filebrowser/filebrowser/issues/1241)) ([f3afd5c](https://github.com/filebrowser/filebrowser/commit/f3afd5cb79d6ad8b9cc8d54cb8fc2344b7c07d3d))
|
||||||
|
* fetch resource api once when sorting (closes [#1172](https://github.com/filebrowser/filebrowser/issues/1172)) ([#1202](https://github.com/filebrowser/filebrowser/issues/1202)) ([05bb7c8](https://github.com/filebrowser/filebrowser/commit/05bb7c85531349f3e9d1d8a523bb1243587b2ebc))
|
||||||
|
|
||||||
|
|
||||||
|
### Build
|
||||||
|
|
||||||
|
* use make for building the project ([#1304](https://github.com/filebrowser/filebrowser/issues/1304)) ([23f8464](https://github.com/filebrowser/filebrowser/commit/23f84642e6c1e07f89f98d2c1bb6fc9da36cc71c))
|
||||||
|
|
||||||
|
## [2.11.0](https://github.com/filebrowser/filebrowser/compare/v2.10.0...v2.11.0) (2020-12-28)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add sharing management ([#1178](https://github.com/filebrowser/filebrowser/issues/1178)) (closes [#1000](https://github.com/filebrowser/filebrowser/issues/1000)) ([677bce3](https://github.com/filebrowser/filebrowser/commit/677bce376b024d9ff38f34e74243034fe5a1ec3c))
|
||||||
|
* download shared subdirectory ([#1184](https://github.com/filebrowser/filebrowser/issues/1184)) ([fb5b28d](https://github.com/filebrowser/filebrowser/commit/fb5b28d9cbdee10d38fcd719b9fd832121be58ef))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* check user input to prevent permission elevation ([#1196](https://github.com/filebrowser/filebrowser/issues/1196)) (closes [#1195](https://github.com/filebrowser/filebrowser/issues/1195)) ([f62806f](https://github.com/filebrowser/filebrowser/commit/f62806f6c9e9c7f392d1b747d65b8fe40b313e89))
|
||||||
|
* delete extra remove prefix ([#1186](https://github.com/filebrowser/filebrowser/issues/1186)) ([7a5298a](https://github.com/filebrowser/filebrowser/commit/7a5298a7556f7dcc52f59b8ea76d040d3ddc3d12))
|
||||||
|
* move files between different volumes (closes [#1177](https://github.com/filebrowser/filebrowser/issues/1177)) ([58835b7](https://github.com/filebrowser/filebrowser/commit/58835b7e535cc96e1c8a5d85821c1545743ca757))
|
||||||
|
* recaptcha race condition ([#1176](https://github.com/filebrowser/filebrowser/issues/1176)) ([ac3673e](https://github.com/filebrowser/filebrowser/commit/ac3673e111afac6616af9650ca07028b6c27e6cd))
|
||||||
|
|
||||||
|
## [2.10.0](https://github.com/filebrowser/filebrowser/compare/v2.9.0...v2.10.0) (2020-11-24)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add hide dotfiles param ([#1148](https://github.com/filebrowser/filebrowser/issues/1148)) ([10e399b](https://github.com/filebrowser/filebrowser/commit/10e399b3c3dbdcfb4465a9d4138e1da6bae0873d))
|
||||||
|
* add single click mode ([#1139](https://github.com/filebrowser/filebrowser/issues/1139)) ([e8b4e9a](https://github.com/filebrowser/filebrowser/commit/e8b4e9af46d6e99dbeb965dd9727d9ed017d52a2))
|
||||||
|
* automatically jump to the next photo when deleting while previewing ([#1143](https://github.com/filebrowser/filebrowser/issues/1143)) ([9515cee](https://github.com/filebrowser/filebrowser/commit/9515ceeb42e5ef5267400220a2082dec775e843d))
|
||||||
|
* shared folder file listing ([e119bc5](https://github.com/filebrowser/filebrowser/commit/e119bc55ea82cefcbcc0571650107dfd5d73f570))
|
||||||
|
* shared item information ([36cacdf](https://github.com/filebrowser/filebrowser/commit/36cacdf598e4e09f064c8ace0ca7a6c24b23028e))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* empty folder in archive ([7096b3d](https://github.com/filebrowser/filebrowser/commit/7096b3dab92441981c9964e4a6175af0a255d2be))
|
||||||
|
* fix hanging when reading a named pipe file (closes [#1155](https://github.com/filebrowser/filebrowser/issues/1155)) ([586d198](https://github.com/filebrowser/filebrowser/commit/586d198d47b525eeccc6fe587573a3ad83adb4f6))
|
||||||
|
* previewer title overflow ([4e48ffc](https://github.com/filebrowser/filebrowser/commit/4e48ffc14d09dabeea12dc495144277db62b5b7d))
|
||||||
|
* resource rename action invalid path ([1ce3068](https://github.com/filebrowser/filebrowser/commit/1ce3068a99c80c153fd41359255d173bce6e79e8))
|
||||||
|
|
||||||
|
## [2.9.0](https://github.com/filebrowser/filebrowser/compare/v2.8.0...v2.9.0) (2020-10-21)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* support WKWebview custom protocol ([#1113](https://github.com/filebrowser/filebrowser/issues/1113)) ([0ac80e8](https://github.com/filebrowser/filebrowser/commit/0ac80e8387a69924284259bde448af2813d84ed1))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* allow start from Windows explorer ([f2c4e78](https://github.com/filebrowser/filebrowser/commit/f2c4e78381610879eda5316d38a999c89df6c14a))
|
||||||
|
* file upload missing path slash ([5e27ba5](https://github.com/filebrowser/filebrowser/commit/5e27ba5c8c1be603c6ae7fec8de48e3532dea1f7))
|
||||||
|
* preview case sensitive file extension ([05bff54](https://github.com/filebrowser/filebrowser/commit/05bff54b71543fd232f1089c40504d0cbfd106be))
|
||||||
|
* search missing path slash ([2bd163d](https://github.com/filebrowser/filebrowser/commit/2bd163d92a856d65c8d4615e37898470c1edf2f4))
|
||||||
|
|
||||||
|
## [2.8.0](https://github.com/filebrowser/filebrowser/compare/v2.7.0...v2.8.0) (2020-10-05)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add disable exec flag ([#1090](https://github.com/filebrowser/filebrowser/issues/1090)) ([97693cc](https://github.com/filebrowser/filebrowser/commit/97693cc6117ce1c956baede91de5dd48b904e175))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* empty commands setting ([c6d4fcd](https://github.com/filebrowser/filebrowser/commit/c6d4fcd08f5f1531c2cef514dc86019e23e7289f))
|
||||||
|
* file upload path encoding ([babd778](https://github.com/filebrowser/filebrowser/commit/babd7783afe85b790e1c558375d7b5013b2d366f))
|
||||||
|
* fix empty command name ([#1106](https://github.com/filebrowser/filebrowser/issues/1106)) ([36fb9f5](https://github.com/filebrowser/filebrowser/commit/36fb9f562a2c005ca4390fdebde0b4690201dff9))
|
||||||
|
* fix panic when accessing nonexistent .js file in static path ([#1105](https://github.com/filebrowser/filebrowser/issues/1105)) ([ad99bf1](https://github.com/filebrowser/filebrowser/commit/ad99bf180197e0e6d82231a86457585de16366a8))
|
||||||
|
* preview key shortcut conflict ([dd7b9dd](https://github.com/filebrowser/filebrowser/commit/dd7b9ddd8546361060ef99e838a691b2fc6c495a))
|
||||||
|
* search results absolute url ([26d62e4](https://github.com/filebrowser/filebrowser/commit/26d62e411716a5eb9a5a703e47484cfb3fbf3bd0))
|
||||||
|
|
||||||
|
## [2.7.0](https://github.com/filebrowser/filebrowser/compare/v2.6.2...v2.7.0) (2020-09-11)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add --socket-perm flag to control unix socket file permissions (closes [#1060](https://github.com/filebrowser/filebrowser/issues/1060)) ([65ac734](https://github.com/filebrowser/filebrowser/commit/65ac73414fadc4686c94803a93ff319e8f7ce9d1))
|
||||||
|
* preview mobile dropdown ([7787344](https://github.com/filebrowser/filebrowser/commit/778734419de314d4cb64d07109bbab73f8e2e42a))
|
||||||
|
* preview size button ([3d2cb83](https://github.com/filebrowser/filebrowser/commit/3d2cb838d111ee61047599f49e76de80c821f341))
|
||||||
|
* put selected files in the root of the archive (closes [#1065](https://github.com/filebrowser/filebrowser/issues/1065)) ([8142b32](https://github.com/filebrowser/filebrowser/commit/8142b32f3865eccd3331328e0d087f805d186ed5))
|
||||||
|
|
||||||
|
### [2.6.2](https://github.com/filebrowser/filebrowser/compare/v2.6.1...v2.6.2) (2020-08-05)
|
||||||
|
|
||||||
|
### [2.6.1](https://github.com/filebrowser/filebrowser/compare/v2.6.0...v2.6.1) (2020-07-28)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* delete cached previews when deleting file ([f5d02cd](https://github.com/filebrowser/filebrowser/commit/f5d02cdde97923b963878abf5a300393b9feb348))
|
||||||
|
* escape special characters in preview url (closes [#1002](https://github.com/filebrowser/filebrowser/issues/1002)) ([c9340af](https://github.com/filebrowser/filebrowser/commit/c9340af8d045671ad3338c5d2d887c335ab92de4))
|
||||||
|
|
||||||
|
## [2.6.0](https://github.com/filebrowser/filebrowser/compare/v2.5.0...v2.6.0) (2020-07-27)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add lazy load of image thumbnails ([bc00165](https://github.com/filebrowser/filebrowser/commit/bc001650944ae963b12b5b2538a68de7cd0d8f82))
|
||||||
|
* add param to disable img resizing ([aa78e3a](https://github.com/filebrowser/filebrowser/commit/aa78e3ab1fcae6f618e811ba4e315a7a209f9df2))
|
||||||
|
* cache resized images ([95bc929](https://github.com/filebrowser/filebrowser/commit/95bc92955f391ece22c40d9592f2a3e6e26907b9))
|
||||||
|
* limit image resize workers ([94ef596](https://github.com/filebrowser/filebrowser/commit/94ef59602fb50fc21b1164feda90a3b9aeb5e972))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* conflict handling on upload button ([f228fa5](https://github.com/filebrowser/filebrowser/commit/f228fa55408824618e9f0879da67c86d22b0d324))
|
||||||
|
* drop feedback ([f2d2c1c](https://github.com/filebrowser/filebrowser/commit/f2d2c1cbf85fba3edffb7b079f121ed3f0bc1e02))
|
||||||
|
* missing error message ([d9be370](https://github.com/filebrowser/filebrowser/commit/d9be370e2474b8070fa58db920c9481270cc4a48))
|
||||||
|
* parent verification on copy ([727c63b](https://github.com/filebrowser/filebrowser/commit/727c63b98e2964d0960d25914c296570f6c79478))
|
||||||
|
* path separator inconsistency on rename ([34dfb49](https://github.com/filebrowser/filebrowser/commit/34dfb49b719c948e709a4639b4af2c5cb73b3887))
|
||||||
|
|
||||||
|
## [2.5.0](https://github.com/filebrowser/filebrowser/compare/v2.4.0...v2.5.0) (2020-07-17)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add previewer title and loading indicator ([716396a](https://github.com/filebrowser/filebrowser/commit/716396a726329f0ba42fc34167dd07497c5bf47c))
|
||||||
|
* duplicate files in the same directory ([43526d9](https://github.com/filebrowser/filebrowser/commit/43526d9d1a8c837245e3f5059e0b4737583eeaeb))
|
||||||
|
* file copy, move and paste conflict checking ([eed9da1](https://github.com/filebrowser/filebrowser/commit/eed9da1471723ed3fbe6c00b1d6362b1c5fd8b04))
|
||||||
|
* rename option on replace prompt ([2636f87](https://github.com/filebrowser/filebrowser/commit/2636f876ab8f88eea6d9548de524ca2339eb0843))
|
||||||
|
* upload queue ([6ec6a23](https://github.com/filebrowser/filebrowser/commit/6ec6a2386173410f5cab9941dbf1bacb6b70ddd2))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* blinking previewer ([9a2ebba](https://github.com/filebrowser/filebrowser/commit/9a2ebbabe2e9f0c292701d33f36f9b7a457b1164))
|
||||||
|
* dark theme colors ([b3b6445](https://github.com/filebrowser/filebrowser/commit/b3b644527d5673e16e61d404ff58a3c7bd6b6637))
|
||||||
|
* directory conflict checking ([7e5beef](https://github.com/filebrowser/filebrowser/commit/7e5beeff464e75ab185c430cd96e7cc67209ccc1))
|
||||||
|
* prompt before closing window ([194030f](https://github.com/filebrowser/filebrowser/commit/194030fcfcf54a2cf5e2f8ececcbb4754474d8f8))
|
||||||
|
* remove incomplete uploaded files ([0727496](https://github.com/filebrowser/filebrowser/commit/0727496601a9918c8131c56f62419bfac7ac589a))
|
||||||
|
* reset clipboard after pasting cutted files ([10570ad](https://github.com/filebrowser/filebrowser/commit/10570ade442b573ebe00af08369e28b1b0688df6))
|
||||||
|
|
||||||
|
## [2.4.0](https://github.com/filebrowser/filebrowser/compare/v2.3.0...v2.4.0) (2020-07-07)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* full screen editor ([0d665e5](https://github.com/filebrowser/filebrowser/commit/0d665e528f880ceda0976ceed66070ac34de7969))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* add preview bypass for .gif files ([#1012](https://github.com/filebrowser/filebrowser/issues/1012)) ([453636d](https://github.com/filebrowser/filebrowser/commit/453636dfe2bbf177c74617862eb763485d4774bf))
|
||||||
|
* prompt key shortcut conflict ([0d69fbd](https://github.com/filebrowser/filebrowser/commit/0d69fbd9a342aa2695859021df0c423e3ae4a4fa))
|
||||||
|
|
||||||
## [2.3.0](https://github.com/filebrowser/filebrowser/compare/v2.2.0...v2.3.0) (2020-06-26)
|
## [2.3.0](https://github.com/filebrowser/filebrowser/compare/v2.2.0...v2.3.0) (2020-06-26)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,7 @@
|
|||||||
FROM alpine:latest as alpine
|
FROM alpine:latest
|
||||||
RUN apk --update add ca-certificates
|
RUN apk --update add ca-certificates
|
||||||
RUN apk --update add mailcap
|
RUN apk --update add mailcap
|
||||||
|
|
||||||
FROM scratch
|
|
||||||
COPY --from=alpine /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
|
|
||||||
COPY --from=alpine /etc/mime.types /etc/mime.types
|
|
||||||
|
|
||||||
VOLUME /srv
|
VOLUME /srv
|
||||||
EXPOSE 80
|
EXPOSE 80
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
FROM alpine:latest as alpine
|
|
||||||
RUN apk --update add ca-certificates
|
|
||||||
RUN apk --update add mailcap
|
|
||||||
|
|
||||||
VOLUME /srv
|
|
||||||
EXPOSE 80
|
|
||||||
|
|
||||||
COPY .docker.json /.filebrowser.json
|
|
||||||
COPY filebrowser /filebrowser
|
|
||||||
|
|
||||||
ENTRYPOINT [ "/filebrowser" ]
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
FROM debian:buster
|
|
||||||
|
|
||||||
VOLUME /srv
|
|
||||||
EXPOSE 80
|
|
||||||
|
|
||||||
COPY .docker.json /.filebrowser.json
|
|
||||||
COPY filebrowser /filebrowser
|
|
||||||
|
|
||||||
ENTRYPOINT [ "/filebrowser" ]
|
|
||||||
94
Makefile
Normal file
94
Makefile
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
SHELL := /bin/bash
|
||||||
|
BASE_PATH := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
|
||||||
|
VERSION ?= $(shell git describe --tags --always --match=v* 2> /dev/null || \
|
||||||
|
cat $(CURDIR)/.version 2> /dev/null || echo v0)
|
||||||
|
VERSION_HASH = $(shell git rev-parse HEAD)
|
||||||
|
|
||||||
|
BIN = $(BASE_PATH)/bin
|
||||||
|
PATH := $(BIN):$(PATH)
|
||||||
|
export PATH
|
||||||
|
|
||||||
|
# printing
|
||||||
|
V = 0
|
||||||
|
Q = $(if $(filter 1,$V),,@)
|
||||||
|
M = $(shell printf "\033[34;1m▶\033[0m")
|
||||||
|
|
||||||
|
GO = GOGC=off go
|
||||||
|
# go module
|
||||||
|
MODULE = $(shell env GO111MODULE=on $(GO) list -m)
|
||||||
|
|
||||||
|
DATE ?= $(shell date +%FT%T%z)
|
||||||
|
VERSION ?= $(shell git describe --tags --always --match=v* 2> /dev/null || \
|
||||||
|
cat $(CURDIR)/.version 2> /dev/null || echo v0)
|
||||||
|
VERSION_HASH = $(shell git rev-parse HEAD)
|
||||||
|
BRANCH = $(shell git rev-parse --abbrev-ref HEAD)
|
||||||
|
|
||||||
|
LDFLAGS += -X "$(MODULE)/varsion.Version=$(VERSION)" -X "$(MODULE)/varsion.CommitSHA=$(VERSION_HASH)"
|
||||||
|
|
||||||
|
# tools
|
||||||
|
$(BIN):
|
||||||
|
@mkdir -p $@
|
||||||
|
$(BIN)/%: | $(BIN) ; $(info $(M) installing $(PACKAGE)…)
|
||||||
|
$Q env GOBIN=$(BIN) $(GO) install $(PACKAGE)
|
||||||
|
|
||||||
|
GOLANGCI_LINT = $(BIN)/golangci-lint
|
||||||
|
$(BIN)/golangci-lint: PACKAGE=github.com/golangci/golangci-lint/cmd/golangci-lint@v1.37.1
|
||||||
|
|
||||||
|
GOIMPORTS = $(BIN)/goimports
|
||||||
|
$(BIN)/goimports: PACKAGE=golang.org/x/tools/cmd/goimports@v0.1.0
|
||||||
|
|
||||||
|
## build: Build
|
||||||
|
.PHONY: build
|
||||||
|
build: | build-frontend build-backend ; $(info $(M) building…)
|
||||||
|
|
||||||
|
## build-frontend: Build frontend
|
||||||
|
.PHONY: build-frontend
|
||||||
|
build-frontend: | ; $(info $(M) building frontend…)
|
||||||
|
$Q cd frontend && npm ci && npm run build
|
||||||
|
|
||||||
|
## build-backend: Build backend
|
||||||
|
.PHONY: build-backend
|
||||||
|
build-backend: | ; $(info $(M) building backend…)
|
||||||
|
$Q $(GO) build -ldflags '$(LDFLAGS)' -o filebrowser
|
||||||
|
|
||||||
|
## test: Run all tests
|
||||||
|
.PHONY: test
|
||||||
|
test: | test-frontend test-backend ; $(info $(M) running tests…)
|
||||||
|
|
||||||
|
## test-frontend: Run frontend tests
|
||||||
|
.PHONY: test-frontend
|
||||||
|
test-frontend: | ; $(info $(M) running frontend tests…)
|
||||||
|
|
||||||
|
## test-backend: Run backend tests
|
||||||
|
.PHONY: test-backend
|
||||||
|
test-backend: | $(RICE) ; $(info $(M) running backend tests…)
|
||||||
|
$Q $(GO) test -v ./...
|
||||||
|
|
||||||
|
## lint: Lint
|
||||||
|
.PHONY: lint
|
||||||
|
lint: lint-frontend lint-backend lint-commits | ; $(info $(M) running all linters…)
|
||||||
|
|
||||||
|
## lint-frontend: Lint frontend
|
||||||
|
.PHONY: lint-frontend
|
||||||
|
lint-frontend: | ; $(info $(M) running frontend linters…)
|
||||||
|
$Q cd frontend && npm ci && npm run lint
|
||||||
|
|
||||||
|
## lint-backend: Lint backend
|
||||||
|
.PHONY: lint-backend
|
||||||
|
lint-backend: | $(GOLANGCI_LINT) ; $(info $(M) running backend linters…)
|
||||||
|
$Q $(GOLANGCI_LINT) run
|
||||||
|
|
||||||
|
## lint-commits: Lint commits
|
||||||
|
.PHONY: lint-commits
|
||||||
|
lint-commits: | ; $(info $(M) running commitlint…)
|
||||||
|
$Q ./scripts/commitlint.sh
|
||||||
|
|
||||||
|
## bump-version: Bump app version
|
||||||
|
.PHONY: bump-version
|
||||||
|
bump-version: | ; $(info $(M) creating a new release…)
|
||||||
|
$Q ./scripts/bump_version.sh
|
||||||
|
|
||||||
|
## help: Show this help
|
||||||
|
.PHONY: help
|
||||||
|
help:
|
||||||
|
@sed -n 's/^## //p' $(MAKEFILE_LIST) | column -t -s ':' | sed -e 's/^/ /' | sort
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
[](https://travis-ci.com/filebrowser/filebrowser)
|
[](https://github.com/filebrowser/filebrowser/actions/workflows/main.yaml)
|
||||||
[](https://goreportcard.com/report/github.com/filebrowser/filebrowser)
|
[](https://goreportcard.com/report/github.com/filebrowser/filebrowser)
|
||||||
[](http://godoc.org/github.com/filebrowser/filebrowser)
|
[](http://godoc.org/github.com/filebrowser/filebrowser)
|
||||||
[](https://github.com/filebrowser/filebrowser/releases/latest)
|
[](https://github.com/filebrowser/filebrowser/releases/latest)
|
||||||
@@ -24,7 +24,7 @@ For installation instructions please refer to our docs at [https://filebrowser.o
|
|||||||
|
|
||||||
[Authentication Method](https://filebrowser.org/configuration/authentication-method) - You can change the way the user authenticates with the filebrowser server
|
[Authentication Method](https://filebrowser.org/configuration/authentication-method) - You can change the way the user authenticates with the filebrowser server
|
||||||
|
|
||||||
[Commander 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.
|
[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.
|
[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.
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
// Auther is the authentication interface.
|
// Auther is the authentication interface.
|
||||||
type Auther interface {
|
type Auther interface {
|
||||||
// Auth is called to authenticate a request.
|
// Auth is called to authenticate a request.
|
||||||
Auth(r *http.Request, s *users.Storage, root string) (*users.User, error)
|
Auth(r *http.Request, s users.Store, root string) (*users.User, error)
|
||||||
// LoginPage indicates if this auther needs a login page.
|
// LoginPage indicates if this auther needs a login page.
|
||||||
LoginPage() bool
|
LoginPage() bool
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ type JSONAuth struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Auth authenticates the user via a json in content body.
|
// Auth authenticates the user via a json in content body.
|
||||||
func (a JSONAuth) Auth(r *http.Request, sto *users.Storage, root string) (*users.User, error) {
|
func (a JSONAuth) Auth(r *http.Request, sto users.Store, root string) (*users.User, error) {
|
||||||
var cred jsonCred
|
var cred jsonCred
|
||||||
|
|
||||||
if r.Body == nil {
|
if r.Body == nil {
|
||||||
@@ -40,7 +40,7 @@ func (a JSONAuth) Auth(r *http.Request, sto *users.Storage, root string) (*users
|
|||||||
|
|
||||||
// If ReCaptcha is enabled, check the code.
|
// If ReCaptcha is enabled, check the code.
|
||||||
if a.ReCaptcha != nil && len(a.ReCaptcha.Secret) > 0 {
|
if a.ReCaptcha != nil && len(a.ReCaptcha.Secret) > 0 {
|
||||||
ok, err := a.ReCaptcha.Ok(cred.ReCaptcha) //nolint:shadow
|
ok, err := a.ReCaptcha.Ok(cred.ReCaptcha) //nolint:govet
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ const MethodNoAuth settings.AuthMethod = "noauth"
|
|||||||
type NoAuth struct{}
|
type NoAuth struct{}
|
||||||
|
|
||||||
// Auth uses authenticates user 1.
|
// Auth uses authenticates user 1.
|
||||||
func (a NoAuth) Auth(r *http.Request, sto *users.Storage, root string) (*users.User, error) {
|
func (a NoAuth) Auth(r *http.Request, sto users.Store, root string) (*users.User, error) {
|
||||||
return sto.Get(root, uint(1))
|
return sto.Get(root, uint(1))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ type ProxyAuth struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Auth authenticates the user via an HTTP header.
|
// Auth authenticates the user via an HTTP header.
|
||||||
func (a ProxyAuth) Auth(r *http.Request, sto *users.Storage, root string) (*users.User, error) {
|
func (a ProxyAuth) Auth(r *http.Request, sto users.Store, root string) (*users.User, error) {
|
||||||
username := r.Header.Get(a.Header)
|
username := r.Header.Get(a.Header)
|
||||||
user, err := sto.Get(root, username)
|
user, err := sto.Get(root, username)
|
||||||
if err == errors.ErrNotExist {
|
if err == errors.ErrNotExist {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ var cmdsAddCmd = &cobra.Command{
|
|||||||
Use: "add <event> <command>",
|
Use: "add <event> <command>",
|
||||||
Short: "Add a command to run on a specific event",
|
Short: "Add a command to run on a specific event",
|
||||||
Long: `Add a command to run on a specific event.`,
|
Long: `Add a command to run on a specific event.`,
|
||||||
Args: cobra.MinimumNArgs(2), //nolint:mnd
|
Args: cobra.MinimumNArgs(2), //nolint:gomnd
|
||||||
Run: python(func(cmd *cobra.Command, args []string, d pythonData) {
|
Run: python(func(cmd *cobra.Command, args []string, d pythonData) {
|
||||||
s, err := d.store.Settings.Get()
|
s, err := d.store.Settings.Get()
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ You can also specify an optional parameter (index_end) so
|
|||||||
you can remove all commands from 'index' to 'index_end',
|
you can remove all commands from 'index' to 'index_end',
|
||||||
including 'index_end'.`,
|
including 'index_end'.`,
|
||||||
Args: func(cmd *cobra.Command, args []string) error {
|
Args: func(cmd *cobra.Command, args []string) error {
|
||||||
if err := cobra.RangeArgs(2, 3)(cmd, args); err != nil { //nolint:mnd
|
if err := cobra.RangeArgs(2, 3)(cmd, args); err != nil { //nolint:gomnd
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ including 'index_end'.`,
|
|||||||
i, err := strconv.Atoi(args[1])
|
i, err := strconv.Atoi(args[1])
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
f := i
|
f := i
|
||||||
if len(args) == 3 { //nolint:mnd
|
if len(args) == 3 { //nolint:gomnd
|
||||||
f, err = strconv.Atoi(args[2])
|
f, err = strconv.Atoi(args[2])
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -140,10 +140,12 @@ func printSettings(ser *settings.Server, set *settings.Settings, auther auth.Aut
|
|||||||
fmt.Fprintf(w, "\tAddress:\t%s\n", ser.Address)
|
fmt.Fprintf(w, "\tAddress:\t%s\n", ser.Address)
|
||||||
fmt.Fprintf(w, "\tTLS Cert:\t%s\n", ser.TLSCert)
|
fmt.Fprintf(w, "\tTLS Cert:\t%s\n", ser.TLSCert)
|
||||||
fmt.Fprintf(w, "\tTLS Key:\t%s\n", ser.TLSKey)
|
fmt.Fprintf(w, "\tTLS Key:\t%s\n", ser.TLSKey)
|
||||||
|
fmt.Fprintf(w, "\tExec Enabled:\t%t\n", ser.EnableExec)
|
||||||
fmt.Fprintln(w, "\nDefaults:")
|
fmt.Fprintln(w, "\nDefaults:")
|
||||||
fmt.Fprintf(w, "\tScope:\t%s\n", set.Defaults.Scope)
|
fmt.Fprintf(w, "\tScope:\t%s\n", set.Defaults.Scope)
|
||||||
fmt.Fprintf(w, "\tLocale:\t%s\n", set.Defaults.Locale)
|
fmt.Fprintf(w, "\tLocale:\t%s\n", set.Defaults.Locale)
|
||||||
fmt.Fprintf(w, "\tView mode:\t%s\n", set.Defaults.ViewMode)
|
fmt.Fprintf(w, "\tView mode:\t%s\n", set.Defaults.ViewMode)
|
||||||
|
fmt.Fprintf(w, "\tSingle Click:\t%t\n", set.Defaults.SingleClick)
|
||||||
fmt.Fprintf(w, "\tCommands:\t%s\n", strings.Join(set.Defaults.Commands, " "))
|
fmt.Fprintf(w, "\tCommands:\t%s\n", strings.Join(set.Defaults.Commands, " "))
|
||||||
fmt.Fprintf(w, "\tSorting:\n")
|
fmt.Fprintf(w, "\tSorting:\n")
|
||||||
fmt.Fprintf(w, "\t\tBy:\t%s\n", set.Defaults.Sorting.By)
|
fmt.Fprintf(w, "\t\tBy:\t%s\n", set.Defaults.Sorting.By)
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
@@ -32,7 +31,7 @@ override the options.`,
|
|||||||
s := &settings.Settings{
|
s := &settings.Settings{
|
||||||
Key: generateKey(),
|
Key: generateKey(),
|
||||||
Signup: mustGetBool(flags, "signup"),
|
Signup: mustGetBool(flags, "signup"),
|
||||||
Shell: strings.Split(strings.TrimSpace(mustGetString(flags, "shell")), " "),
|
Shell: convertCmdStrToCmdArray(mustGetString(flags, "shell")),
|
||||||
AuthMethod: authMethod,
|
AuthMethod: authMethod,
|
||||||
Defaults: defaults,
|
Defaults: defaults,
|
||||||
Branding: settings.Branding{
|
Branding: settings.Branding{
|
||||||
@@ -62,7 +61,7 @@ override the options.`,
|
|||||||
|
|
||||||
fmt.Printf(`
|
fmt.Printf(`
|
||||||
Congratulations! You've set up your database to use with File Browser.
|
Congratulations! You've set up your database to use with File Browser.
|
||||||
Now add your first user via 'filebrowser users new' and then you just
|
Now add your first user via 'filebrowser users add' and then you just
|
||||||
need to call the main command to boot up the server.
|
need to call the main command to boot up the server.
|
||||||
`)
|
`)
|
||||||
printSettings(ser, s, auther)
|
printSettings(ser, s, auther)
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
)
|
)
|
||||||
@@ -50,7 +48,7 @@ you want to change. Other options will remain unchanged.`,
|
|||||||
case "auth.method":
|
case "auth.method":
|
||||||
hasAuth = true
|
hasAuth = true
|
||||||
case "shell":
|
case "shell":
|
||||||
set.Shell = strings.Split(strings.TrimSpace(mustGetString(flags, flag.Name)), " ")
|
set.Shell = convertCmdStrToCmdArray(mustGetString(flags, flag.Name))
|
||||||
case "branding.name":
|
case "branding.name":
|
||||||
set.Branding.Name = mustGetString(flags, flag.Name)
|
set.Branding.Name = mustGetString(flags, flag.Name)
|
||||||
case "branding.disableExternal":
|
case "branding.disableExternal":
|
||||||
|
|||||||
70
cmd/root.go
70
cmd/root.go
@@ -3,6 +3,7 @@ package cmd
|
|||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"errors"
|
"errors"
|
||||||
|
"io/fs"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
@@ -14,13 +15,17 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
homedir "github.com/mitchellh/go-homedir"
|
homedir "github.com/mitchellh/go-homedir"
|
||||||
|
"github.com/spf13/afero"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
v "github.com/spf13/viper"
|
v "github.com/spf13/viper"
|
||||||
lumberjack "gopkg.in/natefinch/lumberjack.v2"
|
lumberjack "gopkg.in/natefinch/lumberjack.v2"
|
||||||
|
|
||||||
"github.com/filebrowser/filebrowser/v2/auth"
|
"github.com/filebrowser/filebrowser/v2/auth"
|
||||||
|
"github.com/filebrowser/filebrowser/v2/diskcache"
|
||||||
|
"github.com/filebrowser/filebrowser/v2/frontend"
|
||||||
fbhttp "github.com/filebrowser/filebrowser/v2/http"
|
fbhttp "github.com/filebrowser/filebrowser/v2/http"
|
||||||
|
"github.com/filebrowser/filebrowser/v2/img"
|
||||||
"github.com/filebrowser/filebrowser/v2/settings"
|
"github.com/filebrowser/filebrowser/v2/settings"
|
||||||
"github.com/filebrowser/filebrowser/v2/storage"
|
"github.com/filebrowser/filebrowser/v2/storage"
|
||||||
"github.com/filebrowser/filebrowser/v2/users"
|
"github.com/filebrowser/filebrowser/v2/users"
|
||||||
@@ -32,6 +37,7 @@ var (
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
cobra.OnInitialize(initConfig)
|
cobra.OnInitialize(initConfig)
|
||||||
|
cobra.MousetrapHelpText = ""
|
||||||
|
|
||||||
rootCmd.SetVersionTemplate("File Browser version {{printf \"%s\" .Version}}\n")
|
rootCmd.SetVersionTemplate("File Browser version {{printf \"%s\" .Version}}\n")
|
||||||
|
|
||||||
@@ -55,7 +61,14 @@ func addServerFlags(flags *pflag.FlagSet) {
|
|||||||
flags.StringP("key", "k", "", "tls key")
|
flags.StringP("key", "k", "", "tls key")
|
||||||
flags.StringP("root", "r", ".", "root to prepend to relative paths")
|
flags.StringP("root", "r", ".", "root to prepend to relative paths")
|
||||||
flags.String("socket", "", "socket to listen to (cannot be used with address, port, cert nor key flags)")
|
flags.String("socket", "", "socket to listen to (cannot be used with address, port, cert nor key flags)")
|
||||||
|
flags.Uint32("socket-perm", 0666, "unix socket file permissions")
|
||||||
flags.StringP("baseurl", "b", "", "base url")
|
flags.StringP("baseurl", "b", "", "base url")
|
||||||
|
flags.String("cache-dir", "", "file cache directory (disabled if empty)")
|
||||||
|
flags.Int("img-processors", 4, "image processors count")
|
||||||
|
flags.Bool("disable-thumbnails", false, "disable image thumbnails")
|
||||||
|
flags.Bool("disable-preview-resize", false, "disable resize of image previews")
|
||||||
|
flags.Bool("disable-exec", false, "disables Command Runner feature")
|
||||||
|
flags.Bool("disable-type-detection-by-header", false, "disables type detection by reading file headers")
|
||||||
}
|
}
|
||||||
|
|
||||||
var rootCmd = &cobra.Command{
|
var rootCmd = &cobra.Command{
|
||||||
@@ -103,6 +116,24 @@ user created with the credentials from options "username" and "password".`,
|
|||||||
quickSetup(cmd.Flags(), d)
|
quickSetup(cmd.Flags(), d)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// build img service
|
||||||
|
workersCount, err := cmd.Flags().GetInt("img-processors")
|
||||||
|
checkErr(err)
|
||||||
|
if workersCount < 1 {
|
||||||
|
log.Fatal("Image resize workers count could not be < 1")
|
||||||
|
}
|
||||||
|
imgSvc := img.New(workersCount)
|
||||||
|
|
||||||
|
var fileCache diskcache.Interface = diskcache.NewNoOp()
|
||||||
|
cacheDir, err := cmd.Flags().GetString("cache-dir")
|
||||||
|
checkErr(err)
|
||||||
|
if cacheDir != "" {
|
||||||
|
if err := os.MkdirAll(cacheDir, 0700); err != nil { //nolint:govet
|
||||||
|
log.Fatalf("can't make directory %s: %s", cacheDir, err)
|
||||||
|
}
|
||||||
|
fileCache = diskcache.New(afero.NewOsFs(), cacheDir)
|
||||||
|
}
|
||||||
|
|
||||||
server := getRunParams(cmd.Flags(), d.store)
|
server := getRunParams(cmd.Flags(), d.store)
|
||||||
setupLog(server.Log)
|
setupLog(server.Log)
|
||||||
|
|
||||||
@@ -118,13 +149,20 @@ user created with the credentials from options "username" and "password".`,
|
|||||||
case server.Socket != "":
|
case server.Socket != "":
|
||||||
listener, err = net.Listen("unix", server.Socket)
|
listener, err = net.Listen("unix", server.Socket)
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
case server.TLSKey != "" && server.TLSCert != "":
|
socketPerm, err := cmd.Flags().GetUint32("socket-perm") //nolint:govet
|
||||||
cer, err := tls.LoadX509KeyPair(server.TLSCert, server.TLSKey) //nolint:shadow
|
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
listener, err = tls.Listen("tcp", adr, &tls.Config{Certificates: []tls.Certificate{cer}}) //nolint:shadow
|
err = os.Chmod(server.Socket, os.FileMode(socketPerm))
|
||||||
|
checkErr(err)
|
||||||
|
case server.TLSKey != "" && server.TLSCert != "":
|
||||||
|
cer, err := tls.LoadX509KeyPair(server.TLSCert, server.TLSKey) //nolint:govet
|
||||||
|
checkErr(err)
|
||||||
|
listener, err = tls.Listen("tcp", adr, &tls.Config{
|
||||||
|
MinVersion: tls.VersionTLS12,
|
||||||
|
Certificates: []tls.Certificate{cer}},
|
||||||
|
)
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
default:
|
default:
|
||||||
listener, err = net.Listen("tcp", adr) //nolint:shadow
|
listener, err = net.Listen("tcp", adr)
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,7 +170,12 @@ user created with the credentials from options "username" and "password".`,
|
|||||||
signal.Notify(sigc, os.Interrupt, syscall.SIGTERM)
|
signal.Notify(sigc, os.Interrupt, syscall.SIGTERM)
|
||||||
go cleanupHandler(listener, sigc)
|
go cleanupHandler(listener, sigc)
|
||||||
|
|
||||||
handler, err := fbhttp.NewHandler(d.store, server)
|
assetsFs, err := fs.Sub(frontend.Assets(), "dist")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
handler, err := fbhttp.NewHandler(imgSvc, fileCache, d.store, server, assetsFs)
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
|
|
||||||
defer listener.Close()
|
defer listener.Close()
|
||||||
@@ -205,6 +248,18 @@ func getRunParams(flags *pflag.FlagSet, st *storage.Storage) *settings.Server {
|
|||||||
server.Socket = ""
|
server.Socket = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_, disableThumbnails := getParamB(flags, "disable-thumbnails")
|
||||||
|
server.EnableThumbnails = !disableThumbnails
|
||||||
|
|
||||||
|
_, disablePreviewResize := getParamB(flags, "disable-preview-resize")
|
||||||
|
server.ResizePreview = !disablePreviewResize
|
||||||
|
|
||||||
|
_, disableTypeDetectionByHeader := getParamB(flags, "disable-type-detection-by-header")
|
||||||
|
server.TypeDetectionByHeader = !disableTypeDetectionByHeader
|
||||||
|
|
||||||
|
_, disableExec := getParamB(flags, "disable-exec")
|
||||||
|
server.EnableExec = !disableExec
|
||||||
|
|
||||||
return server
|
return server
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,8 +316,9 @@ func quickSetup(flags *pflag.FlagSet, d pythonData) {
|
|||||||
Signup: false,
|
Signup: false,
|
||||||
CreateUserDir: false,
|
CreateUserDir: false,
|
||||||
Defaults: settings.UserDefaults{
|
Defaults: settings.UserDefaults{
|
||||||
Scope: ".",
|
Scope: ".",
|
||||||
Locale: "en",
|
Locale: "en",
|
||||||
|
SingleClick: false,
|
||||||
Perm: users.Permissions{
|
Perm: users.Permissions{
|
||||||
Admin: false,
|
Admin: false,
|
||||||
Execute: true,
|
Execute: true,
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ including 'index_end'.`,
|
|||||||
i, err := strconv.Atoi(args[0])
|
i, err := strconv.Atoi(args[0])
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
f := i
|
f := i
|
||||||
if len(args) == 2 { //nolint:mnd
|
if len(args) == 2 { //nolint:gomnd
|
||||||
f, err = strconv.Atoi(args[1])
|
f, err = strconv.Atoi(args[1])
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,15 +27,16 @@ var usersCmd = &cobra.Command{
|
|||||||
|
|
||||||
func printUsers(usrs []*users.User) {
|
func printUsers(usrs []*users.User) {
|
||||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
||||||
fmt.Fprintln(w, "ID\tUsername\tScope\tLocale\tV. Mode\tAdmin\tExecute\tCreate\tRename\tModify\tDelete\tShare\tDownload\tPwd Lock")
|
fmt.Fprintln(w, "ID\tUsername\tScope\tLocale\tV. Mode\tS.Click\tAdmin\tExecute\tCreate\tRename\tModify\tDelete\tShare\tDownload\tPwd Lock")
|
||||||
|
|
||||||
for _, u := range usrs {
|
for _, u := range usrs {
|
||||||
fmt.Fprintf(w, "%d\t%s\t%s\t%s\t%s\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t\n",
|
fmt.Fprintf(w, "%d\t%s\t%s\t%s\t%s\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t\n",
|
||||||
u.ID,
|
u.ID,
|
||||||
u.Username,
|
u.Username,
|
||||||
u.Scope,
|
u.Scope,
|
||||||
u.Locale,
|
u.Locale,
|
||||||
u.ViewMode,
|
u.ViewMode,
|
||||||
|
u.SingleClick,
|
||||||
u.Perm.Admin,
|
u.Perm.Admin,
|
||||||
u.Perm.Execute,
|
u.Perm.Execute,
|
||||||
u.Perm.Create,
|
u.Perm.Create,
|
||||||
@@ -75,6 +76,7 @@ func addUserFlags(flags *pflag.FlagSet) {
|
|||||||
flags.String("scope", ".", "scope for users")
|
flags.String("scope", ".", "scope for users")
|
||||||
flags.String("locale", "en", "locale for users")
|
flags.String("locale", "en", "locale for users")
|
||||||
flags.String("viewMode", string(users.ListViewMode), "view mode for users")
|
flags.String("viewMode", string(users.ListViewMode), "view mode for users")
|
||||||
|
flags.Bool("singleClick", false, "use single clicks only")
|
||||||
}
|
}
|
||||||
|
|
||||||
func getViewMode(flags *pflag.FlagSet) users.ViewMode {
|
func getViewMode(flags *pflag.FlagSet) users.ViewMode {
|
||||||
@@ -95,6 +97,8 @@ func getUserDefaults(flags *pflag.FlagSet, defaults *settings.UserDefaults, all
|
|||||||
defaults.Locale = mustGetString(flags, flag.Name)
|
defaults.Locale = mustGetString(flags, flag.Name)
|
||||||
case "viewMode":
|
case "viewMode":
|
||||||
defaults.ViewMode = getViewMode(flags)
|
defaults.ViewMode = getViewMode(flags)
|
||||||
|
case "singleClick":
|
||||||
|
defaults.SingleClick = mustGetBool(flags, flag.Name)
|
||||||
case "perm.admin":
|
case "perm.admin":
|
||||||
defaults.Perm.Admin = mustGetBool(flags, flag.Name)
|
defaults.Perm.Admin = mustGetBool(flags, flag.Name)
|
||||||
case "perm.execute":
|
case "perm.execute":
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ var usersAddCmd = &cobra.Command{
|
|||||||
Use: "add <username> <password>",
|
Use: "add <username> <password>",
|
||||||
Short: "Create a new user",
|
Short: "Create a new user",
|
||||||
Long: `Create a new user and add it to the database.`,
|
Long: `Create a new user and add it to the database.`,
|
||||||
Args: cobra.ExactArgs(2), //nolint:mnd
|
Args: cobra.ExactArgs(2), //nolint:gomnd
|
||||||
Run: python(func(cmd *cobra.Command, args []string, d pythonData) {
|
Run: python(func(cmd *cobra.Command, args []string, d pythonData) {
|
||||||
s, err := d.store.Settings.Get()
|
s, err := d.store.Settings.Get()
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ list or set it to 0.`,
|
|||||||
// with the new username. If there is, print an error and cancel the
|
// with the new username. If there is, print an error and cancel the
|
||||||
// operation
|
// operation
|
||||||
if user.Username != onDB.Username {
|
if user.Username != onDB.Username {
|
||||||
if conflictuous, err := d.store.Users.Get("", user.Username); err == nil { //nolint:shadow
|
if conflictuous, err := d.store.Users.Get("", user.Username); err == nil { //nolint:govet
|
||||||
checkErr(usernameConflictError(user.Username, conflictuous.ID, user.ID))
|
checkErr(usernameConflictError(user.Username, conflictuous.ID, user.ID))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,17 +41,19 @@ options you want to change.`,
|
|||||||
checkErr(err)
|
checkErr(err)
|
||||||
|
|
||||||
defaults := settings.UserDefaults{
|
defaults := settings.UserDefaults{
|
||||||
Scope: user.Scope,
|
Scope: user.Scope,
|
||||||
Locale: user.Locale,
|
Locale: user.Locale,
|
||||||
ViewMode: user.ViewMode,
|
ViewMode: user.ViewMode,
|
||||||
Perm: user.Perm,
|
SingleClick: user.SingleClick,
|
||||||
Sorting: user.Sorting,
|
Perm: user.Perm,
|
||||||
Commands: user.Commands,
|
Sorting: user.Sorting,
|
||||||
|
Commands: user.Commands,
|
||||||
}
|
}
|
||||||
getUserDefaults(flags, &defaults, false)
|
getUserDefaults(flags, &defaults, false)
|
||||||
user.Scope = defaults.Scope
|
user.Scope = defaults.Scope
|
||||||
user.Locale = defaults.Locale
|
user.Locale = defaults.Locale
|
||||||
user.ViewMode = defaults.ViewMode
|
user.ViewMode = defaults.ViewMode
|
||||||
|
user.SingleClick = defaults.SingleClick
|
||||||
user.Perm = defaults.Perm
|
user.Perm = defaults.Perm
|
||||||
user.Commands = defaults.Commands
|
user.Commands = defaults.Commands
|
||||||
user.Sorting = defaults.Sorting
|
user.Sorting = defaults.Sorting
|
||||||
|
|||||||
15
cmd/utils.go
15
cmd/utils.go
@@ -7,6 +7,7 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/asdine/storm"
|
"github.com/asdine/storm"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
@@ -71,7 +72,7 @@ func dbExists(path string) (bool, error) {
|
|||||||
d := filepath.Dir(path)
|
d := filepath.Dir(path)
|
||||||
_, err = os.Stat(d)
|
_, err = os.Stat(d)
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
if err := os.MkdirAll(d, 0700); err != nil { //nolint:shadow
|
if err := os.MkdirAll(d, 0700); err != nil { //nolint:govet
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
return false, nil
|
return false, nil
|
||||||
@@ -178,3 +179,15 @@ func cleanUpMapValue(v interface{}) interface{} {
|
|||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// convertCmdStrToCmdArray checks if cmd string is blank (whitespace included)
|
||||||
|
// then returns empty string array, else returns the splitted word array of cmd.
|
||||||
|
// This is to ensure the result will never be []string{""}
|
||||||
|
func convertCmdStrToCmdArray(cmd string) []string {
|
||||||
|
var cmdArray []string
|
||||||
|
trimmedCmdStr := strings.TrimSpace(cmd)
|
||||||
|
if trimmedCmdStr != "" {
|
||||||
|
cmdArray = strings.Split(trimmedCmdStr, " ")
|
||||||
|
}
|
||||||
|
return cmdArray
|
||||||
|
}
|
||||||
|
|||||||
34
commitlint.config.js
Normal file
34
commitlint.config.js
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
module.exports = {
|
||||||
|
rules: {
|
||||||
|
'body-leading-blank': [1, 'always'],
|
||||||
|
'body-max-line-length': [2, 'always', 100],
|
||||||
|
'footer-leading-blank': [1, 'always'],
|
||||||
|
'footer-max-line-length': [2, 'always', 100],
|
||||||
|
'header-max-length': [2, 'always', 100],
|
||||||
|
'scope-case': [2, 'always', 'lower-case'],
|
||||||
|
'subject-case': [
|
||||||
|
2,
|
||||||
|
'never',
|
||||||
|
['sentence-case', 'start-case', 'pascal-case', 'upper-case'],
|
||||||
|
],
|
||||||
|
'subject-full-stop': [2, 'never', '.'],
|
||||||
|
'type-case': [2, 'always', 'lower-case'],
|
||||||
|
'type-empty': [2, 'never'],
|
||||||
|
'type-enum': [
|
||||||
|
2,
|
||||||
|
'always',
|
||||||
|
[
|
||||||
|
'feat',
|
||||||
|
'fix',
|
||||||
|
'perf',
|
||||||
|
'revert',
|
||||||
|
'refactor',
|
||||||
|
'build',
|
||||||
|
'ci',
|
||||||
|
'test',
|
||||||
|
'chore',
|
||||||
|
'docs',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
11
diskcache/cache.go
Normal file
11
diskcache/cache.go
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package diskcache
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Interface interface {
|
||||||
|
Store(ctx context.Context, key string, value []byte) error
|
||||||
|
Load(ctx context.Context, key string) (value []byte, exist bool, err error)
|
||||||
|
Delete(ctx context.Context, key string) error
|
||||||
|
}
|
||||||
110
diskcache/file_cache.go
Normal file
110
diskcache/file_cache.go
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
package diskcache
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/sha1" //nolint:gosec
|
||||||
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/spf13/afero"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FileCache struct {
|
||||||
|
fs afero.Fs
|
||||||
|
|
||||||
|
// granular locks
|
||||||
|
scopedLocks struct {
|
||||||
|
sync.Mutex
|
||||||
|
sync.Once
|
||||||
|
locks map[string]sync.Locker
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(fs afero.Fs, root string) *FileCache {
|
||||||
|
return &FileCache{
|
||||||
|
fs: afero.NewBasePathFs(fs, root),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FileCache) Store(ctx context.Context, key string, value []byte) error {
|
||||||
|
mu := f.getScopedLocks(key)
|
||||||
|
mu.Lock()
|
||||||
|
defer mu.Unlock()
|
||||||
|
|
||||||
|
fileName := f.getFileName(key)
|
||||||
|
if err := f.fs.MkdirAll(filepath.Dir(fileName), 0700); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := afero.WriteFile(f.fs, fileName, value, 0700); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FileCache) Load(ctx context.Context, key string) (value []byte, exist bool, err error) {
|
||||||
|
r, ok, err := f.open(key)
|
||||||
|
if err != nil || !ok {
|
||||||
|
return nil, ok, err
|
||||||
|
}
|
||||||
|
defer r.Close()
|
||||||
|
|
||||||
|
value, err = ioutil.ReadAll(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
|
return value, true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FileCache) Delete(ctx context.Context, key string) error {
|
||||||
|
mu := f.getScopedLocks(key)
|
||||||
|
mu.Lock()
|
||||||
|
defer mu.Unlock()
|
||||||
|
|
||||||
|
fileName := f.getFileName(key)
|
||||||
|
if err := f.fs.Remove(fileName); err != nil && !errors.Is(err, os.ErrNotExist) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FileCache) open(key string) (afero.File, bool, error) {
|
||||||
|
fileName := f.getFileName(key)
|
||||||
|
file, err := f.fs.Open(fileName)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, os.ErrNotExist) {
|
||||||
|
return nil, false, nil
|
||||||
|
}
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return file, true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// getScopedLocks pull lock from the map if found or create a new one
|
||||||
|
func (f *FileCache) getScopedLocks(key string) (lock sync.Locker) {
|
||||||
|
f.scopedLocks.Do(func() { f.scopedLocks.locks = map[string]sync.Locker{} })
|
||||||
|
|
||||||
|
f.scopedLocks.Lock()
|
||||||
|
lock, ok := f.scopedLocks.locks[key]
|
||||||
|
if !ok {
|
||||||
|
lock = &sync.Mutex{}
|
||||||
|
f.scopedLocks.locks[key] = lock
|
||||||
|
}
|
||||||
|
f.scopedLocks.Unlock()
|
||||||
|
|
||||||
|
return lock
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FileCache) getFileName(key string) string {
|
||||||
|
hasher := sha1.New() //nolint:gosec
|
||||||
|
_, _ = hasher.Write([]byte(key))
|
||||||
|
hash := hex.EncodeToString(hasher.Sum(nil))
|
||||||
|
return fmt.Sprintf("%s/%s/%s", hash[:1], hash[1:3], hash)
|
||||||
|
}
|
||||||
55
diskcache/file_cache_test.go
Normal file
55
diskcache/file_cache_test.go
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
package diskcache
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/spf13/afero"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFileCache(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
const (
|
||||||
|
key = "key"
|
||||||
|
value = "some text"
|
||||||
|
newValue = "new text"
|
||||||
|
cacheRoot = "/cache"
|
||||||
|
cachedFilePath = "a/62/a62f2225bf70bfaccbc7f1ef2a397836717377de"
|
||||||
|
)
|
||||||
|
|
||||||
|
fs := afero.NewMemMapFs()
|
||||||
|
cache := New(fs, "/cache")
|
||||||
|
|
||||||
|
// store new key
|
||||||
|
err := cache.Store(ctx, key, []byte(value))
|
||||||
|
require.NoError(t, err)
|
||||||
|
checkValue(t, ctx, fs, filepath.Join(cacheRoot, cachedFilePath), cache, key, value)
|
||||||
|
|
||||||
|
// update existing key
|
||||||
|
err = cache.Store(ctx, key, []byte(newValue))
|
||||||
|
require.NoError(t, err)
|
||||||
|
checkValue(t, ctx, fs, filepath.Join(cacheRoot, cachedFilePath), cache, key, newValue)
|
||||||
|
|
||||||
|
// delete key
|
||||||
|
err = cache.Delete(ctx, key)
|
||||||
|
require.NoError(t, err)
|
||||||
|
exists, err := afero.Exists(fs, filepath.Join(cacheRoot, cachedFilePath))
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.False(t, exists)
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkValue(t *testing.T, ctx context.Context, fs afero.Fs, fileFullPath string, cache *FileCache, key, wantValue string) { //nolint:golint
|
||||||
|
t.Helper()
|
||||||
|
// check actual file content
|
||||||
|
b, err := afero.ReadFile(fs, fileFullPath)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, wantValue, string(b))
|
||||||
|
|
||||||
|
// check cache content
|
||||||
|
b, ok, err := cache.Load(ctx, key)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.True(t, ok)
|
||||||
|
require.Equal(t, wantValue, string(b))
|
||||||
|
}
|
||||||
24
diskcache/noop_cache.go
Normal file
24
diskcache/noop_cache.go
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package diskcache
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
type NoOp struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNoOp() *NoOp {
|
||||||
|
return &NoOp{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NoOp) Store(ctx context.Context, key string, value []byte) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NoOp) Load(ctx context.Context, key string) (value []byte, exist bool, err error) {
|
||||||
|
return nil, false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NoOp) Delete(ctx context.Context, key string) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -16,4 +16,6 @@ var (
|
|||||||
ErrInvalidAuthMethod = errors.New("invalid auth method")
|
ErrInvalidAuthMethod = errors.New("invalid auth method")
|
||||||
ErrPermissionDenied = errors.New("permission denied")
|
ErrPermissionDenied = errors.New("permission denied")
|
||||||
ErrInvalidRequestParams = errors.New("invalid request params")
|
ErrInvalidRequestParams = errors.New("invalid request params")
|
||||||
|
ErrSourceIsParent = errors.New("source is parent")
|
||||||
|
ErrRootUserDeletion = errors.New("user with id 1 can't be deleted")
|
||||||
)
|
)
|
||||||
|
|||||||
116
files/file.go
116
files/file.go
@@ -38,15 +38,18 @@ type FileInfo struct {
|
|||||||
Subtitles []string `json:"subtitles,omitempty"`
|
Subtitles []string `json:"subtitles,omitempty"`
|
||||||
Content string `json:"content,omitempty"`
|
Content string `json:"content,omitempty"`
|
||||||
Checksums map[string]string `json:"checksums,omitempty"`
|
Checksums map[string]string `json:"checksums,omitempty"`
|
||||||
|
Token string `json:"token,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// FileOptions are the options when getting a file info.
|
// FileOptions are the options when getting a file info.
|
||||||
type FileOptions struct {
|
type FileOptions struct {
|
||||||
Fs afero.Fs
|
Fs afero.Fs
|
||||||
Path string
|
Path string
|
||||||
Modify bool
|
Modify bool
|
||||||
Expand bool
|
Expand bool
|
||||||
Checker rules.Checker
|
ReadHeader bool
|
||||||
|
Token string
|
||||||
|
Checker rules.Checker
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewFileInfo creates a File object from a path and a given user. This File
|
// NewFileInfo creates a File object from a path and a given user. This File
|
||||||
@@ -71,17 +74,18 @@ func NewFileInfo(opts FileOptions) (*FileInfo, error) {
|
|||||||
IsDir: info.IsDir(),
|
IsDir: info.IsDir(),
|
||||||
Size: info.Size(),
|
Size: info.Size(),
|
||||||
Extension: filepath.Ext(info.Name()),
|
Extension: filepath.Ext(info.Name()),
|
||||||
|
Token: opts.Token,
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.Expand {
|
if opts.Expand {
|
||||||
if file.IsDir {
|
if file.IsDir {
|
||||||
if err := file.readListing(opts.Checker); err != nil { //nolint:shadow
|
if err := file.readListing(opts.Checker, opts.ReadHeader); err != nil { //nolint:govet
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return file, nil
|
return file, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
err = file.detectType(opts.Modify, true)
|
err = file.detectType(opts.Modify, true, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -134,11 +138,60 @@ func (i *FileInfo) Checksum(algo string) error {
|
|||||||
|
|
||||||
//nolint:goconst
|
//nolint:goconst
|
||||||
//TODO: use constants
|
//TODO: use constants
|
||||||
func (i *FileInfo) detectType(modify, saveContent bool) error {
|
func (i *FileInfo) detectType(modify, saveContent, readHeader bool) error {
|
||||||
|
if IsNamedPipe(i.Mode) {
|
||||||
|
i.Type = "blob"
|
||||||
|
return nil
|
||||||
|
}
|
||||||
// failing to detect the type should not return error.
|
// failing to detect the type should not return error.
|
||||||
// imagine the situation where a file in a dir with thousands
|
// imagine the situation where a file in a dir with thousands
|
||||||
// of files couldn't be opened: we'd have immediately
|
// of files couldn't be opened: we'd have immediately
|
||||||
// a 500 even though it doesn't matter. So we just log it.
|
// a 500 even though it doesn't matter. So we just log it.
|
||||||
|
|
||||||
|
var buffer []byte
|
||||||
|
|
||||||
|
mimetype := mime.TypeByExtension(i.Extension)
|
||||||
|
if mimetype == "" && readHeader {
|
||||||
|
buffer = i.readFirstBytes()
|
||||||
|
mimetype = http.DetectContentType(buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case strings.HasPrefix(mimetype, "video"):
|
||||||
|
i.Type = "video"
|
||||||
|
i.detectSubtitles()
|
||||||
|
return nil
|
||||||
|
case strings.HasPrefix(mimetype, "audio"):
|
||||||
|
i.Type = "audio"
|
||||||
|
return nil
|
||||||
|
case strings.HasPrefix(mimetype, "image"):
|
||||||
|
i.Type = "image"
|
||||||
|
return nil
|
||||||
|
case (strings.HasPrefix(mimetype, "text") || (len(buffer) > 0 && !isBinary(buffer))) && i.Size <= 10*1024*1024: // 10 MB
|
||||||
|
i.Type = "text"
|
||||||
|
|
||||||
|
if !modify {
|
||||||
|
i.Type = "textImmutable"
|
||||||
|
}
|
||||||
|
|
||||||
|
if saveContent {
|
||||||
|
afs := &afero.Afero{Fs: i.Fs}
|
||||||
|
content, err := afs.ReadFile(i.Path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
i.Content = string(content)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
i.Type = "blob"
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *FileInfo) readFirstBytes() []byte {
|
||||||
reader, err := i.Fs.Open(i.Path)
|
reader, err := i.Fs.Open(i.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Print(err)
|
log.Print(err)
|
||||||
@@ -155,44 +208,7 @@ func (i *FileInfo) detectType(modify, saveContent bool) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
mimetype := mime.TypeByExtension(i.Extension)
|
return buffer[:n]
|
||||||
if mimetype == "" {
|
|
||||||
mimetype = http.DetectContentType(buffer[:n])
|
|
||||||
}
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case strings.HasPrefix(mimetype, "video"):
|
|
||||||
i.Type = "video"
|
|
||||||
i.detectSubtitles()
|
|
||||||
return nil
|
|
||||||
case strings.HasPrefix(mimetype, "audio"):
|
|
||||||
i.Type = "audio"
|
|
||||||
return nil
|
|
||||||
case strings.HasPrefix(mimetype, "image"):
|
|
||||||
i.Type = "image"
|
|
||||||
return nil
|
|
||||||
case isBinary(buffer[:n], n) || i.Size > 10*1024*1024: // 10 MB
|
|
||||||
i.Type = "blob"
|
|
||||||
return nil
|
|
||||||
default:
|
|
||||||
i.Type = "text"
|
|
||||||
|
|
||||||
if !modify {
|
|
||||||
i.Type = "textImmutable"
|
|
||||||
}
|
|
||||||
|
|
||||||
if saveContent {
|
|
||||||
afs := &afero.Afero{Fs: i.Fs}
|
|
||||||
content, err := afs.ReadFile(i.Path)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
i.Content = string(content)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *FileInfo) detectSubtitles() {
|
func (i *FileInfo) detectSubtitles() {
|
||||||
@@ -211,7 +227,7 @@ func (i *FileInfo) detectSubtitles() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *FileInfo) readListing(checker rules.Checker) error {
|
func (i *FileInfo) readListing(checker rules.Checker, readHeader bool) error {
|
||||||
afs := &afero.Afero{Fs: i.Fs}
|
afs := &afero.Afero{Fs: i.Fs}
|
||||||
dir, err := afs.ReadDir(i.Path)
|
dir, err := afs.ReadDir(i.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -232,9 +248,9 @@ func (i *FileInfo) readListing(checker rules.Checker) error {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.HasPrefix(f.Mode().String(), "L") {
|
if IsSymlink(f.Mode()) {
|
||||||
// It's a symbolic link. We try to follow it. If it doesn't work,
|
// It's a symbolic link. We try to follow it. If it doesn't work,
|
||||||
// we stay with the link information instead if the target's.
|
// we stay with the link information instead of the target's.
|
||||||
info, err := i.Fs.Stat(fPath)
|
info, err := i.Fs.Stat(fPath)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
f = info
|
f = info
|
||||||
@@ -257,7 +273,7 @@ func (i *FileInfo) readListing(checker rules.Checker) error {
|
|||||||
} else {
|
} else {
|
||||||
listing.NumFiles++
|
listing.NumFiles++
|
||||||
|
|
||||||
err := file.detectType(true, false)
|
err := file.detectType(true, false, readHeader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
package files
|
package files
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
)
|
)
|
||||||
|
|
||||||
func isBinary(content []byte, _ int) bool {
|
func isBinary(content []byte) bool {
|
||||||
maybeStr := string(content)
|
maybeStr := string(content)
|
||||||
runeCnt := utf8.RuneCount(content)
|
runeCnt := utf8.RuneCount(content)
|
||||||
runeIndex := 0
|
runeIndex := 0
|
||||||
@@ -48,3 +49,11 @@ func isBinary(content []byte, _ int) bool {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func IsNamedPipe(mode os.FileMode) bool {
|
||||||
|
return mode&os.ModeNamedPipe != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsSymlink(mode os.FileMode) bool {
|
||||||
|
return mode&os.ModeSymlink != 0
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,11 +2,32 @@ package fileutils
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// MoveFile moves file from src to dst.
|
||||||
|
// By default the rename filesystem system call is used. If src and dst point to different volumes
|
||||||
|
// the file copy is used as a fallback
|
||||||
|
func MoveFile(fs afero.Fs, src, dst string) error {
|
||||||
|
if fs.Rename(src, dst) == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// fallback
|
||||||
|
err := CopyFile(fs, src, dst)
|
||||||
|
if err != nil {
|
||||||
|
_ = fs.Remove(dst)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := fs.Remove(src); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// CopyFile copies a file from source to dest and returns
|
// CopyFile copies a file from source to dest and returns
|
||||||
// an error if any.
|
// an error if any.
|
||||||
func CopyFile(fs afero.Fs, source, dest string) error {
|
func CopyFile(fs afero.Fs, source, dest string) error {
|
||||||
@@ -25,7 +46,7 @@ func CopyFile(fs afero.Fs, source, dest string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create the destination file.
|
// Create the destination file.
|
||||||
dst, err := fs.Create(dest)
|
dst, err := fs.OpenFile(dest, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0775)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -37,15 +58,71 @@ func CopyFile(fs afero.Fs, source, dest string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy the mode if the user can't
|
// Copy the mode
|
||||||
// open the file.
|
|
||||||
info, err := fs.Stat(source)
|
info, err := fs.Stat(source)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fs.Chmod(dest, info.Mode())
|
return err
|
||||||
if err != nil {
|
}
|
||||||
return err
|
err = fs.Chmod(dest, info.Mode())
|
||||||
}
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CommonPrefix returns common directory path of provided files
|
||||||
|
func CommonPrefix(sep byte, paths ...string) string {
|
||||||
|
// Handle special cases.
|
||||||
|
switch len(paths) {
|
||||||
|
case 0:
|
||||||
|
return ""
|
||||||
|
case 1:
|
||||||
|
return path.Clean(paths[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note, we treat string as []byte, not []rune as is often
|
||||||
|
// done in Go. (And sep as byte, not rune). This is because
|
||||||
|
// most/all supported OS' treat paths as string of non-zero
|
||||||
|
// bytes. A filename may be displayed as a sequence of Unicode
|
||||||
|
// runes (typically encoded as UTF-8) but paths are
|
||||||
|
// not required to be valid UTF-8 or in any normalized form
|
||||||
|
// (e.g. "é" (U+00C9) and "é" (U+0065,U+0301) are different
|
||||||
|
// file names.
|
||||||
|
c := []byte(path.Clean(paths[0]))
|
||||||
|
|
||||||
|
// We add a trailing sep to handle the case where the
|
||||||
|
// common prefix directory is included in the path list
|
||||||
|
// (e.g. /home/user1, /home/user1/foo, /home/user1/bar).
|
||||||
|
// path.Clean will have cleaned off trailing / separators with
|
||||||
|
// the exception of the root directory, "/" (in which case we
|
||||||
|
// make it "//", but this will get fixed up to "/" bellow).
|
||||||
|
c = append(c, sep)
|
||||||
|
|
||||||
|
// Ignore the first path since it's already in c
|
||||||
|
for _, v := range paths[1:] {
|
||||||
|
// Clean up each path before testing it
|
||||||
|
v = path.Clean(v) + string(sep)
|
||||||
|
|
||||||
|
// Find the first non-common byte and truncate c
|
||||||
|
if len(v) < len(c) {
|
||||||
|
c = c[:len(v)]
|
||||||
|
}
|
||||||
|
for i := 0; i < len(c); i++ {
|
||||||
|
if v[i] != c[i] {
|
||||||
|
c = c[:i]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove trailing non-separator characters and the final separator
|
||||||
|
for i := len(c) - 1; i >= 0; i-- {
|
||||||
|
if c[i] == sep {
|
||||||
|
c = c[:i]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(c)
|
||||||
|
}
|
||||||
|
|||||||
46
fileutils/file_test.go
Normal file
46
fileutils/file_test.go
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
package fileutils
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestCommonPrefix(t *testing.T) {
|
||||||
|
testCases := map[string]struct {
|
||||||
|
paths []string
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
"same lvl": {
|
||||||
|
paths: []string{
|
||||||
|
"/home/user/file1",
|
||||||
|
"/home/user/file2",
|
||||||
|
},
|
||||||
|
want: "/home/user",
|
||||||
|
},
|
||||||
|
"sub folder": {
|
||||||
|
paths: []string{
|
||||||
|
"/home/user/folder",
|
||||||
|
"/home/user/folder/file",
|
||||||
|
},
|
||||||
|
want: "/home/user/folder",
|
||||||
|
},
|
||||||
|
"relative path": {
|
||||||
|
paths: []string{
|
||||||
|
"/home/user/folder",
|
||||||
|
"/home/user/folder/../folder2",
|
||||||
|
},
|
||||||
|
want: "/home/user",
|
||||||
|
},
|
||||||
|
"no common path": {
|
||||||
|
paths: []string{
|
||||||
|
"/home/user/folder",
|
||||||
|
"/etc/file",
|
||||||
|
},
|
||||||
|
want: "",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for name, tt := range testCases {
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
if got := CommonPrefix('/', tt.paths...); got != tt.want {
|
||||||
|
t.Errorf("CommonPrefix() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
10
frontend/assets.go
Normal file
10
frontend/assets.go
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
package frontend
|
||||||
|
|
||||||
|
import "embed"
|
||||||
|
|
||||||
|
//go:embed dist/*
|
||||||
|
var assets embed.FS
|
||||||
|
|
||||||
|
func Assets() embed.FS {
|
||||||
|
return assets
|
||||||
|
}
|
||||||
4
frontend/dist/.gitignore
vendored
Normal file
4
frontend/dist/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# Ignore everything in this directory
|
||||||
|
*
|
||||||
|
# Except this file
|
||||||
|
!.gitignore
|
||||||
16
frontend/package-lock.json
generated
16
frontend/package-lock.json
generated
@@ -9929,8 +9929,7 @@
|
|||||||
"pako": {
|
"pako": {
|
||||||
"version": "1.0.8",
|
"version": "1.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.8.tgz",
|
||||||
"integrity": "sha512-6i0HVbUfcKaTv+EG8ZTr75az7GFXcLYk9UyLEg7Notv/Ma+z/UG3TCoz6GiNeOrn1E/e63I0X/Hpw18jHOTUnA==",
|
"integrity": "sha512-6i0HVbUfcKaTv+EG8ZTr75az7GFXcLYk9UyLEg7Notv/Ma+z/UG3TCoz6GiNeOrn1E/e63I0X/Hpw18jHOTUnA=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"parallel-transform": {
|
"parallel-transform": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
@@ -12895,6 +12894,14 @@
|
|||||||
"integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==",
|
"integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"utif": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "http://mirrors.cloud.tencent.com/npm/utif/-/utif-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-WEo4D/xOvFW53K5f5QTaTbbiORcm2/pCL9P6qmJnup+17eYfKaEhDeX9PeQkuyEoIxlbGklDuGl8xwuXYMrrXQ==",
|
||||||
|
"requires": {
|
||||||
|
"pako": "^1.0.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
"util": {
|
"util": {
|
||||||
"version": "0.11.1",
|
"version": "0.11.1",
|
||||||
"resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz",
|
"resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz",
|
||||||
@@ -13030,6 +13037,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-8.15.3.tgz",
|
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-8.15.3.tgz",
|
||||||
"integrity": "sha512-PVNgo6yhOmacZVFjSapZ314oewwLyXHjJwAqjnaPN1GJAJd/dvsrShGzSiJuCX4Hc36G4epJvNXUwO8y7wEKew=="
|
"integrity": "sha512-PVNgo6yhOmacZVFjSapZ314oewwLyXHjJwAqjnaPN1GJAJd/dvsrShGzSiJuCX4Hc36G4epJvNXUwO8y7wEKew=="
|
||||||
},
|
},
|
||||||
|
"vue-lazyload": {
|
||||||
|
"version": "1.3.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/vue-lazyload/-/vue-lazyload-1.3.3.tgz",
|
||||||
|
"integrity": "sha512-uHnq0FTEeNmqnbBC2aRKlmtd9LofMZ6Q3mWvgfLa+i9vhxU8fDK+nGs9c1iVT85axSua/AUnMttIq3xPaU9G3A=="
|
||||||
|
},
|
||||||
"vue-loader": {
|
"vue-loader": {
|
||||||
"version": "15.8.3",
|
"version": "15.8.3",
|
||||||
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-15.8.3.tgz",
|
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-15.8.3.tgz",
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"serve": "vue-cli-service serve",
|
"serve": "vue-cli-service serve",
|
||||||
"build": "vue-cli-service build",
|
"build": "find ./dist -maxdepth 1 -mindepth 1 ! -name '.gitignore' -exec rm -r {} + && vue-cli-service build --no-clean",
|
||||||
"watch": "vue-cli-service build --watch",
|
"watch": "find ./dist -maxdepth 1 -mindepth 1 ! -name '.gitignore' -exec rm -r {} + && vue-cli-service build --watch --no-clean",
|
||||||
"lint": "vue-cli-service lint --fix"
|
"lint": "vue-cli-service lint --fix"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -19,8 +19,10 @@
|
|||||||
"normalize.css": "^8.0.1",
|
"normalize.css": "^8.0.1",
|
||||||
"noty": "^3.2.0-beta",
|
"noty": "^3.2.0-beta",
|
||||||
"qrcode.vue": "^1.7.0",
|
"qrcode.vue": "^1.7.0",
|
||||||
|
"utif": "^3.1.0",
|
||||||
"vue": "^2.6.10",
|
"vue": "^2.6.10",
|
||||||
"vue-i18n": "^8.15.3",
|
"vue-i18n": "^8.15.3",
|
||||||
|
"vue-lazyload": "^1.3.3",
|
||||||
"vue-router": "^3.1.3",
|
"vue-router": "^3.1.3",
|
||||||
"vuex": "^3.1.2",
|
"vuex": "^3.1.2",
|
||||||
"vuex-router-sync": "^5.0.0"
|
"vuex-router-sync": "^5.0.0"
|
||||||
|
|||||||
@@ -13,18 +13,19 @@
|
|||||||
|
|
||||||
<link rel="icon" type="image/png" sizes="32x32" href="[{[ .StaticURL ]}]/img/icons/favicon-32x32.png">
|
<link rel="icon" type="image/png" sizes="32x32" href="[{[ .StaticURL ]}]/img/icons/favicon-32x32.png">
|
||||||
<link rel="icon" type="image/png" sizes="16x16" href="[{[ .StaticURL ]}]/img/icons/favicon-16x16.png">
|
<link rel="icon" type="image/png" sizes="16x16" href="[{[ .StaticURL ]}]/img/icons/favicon-16x16.png">
|
||||||
|
|
||||||
<!-- Add to home screen for Android and modern mobile browsers -->
|
<!-- Add to home screen for Android and modern mobile browsers -->
|
||||||
<link rel="manifest" id="manifestPlaceholder" crossorigin="use-credentials">
|
<link rel="manifest" id="manifestPlaceholder" crossorigin="use-credentials">
|
||||||
<meta name="theme-color" content="#2979ff">
|
<meta name="theme-color" content="#2979ff">
|
||||||
|
|
||||||
<!-- Add to home screen for Safari on iOS -->
|
<!-- Add to home screen for Safari on iOS/iPadOS -->
|
||||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||||
<meta name="apple-mobile-web-app-title" content="assets">
|
<meta name="apple-mobile-web-app-title" content="assets">
|
||||||
<link rel="apple-touch-icon" href="[{[ .StaticURL ]}]/img/icons/apple-touch-icon-152x152.png">
|
<link rel="apple-touch-icon" href="[{[ .StaticURL ]}]/img/icons/apple-touch-icon.png">
|
||||||
|
|
||||||
<!-- Add to home screen for Windows -->
|
<!-- Add to home screen for Windows -->
|
||||||
<meta name="msapplication-TileImage" content="[{[ .StaticURL ]}]/img/icons/msapplication-icon-144x144.png">
|
<meta name="msapplication-TileImage" content="[{[ .StaticURL ]}]/img/icons/mstile-144x144.png">
|
||||||
<meta name="msapplication-TileColor" content="#2979ff">
|
<meta name="msapplication-TileColor" content="#2979ff">
|
||||||
|
|
||||||
<!-- Inject Some Variables and generate the manifest json -->
|
<!-- Inject Some Variables and generate the manifest json -->
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
:root {
|
:root {
|
||||||
--background: #121212;
|
--background: #141D24;
|
||||||
--surfacePrimary: #171819;
|
--surfacePrimary: #20292F;
|
||||||
--surfaceSecondary: #212528;
|
--surfaceSecondary: #3A4147;
|
||||||
--divider: rgba(255, 255, 255, 0.12);
|
--divider: rgba(255, 255, 255, 0.12);
|
||||||
--icon: #ffffff;
|
--icon: #ffffff;
|
||||||
--textPrimary: rgba(255, 255, 255, 0.87);
|
--textPrimary: rgba(255, 255, 255, 0.87);
|
||||||
@@ -16,7 +16,7 @@ body {
|
|||||||
#loading {
|
#loading {
|
||||||
background: var(--background);
|
background: var(--background);
|
||||||
}
|
}
|
||||||
#loading .spinner div {
|
#loading .spinner div, #previewer .loading .spinner div {
|
||||||
background: var(--icon);
|
background: var(--icon);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,25 +30,34 @@ header {
|
|||||||
|
|
||||||
#search #input {
|
#search #input {
|
||||||
background: var(--surfaceSecondary);
|
background: var(--surfaceSecondary);
|
||||||
|
border-color: var(--surfacePrimary);
|
||||||
}
|
}
|
||||||
#search.active #input,
|
#search #input input::placeholder {
|
||||||
#search.active .boxes {
|
color: var(--textSecondary);
|
||||||
|
}
|
||||||
|
#search.active #input {
|
||||||
background: var(--surfacePrimary);
|
background: var(--surfacePrimary);
|
||||||
}
|
}
|
||||||
#search.active input {
|
#search.active input {
|
||||||
color: var(--textPrimary);
|
color: var(--textPrimary);
|
||||||
}
|
}
|
||||||
#search.active #result {
|
#search #result {
|
||||||
background: var(--background);
|
background: var(--background);
|
||||||
color: var(--textPrimary);
|
color: var(--textPrimary);
|
||||||
}
|
}
|
||||||
#search.active .boxes h3 {
|
#search .boxes {
|
||||||
|
background: var(--surfaceSecondary);
|
||||||
|
}
|
||||||
|
#search .boxes h3 {
|
||||||
color: var(--textPrimary);
|
color: var(--textPrimary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.action {
|
.action {
|
||||||
color: var(--textPrimary) !important;
|
color: var(--textPrimary) !important;
|
||||||
}
|
}
|
||||||
|
.action:hover {
|
||||||
|
background-color: rgba(255, 255, 255, .1);
|
||||||
|
}
|
||||||
.action i {
|
.action i {
|
||||||
color: var(--icon) !important;
|
color: var(--icon) !important;
|
||||||
}
|
}
|
||||||
@@ -60,13 +69,16 @@ nav > div {
|
|||||||
border-color: var(--divider);
|
border-color: var(--divider);
|
||||||
}
|
}
|
||||||
|
|
||||||
#breadcrumbs {
|
.breadcrumbs {
|
||||||
border-color: var(--divider);
|
border-color: var(--divider);
|
||||||
color: var(--textPrimary) !important;
|
color: var(--textPrimary) !important;
|
||||||
}
|
}
|
||||||
#breadcrumbs span {
|
.breadcrumbs span {
|
||||||
color: var(--textPrimary) !important;
|
color: var(--textPrimary) !important;
|
||||||
}
|
}
|
||||||
|
.breadcrumbs a:hover {
|
||||||
|
background-color: rgba(255, 255, 255, .1);
|
||||||
|
}
|
||||||
|
|
||||||
#listing .item {
|
#listing .item {
|
||||||
background: var(--surfacePrimary);
|
background: var(--surfacePrimary);
|
||||||
@@ -93,6 +105,10 @@ nav > div {
|
|||||||
background: var(--background);
|
background: var(--background);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.message {
|
||||||
|
color: var(--textPrimary);
|
||||||
|
}
|
||||||
|
|
||||||
.card {
|
.card {
|
||||||
background: var(--surfacePrimary);
|
background: var(--surfacePrimary);
|
||||||
color: var(--textPrimary);
|
color: var(--textPrimary);
|
||||||
@@ -101,17 +117,38 @@ nav > div {
|
|||||||
background: var(--surfaceSecondary);
|
background: var(--surfaceSecondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dashboard #nav ul li {
|
||||||
|
color: var(--textSecondary);
|
||||||
|
}
|
||||||
|
.dashboard #nav ul li:hover {
|
||||||
|
background: var(--surfaceSecondary);
|
||||||
|
}
|
||||||
|
|
||||||
.card h3,
|
.card h3,
|
||||||
.dashboard #nav,
|
.dashboard #nav,
|
||||||
.dashboard p label {
|
.dashboard p label {
|
||||||
color: var(--textPrimary);
|
color: var(--textPrimary);
|
||||||
}
|
}
|
||||||
|
.card#share input,
|
||||||
|
.card#share select,
|
||||||
.input {
|
.input {
|
||||||
background: var(--surfaceSecondary);
|
background: var(--surfaceSecondary);
|
||||||
color: var(--textPrimary);
|
color: var(--textPrimary);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.05);
|
||||||
|
}
|
||||||
|
.input:hover,
|
||||||
|
.input:focus {
|
||||||
|
border-color: rgba(255, 255, 255, 0.15);
|
||||||
|
}
|
||||||
|
.input--red {
|
||||||
|
background: #73302D;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dashboard #nav li,
|
.input--green {
|
||||||
|
background: #147A41;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard #nav .wrapper,
|
||||||
.collapsible {
|
.collapsible {
|
||||||
border-color: var(--divider);
|
border-color: var(--divider);
|
||||||
}
|
}
|
||||||
@@ -119,10 +156,35 @@ nav > div {
|
|||||||
color: var(--textPrimary);
|
color: var(--textPrimary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
table th {
|
||||||
|
color: var(--textSecondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-list li:hover {
|
||||||
|
background: var(--surfaceSecondary);
|
||||||
|
}
|
||||||
|
.file-list li:before {
|
||||||
|
color: var(--textSecondary);
|
||||||
|
}
|
||||||
|
.file-list li[aria-selected=true]:before {
|
||||||
|
color: var(--icon);
|
||||||
|
}
|
||||||
|
|
||||||
.shell {
|
.shell {
|
||||||
background: var(--surfacePrimary);
|
background: var(--surfacePrimary);
|
||||||
color: var(--textPrimary);
|
color: var(--textPrimary);
|
||||||
}
|
}
|
||||||
|
.shell__result {
|
||||||
|
border-top: 1px solid var(--divider);
|
||||||
|
}
|
||||||
|
|
||||||
|
#editor-container {
|
||||||
|
background: var(--background);
|
||||||
|
}
|
||||||
|
|
||||||
|
#editor-container .bar {
|
||||||
|
background: var(--surfacePrimary);
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 736px) {
|
@media (max-width: 736px) {
|
||||||
#file-selection {
|
#file-selection {
|
||||||
@@ -138,3 +200,12 @@ nav > div {
|
|||||||
background: var(--surfaceSecondary) !important;
|
background: var(--surfaceSecondary) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.share__box {
|
||||||
|
background: var(--surfacePrimary) !important;
|
||||||
|
color: var(--textPrimary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.share__box__element {
|
||||||
|
border-top-color: var(--divider);
|
||||||
|
}
|
||||||
@@ -43,7 +43,7 @@ async function resourceAction (url, method, content) {
|
|||||||
const res = await fetchURL(`/api/resources${url}`, opts)
|
const res = await fetchURL(`/api/resources${url}`, opts)
|
||||||
|
|
||||||
if (res.status !== 200) {
|
if (res.status !== 200) {
|
||||||
throw new Error(res.responseText)
|
throw new Error(await res.text())
|
||||||
} else {
|
} else {
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
@@ -74,17 +74,25 @@ export function download (format, ...files) {
|
|||||||
url += `/?files=${arg}&`
|
url += `/?files=${arg}&`
|
||||||
}
|
}
|
||||||
|
|
||||||
if (format !== null) {
|
if (format) {
|
||||||
url += `algo=${format}&`
|
url += `algo=${format}&`
|
||||||
}
|
}
|
||||||
|
|
||||||
url += `auth=${store.state.jwt}`
|
if (store.state.jwt){
|
||||||
|
url += `auth=${store.state.jwt}&`
|
||||||
|
}
|
||||||
|
|
||||||
window.open(url)
|
window.open(url)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function post (url, content = '', overwrite = false, onupload) {
|
export async function post (url, content = '', overwrite = false, onupload) {
|
||||||
url = removePrefix(url)
|
url = removePrefix(url)
|
||||||
|
|
||||||
|
let bufferContent
|
||||||
|
if (content instanceof Blob && !['http:', 'https:'].includes(window.location.protocol)) {
|
||||||
|
bufferContent = await new Response(content).arrayBuffer()
|
||||||
|
}
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let request = new XMLHttpRequest()
|
let request = new XMLHttpRequest()
|
||||||
request.open('POST', `${baseURL}/api/resources${url}?override=${overwrite}`, true)
|
request.open('POST', `${baseURL}/api/resources${url}?override=${overwrite}`, true)
|
||||||
@@ -94,9 +102,6 @@ export async function post (url, content = '', overwrite = false, onupload) {
|
|||||||
request.upload.onprogress = onupload
|
request.upload.onprogress = onupload
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send a message to user before closing the tab during file upload
|
|
||||||
window.onbeforeunload = () => "Files are being uploaded."
|
|
||||||
|
|
||||||
request.onload = () => {
|
request.onload = () => {
|
||||||
if (request.status === 200) {
|
if (request.status === 200) {
|
||||||
resolve(request.responseText)
|
resolve(request.responseText)
|
||||||
@@ -111,30 +116,29 @@ export async function post (url, content = '', overwrite = false, onupload) {
|
|||||||
reject(error)
|
reject(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
request.send(content)
|
request.send(bufferContent || content)
|
||||||
// Upload is done no more message before closing the tab
|
})
|
||||||
}).finally(() => { window.onbeforeunload = null })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function moveCopy (items, copy = false) {
|
function moveCopy (items, copy = false, overwrite = false, rename = false) {
|
||||||
let promises = []
|
let promises = []
|
||||||
|
|
||||||
for (let item of items) {
|
for (let item of items) {
|
||||||
const from = removePrefix(item.from)
|
const from = item.from
|
||||||
const to = encodeURIComponent(removePrefix(item.to))
|
const to = encodeURIComponent(removePrefix(item.to))
|
||||||
const url = `${from}?action=${copy ? 'copy' : 'rename'}&destination=${to}`
|
const url = `${from}?action=${copy ? 'copy' : 'rename'}&destination=${to}&override=${overwrite}&rename=${rename}`
|
||||||
promises.push(resourceAction(url, 'PATCH'))
|
promises.push(resourceAction(url, 'PATCH'))
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.all(promises)
|
return Promise.all(promises)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function move (items) {
|
export function move (items, overwrite = false, rename = false) {
|
||||||
return moveCopy(items)
|
return moveCopy(items, false, overwrite, rename)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function copy (items) {
|
export function copy (items, overwrite = false, rename = false) {
|
||||||
return moveCopy(items, true)
|
return moveCopy(items, true, overwrite, rename)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function checksum (url, algo) {
|
export async function checksum (url, algo) {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import * as files from './files'
|
|||||||
import * as share from './share'
|
import * as share from './share'
|
||||||
import * as users from './users'
|
import * as users from './users'
|
||||||
import * as settings from './settings'
|
import * as settings from './settings'
|
||||||
|
import * as pub from './pub'
|
||||||
import search from './search'
|
import search from './search'
|
||||||
import commands from './commands'
|
import commands from './commands'
|
||||||
|
|
||||||
@@ -10,6 +11,7 @@ export {
|
|||||||
share,
|
share,
|
||||||
users,
|
users,
|
||||||
settings,
|
settings,
|
||||||
|
pub,
|
||||||
commands,
|
commands,
|
||||||
search
|
search
|
||||||
}
|
}
|
||||||
|
|||||||
61
frontend/src/api/pub.js
Normal file
61
frontend/src/api/pub.js
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
import { fetchURL, removePrefix } from './utils'
|
||||||
|
import { baseURL } from '@/utils/constants'
|
||||||
|
|
||||||
|
export async function fetch (url, password = "") {
|
||||||
|
url = removePrefix(url)
|
||||||
|
|
||||||
|
const res = await fetchURL(`/api/public/share${url}`, {
|
||||||
|
headers: {'X-SHARE-PASSWORD': password},
|
||||||
|
})
|
||||||
|
|
||||||
|
if (res.status === 200) {
|
||||||
|
let data = await res.json()
|
||||||
|
data.url = `/share${url}`
|
||||||
|
|
||||||
|
if (data.isDir) {
|
||||||
|
if (!data.url.endsWith('/')) data.url += '/'
|
||||||
|
data.items = data.items.map((item, index) => {
|
||||||
|
item.index = index
|
||||||
|
item.url = `${data.url}${encodeURIComponent(item.name)}`
|
||||||
|
|
||||||
|
if (item.isDir) {
|
||||||
|
item.url += '/'
|
||||||
|
}
|
||||||
|
|
||||||
|
return item
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return data
|
||||||
|
} else {
|
||||||
|
throw new Error(res.status)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function download(format, hash, token, ...files) {
|
||||||
|
let url = `${baseURL}/api/public/dl/${hash}`
|
||||||
|
|
||||||
|
if (files.length === 1) {
|
||||||
|
url += encodeURIComponent(files[0]) + '?'
|
||||||
|
} else {
|
||||||
|
let arg = ''
|
||||||
|
|
||||||
|
for (let file of files) {
|
||||||
|
arg += encodeURIComponent(file) + ','
|
||||||
|
}
|
||||||
|
|
||||||
|
arg = arg.substring(0, arg.length - 1)
|
||||||
|
arg = encodeURIComponent(arg)
|
||||||
|
url += `/?files=${arg}&`
|
||||||
|
}
|
||||||
|
|
||||||
|
if (format) {
|
||||||
|
url += `algo=${format}&`
|
||||||
|
}
|
||||||
|
|
||||||
|
if (token) {
|
||||||
|
url += `token=${token}&`
|
||||||
|
}
|
||||||
|
|
||||||
|
window.open(url)
|
||||||
|
}
|
||||||
@@ -1,8 +1,31 @@
|
|||||||
import { fetchJSON, removePrefix } from './utils'
|
import { fetchURL, removePrefix } from './utils'
|
||||||
|
import url from '../utils/url'
|
||||||
|
|
||||||
export default async function search (url, query) {
|
export default async function search (base, query) {
|
||||||
url = removePrefix(url)
|
base = removePrefix(base)
|
||||||
query = encodeURIComponent(query)
|
query = encodeURIComponent(query)
|
||||||
|
|
||||||
return fetchJSON(`/api/search${url}?query=${query}`, {})
|
if (!base.endsWith('/')) {
|
||||||
|
base += '/'
|
||||||
|
}
|
||||||
|
|
||||||
|
let res = await fetchURL(`/api/search${base}?query=${query}`, {})
|
||||||
|
|
||||||
|
if (res.status === 200) {
|
||||||
|
let data = await res.json()
|
||||||
|
|
||||||
|
data = data.map((item) => {
|
||||||
|
item.url = `/files${base}` + url.encodePath(item.path)
|
||||||
|
|
||||||
|
if (item.dir) {
|
||||||
|
item.url += '/'
|
||||||
|
}
|
||||||
|
|
||||||
|
return item
|
||||||
|
})
|
||||||
|
|
||||||
|
return data
|
||||||
|
} else {
|
||||||
|
throw Error(res.status)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { fetchURL, fetchJSON, removePrefix } from './utils'
|
import { fetchURL, fetchJSON, removePrefix } from './utils'
|
||||||
|
|
||||||
export async function getHash(hash) {
|
export async function list() {
|
||||||
return fetchJSON(`/api/public/share/${hash}`)
|
return fetchJSON('/api/shares')
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function get(url) {
|
export async function get(url) {
|
||||||
@@ -19,14 +19,18 @@ export async function remove(hash) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function create(url, expires = '', unit = 'hours') {
|
export async function create(url, password = '', expires = '', unit = 'hours') {
|
||||||
url = removePrefix(url)
|
url = removePrefix(url)
|
||||||
url = `/api/share${url}`
|
url = `/api/share${url}`
|
||||||
if (expires !== '') {
|
if (expires !== '') {
|
||||||
url += `?expires=${expires}&unit=${unit}`
|
url += `?expires=${expires}&unit=${unit}`
|
||||||
}
|
}
|
||||||
|
let body = '{}';
|
||||||
|
if (password != '' || expires !== '' || unit !== 'hours') {
|
||||||
|
body = JSON.stringify({password: password, expires: expires, unit: unit})
|
||||||
|
}
|
||||||
return fetchJSON(url, {
|
return fetchJSON(url, {
|
||||||
method: 'POST'
|
method: 'POST',
|
||||||
|
body: body,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,9 +34,7 @@ export async function fetchJSON (url, opts) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function removePrefix (url) {
|
export function removePrefix (url) {
|
||||||
if (url.startsWith('/files')) {
|
url = url.split('/').splice(2).join('/')
|
||||||
url = url.slice(6)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (url === '') url = '/'
|
if (url === '') url = '/'
|
||||||
if (url[0] !== '/') url = '/' + url
|
if (url[0] !== '/') url = '/' + url
|
||||||
|
|||||||
67
frontend/src/components/Breadcrumbs.vue
Normal file
67
frontend/src/components/Breadcrumbs.vue
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
<template>
|
||||||
|
<div class="breadcrumbs">
|
||||||
|
<component :is="element" :to="base || ''" :aria-label="$t('files.home')" :title="$t('files.home')">
|
||||||
|
<i class="material-icons">home</i>
|
||||||
|
</component>
|
||||||
|
|
||||||
|
<span v-for="(link, index) in items" :key="index">
|
||||||
|
<span class="chevron"><i class="material-icons">keyboard_arrow_right</i></span>
|
||||||
|
<component :is="element" :to="link.url">{{ link.name }}</component>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'breadcrumbs',
|
||||||
|
props: [
|
||||||
|
'base',
|
||||||
|
'noLink'
|
||||||
|
],
|
||||||
|
computed: {
|
||||||
|
items () {
|
||||||
|
const relativePath = this.$route.path.replace(this.base, '')
|
||||||
|
let parts = relativePath.split('/')
|
||||||
|
|
||||||
|
if (parts[0] === '') {
|
||||||
|
parts.shift()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parts[parts.length - 1] === '') {
|
||||||
|
parts.pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
let breadcrumbs = []
|
||||||
|
|
||||||
|
for (let i = 0; i < parts.length; i++) {
|
||||||
|
if (i === 0) {
|
||||||
|
breadcrumbs.push({ name: decodeURIComponent(parts[i]), url: this.base + '/' + parts[i] + '/' })
|
||||||
|
} else {
|
||||||
|
breadcrumbs.push({ name: decodeURIComponent(parts[i]), url: breadcrumbs[i - 1].url + parts[i] + '/' })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (breadcrumbs.length > 3) {
|
||||||
|
while (breadcrumbs.length !== 4) {
|
||||||
|
breadcrumbs.shift()
|
||||||
|
}
|
||||||
|
|
||||||
|
breadcrumbs[0].name = '...'
|
||||||
|
}
|
||||||
|
|
||||||
|
return breadcrumbs
|
||||||
|
},
|
||||||
|
element () {
|
||||||
|
if (this.noLink !== undefined) {
|
||||||
|
return 'span'
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'router-link'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
</style>
|
||||||
@@ -1,189 +0,0 @@
|
|||||||
<template>
|
|
||||||
<header>
|
|
||||||
<div>
|
|
||||||
<button @click="openSidebar" :aria-label="$t('buttons.toggleSidebar')" :title="$t('buttons.toggleSidebar')" class="action">
|
|
||||||
<i class="material-icons">menu</i>
|
|
||||||
</button>
|
|
||||||
<img :src="logoURL" alt="File Browser">
|
|
||||||
<search v-if="isLogged"></search>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<template v-if="isLogged">
|
|
||||||
<button @click="openSearch" :aria-label="$t('buttons.search')" :title="$t('buttons.search')" class="search-button action">
|
|
||||||
<i class="material-icons">search</i>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button v-show="showSaveButton" :aria-label="$t('buttons.save')" :title="$t('buttons.save')" class="action" id="save-button">
|
|
||||||
<i class="material-icons">save</i>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button @click="openMore" id="more" :aria-label="$t('buttons.more')" :title="$t('buttons.more')" class="action">
|
|
||||||
<i class="material-icons">more_vert</i>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<!-- Menu that shows on listing AND mobile when there are files selected -->
|
|
||||||
<div id="file-selection" v-if="isMobile && isListing">
|
|
||||||
<span v-if="selectedCount > 0">{{ selectedCount }} selected</span>
|
|
||||||
<share-button v-show="showShareButton"></share-button>
|
|
||||||
<rename-button v-show="showRenameButton"></rename-button>
|
|
||||||
<copy-button v-show="showCopyButton"></copy-button>
|
|
||||||
<move-button v-show="showMoveButton"></move-button>
|
|
||||||
<delete-button v-show="showDeleteButton"></delete-button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- This buttons are shown on a dropdown on mobile phones -->
|
|
||||||
<div id="dropdown" :class="{ active: showMore }">
|
|
||||||
<div v-if="!isListing || !isMobile">
|
|
||||||
<share-button v-show="showShareButton"></share-button>
|
|
||||||
<rename-button v-show="showRenameButton"></rename-button>
|
|
||||||
<copy-button v-show="showCopyButton"></copy-button>
|
|
||||||
<move-button v-show="showMoveButton"></move-button>
|
|
||||||
<delete-button v-show="showDeleteButton"></delete-button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<shell-button v-show="user.perm.execute" />
|
|
||||||
<switch-button v-show="isListing"></switch-button>
|
|
||||||
<download-button v-show="showDownloadButton"></download-button>
|
|
||||||
<upload-button v-show="showUpload"></upload-button>
|
|
||||||
<info-button v-show="isFiles"></info-button>
|
|
||||||
|
|
||||||
<button v-show="isListing" @click="toggleMultipleSelection" :aria-label="$t('buttons.selectMultiple')" :title="$t('buttons.selectMultiple')" class="action" >
|
|
||||||
<i class="material-icons">check_circle</i>
|
|
||||||
<span>{{ $t('buttons.select') }}</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<div v-show="showOverlay" @click="resetPrompts" class="overlay"></div>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import Search from './Search'
|
|
||||||
import InfoButton from './buttons/Info'
|
|
||||||
import DeleteButton from './buttons/Delete'
|
|
||||||
import RenameButton from './buttons/Rename'
|
|
||||||
import UploadButton from './buttons/Upload'
|
|
||||||
import DownloadButton from './buttons/Download'
|
|
||||||
import SwitchButton from './buttons/SwitchView'
|
|
||||||
import MoveButton from './buttons/Move'
|
|
||||||
import CopyButton from './buttons/Copy'
|
|
||||||
import ShareButton from './buttons/Share'
|
|
||||||
import ShellButton from './buttons/Shell'
|
|
||||||
import {mapGetters, mapState} from 'vuex'
|
|
||||||
import { logoURL } from '@/utils/constants'
|
|
||||||
import * as api from '@/api'
|
|
||||||
import buttons from '@/utils/buttons'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'header-layout',
|
|
||||||
components: {
|
|
||||||
Search,
|
|
||||||
InfoButton,
|
|
||||||
DeleteButton,
|
|
||||||
ShareButton,
|
|
||||||
RenameButton,
|
|
||||||
DownloadButton,
|
|
||||||
CopyButton,
|
|
||||||
UploadButton,
|
|
||||||
SwitchButton,
|
|
||||||
MoveButton,
|
|
||||||
ShellButton
|
|
||||||
},
|
|
||||||
data: function () {
|
|
||||||
return {
|
|
||||||
width: window.innerWidth,
|
|
||||||
pluginData: {
|
|
||||||
api,
|
|
||||||
buttons,
|
|
||||||
'store': this.$store,
|
|
||||||
'router': this.$router
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
created () {
|
|
||||||
window.addEventListener('resize', () => {
|
|
||||||
this.width = window.innerWidth
|
|
||||||
})
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
...mapGetters([
|
|
||||||
'selectedCount',
|
|
||||||
'isFiles',
|
|
||||||
'isEditor',
|
|
||||||
'isListing',
|
|
||||||
'isLogged'
|
|
||||||
]),
|
|
||||||
...mapState([
|
|
||||||
'req',
|
|
||||||
'user',
|
|
||||||
'loading',
|
|
||||||
'reload',
|
|
||||||
'multiple'
|
|
||||||
]),
|
|
||||||
logoURL: () => logoURL,
|
|
||||||
isMobile () {
|
|
||||||
return this.width <= 736
|
|
||||||
},
|
|
||||||
showUpload () {
|
|
||||||
return this.isListing && this.user.perm.create
|
|
||||||
},
|
|
||||||
showSaveButton () {
|
|
||||||
return this.isEditor && this.user.perm.modify
|
|
||||||
},
|
|
||||||
showDownloadButton () {
|
|
||||||
return this.isFiles && this.user.perm.download
|
|
||||||
},
|
|
||||||
showDeleteButton () {
|
|
||||||
return this.isFiles && (this.isListing
|
|
||||||
? (this.selectedCount !== 0 && this.user.perm.delete)
|
|
||||||
: this.user.perm.delete)
|
|
||||||
},
|
|
||||||
showRenameButton () {
|
|
||||||
return this.isFiles && (this.isListing
|
|
||||||
? (this.selectedCount === 1 && this.user.perm.rename)
|
|
||||||
: this.user.perm.rename)
|
|
||||||
},
|
|
||||||
showShareButton () {
|
|
||||||
return this.isFiles && (this.isListing
|
|
||||||
? (this.selectedCount === 1 && this.user.perm.share)
|
|
||||||
: this.user.perm.share)
|
|
||||||
},
|
|
||||||
showMoveButton () {
|
|
||||||
return this.isFiles && (this.isListing
|
|
||||||
? (this.selectedCount > 0 && this.user.perm.rename)
|
|
||||||
: this.user.perm.rename)
|
|
||||||
},
|
|
||||||
showCopyButton () {
|
|
||||||
return this.isFiles && (this.isListing
|
|
||||||
? (this.selectedCount > 0 && this.user.perm.create)
|
|
||||||
: this.user.perm.create)
|
|
||||||
},
|
|
||||||
showMore () {
|
|
||||||
return this.isFiles && this.$store.state.show === 'more'
|
|
||||||
},
|
|
||||||
showOverlay () {
|
|
||||||
return this.showMore
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
openSidebar () {
|
|
||||||
this.$store.commit('showHover', 'sidebar')
|
|
||||||
},
|
|
||||||
openMore () {
|
|
||||||
this.$store.commit('showHover', 'more')
|
|
||||||
},
|
|
||||||
openSearch () {
|
|
||||||
this.$store.commit('showHover', 'search')
|
|
||||||
},
|
|
||||||
toggleMultipleSelection () {
|
|
||||||
this.$store.commit('multiple', !this.multiple)
|
|
||||||
this.resetPrompts()
|
|
||||||
},
|
|
||||||
resetPrompts () {
|
|
||||||
this.$store.commit('closeHovers')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@@ -49,7 +49,7 @@
|
|||||||
</template>
|
</template>
|
||||||
<ul v-show="results.length > 0">
|
<ul v-show="results.length > 0">
|
||||||
<li v-for="(s,k) in filteredResults" :key="k">
|
<li v-for="(s,k) in filteredResults" :key="k">
|
||||||
<router-link @click.native="close" :to="'./' + s.path">
|
<router-link @click.native="close" :to="s.url">
|
||||||
<i v-if="s.dir" class="material-icons">folder</i>
|
<i v-if="s.dir" class="material-icons">folder</i>
|
||||||
<i v-else class="material-icons">insert_drive_file</i>
|
<i v-else class="material-icons">insert_drive_file</i>
|
||||||
<span>./{{ s.path }}</span>
|
<span>./{{ s.path }}</span>
|
||||||
@@ -136,12 +136,6 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
window.addEventListener("keydown", event => {
|
|
||||||
if (event.keyCode === 27) {
|
|
||||||
this.closeHovers()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
this.$refs.result.addEventListener('scroll', event => {
|
this.$refs.result.addEventListener('scroll', event => {
|
||||||
if (event.target.offsetHeight + event.target.scrollTop >= event.target.scrollHeight - 100) {
|
if (event.target.offsetHeight + event.target.scrollTop >= event.target.scrollHeight - 100) {
|
||||||
this.resultsCount += 50
|
this.resultsCount += 50
|
||||||
@@ -189,8 +183,12 @@ export default {
|
|||||||
|
|
||||||
this.ongoing = true
|
this.ongoing = true
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.results = await search(path, this.value)
|
||||||
|
} catch (error) {
|
||||||
|
this.$showError(error)
|
||||||
|
}
|
||||||
|
|
||||||
this.results = await search(path, this.value)
|
|
||||||
this.ongoing = false
|
this.ongoing = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
<template>
|
|
||||||
<button @click="show" :aria-label="$t('buttons.copy')" :title="$t('buttons.copy')" class="action" id="copy-button">
|
|
||||||
<i class="material-icons">content_copy</i>
|
|
||||||
<span>{{ $t('buttons.copyFile') }}</span>
|
|
||||||
</button>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: 'copy-button',
|
|
||||||
methods: {
|
|
||||||
show: function () {
|
|
||||||
this.$store.commit('showHover', 'copy')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
<template>
|
|
||||||
<button @click="show" :aria-label="$t('buttons.delete')" :title="$t('buttons.delete')" class="action" id="delete-button">
|
|
||||||
<i class="material-icons">delete</i>
|
|
||||||
<span>{{ $t('buttons.delete') }}</span>
|
|
||||||
</button>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: 'delete-button',
|
|
||||||
methods: {
|
|
||||||
show: function () {
|
|
||||||
this.$store.commit('showHover', 'delete')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
<template>
|
|
||||||
<button @click="download" :aria-label="$t('buttons.download')" :title="$t('buttons.download')" id="download-button" class="action">
|
|
||||||
<i class="material-icons">file_download</i>
|
|
||||||
<span>{{ $t('buttons.download') }}</span>
|
|
||||||
<span v-if="selectedCount > 0" class="counter">{{ selectedCount }}</span>
|
|
||||||
</button>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import {mapGetters, mapState} from 'vuex'
|
|
||||||
import { files as api } from '@/api'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'download-button',
|
|
||||||
computed: {
|
|
||||||
...mapState(['req', 'selected']),
|
|
||||||
...mapGetters(['isListing', 'selectedCount'])
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
download: function () {
|
|
||||||
if (!this.isListing) {
|
|
||||||
api.download(null, this.$route.path)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.selectedCount === 1 && !this.req.items[this.selected[0]].isDir) {
|
|
||||||
api.download(null, this.req.items[this.selected[0]].url)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
this.$store.commit('showHover', 'download')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
<template>
|
|
||||||
<button :title="$t('buttons.info')" :aria-label="$t('buttons.info')" class="action" @click="show">
|
|
||||||
<i class="material-icons">info</i>
|
|
||||||
<span>{{ $t('buttons.info') }}</span>
|
|
||||||
</button>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: 'info-button',
|
|
||||||
methods: {
|
|
||||||
show: function () {
|
|
||||||
this.$store.commit('showHover', 'info')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
<template>
|
|
||||||
<button @click="show" :aria-label="$t('buttons.move')" :title="$t('buttons.move')" class="action" id="move-button">
|
|
||||||
<i class="material-icons">forward</i>
|
|
||||||
<span>{{ $t('buttons.moveFile') }}</span>
|
|
||||||
</button>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: 'move-button',
|
|
||||||
methods: {
|
|
||||||
show: function () {
|
|
||||||
this.$store.commit('showHover', 'move')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
<template>
|
|
||||||
<button @click="show" :aria-label="$t('buttons.rename')" :title="$t('buttons.rename')" class="action" id="rename-button">
|
|
||||||
<i class="material-icons">mode_edit</i>
|
|
||||||
<span>{{ $t('buttons.rename') }}</span>
|
|
||||||
</button>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: 'rename-button',
|
|
||||||
methods: {
|
|
||||||
show: function () {
|
|
||||||
this.$store.commit('showHover', 'rename')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
<template>
|
|
||||||
<button @click="show" :aria-label="$t('buttons.share')" :title="$t('buttons.share')" class="action">
|
|
||||||
<i class="material-icons">share</i>
|
|
||||||
<span>{{ $t('buttons.share') }}</span>
|
|
||||||
</button>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: 'share-button',
|
|
||||||
methods: {
|
|
||||||
show () {
|
|
||||||
this.$store.commit('showHover', 'share')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
<template>
|
|
||||||
<button @click="show" :aria-label="$t('buttons.shell')" :title="$t('buttons.shell')" class="action">
|
|
||||||
<i class="material-icons">code</i>
|
|
||||||
<span>{{ $t('buttons.shell') }}</span>
|
|
||||||
</button>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: 'shell-button',
|
|
||||||
methods: {
|
|
||||||
show: function () {
|
|
||||||
this.$store.commit('toggleShell')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
<template>
|
|
||||||
<button @click="change" :aria-label="$t('buttons.switchView')" :title="$t('buttons.switchView')" class="action" id="switch-view-button">
|
|
||||||
<i class="material-icons">{{ icon }}</i>
|
|
||||||
<span>{{ $t('buttons.switchView') }}</span>
|
|
||||||
</button>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { mapState, mapMutations } from 'vuex'
|
|
||||||
import { users as api } from '@/api'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'switch-button',
|
|
||||||
computed: {
|
|
||||||
...mapState(['user']),
|
|
||||||
icon: function () {
|
|
||||||
if (this.user.viewMode === 'mosaic') return 'view_list'
|
|
||||||
return 'view_module'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
...mapMutations([ 'updateUser', 'closeHovers' ]),
|
|
||||||
change: async function () {
|
|
||||||
this.closeHovers()
|
|
||||||
|
|
||||||
const data = {
|
|
||||||
id: this.user.id,
|
|
||||||
viewMode: (this.icon === 'view_list') ? 'list' : 'mosaic'
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
await api.update(data, ['viewMode'])
|
|
||||||
this.updateUser(data)
|
|
||||||
} catch (e) {
|
|
||||||
this.$showError(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
<template>
|
|
||||||
<button @click="upload" :aria-label="$t('buttons.upload')" :title="$t('buttons.upload')" class="action" id="upload-button">
|
|
||||||
<i class="material-icons">file_upload</i>
|
|
||||||
<span>{{ $t('buttons.upload') }}</span>
|
|
||||||
</button>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: 'upload-button',
|
|
||||||
methods: {
|
|
||||||
upload: function () {
|
|
||||||
if (typeof(DataTransferItem.prototype.webkitGetAsEntry) !== 'undefined') {
|
|
||||||
this.$store.commit('showHover', 'upload')
|
|
||||||
} else {
|
|
||||||
document.getElementById('upload-input').click();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@@ -10,10 +10,13 @@
|
|||||||
@mouseup="mouseUp"
|
@mouseup="mouseUp"
|
||||||
@wheel="wheelMove"
|
@wheel="wheelMove"
|
||||||
>
|
>
|
||||||
<img :src="src" class="image-ex-img" ref="imgex" @load="setCenter">
|
<img src="" class="image-ex-img image-ex-img-center" ref="imgex" @load="onLoad">
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
|
import throttle from 'lodash.throttle'
|
||||||
|
import UTIF from 'utif'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
src: String,
|
src: String,
|
||||||
@@ -50,10 +53,18 @@ export default {
|
|||||||
inDrag: false,
|
inDrag: false,
|
||||||
lastTouchDistance: 0,
|
lastTouchDistance: 0,
|
||||||
moveDisabled: false,
|
moveDisabled: false,
|
||||||
disabledTimer: null
|
disabledTimer: null,
|
||||||
|
imageLoaded: false,
|
||||||
|
position: {
|
||||||
|
center: { x: 0, y: 0 },
|
||||||
|
relative: { x: 0, y: 0 }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
if (!this.decodeUTIF()) {
|
||||||
|
this.$refs.imgex.src = this.src
|
||||||
|
}
|
||||||
let container = this.$refs.container
|
let container = this.$refs.container
|
||||||
this.classList.forEach(className => container.classList.add(className))
|
this.classList.forEach(className => container.classList.add(className))
|
||||||
// set width and height if they are zero
|
// set width and height if they are zero
|
||||||
@@ -63,24 +74,68 @@ export default {
|
|||||||
if (getComputedStyle(container).height === "0px") {
|
if (getComputedStyle(container).height === "0px") {
|
||||||
container.style.height = "100%"
|
container.style.height = "100%"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window.addEventListener('resize', this.onResize)
|
||||||
|
},
|
||||||
|
beforeDestroy () {
|
||||||
|
window.removeEventListener('resize', this.onResize)
|
||||||
|
document.removeEventListener('mouseup', this.onMouseUp)
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
src: function () {
|
||||||
|
this.scale = 1
|
||||||
|
this.setZoom()
|
||||||
|
this.setCenter()
|
||||||
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
// Modified from UTIF.replaceIMG
|
||||||
|
decodeUTIF() {
|
||||||
|
const sufs = ["tif", "tiff", "dng", "cr2", "nef"]
|
||||||
|
let suff = document.location.pathname.split(".").pop().toLowerCase()
|
||||||
|
if (sufs.indexOf(suff) == -1) return false
|
||||||
|
let xhr = new XMLHttpRequest()
|
||||||
|
UTIF._xhrs.push(xhr)
|
||||||
|
UTIF._imgs.push(this.$refs.imgex)
|
||||||
|
xhr.open("GET", this.src)
|
||||||
|
xhr.responseType = "arraybuffer"
|
||||||
|
xhr.onload = UTIF._imgLoaded
|
||||||
|
xhr.send()
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
onLoad() {
|
||||||
|
let img = this.$refs.imgex
|
||||||
|
|
||||||
|
this.imageLoaded = true
|
||||||
|
|
||||||
|
if (img === undefined) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
img.classList.remove('image-ex-img-center')
|
||||||
|
this.setCenter()
|
||||||
|
img.classList.add('image-ex-img-ready')
|
||||||
|
|
||||||
|
document.addEventListener('mouseup', this.onMouseUp)
|
||||||
|
},
|
||||||
|
onMouseUp() {
|
||||||
|
this.inDrag = false
|
||||||
|
},
|
||||||
|
onResize: throttle(function() {
|
||||||
|
if (this.imageLoaded) {
|
||||||
|
this.setCenter()
|
||||||
|
this.doMove(this.position.relative.x, this.position.relative.y)
|
||||||
|
}
|
||||||
|
}, 100),
|
||||||
setCenter() {
|
setCenter() {
|
||||||
let container = this.$refs.container
|
let container = this.$refs.container
|
||||||
let img = this.$refs.imgex
|
let img = this.$refs.imgex
|
||||||
|
|
||||||
let rate = Math.min(
|
this.position.center.x = Math.floor((container.clientWidth - img.clientWidth) / 2)
|
||||||
container.clientWidth / img.clientWidth,
|
this.position.center.y = Math.floor((container.clientHeight - img.clientHeight) / 2)
|
||||||
container.clientHeight / img.clientHeight
|
|
||||||
)
|
img.style.left = this.position.center.x + 'px'
|
||||||
if (!this.autofill && rate > 1) {
|
img.style.top = this.position.center.y + 'px'
|
||||||
rate = 1
|
|
||||||
}
|
|
||||||
// height will be auto set
|
|
||||||
img.width = Math.floor(img.clientWidth * rate)
|
|
||||||
img.style.top = `${Math.floor((container.clientHeight - img.clientHeight) / 2)}px`
|
|
||||||
img.style.left = `${Math.floor((container.clientWidth - img.clientWidth) / 2)}px`
|
|
||||||
document.addEventListener('mouseup', () => this.inDrag = false )
|
|
||||||
},
|
},
|
||||||
mousedownStart(event) {
|
mousedownStart(event) {
|
||||||
this.lastX = null
|
this.lastX = null
|
||||||
@@ -101,6 +156,15 @@ export default {
|
|||||||
this.lastX = null
|
this.lastX = null
|
||||||
this.lastY = null
|
this.lastY = null
|
||||||
this.lastTouchDistance = null
|
this.lastTouchDistance = null
|
||||||
|
if (event.targetTouches.length < 2) {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.touches = 0
|
||||||
|
}, 300)
|
||||||
|
this.touches++
|
||||||
|
if (this.touches > 1) {
|
||||||
|
this.zoomAuto(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
},
|
},
|
||||||
zoomAuto(event) {
|
zoomAuto(event) {
|
||||||
@@ -114,6 +178,7 @@ export default {
|
|||||||
default:
|
default:
|
||||||
case 4:
|
case 4:
|
||||||
this.scale = 1
|
this.scale = 1
|
||||||
|
this.setCenter()
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
this.setZoom()
|
this.setZoom()
|
||||||
@@ -159,8 +224,22 @@ export default {
|
|||||||
},
|
},
|
||||||
doMove(x, y) {
|
doMove(x, y) {
|
||||||
let style = this.$refs.imgex.style
|
let style = this.$refs.imgex.style
|
||||||
style.left = `${this.pxStringToNumber(style.left) + x}px`
|
let posX = this.pxStringToNumber(style.left) + x
|
||||||
style.top = `${this.pxStringToNumber(style.top) + y}px`
|
let posY = this.pxStringToNumber(style.top) + y
|
||||||
|
|
||||||
|
style.left = posX + 'px'
|
||||||
|
style.top = posY + 'px'
|
||||||
|
|
||||||
|
this.position.relative.x = Math.abs(this.position.center.x - posX)
|
||||||
|
this.position.relative.y = Math.abs(this.position.center.y - posY)
|
||||||
|
|
||||||
|
if (posX < this.position.center.x) {
|
||||||
|
this.position.relative.x = this.position.relative.x * -1
|
||||||
|
}
|
||||||
|
|
||||||
|
if (posY < this.position.center.y) {
|
||||||
|
this.position.relative.y = this.position.relative.y * -1
|
||||||
|
}
|
||||||
},
|
},
|
||||||
wheelMove(event) {
|
wheelMove(event) {
|
||||||
this.scale += (event.wheelDeltaY / 100) * this.zoomStep
|
this.scale += (event.wheelDeltaY / 100) * this.zoomStep
|
||||||
@@ -185,9 +264,20 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.image-ex-img {
|
.image-ex-img {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-ex-img-center {
|
||||||
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
position: absolute;
|
||||||
|
transition: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-ex-img-ready {
|
||||||
left: 0;
|
left: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
position: absolute;
|
|
||||||
transition: transform 0.1s ease;
|
transition: transform 0.1s ease;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,578 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div v-if="(req.numDirs + req.numFiles) == 0">
|
|
||||||
<h2 class="message">
|
|
||||||
<i class="material-icons">sentiment_dissatisfied</i>
|
|
||||||
<span>{{ $t('files.lonely') }}</span>
|
|
||||||
</h2>
|
|
||||||
<input style="display:none" type="file" id="upload-input" @change="uploadInput($event)" multiple>
|
|
||||||
<input style="display:none" type="file" id="upload-folder-input" @change="uploadInput($event)" webkitdirectory multiple>
|
|
||||||
</div>
|
|
||||||
<div v-else id="listing"
|
|
||||||
:class="user.viewMode"
|
|
||||||
@dragenter="dragEnter"
|
|
||||||
@dragend="dragEnd">
|
|
||||||
<div>
|
|
||||||
<div class="item header">
|
|
||||||
<div></div>
|
|
||||||
<div>
|
|
||||||
<p :class="{ active: nameSorted }" class="name"
|
|
||||||
role="button"
|
|
||||||
tabindex="0"
|
|
||||||
@click="sort('name')"
|
|
||||||
:title="$t('files.sortByName')"
|
|
||||||
:aria-label="$t('files.sortByName')">
|
|
||||||
<span>{{ $t('files.name') }}</span>
|
|
||||||
<i class="material-icons">{{ nameIcon }}</i>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p :class="{ active: sizeSorted }" class="size"
|
|
||||||
role="button"
|
|
||||||
tabindex="0"
|
|
||||||
@click="sort('size')"
|
|
||||||
:title="$t('files.sortBySize')"
|
|
||||||
:aria-label="$t('files.sortBySize')">
|
|
||||||
<span>{{ $t('files.size') }}</span>
|
|
||||||
<i class="material-icons">{{ sizeIcon }}</i>
|
|
||||||
</p>
|
|
||||||
<p :class="{ active: modifiedSorted }" class="modified"
|
|
||||||
role="button"
|
|
||||||
tabindex="0"
|
|
||||||
@click="sort('modified')"
|
|
||||||
:title="$t('files.sortByLastModified')"
|
|
||||||
:aria-label="$t('files.sortByLastModified')">
|
|
||||||
<span>{{ $t('files.lastModified') }}</span>
|
|
||||||
<i class="material-icons">{{ modifiedIcon }}</i>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h2 v-if="req.numDirs > 0">{{ $t('files.folders') }}</h2>
|
|
||||||
<div v-if="req.numDirs > 0">
|
|
||||||
<item v-for="(item) in dirs"
|
|
||||||
:key="base64(item.name)"
|
|
||||||
v-bind:index="item.index"
|
|
||||||
v-bind:name="item.name"
|
|
||||||
v-bind:isDir="item.isDir"
|
|
||||||
v-bind:url="item.url"
|
|
||||||
v-bind:modified="item.modified"
|
|
||||||
v-bind:type="item.type"
|
|
||||||
v-bind:size="item.size">
|
|
||||||
</item>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h2 v-if="req.numFiles > 0">{{ $t('files.files') }}</h2>
|
|
||||||
<div v-if="req.numFiles > 0">
|
|
||||||
<item v-for="(item) in files"
|
|
||||||
:key="base64(item.name)"
|
|
||||||
v-bind:index="item.index"
|
|
||||||
v-bind:name="item.name"
|
|
||||||
v-bind:isDir="item.isDir"
|
|
||||||
v-bind:url="item.url"
|
|
||||||
v-bind:modified="item.modified"
|
|
||||||
v-bind:type="item.type"
|
|
||||||
v-bind:size="item.size">
|
|
||||||
</item>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<input style="display:none" type="file" id="upload-input" @change="uploadInput($event)" multiple>
|
|
||||||
<input style="display:none" type="file" id="upload-folder-input" @change="uploadInput($event)" webkitdirectory multiple>
|
|
||||||
|
|
||||||
<div :class="{ active: $store.state.multiple }" id="multiple-selection">
|
|
||||||
<p>{{ $t('files.multipleSelectionEnabled') }}</p>
|
|
||||||
<div @click="$store.commit('multiple', false)" tabindex="0" role="button" :title="$t('files.clear')" :aria-label="$t('files.clear')" class="action">
|
|
||||||
<i class="material-icons">clear</i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { mapState, mapMutations } from 'vuex'
|
|
||||||
import throttle from 'lodash.throttle'
|
|
||||||
import Item from './ListingItem'
|
|
||||||
import css from '@/utils/css'
|
|
||||||
import { users, files as api } from '@/api'
|
|
||||||
import buttons from '@/utils/buttons'
|
|
||||||
import url from '@/utils/url'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'listing',
|
|
||||||
components: { Item },
|
|
||||||
data: function () {
|
|
||||||
return {
|
|
||||||
show: 50,
|
|
||||||
uploading: {
|
|
||||||
id: 0,
|
|
||||||
count: 0,
|
|
||||||
size: 0,
|
|
||||||
progress: []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
...mapState(['req', 'selected', 'user']),
|
|
||||||
nameSorted () {
|
|
||||||
return (this.req.sorting.by === 'name')
|
|
||||||
},
|
|
||||||
sizeSorted () {
|
|
||||||
return (this.req.sorting.by === 'size')
|
|
||||||
},
|
|
||||||
modifiedSorted () {
|
|
||||||
return (this.req.sorting.by === 'modified')
|
|
||||||
},
|
|
||||||
ascOrdered () {
|
|
||||||
return this.req.sorting.asc
|
|
||||||
},
|
|
||||||
items () {
|
|
||||||
const dirs = []
|
|
||||||
const files = []
|
|
||||||
|
|
||||||
this.req.items.forEach((item) => {
|
|
||||||
if (item.isDir) {
|
|
||||||
dirs.push(item)
|
|
||||||
} else {
|
|
||||||
files.push(item)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return { dirs, files }
|
|
||||||
},
|
|
||||||
dirs () {
|
|
||||||
return this.items.dirs.slice(0, this.show)
|
|
||||||
},
|
|
||||||
files () {
|
|
||||||
let show = this.show - this.items.dirs.length
|
|
||||||
|
|
||||||
if (show < 0) show = 0
|
|
||||||
|
|
||||||
return this.items.files.slice(0, show)
|
|
||||||
},
|
|
||||||
nameIcon () {
|
|
||||||
if (this.nameSorted && !this.ascOrdered) {
|
|
||||||
return 'arrow_upward'
|
|
||||||
}
|
|
||||||
|
|
||||||
return 'arrow_downward'
|
|
||||||
},
|
|
||||||
sizeIcon () {
|
|
||||||
if (this.sizeSorted && this.ascOrdered) {
|
|
||||||
return 'arrow_downward'
|
|
||||||
}
|
|
||||||
|
|
||||||
return 'arrow_upward'
|
|
||||||
},
|
|
||||||
modifiedIcon () {
|
|
||||||
if (this.modifiedSorted && this.ascOrdered) {
|
|
||||||
return 'arrow_downward'
|
|
||||||
}
|
|
||||||
|
|
||||||
return 'arrow_upward'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted: function () {
|
|
||||||
// Check the columns size for the first time.
|
|
||||||
this.resizeEvent()
|
|
||||||
|
|
||||||
// Add the needed event listeners to the window and document.
|
|
||||||
window.addEventListener('keydown', this.keyEvent)
|
|
||||||
window.addEventListener('resize', this.resizeEvent)
|
|
||||||
window.addEventListener('scroll', this.scrollEvent)
|
|
||||||
document.addEventListener('dragover', this.preventDefault)
|
|
||||||
document.addEventListener('drop', this.drop)
|
|
||||||
},
|
|
||||||
beforeDestroy () {
|
|
||||||
// Remove event listeners before destroying this page.
|
|
||||||
window.removeEventListener('keydown', this.keyEvent)
|
|
||||||
window.removeEventListener('resize', this.resizeEvent)
|
|
||||||
window.removeEventListener('scroll', this.scrollEvent)
|
|
||||||
document.removeEventListener('dragover', this.preventDefault)
|
|
||||||
document.removeEventListener('drop', this.drop)
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
...mapMutations([ 'updateUser', 'addSelected' ]),
|
|
||||||
base64: function (name) {
|
|
||||||
return window.btoa(unescape(encodeURIComponent(name)))
|
|
||||||
},
|
|
||||||
keyEvent (event) {
|
|
||||||
if (!event.ctrlKey && !event.metaKey) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let key = String.fromCharCode(event.which).toLowerCase()
|
|
||||||
|
|
||||||
switch (key) {
|
|
||||||
case 'f':
|
|
||||||
event.preventDefault()
|
|
||||||
this.$store.commit('showHover', 'search')
|
|
||||||
break
|
|
||||||
case 'c':
|
|
||||||
case 'x':
|
|
||||||
this.copyCut(event, key)
|
|
||||||
break
|
|
||||||
case 'v':
|
|
||||||
this.paste(event)
|
|
||||||
break
|
|
||||||
case 'a':
|
|
||||||
event.preventDefault()
|
|
||||||
for (let file of this.items.files) {
|
|
||||||
if (this.$store.state.selected.indexOf(file.index) === -1) {
|
|
||||||
this.addSelected(file.index)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (let dir of this.items.dirs) {
|
|
||||||
if (this.$store.state.selected.indexOf(dir.index) === -1) {
|
|
||||||
this.addSelected(dir.index)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
},
|
|
||||||
preventDefault (event) {
|
|
||||||
// Wrapper around prevent default.
|
|
||||||
event.preventDefault()
|
|
||||||
},
|
|
||||||
copyCut (event, key) {
|
|
||||||
if (event.target.tagName.toLowerCase() === 'input') {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let items = []
|
|
||||||
|
|
||||||
for (let i of this.selected) {
|
|
||||||
items.push({
|
|
||||||
from: this.req.items[i].url,
|
|
||||||
name: encodeURIComponent(this.req.items[i].name)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if (items.length == 0) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
this.$store.commit('updateClipboard', {
|
|
||||||
key: key,
|
|
||||||
items: items
|
|
||||||
})
|
|
||||||
},
|
|
||||||
paste (event) {
|
|
||||||
if (event.target.tagName.toLowerCase() === 'input') {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let items = []
|
|
||||||
|
|
||||||
for (let item of this.$store.state.clipboard.items) {
|
|
||||||
const from = item.from.endsWith('/') ? item.from.slice(0, -1) : item.from
|
|
||||||
const to = this.$route.path + item.name
|
|
||||||
items.push({ from, to })
|
|
||||||
}
|
|
||||||
|
|
||||||
if (items.length === 0) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.$store.state.clipboard.key === 'x') {
|
|
||||||
api.move(items).then(() => {
|
|
||||||
this.$store.commit('setReload', true)
|
|
||||||
}).catch(this.$showError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
api.copy(items).then(() => {
|
|
||||||
this.$store.commit('setReload', true)
|
|
||||||
}).catch(this.$showError)
|
|
||||||
},
|
|
||||||
resizeEvent () {
|
|
||||||
// Update the columns size based on the window width.
|
|
||||||
let columns = Math.floor(document.querySelector('main').offsetWidth / 300)
|
|
||||||
let items = css(['#listing.mosaic .item', '.mosaic#listing .item'])
|
|
||||||
if (columns === 0) columns = 1
|
|
||||||
items.style.width = `calc(${100 / columns}% - 1em)`
|
|
||||||
},
|
|
||||||
scrollEvent () {
|
|
||||||
if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight) {
|
|
||||||
this.show += 50
|
|
||||||
}
|
|
||||||
},
|
|
||||||
dragEnter () {
|
|
||||||
// When the user starts dragging an item, put every
|
|
||||||
// file on the listing with 50% opacity.
|
|
||||||
let items = document.getElementsByClassName('item')
|
|
||||||
|
|
||||||
Array.from(items).forEach(file => {
|
|
||||||
file.style.opacity = 0.5
|
|
||||||
})
|
|
||||||
},
|
|
||||||
dragEnd () {
|
|
||||||
this.resetOpacity()
|
|
||||||
},
|
|
||||||
drop: function (event) {
|
|
||||||
event.preventDefault()
|
|
||||||
this.resetOpacity()
|
|
||||||
|
|
||||||
let dt = event.dataTransfer
|
|
||||||
let el = event.target
|
|
||||||
|
|
||||||
if (dt.files.length <= 0) return
|
|
||||||
|
|
||||||
for (let i = 0; i < 5; i++) {
|
|
||||||
if (el !== null && !el.classList.contains('item')) {
|
|
||||||
el = el.parentElement
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let base = ''
|
|
||||||
if (el !== null && el.classList.contains('item') && el.dataset.dir === 'true') {
|
|
||||||
base = el.querySelector('.name').innerHTML + '/'
|
|
||||||
}
|
|
||||||
|
|
||||||
if (base === '') {
|
|
||||||
this.scanFiles(dt).then((result) => {
|
|
||||||
this.checkConflict(result, this.req.items, base)
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
this.scanFiles(dt).then((result) => {
|
|
||||||
api.fetch(this.$route.path + base)
|
|
||||||
.then(req => {
|
|
||||||
this.checkConflict(result, req.items, base)
|
|
||||||
})
|
|
||||||
.catch(this.$showError)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
checkConflict (files, items, base) {
|
|
||||||
if (typeof items === 'undefined' || items === null) {
|
|
||||||
items = []
|
|
||||||
}
|
|
||||||
|
|
||||||
let folder_upload = false
|
|
||||||
if (files[0].fullPath !== undefined) {
|
|
||||||
folder_upload = true
|
|
||||||
}
|
|
||||||
|
|
||||||
let conflict = false
|
|
||||||
for (let i = 0; i < files.length; i++) {
|
|
||||||
let file = files[i]
|
|
||||||
let name = file.name
|
|
||||||
|
|
||||||
if (folder_upload) {
|
|
||||||
let dirs = file.fullPath.split("/")
|
|
||||||
if (dirs.length > 1) {
|
|
||||||
name = dirs[0]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let res = items.findIndex(function hasConflict (element) {
|
|
||||||
return (element.name === this)
|
|
||||||
}, name)
|
|
||||||
|
|
||||||
if (res >= 0) {
|
|
||||||
conflict = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!conflict) {
|
|
||||||
this.handleFiles(files, base)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
this.$store.commit('showHover', {
|
|
||||||
prompt: 'replace',
|
|
||||||
confirm: (event) => {
|
|
||||||
event.preventDefault()
|
|
||||||
this.$store.commit('closeHovers')
|
|
||||||
this.handleFiles(files, base, true)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
uploadInput (event) {
|
|
||||||
this.$store.commit('closeHovers')
|
|
||||||
|
|
||||||
let files = event.currentTarget.files
|
|
||||||
let folder_upload = files[0].webkitRelativePath !== undefined && files[0].webkitRelativePath !== ''
|
|
||||||
|
|
||||||
if (folder_upload) {
|
|
||||||
for (let i = 0; i < files.length; i++) {
|
|
||||||
let file = files[i]
|
|
||||||
files[i].fullPath = file.webkitRelativePath
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.checkConflict(files, this.req.items, '')
|
|
||||||
},
|
|
||||||
resetOpacity () {
|
|
||||||
let items = document.getElementsByClassName('item')
|
|
||||||
|
|
||||||
Array.from(items).forEach(file => {
|
|
||||||
file.style.opacity = 1
|
|
||||||
})
|
|
||||||
},
|
|
||||||
scanFiles(dt) {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
let reading = 0
|
|
||||||
const contents = []
|
|
||||||
|
|
||||||
if (dt.items !== undefined) {
|
|
||||||
for (let item of dt.items) {
|
|
||||||
if (item.kind === "file" && typeof item.webkitGetAsEntry === "function") {
|
|
||||||
const entry = item.webkitGetAsEntry()
|
|
||||||
readEntry(entry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
resolve(dt.files)
|
|
||||||
}
|
|
||||||
|
|
||||||
function readEntry(entry, directory = "") {
|
|
||||||
if (entry.isFile) {
|
|
||||||
reading++
|
|
||||||
entry.file(file => {
|
|
||||||
reading--
|
|
||||||
|
|
||||||
file.fullPath = `${directory}${file.name}`
|
|
||||||
contents.push(file)
|
|
||||||
|
|
||||||
if (reading === 0) {
|
|
||||||
resolve(contents)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else if (entry.isDirectory) {
|
|
||||||
const dir = {
|
|
||||||
isDir: true,
|
|
||||||
path: `${directory}${entry.name}`
|
|
||||||
}
|
|
||||||
|
|
||||||
contents.push(dir)
|
|
||||||
|
|
||||||
readReaderContent(entry.createReader(), `${directory}${entry.name}`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function readReaderContent(reader, directory) {
|
|
||||||
reading++
|
|
||||||
|
|
||||||
reader.readEntries(function (entries) {
|
|
||||||
reading--
|
|
||||||
if (entries.length > 0) {
|
|
||||||
for (const entry of entries) {
|
|
||||||
readEntry(entry, `${directory}/`)
|
|
||||||
}
|
|
||||||
|
|
||||||
readReaderContent(reader, `${directory}/`)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (reading === 0) {
|
|
||||||
resolve(contents)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
setProgress: throttle(function() {
|
|
||||||
if (this.uploading.count == 0) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let sum = this.uploading.progress.reduce((acc, val) => acc + val)
|
|
||||||
this.$store.commit('setProgress', Math.ceil(sum / this.uploading.size * 100))
|
|
||||||
}, 100, {leading: false, trailing: true}),
|
|
||||||
handleFiles (files, base, overwrite = false) {
|
|
||||||
if (this.uploading.count == 0) {
|
|
||||||
buttons.loading('upload')
|
|
||||||
}
|
|
||||||
|
|
||||||
let promises = []
|
|
||||||
|
|
||||||
let onupload = (id) => (event) => {
|
|
||||||
this.uploading.progress[id] = event.loaded
|
|
||||||
this.setProgress()
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let i = 0; i < files.length; i++) {
|
|
||||||
let file = files[i]
|
|
||||||
|
|
||||||
if (!file.isDir) {
|
|
||||||
let filename = (file.fullPath !== undefined) ? file.fullPath : file.name
|
|
||||||
let filenameEncoded = url.encodeRFC5987ValueChars(filename)
|
|
||||||
|
|
||||||
let id = this.uploading.id
|
|
||||||
|
|
||||||
this.uploading.size += file.size
|
|
||||||
this.uploading.id++
|
|
||||||
this.uploading.count++
|
|
||||||
|
|
||||||
let promise = api.post(this.$route.path + base + filenameEncoded, file, overwrite, throttle(onupload(id), 100)).finally(() => {
|
|
||||||
this.uploading.count--
|
|
||||||
})
|
|
||||||
|
|
||||||
promises.push(promise)
|
|
||||||
} else {
|
|
||||||
let uri = this.$route.path + base
|
|
||||||
let folders = file.path.split("/")
|
|
||||||
|
|
||||||
for (let i = 0; i < folders.length; i++) {
|
|
||||||
let folder = folders[i]
|
|
||||||
let folderEncoded = encodeURIComponent(folder)
|
|
||||||
uri += folderEncoded + "/"
|
|
||||||
}
|
|
||||||
|
|
||||||
api.post(uri)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let finish = () => {
|
|
||||||
if (this.uploading.count > 0) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
buttons.success('upload')
|
|
||||||
|
|
||||||
this.$store.commit('setProgress', 0)
|
|
||||||
this.$store.commit('setReload', true)
|
|
||||||
|
|
||||||
this.uploading.id = 0
|
|
||||||
this.uploading.sizes = []
|
|
||||||
this.uploading.progress = []
|
|
||||||
}
|
|
||||||
|
|
||||||
Promise.all(promises)
|
|
||||||
.then(() => {
|
|
||||||
finish()
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
finish()
|
|
||||||
this.$showError(error)
|
|
||||||
})
|
|
||||||
|
|
||||||
return false
|
|
||||||
},
|
|
||||||
async sort (by) {
|
|
||||||
let asc = false
|
|
||||||
|
|
||||||
if (by === 'name') {
|
|
||||||
if (this.nameIcon === 'arrow_upward') {
|
|
||||||
asc = true
|
|
||||||
}
|
|
||||||
} else if (by === 'size') {
|
|
||||||
if (this.sizeIcon === 'arrow_upward') {
|
|
||||||
asc = true
|
|
||||||
}
|
|
||||||
} else if (by === 'modified') {
|
|
||||||
if (this.modifiedIcon === 'arrow_upward') {
|
|
||||||
asc = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
await users.update({ id: this.user.id, sorting: { by, asc } }, ['sorting'])
|
|
||||||
} catch (e) {
|
|
||||||
this.$showError(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
this.$store.commit('setReload', true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@@ -6,14 +6,14 @@
|
|||||||
@dragstart="dragStart"
|
@dragstart="dragStart"
|
||||||
@dragover="dragOver"
|
@dragover="dragOver"
|
||||||
@drop="drop"
|
@drop="drop"
|
||||||
@click="click"
|
@click="itemClick"
|
||||||
@dblclick="open"
|
@dblclick="dblclick"
|
||||||
@touchstart="touchstart"
|
@touchstart="touchstart"
|
||||||
:data-dir="isDir"
|
:data-dir="isDir"
|
||||||
:aria-label="name"
|
:aria-label="name"
|
||||||
:aria-selected="isSelected">
|
:aria-selected="isSelected">
|
||||||
<div>
|
<div>
|
||||||
<img v-if="type==='image'" :src="thumbnailUrl">
|
<img v-if="readOnly == undefined && type==='image' && isThumbsEnabled" v-lazy="thumbnailUrl">
|
||||||
<i v-else class="material-icons">{{ icon }}</i>
|
<i v-else class="material-icons">{{ icon }}</i>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -31,11 +31,12 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { baseURL } from '@/utils/constants'
|
import { baseURL, enableThumbs } from '@/utils/constants'
|
||||||
import { mapMutations, mapGetters, mapState } from 'vuex'
|
import { mapMutations, mapGetters, mapState } from 'vuex'
|
||||||
import filesize from 'filesize'
|
import filesize from 'filesize'
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
import { files as api } from '@/api'
|
import { files as api } from '@/api'
|
||||||
|
import * as upload from '@/utils/upload'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'item',
|
name: 'item',
|
||||||
@@ -44,10 +45,13 @@ export default {
|
|||||||
touches: 0
|
touches: 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
props: ['name', 'isDir', 'url', 'type', 'size', 'modified', 'index'],
|
props: ['name', 'isDir', 'url', 'type', 'size', 'modified', 'index', 'readOnly'],
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(['selected', 'req', 'user', 'jwt']),
|
...mapState(['user', 'selected', 'req', 'jwt']),
|
||||||
...mapGetters(['selectedCount']),
|
...mapGetters(['selectedCount']),
|
||||||
|
singleClick () {
|
||||||
|
return this.readOnly == undefined && this.user.singleClick
|
||||||
|
},
|
||||||
isSelected () {
|
isSelected () {
|
||||||
return (this.selected.indexOf(this.index) !== -1)
|
return (this.selected.indexOf(this.index) !== -1)
|
||||||
},
|
},
|
||||||
@@ -59,10 +63,10 @@ export default {
|
|||||||
return 'insert_drive_file'
|
return 'insert_drive_file'
|
||||||
},
|
},
|
||||||
isDraggable () {
|
isDraggable () {
|
||||||
return this.user.perm.rename
|
return this.readOnly == undefined && this.user.perm.rename
|
||||||
},
|
},
|
||||||
canDrop () {
|
canDrop () {
|
||||||
if (!this.isDir) return false
|
if (!this.isDir || this.readOnly !== undefined) return false
|
||||||
|
|
||||||
for (let i of this.selected) {
|
for (let i of this.selected) {
|
||||||
if (this.req.items[i].url === this.url) {
|
if (this.req.items[i].url === this.url) {
|
||||||
@@ -74,7 +78,14 @@ export default {
|
|||||||
},
|
},
|
||||||
thumbnailUrl () {
|
thumbnailUrl () {
|
||||||
const path = this.url.replace(/^\/files\//, '')
|
const path = this.url.replace(/^\/files\//, '')
|
||||||
return `${baseURL}/api/preview/thumb/${path}?auth=${this.jwt}&inline=true`
|
|
||||||
|
// reload the image when the file is replaced
|
||||||
|
const key = Date.parse(this.modified)
|
||||||
|
|
||||||
|
return `${baseURL}/api/preview/thumb/${path}?auth=${this.jwt}&inline=true&k=${key}`
|
||||||
|
},
|
||||||
|
isThumbsEnabled () {
|
||||||
|
return enableThumbs
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@@ -110,29 +121,68 @@ export default {
|
|||||||
|
|
||||||
el.style.opacity = 1
|
el.style.opacity = 1
|
||||||
},
|
},
|
||||||
drop: function (event) {
|
drop: async function (event) {
|
||||||
if (!this.canDrop) return
|
if (!this.canDrop) return
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
|
|
||||||
if (this.selectedCount === 0) return
|
if (this.selectedCount === 0) return
|
||||||
|
|
||||||
|
let el = event.target
|
||||||
|
for (let i = 0; i < 5; i++) {
|
||||||
|
if (el !== null && !el.classList.contains('item')) {
|
||||||
|
el = el.parentElement
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let items = []
|
let items = []
|
||||||
|
|
||||||
for (let i of this.selected) {
|
for (let i of this.selected) {
|
||||||
items.push({
|
items.push({
|
||||||
from: this.req.items[i].url,
|
from: this.req.items[i].url,
|
||||||
to: this.url + this.req.items[i].name
|
to: this.url + this.req.items[i].name,
|
||||||
|
name: this.req.items[i].name
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
api.move(items)
|
let base = el.querySelector('.name').innerHTML + '/'
|
||||||
.then(() => {
|
let path = this.$route.path + base
|
||||||
|
let baseItems = (await api.fetch(path)).items
|
||||||
|
|
||||||
|
let action = (overwrite, rename) => {
|
||||||
|
api.move(items, overwrite, rename).then(() => {
|
||||||
this.$store.commit('setReload', true)
|
this.$store.commit('setReload', true)
|
||||||
|
}).catch(this.$showError)
|
||||||
|
}
|
||||||
|
|
||||||
|
let conflict = upload.checkConflict(items, baseItems)
|
||||||
|
|
||||||
|
let overwrite = false
|
||||||
|
let rename = false
|
||||||
|
|
||||||
|
if (conflict) {
|
||||||
|
this.$store.commit('showHover', {
|
||||||
|
prompt: 'replace-rename',
|
||||||
|
confirm: (event, option) => {
|
||||||
|
overwrite = option == 'overwrite'
|
||||||
|
rename = option == 'rename'
|
||||||
|
|
||||||
|
event.preventDefault()
|
||||||
|
this.$store.commit('closeHovers')
|
||||||
|
action(overwrite, rename)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.catch(this.$showError)
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
action(overwrite, rename)
|
||||||
|
},
|
||||||
|
itemClick: function(event) {
|
||||||
|
if (this.singleClick && !this.$store.state.multiple) this.open()
|
||||||
|
else this.click(event)
|
||||||
},
|
},
|
||||||
click: function (event) {
|
click: function (event) {
|
||||||
if (this.selectedCount !== 0) event.preventDefault()
|
if (!this.singleClick && this.selectedCount !== 0) event.preventDefault()
|
||||||
if (this.$store.state.selected.indexOf(this.index) !== -1) {
|
if (this.$store.state.selected.indexOf(this.index) !== -1) {
|
||||||
this.removeSelected(this.index)
|
this.removeSelected(this.index)
|
||||||
return
|
return
|
||||||
@@ -159,9 +209,12 @@ export default {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!event.ctrlKey && !this.$store.state.multiple) this.resetSelected()
|
if (!this.singleClick && !event.ctrlKey && !event.metaKey && !this.$store.state.multiple) this.resetSelected()
|
||||||
this.addSelected(this.index)
|
this.addSelected(this.index)
|
||||||
},
|
},
|
||||||
|
dblclick: function () {
|
||||||
|
if (!this.singleClick) this.open()
|
||||||
|
},
|
||||||
touchstart () {
|
touchstart () {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.touches = 0
|
this.touches = 0
|
||||||
|
|||||||
@@ -1,166 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div id="previewer">
|
|
||||||
<div class="bar">
|
|
||||||
<button @click="back" class="action" :title="$t('files.closePreview')" :aria-label="$t('files.closePreview')" id="close">
|
|
||||||
<i class="material-icons">close</i>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<rename-button v-if="user.perm.rename"></rename-button>
|
|
||||||
<delete-button v-if="user.perm.delete"></delete-button>
|
|
||||||
<download-button v-if="user.perm.download"></download-button>
|
|
||||||
<info-button></info-button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button class="action" @click="prev" v-show="hasPrevious" :aria-label="$t('buttons.previous')" :title="$t('buttons.previous')">
|
|
||||||
<i class="material-icons">chevron_left</i>
|
|
||||||
</button>
|
|
||||||
<button class="action" @click="next" v-show="hasNext" :aria-label="$t('buttons.next')" :title="$t('buttons.next')">
|
|
||||||
<i class="material-icons">chevron_right</i>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<div class="preview">
|
|
||||||
<ExtendedImage v-if="req.type == 'image'" :src="raw"></ExtendedImage>
|
|
||||||
<audio v-else-if="req.type == 'audio'" :src="raw" autoplay controls></audio>
|
|
||||||
<video v-else-if="req.type == 'video'" :src="raw" autoplay controls>
|
|
||||||
<track
|
|
||||||
kind="captions"
|
|
||||||
v-for="(sub, index) in subtitles"
|
|
||||||
:key="index"
|
|
||||||
:src="sub"
|
|
||||||
:label="'Subtitle ' + index" :default="index === 0">
|
|
||||||
Sorry, your browser doesn't support embedded videos,
|
|
||||||
but don't worry, you can <a :href="download">download it</a>
|
|
||||||
and watch it with your favorite video player!
|
|
||||||
</video>
|
|
||||||
<object v-else-if="req.extension == '.pdf'" class="pdf" :data="raw"></object>
|
|
||||||
<a v-else-if="req.type == 'blob'" :href="download">
|
|
||||||
<h2 class="message">{{ $t('buttons.download') }} <i class="material-icons">file_download</i></h2>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { mapState } from 'vuex'
|
|
||||||
import url from '@/utils/url'
|
|
||||||
import { baseURL } from '@/utils/constants'
|
|
||||||
import { files as api } from '@/api'
|
|
||||||
import InfoButton from '@/components/buttons/Info'
|
|
||||||
import DeleteButton from '@/components/buttons/Delete'
|
|
||||||
import RenameButton from '@/components/buttons/Rename'
|
|
||||||
import DownloadButton from '@/components/buttons/Download'
|
|
||||||
import ExtendedImage from './ExtendedImage'
|
|
||||||
|
|
||||||
const mediaTypes = [
|
|
||||||
"image",
|
|
||||||
"video",
|
|
||||||
"audio",
|
|
||||||
"blob"
|
|
||||||
]
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'preview',
|
|
||||||
components: {
|
|
||||||
InfoButton,
|
|
||||||
DeleteButton,
|
|
||||||
RenameButton,
|
|
||||||
DownloadButton,
|
|
||||||
ExtendedImage
|
|
||||||
},
|
|
||||||
data: function () {
|
|
||||||
return {
|
|
||||||
previousLink: '',
|
|
||||||
nextLink: '',
|
|
||||||
listing: null,
|
|
||||||
subtitles: []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
...mapState(['req', 'user', 'oldReq', 'jwt']),
|
|
||||||
hasPrevious () {
|
|
||||||
return (this.previousLink !== '')
|
|
||||||
},
|
|
||||||
hasNext () {
|
|
||||||
return (this.nextLink !== '')
|
|
||||||
},
|
|
||||||
download () {
|
|
||||||
return `${baseURL}/api/raw${this.req.path}?auth=${this.jwt}`
|
|
||||||
},
|
|
||||||
previewUrl () {
|
|
||||||
if (this.req.type === 'image') {
|
|
||||||
return `${baseURL}/api/preview/big${this.req.path}?auth=${this.jwt}`
|
|
||||||
}
|
|
||||||
return `${baseURL}/api/raw${this.req.path}?auth=${this.jwt}`
|
|
||||||
},
|
|
||||||
raw () {
|
|
||||||
return `${this.previewUrl}&inline=true`
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async mounted () {
|
|
||||||
window.addEventListener('keyup', this.key)
|
|
||||||
|
|
||||||
if (this.req.subtitles) {
|
|
||||||
this.subtitles = this.req.subtitles.map(sub => `${baseURL}/api/raw${sub}?auth=${this.jwt}&inline=true`)
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (this.oldReq.items) {
|
|
||||||
this.updateLinks(this.oldReq.items)
|
|
||||||
} else {
|
|
||||||
const path = url.removeLastDir(this.$route.path)
|
|
||||||
const res = await api.fetch(path)
|
|
||||||
this.updateLinks(res.items)
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
this.$showError(e)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
beforeDestroy () {
|
|
||||||
window.removeEventListener('keyup', this.key)
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
back () {
|
|
||||||
let uri = url.removeLastDir(this.$route.path) + '/'
|
|
||||||
this.$router.push({ path: uri })
|
|
||||||
},
|
|
||||||
prev () {
|
|
||||||
this.$router.push({ path: this.previousLink })
|
|
||||||
},
|
|
||||||
next () {
|
|
||||||
this.$router.push({ path: this.nextLink })
|
|
||||||
},
|
|
||||||
key (event) {
|
|
||||||
event.preventDefault()
|
|
||||||
|
|
||||||
if (event.which === 13 || event.which === 39) { // right arrow
|
|
||||||
if (this.hasNext) this.next()
|
|
||||||
} else if (event.which === 37) { // left arrow
|
|
||||||
if (this.hasPrevious) this.prev()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
updateLinks (items) {
|
|
||||||
for (let i = 0; i < items.length; i++) {
|
|
||||||
if (items[i].name !== this.req.name) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let j = i - 1; j >= 0; j--) {
|
|
||||||
if (mediaTypes.includes(items[j].type)) {
|
|
||||||
this.previousLink = items[j].url
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let j = i + 1; j < items.length; j++) {
|
|
||||||
if (mediaTypes.includes(items[j].type)) {
|
|
||||||
this.nextLink = items[j].url
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
32
frontend/src/components/header/Action.vue
Normal file
32
frontend/src/components/header/Action.vue
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<template>
|
||||||
|
<button @click="action" :aria-label="label" :title="label" class="action">
|
||||||
|
<i class="material-icons">{{ icon }}</i>
|
||||||
|
<span>{{ label }}</span>
|
||||||
|
<span v-if="counter > 0" class="counter">{{ counter }}</span>
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'action',
|
||||||
|
props: [
|
||||||
|
'icon',
|
||||||
|
'label',
|
||||||
|
'counter',
|
||||||
|
'show'
|
||||||
|
],
|
||||||
|
methods: {
|
||||||
|
action: function () {
|
||||||
|
if (this.show) {
|
||||||
|
this.$store.commit('showHover', this.show)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$emit('action')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
</style>
|
||||||
47
frontend/src/components/header/HeaderBar.vue
Normal file
47
frontend/src/components/header/HeaderBar.vue
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
<template>
|
||||||
|
<header>
|
||||||
|
<img v-if="showLogo !== undefined" :src="logoURL" />
|
||||||
|
<action v-if="showMenu !== undefined" class="menu-button" icon="menu" :label="$t('buttons.toggleSidebar')" @action="openSidebar()" />
|
||||||
|
|
||||||
|
<slot />
|
||||||
|
|
||||||
|
<div id="dropdown" :class="{ active: this.$store.state.show === 'more' }">
|
||||||
|
<slot name="actions" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<action v-if="this.$slots.actions" id="more" icon="more_vert" :label="$t('buttons.more')" @action="$store.commit('showHover', 'more')" />
|
||||||
|
|
||||||
|
<div class="overlay" v-show="this.$store.state.show == 'more'" @click="$store.commit('closeHovers')" />
|
||||||
|
</header>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { logoURL } from '@/utils/constants'
|
||||||
|
|
||||||
|
import Action from '@/components/header/Action'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'header-bar',
|
||||||
|
props: [
|
||||||
|
'showLogo',
|
||||||
|
'showMenu',
|
||||||
|
],
|
||||||
|
components: {
|
||||||
|
Action
|
||||||
|
},
|
||||||
|
data: function () {
|
||||||
|
return {
|
||||||
|
logoURL
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
openSidebar () {
|
||||||
|
this.$store.commit('showHover', 'sidebar')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
</style>
|
||||||
@@ -16,7 +16,6 @@
|
|||||||
:title="$t('buttons.cancel')">{{ $t('buttons.cancel') }}</button>
|
:title="$t('buttons.cancel')">{{ $t('buttons.cancel') }}</button>
|
||||||
<button class="button button--flat"
|
<button class="button button--flat"
|
||||||
@click="copy"
|
@click="copy"
|
||||||
:disabled="$route.path === dest"
|
|
||||||
:aria-label="$t('buttons.copy')"
|
:aria-label="$t('buttons.copy')"
|
||||||
:title="$t('buttons.copy')">{{ $t('buttons.copy') }}</button>
|
:title="$t('buttons.copy')">{{ $t('buttons.copy') }}</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -28,6 +27,7 @@ import { mapState } from 'vuex'
|
|||||||
import FileList from './FileList'
|
import FileList from './FileList'
|
||||||
import { files as api } from '@/api'
|
import { files as api } from '@/api'
|
||||||
import buttons from '@/utils/buttons'
|
import buttons from '@/utils/buttons'
|
||||||
|
import * as upload from '@/utils/upload'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'copy',
|
name: 'copy',
|
||||||
@@ -42,25 +42,66 @@ export default {
|
|||||||
methods: {
|
methods: {
|
||||||
copy: async function (event) {
|
copy: async function (event) {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
buttons.loading('copy')
|
|
||||||
let items = []
|
let items = []
|
||||||
|
|
||||||
// Create a new promise for each file.
|
// Create a new promise for each file.
|
||||||
for (let item of this.selected) {
|
for (let item of this.selected) {
|
||||||
items.push({
|
items.push({
|
||||||
from: this.req.items[item].url,
|
from: this.req.items[item].url,
|
||||||
to: this.dest + encodeURIComponent(this.req.items[item].name)
|
to: this.dest + encodeURIComponent(this.req.items[item].name),
|
||||||
|
name: this.req.items[item].name
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
let action = async (overwrite, rename) => {
|
||||||
await api.copy(items)
|
buttons.loading('copy')
|
||||||
buttons.success('copy')
|
|
||||||
this.$router.push({ path: this.dest })
|
await api.copy(items, overwrite, rename).then(() => {
|
||||||
} catch (e) {
|
buttons.success('copy')
|
||||||
buttons.done('copy')
|
|
||||||
this.$showError(e)
|
if (this.$route.path === this.dest) {
|
||||||
|
this.$store.commit('setReload', true)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$router.push({ path: this.dest })
|
||||||
|
}).catch((e) => {
|
||||||
|
buttons.done('copy')
|
||||||
|
this.$showError(e)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.$route.path === this.dest) {
|
||||||
|
this.$store.commit('closeHovers')
|
||||||
|
action(false, true)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let dstItems = (await api.fetch(this.dest)).items
|
||||||
|
let conflict = upload.checkConflict(items, dstItems)
|
||||||
|
|
||||||
|
let overwrite = false
|
||||||
|
let rename = false
|
||||||
|
|
||||||
|
if (conflict) {
|
||||||
|
this.$store.commit('showHover', {
|
||||||
|
prompt: 'replace-rename',
|
||||||
|
confirm: (event, option) => {
|
||||||
|
overwrite = option == 'overwrite'
|
||||||
|
rename = option == 'rename'
|
||||||
|
|
||||||
|
event.preventDefault()
|
||||||
|
this.$store.commit('closeHovers')
|
||||||
|
action(overwrite, rename)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
action(overwrite, rename)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,29 +20,31 @@
|
|||||||
<script>
|
<script>
|
||||||
import {mapGetters, mapMutations, mapState} from 'vuex'
|
import {mapGetters, mapMutations, mapState} from 'vuex'
|
||||||
import { files as api } from '@/api'
|
import { files as api } from '@/api'
|
||||||
import url from '@/utils/url'
|
|
||||||
import buttons from '@/utils/buttons'
|
import buttons from '@/utils/buttons'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'delete',
|
name: 'delete',
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters(['isListing', 'selectedCount']),
|
...mapGetters(['isListing', 'selectedCount']),
|
||||||
...mapState(['req', 'selected'])
|
...mapState(['req', 'selected', 'showConfirm'])
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapMutations(['closeHovers']),
|
...mapMutations(['closeHovers']),
|
||||||
submit: async function () {
|
submit: async function () {
|
||||||
this.closeHovers()
|
|
||||||
buttons.loading('delete')
|
buttons.loading('delete')
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!this.isListing) {
|
if (!this.isListing) {
|
||||||
await api.remove(this.$route.path)
|
await api.remove(this.$route.path)
|
||||||
buttons.success('delete')
|
buttons.success('delete')
|
||||||
this.$router.push({ path: url.removeLastDir(this.$route.path) + '/' })
|
|
||||||
|
this.showConfirm()
|
||||||
|
this.closeHovers()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.closeHovers()
|
||||||
|
|
||||||
if (this.selectedCount === 0) {
|
if (this.selectedCount === 0) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,43 +7,29 @@
|
|||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<p>{{ $t('prompts.downloadMessage') }}</p>
|
<p>{{ $t('prompts.downloadMessage') }}</p>
|
||||||
|
|
||||||
<button class="button button--block" @click="download('zip')" v-focus>zip</button>
|
<button v-for="(ext, format) in formats" :key="format" class="button button--block" @click="showConfirm(format)" v-focus>{{ ext }}</button>
|
||||||
<button class="button button--block" @click="download('tar')" v-focus>tar</button>
|
|
||||||
<button class="button button--block" @click="download('targz')" v-focus>tar.gz</button>
|
|
||||||
<button class="button button--block" @click="download('tarbz2')" v-focus>tar.bz2</button>
|
|
||||||
<button class="button button--block" @click="download('tarxz')" v-focus>tar.xz</button>
|
|
||||||
<button class="button button--block" @click="download('tarlz4')" v-focus>tar.lz4</button>
|
|
||||||
<button class="button button--block" @click="download('tarsz')" v-focus>tar.sz</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {mapGetters, mapState} from 'vuex'
|
import { mapState } from 'vuex'
|
||||||
import { files as api } from '@/api'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'download',
|
name: 'download',
|
||||||
computed: {
|
data: function () {
|
||||||
...mapState(['selected', 'req']),
|
return {
|
||||||
...mapGetters(['selectedCount'])
|
formats: {
|
||||||
},
|
zip: 'zip',
|
||||||
methods: {
|
tar: 'tar',
|
||||||
download: function (format) {
|
targz: 'tar.gz',
|
||||||
if (this.selectedCount === 0) {
|
tarbz2: 'tar.bz2',
|
||||||
api.download(format, this.$route.path)
|
tarxz: 'tar.xz',
|
||||||
} else {
|
tarlz4: 'tar.lz4',
|
||||||
let files = []
|
tarsz: 'tar.sz'
|
||||||
|
|
||||||
for (let i of this.selected) {
|
|
||||||
files.push(this.req.items[i].url)
|
|
||||||
}
|
|
||||||
|
|
||||||
api.download(format, ...files)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$store.commit('closeHovers')
|
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
computed: mapState(['showConfirm'])
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<ul class="file-list">
|
<ul class="file-list">
|
||||||
<li @click="select"
|
<li @click="itemClick"
|
||||||
@touchstart="touchstart"
|
@touchstart="touchstart"
|
||||||
@dblclick="next"
|
@dblclick="next"
|
||||||
role="button"
|
role="button"
|
||||||
@@ -35,25 +35,13 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState([ 'req' ]),
|
...mapState([ 'req', 'user' ]),
|
||||||
nav () {
|
nav () {
|
||||||
return decodeURIComponent(this.current)
|
return decodeURIComponent(this.current)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
// If we're showing this on a listing,
|
this.fillOptions(this.req)
|
||||||
// we can use the current request object
|
|
||||||
// to fill the move options.
|
|
||||||
if (this.req.kind === 'listing') {
|
|
||||||
this.fillOptions(this.req)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, we must be on a preview or editor
|
|
||||||
// so we fetch the data from the previous directory.
|
|
||||||
files.fetch(url.removeLastDir(this.$route.path))
|
|
||||||
.then(this.fillOptions)
|
|
||||||
.catch(this.$showError)
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
fillOptions (req) {
|
fillOptions (req) {
|
||||||
@@ -123,6 +111,10 @@ export default {
|
|||||||
this.next(event)
|
this.next(event)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
itemClick: function (event) {
|
||||||
|
if (this.user.singleClick) this.next(event)
|
||||||
|
else this.select(event)
|
||||||
|
},
|
||||||
select: function (event) {
|
select: function (event) {
|
||||||
// If the element is already selected, unselect it.
|
// If the element is already selected, unselect it.
|
||||||
if (this.selected === event.currentTarget.dataset.url) {
|
if (this.selected === event.currentTarget.dataset.url) {
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ export default {
|
|||||||
return moment(this.req.modified).fromNow()
|
return moment(this.req.modified).fromNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
return moment(this.req.items[this.selected[0]]).fromNow()
|
return moment(this.req.items[this.selected[0]].modified).fromNow()
|
||||||
},
|
},
|
||||||
name: function () {
|
name: function () {
|
||||||
return this.selectedCount === 0 ? this.req.name : this.req.items[this.selected[0]].name
|
return this.selectedCount === 0 ? this.req.name : this.req.items[this.selected[0]].name
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import { mapState } from 'vuex'
|
|||||||
import FileList from './FileList'
|
import FileList from './FileList'
|
||||||
import { files as api } from '@/api'
|
import { files as api } from '@/api'
|
||||||
import buttons from '@/utils/buttons'
|
import buttons from '@/utils/buttons'
|
||||||
|
import * as upload from '@/utils/upload'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'move',
|
name: 'move',
|
||||||
@@ -41,26 +42,51 @@ export default {
|
|||||||
methods: {
|
methods: {
|
||||||
move: async function (event) {
|
move: async function (event) {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
buttons.loading('move')
|
|
||||||
let items = []
|
let items = []
|
||||||
|
|
||||||
for (let item of this.selected) {
|
for (let item of this.selected) {
|
||||||
items.push({
|
items.push({
|
||||||
from: this.req.items[item].url,
|
from: this.req.items[item].url,
|
||||||
to: this.dest + encodeURIComponent(this.req.items[item].name)
|
to: this.dest + encodeURIComponent(this.req.items[item].name),
|
||||||
|
name: this.req.items[item].name
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
let action = async (overwrite, rename) => {
|
||||||
api.move(items)
|
buttons.loading('move')
|
||||||
buttons.success('move')
|
|
||||||
this.$router.push({ path: this.dest })
|
await api.move(items, overwrite, rename).then(() => {
|
||||||
} catch (e) {
|
buttons.success('move')
|
||||||
buttons.done('move')
|
this.$router.push({ path: this.dest })
|
||||||
this.$showError(e)
|
}).catch((e) => {
|
||||||
|
buttons.done('move')
|
||||||
|
this.$showError(e)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
event.preventDefault()
|
let dstItems = (await api.fetch(this.dest)).items
|
||||||
|
let conflict = upload.checkConflict(items, dstItems)
|
||||||
|
|
||||||
|
let overwrite = false
|
||||||
|
let rename = false
|
||||||
|
|
||||||
|
if (conflict) {
|
||||||
|
this.$store.commit('showHover', {
|
||||||
|
prompt: 'replace-rename',
|
||||||
|
confirm: (event, option) => {
|
||||||
|
overwrite = option == 'overwrite'
|
||||||
|
rename = option == 'rename'
|
||||||
|
|
||||||
|
event.preventDefault()
|
||||||
|
this.$store.commit('closeHovers')
|
||||||
|
action(overwrite, rename)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
action(overwrite, rename)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,8 +16,10 @@ import Copy from './Copy'
|
|||||||
import NewFile from './NewFile'
|
import NewFile from './NewFile'
|
||||||
import NewDir from './NewDir'
|
import NewDir from './NewDir'
|
||||||
import Replace from './Replace'
|
import Replace from './Replace'
|
||||||
|
import ReplaceRename from './ReplaceRename'
|
||||||
import Share from './Share'
|
import Share from './Share'
|
||||||
import Upload from './Upload'
|
import Upload from './Upload'
|
||||||
|
import ShareDelete from './ShareDelete'
|
||||||
import { mapState } from 'vuex'
|
import { mapState } from 'vuex'
|
||||||
import buttons from '@/utils/buttons'
|
import buttons from '@/utils/buttons'
|
||||||
|
|
||||||
@@ -35,7 +37,9 @@ export default {
|
|||||||
NewDir,
|
NewDir,
|
||||||
Help,
|
Help,
|
||||||
Replace,
|
Replace,
|
||||||
Upload
|
ReplaceRename,
|
||||||
|
Upload,
|
||||||
|
ShareDelete
|
||||||
},
|
},
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
@@ -87,8 +91,10 @@ export default {
|
|||||||
'newDir',
|
'newDir',
|
||||||
'download',
|
'download',
|
||||||
'replace',
|
'replace',
|
||||||
|
'replace-rename',
|
||||||
'share',
|
'share',
|
||||||
'upload'
|
'upload',
|
||||||
|
'share-delete'
|
||||||
].indexOf(this.show) >= 0;
|
].indexOf(this.show) >= 0;
|
||||||
|
|
||||||
return matched && this.show || null;
|
return matched && this.show || null;
|
||||||
|
|||||||
35
frontend/src/components/prompts/ReplaceRename.vue
Normal file
35
frontend/src/components/prompts/ReplaceRename.vue
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<template>
|
||||||
|
<div class="card floating">
|
||||||
|
<div class="card-title">
|
||||||
|
<h2>{{ $t('prompts.replace') }}</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-content">
|
||||||
|
<p>{{ $t('prompts.replaceMessage') }}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-action">
|
||||||
|
<button class="button button--flat button--grey"
|
||||||
|
@click="$store.commit('closeHovers')"
|
||||||
|
:aria-label="$t('buttons.cancel')"
|
||||||
|
:title="$t('buttons.cancel')">{{ $t('buttons.cancel') }}</button>
|
||||||
|
<button class="button button--flat button--blue"
|
||||||
|
@click="(event) => showConfirm(event, 'rename')"
|
||||||
|
:aria-label="$t('buttons.rename')"
|
||||||
|
:title="$t('buttons.rename')">{{ $t('buttons.rename') }}</button>
|
||||||
|
<button class="button button--flat button--red"
|
||||||
|
@click="(event) => showConfirm(event, 'overwrite')"
|
||||||
|
:aria-label="$t('buttons.replace')"
|
||||||
|
:title="$t('buttons.replace')">{{ $t('buttons.replace') }}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { mapState } from 'vuex'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'replace-rename',
|
||||||
|
computed: mapState(['showConfirm'])
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -1,59 +1,85 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="card floating" id="share">
|
<div class="card floating share__promt__card" id="share">
|
||||||
<div class="card-title">
|
<div class="card-title">
|
||||||
<h2>{{ $t('buttons.share') }}</h2>
|
<h2>{{ $t('buttons.share') }}</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-content">
|
<template v-if="listing">
|
||||||
<ul>
|
<div class="card-content">
|
||||||
<li v-if="!hasPermanent">
|
<table>
|
||||||
<a @click="getPermalink" :aria-label="$t('buttons.permalink')">{{ $t('buttons.permalink') }}</a>
|
<tr>
|
||||||
</li>
|
<th>#</th>
|
||||||
|
<th>{{ $t('settings.shareDuration') }}</th>
|
||||||
|
<th></th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
|
||||||
<li v-for="link in links" :key="link.hash">
|
<tr v-for="link in links" :key="link.hash">
|
||||||
<a :href="buildLink(link.hash)" target="_blank">
|
<td>{{ link.hash }}</td>
|
||||||
<template v-if="link.expire !== 0">{{ humanTime(link.expire) }}</template>
|
<td>
|
||||||
<template v-else>{{ $t('permanent') }}</template>
|
<template v-if="link.expire !== 0">{{ humanTime(link.expire) }}</template>
|
||||||
</a>
|
<template v-else>{{ $t('permanent') }}</template>
|
||||||
|
</td>
|
||||||
|
<td class="small">
|
||||||
|
<button class="action copy-clipboard"
|
||||||
|
:data-clipboard-text="buildLink(link.hash)"
|
||||||
|
:aria-label="$t('buttons.copyToClipboard')"
|
||||||
|
:title="$t('buttons.copyToClipboard')"><i class="material-icons">content_paste</i></button>
|
||||||
|
</td>
|
||||||
|
<td class="small">
|
||||||
|
<button class="action"
|
||||||
|
@click="deleteLink($event, link)"
|
||||||
|
:aria-label="$t('buttons.delete')"
|
||||||
|
:title="$t('buttons.delete')"><i class="material-icons">delete</i></button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
<button class="action"
|
<div class="card-action">
|
||||||
@click="deleteLink($event, link)"
|
<button class="button button--flat button--grey"
|
||||||
:aria-label="$t('buttons.delete')"
|
@click="$store.commit('closeHovers')"
|
||||||
:title="$t('buttons.delete')"><i class="material-icons">delete</i></button>
|
:aria-label="$t('buttons.close')"
|
||||||
|
:title="$t('buttons.close')">{{ $t('buttons.close') }}</button>
|
||||||
|
<button class="button button--flat button--blue"
|
||||||
|
@click="() => switchListing()"
|
||||||
|
:aria-label="$t('buttons.new')"
|
||||||
|
:title="$t('buttons.new')">{{ $t('buttons.new') }}</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
<button class="action copy-clipboard"
|
<template v-else>
|
||||||
:data-clipboard-text="buildLink(link.hash)"
|
<div class="card-content">
|
||||||
:aria-label="$t('buttons.copyToClipboard')"
|
<p>{{ $t('settings.shareDuration') }}</p>
|
||||||
:title="$t('buttons.copyToClipboard')"><i class="material-icons">content_paste</i></button>
|
<div class="input-group input">
|
||||||
</li>
|
<input v-focus
|
||||||
|
type="number"
|
||||||
|
max="2147483647"
|
||||||
|
min="1"
|
||||||
|
@keyup.enter="submit"
|
||||||
|
v-model.trim="time">
|
||||||
|
<select class="right" v-model="unit" :aria-label="$t('time.unit')">
|
||||||
|
<option value="seconds">{{ $t('time.seconds') }}</option>
|
||||||
|
<option value="minutes">{{ $t('time.minutes') }}</option>
|
||||||
|
<option value="hours">{{ $t('time.hours') }}</option>
|
||||||
|
<option value="days">{{ $t('time.days') }}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<p>{{ $t('prompts.optionalPassword') }}</p>
|
||||||
|
<input class="input input--block" type="password" v-model.trim="password">
|
||||||
|
</div>
|
||||||
|
|
||||||
<li>
|
<div class="card-action">
|
||||||
<input v-focus
|
<button class="button button--flat button--grey"
|
||||||
type="number"
|
@click="() => switchListing()"
|
||||||
max="2147483647"
|
:aria-label="$t('buttons.cancel')"
|
||||||
min="0"
|
:title="$t('buttons.cancel')">{{ $t('buttons.cancel') }}</button>
|
||||||
@keyup.enter="submit"
|
<button class="button button--flat button--blue"
|
||||||
v-model.trim="time">
|
@click="submit"
|
||||||
<select v-model="unit" :aria-label="$t('time.unit')">
|
:aria-label="$t('buttons.share')"
|
||||||
<option value="seconds">{{ $t('time.seconds') }}</option>
|
:title="$t('buttons.share')">{{ $t('buttons.share') }}</button>
|
||||||
<option value="minutes">{{ $t('time.minutes') }}</option>
|
</div>
|
||||||
<option value="hours">{{ $t('time.hours') }}</option>
|
</template>
|
||||||
<option value="days">{{ $t('time.days') }}</option>
|
|
||||||
</select>
|
|
||||||
<button class="action"
|
|
||||||
@click="submit"
|
|
||||||
:aria-label="$t('buttons.create')"
|
|
||||||
:title="$t('buttons.create')"><i class="material-icons">add</i></button>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="card-action">
|
|
||||||
<button class="button button--flat"
|
|
||||||
@click="$store.commit('closeHovers')"
|
|
||||||
:aria-label="$t('buttons.close')"
|
|
||||||
:title="$t('buttons.close')">{{ $t('buttons.close') }}</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -70,9 +96,10 @@ export default {
|
|||||||
return {
|
return {
|
||||||
time: '',
|
time: '',
|
||||||
unit: 'hours',
|
unit: 'hours',
|
||||||
hasPermanent: false,
|
|
||||||
links: [],
|
links: [],
|
||||||
clip: null
|
clip: null,
|
||||||
|
password: '',
|
||||||
|
listing: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -97,11 +124,8 @@ export default {
|
|||||||
this.links = links
|
this.links = links
|
||||||
this.sort()
|
this.sort()
|
||||||
|
|
||||||
for (let link of this.links) {
|
if (this.links.length == 0) {
|
||||||
if (link.expire === 0) {
|
this.listing = false
|
||||||
this.hasPermanent = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.$showError(e)
|
this.$showError(e)
|
||||||
@@ -118,22 +142,25 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
submit: async function () {
|
submit: async function () {
|
||||||
if (!this.time) return
|
let isPermanent = !this.time || this.time == 0
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await api.create(this.url, this.time, this.unit)
|
let res = null
|
||||||
|
|
||||||
|
if (isPermanent) {
|
||||||
|
res = await api.create(this.url, this.password)
|
||||||
|
} else {
|
||||||
|
res = await api.create(this.url, this.password, this.time, this.unit)
|
||||||
|
}
|
||||||
|
|
||||||
this.links.push(res)
|
this.links.push(res)
|
||||||
this.sort()
|
this.sort()
|
||||||
} catch (e) {
|
|
||||||
this.$showError(e)
|
this.time = ''
|
||||||
}
|
this.unit = 'hours'
|
||||||
},
|
this.password = ''
|
||||||
getPermalink: async function () {
|
|
||||||
try {
|
this.listing = true
|
||||||
const res = await api.create(this.url)
|
|
||||||
this.links.push(res)
|
|
||||||
this.sort()
|
|
||||||
this.hasPermanent = true
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.$showError(e)
|
this.$showError(e)
|
||||||
}
|
}
|
||||||
@@ -142,8 +169,11 @@ export default {
|
|||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
try {
|
try {
|
||||||
await api.remove(link.hash)
|
await api.remove(link.hash)
|
||||||
if (link.expire === 0) this.hasPermanent = false
|
|
||||||
this.links = this.links.filter(item => item.hash !== link.hash)
|
this.links = this.links.filter(item => item.hash !== link.hash)
|
||||||
|
|
||||||
|
if (this.links.length == 0) {
|
||||||
|
this.listing = false
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.$showError(e)
|
this.$showError(e)
|
||||||
}
|
}
|
||||||
@@ -160,6 +190,13 @@ export default {
|
|||||||
if (b.expire === 0) return 1
|
if (b.expire === 0) return 1
|
||||||
return new Date(a.expire) - new Date(b.expire)
|
return new Date(a.expire) - new Date(b.expire)
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
switchListing () {
|
||||||
|
if (this.links.length == 0 && !this.listing) {
|
||||||
|
this.$store.commit('closeHovers')
|
||||||
|
}
|
||||||
|
|
||||||
|
this.listing = !this.listing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
33
frontend/src/components/prompts/ShareDelete.vue
Normal file
33
frontend/src/components/prompts/ShareDelete.vue
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
<template>
|
||||||
|
<div class="card floating">
|
||||||
|
<div class="card-content">
|
||||||
|
<p>{{ $t('prompts.deleteMessageShare', {path: ''}) }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="card-action">
|
||||||
|
<button @click="$store.commit('closeHovers')"
|
||||||
|
class="button button--flat button--grey"
|
||||||
|
:aria-label="$t('buttons.cancel')"
|
||||||
|
:title="$t('buttons.cancel')">{{ $t('buttons.cancel') }}</button>
|
||||||
|
<button @click="submit"
|
||||||
|
class="button button--flat button--red"
|
||||||
|
:aria-label="$t('buttons.delete')"
|
||||||
|
:title="$t('buttons.delete')">{{ $t('buttons.delete') }}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {mapState} from 'vuex'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'share-delete',
|
||||||
|
computed: {
|
||||||
|
...mapState(['showConfirm'])
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
submit: function () {
|
||||||
|
this.showConfirm()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -27,9 +27,11 @@ export default {
|
|||||||
name: 'upload',
|
name: 'upload',
|
||||||
methods: {
|
methods: {
|
||||||
uploadFile: function () {
|
uploadFile: function () {
|
||||||
|
document.getElementById('upload-input').value = ''
|
||||||
document.getElementById('upload-input').click()
|
document.getElementById('upload-input').click()
|
||||||
},
|
},
|
||||||
uploadFolder: function () {
|
uploadFolder: function () {
|
||||||
|
document.getElementById('upload-folder-input').value = ''
|
||||||
document.getElementById('upload-folder-input').click()
|
document.getElementById('upload-folder-input').click()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,11 @@ export default {
|
|||||||
return this.commands.join(' ')
|
return this.commands.join(' ')
|
||||||
},
|
},
|
||||||
set (value) {
|
set (value) {
|
||||||
this.$emit('update:commands', value.split(' '))
|
if (value !== '') {
|
||||||
|
this.$emit('update:commands', value.split(' '))
|
||||||
|
} else {
|
||||||
|
this.$emit('update:commands', [])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,13 +9,14 @@
|
|||||||
<p><input type="checkbox" :disabled="admin" v-model="perm.delete"> {{ $t('settings.perm.delete') }}</p>
|
<p><input type="checkbox" :disabled="admin" v-model="perm.delete"> {{ $t('settings.perm.delete') }}</p>
|
||||||
<p><input type="checkbox" :disabled="admin" v-model="perm.download"> {{ $t('settings.perm.download') }}</p>
|
<p><input type="checkbox" :disabled="admin" v-model="perm.download"> {{ $t('settings.perm.download') }}</p>
|
||||||
<p><input type="checkbox" :disabled="admin" v-model="perm.modify"> {{ $t('settings.perm.modify') }}</p>
|
<p><input type="checkbox" :disabled="admin" v-model="perm.modify"> {{ $t('settings.perm.modify') }}</p>
|
||||||
<p><input type="checkbox" :disabled="admin" v-model="perm.execute"> {{ $t('settings.perm.execute') }}</p>
|
<p v-if="isExecEnabled"><input type="checkbox" :disabled="admin" v-model="perm.execute"> {{ $t('settings.perm.execute') }}</p>
|
||||||
<p><input type="checkbox" :disabled="admin" v-model="perm.rename"> {{ $t('settings.perm.rename') }}</p>
|
<p><input type="checkbox" :disabled="admin" v-model="perm.rename"> {{ $t('settings.perm.rename') }}</p>
|
||||||
<p><input type="checkbox" :disabled="admin" v-model="perm.share"> {{ $t('settings.perm.share') }}</p>
|
<p><input type="checkbox" :disabled="admin" v-model="perm.share"> {{ $t('settings.perm.share') }}</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { enableExec } from '@/utils/constants'
|
||||||
export default {
|
export default {
|
||||||
name: 'permissions',
|
name: 'permissions',
|
||||||
props: ['perm'],
|
props: ['perm'],
|
||||||
@@ -33,7 +34,8 @@ export default {
|
|||||||
|
|
||||||
this.perm.admin = value
|
this.perm.admin = value
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
isExecEnabled: () => enableExec
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<permissions :perm.sync="user.perm" />
|
<permissions :perm.sync="user.perm" />
|
||||||
<commands :commands.sync="user.commands" />
|
<commands v-if="isExecEnabled" :commands.sync="user.commands" />
|
||||||
|
|
||||||
<div v-if="!isDefault">
|
<div v-if="!isDefault">
|
||||||
<h3>{{ $t('settings.rules') }}</h3>
|
<h3>{{ $t('settings.rules') }}</h3>
|
||||||
@@ -40,6 +40,7 @@ import Languages from './Languages'
|
|||||||
import Rules from './Rules'
|
import Rules from './Rules'
|
||||||
import Permissions from './Permissions'
|
import Permissions from './Permissions'
|
||||||
import Commands from './Commands'
|
import Commands from './Commands'
|
||||||
|
import { enableExec } from '@/utils/constants'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'user',
|
name: 'user',
|
||||||
@@ -53,7 +54,8 @@ export default {
|
|||||||
computed: {
|
computed: {
|
||||||
passwordPlaceholder () {
|
passwordPlaceholder () {
|
||||||
return this.isNew ? '' : this.$t('settings.avoidChanges')
|
return this.isNew ? '' : this.$t('settings.avoidChanges')
|
||||||
}
|
},
|
||||||
|
isExecEnabled: () => enableExec
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
'user.perm.admin': function () {
|
'user.perm.admin': function () {
|
||||||
|
|||||||
@@ -25,8 +25,8 @@
|
|||||||
background: var(--red);
|
background: var(--red);
|
||||||
}
|
}
|
||||||
|
|
||||||
.button--red:hover {
|
.button--blue {
|
||||||
background: var(--dark-red);
|
background: var(--blue);
|
||||||
}
|
}
|
||||||
|
|
||||||
.button--flat {
|
.button--flat {
|
||||||
|
|||||||
@@ -1,29 +1,73 @@
|
|||||||
.share__box {
|
.share {
|
||||||
text-align: center;
|
display: flex;
|
||||||
box-shadow: rgba(0, 0, 0, 0.06) 0px 1px 3px, rgba(0, 0, 0, 0.12) 0px 1px 2px;
|
flex-wrap: wrap;
|
||||||
background: #fff;
|
justify-content: center;
|
||||||
display: block;
|
align-items: flex-start;
|
||||||
border-radius: 0.2em;
|
|
||||||
width: 90%;
|
|
||||||
max-width: 25em;
|
|
||||||
margin: 6em auto;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.share__box__download {
|
@media (max-width: 736px) {
|
||||||
width: 100%;
|
.share {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.share__box {
|
||||||
|
box-shadow: rgba(0, 0, 0, 0.06) 0px 1px 3px, rgba(0, 0, 0, 0.12) 0px 1px 2px;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 0.2em;
|
||||||
|
margin: 5px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.share__box__header {
|
||||||
padding: 1em;
|
padding: 1em;
|
||||||
cursor: pointer;
|
text-align: center;
|
||||||
background: #ffffff;
|
}
|
||||||
color: rgba(0, 0, 0, 0.5);
|
|
||||||
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
|
.share__box__icon i {
|
||||||
|
font-size: 10em;
|
||||||
|
color: #40c4ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.share__box__center {
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.share__box__info {
|
.share__box__info {
|
||||||
padding: 2em 3em;
|
flex: 1 1 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.share__box__title {
|
.share__box__element {
|
||||||
margin-top: .2em;
|
padding: 1em;
|
||||||
overflow: hidden;
|
border-top: 1px solid rgba(0, 0, 0, 0.1);
|
||||||
text-overflow: ellipsis;
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.share__box__items {
|
||||||
|
text-align: left;
|
||||||
|
flex: 10 0 25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.share__box__items #listing.list .item {
|
||||||
|
cursor: pointer;
|
||||||
|
border-left: 0;
|
||||||
|
border-right: 0;
|
||||||
|
border-bottom: 0;
|
||||||
|
border-top: 1px solid rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.share__box__items #listing.list .item .name {
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.share__box__items #listing.list .item .modified {
|
||||||
|
width: 25%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.share__wrong__password {
|
||||||
|
background: var(--red);
|
||||||
|
color: #fff;
|
||||||
|
padding: .5em;
|
||||||
|
text-align: center;
|
||||||
|
animation: .2s opac forwards;
|
||||||
}
|
}
|
||||||
@@ -83,29 +83,29 @@ main {
|
|||||||
width: calc(100% - 19em);
|
width: calc(100% - 19em);
|
||||||
}
|
}
|
||||||
|
|
||||||
#breadcrumbs {
|
.breadcrumbs {
|
||||||
height: 3em;
|
height: 3em;
|
||||||
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
|
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
|
||||||
}
|
}
|
||||||
|
|
||||||
#breadcrumbs span,
|
.breadcrumbs span,
|
||||||
#breadcrumbs {
|
.breadcrumbs {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
color: #6f6f6f;
|
color: #6f6f6f;
|
||||||
}
|
}
|
||||||
|
|
||||||
#breadcrumbs a {
|
.breadcrumbs a {
|
||||||
color: inherit;
|
color: inherit;
|
||||||
transition: .1s ease-in;
|
transition: .1s ease-in;
|
||||||
border-radius: .125em;
|
border-radius: .125em;
|
||||||
}
|
}
|
||||||
|
|
||||||
#breadcrumbs a:hover {
|
.breadcrumbs a:hover {
|
||||||
background-color: rgba(0,0,0, 0.05);
|
background-color: rgba(0,0,0, 0.05);
|
||||||
}
|
}
|
||||||
|
|
||||||
#breadcrumbs span a {
|
.breadcrumbs span a {
|
||||||
padding: .2em;
|
padding: .2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,29 @@
|
|||||||
.dashboard {
|
.dashboard {
|
||||||
max-width: 600px;
|
|
||||||
margin: 1em 0;
|
margin: 1em 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dashboard .row {
|
||||||
|
display: flex;
|
||||||
|
margin: 0 -.5em;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard .row .column {
|
||||||
|
display: flex;
|
||||||
|
padding: 0 .5em;
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard .row .column .card {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media(max-width: 1200px) {
|
||||||
|
.dashboard .row .column {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
color: inherit
|
color: inherit
|
||||||
}
|
}
|
||||||
@@ -28,25 +49,56 @@ p code {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.dashboard #nav {
|
.dashboard #nav {
|
||||||
|
display: flex;
|
||||||
|
padding-bottom: 1em;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard #nav .wrapper {
|
||||||
|
display: flex;
|
||||||
|
flex-grow: 1;
|
||||||
|
border-bottom: 2px solid rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard #nav ul {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
display: flex;
|
display: flex;
|
||||||
color: rgb(84, 110, 122);
|
color: rgb(84, 110, 122);
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
margin: 0 0 1em;
|
padding: 0;
|
||||||
|
margin: 0 0 -2px 0;
|
||||||
font-size: .8em;
|
font-size: .8em;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
justify-content: space-between;
|
justify-content: left;
|
||||||
padding: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.dashboard #nav li {
|
.dashboard #nav ul li {
|
||||||
|
position: relative;
|
||||||
|
padding: 1.5em 2em;
|
||||||
|
white-space: nowrap;
|
||||||
|
border-bottom: 2px solid transparent;
|
||||||
|
transition: .1s ease-in-out all;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard #nav ul li:hover {
|
||||||
|
background: var(--moon-grey);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard #nav ul li.active {
|
||||||
|
border-color: var(--blue);
|
||||||
|
color: var(--blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard #nav ul li.active::before {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 0 0 1em;
|
height: 100%;
|
||||||
border-bottom: 2px solid rgba(0, 0, 0, 0.05);
|
position: absolute;
|
||||||
}
|
top: 0;
|
||||||
|
left: 0;
|
||||||
.dashboard #nav li.active {
|
content: "";
|
||||||
border-color: var(--blue)
|
background: var(--blue);
|
||||||
|
opacity: 0.08;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dashboard #nav i {
|
.dashboard #nav i {
|
||||||
@@ -92,7 +144,7 @@ table tr>*:last-child {
|
|||||||
|
|
||||||
.card {
|
.card {
|
||||||
position: relative;
|
position: relative;
|
||||||
margin: .5rem 0 1rem 0;
|
margin: 0 0 1rem 0;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -2px rgba(0, 0, 0, 0.2);
|
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -2px rgba(0, 0, 0, 0.2);
|
||||||
@@ -151,6 +203,7 @@ table tr>*:last-child {
|
|||||||
|
|
||||||
.card .card-content.full {
|
.card .card-content.full {
|
||||||
padding-bottom: 0;
|
padding-bottom: 0;
|
||||||
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card h2 {
|
.card h2 {
|
||||||
@@ -226,6 +279,18 @@ table tr>*:last-child {
|
|||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.card#share .input-group {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card#share .input-group * {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card#share .input-group input {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
.overlay {
|
.overlay {
|
||||||
background-color: rgba(0, 0, 0, 0.5);
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
position: fixed;
|
position: fixed;
|
||||||
|
|||||||
@@ -6,9 +6,25 @@ header {
|
|||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
height: 4em;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
padding: 0.5em 0.5em 0.5em 1em;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
header > * {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
header title {
|
||||||
|
display: block;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
padding: 0 1em;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
font-size: 1.2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
header .overlay {
|
header .overlay {
|
||||||
@@ -30,17 +46,6 @@ header img {
|
|||||||
height: 2.5em;
|
height: 2.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
header>div:first-child>.action {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
header>div {
|
|
||||||
display: flex;
|
|
||||||
width: 100%;
|
|
||||||
padding: 0.5em 0.5em 0.5em 1em;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
header .action span {
|
header .action span {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
@@ -50,19 +55,8 @@ header>div div {
|
|||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
header>div:last-child div {
|
header .search-button,
|
||||||
display: flex;
|
header .menu-button {
|
||||||
}
|
|
||||||
|
|
||||||
header>div:first-child {
|
|
||||||
height: 4em;
|
|
||||||
}
|
|
||||||
|
|
||||||
header>div:last-child {
|
|
||||||
justify-content: flex-end;
|
|
||||||
}
|
|
||||||
|
|
||||||
header .search-button {
|
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -70,6 +70,7 @@
|
|||||||
box-shadow: rgba(0, 0, 0, 0.06) 0px 1px 3px, rgba(0, 0, 0, 0.12) 0px 1px 2px;
|
box-shadow: rgba(0, 0, 0, 0.06) 0px 1px 3px, rgba(0, 0, 0, 0.12) 0px 1px 2px;
|
||||||
width: 95%;
|
width: 95%;
|
||||||
max-width: 20em;
|
max-width: 20em;
|
||||||
|
z-index: 1;
|
||||||
}
|
}
|
||||||
#file-selection .action {
|
#file-selection .action {
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
@@ -81,6 +82,9 @@
|
|||||||
color: #6f6f6f;
|
color: #6f6f6f;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
}
|
}
|
||||||
|
#file-selection .action span {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
nav {
|
nav {
|
||||||
top: 0;
|
top: 0;
|
||||||
z-index: 99999;
|
z-index: 99999;
|
||||||
@@ -95,7 +99,7 @@
|
|||||||
left: 0;
|
left: 0;
|
||||||
}
|
}
|
||||||
header .search-button,
|
header .search-button,
|
||||||
header>div:first-child>.action {
|
header .menu-button {
|
||||||
display: inherit;
|
display: inherit;
|
||||||
}
|
}
|
||||||
header img {
|
header img {
|
||||||
|
|||||||
@@ -96,10 +96,11 @@
|
|||||||
color: #fff;
|
color: #fff;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
font-size: .75em;
|
font-size: .75em;
|
||||||
width: 1.5em;
|
width: 1.8em;
|
||||||
height: 1.5em;
|
height: 1.8em;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
line-height: 1.25em;
|
line-height: 1.55em;
|
||||||
|
font-weight: bold;
|
||||||
border: 2px solid white;
|
border: 2px solid white;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,35 +118,33 @@
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
#previewer .bar {
|
#previewer header {
|
||||||
width: 100%;
|
background: none;
|
||||||
text-align: right;
|
|
||||||
display: flex;
|
|
||||||
padding: 0.5em;
|
|
||||||
height: 3.7em;
|
|
||||||
}
|
|
||||||
|
|
||||||
#previewer .action:first-of-type {
|
|
||||||
margin-right: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
#previewer .action i {
|
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
#previewer .action:hover {
|
#previewer header > .action i {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 738px) {
|
||||||
|
#previewer header #dropdown .action i {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#previewer header .action:hover {
|
||||||
background-color: rgba(255, 255, 255, 0.3)
|
background-color: rgba(255, 255, 255, 0.3)
|
||||||
}
|
}
|
||||||
|
|
||||||
#previewer .action span {
|
#previewer header .action span {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#previewer .preview {
|
#previewer .preview {
|
||||||
margin: 2em auto 4em;
|
margin-top: 4em;
|
||||||
max-width: 80%;
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
height: calc(100vh - 9.7em);
|
height: calc(100vh - 4em);
|
||||||
}
|
}
|
||||||
|
|
||||||
#previewer .preview pre {
|
#previewer .preview pre {
|
||||||
@@ -160,6 +159,10 @@
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#previewer .preview video {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
#previewer .pdf {
|
#previewer .pdf {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@@ -172,8 +175,25 @@
|
|||||||
#previewer>button {
|
#previewer>button {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 50%;
|
top: calc(50% + 1.85em);
|
||||||
transform: translateY(-50%);
|
transform: translateY(-50%);
|
||||||
|
background-color: rgba(80, 80, 80, .5);
|
||||||
|
color: white;
|
||||||
|
border-radius: 50%;
|
||||||
|
cursor: pointer;
|
||||||
|
border: 0;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
transition: 0.2s ease all;
|
||||||
|
}
|
||||||
|
|
||||||
|
#previewer>button.hidden {
|
||||||
|
opacity: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
#previewer>button>i {
|
||||||
|
padding: 0.4em;
|
||||||
}
|
}
|
||||||
|
|
||||||
#previewer>button:first-of-type {
|
#previewer>button:first-of-type {
|
||||||
@@ -184,6 +204,40 @@
|
|||||||
right: 0.5em;
|
right: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* EDITOR */
|
||||||
|
|
||||||
|
#editor-container {
|
||||||
|
background-color: #fafafa;
|
||||||
|
position: fixed;
|
||||||
|
margin-top: 4em;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
z-index: 9999;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
#previewer .loading {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#editor-container #editor {
|
||||||
|
height: calc(100vh - 8.4em);
|
||||||
|
}
|
||||||
|
|
||||||
|
#editor-container .breadcrumbs {
|
||||||
|
height: 2.3em;
|
||||||
|
padding: 0 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#editor-container .breadcrumbs span {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#editor-container .breadcrumbs i {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
/* * * * * * * * * * * * * * * *
|
/* * * * * * * * * * * * * * * *
|
||||||
* PROMPT *
|
* PROMPT *
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
{
|
{
|
||||||
"permanent": "دائم",
|
|
||||||
"buttons": {
|
"buttons": {
|
||||||
"shell": "Toggle shell",
|
|
||||||
"cancel": "إلغاء",
|
"cancel": "إلغاء",
|
||||||
"close": "إغلاق",
|
"close": "إغلاق",
|
||||||
"copy": "نسخ",
|
"copy": "نسخ",
|
||||||
@@ -10,6 +8,7 @@
|
|||||||
"create": "إنشاء",
|
"create": "إنشاء",
|
||||||
"delete": "حذف",
|
"delete": "حذف",
|
||||||
"download": "تحميل",
|
"download": "تحميل",
|
||||||
|
"hideDotfiles": "",
|
||||||
"info": "معلومات",
|
"info": "معلومات",
|
||||||
"more": "المزيد",
|
"more": "المزيد",
|
||||||
"move": "نقل",
|
"move": "نقل",
|
||||||
@@ -17,25 +16,28 @@
|
|||||||
"new": "جديد",
|
"new": "جديد",
|
||||||
"next": "التالي",
|
"next": "التالي",
|
||||||
"ok": "موافق",
|
"ok": "موافق",
|
||||||
"replace": "استبدال",
|
"permalink": "الحصول على لنك دائم",
|
||||||
"previous": "السابق",
|
"previous": "السابق",
|
||||||
|
"publish": "نشر",
|
||||||
"rename": "إعادة تسمية",
|
"rename": "إعادة تسمية",
|
||||||
|
"replace": "استبدال",
|
||||||
"reportIssue": "إبلاغ عن مشكلة",
|
"reportIssue": "إبلاغ عن مشكلة",
|
||||||
"save": "حفظ",
|
"save": "حفظ",
|
||||||
|
"schedule": "جدولة",
|
||||||
"search": "بحث",
|
"search": "بحث",
|
||||||
"select": "تحديد",
|
"select": "تحديد",
|
||||||
"share": "مشاركة",
|
|
||||||
"publish": "نشر",
|
|
||||||
"selectMultiple": "تحديد متعدد",
|
"selectMultiple": "تحديد متعدد",
|
||||||
"schedule": "جدولة",
|
"share": "مشاركة",
|
||||||
|
"shell": "Toggle shell",
|
||||||
"switchView": "تغيير العرض",
|
"switchView": "تغيير العرض",
|
||||||
"toggleSidebar": "تبديل الشريط الجانبي",
|
"toggleSidebar": "تبديل الشريط الجانبي",
|
||||||
"update": "تحديث",
|
"update": "تحديث",
|
||||||
"upload": "رفع",
|
"upload": "رفع"
|
||||||
"permalink": "الحصول على لنك دائم"
|
|
||||||
},
|
},
|
||||||
"success": {
|
"download": {
|
||||||
"linkCopied": "تم نسخ الملف"
|
"downloadFile": "Download File",
|
||||||
|
"downloadFolder": "Download Folder",
|
||||||
|
"downloadSelected": ""
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"forbidden": "You don't have permissions to access this.",
|
"forbidden": "You don't have permissions to access this.",
|
||||||
@@ -43,11 +45,11 @@
|
|||||||
"notFound": "لا يمكن الوصول لهذا المحتوى."
|
"notFound": "لا يمكن الوصول لهذا المحتوى."
|
||||||
},
|
},
|
||||||
"files": {
|
"files": {
|
||||||
"folders": "المجلدات",
|
|
||||||
"files": "الملفات",
|
|
||||||
"body": "الصفحة",
|
"body": "الصفحة",
|
||||||
"clear": "مسح",
|
"clear": "مسح",
|
||||||
"closePreview": "إغلاق العرض",
|
"closePreview": "إغلاق العرض",
|
||||||
|
"files": "الملفات",
|
||||||
|
"folders": "المجلدات",
|
||||||
"home": "الصفحة الاولى",
|
"home": "الصفحة الاولى",
|
||||||
"lastModified": "آخر تعديل",
|
"lastModified": "آخر تعديل",
|
||||||
"loading": "جاري التحميل...",
|
"loading": "جاري التحميل...",
|
||||||
@@ -56,9 +58,9 @@
|
|||||||
"multipleSelectionEnabled": "التحديد المتعدد مفعل",
|
"multipleSelectionEnabled": "التحديد المتعدد مفعل",
|
||||||
"name": "الإسم",
|
"name": "الإسم",
|
||||||
"size": "الحجم",
|
"size": "الحجم",
|
||||||
|
"sortByLastModified": "الترتيب بآخر تعديل",
|
||||||
"sortByName": "الترتيب بالإسم",
|
"sortByName": "الترتيب بالإسم",
|
||||||
"sortBySize": "الترتيب بالحجم",
|
"sortBySize": "الترتيب بالحجم"
|
||||||
"sortByLastModified": "الترتيب بآخر تعديل"
|
|
||||||
},
|
},
|
||||||
"help": {
|
"help": {
|
||||||
"click": "حدد الملف أو المجلد",
|
"click": "حدد الملف أو المجلد",
|
||||||
@@ -74,18 +76,39 @@
|
|||||||
"f2": "إعادة تسمية الملف",
|
"f2": "إعادة تسمية الملف",
|
||||||
"help": "مساعدة"
|
"help": "مساعدة"
|
||||||
},
|
},
|
||||||
|
"languages": {
|
||||||
|
"ar": "العربية",
|
||||||
|
"de": "Deutsch",
|
||||||
|
"en": "English",
|
||||||
|
"es": "Español",
|
||||||
|
"fr": "Français",
|
||||||
|
"is": "",
|
||||||
|
"it": "Italiano",
|
||||||
|
"ja": "日本語",
|
||||||
|
"ko": "한국어",
|
||||||
|
"nlBE": "",
|
||||||
|
"pl": "Polski",
|
||||||
|
"pt": "Português",
|
||||||
|
"ptBR": "Português (Brasil)",
|
||||||
|
"ro": "",
|
||||||
|
"ru": "Русский",
|
||||||
|
"svSE": "",
|
||||||
|
"zhCN": "中文 (简体)",
|
||||||
|
"zhTW": "中文 (繁體)"
|
||||||
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"password": "كلمة المرور",
|
|
||||||
"passwordConfirm": "Password Confirmation",
|
|
||||||
"submit": "تسجيل دخول",
|
|
||||||
"createAnAccount": "Create an account",
|
"createAnAccount": "Create an account",
|
||||||
"loginInstead": "Already have an account",
|
"loginInstead": "Already have an account",
|
||||||
|
"password": "كلمة المرور",
|
||||||
|
"passwordConfirm": "Password Confirmation",
|
||||||
"passwordsDontMatch": "Passwords don't match",
|
"passwordsDontMatch": "Passwords don't match",
|
||||||
"usernameTaken": "Username already taken",
|
|
||||||
"signup": "Signup",
|
"signup": "Signup",
|
||||||
|
"submit": "تسجيل دخول",
|
||||||
"username": "إسم المستخدم",
|
"username": "إسم المستخدم",
|
||||||
|
"usernameTaken": "Username already taken",
|
||||||
"wrongCredentials": "بيانات دخول خاطئة"
|
"wrongCredentials": "بيانات دخول خاطئة"
|
||||||
},
|
},
|
||||||
|
"permanent": "دائم",
|
||||||
"prompts": {
|
"prompts": {
|
||||||
"copy": "نسخ",
|
"copy": "نسخ",
|
||||||
"copyMessage": "رجاء حدد المكان لنسخ ملفاتك فيه:",
|
"copyMessage": "رجاء حدد المكان لنسخ ملفاتك فيه:",
|
||||||
@@ -102,43 +125,64 @@
|
|||||||
"lastModified": "آخر تعديل",
|
"lastModified": "آخر تعديل",
|
||||||
"move": "نقل",
|
"move": "نقل",
|
||||||
"moveMessage": "إختر مكان جديد للملفات أو المجلدات المراد نقلها:",
|
"moveMessage": "إختر مكان جديد للملفات أو المجلدات المراد نقلها:",
|
||||||
|
"newArchetype": "إنشاء منشور من المنشور الأصلي. الملف سيتم انشاءه في مجلد المحتويات.",
|
||||||
"newDir": "مجلد جديد",
|
"newDir": "مجلد جديد",
|
||||||
"newDirMessage": "رجاء أدخل اسم المجلد الجديد.",
|
"newDirMessage": "رجاء أدخل اسم المجلد الجديد.",
|
||||||
"newFile": "ملف جديد",
|
"newFile": "ملف جديد",
|
||||||
"newFileMessage": "رجاء ادخل اسم الملف الجديد.",
|
"newFileMessage": "رجاء ادخل اسم الملف الجديد.",
|
||||||
"numberDirs": "عدد المجلدات",
|
"numberDirs": "عدد المجلدات",
|
||||||
"numberFiles": "عدد الملفات",
|
"numberFiles": "عدد الملفات",
|
||||||
"replace": "إستبدال",
|
|
||||||
"replaceMessage": "أحد الملفات التي تحاول رفعها يتعارض مع ملف موجود بنفس الإسم. هل تريد إستبدال الملف الموجود؟\n",
|
|
||||||
"rename": "إعادة تسمية",
|
"rename": "إعادة تسمية",
|
||||||
"renameMessage": "إدراج اسم جديد لـ",
|
"renameMessage": "إدراج اسم جديد لـ",
|
||||||
"show": "عرض",
|
"replace": "إستبدال",
|
||||||
"size": "الحجم",
|
"replaceMessage": "أحد الملفات التي تحاول رفعها يتعارض مع ملف موجود بنفس الإسم. هل تريد إستبدال الملف الموجود؟\n",
|
||||||
"schedule": "جدولة",
|
"schedule": "جدولة",
|
||||||
"scheduleMessage": "أختر الوقت والتاريخ لجدولة نشر هذا المقال.",
|
"scheduleMessage": "أختر الوقت والتاريخ لجدولة نشر هذا المقال.",
|
||||||
"newArchetype": "إنشاء منشور من المنشور الأصلي. الملف سيتم انشاءه في مجلد المحتويات."
|
"show": "عرض",
|
||||||
|
"size": "الحجم",
|
||||||
|
"upload": "",
|
||||||
|
"uploadMessage": ""
|
||||||
|
},
|
||||||
|
"search": {
|
||||||
|
"images": "الصور",
|
||||||
|
"music": "الموسيقى",
|
||||||
|
"pdf": "PDF",
|
||||||
|
"pressToSearch": "Press enter to search...",
|
||||||
|
"search": "البحث...",
|
||||||
|
"typeToSearch": "Type to search...",
|
||||||
|
"types": "الأنواع",
|
||||||
|
"video": "فيديوهات"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"instanceName": "Instance name",
|
|
||||||
"brandingDirectoryPath": "Branding directory path",
|
|
||||||
"documentation": "documentation",
|
|
||||||
"branding": "Branding",
|
|
||||||
"disableExternalLinks": "Disable external links (except documentation)",
|
|
||||||
"brandingHelp": "You can costumize how your File Browser instance looks and feels by changing its name, replacing the logo, adding custom styles and even disable external links to GitHub.\nFor more information about custom branding, please check out the {0}.",
|
|
||||||
"admin": "Admin",
|
"admin": "Admin",
|
||||||
"administrator": "Administrator",
|
"administrator": "Administrator",
|
||||||
"allowCommands": "تنفيذ الأوامر",
|
"allowCommands": "تنفيذ الأوامر",
|
||||||
"allowEdit": "تعديل، إعادة تسمية وحذف الملفات والمجلدات",
|
"allowEdit": "تعديل، إعادة تسمية وحذف الملفات والمجلدات",
|
||||||
"allowNew": "إنشاء ملفات ومجلدات جديدة",
|
"allowNew": "إنشاء ملفات ومجلدات جديدة",
|
||||||
"allowPublish": "نشر مقالات وصفحات جديدة",
|
"allowPublish": "نشر مقالات وصفحات جديدة",
|
||||||
|
"allowSignup": "Allow users to signup",
|
||||||
"avoidChanges": "(أتركه فارغاً إن لم ترد تغييره)",
|
"avoidChanges": "(أتركه فارغاً إن لم ترد تغييره)",
|
||||||
|
"branding": "Branding",
|
||||||
|
"brandingDirectoryPath": "Branding directory path",
|
||||||
|
"brandingHelp": "You can customize how your File Browser instance looks and feels by changing its name, replacing the logo, adding custom styles and even disable external links to GitHub.\nFor more information about custom branding, please check out the {0}.",
|
||||||
"changePassword": "تغيير كلمة المرور",
|
"changePassword": "تغيير كلمة المرور",
|
||||||
"commandRunner": "Command runner",
|
"commandRunner": "Command runner",
|
||||||
"commandRunnerHelp": "Here you can set commands that are executed in the named events. You must write one per line. The environment variables {0} and {1} will be available, being {0} relative to {1}. For more information about this feature and the available environment variables, please read the {2}.",
|
"commandRunnerHelp": "Here you can set commands that are executed in the named events. You must write one per line. The environment variables {0} and {1} will be available, being {0} relative to {1}. For more information about this feature and the available environment variables, please read the {2}.",
|
||||||
"commandsUpdated": "تم تحديث الأوامر",
|
"commandsUpdated": "تم تحديث الأوامر",
|
||||||
|
"createUserDir": "Auto create user home dir while adding new user",
|
||||||
"customStylesheet": "ستايل مخصص",
|
"customStylesheet": "ستايل مخصص",
|
||||||
|
"defaultUserDescription": "This are the default settings for new users.",
|
||||||
|
"disableExternalLinks": "Disable external links (except documentation)",
|
||||||
|
"documentation": "documentation",
|
||||||
"examples": "أمثلة",
|
"examples": "أمثلة",
|
||||||
|
"executeOnShell": "Execute on shell",
|
||||||
|
"executeOnShellDescription": "By default, File Browser executes the commands by calling their binaries directly. If you want to run them on a shell instead (such as Bash or PowerShell), you can define it here with the required arguments and flags. If set, the command you execute will be appended as an argument. This apply to both user commands and event hooks.",
|
||||||
|
"globalRules": "This is a global set of allow and disallow rules. They apply to every user. You can define specific rules on each user's settings to override this ones.",
|
||||||
"globalSettings": "إعدادات عامة",
|
"globalSettings": "إعدادات عامة",
|
||||||
|
"hideDotfiles": "",
|
||||||
|
"insertPath": "Insert the path",
|
||||||
|
"insertRegex": "Insert regex expression",
|
||||||
|
"instanceName": "Instance name",
|
||||||
"language": "اللغة",
|
"language": "اللغة",
|
||||||
"lockPassword": "منع المستخدم من تغيير كلمة المرور",
|
"lockPassword": "منع المستخدم من تغيير كلمة المرور",
|
||||||
"newPassword": "كلمة المرور الجديدة",
|
"newPassword": "كلمة المرور الجديدة",
|
||||||
@@ -146,6 +190,16 @@
|
|||||||
"newUser": "مستخدم جديد",
|
"newUser": "مستخدم جديد",
|
||||||
"password": "كلمة المرور",
|
"password": "كلمة المرور",
|
||||||
"passwordUpdated": "تم تغيير كلمة المرور",
|
"passwordUpdated": "تم تغيير كلمة المرور",
|
||||||
|
"path": "",
|
||||||
|
"perm": {
|
||||||
|
"create": "Create files and directories",
|
||||||
|
"delete": "Delete files and directories",
|
||||||
|
"download": "Download",
|
||||||
|
"execute": "Execute commands",
|
||||||
|
"modify": "Edit files",
|
||||||
|
"rename": "Rename or move files and directories",
|
||||||
|
"share": "Share files"
|
||||||
|
},
|
||||||
"permissions": "الصلاحيات",
|
"permissions": "الصلاحيات",
|
||||||
"permissionsHelp": "يمكنك تعيين المستخدم كـ \"مدير\" أو تحديد الصلاحيات بشكل منفرد.\n إذا قمت بتحديد المستخدم كـ \"مدير\"، باقي الخيارات سيتم تحديدها تلقائياً.\n إدارة المستخدمين تبقى صلاحية فريدة للـ \"مدير\" فقط.\n",
|
"permissionsHelp": "يمكنك تعيين المستخدم كـ \"مدير\" أو تحديد الصلاحيات بشكل منفرد.\n إذا قمت بتحديد المستخدم كـ \"مدير\"، باقي الخيارات سيتم تحديدها تلقائياً.\n إدارة المستخدمين تبقى صلاحية فريدة للـ \"مدير\" فقط.\n",
|
||||||
"profileSettings": "إعدادات الحساب",
|
"profileSettings": "إعدادات الحساب",
|
||||||
@@ -155,82 +209,46 @@
|
|||||||
"rulesHelp": "يمكنك هنا تحديد مجموعة من شروط السماح والمنع لهذا المستخدم. الملفات الممنوعة لن تظهر ضمن القائمة لهذا المستخدم ولن يستطيع الوصول لها. هنا ندعم الـ regex والـ relative path لنطاق المستخدمين.\n",
|
"rulesHelp": "يمكنك هنا تحديد مجموعة من شروط السماح والمنع لهذا المستخدم. الملفات الممنوعة لن تظهر ضمن القائمة لهذا المستخدم ولن يستطيع الوصول لها. هنا ندعم الـ regex والـ relative path لنطاق المستخدمين.\n",
|
||||||
"scope": "نطاق",
|
"scope": "نطاق",
|
||||||
"settingsUpdated": "تم تعديل الإعدادات",
|
"settingsUpdated": "تم تعديل الإعدادات",
|
||||||
|
"shareDuration": "",
|
||||||
|
"shareManagement": "",
|
||||||
|
"singleClick": "",
|
||||||
|
"themes": {
|
||||||
|
"dark": "",
|
||||||
|
"light": "",
|
||||||
|
"title": ""
|
||||||
|
},
|
||||||
"user": "المستخدم",
|
"user": "المستخدم",
|
||||||
"userCommands": "الأوامر",
|
"userCommands": "الأوامر",
|
||||||
"userCommandsHelp": "الأوامر المتاحة لهذا المستخدم مفصولة فيما بينها بمسافة. مثال:\n",
|
"userCommandsHelp": "الأوامر المتاحة لهذا المستخدم مفصولة فيما بينها بمسافة. مثال:\n",
|
||||||
"userCreated": "تم إنشاء المستخدم",
|
"userCreated": "تم إنشاء المستخدم",
|
||||||
|
"userDefaults": "User default settings",
|
||||||
"userDeleted": "تم حذف المستخدم",
|
"userDeleted": "تم حذف المستخدم",
|
||||||
"userManagement": "إدارة المستخدمين",
|
"userManagement": "إدارة المستخدمين",
|
||||||
"username": "إسم المستخدم",
|
|
||||||
"users": "المستخدمين",
|
|
||||||
"globalRules": "This is a global set of allow and disallow rules. They apply to every user. You can define specific rules on each user's settings to override this ones.",
|
|
||||||
"allowSignup": "Allow users to signup",
|
|
||||||
"createUserDir": "Auto create user home dir while adding new user",
|
|
||||||
"insertRegex": "Insert regex expression",
|
|
||||||
"insertPath": "Insert the path",
|
|
||||||
"userUpdated": "تم تعديل المستخدم",
|
"userUpdated": "تم تعديل المستخدم",
|
||||||
"userDefaults": "User default settings",
|
"username": "إسم المستخدم",
|
||||||
"defaultUserDescription": "This are the default settings for new users.",
|
"users": "المستخدمين"
|
||||||
"executeOnShell": "Execute on shell",
|
|
||||||
"executeOnShellDescription": "By default, File Browser executes the commands by calling their binaries directly. If you want to run them on a shell instead (such as Bash or PowerShell), you can define it here with the required arguments and flags. If set, the command you execute will be appended as an argument. This apply to both user commands and event hooks.",
|
|
||||||
"perm": {
|
|
||||||
"create": "Create files and directories",
|
|
||||||
"delete": "Delete files and directories",
|
|
||||||
"download": "Download",
|
|
||||||
"modify": "Edit files",
|
|
||||||
"execute": "Execute commands",
|
|
||||||
"rename": "Rename or move files and directories",
|
|
||||||
"share": "Share files"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"sidebar": {
|
"sidebar": {
|
||||||
"help": "مساعدة",
|
"help": "مساعدة",
|
||||||
|
"hugoNew": "هيوجو جديد",
|
||||||
"login": "Login",
|
"login": "Login",
|
||||||
"signup": "Signup",
|
|
||||||
"logout": "تسجيل خروج",
|
"logout": "تسجيل خروج",
|
||||||
"myFiles": "ملفاتي",
|
"myFiles": "ملفاتي",
|
||||||
"newFile": "ملف جديد",
|
"newFile": "ملف جديد",
|
||||||
"newFolder": "مجلد جديد",
|
"newFolder": "مجلد جديد",
|
||||||
|
"preview": "معاينة",
|
||||||
"settings": "الإعدادات",
|
"settings": "الإعدادات",
|
||||||
"siteSettings": "إعدادات الموقع",
|
"signup": "Signup",
|
||||||
"hugoNew": "هيوجو جديد",
|
"siteSettings": "إعدادات الموقع"
|
||||||
"preview": "معاينة"
|
|
||||||
},
|
},
|
||||||
"search": {
|
"success": {
|
||||||
"images": "الصور",
|
"linkCopied": "تم نسخ الملف"
|
||||||
"music": "الموسيقى",
|
|
||||||
"pdf": "PDF",
|
|
||||||
"types": "الأنواع",
|
|
||||||
"video": "فيديوهات",
|
|
||||||
"search": "البحث...",
|
|
||||||
"typeToSearch": "Type to search...",
|
|
||||||
"pressToSearch": "Press enter to search..."
|
|
||||||
},
|
|
||||||
"languages": {
|
|
||||||
"ar": "العربية",
|
|
||||||
"en": "English",
|
|
||||||
"it": "Italiano",
|
|
||||||
"fr": "Français",
|
|
||||||
"pt": "Português",
|
|
||||||
"ptBR": "Português (Brasil)",
|
|
||||||
"ja": "日本語",
|
|
||||||
"zhCN": "中文 (简体)",
|
|
||||||
"zhTW": "中文 (繁體)",
|
|
||||||
"es": "Español",
|
|
||||||
"de": "Deutsch",
|
|
||||||
"ru": "Русский",
|
|
||||||
"pl": "Polski",
|
|
||||||
"ko": "한국어"
|
|
||||||
},
|
},
|
||||||
"time": {
|
"time": {
|
||||||
"unit": "وحدة الوقت",
|
"days": "أيام",
|
||||||
"seconds": "ثواني",
|
|
||||||
"minutes": "دقائق",
|
|
||||||
"hours": "ساعات",
|
"hours": "ساعات",
|
||||||
"days": "أيام"
|
"minutes": "دقائق",
|
||||||
},
|
"seconds": "ثواني",
|
||||||
"download": {
|
"unit": "وحدة الوقت"
|
||||||
"downloadFile": "Download File",
|
|
||||||
"downloadFolder": "Download Folder"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
{
|
{
|
||||||
"permanent": "Permanent",
|
|
||||||
"buttons": {
|
"buttons": {
|
||||||
"shell": "Kommandozeile ein/ausschalten",
|
|
||||||
"cancel": "Abbrechen",
|
"cancel": "Abbrechen",
|
||||||
"close": "Schließen",
|
"close": "Schließen",
|
||||||
"copy": "Kopieren",
|
"copy": "Kopieren",
|
||||||
@@ -10,6 +8,7 @@
|
|||||||
"create": "Neu",
|
"create": "Neu",
|
||||||
"delete": "Löschen",
|
"delete": "Löschen",
|
||||||
"download": "Downloaden",
|
"download": "Downloaden",
|
||||||
|
"hideDotfiles": "",
|
||||||
"info": "Info",
|
"info": "Info",
|
||||||
"more": "mehr",
|
"more": "mehr",
|
||||||
"move": "Verschieben",
|
"move": "Verschieben",
|
||||||
@@ -17,25 +16,28 @@
|
|||||||
"new": "Neu",
|
"new": "Neu",
|
||||||
"next": "nächste",
|
"next": "nächste",
|
||||||
"ok": "OK",
|
"ok": "OK",
|
||||||
"replace": "Ersetzen",
|
"permalink": "permanenten Verweis anzeigen",
|
||||||
"previous": "vorherige",
|
"previous": "vorherige",
|
||||||
|
"publish": "Veröffentlichen",
|
||||||
"rename": "umbenennen",
|
"rename": "umbenennen",
|
||||||
|
"replace": "Ersetzen",
|
||||||
"reportIssue": "Fehler melden",
|
"reportIssue": "Fehler melden",
|
||||||
"save": "Speichern",
|
"save": "Speichern",
|
||||||
|
"schedule": "Planung",
|
||||||
"search": "Suchen",
|
"search": "Suchen",
|
||||||
"select": "Auswählen",
|
"select": "Auswählen",
|
||||||
"share": "Teilen",
|
|
||||||
"publish": "Veröffentlichen",
|
|
||||||
"selectMultiple": "Mehrfachauswahl",
|
"selectMultiple": "Mehrfachauswahl",
|
||||||
"schedule": "Planung",
|
"share": "Teilen",
|
||||||
|
"shell": "Kommandozeile ein/ausschalten",
|
||||||
"switchView": "Ansicht wechseln",
|
"switchView": "Ansicht wechseln",
|
||||||
"toggleSidebar": "Seitenleiste anzeigen",
|
"toggleSidebar": "Seitenleiste anzeigen",
|
||||||
"update": "Update",
|
"update": "Update",
|
||||||
"upload": "Upload",
|
"upload": "Upload"
|
||||||
"permalink": "permanenten Verweis anzeigen"
|
|
||||||
},
|
},
|
||||||
"success": {
|
"download": {
|
||||||
"linkCopied": "Verweis wurde kopiert!"
|
"downloadFile": "Download Datei",
|
||||||
|
"downloadFolder": "Download Ordner",
|
||||||
|
"downloadSelected": ""
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"forbidden": "Sie haben keine Berechtigung dies abzurufen.",
|
"forbidden": "Sie haben keine Berechtigung dies abzurufen.",
|
||||||
@@ -43,11 +45,11 @@
|
|||||||
"notFound": "Dieser Ort kann nicht angezeigt werden."
|
"notFound": "Dieser Ort kann nicht angezeigt werden."
|
||||||
},
|
},
|
||||||
"files": {
|
"files": {
|
||||||
"folders": "Ordner",
|
|
||||||
"files": "Dateien",
|
|
||||||
"body": "Body",
|
"body": "Body",
|
||||||
"clear": "Clear",
|
"clear": "Clear",
|
||||||
"closePreview": "Vorschau schließen",
|
"closePreview": "Vorschau schließen",
|
||||||
|
"files": "Dateien",
|
||||||
|
"folders": "Ordner",
|
||||||
"home": "Home",
|
"home": "Home",
|
||||||
"lastModified": "zuletzt verändert",
|
"lastModified": "zuletzt verändert",
|
||||||
"loading": "Lade...",
|
"loading": "Lade...",
|
||||||
@@ -56,9 +58,9 @@
|
|||||||
"multipleSelectionEnabled": "Mehrfachauswahl ausgewählt",
|
"multipleSelectionEnabled": "Mehrfachauswahl ausgewählt",
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
"size": "Größe",
|
"size": "Größe",
|
||||||
|
"sortByLastModified": "Nach Änderungsdatum sortieren",
|
||||||
"sortByName": "Nach Namen sortieren",
|
"sortByName": "Nach Namen sortieren",
|
||||||
"sortBySize": "Nach Größe sortieren",
|
"sortBySize": "Nach Größe sortieren"
|
||||||
"sortByLastModified": "Nach Änderungsdatum sortieren"
|
|
||||||
},
|
},
|
||||||
"help": {
|
"help": {
|
||||||
"click": "wähle Datei oder Ordner",
|
"click": "wähle Datei oder Ordner",
|
||||||
@@ -74,18 +76,39 @@
|
|||||||
"f2": "Datei umbenennen",
|
"f2": "Datei umbenennen",
|
||||||
"help": "Hilfe"
|
"help": "Hilfe"
|
||||||
},
|
},
|
||||||
|
"languages": {
|
||||||
|
"ar": "العربية",
|
||||||
|
"de": "Deutsch",
|
||||||
|
"en": "English",
|
||||||
|
"es": "Español",
|
||||||
|
"fr": "Français",
|
||||||
|
"is": "",
|
||||||
|
"it": "Italiano",
|
||||||
|
"ja": "日本語",
|
||||||
|
"ko": "한국어",
|
||||||
|
"nlBE": "",
|
||||||
|
"pl": "Polski",
|
||||||
|
"pt": "Português",
|
||||||
|
"ptBR": "Português (Brasil)",
|
||||||
|
"ro": "",
|
||||||
|
"ru": "Русский",
|
||||||
|
"svSE": "",
|
||||||
|
"zhCN": "中文 (简体)",
|
||||||
|
"zhTW": "中文 (繁體)"
|
||||||
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"password": "Passwort",
|
|
||||||
"passwordConfirm": "Passwort Bestätigung",
|
|
||||||
"submit": "Login",
|
|
||||||
"createAnAccount": "Account erstellen",
|
"createAnAccount": "Account erstellen",
|
||||||
"loginInstead": "Account besteht bereits",
|
"loginInstead": "Account besteht bereits",
|
||||||
|
"password": "Passwort",
|
||||||
|
"passwordConfirm": "Passwort Bestätigung",
|
||||||
"passwordsDontMatch": "Passwörter stimmen nicht überein",
|
"passwordsDontMatch": "Passwörter stimmen nicht überein",
|
||||||
"usernameTaken": "Benutzername ist bereits vergeben",
|
|
||||||
"signup": "Registrieren",
|
"signup": "Registrieren",
|
||||||
|
"submit": "Login",
|
||||||
"username": "Benutzername",
|
"username": "Benutzername",
|
||||||
|
"usernameTaken": "Benutzername ist bereits vergeben",
|
||||||
"wrongCredentials": "Falsche Zugangsdaten"
|
"wrongCredentials": "Falsche Zugangsdaten"
|
||||||
},
|
},
|
||||||
|
"permanent": "Permanent",
|
||||||
"prompts": {
|
"prompts": {
|
||||||
"copy": "Kopieren",
|
"copy": "Kopieren",
|
||||||
"copyMessage": "Wählen Sie einen Zielort zum Kopieren:",
|
"copyMessage": "Wählen Sie einen Zielort zum Kopieren:",
|
||||||
@@ -102,43 +125,64 @@
|
|||||||
"lastModified": "Zuletzt geändert",
|
"lastModified": "Zuletzt geändert",
|
||||||
"move": "Verschieben",
|
"move": "Verschieben",
|
||||||
"moveMessage": "Wählen sie einen neuen Platz für ihre Datei(en)/Ordner:",
|
"moveMessage": "Wählen sie einen neuen Platz für ihre Datei(en)/Ordner:",
|
||||||
|
"newArchetype": "Erstelle neuen Beitrag auf dem Archetyp. Ihre Datei wird im Inhalteordner erstellt.",
|
||||||
"newDir": "Neuer Ordner",
|
"newDir": "Neuer Ordner",
|
||||||
"newDirMessage": "Geben Sie den Namen des neuen Ordners an.",
|
"newDirMessage": "Geben Sie den Namen des neuen Ordners an.",
|
||||||
"newFile": "Neue Datei",
|
"newFile": "Neue Datei",
|
||||||
"newFileMessage": "Geben Sie den Namen der neuen Datei an.",
|
"newFileMessage": "Geben Sie den Namen der neuen Datei an.",
|
||||||
"numberDirs": "Anzahl der Ordner",
|
"numberDirs": "Anzahl der Ordner",
|
||||||
"numberFiles": "Anzahl der Dateien",
|
"numberFiles": "Anzahl der Dateien",
|
||||||
"replace": "Ersetzen",
|
|
||||||
"replaceMessage": "Eine der Datei mit dem gleichen Namen, wie die Sie hochladen wollen, existiert bereits. Soll die vorhandene Datei ersetzt werden ?\n",
|
|
||||||
"rename": "Umbenennen",
|
"rename": "Umbenennen",
|
||||||
"renameMessage": "Fügen Sie einen Namen ein für",
|
"renameMessage": "Fügen Sie einen Namen ein für",
|
||||||
"show": "Anzeigen",
|
"replace": "Ersetzen",
|
||||||
"size": "Größe",
|
"replaceMessage": "Eine der Datei mit dem gleichen Namen, wie die Sie hochladen wollen, existiert bereits. Soll die vorhandene Datei ersetzt werden ?\n",
|
||||||
"schedule": "Plan",
|
"schedule": "Plan",
|
||||||
"scheduleMessage": "Wählen Sie ein Datum und eine Zeit für die Veröffentlichung dieses Beitrags.",
|
"scheduleMessage": "Wählen Sie ein Datum und eine Zeit für die Veröffentlichung dieses Beitrags.",
|
||||||
"newArchetype": "Erstelle neuen Beitrag auf dem Archetyp. Ihre Datei wird im Inhalteordner erstellt."
|
"show": "Anzeigen",
|
||||||
|
"size": "Größe",
|
||||||
|
"upload": "",
|
||||||
|
"uploadMessage": ""
|
||||||
|
},
|
||||||
|
"search": {
|
||||||
|
"images": "Bilder",
|
||||||
|
"music": "Musik",
|
||||||
|
"pdf": "PDF",
|
||||||
|
"pressToSearch": "Drücken sie Enter um zu suchen...",
|
||||||
|
"search": "Suche...",
|
||||||
|
"typeToSearch": "Tippe um zu suchen...",
|
||||||
|
"types": "Typen",
|
||||||
|
"video": "Video"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"instanceName": "Instanzname",
|
|
||||||
"brandingDirectoryPath": "Markenverzeichnispfad",
|
|
||||||
"documentation": "Dokumentation",
|
|
||||||
"branding": "Marke",
|
|
||||||
"disableExternalLinks": "Externe Links deaktivieren (außer Dokumentation)",
|
|
||||||
"brandingHelp": "Sie können das Erscheinungsbild ihres File Browser anpassen, in dem sie den Namen ändern, das Logo austauchsen oder eigene Stile definieren und sogar externe Links zu GitHub deaktivieren.\nUm mehr Informationen zum Anpassen an ihre Marke zu bekommen, gehen sie bitte zu {0}.",
|
|
||||||
"admin": "Admin",
|
"admin": "Admin",
|
||||||
"administrator": "Administrator",
|
"administrator": "Administrator",
|
||||||
"allowCommands": "Befehle ausführen",
|
"allowCommands": "Befehle ausführen",
|
||||||
"allowEdit": "Bearbeiten, Umbenennen und Löschen von Dateien oder Ordnern",
|
"allowEdit": "Bearbeiten, Umbenennen und Löschen von Dateien oder Ordnern",
|
||||||
"allowNew": "Erstellen neuer Dateien und Ordner",
|
"allowNew": "Erstellen neuer Dateien und Ordner",
|
||||||
"allowPublish": "Veröffentlichen von neuen Beiträgen und Seiten",
|
"allowPublish": "Veröffentlichen von neuen Beiträgen und Seiten",
|
||||||
|
"allowSignup": "Erlaube Benutzern sich zu registrieren",
|
||||||
"avoidChanges": "(leer lassen um Änderungen zu vermeiden)",
|
"avoidChanges": "(leer lassen um Änderungen zu vermeiden)",
|
||||||
|
"branding": "Marke",
|
||||||
|
"brandingDirectoryPath": "Markenverzeichnispfad",
|
||||||
|
"brandingHelp": "Sie können das Erscheinungsbild ihres File Browser anpassen, in dem sie den Namen ändern, das Logo austauchsen oder eigene Stile definieren und sogar externe Links zu GitHub deaktivieren.\nUm mehr Informationen zum Anpassen an ihre Marke zu bekommen, gehen sie bitte zu {0}.",
|
||||||
"changePassword": "Ändere das Passwort",
|
"changePassword": "Ändere das Passwort",
|
||||||
"commandRunner": "Befehlseingabe",
|
"commandRunner": "Befehlseingabe",
|
||||||
"commandRunnerHelp": "Hier könne sie Befehle eintragen die bei benannten Aktionen ausgeführt werden. Sie müssen pro Zeile jeweils einen eingeben. Die Umgebungsvariable {0} und {1} sind verfügbar, wobei {0} relative zu {1} ist. Für mehr Informationen über diese Funktion und die verfügbaren Umgebungsvariablen, lesen sie bitte das {2}.",
|
"commandRunnerHelp": "Hier könne sie Befehle eintragen die bei benannten Aktionen ausgeführt werden. Sie müssen pro Zeile jeweils einen eingeben. Die Umgebungsvariable {0} und {1} sind verfügbar, wobei {0} relative zu {1} ist. Für mehr Informationen über diese Funktion und die verfügbaren Umgebungsvariablen, lesen sie bitte das {2}.",
|
||||||
"commandsUpdated": "Befehle aktualisiert!",
|
"commandsUpdated": "Befehle aktualisiert!",
|
||||||
|
"createUserDir": "Auto create user home dir while adding new user",
|
||||||
"customStylesheet": "Individuelles Stylesheet",
|
"customStylesheet": "Individuelles Stylesheet",
|
||||||
|
"defaultUserDescription": "Das sind die Standard Einstellunge für Benutzer",
|
||||||
|
"disableExternalLinks": "Externe Links deaktivieren (außer Dokumentation)",
|
||||||
|
"documentation": "Dokumentation",
|
||||||
"examples": "Beispiele",
|
"examples": "Beispiele",
|
||||||
|
"executeOnShell": "In shell ausführen",
|
||||||
|
"executeOnShellDescription": "Es ist voreingestellt das der File Brower Befehle ausführt in dem er die Befehlsdatein direkt auf ruft. Wenn sie wollen das sie auf einer Kommandozeile (wo Bash oder PowerShell) laufen, könne sie das hier definieren mit allen bennötigten Argumenten und Optionen. Wenn gesetzt, wird das Kommando das ausgeführt werden soll als Parameter angehängt. Das gilt für Benuzerkommandos sowie auch für Ereignisse.",
|
||||||
|
"globalRules": "Das ist ein globales Set von Regeln die erlauben oder nicht erlauben. Die sind für alle Benutzer zutreffend. Es können spezielle Regeln in den Einstellungen der Benutzer definiert werden die diese übersteuern.",
|
||||||
"globalSettings": "Globale Einstellungen",
|
"globalSettings": "Globale Einstellungen",
|
||||||
|
"hideDotfiles": "",
|
||||||
|
"insertPath": "Pfad einfügen",
|
||||||
|
"insertRegex": "Regex Ausdruck einfügen",
|
||||||
|
"instanceName": "Instanzname",
|
||||||
"language": "Sprache",
|
"language": "Sprache",
|
||||||
"lockPassword": "Verhindere, dass der Benutzer sein Passwort ändert",
|
"lockPassword": "Verhindere, dass der Benutzer sein Passwort ändert",
|
||||||
"newPassword": "Ihr neues Passwort.",
|
"newPassword": "Ihr neues Passwort.",
|
||||||
@@ -146,6 +190,16 @@
|
|||||||
"newUser": "Neuer Benutzer",
|
"newUser": "Neuer Benutzer",
|
||||||
"password": "Passwort",
|
"password": "Passwort",
|
||||||
"passwordUpdated": "Passwort aktualisiert!",
|
"passwordUpdated": "Passwort aktualisiert!",
|
||||||
|
"path": "",
|
||||||
|
"perm": {
|
||||||
|
"create": "Dateien und Ordner erstellen",
|
||||||
|
"delete": "Dateien und Ordner löschen",
|
||||||
|
"download": "Download",
|
||||||
|
"execute": "Befehle ausführen",
|
||||||
|
"modify": "Dateien editieren",
|
||||||
|
"rename": "Umbenennen oder Verschieben von Dateien oder Ordnern",
|
||||||
|
"share": "Datei teilen"
|
||||||
|
},
|
||||||
"permissions": "Berechtigungen",
|
"permissions": "Berechtigungen",
|
||||||
"permissionsHelp": "Sie können einem Benutzer Administratorrechte einräumen oder die Berechtigunen individuell festlegen. Wenn Sie \"Administrator\" auswählen, werden alle anderen Rechte automatisch vergeben. Die Nutzerverwaltung kann nur durch einen Administrator erfolgen.\n",
|
"permissionsHelp": "Sie können einem Benutzer Administratorrechte einräumen oder die Berechtigunen individuell festlegen. Wenn Sie \"Administrator\" auswählen, werden alle anderen Rechte automatisch vergeben. Die Nutzerverwaltung kann nur durch einen Administrator erfolgen.\n",
|
||||||
"profileSettings": "Profileinstellungen",
|
"profileSettings": "Profileinstellungen",
|
||||||
@@ -155,82 +209,46 @@
|
|||||||
"rulesHelp": "Hier können Sie erlaubte und verbotene Aktionen für einen einzelnen Benutzer festlegen. Bockierte Dateien werden nicht im Listing angezeigt und sind nicht erreichbar für den Nutzer. Wir unterstützen reguläre Ausdrücke (Regex) und Pfade die relativ zum Benutzerordner sind. \n",
|
"rulesHelp": "Hier können Sie erlaubte und verbotene Aktionen für einen einzelnen Benutzer festlegen. Bockierte Dateien werden nicht im Listing angezeigt und sind nicht erreichbar für den Nutzer. Wir unterstützen reguläre Ausdrücke (Regex) und Pfade die relativ zum Benutzerordner sind. \n",
|
||||||
"scope": "Scope",
|
"scope": "Scope",
|
||||||
"settingsUpdated": "Einstellungen aktualisiert!",
|
"settingsUpdated": "Einstellungen aktualisiert!",
|
||||||
|
"shareDuration": "",
|
||||||
|
"shareManagement": "",
|
||||||
|
"singleClick": "",
|
||||||
|
"themes": {
|
||||||
|
"dark": "",
|
||||||
|
"light": "",
|
||||||
|
"title": ""
|
||||||
|
},
|
||||||
"user": "Benutzer",
|
"user": "Benutzer",
|
||||||
"userCommands": "Befehle",
|
"userCommands": "Befehle",
|
||||||
"userCommandsHelp": "Eine Liste, mit einem Leerzeichen als Trennung, mit den für diesen Nutzer verfügbaren Befehlen. Example:\n",
|
"userCommandsHelp": "Eine Liste, mit einem Leerzeichen als Trennung, mit den für diesen Nutzer verfügbaren Befehlen. Example:\n",
|
||||||
"userCreated": "Benutzer angelegt!",
|
"userCreated": "Benutzer angelegt!",
|
||||||
|
"userDefaults": "Benutzer Standard Einstellungen",
|
||||||
"userDeleted": "Benutzer gelöscht!",
|
"userDeleted": "Benutzer gelöscht!",
|
||||||
"userManagement": "Benutzerverwaltung",
|
"userManagement": "Benutzerverwaltung",
|
||||||
"username": "Nutzername",
|
|
||||||
"users": "Nutzer",
|
|
||||||
"globalRules": "Das ist ein globales Set von Regeln die erlauben oder nicht erlauben. Die sind für alle Benutzer zutreffend. Es können spezielle Regeln in den Einstellungen der Benutzer definiert werden die diese übersteuern.",
|
|
||||||
"allowSignup": "Erlaube Benutzern sich zu registrieren",
|
|
||||||
"createUserDir": "Auto create user home dir while adding new user",
|
|
||||||
"insertRegex": "Regex Ausdruck einfügen",
|
|
||||||
"insertPath": "Pfad einfügen",
|
|
||||||
"userUpdated": "Benutzer aktualisiert!",
|
"userUpdated": "Benutzer aktualisiert!",
|
||||||
"userDefaults": "Benutzer Standard Einstellungen",
|
"username": "Nutzername",
|
||||||
"defaultUserDescription": "Das sind die Standard Einstellunge für Benutzer",
|
"users": "Nutzer"
|
||||||
"executeOnShell": "In shell ausführen",
|
|
||||||
"executeOnShellDescription": "Es ist voreingestellt das der File Brower Befehle ausführt in dem er die Befehlsdatein direkt auf ruft. Wenn sie wollen das sie auf einer Kommandozeile (wo Bash oder PowerShell) laufen, könne sie das hier definieren mit allen bennötigten Argumenten und Optionen. Wenn gesetzt, wird das Kommando das ausgeführt werden soll als Parameter angehängt. Das gilt für Benuzerkommandos sowie auch für Ereignisse.",
|
|
||||||
"perm": {
|
|
||||||
"create": "Dateien und Ordner erstellen",
|
|
||||||
"delete": "Dateien und Ordner löschen",
|
|
||||||
"download": "Download",
|
|
||||||
"modify": "Dateien editieren",
|
|
||||||
"execute": "Befehle ausführen",
|
|
||||||
"rename": "Umbenennen oder Verschieben von Dateien oder Ordnern",
|
|
||||||
"share": "Datei teilen"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"sidebar": {
|
"sidebar": {
|
||||||
"help": "Hilfe",
|
"help": "Hilfe",
|
||||||
|
"hugoNew": "Hugo Neu",
|
||||||
"login": "Anmelden",
|
"login": "Anmelden",
|
||||||
"signup": "Registrieren",
|
|
||||||
"logout": "Logout",
|
"logout": "Logout",
|
||||||
"myFiles": "Meine Dateien",
|
"myFiles": "Meine Dateien",
|
||||||
"newFile": "Neue Datei",
|
"newFile": "Neue Datei",
|
||||||
"newFolder": "Neuer Ordner",
|
"newFolder": "Neuer Ordner",
|
||||||
|
"preview": "Vorschau",
|
||||||
"settings": "Einstellungen",
|
"settings": "Einstellungen",
|
||||||
"siteSettings": "Seiteneinstellungen",
|
"signup": "Registrieren",
|
||||||
"hugoNew": "Hugo Neu",
|
"siteSettings": "Seiteneinstellungen"
|
||||||
"preview": "Vorschau"
|
|
||||||
},
|
},
|
||||||
"search": {
|
"success": {
|
||||||
"images": "Bilder",
|
"linkCopied": "Verweis wurde kopiert!"
|
||||||
"music": "Musik",
|
|
||||||
"pdf": "PDF",
|
|
||||||
"types": "Typen",
|
|
||||||
"video": "Video",
|
|
||||||
"search": "Suche...",
|
|
||||||
"typeToSearch": "Tippe um zu suchen...",
|
|
||||||
"pressToSearch": "Drücken sie Enter um zu suchen..."
|
|
||||||
},
|
|
||||||
"languages": {
|
|
||||||
"ar": "العربية",
|
|
||||||
"en": "English",
|
|
||||||
"it": "Italiano",
|
|
||||||
"fr": "Français",
|
|
||||||
"pt": "Português",
|
|
||||||
"ptBR": "Português (Brasil)",
|
|
||||||
"ja": "日本語",
|
|
||||||
"zhCN": "中文 (简体)",
|
|
||||||
"zhTW": "中文 (繁體)",
|
|
||||||
"es": "Español",
|
|
||||||
"de": "Deutsch",
|
|
||||||
"ru": "Русский",
|
|
||||||
"pl": "Polski",
|
|
||||||
"ko": "한국어"
|
|
||||||
},
|
},
|
||||||
"time": {
|
"time": {
|
||||||
"unit": "Zeiteinheit",
|
"days": "Tage",
|
||||||
"seconds": "Sekunden",
|
|
||||||
"minutes": "Minuten",
|
|
||||||
"hours": "Stunden",
|
"hours": "Stunden",
|
||||||
"days": "Tage"
|
"minutes": "Minuten",
|
||||||
},
|
"seconds": "Sekunden",
|
||||||
"download": {
|
"unit": "Zeiteinheit"
|
||||||
"downloadFile": "Download Datei",
|
|
||||||
"downloadFolder": "Download Ordner"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
{
|
{
|
||||||
"permanent": "Permanent",
|
|
||||||
"buttons": {
|
"buttons": {
|
||||||
"shell": "Toggle shell",
|
|
||||||
"cancel": "Cancel",
|
"cancel": "Cancel",
|
||||||
"close": "Close",
|
"close": "Close",
|
||||||
"copy": "Copy",
|
"copy": "Copy",
|
||||||
@@ -10,6 +8,7 @@
|
|||||||
"create": "Create",
|
"create": "Create",
|
||||||
"delete": "Delete",
|
"delete": "Delete",
|
||||||
"download": "Download",
|
"download": "Download",
|
||||||
|
"hideDotfiles": "Hide dotfiles",
|
||||||
"info": "Info",
|
"info": "Info",
|
||||||
"more": "More",
|
"more": "More",
|
||||||
"move": "Move",
|
"move": "Move",
|
||||||
@@ -17,25 +16,29 @@
|
|||||||
"new": "New",
|
"new": "New",
|
||||||
"next": "Next",
|
"next": "Next",
|
||||||
"ok": "OK",
|
"ok": "OK",
|
||||||
"replace": "Replace",
|
"permalink": "Get Permanent Link",
|
||||||
"previous": "Previous",
|
"previous": "Previous",
|
||||||
|
"publish": "Publish",
|
||||||
"rename": "Rename",
|
"rename": "Rename",
|
||||||
|
"replace": "Replace",
|
||||||
"reportIssue": "Report Issue",
|
"reportIssue": "Report Issue",
|
||||||
"save": "Save",
|
"save": "Save",
|
||||||
|
"schedule": "Schedule",
|
||||||
"search": "Search",
|
"search": "Search",
|
||||||
"select": "Select",
|
"select": "Select",
|
||||||
"share": "Share",
|
|
||||||
"publish": "Publish",
|
|
||||||
"selectMultiple": "Select multiple",
|
"selectMultiple": "Select multiple",
|
||||||
"schedule": "Schedule",
|
"share": "Share",
|
||||||
|
"shell": "Toggle shell",
|
||||||
|
"submit": "Submit",
|
||||||
"switchView": "Switch view",
|
"switchView": "Switch view",
|
||||||
"toggleSidebar": "Toggle sidebar",
|
"toggleSidebar": "Toggle sidebar",
|
||||||
"update": "Update",
|
"update": "Update",
|
||||||
"upload": "Upload",
|
"upload": "Upload"
|
||||||
"permalink": "Get Permanent Link"
|
|
||||||
},
|
},
|
||||||
"success": {
|
"download": {
|
||||||
"linkCopied": "Link copied!"
|
"downloadFile": "Download File",
|
||||||
|
"downloadFolder": "Download Folder",
|
||||||
|
"downloadSelected": "Download Selected"
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"forbidden": "You don't have permissions to access this.",
|
"forbidden": "You don't have permissions to access this.",
|
||||||
@@ -43,11 +46,11 @@
|
|||||||
"notFound": "This location can't be reached."
|
"notFound": "This location can't be reached."
|
||||||
},
|
},
|
||||||
"files": {
|
"files": {
|
||||||
"folders": "Folders",
|
|
||||||
"files": "Files",
|
|
||||||
"body": "Body",
|
"body": "Body",
|
||||||
"clear": "Clear",
|
"clear": "Clear",
|
||||||
"closePreview": "Close preview",
|
"closePreview": "Close preview",
|
||||||
|
"files": "Files",
|
||||||
|
"folders": "Folders",
|
||||||
"home": "Home",
|
"home": "Home",
|
||||||
"lastModified": "Last modified",
|
"lastModified": "Last modified",
|
||||||
"loading": "Loading...",
|
"loading": "Loading...",
|
||||||
@@ -56,9 +59,9 @@
|
|||||||
"multipleSelectionEnabled": "Multiple selection enabled",
|
"multipleSelectionEnabled": "Multiple selection enabled",
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
"size": "Size",
|
"size": "Size",
|
||||||
|
"sortByLastModified": "Sort by last modified",
|
||||||
"sortByName": "Sort by name",
|
"sortByName": "Sort by name",
|
||||||
"sortBySize": "Sort by size",
|
"sortBySize": "Sort by size"
|
||||||
"sortByLastModified": "Sort by last modified"
|
|
||||||
},
|
},
|
||||||
"help": {
|
"help": {
|
||||||
"click": "select file or directory",
|
"click": "select file or directory",
|
||||||
@@ -74,24 +77,46 @@
|
|||||||
"f2": "rename file",
|
"f2": "rename file",
|
||||||
"help": "Help"
|
"help": "Help"
|
||||||
},
|
},
|
||||||
|
"languages": {
|
||||||
|
"ar": "العربية",
|
||||||
|
"de": "Deutsch",
|
||||||
|
"en": "English",
|
||||||
|
"es": "Español",
|
||||||
|
"fr": "Français",
|
||||||
|
"is": "Icelandic",
|
||||||
|
"it": "Italiano",
|
||||||
|
"ja": "日本語",
|
||||||
|
"ko": "한국어",
|
||||||
|
"nlBE": "Dutch (Belgium)",
|
||||||
|
"pl": "Polski",
|
||||||
|
"pt": "Português",
|
||||||
|
"ptBR": "Português (Brasil)",
|
||||||
|
"ro": "Romanian",
|
||||||
|
"ru": "Русский",
|
||||||
|
"svSE": "Swedish (Sweden)",
|
||||||
|
"zhCN": "中文 (简体)",
|
||||||
|
"zhTW": "中文 (繁體)"
|
||||||
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"password": "Password",
|
|
||||||
"passwordConfirm": "Password Confirmation",
|
|
||||||
"submit": "Login",
|
|
||||||
"createAnAccount": "Create an account",
|
"createAnAccount": "Create an account",
|
||||||
"loginInstead": "Already have an account",
|
"loginInstead": "Already have an account",
|
||||||
|
"password": "Password",
|
||||||
|
"passwordConfirm": "Password Confirmation",
|
||||||
"passwordsDontMatch": "Passwords don't match",
|
"passwordsDontMatch": "Passwords don't match",
|
||||||
"usernameTaken": "Username already taken",
|
|
||||||
"signup": "Signup",
|
"signup": "Signup",
|
||||||
|
"submit": "Login",
|
||||||
"username": "Username",
|
"username": "Username",
|
||||||
|
"usernameTaken": "Username already taken",
|
||||||
"wrongCredentials": "Wrong credentials"
|
"wrongCredentials": "Wrong credentials"
|
||||||
},
|
},
|
||||||
|
"permanent": "Permanent",
|
||||||
"prompts": {
|
"prompts": {
|
||||||
"copy": "Copy",
|
"copy": "Copy",
|
||||||
"copyMessage": "Choose the place to copy your files:",
|
"copyMessage": "Choose the place to copy your files:",
|
||||||
"currentlyNavigating": "Currently navigating on:",
|
"currentlyNavigating": "Currently navigating on:",
|
||||||
"deleteMessageMultiple": "Are you sure you want to delete {count} file(s)?",
|
"deleteMessageMultiple": "Are you sure you want to delete {count} file(s)?",
|
||||||
"deleteMessageSingle": "Are you sure you want to delete this file/folder?",
|
"deleteMessageSingle": "Are you sure you want to delete this file/folder?",
|
||||||
|
"deleteMessageShare": "Are you sure you want to delete this share({path})?",
|
||||||
"deleteTitle": "Delete files",
|
"deleteTitle": "Delete files",
|
||||||
"displayName": "Display Name:",
|
"displayName": "Display Name:",
|
||||||
"download": "Download files",
|
"download": "Download files",
|
||||||
@@ -102,50 +127,65 @@
|
|||||||
"lastModified": "Last Modified",
|
"lastModified": "Last Modified",
|
||||||
"move": "Move",
|
"move": "Move",
|
||||||
"moveMessage": "Choose new house for your file(s)/folder(s):",
|
"moveMessage": "Choose new house for your file(s)/folder(s):",
|
||||||
|
"newArchetype": "Create a new post based on an archetype. Your file will be created on content folder.",
|
||||||
"newDir": "New directory",
|
"newDir": "New directory",
|
||||||
"newDirMessage": "Write the name of the new directory.",
|
"newDirMessage": "Write the name of the new directory.",
|
||||||
"newFile": "New file",
|
"newFile": "New file",
|
||||||
"newFileMessage": "Write the name of the new file.",
|
"newFileMessage": "Write the name of the new file.",
|
||||||
"numberDirs": "Number of directories",
|
"numberDirs": "Number of directories",
|
||||||
"numberFiles": "Number of files",
|
"numberFiles": "Number of files",
|
||||||
"replace": "Replace",
|
|
||||||
"replaceMessage": "One of the files you're trying to upload is conflicting because of its name. Do you wish to replace the existing one?\n",
|
|
||||||
"rename": "Rename",
|
"rename": "Rename",
|
||||||
"renameMessage": "Insert a new name for",
|
"renameMessage": "Insert a new name for",
|
||||||
"show": "Show",
|
"replace": "Replace",
|
||||||
"size": "Size",
|
"replaceMessage": "One of the files you're trying to upload is conflicting because of its name. Do you wish to replace the existing one?\n",
|
||||||
"schedule": "Schedule",
|
"schedule": "Schedule",
|
||||||
"scheduleMessage": "Pick a date and time to schedule the publication of this post.",
|
"scheduleMessage": "Pick a date and time to schedule the publication of this post.",
|
||||||
"newArchetype": "Create a new post based on an archetype. Your file will be created on content folder.",
|
"show": "Show",
|
||||||
|
"size": "Size",
|
||||||
"upload": "Upload",
|
"upload": "Upload",
|
||||||
"uploadMessage": "Select an option to upload."
|
"uploadMessage": "Select an option to upload.",
|
||||||
|
"optionalPassword": "Optional password"
|
||||||
|
},
|
||||||
|
"search": {
|
||||||
|
"images": "Images",
|
||||||
|
"music": "Music",
|
||||||
|
"pdf": "PDF",
|
||||||
|
"pressToSearch": "Press enter to search...",
|
||||||
|
"search": "Search...",
|
||||||
|
"typeToSearch": "Type to search...",
|
||||||
|
"types": "Types",
|
||||||
|
"video": "Video"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"themes": {
|
|
||||||
"title": "Theme",
|
|
||||||
"light": "Light",
|
|
||||||
"dark": "Dark"
|
|
||||||
},
|
|
||||||
"instanceName": "Instance name",
|
|
||||||
"brandingDirectoryPath": "Branding directory path",
|
|
||||||
"documentation": "documentation",
|
|
||||||
"branding": "Branding",
|
|
||||||
"disableExternalLinks": "Disable external links (except documentation)",
|
|
||||||
"brandingHelp": "You can costumize how your File Browser instance looks and feels by changing its name, replacing the logo, adding custom styles and even disable external links to GitHub.\nFor more information about custom branding, please check out the {0}.",
|
|
||||||
"admin": "Admin",
|
"admin": "Admin",
|
||||||
"administrator": "Administrator",
|
"administrator": "Administrator",
|
||||||
"allowCommands": "Execute commands",
|
"allowCommands": "Execute commands",
|
||||||
"allowEdit": "Edit, rename and delete files or directories",
|
"allowEdit": "Edit, rename and delete files or directories",
|
||||||
"allowNew": "Create new files and directories",
|
"allowNew": "Create new files and directories",
|
||||||
"allowPublish": "Publish new posts and pages",
|
"allowPublish": "Publish new posts and pages",
|
||||||
|
"allowSignup": "Allow users to signup",
|
||||||
"avoidChanges": "(leave blank to avoid changes)",
|
"avoidChanges": "(leave blank to avoid changes)",
|
||||||
|
"branding": "Branding",
|
||||||
|
"brandingDirectoryPath": "Branding directory path",
|
||||||
|
"brandingHelp": "You can customize how your File Browser instance looks and feels by changing its name, replacing the logo, adding custom styles and even disable external links to GitHub.\nFor more information about custom branding, please check out the {0}.",
|
||||||
"changePassword": "Change Password",
|
"changePassword": "Change Password",
|
||||||
"commandRunner": "Command runner",
|
"commandRunner": "Command runner",
|
||||||
"commandRunnerHelp": "Here you can set commands that are executed in the named events. You must write one per line. The environment variables {0} and {1} will be available, being {0} relative to {1}. For more information about this feature and the available environment variables, please read the {2}.",
|
"commandRunnerHelp": "Here you can set commands that are executed in the named events. You must write one per line. The environment variables {0} and {1} will be available, being {0} relative to {1}. For more information about this feature and the available environment variables, please read the {2}.",
|
||||||
"commandsUpdated": "Commands updated!",
|
"commandsUpdated": "Commands updated!",
|
||||||
|
"createUserDir": "Auto create user home dir while adding new user",
|
||||||
"customStylesheet": "Custom Stylesheet",
|
"customStylesheet": "Custom Stylesheet",
|
||||||
|
"defaultUserDescription": "This are the default settings for new users.",
|
||||||
|
"disableExternalLinks": "Disable external links (except documentation)",
|
||||||
|
"documentation": "documentation",
|
||||||
"examples": "Examples",
|
"examples": "Examples",
|
||||||
|
"executeOnShell": "Execute on shell",
|
||||||
|
"executeOnShellDescription": "By default, File Browser executes the commands by calling their binaries directly. If you want to run them on a shell instead (such as Bash or PowerShell), you can define it here with the required arguments and flags. If set, the command you execute will be appended as an argument. This apply to both user commands and event hooks.",
|
||||||
|
"globalRules": "This is a global set of allow and disallow rules. They apply to every user. You can define specific rules on each user's settings to override this ones.",
|
||||||
"globalSettings": "Global Settings",
|
"globalSettings": "Global Settings",
|
||||||
|
"hideDotfiles": "Hide dotfiles",
|
||||||
|
"insertPath": "Insert the path",
|
||||||
|
"insertRegex": "Insert regex expression",
|
||||||
|
"instanceName": "Instance name",
|
||||||
"language": "Language",
|
"language": "Language",
|
||||||
"lockPassword": "Prevent the user from changing the password",
|
"lockPassword": "Prevent the user from changing the password",
|
||||||
"newPassword": "Your new password",
|
"newPassword": "Your new password",
|
||||||
@@ -153,6 +193,16 @@
|
|||||||
"newUser": "New User",
|
"newUser": "New User",
|
||||||
"password": "Password",
|
"password": "Password",
|
||||||
"passwordUpdated": "Password updated!",
|
"passwordUpdated": "Password updated!",
|
||||||
|
"path": "Path",
|
||||||
|
"perm": {
|
||||||
|
"create": "Create files and directories",
|
||||||
|
"delete": "Delete files and directories",
|
||||||
|
"download": "Download",
|
||||||
|
"execute": "Execute commands",
|
||||||
|
"modify": "Edit files",
|
||||||
|
"rename": "Rename or move files and directories",
|
||||||
|
"share": "Share files"
|
||||||
|
},
|
||||||
"permissions": "Permissions",
|
"permissions": "Permissions",
|
||||||
"permissionsHelp": "You can set the user to be an administrator or choose the permissions individually. If you select \"Administrator\", all of the other options will be automatically checked. The management of users remains a privilege of an administrator.\n",
|
"permissionsHelp": "You can set the user to be an administrator or choose the permissions individually. If you select \"Administrator\", all of the other options will be automatically checked. The management of users remains a privilege of an administrator.\n",
|
||||||
"profileSettings": "Profile Settings",
|
"profileSettings": "Profile Settings",
|
||||||
@@ -162,86 +212,46 @@
|
|||||||
"rulesHelp": "Here you can define a set of allow and disallow rules for this specific user. The blocked files won't show up in the listings and they wont be accessible to the user. We support regex and paths relative to the users scope.\n",
|
"rulesHelp": "Here you can define a set of allow and disallow rules for this specific user. The blocked files won't show up in the listings and they wont be accessible to the user. We support regex and paths relative to the users scope.\n",
|
||||||
"scope": "Scope",
|
"scope": "Scope",
|
||||||
"settingsUpdated": "Settings updated!",
|
"settingsUpdated": "Settings updated!",
|
||||||
|
"shareDuration": "Share Duration",
|
||||||
|
"shareManagement": "Share Management",
|
||||||
|
"singleClick": "Use single clicks to open files and directories",
|
||||||
|
"themes": {
|
||||||
|
"dark": "Dark",
|
||||||
|
"light": "Light",
|
||||||
|
"title": "Theme"
|
||||||
|
},
|
||||||
"user": "User",
|
"user": "User",
|
||||||
"userCommands": "Commands",
|
"userCommands": "Commands",
|
||||||
"userCommandsHelp": "A space separated list with the available commands for this user. Example:\n",
|
"userCommandsHelp": "A space separated list with the available commands for this user. Example:\n",
|
||||||
"userCreated": "User created!",
|
"userCreated": "User created!",
|
||||||
|
"userDefaults": "User default settings",
|
||||||
"userDeleted": "User deleted!",
|
"userDeleted": "User deleted!",
|
||||||
"userManagement": "User Management",
|
"userManagement": "User Management",
|
||||||
"username": "Username",
|
|
||||||
"users": "Users",
|
|
||||||
"globalRules": "This is a global set of allow and disallow rules. They apply to every user. You can define specific rules on each user's settings to override this ones.",
|
|
||||||
"allowSignup": "Allow users to signup",
|
|
||||||
"createUserDir": "Auto create user home dir while adding new user",
|
|
||||||
"insertRegex": "Insert regex expression",
|
|
||||||
"insertPath": "Insert the path",
|
|
||||||
"userUpdated": "User updated!",
|
"userUpdated": "User updated!",
|
||||||
"userDefaults": "User default settings",
|
"username": "Username",
|
||||||
"defaultUserDescription": "This are the default settings for new users.",
|
"users": "Users"
|
||||||
"executeOnShell": "Execute on shell",
|
|
||||||
"executeOnShellDescription": "By default, File Browser executes the commands by calling their binaries directly. If you want to run them on a shell instead (such as Bash or PowerShell), you can define it here with the required arguments and flags. If set, the command you execute will be appended as an argument. This apply to both user commands and event hooks.",
|
|
||||||
"perm": {
|
|
||||||
"create": "Create files and directories",
|
|
||||||
"delete": "Delete files and directories",
|
|
||||||
"download": "Download",
|
|
||||||
"modify": "Edit files",
|
|
||||||
"execute": "Execute commands",
|
|
||||||
"rename": "Rename or move files and directories",
|
|
||||||
"share": "Share files"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"sidebar": {
|
"sidebar": {
|
||||||
"help": "Help",
|
"help": "Help",
|
||||||
|
"hugoNew": "Hugo New",
|
||||||
"login": "Login",
|
"login": "Login",
|
||||||
"signup": "Signup",
|
|
||||||
"logout": "Logout",
|
"logout": "Logout",
|
||||||
"myFiles": "My files",
|
"myFiles": "My files",
|
||||||
"newFile": "New file",
|
"newFile": "New file",
|
||||||
"newFolder": "New folder",
|
"newFolder": "New folder",
|
||||||
|
"preview": "Preview",
|
||||||
"settings": "Settings",
|
"settings": "Settings",
|
||||||
"siteSettings": "Site Settings",
|
"signup": "Signup",
|
||||||
"hugoNew": "Hugo New",
|
"siteSettings": "Site Settings"
|
||||||
"preview": "Preview"
|
|
||||||
},
|
},
|
||||||
"search": {
|
"success": {
|
||||||
"images": "Images",
|
"linkCopied": "Link copied!"
|
||||||
"music": "Music",
|
|
||||||
"pdf": "PDF",
|
|
||||||
"types": "Types",
|
|
||||||
"video": "Video",
|
|
||||||
"search": "Search...",
|
|
||||||
"typeToSearch": "Type to search...",
|
|
||||||
"pressToSearch": "Press enter to search..."
|
|
||||||
},
|
|
||||||
"languages": {
|
|
||||||
"ar": "العربية",
|
|
||||||
"en": "English",
|
|
||||||
"is": "Icelandic",
|
|
||||||
"it": "Italiano",
|
|
||||||
"fr": "Français",
|
|
||||||
"pt": "Português",
|
|
||||||
"ptBR": "Português (Brasil)",
|
|
||||||
"ja": "日本語",
|
|
||||||
"zhCN": "中文 (简体)",
|
|
||||||
"zhTW": "中文 (繁體)",
|
|
||||||
"es": "Español",
|
|
||||||
"de": "Deutsch",
|
|
||||||
"ru": "Русский",
|
|
||||||
"pl": "Polski",
|
|
||||||
"ko": "한국어",
|
|
||||||
"nlBE": "Dutch (Belgium)",
|
|
||||||
"ro": "Romanian",
|
|
||||||
"svSE": "Swedish (Sweden)"
|
|
||||||
},
|
},
|
||||||
"time": {
|
"time": {
|
||||||
"unit": "Time Unit",
|
"days": "Days",
|
||||||
"seconds": "Seconds",
|
|
||||||
"minutes": "Minutes",
|
|
||||||
"hours": "Hours",
|
"hours": "Hours",
|
||||||
"days": "Days"
|
"minutes": "Minutes",
|
||||||
},
|
"seconds": "Seconds",
|
||||||
"download": {
|
"unit": "Time Unit"
|
||||||
"downloadFile": "Download File",
|
|
||||||
"downloadFolder": "Download Folder"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
{
|
{
|
||||||
"permanent": "Permanente",
|
|
||||||
"buttons": {
|
"buttons": {
|
||||||
"shell": "Presiona Enter para buscar...",
|
|
||||||
"cancel": "Cancelar",
|
"cancel": "Cancelar",
|
||||||
"close": "Cerrar",
|
"close": "Cerrar",
|
||||||
"copy": "Copiar",
|
"copy": "Copiar",
|
||||||
@@ -10,6 +8,7 @@
|
|||||||
"create": "Crear",
|
"create": "Crear",
|
||||||
"delete": "Borrar",
|
"delete": "Borrar",
|
||||||
"download": "Descargar",
|
"download": "Descargar",
|
||||||
|
"hideDotfiles": "",
|
||||||
"info": "Info",
|
"info": "Info",
|
||||||
"more": "Más",
|
"more": "Más",
|
||||||
"move": "Mover",
|
"move": "Mover",
|
||||||
@@ -17,25 +16,28 @@
|
|||||||
"new": "Nuevo",
|
"new": "Nuevo",
|
||||||
"next": "Siguiente",
|
"next": "Siguiente",
|
||||||
"ok": "OK",
|
"ok": "OK",
|
||||||
"replace": "Reemplazar",
|
"permalink": "Link permanente",
|
||||||
"previous": "Anterior",
|
"previous": "Anterior",
|
||||||
|
"publish": "Publicar",
|
||||||
"rename": "Renombrar",
|
"rename": "Renombrar",
|
||||||
|
"replace": "Reemplazar",
|
||||||
"reportIssue": "Reportar problema",
|
"reportIssue": "Reportar problema",
|
||||||
"save": "Guardar",
|
"save": "Guardar",
|
||||||
|
"schedule": "Programar",
|
||||||
"search": "Buscar",
|
"search": "Buscar",
|
||||||
"select": "Seleccionar",
|
"select": "Seleccionar",
|
||||||
"share": "Compartir",
|
|
||||||
"publish": "Publicar",
|
|
||||||
"selectMultiple": "Selección múltiple",
|
"selectMultiple": "Selección múltiple",
|
||||||
"schedule": "Programar",
|
"share": "Compartir",
|
||||||
|
"shell": "Presiona Enter para buscar...",
|
||||||
"switchView": "Cambiar vista",
|
"switchView": "Cambiar vista",
|
||||||
"toggleSidebar": "Mostrar/Ocultar menú",
|
"toggleSidebar": "Mostrar/Ocultar menú",
|
||||||
"update": "Actualizar",
|
"update": "Actualizar",
|
||||||
"upload": "Subir",
|
"upload": "Subir"
|
||||||
"permalink": "Link permanente"
|
|
||||||
},
|
},
|
||||||
"success": {
|
"download": {
|
||||||
"linkCopied": "¡Link copiado!"
|
"downloadFile": "Descargar fichero",
|
||||||
|
"downloadFolder": "Descargar directorio",
|
||||||
|
"downloadSelected": ""
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"forbidden": "No tienes los permisos necesarios para acceder.",
|
"forbidden": "No tienes los permisos necesarios para acceder.",
|
||||||
@@ -43,11 +45,11 @@
|
|||||||
"notFound": "No se puede acceder a este lugar."
|
"notFound": "No se puede acceder a este lugar."
|
||||||
},
|
},
|
||||||
"files": {
|
"files": {
|
||||||
"folders": "Carpetas",
|
|
||||||
"files": "Archivos",
|
|
||||||
"body": "Cuerpo",
|
"body": "Cuerpo",
|
||||||
"clear": "Limpiar",
|
"clear": "Limpiar",
|
||||||
"closePreview": "Cerrar vista previa",
|
"closePreview": "Cerrar vista previa",
|
||||||
|
"files": "Archivos",
|
||||||
|
"folders": "Carpetas",
|
||||||
"home": "Inicio",
|
"home": "Inicio",
|
||||||
"lastModified": "Última modificación",
|
"lastModified": "Última modificación",
|
||||||
"loading": "Cargando...",
|
"loading": "Cargando...",
|
||||||
@@ -56,9 +58,9 @@
|
|||||||
"multipleSelectionEnabled": "Selección múltiple activada",
|
"multipleSelectionEnabled": "Selección múltiple activada",
|
||||||
"name": "Nombre",
|
"name": "Nombre",
|
||||||
"size": "Tamaño",
|
"size": "Tamaño",
|
||||||
|
"sortByLastModified": "Ordenar por última modificación",
|
||||||
"sortByName": "Ordenar por nombre",
|
"sortByName": "Ordenar por nombre",
|
||||||
"sortBySize": "Ordenar por tamaño",
|
"sortBySize": "Ordenar por tamaño"
|
||||||
"sortByLastModified": "Ordenar por última modificación"
|
|
||||||
},
|
},
|
||||||
"help": {
|
"help": {
|
||||||
"click": "seleccionar archivo o carpeta",
|
"click": "seleccionar archivo o carpeta",
|
||||||
@@ -74,18 +76,39 @@
|
|||||||
"f2": "renombrar archivo",
|
"f2": "renombrar archivo",
|
||||||
"help": "Ayuda"
|
"help": "Ayuda"
|
||||||
},
|
},
|
||||||
|
"languages": {
|
||||||
|
"ar": "العربية",
|
||||||
|
"de": "Deutsch",
|
||||||
|
"en": "English",
|
||||||
|
"es": "Español",
|
||||||
|
"fr": "Français",
|
||||||
|
"is": "",
|
||||||
|
"it": "Italiano",
|
||||||
|
"ja": "日本語",
|
||||||
|
"ko": "한국어",
|
||||||
|
"nlBE": "",
|
||||||
|
"pl": "Polski",
|
||||||
|
"pt": "Português",
|
||||||
|
"ptBR": "Português (Brasil)",
|
||||||
|
"ro": "",
|
||||||
|
"ru": "Русский",
|
||||||
|
"svSE": "",
|
||||||
|
"zhCN": "中文 (简体)",
|
||||||
|
"zhTW": "中文 (繁體)"
|
||||||
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"password": "Contraseña",
|
|
||||||
"passwordConfirm": "Confirmación de contraseña",
|
|
||||||
"submit": "Iniciar sesión",
|
|
||||||
"createAnAccount": "Crear una cuenta",
|
"createAnAccount": "Crear una cuenta",
|
||||||
"loginInstead": "Usuario ya existente",
|
"loginInstead": "Usuario ya existente",
|
||||||
|
"password": "Contraseña",
|
||||||
|
"passwordConfirm": "Confirmación de contraseña",
|
||||||
"passwordsDontMatch": "Las contraseñas no coinciden",
|
"passwordsDontMatch": "Las contraseñas no coinciden",
|
||||||
"usernameTaken": "Nombre usuario no disponible",
|
|
||||||
"signup": "Registrate",
|
"signup": "Registrate",
|
||||||
|
"submit": "Iniciar sesión",
|
||||||
"username": "Usuario",
|
"username": "Usuario",
|
||||||
|
"usernameTaken": "Nombre usuario no disponible",
|
||||||
"wrongCredentials": "Usuario y/o contraseña incorrectos"
|
"wrongCredentials": "Usuario y/o contraseña incorrectos"
|
||||||
},
|
},
|
||||||
|
"permanent": "Permanente",
|
||||||
"prompts": {
|
"prompts": {
|
||||||
"copy": "Copiar",
|
"copy": "Copiar",
|
||||||
"copyMessage": "Elige el lugar donde quieres copiar tus archivos:",
|
"copyMessage": "Elige el lugar donde quieres copiar tus archivos:",
|
||||||
@@ -102,43 +125,64 @@
|
|||||||
"lastModified": "Última modificación",
|
"lastModified": "Última modificación",
|
||||||
"move": "Mover",
|
"move": "Mover",
|
||||||
"moveMessage": "Elige una nueva casa para tus archivo(s)/carpeta(s):",
|
"moveMessage": "Elige una nueva casa para tus archivo(s)/carpeta(s):",
|
||||||
|
"newArchetype": "Crea un nuevo post basado en un arquetipo. Tu archivo será creado en la carpeta de contenido.",
|
||||||
"newDir": "Nueva carpeta",
|
"newDir": "Nueva carpeta",
|
||||||
"newDirMessage": "Escribe el nombre de la nueva carpeta.",
|
"newDirMessage": "Escribe el nombre de la nueva carpeta.",
|
||||||
"newFile": "Nuevo archivo",
|
"newFile": "Nuevo archivo",
|
||||||
"newFileMessage": "Escribe el nombre del nuevo archivo.",
|
"newFileMessage": "Escribe el nombre del nuevo archivo.",
|
||||||
"numberDirs": "Número de carpetas",
|
"numberDirs": "Número de carpetas",
|
||||||
"numberFiles": "Número de archivos",
|
"numberFiles": "Número de archivos",
|
||||||
"replace": "Reemplazar",
|
|
||||||
"replaceMessage": "Uno de los archivos ue intentas subir está creando conflicto por su nombre. ¿Quieres cambiar el nombre del ya existente?\n",
|
|
||||||
"rename": "Renombrar",
|
"rename": "Renombrar",
|
||||||
"renameMessage": "Escribe el nuevo nombre para",
|
"renameMessage": "Escribe el nuevo nombre para",
|
||||||
"show": "Mostrar",
|
"replace": "Reemplazar",
|
||||||
"size": "Tamaño",
|
"replaceMessage": "Uno de los archivos ue intentas subir está creando conflicto por su nombre. ¿Quieres cambiar el nombre del ya existente?\n",
|
||||||
"schedule": "Programar",
|
"schedule": "Programar",
|
||||||
"scheduleMessage": "Elige una hora y fecha para programar la publicación de este post.",
|
"scheduleMessage": "Elige una hora y fecha para programar la publicación de este post.",
|
||||||
"newArchetype": "Crea un nuevo post basado en un arquetipo. Tu archivo será creado en la carpeta de contenido."
|
"show": "Mostrar",
|
||||||
|
"size": "Tamaño",
|
||||||
|
"upload": "",
|
||||||
|
"uploadMessage": ""
|
||||||
|
},
|
||||||
|
"search": {
|
||||||
|
"images": "Images",
|
||||||
|
"music": "Música",
|
||||||
|
"pdf": "PDF",
|
||||||
|
"pressToSearch": "Presiona enter para buscar...",
|
||||||
|
"search": "Buscar...",
|
||||||
|
"typeToSearch": "Escribe para realizar una busqueda...",
|
||||||
|
"types": "Tipos",
|
||||||
|
"video": "Vídeo"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"instanceName": "Nombre de la instancia",
|
|
||||||
"brandingDirectoryPath": "Ruta de la carpeta de personalizacion de marca",
|
|
||||||
"documentation": "documentación",
|
|
||||||
"branding": "Marca",
|
|
||||||
"disableExternalLinks": "Deshabilitar enlaces externos (excepto documentación)",
|
|
||||||
"brandingHelp": "Tú puedes personalizar como se ve tu instancia de FileBrowser cambiándole el nombre, reemplazando ellogo, agregar estilos personalizados e incluso deshabilitando loslinks externos que apuntan hacia GitHub. \nPara mayor información acerca de personalización de marca, por favor revisa el {0}.",
|
|
||||||
"admin": "Admin",
|
"admin": "Admin",
|
||||||
"administrator": "Administrador",
|
"administrator": "Administrador",
|
||||||
"allowCommands": "Ejecutar comandos",
|
"allowCommands": "Ejecutar comandos",
|
||||||
"allowEdit": "Editar, renombrar y borrar archivos o carpetas",
|
"allowEdit": "Editar, renombrar y borrar archivos o carpetas",
|
||||||
"allowNew": "Crear nuevos archivos y carpetas",
|
"allowNew": "Crear nuevos archivos y carpetas",
|
||||||
"allowPublish": "Publicar nuevos posts y páginas",
|
"allowPublish": "Publicar nuevos posts y páginas",
|
||||||
|
"allowSignup": "Permitir registro de usuarios",
|
||||||
"avoidChanges": "(dejar en blanco para evitar cambios)",
|
"avoidChanges": "(dejar en blanco para evitar cambios)",
|
||||||
|
"branding": "Marca",
|
||||||
|
"brandingDirectoryPath": "Ruta de la carpeta de personalizacion de marca",
|
||||||
|
"brandingHelp": "Tú puedes personalizar como se ve tu instancia de FileBrowser cambiándole el nombre, reemplazando ellogo, agregar estilos personalizados e incluso deshabilitando loslinks externos que apuntan hacia GitHub. \nPara mayor información acerca de personalización de marca, por favor revisa el {0}.",
|
||||||
"changePassword": "Cambiar contraseña",
|
"changePassword": "Cambiar contraseña",
|
||||||
"commandRunner": "Executor de comandos",
|
"commandRunner": "Executor de comandos",
|
||||||
"commandRunnerHelp": "Here you can set commands that are executed in the named events. You must write one per line. The environment variables {0} and {1} will be available, being {0} relative to {1}. For more information about this feature and the available environment variables, please read the {2}.",
|
"commandRunnerHelp": "Here you can set commands that are executed in the named events. You must write one per line. The environment variables {0} and {1} will be available, being {0} relative to {1}. For more information about this feature and the available environment variables, please read the {2}.",
|
||||||
"commandsUpdated": "¡Comandos actualizados!",
|
"commandsUpdated": "¡Comandos actualizados!",
|
||||||
|
"createUserDir": "Crea automaticamente una carpeta de inicio cuando se agrega un usuario",
|
||||||
"customStylesheet": "Modificar hoja de estilos",
|
"customStylesheet": "Modificar hoja de estilos",
|
||||||
|
"defaultUserDescription": "Estas son las configuraciones por defecto para nuevos usuarios.",
|
||||||
|
"disableExternalLinks": "Deshabilitar enlaces externos (excepto documentación)",
|
||||||
|
"documentation": "documentación",
|
||||||
"examples": "Ejemplos",
|
"examples": "Ejemplos",
|
||||||
|
"executeOnShell": "Ejecutar en la shell",
|
||||||
|
"executeOnShellDescription": "By default, File Browser executes the commands by calling their binaries directly. If you want to run them on a shell instead (such as Bash or PowerShell), you can define it here with the required arguments and flags. If set, the command you execute will be appended as an argument. This apply to both user commands and event hooks.",
|
||||||
|
"globalRules": "This is a global set of allow and disallow rules. They apply to every user. You can define specific rules on each user's settings to override this ones.",
|
||||||
"globalSettings": "Ajustes globales",
|
"globalSettings": "Ajustes globales",
|
||||||
|
"hideDotfiles": "",
|
||||||
|
"insertPath": "Introduce la ruta",
|
||||||
|
"insertRegex": "Introducir expresión regular",
|
||||||
|
"instanceName": "Nombre de la instancia",
|
||||||
"language": "Idioma",
|
"language": "Idioma",
|
||||||
"lockPassword": "Evitar que el usuario cambie la contraseña",
|
"lockPassword": "Evitar que el usuario cambie la contraseña",
|
||||||
"newPassword": "Tu nueva contraseña",
|
"newPassword": "Tu nueva contraseña",
|
||||||
@@ -146,6 +190,16 @@
|
|||||||
"newUser": "Nuevo usuario",
|
"newUser": "Nuevo usuario",
|
||||||
"password": "Contraseña",
|
"password": "Contraseña",
|
||||||
"passwordUpdated": "¡Contraseña actualizada!",
|
"passwordUpdated": "¡Contraseña actualizada!",
|
||||||
|
"path": "",
|
||||||
|
"perm": {
|
||||||
|
"create": "Crear ficheros y directorios",
|
||||||
|
"delete": "Eliminar ficheros y directorios",
|
||||||
|
"download": "Descargar",
|
||||||
|
"execute": "Executar comandos",
|
||||||
|
"modify": "Editar ficheros",
|
||||||
|
"rename": "Renombrar o mover ficheros y directorios",
|
||||||
|
"share": "Compartir ficheros"
|
||||||
|
},
|
||||||
"permissions": "Permisos",
|
"permissions": "Permisos",
|
||||||
"permissionsHelp": "Puedes nombrar al usuario como administrador o elegir los permisos individualmente. Si seleccionas \"Administrador\", todas las otras opciones serán activadas automáticamente. La administración de usuarios es un privilegio de administrador.\n",
|
"permissionsHelp": "Puedes nombrar al usuario como administrador o elegir los permisos individualmente. Si seleccionas \"Administrador\", todas las otras opciones serán activadas automáticamente. La administración de usuarios es un privilegio de administrador.\n",
|
||||||
"profileSettings": "Ajustes del perfil",
|
"profileSettings": "Ajustes del perfil",
|
||||||
@@ -155,82 +209,46 @@
|
|||||||
"rulesHelp": "Aquí puedes definir un conjunto de reglas de permisos para este usuario específico. Los archivos bloqueados no se mostrarán en las listas y no serán accesibles por el usuario. Puedes utilizar regex y rutas relativas a la raíz del usuario.\n",
|
"rulesHelp": "Aquí puedes definir un conjunto de reglas de permisos para este usuario específico. Los archivos bloqueados no se mostrarán en las listas y no serán accesibles por el usuario. Puedes utilizar regex y rutas relativas a la raíz del usuario.\n",
|
||||||
"scope": "Raíz",
|
"scope": "Raíz",
|
||||||
"settingsUpdated": "¡Ajustes actualizados!",
|
"settingsUpdated": "¡Ajustes actualizados!",
|
||||||
|
"shareDuration": "",
|
||||||
|
"shareManagement": "",
|
||||||
|
"singleClick": "",
|
||||||
|
"themes": {
|
||||||
|
"dark": "",
|
||||||
|
"light": "",
|
||||||
|
"title": ""
|
||||||
|
},
|
||||||
"user": "Usuario",
|
"user": "Usuario",
|
||||||
"userCommands": "Comandos",
|
"userCommands": "Comandos",
|
||||||
"userCommandsHelp": "Una lista separada por espacios con los comandos permitidos para este usuario. Ejemplo:\n",
|
"userCommandsHelp": "Una lista separada por espacios con los comandos permitidos para este usuario. Ejemplo:\n",
|
||||||
"userCreated": "¡Usuario creado!",
|
"userCreated": "¡Usuario creado!",
|
||||||
|
"userDefaults": "Configuración de usuario por defecto",
|
||||||
"userDeleted": "¡Usuario eliminado!",
|
"userDeleted": "¡Usuario eliminado!",
|
||||||
"userManagement": "Administración de usuarios",
|
"userManagement": "Administración de usuarios",
|
||||||
"username": "Usuario",
|
|
||||||
"users": "Usuarios",
|
|
||||||
"globalRules": "This is a global set of allow and disallow rules. They apply to every user. You can define specific rules on each user's settings to override this ones.",
|
|
||||||
"allowSignup": "Permitir registro de usuarios",
|
|
||||||
"createUserDir": "Crea automaticamente una carpeta de inicio cuando se agrega un usuario",
|
|
||||||
"insertRegex": "Introducir expresión regular",
|
|
||||||
"insertPath": "Introduce la ruta",
|
|
||||||
"userUpdated": "¡Usuario actualizado!",
|
"userUpdated": "¡Usuario actualizado!",
|
||||||
"userDefaults": "Configuración de usuario por defecto",
|
"username": "Usuario",
|
||||||
"defaultUserDescription": "Estas son las configuraciones por defecto para nuevos usuarios.",
|
"users": "Usuarios"
|
||||||
"executeOnShell": "Ejecutar en la shell",
|
|
||||||
"executeOnShellDescription": "By default, File Browser executes the commands by calling their binaries directly. If you want to run them on a shell instead (such as Bash or PowerShell), you can define it here with the required arguments and flags. If set, the command you execute will be appended as an argument. This apply to both user commands and event hooks.",
|
|
||||||
"perm": {
|
|
||||||
"create": "Crear ficheros y directorios",
|
|
||||||
"delete": "Eliminar ficheros y directorios",
|
|
||||||
"download": "Descargar",
|
|
||||||
"modify": "Editar ficheros",
|
|
||||||
"execute": "Executar comandos",
|
|
||||||
"rename": "Renombrar o mover ficheros y directorios",
|
|
||||||
"share": "Compartir ficheros"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"sidebar": {
|
"sidebar": {
|
||||||
"help": "Ayuda",
|
"help": "Ayuda",
|
||||||
|
"hugoNew": "Nuevo Hugo",
|
||||||
"login": "Iniciar sesión",
|
"login": "Iniciar sesión",
|
||||||
"signup": "Registrate",
|
|
||||||
"logout": "Cerrar sesión",
|
"logout": "Cerrar sesión",
|
||||||
"myFiles": "Mis archivos",
|
"myFiles": "Mis archivos",
|
||||||
"newFile": "Nuevo archivo",
|
"newFile": "Nuevo archivo",
|
||||||
"newFolder": "Nueva carpeta",
|
"newFolder": "Nueva carpeta",
|
||||||
|
"preview": "Vista previa",
|
||||||
"settings": "Ajustes",
|
"settings": "Ajustes",
|
||||||
"siteSettings": "Ajustes del sitio",
|
"signup": "Registrate",
|
||||||
"hugoNew": "Nuevo Hugo",
|
"siteSettings": "Ajustes del sitio"
|
||||||
"preview": "Vista previa"
|
|
||||||
},
|
},
|
||||||
"search": {
|
"success": {
|
||||||
"images": "Images",
|
"linkCopied": "¡Link copiado!"
|
||||||
"music": "Música",
|
|
||||||
"pdf": "PDF",
|
|
||||||
"types": "Tipos",
|
|
||||||
"video": "Vídeo",
|
|
||||||
"search": "Buscar...",
|
|
||||||
"typeToSearch": "Escribe para realizar una busqueda...",
|
|
||||||
"pressToSearch": "Presiona enter para buscar..."
|
|
||||||
},
|
|
||||||
"languages": {
|
|
||||||
"ar": "العربية",
|
|
||||||
"en": "English",
|
|
||||||
"it": "Italiano",
|
|
||||||
"fr": "Français",
|
|
||||||
"pt": "Português",
|
|
||||||
"ptBR": "Português (Brasil)",
|
|
||||||
"ja": "日本語",
|
|
||||||
"zhCN": "中文 (简体)",
|
|
||||||
"zhTW": "中文 (繁體)",
|
|
||||||
"es": "Español",
|
|
||||||
"de": "Deutsch",
|
|
||||||
"ru": "Русский",
|
|
||||||
"pl": "Polski",
|
|
||||||
"ko": "한국어"
|
|
||||||
},
|
},
|
||||||
"time": {
|
"time": {
|
||||||
"unit": "Unidad",
|
"days": "Días",
|
||||||
"seconds": "Segundos",
|
|
||||||
"minutes": "Minutos",
|
|
||||||
"hours": "Horas",
|
"hours": "Horas",
|
||||||
"days": "Días"
|
"minutes": "Minutos",
|
||||||
},
|
"seconds": "Segundos",
|
||||||
"download": {
|
"unit": "Unidad"
|
||||||
"downloadFile": "Descargar fichero",
|
|
||||||
"downloadFolder": "Descargar directorio"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
{
|
{
|
||||||
"permanent": "Permanent",
|
|
||||||
"buttons": {
|
"buttons": {
|
||||||
"shell": "Toggle shell",
|
|
||||||
"cancel": "Annuler",
|
"cancel": "Annuler",
|
||||||
"close": "Fermer",
|
"close": "Fermer",
|
||||||
"copy": "Copier",
|
"copy": "Copier",
|
||||||
@@ -10,6 +8,7 @@
|
|||||||
"create": "Créer",
|
"create": "Créer",
|
||||||
"delete": "Supprimer",
|
"delete": "Supprimer",
|
||||||
"download": "Télécharger",
|
"download": "Télécharger",
|
||||||
|
"hideDotfiles": "",
|
||||||
"info": "Info",
|
"info": "Info",
|
||||||
"more": "Plus",
|
"more": "Plus",
|
||||||
"move": "Déplacer",
|
"move": "Déplacer",
|
||||||
@@ -17,25 +16,28 @@
|
|||||||
"new": "Nouveau",
|
"new": "Nouveau",
|
||||||
"next": "Suivant",
|
"next": "Suivant",
|
||||||
"ok": "OK",
|
"ok": "OK",
|
||||||
"replace": "Remplacer",
|
"permalink": "Obtenir un lien permanent",
|
||||||
"previous": "Précédent",
|
"previous": "Précédent",
|
||||||
|
"publish": "Publier",
|
||||||
"rename": "Renommer",
|
"rename": "Renommer",
|
||||||
|
"replace": "Remplacer",
|
||||||
"reportIssue": "Rapport d'erreur",
|
"reportIssue": "Rapport d'erreur",
|
||||||
"save": "Enregistrer",
|
"save": "Enregistrer",
|
||||||
|
"schedule": "Fixer la date",
|
||||||
"search": "Chercher",
|
"search": "Chercher",
|
||||||
"select": "Sélectionner",
|
"select": "Sélectionner",
|
||||||
"share": "Partager",
|
|
||||||
"publish": "Publier",
|
|
||||||
"selectMultiple": "Sélection multiple",
|
"selectMultiple": "Sélection multiple",
|
||||||
"schedule": "Fixer la date",
|
"share": "Partager",
|
||||||
|
"shell": "Toggle shell",
|
||||||
"switchView": "Changer le mode d'affichage",
|
"switchView": "Changer le mode d'affichage",
|
||||||
"toggleSidebar": "Afficher/Masquer la barre latérale",
|
"toggleSidebar": "Afficher/Masquer la barre latérale",
|
||||||
"update": "Mettre à jour",
|
"update": "Mettre à jour",
|
||||||
"upload": "Importer",
|
"upload": "Importer"
|
||||||
"permalink": "Obtenir un lien permanent"
|
|
||||||
},
|
},
|
||||||
"success": {
|
"download": {
|
||||||
"linkCopied": "Link copied!"
|
"downloadFile": "Download File",
|
||||||
|
"downloadFolder": "Download Folder",
|
||||||
|
"downloadSelected": ""
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"forbidden": "You don't have permissions to access this.",
|
"forbidden": "You don't have permissions to access this.",
|
||||||
@@ -43,22 +45,22 @@
|
|||||||
"notFound": "Impossible d'accéder à cet emplacement."
|
"notFound": "Impossible d'accéder à cet emplacement."
|
||||||
},
|
},
|
||||||
"files": {
|
"files": {
|
||||||
"folders": "Dossiers",
|
|
||||||
"files": "Fichiers",
|
|
||||||
"body": "Corps",
|
"body": "Corps",
|
||||||
"clear": "Fermer",
|
"clear": "Fermer",
|
||||||
"closePreview": "Fermer la prévisualisation",
|
"closePreview": "Fermer la prévisualisation",
|
||||||
|
"files": "Fichiers",
|
||||||
|
"folders": "Dossiers",
|
||||||
"home": "Accueil",
|
"home": "Accueil",
|
||||||
"lastModified": "Dernière modification",
|
"lastModified": "Dernière modification",
|
||||||
"loading": "Chargement...",
|
"loading": "Chargement...",
|
||||||
"lonely": "Il semble qu'il n'y ai rien par ici...",
|
"lonely": "Il semble qu'il n'y ait rien par ici...",
|
||||||
"metadata": "Metadonnées",
|
"metadata": "Metadonnées",
|
||||||
"multipleSelectionEnabled": "Sélection multiple activée",
|
"multipleSelectionEnabled": "Sélection multiple activée",
|
||||||
"name": "Nom",
|
"name": "Nom",
|
||||||
"size": "Taille",
|
"size": "Taille",
|
||||||
|
"sortByLastModified": "Trier par date de dernière modification",
|
||||||
"sortByName": "Trier par nom",
|
"sortByName": "Trier par nom",
|
||||||
"sortBySize": "Trier par taille",
|
"sortBySize": "Trier par taille"
|
||||||
"sortByLastModified": "Trier par date de dernière modification"
|
|
||||||
},
|
},
|
||||||
"help": {
|
"help": {
|
||||||
"click": "Sélectionner un élément",
|
"click": "Sélectionner un élément",
|
||||||
@@ -74,18 +76,39 @@
|
|||||||
"f2": "Renommer le fichier",
|
"f2": "Renommer le fichier",
|
||||||
"help": "Aide"
|
"help": "Aide"
|
||||||
},
|
},
|
||||||
|
"languages": {
|
||||||
|
"ar": "العربية",
|
||||||
|
"de": "Deutsch",
|
||||||
|
"en": "English",
|
||||||
|
"es": "Español",
|
||||||
|
"fr": "Français",
|
||||||
|
"is": "",
|
||||||
|
"it": "Italiano",
|
||||||
|
"ja": "日本語",
|
||||||
|
"ko": "한국어",
|
||||||
|
"nlBE": "",
|
||||||
|
"pl": "Polski",
|
||||||
|
"pt": "Português",
|
||||||
|
"ptBR": "Português (Brasil)",
|
||||||
|
"ro": "",
|
||||||
|
"ru": "Русский",
|
||||||
|
"svSE": "",
|
||||||
|
"zhCN": "中文 (简体)",
|
||||||
|
"zhTW": "中文 (繁體)"
|
||||||
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"password": "Mot de passe",
|
|
||||||
"passwordConfirm": "Password Confirmation",
|
|
||||||
"submit": "Se connecter",
|
|
||||||
"createAnAccount": "Create an account",
|
"createAnAccount": "Create an account",
|
||||||
"loginInstead": "Already have an account",
|
"loginInstead": "Already have an account",
|
||||||
|
"password": "Mot de passe",
|
||||||
|
"passwordConfirm": "Password Confirmation",
|
||||||
"passwordsDontMatch": "Passwords don't match",
|
"passwordsDontMatch": "Passwords don't match",
|
||||||
"usernameTaken": "Username already taken",
|
|
||||||
"signup": "Signup",
|
"signup": "Signup",
|
||||||
|
"submit": "Se connecter",
|
||||||
"username": "Utilisateur",
|
"username": "Utilisateur",
|
||||||
|
"usernameTaken": "Username already taken",
|
||||||
"wrongCredentials": "Identifiants incorrects !"
|
"wrongCredentials": "Identifiants incorrects !"
|
||||||
},
|
},
|
||||||
|
"permanent": "Permanent",
|
||||||
"prompts": {
|
"prompts": {
|
||||||
"copy": "Copier",
|
"copy": "Copier",
|
||||||
"copyMessage": "Choisissez l'emplacement où copier la sélection :",
|
"copyMessage": "Choisissez l'emplacement où copier la sélection :",
|
||||||
@@ -102,43 +125,64 @@
|
|||||||
"lastModified": "Dernière modification",
|
"lastModified": "Dernière modification",
|
||||||
"move": "Déplacer",
|
"move": "Déplacer",
|
||||||
"moveMessage": "Choisissez l'emplacement où déplacer la sélection :",
|
"moveMessage": "Choisissez l'emplacement où déplacer la sélection :",
|
||||||
|
"newArchetype": "Créer un nouveau post basé sur un archétype. Votre fichier sera créé dans le dossier de contenu.",
|
||||||
"newDir": "Nouveau dossier",
|
"newDir": "Nouveau dossier",
|
||||||
"newDirMessage": "Nom du nouveau dossier :",
|
"newDirMessage": "Nom du nouveau dossier :",
|
||||||
"newFile": "Nouveau fichier",
|
"newFile": "Nouveau fichier",
|
||||||
"newFileMessage": "Nom du nouveau fichier :",
|
"newFileMessage": "Nom du nouveau fichier :",
|
||||||
"numberDirs": "Nombre de dossiers",
|
"numberDirs": "Nombre de dossiers",
|
||||||
"numberFiles": "Nombre de fichiers",
|
"numberFiles": "Nombre de fichiers",
|
||||||
"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",
|
|
||||||
"rename": "Renommer",
|
"rename": "Renommer",
|
||||||
"renameMessage": "Nouveau nom pour",
|
"renameMessage": "Nouveau nom pour",
|
||||||
"show": "Montrer",
|
"replace": "Remplacer",
|
||||||
"size": "Taille",
|
"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",
|
"schedule": "Fixer la date",
|
||||||
"scheduleMessage": "Choisissez une date pour planifier la publication de ce post",
|
"scheduleMessage": "Choisissez une date pour planifier la publication de ce post",
|
||||||
"newArchetype": "Créer un nouveau post basé sur un archétype. Votre fichier sera créé dans le dossier de contenu."
|
"show": "Montrer",
|
||||||
|
"size": "Taille",
|
||||||
|
"upload": "",
|
||||||
|
"uploadMessage": ""
|
||||||
|
},
|
||||||
|
"search": {
|
||||||
|
"images": "Images",
|
||||||
|
"music": "Musique",
|
||||||
|
"pdf": "PDF",
|
||||||
|
"pressToSearch": "Press enter to search...",
|
||||||
|
"search": "Recherche en cours...",
|
||||||
|
"typeToSearch": "Type to search...",
|
||||||
|
"types": "Types",
|
||||||
|
"video": "Video"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"instanceName": "Instance name",
|
|
||||||
"brandingDirectoryPath": "Branding directory path",
|
|
||||||
"documentation": "documentation",
|
|
||||||
"branding": "Branding",
|
|
||||||
"disableExternalLinks": "Disable external links (except documentation)",
|
|
||||||
"brandingHelp": "You can costumize how your File Browser instance looks and feels by changing its name, replacing the logo, adding custom styles and even disable external links to GitHub.\nFor more information about custom branding, please check out the {0}.",
|
|
||||||
"admin": "Admin",
|
"admin": "Admin",
|
||||||
"administrator": "Administrateur",
|
"administrator": "Administrateur",
|
||||||
"allowCommands": "Exécuter des commandes",
|
"allowCommands": "Exécuter des commandes",
|
||||||
"allowEdit": "Editer, renommer et supprimer des fichiers ou des dossiers",
|
"allowEdit": "Editer, renommer et supprimer des fichiers ou des dossiers",
|
||||||
"allowNew": "Créer de nouveaux fichiers et dossiers",
|
"allowNew": "Créer de nouveaux fichiers et dossiers",
|
||||||
"allowPublish": "Publier de nouveaux posts et pages",
|
"allowPublish": "Publier de nouveaux posts et pages",
|
||||||
|
"allowSignup": "Allow users to signup",
|
||||||
"avoidChanges": "(Laisser vide pour conserver l'actuel)",
|
"avoidChanges": "(Laisser vide pour conserver l'actuel)",
|
||||||
|
"branding": "Branding",
|
||||||
|
"brandingDirectoryPath": "Branding directory path",
|
||||||
|
"brandingHelp": "You can customize how your File Browser instance looks and feels by changing its name, replacing the logo, adding custom styles and even disable external links to GitHub.\nFor more information about custom branding, please check out the {0}.",
|
||||||
"changePassword": "Modifier le mot de passe",
|
"changePassword": "Modifier le mot de passe",
|
||||||
"commandRunner": "Command runner",
|
"commandRunner": "Command runner",
|
||||||
"commandRunnerHelp": "Here you can set commands that are executed in the named events. You must write one per line. The environment variables {0} and {1} will be available, being {0} relative to {1}. For more information about this feature and the available environment variables, please read the {2}.",
|
"commandRunnerHelp": "Here you can set commands that are executed in the named events. You must write one per line. The environment variables {0} and {1} will be available, being {0} relative to {1}. For more information about this feature and the available environment variables, please read the {2}.",
|
||||||
"commandsUpdated": "Commandes mises à jour !",
|
"commandsUpdated": "Commandes mises à jour !",
|
||||||
|
"createUserDir": "Auto create user home dir while adding new user",
|
||||||
"customStylesheet": "Feuille de style personnalisée",
|
"customStylesheet": "Feuille de style personnalisée",
|
||||||
|
"defaultUserDescription": "This are the default settings for new users.",
|
||||||
|
"disableExternalLinks": "Disable external links (except documentation)",
|
||||||
|
"documentation": "documentation",
|
||||||
"examples": "Exemples",
|
"examples": "Exemples",
|
||||||
|
"executeOnShell": "Execute on shell",
|
||||||
|
"executeOnShellDescription": "By default, File Browser executes the commands by calling their binaries directly. If you want to run them on a shell instead (such as Bash or PowerShell), you can define it here with the required arguments and flags. If set, the command you execute will be appended as an argument. This apply to both user commands and event hooks.",
|
||||||
|
"globalRules": "This is a global set of allow and disallow rules. They apply to every user. You can define specific rules on each user's settings to override this ones.",
|
||||||
"globalSettings": "Paramètres généraux",
|
"globalSettings": "Paramètres généraux",
|
||||||
|
"hideDotfiles": "",
|
||||||
|
"insertPath": "Insert the path",
|
||||||
|
"insertRegex": "Insert regex expression",
|
||||||
|
"instanceName": "Instance name",
|
||||||
"language": "Langue",
|
"language": "Langue",
|
||||||
"lockPassword": "Prevent the user from changing the password",
|
"lockPassword": "Prevent the user from changing the password",
|
||||||
"newPassword": "Votre nouveau mot de passe",
|
"newPassword": "Votre nouveau mot de passe",
|
||||||
@@ -146,6 +190,16 @@
|
|||||||
"newUser": "Nouvel Utilisateur",
|
"newUser": "Nouvel Utilisateur",
|
||||||
"password": "Mot de passe",
|
"password": "Mot de passe",
|
||||||
"passwordUpdated": "Mot de passe mis à jour !",
|
"passwordUpdated": "Mot de passe mis à jour !",
|
||||||
|
"path": "",
|
||||||
|
"perm": {
|
||||||
|
"create": "Create files and directories",
|
||||||
|
"delete": "Delete files and directories",
|
||||||
|
"download": "Download",
|
||||||
|
"execute": "Execute commands",
|
||||||
|
"modify": "Edit files",
|
||||||
|
"rename": "Rename or move files and directories",
|
||||||
|
"share": "Share files"
|
||||||
|
},
|
||||||
"permissions": "Permissions",
|
"permissions": "Permissions",
|
||||||
"permissionsHelp": "Vous pouvez définir l'utilisateur comme étant un administrateur ou encore choisir les permissions individuellement. Si vous sélectionnez \"Administrateur\", toutes les autres options seront automatiquement activées. La gestion des utilisateurs est un privilège que seul l'administrateur possède.\n",
|
"permissionsHelp": "Vous pouvez définir l'utilisateur comme étant un administrateur ou encore choisir les permissions individuellement. Si vous sélectionnez \"Administrateur\", toutes les autres options seront automatiquement activées. La gestion des utilisateurs est un privilège que seul l'administrateur possède.\n",
|
||||||
"profileSettings": "Paramètres du profil",
|
"profileSettings": "Paramètres du profil",
|
||||||
@@ -155,82 +209,46 @@
|
|||||||
"rulesHelp": "Vous pouvez définir ici un ensemble de règles pour cet utilisateur. Les fichiers bloqués ne seront pas affichés et ne seront pas accessibles par l'utilisateur. Les expressions régulières sont supportées et les chemins d'accès sont relatifs par rapport au dossier de l'utilisateur.\n",
|
"rulesHelp": "Vous pouvez définir ici un ensemble de règles pour cet utilisateur. Les fichiers bloqués ne seront pas affichés et ne seront pas accessibles par l'utilisateur. Les expressions régulières sont supportées et les chemins d'accès sont relatifs par rapport au dossier de l'utilisateur.\n",
|
||||||
"scope": "Portée du dossier utilisateur",
|
"scope": "Portée du dossier utilisateur",
|
||||||
"settingsUpdated": "Les paramètres ont été mis à jour !",
|
"settingsUpdated": "Les paramètres ont été mis à jour !",
|
||||||
|
"shareDuration": "",
|
||||||
|
"shareManagement": "",
|
||||||
|
"singleClick": "",
|
||||||
|
"themes": {
|
||||||
|
"dark": "",
|
||||||
|
"light": "",
|
||||||
|
"title": ""
|
||||||
|
},
|
||||||
"user": "Utilisateur",
|
"user": "Utilisateur",
|
||||||
"userCommands": "Commandes",
|
"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 :",
|
||||||
"userCreated": "Utilisateur créé !",
|
"userCreated": "Utilisateur créé !",
|
||||||
|
"userDefaults": "User default settings",
|
||||||
"userDeleted": "Utilisateur supprimé !",
|
"userDeleted": "Utilisateur supprimé !",
|
||||||
"userManagement": "Gestion des utilisateurs",
|
"userManagement": "Gestion des utilisateurs",
|
||||||
"username": "Nom d'utilisateur",
|
|
||||||
"users": "Utilisateurs",
|
|
||||||
"globalRules": "This is a global set of allow and disallow rules. They apply to every user. You can define specific rules on each user's settings to override this ones.",
|
|
||||||
"allowSignup": "Allow users to signup",
|
|
||||||
"createUserDir": "Auto create user home dir while adding new user",
|
|
||||||
"insertRegex": "Insert regex expression",
|
|
||||||
"insertPath": "Insert the path",
|
|
||||||
"userUpdated": "Utilisateur mis à jour !",
|
"userUpdated": "Utilisateur mis à jour !",
|
||||||
"userDefaults": "User default settings",
|
"username": "Nom d'utilisateur",
|
||||||
"defaultUserDescription": "This are the default settings for new users.",
|
"users": "Utilisateurs"
|
||||||
"executeOnShell": "Execute on shell",
|
|
||||||
"executeOnShellDescription": "By default, File Browser executes the commands by calling their binaries directly. If you want to run them on a shell instead (such as Bash or PowerShell), you can define it here with the required arguments and flags. If set, the command you execute will be appended as an argument. This apply to both user commands and event hooks.",
|
|
||||||
"perm": {
|
|
||||||
"create": "Create files and directories",
|
|
||||||
"delete": "Delete files and directories",
|
|
||||||
"download": "Download",
|
|
||||||
"modify": "Edit files",
|
|
||||||
"execute": "Execute commands",
|
|
||||||
"rename": "Rename or move files and directories",
|
|
||||||
"share": "Share files"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"sidebar": {
|
"sidebar": {
|
||||||
"help": "Aide",
|
"help": "Aide",
|
||||||
|
"hugoNew": "Nouveau Hugo",
|
||||||
"login": "Login",
|
"login": "Login",
|
||||||
"signup": "Signup",
|
|
||||||
"logout": "Se déconnecter",
|
"logout": "Se déconnecter",
|
||||||
"myFiles": "Mes fichiers",
|
"myFiles": "Mes fichiers",
|
||||||
"newFile": "Nouveau fichier",
|
"newFile": "Nouveau fichier",
|
||||||
"newFolder": "Nouveau dossier",
|
"newFolder": "Nouveau dossier",
|
||||||
|
"preview": "Prévisualiser",
|
||||||
"settings": "Paramètres",
|
"settings": "Paramètres",
|
||||||
"siteSettings": "Paramètres du site",
|
"signup": "Signup",
|
||||||
"hugoNew": "Nouveau Hugo",
|
"siteSettings": "Paramètres du site"
|
||||||
"preview": "Prévisualiser"
|
|
||||||
},
|
},
|
||||||
"search": {
|
"success": {
|
||||||
"images": "Images",
|
"linkCopied": "Link copied!"
|
||||||
"music": "Musique",
|
|
||||||
"pdf": "PDF",
|
|
||||||
"types": "Types",
|
|
||||||
"video": "Video",
|
|
||||||
"search": "Recherche en cours...",
|
|
||||||
"typeToSearch": "Type to search...",
|
|
||||||
"pressToSearch": "Press enter to search..."
|
|
||||||
},
|
|
||||||
"languages": {
|
|
||||||
"ar": "العربية",
|
|
||||||
"en": "English",
|
|
||||||
"it": "Italiano",
|
|
||||||
"fr": "Français",
|
|
||||||
"pt": "Português",
|
|
||||||
"ptBR": "Português (Brasil)",
|
|
||||||
"ja": "日本語",
|
|
||||||
"zhCN": "中文 (简体)",
|
|
||||||
"zhTW": "中文 (繁體)",
|
|
||||||
"es": "Español",
|
|
||||||
"de": "Deutsch",
|
|
||||||
"ru": "Русский",
|
|
||||||
"pl": "Polski",
|
|
||||||
"ko": "한국어"
|
|
||||||
},
|
},
|
||||||
"time": {
|
"time": {
|
||||||
"unit": "Unité de temps",
|
"days": "Jours",
|
||||||
"seconds": "Secondes",
|
|
||||||
"minutes": "Minutes",
|
|
||||||
"hours": "Heures",
|
"hours": "Heures",
|
||||||
"days": "Jours"
|
"minutes": "Minutes",
|
||||||
},
|
"seconds": "Secondes",
|
||||||
"download": {
|
"unit": "Unité de temps"
|
||||||
"downloadFile": "Download File",
|
|
||||||
"downloadFolder": "Download Folder"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -77,28 +77,39 @@ export function detectLocale () {
|
|||||||
return locale
|
return locale
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const removeEmpty = (obj) =>
|
||||||
|
Object.keys(obj)
|
||||||
|
.filter((k) => obj[k] !== null && obj[k] !== undefined && obj[k] !== '') // Remove undef. and null and empty.string.
|
||||||
|
.reduce(
|
||||||
|
(newObj, k) =>
|
||||||
|
typeof obj[k] === 'object'
|
||||||
|
? Object.assign(newObj, { [k]: removeEmpty(obj[k]) }) // Recurse.
|
||||||
|
: Object.assign(newObj, { [k]: obj[k] }), // Copy value.
|
||||||
|
{},
|
||||||
|
);
|
||||||
|
|
||||||
const i18n = new VueI18n({
|
const i18n = new VueI18n({
|
||||||
locale: detectLocale(),
|
locale: detectLocale(),
|
||||||
fallbackLocale: 'en',
|
fallbackLocale: 'en',
|
||||||
messages: {
|
messages: {
|
||||||
'ar': ar,
|
'ar': removeEmpty(ar),
|
||||||
'de': de,
|
'de': removeEmpty(de),
|
||||||
'en': en,
|
'en': en,
|
||||||
'es': es,
|
'es': removeEmpty(es),
|
||||||
'fr': fr,
|
'fr': removeEmpty(fr),
|
||||||
'is': is,
|
'is': removeEmpty(is),
|
||||||
'it': it,
|
'it': removeEmpty(it),
|
||||||
'ja': ja,
|
'ja': removeEmpty(ja),
|
||||||
'ko': ko,
|
'ko': removeEmpty(ko),
|
||||||
'nl-be': nlBE,
|
'nl-be': removeEmpty(nlBE),
|
||||||
'pl': pl,
|
'pl': removeEmpty(pl),
|
||||||
'pt-br': ptBR,
|
'pt-br': removeEmpty(ptBR),
|
||||||
'pt': pt,
|
'pt': removeEmpty(pt),
|
||||||
'ru': ru,
|
'ru': removeEmpty(ru),
|
||||||
'ro': ro,
|
'ro': removeEmpty(ro),
|
||||||
'sv-se': svSE,
|
'sv-se': removeEmpty(svSE),
|
||||||
'zh-cn': zhCN,
|
'zh-cn': removeEmpty(zhCN),
|
||||||
'zh-tw': zhTW
|
'zh-tw': removeEmpty(zhTW)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
{
|
{
|
||||||
"permanent": "Varanlegt",
|
|
||||||
"buttons": {
|
"buttons": {
|
||||||
"shell": "Sýna skipanaglugga",
|
|
||||||
"cancel": "Hætta við",
|
"cancel": "Hætta við",
|
||||||
"close": "Loka",
|
"close": "Loka",
|
||||||
"copy": "Afrita",
|
"copy": "Afrita",
|
||||||
@@ -10,6 +8,7 @@
|
|||||||
"create": "Búa til",
|
"create": "Búa til",
|
||||||
"delete": "Eyða",
|
"delete": "Eyða",
|
||||||
"download": "Sækja",
|
"download": "Sækja",
|
||||||
|
"hideDotfiles": "",
|
||||||
"info": "Upplýsingar",
|
"info": "Upplýsingar",
|
||||||
"more": "Meira",
|
"more": "Meira",
|
||||||
"move": "Færa",
|
"move": "Færa",
|
||||||
@@ -17,25 +16,28 @@
|
|||||||
"new": "Nýtt",
|
"new": "Nýtt",
|
||||||
"next": "Næsta",
|
"next": "Næsta",
|
||||||
"ok": "OK",
|
"ok": "OK",
|
||||||
"replace": "Skipta út",
|
"permalink": "Sækja fastan hlekk",
|
||||||
"previous": "Fyrri",
|
"previous": "Fyrri",
|
||||||
|
"publish": "Gefa út",
|
||||||
"rename": "Endurnefna",
|
"rename": "Endurnefna",
|
||||||
|
"replace": "Skipta út",
|
||||||
"reportIssue": "Tilkynna vandamál",
|
"reportIssue": "Tilkynna vandamál",
|
||||||
"save": "Vista",
|
"save": "Vista",
|
||||||
|
"schedule": "Áætlun",
|
||||||
"search": "Leita",
|
"search": "Leita",
|
||||||
"select": "Velja",
|
"select": "Velja",
|
||||||
"share": "Deila",
|
|
||||||
"publish": "Gefa út",
|
|
||||||
"selectMultiple": "Velja mörg",
|
"selectMultiple": "Velja mörg",
|
||||||
"schedule": "Áætlun",
|
"share": "Deila",
|
||||||
|
"shell": "Sýna skipanaglugga",
|
||||||
"switchView": "Skipta um útlit",
|
"switchView": "Skipta um útlit",
|
||||||
"toggleSidebar": "Sýna hliðarstiku",
|
"toggleSidebar": "Sýna hliðarstiku",
|
||||||
"update": "Vista",
|
"update": "Vista",
|
||||||
"upload": "Hlaða upp",
|
"upload": "Hlaða upp"
|
||||||
"permalink": "Sækja fastan hlekk"
|
|
||||||
},
|
},
|
||||||
"success": {
|
"download": {
|
||||||
"linkCopied": "Hlekkur afritaður!"
|
"downloadFile": "Sækja skjal",
|
||||||
|
"downloadFolder": "Sækja möppu",
|
||||||
|
"downloadSelected": ""
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"forbidden": "Þú hefur ekki aðgang að þessari síðu.",
|
"forbidden": "Þú hefur ekki aðgang að þessari síðu.",
|
||||||
@@ -43,11 +45,11 @@
|
|||||||
"notFound": "Ekki er hægt að opna þessa síðu."
|
"notFound": "Ekki er hægt að opna þessa síðu."
|
||||||
},
|
},
|
||||||
"files": {
|
"files": {
|
||||||
"folders": "Möppur",
|
|
||||||
"files": "Skjöl",
|
|
||||||
"body": "Meginmál",
|
"body": "Meginmál",
|
||||||
"clear": "Hreinsa",
|
"clear": "Hreinsa",
|
||||||
"closePreview": "Loka forskoðun",
|
"closePreview": "Loka forskoðun",
|
||||||
|
"files": "Skjöl",
|
||||||
|
"folders": "Möppur",
|
||||||
"home": "Heim",
|
"home": "Heim",
|
||||||
"lastModified": "Seinast breytt",
|
"lastModified": "Seinast breytt",
|
||||||
"loading": "Hleð...",
|
"loading": "Hleð...",
|
||||||
@@ -56,9 +58,9 @@
|
|||||||
"multipleSelectionEnabled": "Hægt að velja mörg skjöl/möppur",
|
"multipleSelectionEnabled": "Hægt að velja mörg skjöl/möppur",
|
||||||
"name": "Nafn",
|
"name": "Nafn",
|
||||||
"size": "Stærð",
|
"size": "Stærð",
|
||||||
|
"sortByLastModified": "Flokka eftir Seinast breytt",
|
||||||
"sortByName": "Flokka eftir nafni",
|
"sortByName": "Flokka eftir nafni",
|
||||||
"sortBySize": "Flokka eftir stærð",
|
"sortBySize": "Flokka eftir stærð"
|
||||||
"sortByLastModified": "Flokka eftir Seinast breytt"
|
|
||||||
},
|
},
|
||||||
"help": {
|
"help": {
|
||||||
"click": "velja skjal eða möppu",
|
"click": "velja skjal eða möppu",
|
||||||
@@ -74,18 +76,39 @@
|
|||||||
"f2": "endurnefna skjal",
|
"f2": "endurnefna skjal",
|
||||||
"help": "Hjálp"
|
"help": "Hjálp"
|
||||||
},
|
},
|
||||||
|
"languages": {
|
||||||
|
"ar": "العربية",
|
||||||
|
"de": "Deutsch",
|
||||||
|
"en": "English",
|
||||||
|
"es": "Español",
|
||||||
|
"fr": "Français",
|
||||||
|
"is": "",
|
||||||
|
"it": "Italiano",
|
||||||
|
"ja": "日本語",
|
||||||
|
"ko": "한국어",
|
||||||
|
"nlBE": "",
|
||||||
|
"pl": "Polski",
|
||||||
|
"pt": "Português",
|
||||||
|
"ptBR": "Português (Brasil)",
|
||||||
|
"ro": "",
|
||||||
|
"ru": "Русский",
|
||||||
|
"svSE": "",
|
||||||
|
"zhCN": "中文 (简体)",
|
||||||
|
"zhTW": "中文 (繁體)"
|
||||||
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"password": "Lykilorð",
|
|
||||||
"passwordConfirm": "Staðfesting lykilorðs",
|
|
||||||
"submit": "Innskráning",
|
|
||||||
"createAnAccount": "Búa til nýjan aðgang",
|
"createAnAccount": "Búa til nýjan aðgang",
|
||||||
"loginInstead": "Þú ert þegar með aðgang",
|
"loginInstead": "Þú ert þegar með aðgang",
|
||||||
|
"password": "Lykilorð",
|
||||||
|
"passwordConfirm": "Staðfesting lykilorðs",
|
||||||
"passwordsDontMatch": "Lykilorð eru mismunandi",
|
"passwordsDontMatch": "Lykilorð eru mismunandi",
|
||||||
"usernameTaken": "Þetta norendanafn er þegar í notkun",
|
|
||||||
"signup": "Nýskráning",
|
"signup": "Nýskráning",
|
||||||
|
"submit": "Innskráning",
|
||||||
"username": "Notendanafn",
|
"username": "Notendanafn",
|
||||||
|
"usernameTaken": "Þetta norendanafn er þegar í notkun",
|
||||||
"wrongCredentials": "Rangar notendaupplýsingar"
|
"wrongCredentials": "Rangar notendaupplýsingar"
|
||||||
},
|
},
|
||||||
|
"permanent": "Varanlegt",
|
||||||
"prompts": {
|
"prompts": {
|
||||||
"copy": "Afrita",
|
"copy": "Afrita",
|
||||||
"copyMessage": "Veldu staðsetningu til að afrita gögn: ",
|
"copyMessage": "Veldu staðsetningu til að afrita gögn: ",
|
||||||
@@ -102,43 +125,64 @@
|
|||||||
"lastModified": "Seinast breytt",
|
"lastModified": "Seinast breytt",
|
||||||
"move": "Færa",
|
"move": "Færa",
|
||||||
"moveMessage": "Velja nýtt hús fyrir skjöl/möppur:",
|
"moveMessage": "Velja nýtt hús fyrir skjöl/möppur:",
|
||||||
|
"newArchetype": "Búðu til nýja færslu sem byggir á frumgerð. Skjalið verður búið til í content möppu. ",
|
||||||
"newDir": "Ný mappa",
|
"newDir": "Ný mappa",
|
||||||
"newDirMessage": "Hvað á mappan að heita?",
|
"newDirMessage": "Hvað á mappan að heita?",
|
||||||
"newFile": "Nýtt skjal",
|
"newFile": "Nýtt skjal",
|
||||||
"newFileMessage": "Hvað á skjalið að heita?",
|
"newFileMessage": "Hvað á skjalið að heita?",
|
||||||
"numberDirs": "Fjöldi mappa",
|
"numberDirs": "Fjöldi mappa",
|
||||||
"numberFiles": "Fjöldi skjala",
|
"numberFiles": "Fjöldi skjala",
|
||||||
"replace": "Skipta út",
|
|
||||||
"replaceMessage": "Eitt af skjölunum sem þú ert að reyna að hlaða upp hefur sama nafn og annað skjal. Viltu skipta nýja skjalinu út fyrir það gamla?\n",
|
|
||||||
"rename": "Endurnefna",
|
"rename": "Endurnefna",
|
||||||
"renameMessage": "Settu inn nýtt nafn fyrir",
|
"renameMessage": "Settu inn nýtt nafn fyrir",
|
||||||
"show": "Sýna",
|
"replace": "Skipta út",
|
||||||
"size": "Stærð",
|
"replaceMessage": "Eitt af skjölunum sem þú ert að reyna að hlaða upp hefur sama nafn og annað skjal. Viltu skipta nýja skjalinu út fyrir það gamla?\n",
|
||||||
"schedule": "Áætlun",
|
"schedule": "Áætlun",
|
||||||
"scheduleMessage": "Veldu dagsetningu og tíma fyrir áætlaða útgáfu. ",
|
"scheduleMessage": "Veldu dagsetningu og tíma fyrir áætlaða útgáfu. ",
|
||||||
"newArchetype": "Búðu til nýja færslu sem byggir á frumgerð. Skjalið verður búið til í content möppu. "
|
"show": "Sýna",
|
||||||
|
"size": "Stærð",
|
||||||
|
"upload": "",
|
||||||
|
"uploadMessage": ""
|
||||||
|
},
|
||||||
|
"search": {
|
||||||
|
"images": "Myndir",
|
||||||
|
"music": "Tónlist",
|
||||||
|
"pdf": "PDF",
|
||||||
|
"pressToSearch": "Ýttu á Enter til að leita...",
|
||||||
|
"search": "Leita...",
|
||||||
|
"typeToSearch": "Skrifaðu til að leita...",
|
||||||
|
"types": "Skrárgerðir",
|
||||||
|
"video": "Myndbönd"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"instanceName": "Nafn tilviks",
|
|
||||||
"brandingDirectoryPath": "Mappa fyrir branding-skjöl",
|
|
||||||
"documentation": "leiðbeiningar",
|
|
||||||
"branding": "Útlit",
|
|
||||||
"disableExternalLinks": "Sýna ytri-hlekki (fyrir utan leiðbeiningar)",
|
|
||||||
"brandingHelp": "Þú getur breytt því hvernig File Browser lítur út með því að breyta nafninu, setja inn nýtt lógó, búa til þína eigin stíla og tekið út GitHub-hlekki. \nTil að lesa meira um custom-branding, kíktu á {0}.",
|
|
||||||
"admin": "Stjórnandi",
|
"admin": "Stjórnandi",
|
||||||
"administrator": "Stjórnandi",
|
"administrator": "Stjórnandi",
|
||||||
"allowCommands": "Senda skipanir",
|
"allowCommands": "Senda skipanir",
|
||||||
"allowEdit": "Breyta, endurnefna og eyða skjölum eða möppum",
|
"allowEdit": "Breyta, endurnefna og eyða skjölum eða möppum",
|
||||||
"allowNew": "Búa til ný skjöl og möppur",
|
"allowNew": "Búa til ný skjöl og möppur",
|
||||||
"allowPublish": "Gefa út nýjar færslur og síður",
|
"allowPublish": "Gefa út nýjar færslur og síður",
|
||||||
|
"allowSignup": "Leyfa nýjum notendum að skrá sig",
|
||||||
"avoidChanges": "(engar breytingar ef ekkert er skrifað)",
|
"avoidChanges": "(engar breytingar ef ekkert er skrifað)",
|
||||||
|
"branding": "Útlit",
|
||||||
|
"brandingDirectoryPath": "Mappa fyrir branding-skjöl",
|
||||||
|
"brandingHelp": "Þú getur breytt því hvernig File Browser lítur út með því að breyta nafninu, setja inn nýtt lógó, búa til þína eigin stíla og tekið út GitHub-hlekki. \nTil að lesa meira um custom-branding, kíktu á {0}.",
|
||||||
"changePassword": "Breyta lykilorði",
|
"changePassword": "Breyta lykilorði",
|
||||||
"commandRunner": "Skipanagluggi",
|
"commandRunner": "Skipanagluggi",
|
||||||
"commandRunnerHelp": "Hér geturðu sett inn skipanir sem eru keyrðar eftir því sem þú tilgreinir. Skrifaðu eina skipun í hverja línu. Umhverfisbreyturnar {0} og {1} verða aðgengilegar ({0} miðast við {1}). Til að lesa meira og sjá lista yfir þær skipanir sem eru í boði, vinsamlegast lestu {2}. ",
|
"commandRunnerHelp": "Hér geturðu sett inn skipanir sem eru keyrðar eftir því sem þú tilgreinir. Skrifaðu eina skipun í hverja línu. Umhverfisbreyturnar {0} og {1} verða aðgengilegar ({0} miðast við {1}). Til að lesa meira og sjá lista yfir þær skipanir sem eru í boði, vinsamlegast lestu {2}. ",
|
||||||
"commandsUpdated": "Skipanastillingar vistaðar!",
|
"commandsUpdated": "Skipanastillingar vistaðar!",
|
||||||
|
"createUserDir": "Auto create user home dir while adding new user",
|
||||||
"customStylesheet": "Custom Stylesheet",
|
"customStylesheet": "Custom Stylesheet",
|
||||||
|
"defaultUserDescription": "Þetta eru sjálfgefnar stillingar fyrir nýja notendur.",
|
||||||
|
"disableExternalLinks": "Sýna ytri-hlekki (fyrir utan leiðbeiningar)",
|
||||||
|
"documentation": "leiðbeiningar",
|
||||||
"examples": "Dæmi",
|
"examples": "Dæmi",
|
||||||
|
"executeOnShell": "Keyra í skel",
|
||||||
|
"executeOnShellDescription": "Sjálfgefnar stillingar File Browser eru að keyra skipanir beint með því að sækja binaries. Ef þú villt keyra skipanir í skel (t.d. í Bash eða PowerShell), þá geturðu skilgreint það hér með nauðsynlegum arguments og flags. Ef þetta er stillt, þá verður skipuninni bætt fyrir aftan sem argument. Þetta gildir bæði um skipanir notenda og event hooks.",
|
||||||
|
"globalRules": "Þetta eru sjálfgegnar aðgangsreglur. Þær gilda um alla notendur. Þú getur tilgreint sérstakar reglur í stillingum fyrir hvern notenda til að ógilda þessar reglur. ",
|
||||||
"globalSettings": "Global stillingar",
|
"globalSettings": "Global stillingar",
|
||||||
|
"hideDotfiles": "",
|
||||||
|
"insertPath": "Settu inn slóð",
|
||||||
|
"insertRegex": "Setja inn reglulega segð",
|
||||||
|
"instanceName": "Nafn tilviks",
|
||||||
"language": "Tungumál",
|
"language": "Tungumál",
|
||||||
"lockPassword": "Koma í veg fyrir að notandi breyti lykilorðinu",
|
"lockPassword": "Koma í veg fyrir að notandi breyti lykilorðinu",
|
||||||
"newPassword": "Nýja lykilorðið þitt",
|
"newPassword": "Nýja lykilorðið þitt",
|
||||||
@@ -146,6 +190,16 @@
|
|||||||
"newUser": "Nýr notandi",
|
"newUser": "Nýr notandi",
|
||||||
"password": "Lykilorð",
|
"password": "Lykilorð",
|
||||||
"passwordUpdated": "Lykilorð vistað!",
|
"passwordUpdated": "Lykilorð vistað!",
|
||||||
|
"path": "",
|
||||||
|
"perm": {
|
||||||
|
"create": "Búa til sköl og möppur",
|
||||||
|
"delete": "Eyða skjölum og möppum",
|
||||||
|
"download": "Sækja",
|
||||||
|
"execute": "Keyra skipanir",
|
||||||
|
"modify": "Breyta skjölum",
|
||||||
|
"rename": "Endurnefna eða færa skjöl og möppur",
|
||||||
|
"share": "Deila skjölum"
|
||||||
|
},
|
||||||
"permissions": "Heimildir",
|
"permissions": "Heimildir",
|
||||||
"permissionsHelp": "Þú getur stillt notenda sem stjórnanda eða valið einstaklingsbundnar heimildir. Ef þú velur \"Stjórnandi\", þá verða allir aðrir valmöguleikar valdir sjálfrafa. Aðgangstýring notenda er á hendi stjórnenda. \n",
|
"permissionsHelp": "Þú getur stillt notenda sem stjórnanda eða valið einstaklingsbundnar heimildir. Ef þú velur \"Stjórnandi\", þá verða allir aðrir valmöguleikar valdir sjálfrafa. Aðgangstýring notenda er á hendi stjórnenda. \n",
|
||||||
"profileSettings": "Stilla prófíl",
|
"profileSettings": "Stilla prófíl",
|
||||||
@@ -155,82 +209,46 @@
|
|||||||
"rulesHelp": "Hér getur þú skilgreint hvaða reglur gilda um notandann. Skjölin sem hann hefur ekki aðgang að eru óaðgengileg og hann sér þau ekki. Stuðst er við reglulegar segðir og slóðir sem miðast við sýn notandans. ",
|
"rulesHelp": "Hér getur þú skilgreint hvaða reglur gilda um notandann. Skjölin sem hann hefur ekki aðgang að eru óaðgengileg og hann sér þau ekki. Stuðst er við reglulegar segðir og slóðir sem miðast við sýn notandans. ",
|
||||||
"scope": "Sýn notandans",
|
"scope": "Sýn notandans",
|
||||||
"settingsUpdated": "Stillingar vistaðar!",
|
"settingsUpdated": "Stillingar vistaðar!",
|
||||||
|
"shareDuration": "",
|
||||||
|
"shareManagement": "",
|
||||||
|
"singleClick": "",
|
||||||
|
"themes": {
|
||||||
|
"dark": "",
|
||||||
|
"light": "",
|
||||||
|
"title": ""
|
||||||
|
},
|
||||||
"user": "Notandi",
|
"user": "Notandi",
|
||||||
"userCommands": "Skipanir",
|
"userCommands": "Skipanir",
|
||||||
"userCommandsHelp": "Listi þar sem gildum er skipt upp með bili og inniheldur tiltækar skipanir fyrir þennan notanda. Til dæmis:\n",
|
"userCommandsHelp": "Listi þar sem gildum er skipt upp með bili og inniheldur tiltækar skipanir fyrir þennan notanda. Til dæmis:\n",
|
||||||
"userCreated": "Notandi stofnaður!",
|
"userCreated": "Notandi stofnaður!",
|
||||||
|
"userDefaults": "Sjálfgefnar notendastillingar",
|
||||||
"userDeleted": "Notanda eytt!",
|
"userDeleted": "Notanda eytt!",
|
||||||
"userManagement": "Notendastýring",
|
"userManagement": "Notendastýring",
|
||||||
"username": "Notendanafn",
|
|
||||||
"users": "Notendur",
|
|
||||||
"globalRules": "Þetta eru sjálfgegnar aðgangsreglur. Þær gilda um alla notendur. Þú getur tilgreint sérstakar reglur í stillingum fyrir hvern notenda til að ógilda þessar reglur. ",
|
|
||||||
"allowSignup": "Leyfa nýjum notendum að skrá sig",
|
|
||||||
"createUserDir": "Auto create user home dir while adding new user",
|
|
||||||
"insertRegex": "Setja inn reglulega segð",
|
|
||||||
"insertPath": "Settu inn slóð",
|
|
||||||
"userUpdated": "Notandastillingar vistaðar!",
|
"userUpdated": "Notandastillingar vistaðar!",
|
||||||
"userDefaults": "Sjálfgefnar notendastillingar",
|
"username": "Notendanafn",
|
||||||
"defaultUserDescription": "Þetta eru sjálfgefnar stillingar fyrir nýja notendur.",
|
"users": "Notendur"
|
||||||
"executeOnShell": "Keyra í skel",
|
|
||||||
"executeOnShellDescription": "Sjálfgefnar stillingar File Browser eru að keyra skipanir beint með því að sækja binaries. Ef þú villt keyra skipanir í skel (t.d. í Bash eða PowerShell), þá geturðu skilgreint það hér með nauðsynlegum arguments og flags. Ef þetta er stillt, þá verður skipuninni bætt fyrir aftan sem argument. Þetta gildir bæði um skipanir notenda og event hooks.",
|
|
||||||
"perm": {
|
|
||||||
"create": "Búa til sköl og möppur",
|
|
||||||
"delete": "Eyða skjölum og möppum",
|
|
||||||
"download": "Sækja",
|
|
||||||
"modify": "Breyta skjölum",
|
|
||||||
"execute": "Keyra skipanir",
|
|
||||||
"rename": "Endurnefna eða færa skjöl og möppur",
|
|
||||||
"share": "Deila skjölum"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"sidebar": {
|
"sidebar": {
|
||||||
"help": "Hjálp",
|
"help": "Hjálp",
|
||||||
|
"hugoNew": "Hugo New",
|
||||||
"login": "Innskráning",
|
"login": "Innskráning",
|
||||||
"signup": "Nýskráning",
|
|
||||||
"logout": "Útskráning",
|
"logout": "Útskráning",
|
||||||
"myFiles": "Gögnin mín",
|
"myFiles": "Gögnin mín",
|
||||||
"newFile": "Nýtt skjal",
|
"newFile": "Nýtt skjal",
|
||||||
"newFolder": "Ný mappa",
|
"newFolder": "Ný mappa",
|
||||||
|
"preview": "Sýnishorn",
|
||||||
"settings": "Stillingar",
|
"settings": "Stillingar",
|
||||||
"siteSettings": "Stillingar síðu",
|
"signup": "Nýskráning",
|
||||||
"hugoNew": "Hugo New",
|
"siteSettings": "Stillingar síðu"
|
||||||
"preview": "Sýnishorn"
|
|
||||||
},
|
},
|
||||||
"search": {
|
"success": {
|
||||||
"images": "Myndir",
|
"linkCopied": "Hlekkur afritaður!"
|
||||||
"music": "Tónlist",
|
|
||||||
"pdf": "PDF",
|
|
||||||
"types": "Skrárgerðir",
|
|
||||||
"video": "Myndbönd",
|
|
||||||
"search": "Leita...",
|
|
||||||
"typeToSearch": "Skrifaðu til að leita...",
|
|
||||||
"pressToSearch": "Ýttu á Enter til að leita..."
|
|
||||||
},
|
|
||||||
"languages": {
|
|
||||||
"ar": "العربية",
|
|
||||||
"en": "English",
|
|
||||||
"it": "Italiano",
|
|
||||||
"fr": "Français",
|
|
||||||
"pt": "Português",
|
|
||||||
"ptBR": "Português (Brasil)",
|
|
||||||
"ja": "日本語",
|
|
||||||
"zhCN": "中文 (简体)",
|
|
||||||
"zhTW": "中文 (繁體)",
|
|
||||||
"es": "Español",
|
|
||||||
"de": "Deutsch",
|
|
||||||
"ru": "Русский",
|
|
||||||
"pl": "Polski",
|
|
||||||
"ko": "한국어"
|
|
||||||
},
|
},
|
||||||
"time": {
|
"time": {
|
||||||
"unit": "Tímastilling",
|
"days": "Dagar",
|
||||||
"seconds": "Sekúndur",
|
|
||||||
"minutes": "Mínútur",
|
|
||||||
"hours": "Klukkutímar",
|
"hours": "Klukkutímar",
|
||||||
"days": "Dagar"
|
"minutes": "Mínútur",
|
||||||
},
|
"seconds": "Sekúndur",
|
||||||
"download": {
|
"unit": "Tímastilling"
|
||||||
"downloadFile": "Sækja skjal",
|
|
||||||
"downloadFolder": "Sækja möppu"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
{
|
{
|
||||||
"permanent": "Permanente",
|
|
||||||
"buttons": {
|
"buttons": {
|
||||||
"shell": "Toggle shell",
|
|
||||||
"cancel": "Annulla",
|
"cancel": "Annulla",
|
||||||
"close": "Chiudi",
|
"close": "Chiudi",
|
||||||
"copy": "Copia",
|
"copy": "Copia",
|
||||||
@@ -10,6 +8,7 @@
|
|||||||
"create": "Crea",
|
"create": "Crea",
|
||||||
"delete": "Elimina",
|
"delete": "Elimina",
|
||||||
"download": "Scarica",
|
"download": "Scarica",
|
||||||
|
"hideDotfiles": "",
|
||||||
"info": "Informazioni",
|
"info": "Informazioni",
|
||||||
"more": "Altro",
|
"more": "Altro",
|
||||||
"move": "Sposta",
|
"move": "Sposta",
|
||||||
@@ -17,25 +16,28 @@
|
|||||||
"new": "Nuovo",
|
"new": "Nuovo",
|
||||||
"next": "Successivo",
|
"next": "Successivo",
|
||||||
"ok": "OK",
|
"ok": "OK",
|
||||||
"replace": "Sostituisci",
|
"permalink": "Ottieni link permanente",
|
||||||
"previous": "Precedente",
|
"previous": "Precedente",
|
||||||
|
"publish": "Publica",
|
||||||
"rename": "Rinomina",
|
"rename": "Rinomina",
|
||||||
|
"replace": "Sostituisci",
|
||||||
"reportIssue": "Segnala un problema",
|
"reportIssue": "Segnala un problema",
|
||||||
"save": "Salva",
|
"save": "Salva",
|
||||||
|
"schedule": "Programma",
|
||||||
"search": "Cerca",
|
"search": "Cerca",
|
||||||
"select": "Seleziona",
|
"select": "Seleziona",
|
||||||
"share": "Condividi",
|
|
||||||
"publish": "Publica",
|
|
||||||
"selectMultiple": "Seleziona molteplici",
|
"selectMultiple": "Seleziona molteplici",
|
||||||
"schedule": "Programma",
|
"share": "Condividi",
|
||||||
|
"shell": "Toggle shell",
|
||||||
"switchView": "Cambia vista",
|
"switchView": "Cambia vista",
|
||||||
"toggleSidebar": "Mostra/nascondi la barra laterale",
|
"toggleSidebar": "Mostra/nascondi la barra laterale",
|
||||||
"update": "Aggiorna",
|
"update": "Aggiorna",
|
||||||
"upload": "Carica",
|
"upload": "Carica"
|
||||||
"permalink": "Ottieni link permanente"
|
|
||||||
},
|
},
|
||||||
"success": {
|
"download": {
|
||||||
"linkCopied": "Link copiato!"
|
"downloadFile": "Download File",
|
||||||
|
"downloadFolder": "Download Folder",
|
||||||
|
"downloadSelected": ""
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"forbidden": "You don't have permissions to access this.",
|
"forbidden": "You don't have permissions to access this.",
|
||||||
@@ -43,11 +45,11 @@
|
|||||||
"notFound": "Questo percorso non può essere raggiunto."
|
"notFound": "Questo percorso non può essere raggiunto."
|
||||||
},
|
},
|
||||||
"files": {
|
"files": {
|
||||||
"folders": "Cartelle",
|
|
||||||
"files": "Files",
|
|
||||||
"body": "Contenuto",
|
"body": "Contenuto",
|
||||||
"clear": "Cancella",
|
"clear": "Cancella",
|
||||||
"closePreview": "Chiudi anteprima",
|
"closePreview": "Chiudi anteprima",
|
||||||
|
"files": "Files",
|
||||||
|
"folders": "Cartelle",
|
||||||
"home": "Home",
|
"home": "Home",
|
||||||
"lastModified": "Ultima modifica",
|
"lastModified": "Ultima modifica",
|
||||||
"loading": "Caricamento...",
|
"loading": "Caricamento...",
|
||||||
@@ -56,9 +58,9 @@
|
|||||||
"multipleSelectionEnabled": "Selezione multipla attivata",
|
"multipleSelectionEnabled": "Selezione multipla attivata",
|
||||||
"name": "Nome",
|
"name": "Nome",
|
||||||
"size": "Grandezza",
|
"size": "Grandezza",
|
||||||
|
"sortByLastModified": "Ordina per ultima modifica",
|
||||||
"sortByName": "Ordina per nome",
|
"sortByName": "Ordina per nome",
|
||||||
"sortBySize": "Ordina per dimensione",
|
"sortBySize": "Ordina per dimensione"
|
||||||
"sortByLastModified": "Ordina per ultima modifica"
|
|
||||||
},
|
},
|
||||||
"help": {
|
"help": {
|
||||||
"click": "seleziona un file o una cartella",
|
"click": "seleziona un file o una cartella",
|
||||||
@@ -74,18 +76,39 @@
|
|||||||
"f2": "rinomina un file",
|
"f2": "rinomina un file",
|
||||||
"help": "Aiuto"
|
"help": "Aiuto"
|
||||||
},
|
},
|
||||||
|
"languages": {
|
||||||
|
"ar": "العربية",
|
||||||
|
"de": "Deutsch",
|
||||||
|
"en": "English",
|
||||||
|
"es": "Español",
|
||||||
|
"fr": "Français",
|
||||||
|
"is": "",
|
||||||
|
"it": "Italiano",
|
||||||
|
"ja": "日本語",
|
||||||
|
"ko": "한국어",
|
||||||
|
"nlBE": "",
|
||||||
|
"pl": "Polski",
|
||||||
|
"pt": "Português",
|
||||||
|
"ptBR": "Português (Brasil)",
|
||||||
|
"ro": "",
|
||||||
|
"ru": "Русский",
|
||||||
|
"svSE": "",
|
||||||
|
"zhCN": "中文 (简体)",
|
||||||
|
"zhTW": "中文 (繁體)"
|
||||||
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"password": "Password",
|
|
||||||
"passwordConfirm": "Password Confirmation",
|
|
||||||
"submit": "Entra",
|
|
||||||
"createAnAccount": "Create an account",
|
"createAnAccount": "Create an account",
|
||||||
"loginInstead": "Already have an account",
|
"loginInstead": "Already have an account",
|
||||||
|
"password": "Password",
|
||||||
|
"passwordConfirm": "Password Confirmation",
|
||||||
"passwordsDontMatch": "Passwords don't match",
|
"passwordsDontMatch": "Passwords don't match",
|
||||||
"usernameTaken": "Username already taken",
|
|
||||||
"signup": "Signup",
|
"signup": "Signup",
|
||||||
|
"submit": "Entra",
|
||||||
"username": "Nome utente",
|
"username": "Nome utente",
|
||||||
|
"usernameTaken": "Username already taken",
|
||||||
"wrongCredentials": "Credenziali errate"
|
"wrongCredentials": "Credenziali errate"
|
||||||
},
|
},
|
||||||
|
"permanent": "Permanente",
|
||||||
"prompts": {
|
"prompts": {
|
||||||
"copy": "Copia",
|
"copy": "Copia",
|
||||||
"copyMessage": "Seleziona la cartella in cui copiare i file:",
|
"copyMessage": "Seleziona la cartella in cui copiare i file:",
|
||||||
@@ -102,43 +125,64 @@
|
|||||||
"lastModified": "Ultima modifica",
|
"lastModified": "Ultima modifica",
|
||||||
"move": "Sposta",
|
"move": "Sposta",
|
||||||
"moveMessage": "Seleziona la nuova posizione per i tuoi file e/o cartella/e:",
|
"moveMessage": "Seleziona la nuova posizione per i tuoi file e/o cartella/e:",
|
||||||
|
"newArchetype": "Crea un nuovo post basato su un modello. Il tuo file verrà creato nella cartella.",
|
||||||
"newDir": "Nuova cartella",
|
"newDir": "Nuova cartella",
|
||||||
"newDirMessage": "Scrivi il nome della nuova cartella.",
|
"newDirMessage": "Scrivi il nome della nuova cartella.",
|
||||||
"newFile": "Nuovo file",
|
"newFile": "Nuovo file",
|
||||||
"newFileMessage": "Scrivi il nome del nuovo file.",
|
"newFileMessage": "Scrivi il nome del nuovo file.",
|
||||||
"numberDirs": "Numero di cartelle",
|
"numberDirs": "Numero di cartelle",
|
||||||
"numberFiles": "Numero di files",
|
"numberFiles": "Numero di files",
|
||||||
"replace": "Sostituisci",
|
|
||||||
"replaceMessage": "Uno dei file che stai cercando di caricare sta generando un conflitto per via del suo nome. Desideri sostituire il file già esistente?\n",
|
|
||||||
"rename": "Rinomina",
|
"rename": "Rinomina",
|
||||||
"renameMessage": "Inserisci un nuovo nome per",
|
"renameMessage": "Inserisci un nuovo nome per",
|
||||||
"show": "Mostra",
|
"replace": "Sostituisci",
|
||||||
"size": "Grandezza",
|
"replaceMessage": "Uno dei file che stai cercando di caricare sta generando un conflitto per via del suo nome. Desideri sostituire il file già esistente?\n",
|
||||||
"schedule": "Pianifica",
|
"schedule": "Pianifica",
|
||||||
"scheduleMessage": "Seleziona data e ora per programmare la pubbilicazione di questo post",
|
"scheduleMessage": "Seleziona data e ora per programmare la pubbilicazione di questo post",
|
||||||
"newArchetype": "Crea un nuovo post basato su un modello. Il tuo file verrà creato nella cartella."
|
"show": "Mostra",
|
||||||
|
"size": "Grandezza",
|
||||||
|
"upload": "",
|
||||||
|
"uploadMessage": ""
|
||||||
|
},
|
||||||
|
"search": {
|
||||||
|
"images": "Immagini",
|
||||||
|
"music": "Musica",
|
||||||
|
"pdf": "PDF",
|
||||||
|
"pressToSearch": "Press enter to search...",
|
||||||
|
"search": "Cerca...",
|
||||||
|
"typeToSearch": "Type to search...",
|
||||||
|
"types": "Tipi",
|
||||||
|
"video": "Video"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"instanceName": "Instance name",
|
|
||||||
"brandingDirectoryPath": "Branding directory path",
|
|
||||||
"documentation": "documentation",
|
|
||||||
"branding": "Branding",
|
|
||||||
"disableExternalLinks": "Disable external links (except documentation)",
|
|
||||||
"brandingHelp": "You can costumize how your File Browser instance looks and feels by changing its name, replacing the logo, adding custom styles and even disable external links to GitHub.\nFor more information about custom branding, please check out the {0}.",
|
|
||||||
"admin": "Admin",
|
"admin": "Admin",
|
||||||
"administrator": "Amministratore",
|
"administrator": "Amministratore",
|
||||||
"allowCommands": "Esegui comandi",
|
"allowCommands": "Esegui comandi",
|
||||||
"allowEdit": "Modifica, rinomina ed elimina file o cartelle",
|
"allowEdit": "Modifica, rinomina ed elimina file o cartelle",
|
||||||
"allowNew": "Crea nuovi files o cartelle",
|
"allowNew": "Crea nuovi files o cartelle",
|
||||||
"allowPublish": "Pubblica nuovi post e pagine",
|
"allowPublish": "Pubblica nuovi post e pagine",
|
||||||
|
"allowSignup": "Allow users to signup",
|
||||||
"avoidChanges": "(lascia vuoto per evitare cambiamenti)",
|
"avoidChanges": "(lascia vuoto per evitare cambiamenti)",
|
||||||
|
"branding": "Branding",
|
||||||
|
"brandingDirectoryPath": "Branding directory path",
|
||||||
|
"brandingHelp": "You can customize how your File Browser instance looks and feels by changing its name, replacing the logo, adding custom styles and even disable external links to GitHub.\nFor more information about custom branding, please check out the {0}.",
|
||||||
"changePassword": "Modifica password",
|
"changePassword": "Modifica password",
|
||||||
"commandRunner": "Command runner",
|
"commandRunner": "Command runner",
|
||||||
"commandRunnerHelp": "Here you can set commands that are executed in the named events. You must write one per line. The environment variables {0} and {1} will be available, being {0} relative to {1}. For more information about this feature and the available environment variables, please read the {2}.",
|
"commandRunnerHelp": "Here you can set commands that are executed in the named events. You must write one per line. The environment variables {0} and {1} will be available, being {0} relative to {1}. For more information about this feature and the available environment variables, please read the {2}.",
|
||||||
"commandsUpdated": "Comandi aggiornati!",
|
"commandsUpdated": "Comandi aggiornati!",
|
||||||
|
"createUserDir": "Auto create user home dir while adding new user",
|
||||||
"customStylesheet": "Folgio di stile personalizzato",
|
"customStylesheet": "Folgio di stile personalizzato",
|
||||||
|
"defaultUserDescription": "This are the default settings for new users.",
|
||||||
|
"disableExternalLinks": "Disable external links (except documentation)",
|
||||||
|
"documentation": "documentation",
|
||||||
"examples": "Esempi",
|
"examples": "Esempi",
|
||||||
|
"executeOnShell": "Execute on shell",
|
||||||
|
"executeOnShellDescription": "By default, File Browser executes the commands by calling their binaries directly. If you want to run them on a shell instead (such as Bash or PowerShell), you can define it here with the required arguments and flags. If set, the command you execute will be appended as an argument. This apply to both user commands and event hooks.",
|
||||||
|
"globalRules": "This is a global set of allow and disallow rules. They apply to every user. You can define specific rules on each user's settings to override this ones.",
|
||||||
"globalSettings": "Impostazioni Globali",
|
"globalSettings": "Impostazioni Globali",
|
||||||
|
"hideDotfiles": "",
|
||||||
|
"insertPath": "Insert the path",
|
||||||
|
"insertRegex": "Insert regex expression",
|
||||||
|
"instanceName": "Instance name",
|
||||||
"language": "Lingua",
|
"language": "Lingua",
|
||||||
"lockPassword": "Impedisci all'utente di modificare la password",
|
"lockPassword": "Impedisci all'utente di modificare la password",
|
||||||
"newPassword": "La tua nuova password",
|
"newPassword": "La tua nuova password",
|
||||||
@@ -146,6 +190,16 @@
|
|||||||
"newUser": "Nuovo utente",
|
"newUser": "Nuovo utente",
|
||||||
"password": "Password",
|
"password": "Password",
|
||||||
"passwordUpdated": "Password aggiornata!",
|
"passwordUpdated": "Password aggiornata!",
|
||||||
|
"path": "",
|
||||||
|
"perm": {
|
||||||
|
"create": "Create files and directories",
|
||||||
|
"delete": "Delete files and directories",
|
||||||
|
"download": "Download",
|
||||||
|
"execute": "Execute commands",
|
||||||
|
"modify": "Edit files",
|
||||||
|
"rename": "Rename or move files and directories",
|
||||||
|
"share": "Share files"
|
||||||
|
},
|
||||||
"permissions": "Permessi",
|
"permissions": "Permessi",
|
||||||
"permissionsHelp": "È possibile impostare l'utente come amministratore o scegliere i permessi singolarmente. Se si seleziona \"Amministratore\", tutte le altre opzioni saranno automaticamente assegnate. La gestione degli utenti rimane un privilegio di un amministratore.\n",
|
"permissionsHelp": "È possibile impostare l'utente come amministratore o scegliere i permessi singolarmente. Se si seleziona \"Amministratore\", tutte le altre opzioni saranno automaticamente assegnate. La gestione degli utenti rimane un privilegio di un amministratore.\n",
|
||||||
"profileSettings": "Impostazioni del profilo",
|
"profileSettings": "Impostazioni del profilo",
|
||||||
@@ -155,82 +209,46 @@
|
|||||||
"rulesHelp": "Qui è possibile definire una serie di regole e permessi per questo specifico utente. I file bloccati non appariranno negli elenchi e non saranno accessibili dagli utenti. all'utente. Sia regex che i percorsi relativi all'ambito di applicazione degli utenti sono supportati.\n",
|
"rulesHelp": "Qui è possibile definire una serie di regole e permessi per questo specifico utente. I file bloccati non appariranno negli elenchi e non saranno accessibili dagli utenti. all'utente. Sia regex che i percorsi relativi all'ambito di applicazione degli utenti sono supportati.\n",
|
||||||
"scope": "Scopo",
|
"scope": "Scopo",
|
||||||
"settingsUpdated": "Impostazioni aggiornate!",
|
"settingsUpdated": "Impostazioni aggiornate!",
|
||||||
|
"shareDuration": "",
|
||||||
|
"shareManagement": "",
|
||||||
|
"singleClick": "",
|
||||||
|
"themes": {
|
||||||
|
"dark": "",
|
||||||
|
"light": "",
|
||||||
|
"title": ""
|
||||||
|
},
|
||||||
"user": "Utente",
|
"user": "Utente",
|
||||||
"userCommands": "Comandi",
|
"userCommands": "Comandi",
|
||||||
"userCommandsHelp": "Una lista separata dal spazi con i comandi disponibili per questo utente. Example:\n",
|
"userCommandsHelp": "Una lista separata dal spazi con i comandi disponibili per questo utente. Example:\n",
|
||||||
"userCreated": "Utente creato!",
|
"userCreated": "Utente creato!",
|
||||||
|
"userDefaults": "User default settings",
|
||||||
"userDeleted": "Utente eliminato!",
|
"userDeleted": "Utente eliminato!",
|
||||||
"userManagement": "Gestione degli utenti",
|
"userManagement": "Gestione degli utenti",
|
||||||
"username": "Nome utente",
|
|
||||||
"users": "Utenti",
|
|
||||||
"globalRules": "This is a global set of allow and disallow rules. They apply to every user. You can define specific rules on each user's settings to override this ones.",
|
|
||||||
"allowSignup": "Allow users to signup",
|
|
||||||
"createUserDir": "Auto create user home dir while adding new user",
|
|
||||||
"insertRegex": "Insert regex expression",
|
|
||||||
"insertPath": "Insert the path",
|
|
||||||
"userUpdated": "Utente aggiornato!",
|
"userUpdated": "Utente aggiornato!",
|
||||||
"userDefaults": "User default settings",
|
"username": "Nome utente",
|
||||||
"defaultUserDescription": "This are the default settings for new users.",
|
"users": "Utenti"
|
||||||
"executeOnShell": "Execute on shell",
|
|
||||||
"executeOnShellDescription": "By default, File Browser executes the commands by calling their binaries directly. If you want to run them on a shell instead (such as Bash or PowerShell), you can define it here with the required arguments and flags. If set, the command you execute will be appended as an argument. This apply to both user commands and event hooks.",
|
|
||||||
"perm": {
|
|
||||||
"create": "Create files and directories",
|
|
||||||
"delete": "Delete files and directories",
|
|
||||||
"download": "Download",
|
|
||||||
"modify": "Edit files",
|
|
||||||
"execute": "Execute commands",
|
|
||||||
"rename": "Rename or move files and directories",
|
|
||||||
"share": "Share files"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"sidebar": {
|
"sidebar": {
|
||||||
"help": "Aiuto",
|
"help": "Aiuto",
|
||||||
|
"hugoNew": "Hugo New",
|
||||||
"login": "Login",
|
"login": "Login",
|
||||||
"signup": "Signup",
|
|
||||||
"logout": "Esci",
|
"logout": "Esci",
|
||||||
"myFiles": "I miei file",
|
"myFiles": "I miei file",
|
||||||
"newFile": "Nuovo file",
|
"newFile": "Nuovo file",
|
||||||
"newFolder": "Nuova cartella",
|
"newFolder": "Nuova cartella",
|
||||||
|
"preview": "Anteprima",
|
||||||
"settings": "Impostazioni",
|
"settings": "Impostazioni",
|
||||||
"siteSettings": "Impostaizoni del sito",
|
"signup": "Signup",
|
||||||
"hugoNew": "Hugo New",
|
"siteSettings": "Impostaizoni del sito"
|
||||||
"preview": "Anteprima"
|
|
||||||
},
|
},
|
||||||
"search": {
|
"success": {
|
||||||
"images": "Immagini",
|
"linkCopied": "Link copiato!"
|
||||||
"music": "Musica",
|
|
||||||
"pdf": "PDF",
|
|
||||||
"types": "Tipi",
|
|
||||||
"video": "Video",
|
|
||||||
"search": "Cerca...",
|
|
||||||
"typeToSearch": "Type to search...",
|
|
||||||
"pressToSearch": "Press enter to search..."
|
|
||||||
},
|
|
||||||
"languages": {
|
|
||||||
"ar": "العربية",
|
|
||||||
"en": "English",
|
|
||||||
"it": "Italiano",
|
|
||||||
"fr": "Français",
|
|
||||||
"pt": "Português",
|
|
||||||
"ptBR": "Português (Brasil)",
|
|
||||||
"ja": "日本語",
|
|
||||||
"zhCN": "中文 (简体)",
|
|
||||||
"zhTW": "中文 (繁體)",
|
|
||||||
"es": "Español",
|
|
||||||
"de": "Deutsch",
|
|
||||||
"ru": "Русский",
|
|
||||||
"pl": "Polski",
|
|
||||||
"ko": "한국어"
|
|
||||||
},
|
},
|
||||||
"time": {
|
"time": {
|
||||||
"unit": "Unità di tempo",
|
"days": "Giorni",
|
||||||
"seconds": "Secondi",
|
|
||||||
"minutes": "Minuti",
|
|
||||||
"hours": "Ore",
|
"hours": "Ore",
|
||||||
"days": "Giorni"
|
"minutes": "Minuti",
|
||||||
},
|
"seconds": "Secondi",
|
||||||
"download": {
|
"unit": "Unità di tempo"
|
||||||
"downloadFile": "Download File",
|
|
||||||
"downloadFolder": "Download Folder"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user