mirror of
https://github.com/filebrowser/filebrowser.git
synced 2025-05-08 19:22:57 +00:00
Compare commits
26 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
35d1c09243 | ||
![]() |
3d6c5152fe | ||
![]() |
ba797cda31 | ||
![]() |
5300d00d2e | ||
![]() |
bbdd313705 | ||
![]() |
045064f8b8 | ||
![]() |
252f0a7533 | ||
![]() |
1194cfe009 | ||
![]() |
0201f9c5c4 | ||
![]() |
cc331383fb | ||
![]() |
d1c84a8412 | ||
![]() |
e92dbb4bb8 | ||
![]() |
209acf2429 | ||
![]() |
25372edb5c | ||
![]() |
d51a343820 | ||
![]() |
065959451d | ||
![]() |
2fdea73430 | ||
![]() |
129a4fd39d | ||
![]() |
64400ffda8 | ||
![]() |
03d74ee758 | ||
![]() |
2b37e696c9 | ||
![]() |
21d5ee1b97 | ||
![]() |
ec7b643e8e | ||
![]() |
d729701bd4 | ||
![]() |
406d4f7884 | ||
![]() |
1e7c41505f |
31
.github/workflows/main.yaml
vendored
31
.github/workflows/main.yaml
vendored
@ -3,20 +3,25 @@ name: main
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- 'master'
|
- "master"
|
||||||
tags:
|
tags:
|
||||||
- 'v*'
|
- "v*"
|
||||||
pull_request:
|
pull_request:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
# linters
|
# linters
|
||||||
lint-frontend:
|
lint-frontend:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
- uses: pnpm/action-setup@v4
|
||||||
|
with:
|
||||||
|
package_json_file: "frontend/package.json"
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: '18'
|
node-version: "22.x"
|
||||||
|
cache: "pnpm"
|
||||||
|
cache-dependency-path: "frontend/pnpm-lock.yaml"
|
||||||
- run: make lint-frontend
|
- run: make lint-frontend
|
||||||
lint-backend:
|
lint-backend:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@ -32,14 +37,19 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- run: echo "done"
|
- run: echo "done"
|
||||||
|
|
||||||
# tests
|
# tests
|
||||||
test-frontend:
|
test-frontend:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
- uses: pnpm/action-setup@v4
|
||||||
|
with:
|
||||||
|
package_json_file: "frontend/package.json"
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: '18'
|
node-version: "22.x"
|
||||||
|
cache: "pnpm"
|
||||||
|
cache-dependency-path: "frontend/pnpm-lock.yaml"
|
||||||
- run: make test-frontend
|
- run: make test-frontend
|
||||||
test-backend:
|
test-backend:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@ -55,7 +65,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- run: echo "done"
|
- run: echo "done"
|
||||||
|
|
||||||
# release
|
# release
|
||||||
release:
|
release:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: [lint, test]
|
needs: [lint, test]
|
||||||
@ -67,9 +77,14 @@ jobs:
|
|||||||
- uses: actions/setup-go@v5
|
- uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: 1.23.0
|
go-version: 1.23.0
|
||||||
|
- uses: pnpm/action-setup@v4
|
||||||
|
with:
|
||||||
|
package_json_file: "frontend/package.json"
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: '18'
|
node-version: "22.x"
|
||||||
|
cache: "pnpm"
|
||||||
|
cache-dependency-path: "frontend/pnpm-lock.yaml"
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v1
|
uses: docker/setup-qemu-action@v1
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
|
2
.github/workflows/stale.yml
vendored
2
.github/workflows/stale.yml
vendored
@ -11,7 +11,7 @@ jobs:
|
|||||||
stale:
|
stale:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/stale@v5
|
- uses: actions/stale@v9
|
||||||
with:
|
with:
|
||||||
stale-pr-message: 'This PR is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.'
|
stale-pr-message: 'This PR is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.'
|
||||||
close-pr-message: 'This PR was closed because it has been stalled for 5 days with no activity.'
|
close-pr-message: 'This PR was closed because it has been stalled for 5 days with no activity.'
|
||||||
|
@ -36,10 +36,10 @@ builds:
|
|||||||
archives:
|
archives:
|
||||||
-
|
-
|
||||||
name_template: "{{.Os}}-{{.Arch}}{{if .Arm}}v{{.Arm}}{{end}}-{{ .ProjectName }}"
|
name_template: "{{.Os}}-{{.Arch}}{{if .Arm}}v{{.Arm}}{{end}}-{{ .ProjectName }}"
|
||||||
format: tar.gz
|
formats: [ 'tar.gz' ]
|
||||||
format_overrides:
|
format_overrides:
|
||||||
- goos: windows
|
- goos: windows
|
||||||
format: zip
|
formats: [ 'zip' ]
|
||||||
|
|
||||||
dockers:
|
dockers:
|
||||||
-
|
-
|
||||||
@ -139,6 +139,7 @@ dockers:
|
|||||||
- "filebrowser/filebrowser:v{{ .Major }}-amd64-s6"
|
- "filebrowser/filebrowser:v{{ .Major }}-amd64-s6"
|
||||||
extra_files:
|
extra_files:
|
||||||
- docker/root
|
- docker/root
|
||||||
|
- healthcheck.sh
|
||||||
-
|
-
|
||||||
dockerfile: Dockerfile.s6.aarch64
|
dockerfile: Dockerfile.s6.aarch64
|
||||||
use: buildx
|
use: buildx
|
||||||
@ -157,6 +158,7 @@ dockers:
|
|||||||
- "filebrowser/filebrowser:v{{ .Major }}-arm64-s6"
|
- "filebrowser/filebrowser:v{{ .Major }}-arm64-s6"
|
||||||
extra_files:
|
extra_files:
|
||||||
- docker/root
|
- docker/root
|
||||||
|
- healthcheck.sh
|
||||||
docker_manifests:
|
docker_manifests:
|
||||||
- name_template: "filebrowser/filebrowser:latest"
|
- name_template: "filebrowser/filebrowser:latest"
|
||||||
image_templates:
|
image_templates:
|
||||||
|
49
CHANGELOG.md
49
CHANGELOG.md
@ -2,6 +2,53 @@
|
|||||||
|
|
||||||
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.32.0](https://github.com/filebrowser/filebrowser/compare/v2.31.2...v2.32.0) (2025-01-31)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* create user on proxy authentication if user does not exist ([#3569](https://github.com/filebrowser/filebrowser/issues/3569)) ([209acf2](https://github.com/filebrowser/filebrowser/commit/209acf2429b06e2e8d78218937c59fd7e7edd1be))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* add proper healthcheck for S6 containers ([#3691](https://github.com/filebrowser/filebrowser/issues/3691)) ([045064f](https://github.com/filebrowser/filebrowser/commit/045064f8b8bf9f86058e877448085e38da8b3f2e))
|
||||||
|
* disk usage refreshing ([#3692](https://github.com/filebrowser/filebrowser/issues/3692)) ([bbdd313](https://github.com/filebrowser/filebrowser/commit/bbdd313705b8d253f0c47ad717a6e47b2f46e719))
|
||||||
|
* Fix user creation on proxy auth ([#3666](https://github.com/filebrowser/filebrowser/issues/3666)) ([5300d00](https://github.com/filebrowser/filebrowser/commit/5300d00d2e7dbb80a252aff57e100113f02506c3))
|
||||||
|
* prompts disappearing on copy / move / upload ([#3537](https://github.com/filebrowser/filebrowser/issues/3537)) ([d1c84a8](https://github.com/filebrowser/filebrowser/commit/d1c84a84123c77dede05c023b3697a432b56122c))
|
||||||
|
|
||||||
|
|
||||||
|
### Refactorings
|
||||||
|
|
||||||
|
* Fix eslint warnings ([#3698](https://github.com/filebrowser/filebrowser/issues/3698)) ([0201f9c](https://github.com/filebrowser/filebrowser/commit/0201f9c5c4dd2a4d5a3503e59cdb8045e8d3a91f)), closes [#3407](https://github.com/filebrowser/filebrowser/issues/3407)
|
||||||
|
|
||||||
|
|
||||||
|
### Build
|
||||||
|
|
||||||
|
* **deps:** bump cross-spawn from 7.0.3 to 7.0.6 in /tools ([#3601](https://github.com/filebrowser/filebrowser/issues/3601)) ([25372ed](https://github.com/filebrowser/filebrowser/commit/25372edb5c0e616e82b76b5f523633af57d347e0))
|
||||||
|
* **deps:** bump github.com/golang-jwt/jwt/v4 from 4.5.0 to 4.5.1 ([#3574](https://github.com/filebrowser/filebrowser/issues/3574)) ([2fdea73](https://github.com/filebrowser/filebrowser/commit/2fdea73430011846276a1cda52458f1d670f5ea7))
|
||||||
|
* **deps:** bump golang.org/x/crypto from 0.26.0 to 0.31.0 ([#3634](https://github.com/filebrowser/filebrowser/issues/3634)) ([e92dbb4](https://github.com/filebrowser/filebrowser/commit/e92dbb4bb8b7894264fbf0a48a641712c3b68766))
|
||||||
|
* **deps:** bump golang.org/x/net from 0.23.0 to 0.33.0 ([#3712](https://github.com/filebrowser/filebrowser/issues/3712)) ([1194cfe](https://github.com/filebrowser/filebrowser/commit/1194cfe0097a70399c1f06cf0f514b9d70fa463c))
|
||||||
|
* **deps:** bump vue-i18n from 9.10.2 to 9.14.2 in /frontend ([#3618](https://github.com/filebrowser/filebrowser/issues/3618)) ([0659594](https://github.com/filebrowser/filebrowser/commit/065959451d3ba12019c6151274aa4e6904cdca99))
|
||||||
|
* fix go releaser ([ba797cd](https://github.com/filebrowser/filebrowser/commit/ba797cda3135eddb9b7165dc5ceb932399cb54df))
|
||||||
|
* update to node 22 and pnpm ([#3616](https://github.com/filebrowser/filebrowser/issues/3616)) ([d51a343](https://github.com/filebrowser/filebrowser/commit/d51a3438201274a1b826be1b775ca1035ade20c5))
|
||||||
|
|
||||||
|
### [2.31.2](https://github.com/filebrowser/filebrowser/compare/v2.31.1...v2.31.2) (2024-10-03)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* added whitespace before version ([#3510](https://github.com/filebrowser/filebrowser/issues/3510)) ([2b37e69](https://github.com/filebrowser/filebrowser/commit/2b37e696c9bde4d0c453de236a3555d982346bbb))
|
||||||
|
* change location of custom init scripts ([#3493](https://github.com/filebrowser/filebrowser/issues/3493)) ([406d4f7](https://github.com/filebrowser/filebrowser/commit/406d4f78845a1684df7c9c457b208f4dd9b2a930))
|
||||||
|
* files list alignment ([#3494](https://github.com/filebrowser/filebrowser/issues/3494)) ([64400ff](https://github.com/filebrowser/filebrowser/commit/64400ffda8b09f66b8662a3c9400235139800a4d))
|
||||||
|
* german translation spelling typos ([#3469](https://github.com/filebrowser/filebrowser/issues/3469)) ([1e7c415](https://github.com/filebrowser/filebrowser/commit/1e7c41505fb6a3b9baa1534787492a186e09bcfb))
|
||||||
|
|
||||||
|
|
||||||
|
### Build
|
||||||
|
|
||||||
|
* **deps-dev:** bump vite from 5.2.7 to 5.4.6 in /frontend ([#3496](https://github.com/filebrowser/filebrowser/issues/3496)) ([ec7b643](https://github.com/filebrowser/filebrowser/commit/ec7b643e8e9499f7ff226ec7f8e63a9df9890352))
|
||||||
|
* **deps:** bump rollup from 4.21.3 to 4.22.4 in /frontend ([#3504](https://github.com/filebrowser/filebrowser/issues/3504)) ([03d74ee](https://github.com/filebrowser/filebrowser/commit/03d74ee7582196c09720f8d488056339f06c446c))
|
||||||
|
|
||||||
### [2.31.1](https://github.com/filebrowser/filebrowser/compare/v2.31.0...v2.31.1) (2024-08-30)
|
### [2.31.1](https://github.com/filebrowser/filebrowser/compare/v2.31.0...v2.31.1) (2024-08-30)
|
||||||
|
|
||||||
|
|
||||||
@ -99,7 +146,7 @@ All notable changes to this project will be documented in this file. See [standa
|
|||||||
* close editor when click escape key ([#2947](https://github.com/filebrowser/filebrowser/issues/2947)) ([70c8261](https://github.com/filebrowser/filebrowser/commit/70c826133b8578b8712e6db8f762a15a076cd9a9))
|
* close editor when click escape key ([#2947](https://github.com/filebrowser/filebrowser/issues/2947)) ([70c8261](https://github.com/filebrowser/filebrowser/commit/70c826133b8578b8712e6db8f762a15a076cd9a9))
|
||||||
* enable preview in shared folder ([#3055](https://github.com/filebrowser/filebrowser/issues/3055)) ([4c233c3](https://github.com/filebrowser/filebrowser/commit/4c233c3db39ea5a00d6e602ec0ecbddecb590877))
|
* enable preview in shared folder ([#3055](https://github.com/filebrowser/filebrowser/issues/3055)) ([4c233c3](https://github.com/filebrowser/filebrowser/commit/4c233c3db39ea5a00d6e602ec0ecbddecb590877))
|
||||||
* focus editor when opened ([#2946](https://github.com/filebrowser/filebrowser/issues/2946)) ([b19710e](https://github.com/filebrowser/filebrowser/commit/b19710efca6daa7af56dc211d0051d500d2eea22))
|
* focus editor when opened ([#2946](https://github.com/filebrowser/filebrowser/issues/2946)) ([b19710e](https://github.com/filebrowser/filebrowser/commit/b19710efca6daa7af56dc211d0051d500d2eea22))
|
||||||
* freezing the list in the backgroud while previewing a file ([#3004](https://github.com/filebrowser/filebrowser/issues/3004)) ([e167c3e](https://github.com/filebrowser/filebrowser/commit/e167c3e1efed8b16be45d994a8d443fda1d8cf49))
|
* freezing the list in the background while previewing a file ([#3004](https://github.com/filebrowser/filebrowser/issues/3004)) ([e167c3e](https://github.com/filebrowser/filebrowser/commit/e167c3e1efed8b16be45d994a8d443fda1d8cf49))
|
||||||
* prompt to confirm discard editor changes ([#2948](https://github.com/filebrowser/filebrowser/issues/2948)) ([fb1a09c](https://github.com/filebrowser/filebrowser/commit/fb1a09c7c172b913c12b30975ca545e505df0c05))
|
* prompt to confirm discard editor changes ([#2948](https://github.com/filebrowser/filebrowser/issues/2948)) ([fb1a09c](https://github.com/filebrowser/filebrowser/commit/fb1a09c7c172b913c12b30975ca545e505df0c05))
|
||||||
* select multiple files with ctrl even with singleClick option ([#2953](https://github.com/filebrowser/filebrowser/issues/2953)) ([d49c3df](https://github.com/filebrowser/filebrowser/commit/d49c3dfacfc0ff07e620b3ad2700e64927b06235))
|
* select multiple files with ctrl even with singleClick option ([#2953](https://github.com/filebrowser/filebrowser/issues/2953)) ([d49c3df](https://github.com/filebrowser/filebrowser/commit/d49c3dfacfc0ff07e620b3ad2700e64927b06235))
|
||||||
|
|
||||||
|
@ -2,13 +2,18 @@ FROM ghcr.io/linuxserver/baseimage-alpine:3.20
|
|||||||
|
|
||||||
RUN apk --update add ca-certificates \
|
RUN apk --update add ca-certificates \
|
||||||
mailcap \
|
mailcap \
|
||||||
curl
|
curl \
|
||||||
|
jq
|
||||||
|
|
||||||
|
COPY healthcheck.sh /healthcheck.sh
|
||||||
|
RUN chmod +x /healthcheck.sh # Make the script executable
|
||||||
|
|
||||||
HEALTHCHECK --start-period=2s --interval=5s --timeout=3s \
|
HEALTHCHECK --start-period=2s --interval=5s --timeout=3s \
|
||||||
CMD curl -f http://localhost/health || exit 1
|
CMD /healthcheck.sh || exit 1
|
||||||
|
|
||||||
# copy local files
|
# copy local files
|
||||||
COPY docker/root/ /
|
COPY docker/root/ /
|
||||||
|
RUN ln -s /config/settings.json /.filebrowser.json
|
||||||
COPY filebrowser /usr/bin/filebrowser
|
COPY filebrowser /usr/bin/filebrowser
|
||||||
|
|
||||||
# ports and volumes
|
# ports and volumes
|
||||||
|
@ -2,13 +2,18 @@ FROM ghcr.io/linuxserver/baseimage-alpine:arm64v8-3.20
|
|||||||
|
|
||||||
RUN apk --update add ca-certificates \
|
RUN apk --update add ca-certificates \
|
||||||
mailcap \
|
mailcap \
|
||||||
curl
|
curl \
|
||||||
|
jq
|
||||||
|
|
||||||
|
COPY healthcheck.sh /healthcheck.sh
|
||||||
|
RUN chmod +x /healthcheck.sh # Make the script executable
|
||||||
|
|
||||||
HEALTHCHECK --start-period=2s --interval=5s --timeout=3s \
|
HEALTHCHECK --start-period=2s --interval=5s --timeout=3s \
|
||||||
CMD curl -f http://localhost/health || exit 1
|
CMD /healthcheck.sh || exit 1
|
||||||
|
|
||||||
# copy local files
|
# copy local files
|
||||||
COPY docker/root/ /
|
COPY docker/root/ /
|
||||||
|
RUN ln -s /config/settings.json /.filebrowser.json
|
||||||
COPY filebrowser /usr/bin/filebrowser
|
COPY filebrowser /usr/bin/filebrowser
|
||||||
|
|
||||||
# ports and volumes
|
# ports and volumes
|
||||||
|
5
Makefile
5
Makefile
@ -10,7 +10,7 @@ build: | build-frontend build-backend ## Build binary
|
|||||||
|
|
||||||
.PHONY: build-frontend
|
.PHONY: build-frontend
|
||||||
build-frontend: ## Build frontend
|
build-frontend: ## Build frontend
|
||||||
$Q cd frontend && npm ci && npm run build
|
$Q cd frontend && pnpm install --frozen-lockfile && pnpm run build
|
||||||
|
|
||||||
.PHONY: build-backend
|
.PHONY: build-backend
|
||||||
build-backend: ## Build backend
|
build-backend: ## Build backend
|
||||||
@ -21,6 +21,7 @@ test: | test-frontend test-backend ## Run all tests
|
|||||||
|
|
||||||
.PHONY: test-frontend
|
.PHONY: test-frontend
|
||||||
test-frontend: ## Run frontend tests
|
test-frontend: ## Run frontend tests
|
||||||
|
$Q cd frontend && pnpm install --frozen-lockfile && pnpm run typecheck
|
||||||
|
|
||||||
.PHONY: test-backend
|
.PHONY: test-backend
|
||||||
test-backend: ## Run backend tests
|
test-backend: ## Run backend tests
|
||||||
@ -31,7 +32,7 @@ lint: lint-frontend lint-backend ## Run all linters
|
|||||||
|
|
||||||
.PHONY: lint-frontend
|
.PHONY: lint-frontend
|
||||||
lint-frontend: ## Run frontend linters
|
lint-frontend: ## Run frontend linters
|
||||||
$Q cd frontend && npm ci && npm run lint
|
$Q cd frontend && pnpm install --frozen-lockfile && pnpm run lint
|
||||||
|
|
||||||
.PHONY: lint-backend
|
.PHONY: lint-backend
|
||||||
lint-backend: | $(golangci-lint) ## Run backend linters
|
lint-backend: | $(golangci-lint) ## Run backend linters
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
package auth
|
package auth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/rand"
|
||||||
"errors"
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
|
||||||
|
|
||||||
fbErrors "github.com/filebrowser/filebrowser/v2/errors"
|
fbErrors "github.com/filebrowser/filebrowser/v2/errors"
|
||||||
"github.com/filebrowser/filebrowser/v2/settings"
|
"github.com/filebrowser/filebrowser/v2/settings"
|
||||||
@ -19,14 +19,49 @@ 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, usr users.Store, _ *settings.Settings, srv *settings.Server) (*users.User, error) {
|
func (a ProxyAuth) Auth(r *http.Request, usr users.Store, setting *settings.Settings, srv *settings.Server) (*users.User, error) {
|
||||||
username := r.Header.Get(a.Header)
|
username := r.Header.Get(a.Header)
|
||||||
user, err := usr.Get(srv.Root, username)
|
user, err := usr.Get(srv.Root, username)
|
||||||
if errors.Is(err, fbErrors.ErrNotExist) {
|
if errors.Is(err, fbErrors.ErrNotExist) {
|
||||||
return nil, os.ErrPermission
|
return a.createUser(usr, setting, srv, username)
|
||||||
|
}
|
||||||
|
return user, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a ProxyAuth) createUser(usr users.Store, setting *settings.Settings, srv *settings.Server, username string) (*users.User, error) {
|
||||||
|
const passwordSize = 32
|
||||||
|
randomPasswordBytes := make([]byte, passwordSize)
|
||||||
|
_, err := rand.Read(randomPasswordBytes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return user, err
|
var hashedRandomPassword string
|
||||||
|
hashedRandomPassword, err = users.HashPwd(string(randomPasswordBytes))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
user := &users.User{
|
||||||
|
Username: username,
|
||||||
|
Password: hashedRandomPassword,
|
||||||
|
LockPassword: true,
|
||||||
|
}
|
||||||
|
setting.Defaults.Apply(user)
|
||||||
|
|
||||||
|
var userHome string
|
||||||
|
userHome, err = setting.MakeUserDir(user.Username, user.Scope, srv.Root)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
user.Scope = userHome
|
||||||
|
|
||||||
|
err = usr.Save(user)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return user, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoginPage tells that proxy auth doesn't require a login page.
|
// LoginPage tells that proxy auth doesn't require a login page.
|
||||||
|
@ -76,7 +76,7 @@ var rootCmd = &cobra.Command{
|
|||||||
Use: "filebrowser",
|
Use: "filebrowser",
|
||||||
Short: "A stylish web-based file browser",
|
Short: "A stylish web-based file browser",
|
||||||
Long: `File Browser CLI lets you create the database to use with File Browser,
|
Long: `File Browser CLI lets you create the database to use with File Browser,
|
||||||
manage your users and all the configurations without acessing the
|
manage your users and all the configurations without accessing the
|
||||||
web interface.
|
web interface.
|
||||||
|
|
||||||
If you've never run File Browser, you'll need to have a database for
|
If you've never run File Browser, you'll need to have a database for
|
||||||
@ -108,7 +108,7 @@ name in caps. So to set "database" via an env variable, you should
|
|||||||
set FB_DATABASE.
|
set FB_DATABASE.
|
||||||
|
|
||||||
Also, if the database path doesn't exist, File Browser will enter into
|
Also, if the database path doesn't exist, File Browser will enter into
|
||||||
the quick setup mode and a new database will be bootstraped and a new
|
the quick setup mode and a new database will be bootstrapped and a new
|
||||||
user created with the credentials from options "username" and "password".`,
|
user created with the credentials from options "username" and "password".`,
|
||||||
Run: python(func(cmd *cobra.Command, _ []string, d pythonData) {
|
Run: python(func(cmd *cobra.Command, _ []string, d pythonData) {
|
||||||
log.Println(cfgFile)
|
log.Println(cfgFile)
|
||||||
|
@ -188,7 +188,7 @@ func cleanUpMapValue(v interface{}) interface{} {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// convertCmdStrToCmdArray checks if cmd string is blank (whitespace included)
|
// convertCmdStrToCmdArray checks if cmd string is blank (whitespace included)
|
||||||
// then returns empty string array, else returns the splitted word array of cmd.
|
// then returns empty string array, else returns the split word array of cmd.
|
||||||
// This is to ensure the result will never be []string{""}
|
// This is to ensure the result will never be []string{""}
|
||||||
func convertCmdStrToCmdArray(cmd string) []string {
|
func convertCmdStrToCmdArray(cmd string) []string {
|
||||||
var cmdArray []string
|
var cmdArray []string
|
||||||
|
@ -28,7 +28,7 @@ const (
|
|||||||
ContentTextHeaderValue = "text/plain"
|
ContentTextHeaderValue = "text/plain"
|
||||||
// ContentXMLHeaderValue header value for XML data.
|
// ContentXMLHeaderValue header value for XML data.
|
||||||
ContentXMLHeaderValue = "text/xml"
|
ContentXMLHeaderValue = "text/xml"
|
||||||
// ContentXMLUnreadableHeaderValue obselete header value for XML.
|
// ContentXMLUnreadableHeaderValue obsolete header value for XML.
|
||||||
ContentXMLUnreadableHeaderValue = "application/xml"
|
ContentXMLUnreadableHeaderValue = "application/xml"
|
||||||
// ContentMarkdownHeaderValue custom key/content type, the real is the text/html.
|
// ContentMarkdownHeaderValue custom key/content type, the real is the text/html.
|
||||||
ContentMarkdownHeaderValue = "text/markdown"
|
ContentMarkdownHeaderValue = "text/markdown"
|
||||||
|
@ -98,7 +98,7 @@ func CommonPrefix(sep byte, paths ...string) string {
|
|||||||
// (e.g. /home/user1, /home/user1/foo, /home/user1/bar).
|
// (e.g. /home/user1, /home/user1/foo, /home/user1/bar).
|
||||||
// path.Clean will have cleaned off trailing / separators with
|
// path.Clean will have cleaned off trailing / separators with
|
||||||
// the exception of the root directory, "/" (in which case we
|
// the exception of the root directory, "/" (in which case we
|
||||||
// make it "//", but this will get fixed up to "/" bellow).
|
// make it "//", but this will get fixed up to "/" below).
|
||||||
c = append(c, sep)
|
c = append(c, sep)
|
||||||
|
|
||||||
// Ignore the first path since it's already in c
|
// Ignore the first path since it's already in c
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
{
|
|
||||||
"root": true,
|
|
||||||
"env": {
|
|
||||||
"node": true
|
|
||||||
},
|
|
||||||
"extends": [
|
|
||||||
"plugin:vue/vue3-essential",
|
|
||||||
"eslint:recommended",
|
|
||||||
"@vue/eslint-config-typescript",
|
|
||||||
"@vue/eslint-config-prettier"
|
|
||||||
],
|
|
||||||
"rules": {
|
|
||||||
"vue/multi-word-component-names": "off",
|
|
||||||
"vue/no-mutating-props": [
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
"shallowOnly": true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
// no-undef is already included in
|
|
||||||
// @vue/eslint-config-typescript
|
|
||||||
},
|
|
||||||
"parserOptions": {
|
|
||||||
"ecmaVersion": "latest",
|
|
||||||
"sourceType": "module"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,2 +1,3 @@
|
|||||||
# Ignore artifacts:
|
# Ignore artifacts:
|
||||||
dist
|
dist
|
||||||
|
pnpm-lock.yaml
|
38
frontend/eslint.config.js
Normal file
38
frontend/eslint.config.js
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import pluginVue from "eslint-plugin-vue";
|
||||||
|
import vueTsEslintConfig from "@vue/eslint-config-typescript";
|
||||||
|
import prettierConfig from "@vue/eslint-config-prettier";
|
||||||
|
|
||||||
|
export default [
|
||||||
|
{
|
||||||
|
name: "app/files-to-lint",
|
||||||
|
files: ["**/*.{ts,mts,tsx,vue}"],
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: "app/files-to-ignore",
|
||||||
|
ignores: ["**/dist/**", "**/dist-ssr/**", "**/coverage/**"],
|
||||||
|
},
|
||||||
|
|
||||||
|
...pluginVue.configs["flat/essential"],
|
||||||
|
...vueTsEslintConfig(),
|
||||||
|
prettierConfig,
|
||||||
|
|
||||||
|
{
|
||||||
|
rules: {
|
||||||
|
// Note: you must disable the base rule as it can report incorrect errors
|
||||||
|
"no-unused-expressions": "off",
|
||||||
|
"@typescript-eslint/no-unused-expressions": "off",
|
||||||
|
// TODO: theres too many of these from before ts
|
||||||
|
"@typescript-eslint/no-explicit-any": "off",
|
||||||
|
// TODO: finish the ts conversion
|
||||||
|
"vue/block-lang": "off",
|
||||||
|
"vue/multi-word-component-names": "off",
|
||||||
|
"vue/no-mutating-props": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
shallowOnly: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
@ -1,10 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"baseUrl": ".",
|
|
||||||
"paths": {
|
|
||||||
"@/*": ["./src/*"]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"include": ["src/**/*"],
|
|
||||||
"exclude": ["node_modules", "dist"]
|
|
||||||
}
|
|
7962
frontend/package-lock.json
generated
7962
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -4,70 +4,74 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"engines": {
|
"engines": {
|
||||||
"npm": ">=7.0.0",
|
"node": ">=22.0.0",
|
||||||
"node": ">=18.0.0"
|
"pnpm": ">=9.0.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite dev",
|
"dev": "vite dev",
|
||||||
"build": "npm run typecheck && vite build",
|
"build": "pnpm run typecheck && vite build",
|
||||||
"clean": "find ./dist -maxdepth 1 -mindepth 1 ! -name '.gitkeep' -exec rm -r {} +",
|
"clean": "find ./dist -maxdepth 1 -mindepth 1 ! -name '.gitkeep' -exec rm -r {} +",
|
||||||
"typecheck": "vue-tsc -p ./tsconfig.json --noEmit",
|
"typecheck": "vue-tsc -p ./tsconfig.tsc.json --noEmit",
|
||||||
"lint": "npm run typecheck && eslint --ext .vue,.ts src/",
|
"lint": "eslint src/",
|
||||||
"lint:fix": "eslint --ext .vue,.ts --fix src/",
|
"lint:fix": "eslint --fix src/",
|
||||||
"format": "prettier --write .",
|
"format": "prettier --write .",
|
||||||
"test": "playwright test"
|
"test": "playwright test"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@chenfengyuan/vue-number-input": "^2.0.1",
|
"@chenfengyuan/vue-number-input": "^2.0.1",
|
||||||
"@vueuse/core": "^10.9.0",
|
"@vueuse/core": "^12.5.0",
|
||||||
"@vueuse/integrations": "^10.9.0",
|
"@vueuse/integrations": "^12.5.0",
|
||||||
"ace-builds": "^1.32.9",
|
"ace-builds": "^1.37.5",
|
||||||
"core-js": "^3.36.1",
|
"core-js": "^3.40.0",
|
||||||
"dayjs": "^1.11.10",
|
"dayjs": "^1.11.10",
|
||||||
|
"epubjs": "^0.3.93",
|
||||||
"filesize": "^10.1.1",
|
"filesize": "^10.1.1",
|
||||||
"js-base64": "^3.7.7",
|
"js-base64": "^3.7.7",
|
||||||
"jwt-decode": "^4.0.0",
|
"jwt-decode": "^4.0.0",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"material-icons": "^1.13.12",
|
"marked": "^15.0.6",
|
||||||
"marked": "^14.1.0",
|
"material-icons": "^1.13.13",
|
||||||
"normalize.css": "^8.0.1",
|
"normalize.css": "^8.0.1",
|
||||||
"pinia": "^2.1.7",
|
"pinia": "^2.3.1",
|
||||||
"pretty-bytes": "^6.1.1",
|
"pretty-bytes": "^6.1.1",
|
||||||
"qrcode.vue": "^3.4.1",
|
"qrcode.vue": "^3.4.1",
|
||||||
"tus-js-client": "^4.1.0",
|
"tus-js-client": "^4.3.1",
|
||||||
"utif": "^3.1.0",
|
"utif": "^3.1.0",
|
||||||
"video.js": "^8.10.0",
|
"video.js": "^8.21.0",
|
||||||
"videojs-hotkeys": "^0.2.28",
|
"videojs-hotkeys": "^0.2.28",
|
||||||
"videojs-mobile-ui": "^1.1.1",
|
"videojs-mobile-ui": "^1.1.1",
|
||||||
"vue": "^3.4.21",
|
"vue": "^3.4.21",
|
||||||
"vue-final-modal": "^4.5.4",
|
"vue-final-modal": "^4.5.4",
|
||||||
"vue-i18n": "^9.10.2",
|
"vue-i18n": "^11.1.2",
|
||||||
"vue-lazyload": "^3.0.0",
|
"vue-lazyload": "^3.0.0",
|
||||||
"vue-reader": "^1.2.14",
|
"vue-reader": "^1.2.17",
|
||||||
"vue-router": "^4.3.0",
|
"vue-router": "^4.3.0",
|
||||||
"vue-toastification": "^2.0.0-rc.5"
|
"vue-toastification": "^2.0.0-rc.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@intlify/unplugin-vue-i18n": "^4.0.0",
|
"@intlify/unplugin-vue-i18n": "^6.0.3",
|
||||||
"@playwright/test": "^1.42.1",
|
"@playwright/test": "^1.50.0",
|
||||||
|
"@tsconfig/node22": "^22.0.0",
|
||||||
"@types/lodash-es": "^4.17.12",
|
"@types/lodash-es": "^4.17.12",
|
||||||
"@types/node": "^20.12.2",
|
"@types/node": "^22.10.10",
|
||||||
"@typescript-eslint/eslint-plugin": "^7.4.0",
|
"@typescript-eslint/eslint-plugin": "^8.21.0",
|
||||||
"@vitejs/plugin-legacy": "^5.3.2",
|
"@vitejs/plugin-legacy": "^6.0.0",
|
||||||
"@vitejs/plugin-vue": "^5.0.4",
|
"@vitejs/plugin-vue": "^5.0.4",
|
||||||
"@vue/eslint-config-prettier": "^9.0.0",
|
"@vue/eslint-config-prettier": "^10.2.0",
|
||||||
"@vue/eslint-config-typescript": "^13.0.0",
|
"@vue/eslint-config-typescript": "^14.3.0",
|
||||||
|
"@vue/tsconfig": "^0.7.0",
|
||||||
"autoprefixer": "^10.4.19",
|
"autoprefixer": "^10.4.19",
|
||||||
"concurrently": "^8.2.2",
|
"concurrently": "^9.1.2",
|
||||||
"eslint": "^8.57.0",
|
"eslint": "^9.19.0",
|
||||||
"eslint-plugin-prettier": "^5.1.3",
|
"eslint-plugin-prettier": "^5.2.3",
|
||||||
"eslint-plugin-vue": "^9.24.0",
|
"eslint-plugin-vue": "^9.24.0",
|
||||||
"jsdom": "^24.0.0",
|
"jsdom": "^26.0.0",
|
||||||
"postcss": "^8.4.38",
|
"postcss": "^8.5.1",
|
||||||
"prettier": "^3.2.5",
|
"prettier": "^3.4.2",
|
||||||
"terser": "^5.30.0",
|
"terser": "^5.37.0",
|
||||||
"vite": "^5.2.7",
|
"vite": "^6.0.11",
|
||||||
"vite-plugin-compression2": "^1.0.0",
|
"vite-plugin-compression2": "^1.0.0",
|
||||||
"vue-tsc": "^2.0.7"
|
"vue-tsc": "^2.2.0"
|
||||||
}
|
},
|
||||||
|
"packageManager": "pnpm@9.15.4+sha512.b2dc20e2fc72b3e18848459b37359a32064663e5627a51e4c74b2c29dd8e8e0491483c3abb40789cfd578bf362fb6ba8261b05f0387d76792ed6e23ea3b1b6a0"
|
||||||
}
|
}
|
||||||
|
5389
frontend/pnpm-lock.yaml
generated
Normal file
5389
frontend/pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,8 @@
|
|||||||
import { createURL, fetchURL, removePrefix } from "./utils";
|
|
||||||
import { baseURL } from "@/utils/constants";
|
|
||||||
import { useAuthStore } from "@/stores/auth";
|
import { useAuthStore } from "@/stores/auth";
|
||||||
|
import { useLayoutStore } from "@/stores/layout";
|
||||||
|
import { baseURL } from "@/utils/constants";
|
||||||
import { upload as postTus, useTus } from "./tus";
|
import { upload as postTus, useTus } from "./tus";
|
||||||
|
import { createURL, fetchURL, removePrefix } from "./utils";
|
||||||
|
|
||||||
export async function fetch(url: string) {
|
export async function fetch(url: string) {
|
||||||
url = removePrefix(url);
|
url = removePrefix(url);
|
||||||
@ -156,6 +157,7 @@ function moveCopy(
|
|||||||
overwrite = false,
|
overwrite = false,
|
||||||
rename = false
|
rename = false
|
||||||
) {
|
) {
|
||||||
|
const layoutStore = useLayoutStore();
|
||||||
const promises = [];
|
const promises = [];
|
||||||
|
|
||||||
for (const item of items) {
|
for (const item of items) {
|
||||||
@ -166,7 +168,7 @@ function moveCopy(
|
|||||||
}&destination=${to}&override=${overwrite}&rename=${rename}`;
|
}&destination=${to}&override=${overwrite}&rename=${rename}`;
|
||||||
promises.push(resourceAction(url, "PATCH"));
|
promises.push(resourceAction(url, "PATCH"));
|
||||||
}
|
}
|
||||||
|
layoutStore.closeHovers();
|
||||||
return Promise.all(promises);
|
return Promise.all(promises);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ export async function create(user: IUser) {
|
|||||||
throw new StatusError(await res.text(), res.status);
|
throw new StatusError(await res.text(), res.status);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function update(user: IUser, which = ["all"]) {
|
export async function update(user: Partial<IUser>, which = ["all"]) {
|
||||||
await fetchURL(`/api/users/${user.id}`, {
|
await fetchURL(`/api/users/${user.id}`, {
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
|
@ -34,7 +34,7 @@ const props = defineProps<{
|
|||||||
|
|
||||||
const items = computed(() => {
|
const items = computed(() => {
|
||||||
const relativePath = route.path.replace(props.base, "");
|
const relativePath = route.path.replace(props.base, "");
|
||||||
let parts = relativePath.split("/");
|
const parts = relativePath.split("/");
|
||||||
|
|
||||||
if (parts[0] === "") {
|
if (parts[0] === "") {
|
||||||
parts.shift();
|
parts.shift();
|
||||||
@ -44,7 +44,7 @@ const items = computed(() => {
|
|||||||
parts.pop();
|
parts.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
let breadcrumbs: BreadCrumb[] = [];
|
const breadcrumbs: BreadCrumb[] = [];
|
||||||
|
|
||||||
for (let i = 0; i < parts.length; i++) {
|
for (let i = 0; i < parts.length; i++) {
|
||||||
if (i === 0) {
|
if (i === 0) {
|
||||||
|
@ -46,7 +46,7 @@ https://raw.githubusercontent.com/dzwillia/vue-simple-progress/master/src/compon
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
// We're leaving this untouched as you can read in the beginning
|
// We're leaving this untouched as you can read in the beginning
|
||||||
var isNumber = function (n) {
|
const isNumber = function (n) {
|
||||||
return !isNaN(parseFloat(n)) && isFinite(n);
|
return !isNaN(parseFloat(n)) && isFinite(n);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -107,7 +107,7 @@ export default {
|
|||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
pct() {
|
pct() {
|
||||||
var pct = (this.val / this.max) * 100;
|
let pct = (this.val / this.max) * 100;
|
||||||
pct = pct.toFixed(2);
|
pct = pct.toFixed(2);
|
||||||
return Math.min(pct, this.max);
|
return Math.min(pct, this.max);
|
||||||
},
|
},
|
||||||
@ -160,7 +160,7 @@ export default {
|
|||||||
return isNumber(this.fontSize) ? this.fontSize : 13;
|
return isNumber(this.fontSize) ? this.fontSize : 13;
|
||||||
},
|
},
|
||||||
progress_style() {
|
progress_style() {
|
||||||
var style = {
|
const style = {
|
||||||
background: this.bgColor,
|
background: this.bgColor,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -177,7 +177,7 @@ export default {
|
|||||||
return style;
|
return style;
|
||||||
},
|
},
|
||||||
bar_style() {
|
bar_style() {
|
||||||
var style = {
|
const style = {
|
||||||
background: this.barColor,
|
background: this.barColor,
|
||||||
width: this.pct + "%",
|
width: this.pct + "%",
|
||||||
height: this.size_px + "px",
|
height: this.size_px + "px",
|
||||||
@ -198,7 +198,7 @@ export default {
|
|||||||
return style;
|
return style;
|
||||||
},
|
},
|
||||||
text_style() {
|
text_style() {
|
||||||
var style = {
|
const style = {
|
||||||
color: this.textFgColor,
|
color: this.textFgColor,
|
||||||
"font-size": this.text_font_size + "px",
|
"font-size": this.text_font_size + "px",
|
||||||
"text-align": this.textAlign,
|
"text-align": this.textAlign,
|
||||||
|
@ -50,7 +50,7 @@ import { useFileStore } from "@/stores/file";
|
|||||||
import { useLayoutStore } from "@/stores/layout";
|
import { useLayoutStore } from "@/stores/layout";
|
||||||
|
|
||||||
import { commands } from "@/api";
|
import { commands } from "@/api";
|
||||||
import { throttle } from "lodash";
|
import { throttle } from "lodash-es";
|
||||||
import { theme } from "@/utils/constants";
|
import { theme } from "@/utils/constants";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -163,7 +163,7 @@ export default {
|
|||||||
this.canInput = false;
|
this.canInput = false;
|
||||||
event.target.innerHTML = "";
|
event.target.innerHTML = "";
|
||||||
|
|
||||||
let results = {
|
const results = {
|
||||||
text: `${cmd}\n\n`,
|
text: `${cmd}\n\n`,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -180,7 +180,7 @@ export default {
|
|||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
results.text = results.text
|
results.text = results.text
|
||||||
// eslint-disable-next-line no-control-regex
|
|
||||||
.replace(/\u001b\[[0-9;]+m/g, "") // Filter ANSI color for now
|
.replace(/\u001b\[[0-9;]+m/g, "") // Filter ANSI color for now
|
||||||
.trimEnd();
|
.trimEnd();
|
||||||
this.canInput = true;
|
this.canInput = true;
|
||||||
|
@ -101,7 +101,7 @@
|
|||||||
href="https://github.com/filebrowser/filebrowser"
|
href="https://github.com/filebrowser/filebrowser"
|
||||||
>File Browser</a
|
>File Browser</a
|
||||||
>
|
>
|
||||||
<span> {{ version }}</span>
|
<span> {{ " " }} {{ version }}</span>
|
||||||
</span>
|
</span>
|
||||||
<span>
|
<span>
|
||||||
<a @click="help">{{ $t("sidebar.help") }}</a>
|
<a @click="help">{{ $t("sidebar.help") }}</a>
|
||||||
@ -158,7 +158,7 @@ export default {
|
|||||||
methods: {
|
methods: {
|
||||||
...mapActions(useLayoutStore, ["closeHovers", "showHover"]),
|
...mapActions(useLayoutStore, ["closeHovers", "showHover"]),
|
||||||
async fetchUsage() {
|
async fetchUsage() {
|
||||||
let path = this.$route.path.endsWith("/")
|
const path = this.$route.path.endsWith("/")
|
||||||
? this.$route.path
|
? this.$route.path
|
||||||
: this.$route.path + "/";
|
: this.$route.path + "/";
|
||||||
let usageStats = USAGE_DEFAULT;
|
let usageStats = USAGE_DEFAULT;
|
||||||
@ -166,7 +166,7 @@ export default {
|
|||||||
return Object.assign(this.usage, usageStats);
|
return Object.assign(this.usage, usageStats);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
let usage = await api.usage(path);
|
const usage = await api.usage(path);
|
||||||
usageStats = {
|
usageStats = {
|
||||||
used: prettyBytes(usage.used, { binary: true }),
|
used: prettyBytes(usage.used, { binary: true }),
|
||||||
total: prettyBytes(usage.total, { binary: true }),
|
total: prettyBytes(usage.total, { binary: true }),
|
||||||
@ -191,8 +191,13 @@ export default {
|
|||||||
logout: auth.logout,
|
logout: auth.logout,
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
isFiles(newValue) {
|
$route: {
|
||||||
newValue && this.fetchUsage();
|
handler(to) {
|
||||||
|
if (to.path.includes("/files")) {
|
||||||
|
this.fetchUsage();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
immediate: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -14,15 +14,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import throttle from "lodash/throttle";
|
import { throttle } from "lodash-es";
|
||||||
import UTIF from "utif";
|
import UTIF from "utif";
|
||||||
import { onBeforeUnmount, onMounted, ref, watch } from "vue";
|
import { onBeforeUnmount, onMounted, ref, watch } from "vue";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
src: string;
|
src: string;
|
||||||
moveDisabledTime: number;
|
moveDisabledTime?: number;
|
||||||
classList: any[];
|
classList?: any[];
|
||||||
zoomStep: number;
|
zoomStep?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<IProps>(), {
|
const props = withDefaults(defineProps<IProps>(), {
|
||||||
@ -102,10 +102,11 @@ const decodeUTIF = () => {
|
|||||||
if (document?.location?.pathname === undefined) {
|
if (document?.location?.pathname === undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let suff = document.location.pathname.split(".")?.pop()?.toLowerCase() ?? "";
|
const suff =
|
||||||
|
document.location.pathname.split(".")?.pop()?.toLowerCase() ?? "";
|
||||||
|
|
||||||
if (sufs.indexOf(suff) == -1) return false;
|
if (sufs.indexOf(suff) == -1) return false;
|
||||||
let xhr = new XMLHttpRequest();
|
const xhr = new XMLHttpRequest();
|
||||||
UTIF._xhrs.push(xhr);
|
UTIF._xhrs.push(xhr);
|
||||||
UTIF._imgs.push(imgex.value);
|
UTIF._imgs.push(imgex.value);
|
||||||
xhr.open("GET", props.src);
|
xhr.open("GET", props.src);
|
||||||
@ -230,7 +231,7 @@ const touchMove = (event: TouchEvent) => {
|
|||||||
if (imgex.value === null) {
|
if (imgex.value === null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let step = imgex.value.width / 5;
|
const step = imgex.value.width / 5;
|
||||||
if (event.targetTouches.length === 2) {
|
if (event.targetTouches.length === 2) {
|
||||||
moveDisabled.value = true;
|
moveDisabled.value = true;
|
||||||
if (disabledTimer.value) clearTimeout(disabledTimer.value);
|
if (disabledTimer.value) clearTimeout(disabledTimer.value);
|
||||||
@ -239,9 +240,9 @@ const touchMove = (event: TouchEvent) => {
|
|||||||
props.moveDisabledTime
|
props.moveDisabledTime
|
||||||
);
|
);
|
||||||
|
|
||||||
let p1 = event.targetTouches[0];
|
const p1 = event.targetTouches[0];
|
||||||
let p2 = event.targetTouches[1];
|
const p2 = event.targetTouches[1];
|
||||||
let touchDistance = Math.sqrt(
|
const touchDistance = Math.sqrt(
|
||||||
Math.pow(p2.pageX - p1.pageX, 2) + Math.pow(p2.pageY - p1.pageY, 2)
|
Math.pow(p2.pageX - p1.pageX, 2) + Math.pow(p2.pageY - p1.pageY, 2)
|
||||||
);
|
);
|
||||||
if (!lastTouchDistance.value) {
|
if (!lastTouchDistance.value) {
|
||||||
@ -253,8 +254,8 @@ const touchMove = (event: TouchEvent) => {
|
|||||||
setZoom();
|
setZoom();
|
||||||
} else if (event.targetTouches.length === 1) {
|
} else if (event.targetTouches.length === 1) {
|
||||||
if (moveDisabled.value) return;
|
if (moveDisabled.value) return;
|
||||||
let x = event.targetTouches[0].pageX - (lastX.value ?? 0);
|
const x = event.targetTouches[0].pageX - (lastX.value ?? 0);
|
||||||
let y = event.targetTouches[0].pageY - (lastY.value ?? 0);
|
const y = event.targetTouches[0].pageY - (lastY.value ?? 0);
|
||||||
if (Math.abs(x) >= step && Math.abs(y) >= step) return;
|
if (Math.abs(x) >= step && Math.abs(y) >= step) return;
|
||||||
lastX.value = event.targetTouches[0].pageX;
|
lastX.value = event.targetTouches[0].pageX;
|
||||||
lastY.value = event.targetTouches[0].pageY;
|
lastY.value = event.targetTouches[0].pageY;
|
||||||
@ -268,8 +269,8 @@ const doMove = (x: number, y: number) => {
|
|||||||
}
|
}
|
||||||
const style = imgex.value.style;
|
const style = imgex.value.style;
|
||||||
|
|
||||||
let posX = pxStringToNumber(style.left) + x;
|
const posX = pxStringToNumber(style.left) + x;
|
||||||
let posY = pxStringToNumber(style.top) + y;
|
const posY = pxStringToNumber(style.top) + y;
|
||||||
|
|
||||||
style.left = posX + "px";
|
style.left = posX + "px";
|
||||||
style.top = posY + "px";
|
style.top = posY + "px";
|
||||||
|
@ -82,7 +82,7 @@ const isDraggable = computed(
|
|||||||
const canDrop = computed(() => {
|
const canDrop = computed(() => {
|
||||||
if (!props.isDir || props.readOnly) return false;
|
if (!props.isDir || props.readOnly) return false;
|
||||||
|
|
||||||
for (let i of fileStore.selected) {
|
for (const i of fileStore.selected) {
|
||||||
if (fileStore.req?.items[i].url === props.url) {
|
if (fileStore.req?.items[i].url === props.url) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -156,9 +156,9 @@ const drop = async (event: Event) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let items: any[] = [];
|
const items: any[] = [];
|
||||||
|
|
||||||
for (let i of fileStore.selected) {
|
for (const i of fileStore.selected) {
|
||||||
if (fileStore.req) {
|
if (fileStore.req) {
|
||||||
items.push({
|
items.push({
|
||||||
from: fileStore.req?.items[i].url,
|
from: fileStore.req?.items[i].url,
|
||||||
@ -172,10 +172,10 @@ const drop = async (event: Event) => {
|
|||||||
if (el === null) {
|
if (el === null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let path = el.__vue__.url;
|
const path = el.__vue__.url;
|
||||||
let baseItems = (await api.fetch(path)).items;
|
const baseItems = (await api.fetch(path)).items;
|
||||||
|
|
||||||
let action = (overwrite: boolean, rename: boolean) => {
|
const action = (overwrite: boolean, rename: boolean) => {
|
||||||
api
|
api
|
||||||
.move(items, overwrite, rename)
|
.move(items, overwrite, rename)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
@ -184,7 +184,7 @@ const drop = async (event: Event) => {
|
|||||||
.catch($showError);
|
.catch($showError);
|
||||||
};
|
};
|
||||||
|
|
||||||
let conflict = upload.checkConflict(items, baseItems);
|
const conflict = upload.checkConflict(items, baseItems);
|
||||||
|
|
||||||
let overwrite = false;
|
let overwrite = false;
|
||||||
let rename = false;
|
let rename = false;
|
||||||
|
@ -73,11 +73,16 @@ const initVideoPlayer = async () => {
|
|||||||
const langOpt = { language: "videoPlayerLocal" };
|
const langOpt = { language: "videoPlayerLocal" };
|
||||||
// support for playback at different speeds.
|
// support for playback at different speeds.
|
||||||
const playbackRatesOpt = { playbackRates: [0.5, 1, 1.5, 2, 2.5, 3] };
|
const playbackRatesOpt = { playbackRates: [0.5, 1, 1.5, 2, 2.5, 3] };
|
||||||
let options = getOptions(props.options, langOpt, srcOpt, playbackRatesOpt);
|
const options = getOptions(
|
||||||
|
props.options,
|
||||||
|
langOpt,
|
||||||
|
srcOpt,
|
||||||
|
playbackRatesOpt
|
||||||
|
);
|
||||||
player.value = videojs(videoPlayer.value!, options, () => {});
|
player.value = videojs(videoPlayer.value!, options, () => {});
|
||||||
|
|
||||||
// TODO: need to test on mobile
|
// TODO: need to test on mobile
|
||||||
// @ts-ignore
|
// @ts-expect-error no ts definition for mobileUi
|
||||||
player.value!.mobileUi();
|
player.value!.mobileUi();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error initializing video player:", error);
|
console.error("Error initializing video player:", error);
|
||||||
@ -120,7 +125,7 @@ const subLabel = (subUrl: string) => {
|
|||||||
let url: URL;
|
let url: URL;
|
||||||
try {
|
try {
|
||||||
url = new URL(subUrl);
|
url = new URL(subUrl);
|
||||||
} catch (_) {
|
} catch {
|
||||||
// treat it as a relative url
|
// treat it as a relative url
|
||||||
// we only need this for filename
|
// we only need this for filename
|
||||||
url = new URL(subUrl, window.location.origin);
|
url = new URL(subUrl, window.location.origin);
|
||||||
|
@ -82,10 +82,10 @@ export default {
|
|||||||
...mapActions(useLayoutStore, ["showHover", "closeHovers"]),
|
...mapActions(useLayoutStore, ["showHover", "closeHovers"]),
|
||||||
copy: async function (event) {
|
copy: async function (event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
let items = [];
|
const items = [];
|
||||||
|
|
||||||
// Create a new promise for each file.
|
// Create a new promise for each file.
|
||||||
for (let item of this.selected) {
|
for (const 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),
|
||||||
@ -93,7 +93,7 @@ export default {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let action = async (overwrite, rename) => {
|
const action = async (overwrite, rename) => {
|
||||||
buttons.loading("copy");
|
buttons.loading("copy");
|
||||||
|
|
||||||
await api
|
await api
|
||||||
@ -122,8 +122,8 @@ export default {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let dstItems = (await api.fetch(this.dest)).items;
|
const dstItems = (await api.fetch(this.dest)).items;
|
||||||
let conflict = upload.checkConflict(items, dstItems);
|
const conflict = upload.checkConflict(items, dstItems);
|
||||||
|
|
||||||
let overwrite = false;
|
let overwrite = false;
|
||||||
let rename = false;
|
let rename = false;
|
||||||
|
@ -74,8 +74,8 @@ export default {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let promises = [];
|
const promises = [];
|
||||||
for (let index of this.selected) {
|
for (const index of this.selected) {
|
||||||
promises.push(api.remove(this.req.items[index].url));
|
promises.push(api.remove(this.req.items[index].url));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ export default {
|
|||||||
submit: async function () {
|
submit: async function () {
|
||||||
this.updateRequest(null);
|
this.updateRequest(null);
|
||||||
|
|
||||||
let uri = url.removeLastDir(this.$route.path) + "/";
|
const uri = url.removeLastDir(this.$route.path) + "/";
|
||||||
this.$router.push({ path: uri });
|
this.$router.push({ path: uri });
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -80,7 +80,7 @@ export default {
|
|||||||
|
|
||||||
// Otherwise we add every directory to the
|
// Otherwise we add every directory to the
|
||||||
// move options.
|
// move options.
|
||||||
for (let item of req.items) {
|
for (const item of req.items) {
|
||||||
if (!item.isDir) continue;
|
if (!item.isDir) continue;
|
||||||
|
|
||||||
this.items.push({
|
this.items.push({
|
||||||
@ -93,12 +93,12 @@ export default {
|
|||||||
// Retrieves the URL of the directory the user
|
// Retrieves the URL of the directory the user
|
||||||
// just clicked in and fill the options with its
|
// just clicked in and fill the options with its
|
||||||
// content.
|
// content.
|
||||||
let uri = event.currentTarget.dataset.url;
|
const uri = event.currentTarget.dataset.url;
|
||||||
|
|
||||||
files.fetch(uri).then(this.fillOptions).catch(this.$showError);
|
files.fetch(uri).then(this.fillOptions).catch(this.$showError);
|
||||||
},
|
},
|
||||||
touchstart(event) {
|
touchstart(event) {
|
||||||
let url = event.currentTarget.dataset.url;
|
const url = event.currentTarget.dataset.url;
|
||||||
|
|
||||||
// In 300 milliseconds, we shall reset the count.
|
// In 300 milliseconds, we shall reset the count.
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
@ -124,7 +124,7 @@ export default {
|
|||||||
|
|
||||||
let sum = 0;
|
let sum = 0;
|
||||||
|
|
||||||
for (let selected of this.selected) {
|
for (const selected of this.selected) {
|
||||||
sum += this.req.items[selected].size;
|
sum += this.req.items[selected].size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,9 +81,9 @@ export default {
|
|||||||
...mapActions(useLayoutStore, ["showHover", "closeHovers"]),
|
...mapActions(useLayoutStore, ["showHover", "closeHovers"]),
|
||||||
move: async function (event) {
|
move: async function (event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
let items = [];
|
const items = [];
|
||||||
|
|
||||||
for (let item of this.selected) {
|
for (const 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),
|
||||||
@ -91,7 +91,7 @@ export default {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let action = async (overwrite, rename) => {
|
const action = async (overwrite, rename) => {
|
||||||
buttons.loading("move");
|
buttons.loading("move");
|
||||||
|
|
||||||
await api
|
await api
|
||||||
@ -106,8 +106,8 @@ export default {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
let dstItems = (await api.fetch(this.dest)).items;
|
const dstItems = (await api.fetch(this.dest)).items;
|
||||||
let conflict = upload.checkConflict(items, dstItems);
|
const conflict = upload.checkConflict(items, dstItems);
|
||||||
|
|
||||||
let overwrite = false;
|
let overwrite = false;
|
||||||
let rename = false;
|
let rename = false;
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, watch } from "vue";
|
import { watch } from "vue";
|
||||||
import { ModalsContainer, useModal } from "vue-final-modal";
|
import { ModalsContainer, useModal } from "vue-final-modal";
|
||||||
import { storeToRefs } from "pinia";
|
import { storeToRefs } from "pinia";
|
||||||
import { useLayoutStore } from "@/stores/layout";
|
import { useLayoutStore } from "@/stores/layout";
|
||||||
@ -30,8 +30,6 @@ const layoutStore = useLayoutStore();
|
|||||||
|
|
||||||
const { currentPromptName } = storeToRefs(layoutStore);
|
const { currentPromptName } = storeToRefs(layoutStore);
|
||||||
|
|
||||||
const closeModal = ref<() => Promise<string>>();
|
|
||||||
|
|
||||||
const components = new Map<string, any>([
|
const components = new Map<string, any>([
|
||||||
["info", Info],
|
["info", Info],
|
||||||
["help", Help],
|
["help", Help],
|
||||||
@ -52,11 +50,6 @@ const components = new Map<string, any>([
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
watch(currentPromptName, (newValue) => {
|
watch(currentPromptName, (newValue) => {
|
||||||
if (closeModal.value) {
|
|
||||||
closeModal.value();
|
|
||||||
closeModal.value = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
const modal = components.get(newValue!);
|
const modal = components.get(newValue!);
|
||||||
if (!modal) return;
|
if (!modal) return;
|
||||||
|
|
||||||
@ -67,7 +60,7 @@ watch(currentPromptName, (newValue) => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
closeModal.value = close;
|
layoutStore.setCloseOnPrompt(close, newValue!);
|
||||||
open();
|
open();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -196,13 +196,23 @@ export default {
|
|||||||
methods: {
|
methods: {
|
||||||
...mapActions(useLayoutStore, ["closeHovers"]),
|
...mapActions(useLayoutStore, ["closeHovers"]),
|
||||||
copyToClipboard: function (text) {
|
copyToClipboard: function (text) {
|
||||||
copy(text).then(
|
copy({ text }).then(
|
||||||
() => {
|
() => {
|
||||||
// clipboard successfully set
|
// clipboard successfully set
|
||||||
this.$showSuccess(this.$t("success.linkCopied"));
|
this.$showSuccess(this.$t("success.linkCopied"));
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
// clipboard write failed
|
// clipboard write failed
|
||||||
|
copy({ text }, { permission: true }).then(
|
||||||
|
() => {
|
||||||
|
// clipboard successfully set
|
||||||
|
this.$showSuccess(this.$t("success.linkCopied"));
|
||||||
|
},
|
||||||
|
(e) => {
|
||||||
|
// clipboard write failed
|
||||||
|
this.$showError(e);
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -48,12 +48,10 @@ const layoutStore = useLayoutStore();
|
|||||||
|
|
||||||
// TODO: this is a copy of the same function in FileListing.vue
|
// TODO: this is a copy of the same function in FileListing.vue
|
||||||
const uploadInput = (event: Event) => {
|
const uploadInput = (event: Event) => {
|
||||||
layoutStore.closeHovers();
|
const files = (event.currentTarget as HTMLInputElement)?.files;
|
||||||
|
|
||||||
let files = (event.currentTarget as HTMLInputElement)?.files;
|
|
||||||
if (files === null) return;
|
if (files === null) return;
|
||||||
|
|
||||||
let folder_upload = !!files[0].webkitRelativePath;
|
const folder_upload = !!files[0].webkitRelativePath;
|
||||||
|
|
||||||
const uploadFiles: UploadList = [];
|
const uploadFiles: UploadList = [];
|
||||||
for (let i = 0; i < files.length; i++) {
|
for (let i = 0; i < files.length; i++) {
|
||||||
@ -68,8 +66,8 @@ const uploadInput = (event: Event) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let path = route.path.endsWith("/") ? route.path : route.path + "/";
|
const path = route.path.endsWith("/") ? route.path : route.path + "/";
|
||||||
let conflict = upload.checkConflict(uploadFiles, fileStore.req!.items);
|
const conflict = upload.checkConflict(uploadFiles, fileStore.req!.items);
|
||||||
|
|
||||||
if (conflict) {
|
if (conflict) {
|
||||||
layoutStore.showHover({
|
layoutStore.showHover({
|
||||||
|
@ -13,7 +13,7 @@ export default {
|
|||||||
name: "languages",
|
name: "languages",
|
||||||
props: ["locale"],
|
props: ["locale"],
|
||||||
data() {
|
data() {
|
||||||
let dataObj = {};
|
const dataObj = {};
|
||||||
const locales = {
|
const locales = {
|
||||||
he: "עברית",
|
he: "עברית",
|
||||||
hu: "Magyar",
|
hu: "Magyar",
|
||||||
|
@ -39,7 +39,7 @@ export default {
|
|||||||
methods: {
|
methods: {
|
||||||
remove(event, index) {
|
remove(event, index) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
let rules = [...this.rules];
|
const rules = [...this.rules];
|
||||||
rules.splice(index, 1);
|
rules.splice(index, 1);
|
||||||
this.$emit("update:rules", [...rules]);
|
this.$emit("update:rules", [...rules]);
|
||||||
},
|
},
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { SelectHTMLAttributes } from "vue";
|
import type { SelectHTMLAttributes } from "vue";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
@ -17,7 +17,6 @@ defineProps<{
|
|||||||
}>();
|
}>();
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
(e: "update:theme", val: string | null): void;
|
(e: "update:theme", val: string | null): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
@ -116,7 +116,7 @@ watch(createUserDirData, () => {
|
|||||||
if (props.user?.scope) {
|
if (props.user?.scope) {
|
||||||
props.user.scope = createUserDirData.value
|
props.user.scope = createUserDirData.value
|
||||||
? ""
|
? ""
|
||||||
: originalUserScope.value ?? "";
|
: (originalUserScope.value ?? "");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -63,8 +63,8 @@
|
|||||||
local("Roboto"),
|
local("Roboto"),
|
||||||
local("Roboto-Regular"),
|
local("Roboto-Regular"),
|
||||||
url(../assets/fonts/roboto/normal-latin-ext.woff2) format("woff2");
|
url(../assets/fonts/roboto/normal-latin-ext.woff2) format("woff2");
|
||||||
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F,
|
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF,
|
||||||
U+A720-A7FF;
|
U+2C60-2C7F, U+A720-A7FF;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
@ -142,8 +142,8 @@
|
|||||||
local("Roboto Medium"),
|
local("Roboto Medium"),
|
||||||
local("Roboto-Medium"),
|
local("Roboto-Medium"),
|
||||||
url(../assets/fonts/roboto/medium-latin-ext.woff2) format("woff2");
|
url(../assets/fonts/roboto/medium-latin-ext.woff2) format("woff2");
|
||||||
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F,
|
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF,
|
||||||
U+A720-A7FF;
|
U+2C60-2C7F, U+A720-A7FF;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
@ -221,8 +221,8 @@
|
|||||||
local("Roboto Bold"),
|
local("Roboto Bold"),
|
||||||
local("Roboto-Bold"),
|
local("Roboto-Bold"),
|
||||||
url(../assets/fonts/roboto/bold-latin-ext.woff2) format("woff2");
|
url(../assets/fonts/roboto/bold-latin-ext.woff2) format("woff2");
|
||||||
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F,
|
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF,
|
||||||
U+A720-A7FF;
|
U+2C60-2C7F, U+A720-A7FF;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
|
@ -195,6 +195,10 @@ html[dir="rtl"] #listing {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#listing.list .item p.name:not(#listing.list .item.header .name) {
|
||||||
|
margin-right: -3em;
|
||||||
|
}
|
||||||
|
|
||||||
#listing.list .item .name {
|
#listing.list .item .name {
|
||||||
width: 50%;
|
width: 50%;
|
||||||
}
|
}
|
||||||
@ -227,10 +231,6 @@ html[dir="rtl"] #listing {
|
|||||||
width: 0;
|
width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#listing.list .item.header .name {
|
|
||||||
margin-right: 3em;
|
|
||||||
}
|
|
||||||
|
|
||||||
#listing.list .header a {
|
#listing.list .header a {
|
||||||
color: inherit;
|
color: inherit;
|
||||||
}
|
}
|
||||||
@ -246,10 +246,6 @@ html[dir="rtl"] #listing {
|
|||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
#listing.list .item.header .name {
|
|
||||||
margin-right: 3em;
|
|
||||||
}
|
|
||||||
|
|
||||||
#listing.list .header span {
|
#listing.list .header span {
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@
|
|||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"forbidden": "Sie haben keine Berechtigung dies abzurufen.",
|
"forbidden": "Sie haben keine Berechtigung dies abzurufen.",
|
||||||
"internal": "Etwas ist schief gelaufen.",
|
"internal": "Etwas ist schiefgelaufen.",
|
||||||
"notFound": "Dieser Ort kann nicht angezeigt werden.",
|
"notFound": "Dieser Ort kann nicht angezeigt werden.",
|
||||||
"connection": "Der Server ist nicht erreichbar."
|
"connection": "Der Server ist nicht erreichbar."
|
||||||
},
|
},
|
||||||
@ -73,7 +73,7 @@
|
|||||||
"ctrl": {
|
"ctrl": {
|
||||||
"click": "Markiere mehrere Dateien oder Ordner",
|
"click": "Markiere mehrere Dateien oder Ordner",
|
||||||
"f": "Öffnet eine neue Suche",
|
"f": "Öffnet eine neue Suche",
|
||||||
"s": "Speichert eine Datei oder einen Ordner am akutellen Ort"
|
"s": "Speichert eine Datei oder einen Ordner am aktuellen Ort"
|
||||||
},
|
},
|
||||||
"del": "Löscht die ausgewählten Elemente",
|
"del": "Löscht die ausgewählten Elemente",
|
||||||
"doubleClick": "Öffnet eine Datei oder einen Ordner",
|
"doubleClick": "Öffnet eine Datei oder einen Ordner",
|
||||||
@ -106,7 +106,7 @@
|
|||||||
"displayName": "Anzeigename:",
|
"displayName": "Anzeigename:",
|
||||||
"download": "Lade Dateien",
|
"download": "Lade Dateien",
|
||||||
"downloadMessage": "Wählen Sie ein Format zum Herunterladen aus.",
|
"downloadMessage": "Wählen Sie ein Format zum Herunterladen aus.",
|
||||||
"error": "Etwas ist schief gelaufen",
|
"error": "Etwas ist schiefgelaufen",
|
||||||
"fileInfo": "Dateiinformation",
|
"fileInfo": "Dateiinformation",
|
||||||
"filesSelected": "{count} Dateien ausgewählt.",
|
"filesSelected": "{count} Dateien ausgewählt.",
|
||||||
"lastModified": "Zuletzt geändert",
|
"lastModified": "Zuletzt geändert",
|
||||||
@ -150,13 +150,13 @@
|
|||||||
"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",
|
"allowSignup": "Erlaube Benutzern sich zu registrieren",
|
||||||
"avoidChanges": "(leer lassen um Änderungen zu vermeiden)",
|
"avoidChanges": "(leer lassen, um Änderungen zu vermeiden)",
|
||||||
"branding": "Design",
|
"branding": "Design",
|
||||||
"brandingDirectoryPath": "Designverzeichnispfad",
|
"brandingDirectoryPath": "Designverzeichnispfad",
|
||||||
"brandingHelp": "Sie können das Erscheinungsbild Ihres File Browser anpassen, in dem Sie den Namen ändern, das Logo austauchsen oder eigene Stile definieren und sogar externe Links zu GitHub deaktivieren.\nUm mehr Informationen zum Anpassen des Designs zu bekommen, gehen Sie bitte zu {0}.",
|
"brandingHelp": "Sie können das Erscheinungsbild Ihres File Browser anpassen, in dem Sie den Namen ändern, das Logo austauschen oder eigene Stile definieren und sogar externe Links zu GitHub deaktivieren.\nUm mehr Informationen zum Anpassen des Designs zu bekommen, gehen Sie bitte zu {0}.",
|
||||||
"changePassword": "Passwort ändern",
|
"changePassword": "Passwort ändern",
|
||||||
"commandRunner": "Befehlseingabe",
|
"commandRunner": "Befehlseingabe",
|
||||||
"commandRunnerHelp": "Hier könne Sie Befehle eintragen, welche bei den benannten Aktionen ausgeführt werden. Sie müssen pro Zeile jeweils einen Befehl eingeben. Die Umgebungsvariable {0} und {1} sind verfügbar, wobei {0} relative zu {1} ist. Für mehr Informationen über diese Funktion und die verfügbaren Umgebungsvariablen, lesen Sie bitte die {2}.",
|
"commandRunnerHelp": "Hier könne Sie Befehle eintragen, welche bei den benannten Aktionen ausgeführt werden. Sie müssen pro Zeile jeweils einen Befehl eingeben. Die Umgebungsvariable {0} und {1} sind verfügbar, wobei {0} relative zu {1} ist. Für mehr Informationen über diese Funktion und die verfügbaren Umgebungsvariablen lesen Sie bitte die {2}.",
|
||||||
"commandsUpdated": "Befehle aktualisiert!",
|
"commandsUpdated": "Befehle aktualisiert!",
|
||||||
"createUserDir": "Automatisches Erstellen des Home-Verzeichnisses beim Anlegen neuer Benutzer",
|
"createUserDir": "Automatisches Erstellen des Home-Verzeichnisses beim Anlegen neuer Benutzer",
|
||||||
"tusUploads": "Gestückelter Upload",
|
"tusUploads": "Gestückelter Upload",
|
||||||
@ -170,7 +170,7 @@
|
|||||||
"documentation": "Dokumentation",
|
"documentation": "Dokumentation",
|
||||||
"examples": "Beispiele",
|
"examples": "Beispiele",
|
||||||
"executeOnShell": "In Shell ausführen",
|
"executeOnShell": "In Shell ausführen",
|
||||||
"executeOnShellDescription": "Es ist voreingestellt das der File Brower Befehle ausführt in dem er die Befehlsdateien direkt aufruft. Wenn Sie wollen, dass sie über einer Kommandozeile (wie Bash oder PowerShell) laufen, könne Sie diese hier definieren mit allen bennötigten Argumenten und Optionen. Wenn gesetzt, wird das Kommando das ausgeführt werden soll als Parameter angehängt. Das gilt für Benuzerkommandos sowie auch für Ereignisse.",
|
"executeOnShellDescription": "Es ist voreingestellt, dass der File Brower Befehle ausführt, indem er die Befehlsdateien direkt aufruft. Wenn Sie wollen, dass sie über einer Kommandozeile (wie Bash oder PowerShell) laufen, könne Sie diese hier definieren mit allen benötigten Argumenten und Optionen. Wenn gesetzt, wird das Kommando das ausgeführt werden soll als Parameter angehängt. Das gilt für Benutzerkommandos sowie auch für Ereignisse.",
|
||||||
"globalRules": "Das ist ein globales Set von Regeln die erlauben oder nicht erlauben. Die sind für alle Benutzer zutreffend. Es können spezielle Regeln in den Einstellungen der Benutzer definiert werden, die diese überschreiben.",
|
"globalRules": "Das ist ein globales Set von Regeln die erlauben oder nicht erlauben. Die sind für alle Benutzer zutreffend. Es können spezielle Regeln in den Einstellungen der Benutzer definiert werden, die diese überschreiben.",
|
||||||
"globalSettings": "Globale Einstellungen",
|
"globalSettings": "Globale Einstellungen",
|
||||||
"hideDotfiles": "Versteckte Dateien ausblenden",
|
"hideDotfiles": "Versteckte Dateien ausblenden",
|
||||||
@ -195,7 +195,7 @@
|
|||||||
"share": "Datei teilen"
|
"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 Berechtigungen 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",
|
||||||
"ruleExample1": "Verhindert den Zugang zu versteckten Dateien (dot-Files, wie .git, .gitignore) in allen Ordnern\n",
|
"ruleExample1": "Verhindert den Zugang zu versteckten Dateien (dot-Files, wie .git, .gitignore) in allen Ordnern\n",
|
||||||
"ruleExample2": "blockiert den Zugang auf Dateien mit dem Namen Caddyfile in der Wurzel/Basis des Scopes.",
|
"ruleExample2": "blockiert den Zugang auf Dateien mit dem Namen Caddyfile in der Wurzel/Basis des Scopes.",
|
||||||
|
@ -173,7 +173,7 @@
|
|||||||
"executeOnShellDescription": "Por defecto, FileBrowser ejecuta los comandos llamando directamente a sus binarios. Si quieres ejecutarlos en un shell en su lugar (como Bash o PowerShell), puedes definirlo aquí con los argumentos y banderas (flags) necesarios. Si se define, el comando que se ejecuta se añadirá como argumento. Esto se aplica tanto a los comandos de usuario como a los ganchos de eventos.",
|
"executeOnShellDescription": "Por defecto, FileBrowser ejecuta los comandos llamando directamente a sus binarios. Si quieres ejecutarlos en un shell en su lugar (como Bash o PowerShell), puedes definirlo aquí con los argumentos y banderas (flags) necesarios. Si se define, el comando que se ejecuta se añadirá como argumento. Esto se aplica tanto a los comandos de usuario como a los ganchos de eventos.",
|
||||||
"globalRules": "Se trata de un conjunto global de reglas de permiso y rechazo. Se aplican a todos los usuarios. Puedes definir reglas específicas en la configuración de cada usuario para anular estas.",
|
"globalRules": "Se trata de un conjunto global de reglas de permiso y rechazo. Se aplican a todos los usuarios. Puedes definir reglas específicas en la configuración de cada usuario para anular estas.",
|
||||||
"globalSettings": "Ajustes globales",
|
"globalSettings": "Ajustes globales",
|
||||||
"hideDotfiles": "",
|
"hideDotfiles": "Ocultar archivos empezados por punto",
|
||||||
"insertPath": "Introduce la ruta",
|
"insertPath": "Introduce la ruta",
|
||||||
"insertRegex": "Introducir expresión regular",
|
"insertRegex": "Introducir expresión regular",
|
||||||
"instanceName": "Nombre de la instancia",
|
"instanceName": "Nombre de la instancia",
|
||||||
|
@ -142,7 +142,7 @@ export const i18n = createI18n({
|
|||||||
|
|
||||||
export const isRtl = (locale?: string) => {
|
export const isRtl = (locale?: string) => {
|
||||||
// see below
|
// see below
|
||||||
// @ts-ignore
|
// @ts-expect-error incorrect type when legacy
|
||||||
return rtlLanguages.includes(locale || i18n.global.locale.value);
|
return rtlLanguages.includes(locale || i18n.global.locale.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -150,7 +150,7 @@ export function setLocale(locale: string) {
|
|||||||
dayjs.locale(locale);
|
dayjs.locale(locale);
|
||||||
// according to doc u only need .value if legacy: false but they lied
|
// according to doc u only need .value if legacy: false but they lied
|
||||||
// https://vue-i18n.intlify.dev/guide/essentials/scope.html#local-scope-1
|
// https://vue-i18n.intlify.dev/guide/essentials/scope.html#local-scope-1
|
||||||
//@ts-ignore
|
// @ts-expect-error incorrect type when legacy
|
||||||
i18n.global.locale.value = locale;
|
i18n.global.locale.value = locale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
"create": "생성",
|
"create": "생성",
|
||||||
"delete": "삭제",
|
"delete": "삭제",
|
||||||
"download": "다운로드",
|
"download": "다운로드",
|
||||||
"hideDotfiles": "",
|
"hideDotfiles": "숨김파일(dotfile)을 표시 안함",
|
||||||
"info": "정보",
|
"info": "정보",
|
||||||
"more": "더보기",
|
"more": "더보기",
|
||||||
"move": "이동",
|
"move": "이동",
|
||||||
@ -38,7 +38,7 @@
|
|||||||
"download": {
|
"download": {
|
||||||
"downloadFile": "파일 다운로드",
|
"downloadFile": "파일 다운로드",
|
||||||
"downloadFolder": "폴더 다운로드",
|
"downloadFolder": "폴더 다운로드",
|
||||||
"downloadSelected": ""
|
"downloadSelected": "선택 항목 다운로드"
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"forbidden": "접근 권한이 없습니다.",
|
"forbidden": "접근 권한이 없습니다.",
|
||||||
@ -120,8 +120,8 @@
|
|||||||
"scheduleMessage": "이 글을 공개할 시간을 알려주세요.",
|
"scheduleMessage": "이 글을 공개할 시간을 알려주세요.",
|
||||||
"show": "보기",
|
"show": "보기",
|
||||||
"size": "크기",
|
"size": "크기",
|
||||||
"upload": "",
|
"upload": "업로드",
|
||||||
"uploadMessage": ""
|
"uploadMessage": "업로드 옵션을 선택하세요."
|
||||||
},
|
},
|
||||||
"search": {
|
"search": {
|
||||||
"images": "이미지",
|
"images": "이미지",
|
||||||
@ -160,7 +160,7 @@
|
|||||||
"executeOnShellDescription": "기본적으로 File Browser 는 바이너리를 명령어로 호출하여 실행합니다. 쉘을 통해 실행하기를 원한다면, Bash 또는 PowerShell 에 필요한 인수와 플래그를 설정하세요. 사용자 명령어와 이벤트 훅에 모두 적용됩니다.",
|
"executeOnShellDescription": "기본적으로 File Browser 는 바이너리를 명령어로 호출하여 실행합니다. 쉘을 통해 실행하기를 원한다면, Bash 또는 PowerShell 에 필요한 인수와 플래그를 설정하세요. 사용자 명령어와 이벤트 훅에 모두 적용됩니다.",
|
||||||
"globalRules": "규칙에 대한 전역설정으로 모든 사용자에게 적용됩니다. 지정된 규칙은 사용자 설정을 덮어쓰기 합니다.",
|
"globalRules": "규칙에 대한 전역설정으로 모든 사용자에게 적용됩니다. 지정된 규칙은 사용자 설정을 덮어쓰기 합니다.",
|
||||||
"globalSettings": "전역 설정",
|
"globalSettings": "전역 설정",
|
||||||
"hideDotfiles": "",
|
"hideDotfiles": "숨김파일(dotfile)을 표시하지 않습니다.",
|
||||||
"insertPath": "경로 입력",
|
"insertPath": "경로 입력",
|
||||||
"insertRegex": "정규식 입력",
|
"insertRegex": "정규식 입력",
|
||||||
"instanceName": "인스턴스 이름",
|
"instanceName": "인스턴스 이름",
|
||||||
@ -171,7 +171,7 @@
|
|||||||
"newUser": "새로운 사용자",
|
"newUser": "새로운 사용자",
|
||||||
"password": "비밀번호",
|
"password": "비밀번호",
|
||||||
"passwordUpdated": "비밀번호 수정 완료!",
|
"passwordUpdated": "비밀번호 수정 완료!",
|
||||||
"path": "",
|
"path": "경로",
|
||||||
"perm": {
|
"perm": {
|
||||||
"create": "파일이나 디렉토리 생성하기",
|
"create": "파일이나 디렉토리 생성하기",
|
||||||
"delete": "화일이나 디렉토리 삭제하기",
|
"delete": "화일이나 디렉토리 삭제하기",
|
||||||
@ -190,13 +190,13 @@
|
|||||||
"rulesHelp": "사용자별로 규칙을 허용/방지를 지정할 수 있습니다. 방지된 파일은 보이지 않고 사용자들은 접근할 수 없습니다. 사용자의 접근 허용 범위와 관련해 정규표현식(regex)과 경로를 지원합니다.\n",
|
"rulesHelp": "사용자별로 규칙을 허용/방지를 지정할 수 있습니다. 방지된 파일은 보이지 않고 사용자들은 접근할 수 없습니다. 사용자의 접근 허용 범위와 관련해 정규표현식(regex)과 경로를 지원합니다.\n",
|
||||||
"scope": "범위",
|
"scope": "범위",
|
||||||
"settingsUpdated": "설정 수정됨!",
|
"settingsUpdated": "설정 수정됨!",
|
||||||
"shareDuration": "",
|
"shareDuration": "공유 기간",
|
||||||
"shareManagement": "",
|
"shareManagement": "공유 내역 관리",
|
||||||
"singleClick": "",
|
"singleClick": "한번 클릭으로 파일과 폴더를 열도록 합니다.",
|
||||||
"themes": {
|
"themes": {
|
||||||
"dark": "",
|
"dark": "다크테마",
|
||||||
"light": "",
|
"light": "라이트테마",
|
||||||
"title": ""
|
"title": "테마"
|
||||||
},
|
},
|
||||||
"user": "사용자",
|
"user": "사용자",
|
||||||
"userCommands": "명령어",
|
"userCommands": "명령어",
|
||||||
|
@ -4,7 +4,7 @@ import VueNumberInput from "@chenfengyuan/vue-number-input";
|
|||||||
import VueLazyload from "vue-lazyload";
|
import VueLazyload from "vue-lazyload";
|
||||||
import { createVfm } from "vue-final-modal";
|
import { createVfm } from "vue-final-modal";
|
||||||
import Toast, { POSITION, useToast } from "vue-toastification";
|
import Toast, { POSITION, useToast } from "vue-toastification";
|
||||||
import {
|
import type {
|
||||||
ToastOptions,
|
ToastOptions,
|
||||||
PluginOptions,
|
PluginOptions,
|
||||||
} from "vue-toastification/dist/types/types";
|
} from "vue-toastification/dist/types/types";
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { RouteLocation, createRouter, createWebHistory } from "vue-router";
|
import type { RouteLocation } from "vue-router";
|
||||||
|
import { createRouter, createWebHistory } from "vue-router";
|
||||||
import Login from "@/views/Login.vue";
|
import Login from "@/views/Login.vue";
|
||||||
import Layout from "@/views/Layout.vue";
|
import Layout from "@/views/Layout.vue";
|
||||||
import Files from "@/views/Files.vue";
|
import Files from "@/views/Files.vue";
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { createPinia as _createPinia } from "pinia";
|
import { createPinia as _createPinia } from "pinia";
|
||||||
import { markRaw } from "vue";
|
import { markRaw } from "vue";
|
||||||
import { Router } from "vue-router";
|
import type { Router } from "vue-router";
|
||||||
|
|
||||||
export default function createPinia(router: Router) {
|
export default function createPinia(router: Router) {
|
||||||
const pinia = _createPinia();
|
const pinia = _createPinia();
|
||||||
|
@ -29,6 +29,12 @@ export const useLayoutStore = defineStore("layout", {
|
|||||||
toggleShell() {
|
toggleShell() {
|
||||||
this.showShell = !this.showShell;
|
this.showShell = !this.showShell;
|
||||||
},
|
},
|
||||||
|
setCloseOnPrompt(closeFunction: () => Promise<string>, onPrompt: string) {
|
||||||
|
const prompt = this.prompts.find((prompt) => prompt.prompt === onPrompt);
|
||||||
|
if (prompt) {
|
||||||
|
prompt.close = closeFunction;
|
||||||
|
}
|
||||||
|
},
|
||||||
showHover(value: PopupProps | string) {
|
showHover(value: PopupProps | string) {
|
||||||
if (typeof value !== "object") {
|
if (typeof value !== "object") {
|
||||||
this.prompts.push({
|
this.prompts.push({
|
||||||
@ -36,6 +42,7 @@ export const useLayoutStore = defineStore("layout", {
|
|||||||
confirm: null,
|
confirm: null,
|
||||||
action: undefined,
|
action: undefined,
|
||||||
props: null,
|
props: null,
|
||||||
|
close: null,
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -45,6 +52,7 @@ export const useLayoutStore = defineStore("layout", {
|
|||||||
confirm: value?.confirm,
|
confirm: value?.confirm,
|
||||||
action: value?.action,
|
action: value?.action,
|
||||||
props: value?.props,
|
props: value?.props,
|
||||||
|
close: value?.close,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
showError() {
|
showError() {
|
||||||
@ -53,6 +61,7 @@ export const useLayoutStore = defineStore("layout", {
|
|||||||
confirm: null,
|
confirm: null,
|
||||||
action: undefined,
|
action: undefined,
|
||||||
props: null,
|
props: null,
|
||||||
|
close: null,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
showSuccess() {
|
showSuccess() {
|
||||||
@ -61,10 +70,11 @@ export const useLayoutStore = defineStore("layout", {
|
|||||||
confirm: null,
|
confirm: null,
|
||||||
action: undefined,
|
action: undefined,
|
||||||
props: null,
|
props: null,
|
||||||
|
close: null,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
closeHovers() {
|
closeHovers() {
|
||||||
this.prompts.pop();
|
this.prompts.shift()?.close?.();
|
||||||
},
|
},
|
||||||
// easily reset state using `$reset`
|
// easily reset state using `$reset`
|
||||||
clearLayout() {
|
clearLayout() {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
import { useFileStore } from "./file";
|
import { useFileStore } from "./file";
|
||||||
import { files as api } from "@/api";
|
import { files as api } from "@/api";
|
||||||
import throttle from "lodash/throttle";
|
import { throttle } from "lodash-es";
|
||||||
import buttons from "@/utils/buttons";
|
import buttons from "@/utils/buttons";
|
||||||
|
|
||||||
// TODO: make this into a user setting
|
// TODO: make this into a user setting
|
||||||
@ -170,12 +170,12 @@ export const useUploadStore = defineStore("upload", {
|
|||||||
async processUploads() {
|
async processUploads() {
|
||||||
const uploadsCount = Object.keys(this.uploads).length;
|
const uploadsCount = Object.keys(this.uploads).length;
|
||||||
|
|
||||||
const isBellowLimit = uploadsCount < UPLOADS_LIMIT;
|
const isBelowLimit = uploadsCount < UPLOADS_LIMIT;
|
||||||
const isQueueEmpty = this.queue.length == 0;
|
const isQueueEmpty = this.queue.length == 0;
|
||||||
const isUploadsEmpty = uploadsCount == 0;
|
const isUploadsEmpty = uploadsCount == 0;
|
||||||
|
|
||||||
const isFinished = isQueueEmpty && isUploadsEmpty;
|
const isFinished = isQueueEmpty && isUploadsEmpty;
|
||||||
const canProcess = isBellowLimit && !isQueueEmpty;
|
const canProcess = isBelowLimit && !isQueueEmpty;
|
||||||
|
|
||||||
if (isFinished) {
|
if (isFinished) {
|
||||||
const fileStore = useFileStore();
|
const fileStore = useFileStore();
|
||||||
|
1
frontend/src/types/layout.d.ts
vendored
1
frontend/src/types/layout.d.ts
vendored
@ -3,6 +3,7 @@ interface PopupProps {
|
|||||||
confirm?: any;
|
confirm?: any;
|
||||||
action?: PopupAction;
|
action?: PopupAction;
|
||||||
props?: any;
|
props?: any;
|
||||||
|
close?: (() => Promise<string>) | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
type PopupAction = (e: Event) => void;
|
type PopupAction = (e: Event) => void;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { useAuthStore } from "@/stores/auth";
|
import { useAuthStore } from "@/stores/auth";
|
||||||
import router from "@/router";
|
import router from "@/router";
|
||||||
import { JwtPayload, jwtDecode } from "jwt-decode";
|
import type { JwtPayload } from "jwt-decode";
|
||||||
|
import { jwtDecode } from "jwt-decode";
|
||||||
import { baseURL, noAuth } from "./constants";
|
import { baseURL, noAuth } from "./constants";
|
||||||
import { StatusError } from "@/api/utils";
|
import { StatusError } from "@/api/utils";
|
||||||
|
|
||||||
@ -23,7 +24,7 @@ export async function validateLogin() {
|
|||||||
await renew(<string>localStorage.getItem("jwt"));
|
await renew(<string>localStorage.getItem("jwt"));
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn("Invalid JWT token in storage"); // eslint-disable-line
|
console.warn("Invalid JWT token in storage");
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ function loading(button: string) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (el === undefined || el === null) {
|
if (el === undefined || el === null) {
|
||||||
console.log("Error getting button " + button); // eslint-disable-line
|
console.log("Error getting button " + button);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ function done(button: string) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (el === undefined || el === null) {
|
if (el === undefined || el === null) {
|
||||||
console.log("Error getting button " + button); // eslint-disable-line
|
console.log("Error getting button " + button);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,7 +51,7 @@ function success(button: string) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (el === undefined || el === null) {
|
if (el === undefined || el === null) {
|
||||||
console.log("Error getting button " + button); // eslint-disable-line
|
console.log("Error getting button " + button);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,39 +1,36 @@
|
|||||||
// Based on code by the following links:
|
// Based on code by the following links:
|
||||||
// https://stackoverflow.com/a/74528564
|
// https://stackoverflow.com/a/74528564
|
||||||
// https://web.dev/articles/async-clipboard
|
// https://web.dev/articles/async-clipboard
|
||||||
export function copy(text: string) {
|
|
||||||
|
interface ClipboardArgs {
|
||||||
|
text?: string;
|
||||||
|
data?: ClipboardItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ClipboardOpts {
|
||||||
|
permission?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function copy(data: ClipboardArgs, opts?: ClipboardOpts) {
|
||||||
return new Promise<void>((resolve, reject) => {
|
return new Promise<void>((resolve, reject) => {
|
||||||
if (
|
if (
|
||||||
// Clipboard API requires secure context
|
// Clipboard API requires secure context
|
||||||
window.isSecureContext &&
|
window.isSecureContext &&
|
||||||
typeof navigator.clipboard !== "undefined" &&
|
typeof navigator.clipboard !== "undefined"
|
||||||
// @ts-ignore
|
|
||||||
navigator.permissions !== "undefined"
|
|
||||||
) {
|
) {
|
||||||
navigator.permissions
|
if (opts?.permission) {
|
||||||
// @ts-ignore
|
getPermission("clipboard-write")
|
||||||
.query({ name: "clipboard-write" })
|
.then(() => writeToClipboard(data).then(resolve).catch(reject))
|
||||||
.then((permission) => {
|
.catch(reject);
|
||||||
if (permission.state === "granted" || permission.state === "prompt") {
|
|
||||||
// simple writeText should work for all modern browsers
|
|
||||||
navigator.clipboard.writeText(text).then(resolve).catch(reject);
|
|
||||||
} else {
|
} else {
|
||||||
reject(new Error("Permission not granted!"));
|
writeToClipboard(data).then(resolve).catch(reject);
|
||||||
}
|
}
|
||||||
})
|
|
||||||
.catch((e) => {
|
|
||||||
// Firefox doesn't support clipboard-write permission
|
|
||||||
if (navigator.userAgent.indexOf("Firefox") != -1) {
|
|
||||||
navigator.clipboard.writeText(text).then(resolve).catch(reject);
|
|
||||||
} else {
|
|
||||||
reject(e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else if (
|
} else if (
|
||||||
document.queryCommandSupported &&
|
document.queryCommandSupported &&
|
||||||
document.queryCommandSupported("copy")
|
document.queryCommandSupported("copy") &&
|
||||||
|
data.text // old method only supports text
|
||||||
) {
|
) {
|
||||||
const textarea = createTemporaryTextarea(text);
|
const textarea = createTemporaryTextarea(data.text);
|
||||||
const body = document.activeElement || document.body;
|
const body = document.activeElement || document.body;
|
||||||
try {
|
try {
|
||||||
body.appendChild(textarea);
|
body.appendChild(textarea);
|
||||||
@ -54,6 +51,35 @@ export function copy(text: string) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getPermission(name: string) {
|
||||||
|
return new Promise<void>((resolve, reject) => {
|
||||||
|
typeof navigator.permissions !== "undefined" &&
|
||||||
|
navigator.permissions
|
||||||
|
// @ts-expect-error chrome specific api
|
||||||
|
.query({ name })
|
||||||
|
.then((permission) => {
|
||||||
|
if (permission.state === "granted" || permission.state === "prompt") {
|
||||||
|
resolve();
|
||||||
|
} else {
|
||||||
|
reject(new Error("Permission denied!"));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeToClipboard(data: ClipboardArgs) {
|
||||||
|
if (data.text) {
|
||||||
|
return navigator.clipboard.writeText(data.text);
|
||||||
|
}
|
||||||
|
if (data.data) {
|
||||||
|
return navigator.clipboard.write(data.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise<void>((resolve, reject) => {
|
||||||
|
reject(new Error("No data was supplied!"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const styles = {
|
const styles = {
|
||||||
fontSize: "12pt",
|
fontSize: "12pt",
|
||||||
position: "fixed",
|
position: "fixed",
|
||||||
@ -69,10 +95,10 @@ const styles = {
|
|||||||
background: "transparent",
|
background: "transparent",
|
||||||
};
|
};
|
||||||
|
|
||||||
const createTemporaryTextarea = (text: string) => {
|
function createTemporaryTextarea(text: string) {
|
||||||
const textarea = document.createElement("textarea");
|
const textarea = document.createElement("textarea");
|
||||||
textarea.value = text;
|
textarea.value = text;
|
||||||
textarea.setAttribute("readonly", "");
|
textarea.setAttribute("readonly", "");
|
||||||
Object.assign(textarea.style, styles);
|
Object.assign(textarea.style, styles);
|
||||||
return textarea;
|
return textarea;
|
||||||
};
|
}
|
||||||
|
@ -6,13 +6,16 @@ export default function getRule(rules: string[]) {
|
|||||||
let result = null;
|
let result = null;
|
||||||
const find = Array.prototype.find;
|
const find = Array.prototype.find;
|
||||||
|
|
||||||
find.call(document.styleSheets, (styleSheet) => {
|
find.call(document.styleSheets, (styleSheet: CSSStyleSheet) => {
|
||||||
result = find.call(styleSheet.cssRules, (cssRule) => {
|
result = find.call(styleSheet.cssRules, (cssRule: CSSRule) => {
|
||||||
let found = false;
|
let found = false;
|
||||||
|
|
||||||
if (cssRule instanceof window.CSSStyleRule) {
|
// faster than checking instanceof for every element
|
||||||
|
if (cssRule.constructor.name === "CSSStyleRule") {
|
||||||
for (let i = 0; i < rules.length; i++) {
|
for (let i = 0; i < rules.length; i++) {
|
||||||
if (cssRule.selectorText.toLowerCase() === rules[i]) {
|
if (
|
||||||
|
(cssRule as CSSStyleRule).selectorText.toLowerCase() === rules[i]
|
||||||
|
) {
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -24,5 +27,5 @@ export default function getRule(rules: string[]) {
|
|||||||
return result != null;
|
return result != null;
|
||||||
});
|
});
|
||||||
|
|
||||||
return result;
|
return result as CSSStyleRule | null;
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { useLayoutStore } from "@/stores/layout";
|
||||||
import { useUploadStore } from "@/stores/upload";
|
import { useUploadStore } from "@/stores/upload";
|
||||||
import url from "@/utils/url";
|
import url from "@/utils/url";
|
||||||
|
|
||||||
@ -126,6 +127,9 @@ export function handleFiles(
|
|||||||
overwrite = false
|
overwrite = false
|
||||||
) {
|
) {
|
||||||
const uploadStore = useUploadStore();
|
const uploadStore = useUploadStore();
|
||||||
|
const layoutStore = useLayoutStore();
|
||||||
|
|
||||||
|
layoutStore.closeHovers();
|
||||||
|
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
const id = uploadStore.id;
|
const id = uploadStore.id;
|
||||||
|
@ -325,6 +325,7 @@ const token = ref<string>("");
|
|||||||
const audio = ref<HTMLAudioElement>();
|
const audio = ref<HTMLAudioElement>();
|
||||||
const tag = ref<boolean>(false);
|
const tag = ref<boolean>(false);
|
||||||
|
|
||||||
|
const $showError = inject<IToastError>("$showError")!;
|
||||||
const $showSuccess = inject<IToastSuccess>("$showSuccess")!;
|
const $showSuccess = inject<IToastSuccess>("$showSuccess")!;
|
||||||
|
|
||||||
const { t } = useI18n({});
|
const { t } = useI18n({});
|
||||||
@ -463,9 +464,9 @@ const download = () => {
|
|||||||
if (req.value === null) return false;
|
if (req.value === null) return false;
|
||||||
layoutStore.closeHovers();
|
layoutStore.closeHovers();
|
||||||
|
|
||||||
let files: string[] = [];
|
const files: string[] = [];
|
||||||
|
|
||||||
for (let i of fileStore.selected) {
|
for (const i of fileStore.selected) {
|
||||||
files.push(req.value.items[i].path);
|
files.push(req.value.items[i].path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -488,13 +489,23 @@ const linkSelected = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const copyToClipboard = (text: string) => {
|
const copyToClipboard = (text: string) => {
|
||||||
copy(text).then(
|
copy({ text }).then(
|
||||||
() => {
|
() => {
|
||||||
// clipboard successfully set
|
// clipboard successfully set
|
||||||
$showSuccess(t("success.linkCopied"));
|
$showSuccess(t("success.linkCopied"));
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
// clipboard write failed
|
// clipboard write failed
|
||||||
|
copy({ text }, { permission: true }).then(
|
||||||
|
() => {
|
||||||
|
// clipboard successfully set
|
||||||
|
$showSuccess(t("success.linkCopied"));
|
||||||
|
},
|
||||||
|
(e) => {
|
||||||
|
// clipboard write failed
|
||||||
|
$showError(e);
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -108,7 +108,7 @@ onMounted(() => {
|
|||||||
showPrintMargin: false,
|
showPrintMargin: false,
|
||||||
readOnly: fileStore.req?.type === "textImmutable",
|
readOnly: fileStore.req?.type === "textImmutable",
|
||||||
theme: "ace/theme/chrome",
|
theme: "ace/theme/chrome",
|
||||||
mode: modelist.getModeForPath(fileStore.req?.name).mode,
|
mode: modelist.getModeForPath(fileStore.req!.name).mode,
|
||||||
wrap: true,
|
wrap: true,
|
||||||
enableBasicAutocompletion: true,
|
enableBasicAutocompletion: true,
|
||||||
enableLiveAutocompletion: true,
|
enableLiveAutocompletion: true,
|
||||||
@ -173,7 +173,7 @@ const close = () => {
|
|||||||
|
|
||||||
fileStore.updateRequest(null);
|
fileStore.updateRequest(null);
|
||||||
|
|
||||||
let uri = url.removeLastDir(route.path) + "/";
|
const uri = url.removeLastDir(route.path) + "/";
|
||||||
router.push({ path: uri });
|
router.push({ path: uri });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -285,7 +285,7 @@ import { users, files as api } from "@/api";
|
|||||||
import { enableExec } from "@/utils/constants";
|
import { enableExec } from "@/utils/constants";
|
||||||
import * as upload from "@/utils/upload";
|
import * as upload from "@/utils/upload";
|
||||||
import css from "@/utils/css";
|
import css from "@/utils/css";
|
||||||
import throttle from "lodash/throttle";
|
import { throttle } from "lodash-es";
|
||||||
import { Base64 } from "js-base64";
|
import { Base64 } from "js-base64";
|
||||||
|
|
||||||
import HeaderBar from "@/components/header/HeaderBar.vue";
|
import HeaderBar from "@/components/header/HeaderBar.vue";
|
||||||
@ -523,12 +523,12 @@ const keyEvent = (event: KeyboardEvent) => {
|
|||||||
break;
|
break;
|
||||||
case "a":
|
case "a":
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
for (let file of items.value.files) {
|
for (const file of items.value.files) {
|
||||||
if (fileStore.selected.indexOf(file.index) === -1) {
|
if (fileStore.selected.indexOf(file.index) === -1) {
|
||||||
fileStore.selected.push(file.index);
|
fileStore.selected.push(file.index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (let dir of items.value.dirs) {
|
for (const dir of items.value.dirs) {
|
||||||
if (fileStore.selected.indexOf(dir.index) === -1) {
|
if (fileStore.selected.indexOf(dir.index) === -1) {
|
||||||
fileStore.selected.push(dir.index);
|
fileStore.selected.push(dir.index);
|
||||||
}
|
}
|
||||||
@ -551,9 +551,9 @@ const copyCut = (event: Event | KeyboardEvent): void => {
|
|||||||
|
|
||||||
if (fileStore.req === null) return;
|
if (fileStore.req === null) return;
|
||||||
|
|
||||||
let items = [];
|
const items = [];
|
||||||
|
|
||||||
for (let i of fileStore.selected) {
|
for (const i of fileStore.selected) {
|
||||||
items.push({
|
items.push({
|
||||||
from: fileStore.req.items[i].url,
|
from: fileStore.req.items[i].url,
|
||||||
name: fileStore.req.items[i].name,
|
name: fileStore.req.items[i].name,
|
||||||
@ -575,9 +575,9 @@ const paste = (event: Event) => {
|
|||||||
if ((event.target as HTMLElement).tagName?.toLowerCase() === "input") return;
|
if ((event.target as HTMLElement).tagName?.toLowerCase() === "input") return;
|
||||||
|
|
||||||
// TODO router location should it be
|
// TODO router location should it be
|
||||||
let items: any[] = [];
|
const items: any[] = [];
|
||||||
|
|
||||||
for (let item of clipboardStore.items) {
|
for (const item of clipboardStore.items) {
|
||||||
const from = item.from.endsWith("/") ? item.from.slice(0, -1) : item.from;
|
const from = item.from.endsWith("/") ? item.from.slice(0, -1) : item.from;
|
||||||
const to = route.path + encodeURIComponent(item.name);
|
const to = route.path + encodeURIComponent(item.name);
|
||||||
items.push({ from, to, name: item.name });
|
items.push({ from, to, name: item.name });
|
||||||
@ -614,7 +614,7 @@ const paste = (event: Event) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let conflict = upload.checkConflict(items, fileStore.req!.items);
|
const conflict = upload.checkConflict(items, fileStore.req!.items);
|
||||||
|
|
||||||
let overwrite = false;
|
let overwrite = false;
|
||||||
let rename = false;
|
let rename = false;
|
||||||
@ -640,14 +640,13 @@ const paste = (event: Event) => {
|
|||||||
|
|
||||||
const colunmsResize = () => {
|
const colunmsResize = () => {
|
||||||
// Update the columns size based on the window width.
|
// Update the columns size based on the window width.
|
||||||
let items_ = css(["#listing.mosaic .item", ".mosaic#listing .item"]);
|
const items_ = css(["#listing.mosaic .item", ".mosaic#listing .item"]);
|
||||||
if (items_ === null) return;
|
if (items_ === null) return;
|
||||||
|
|
||||||
let columns = Math.floor(
|
let columns = Math.floor(
|
||||||
(document.querySelector("main")?.offsetWidth ?? 0) / columnWidth.value
|
(document.querySelector("main")?.offsetWidth ?? 0) / columnWidth.value
|
||||||
);
|
);
|
||||||
if (columns === 0) columns = 1;
|
if (columns === 0) columns = 1;
|
||||||
// @ts-ignore never type error
|
|
||||||
items_.style.width = `calc(${100 / columns}% - 1em)`;
|
items_.style.width = `calc(${100 / columns}% - 1em)`;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -677,11 +676,10 @@ const dragEnter = () => {
|
|||||||
|
|
||||||
// When the user starts dragging an item, put every
|
// When the user starts dragging an item, put every
|
||||||
// file on the listing with 50% opacity.
|
// file on the listing with 50% opacity.
|
||||||
let items = document.getElementsByClassName("item");
|
const items = document.getElementsByClassName("item");
|
||||||
|
|
||||||
// @ts-ignore
|
Array.from(items).forEach((file: Element) => {
|
||||||
Array.from(items).forEach((file: HTMLElement) => {
|
(file as HTMLElement).style.opacity = "0.5";
|
||||||
file.style.opacity = "0.5";
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -698,7 +696,7 @@ const drop = async (event: DragEvent) => {
|
|||||||
dragCounter.value = 0;
|
dragCounter.value = 0;
|
||||||
resetOpacity();
|
resetOpacity();
|
||||||
|
|
||||||
let dt = event.dataTransfer;
|
const dt = event.dataTransfer;
|
||||||
let el: HTMLElement | null = event.target as HTMLElement;
|
let el: HTMLElement | null = event.target as HTMLElement;
|
||||||
|
|
||||||
if (fileStore.req === null || dt === null || dt.files.length <= 0) return;
|
if (fileStore.req === null || dt === null || dt.files.length <= 0) return;
|
||||||
@ -709,7 +707,7 @@ const drop = async (event: DragEvent) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let files: UploadList = (await upload.scanFiles(dt)) as UploadList;
|
const files: UploadList = (await upload.scanFiles(dt)) as UploadList;
|
||||||
let items = fileStore.req.items;
|
let items = fileStore.req.items;
|
||||||
let path = route.path.endsWith("/") ? route.path : route.path + "/";
|
let path = route.path.endsWith("/") ? route.path : route.path + "/";
|
||||||
|
|
||||||
@ -729,7 +727,7 @@ const drop = async (event: DragEvent) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let conflict = upload.checkConflict(files, items);
|
const conflict = upload.checkConflict(files, items);
|
||||||
|
|
||||||
if (conflict) {
|
if (conflict) {
|
||||||
layoutStore.showHover({
|
layoutStore.showHover({
|
||||||
@ -753,12 +751,10 @@ const drop = async (event: DragEvent) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const uploadInput = (event: Event) => {
|
const uploadInput = (event: Event) => {
|
||||||
layoutStore.closeHovers();
|
const files = (event.currentTarget as HTMLInputElement)?.files;
|
||||||
|
|
||||||
let files = (event.currentTarget as HTMLInputElement)?.files;
|
|
||||||
if (files === null) return;
|
if (files === null) return;
|
||||||
|
|
||||||
let folder_upload = !!files[0].webkitRelativePath;
|
const folder_upload = !!files[0].webkitRelativePath;
|
||||||
|
|
||||||
const uploadFiles: UploadList = [];
|
const uploadFiles: UploadList = [];
|
||||||
for (let i = 0; i < files.length; i++) {
|
for (let i = 0; i < files.length; i++) {
|
||||||
@ -773,8 +769,8 @@ const uploadInput = (event: Event) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let path = route.path.endsWith("/") ? route.path : route.path + "/";
|
const path = route.path.endsWith("/") ? route.path : route.path + "/";
|
||||||
let conflict = upload.checkConflict(uploadFiles, fileStore.req!.items);
|
const conflict = upload.checkConflict(uploadFiles, fileStore.req!.items);
|
||||||
|
|
||||||
if (conflict) {
|
if (conflict) {
|
||||||
layoutStore.showHover({
|
layoutStore.showHover({
|
||||||
@ -798,7 +794,7 @@ const uploadInput = (event: Event) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const resetOpacity = () => {
|
const resetOpacity = () => {
|
||||||
let items = document.getElementsByClassName("item");
|
const items = document.getElementsByClassName("item");
|
||||||
|
|
||||||
Array.from(items).forEach((file: Element) => {
|
Array.from(items).forEach((file: Element) => {
|
||||||
(file as HTMLElement).style.opacity = "1";
|
(file as HTMLElement).style.opacity = "1";
|
||||||
@ -824,7 +820,6 @@ const sort = async (by: string) => {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (authStore.user?.id) {
|
if (authStore.user?.id) {
|
||||||
// @ts-ignore
|
|
||||||
await users.update({ id: authStore.user?.id, sorting: { by, asc } }, [
|
await users.update({ id: authStore.user?.id, sorting: { by, asc } }, [
|
||||||
"sorting",
|
"sorting",
|
||||||
]);
|
]);
|
||||||
@ -875,10 +870,10 @@ const download = () => {
|
|||||||
confirm: (format: any) => {
|
confirm: (format: any) => {
|
||||||
layoutStore.closeHovers();
|
layoutStore.closeHovers();
|
||||||
|
|
||||||
let files = [];
|
const files = [];
|
||||||
|
|
||||||
if (fileStore.selectedCount > 0 && fileStore.req !== null) {
|
if (fileStore.selectedCount > 0 && fileStore.req !== null) {
|
||||||
for (let i of fileStore.selected) {
|
for (const i of fileStore.selected) {
|
||||||
files.push(fileStore.req.items[i].url);
|
files.push(fileStore.req.items[i].url);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -901,13 +896,12 @@ const switchView = async () => {
|
|||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
id: authStore.user?.id,
|
id: authStore.user?.id,
|
||||||
viewMode: modes[authStore.user?.viewMode ?? "list"] || "list",
|
viewMode: (modes[authStore.user?.viewMode ?? "list"] ||
|
||||||
|
"list") as ViewModeType,
|
||||||
};
|
};
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
users.update(data, ["viewMode"]).catch($showError);
|
users.update(data, ["viewMode"]).catch($showError);
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
authStore.updateUser(data);
|
authStore.updateUser(data);
|
||||||
|
|
||||||
setItemWeight();
|
setItemWeight();
|
||||||
|
@ -168,7 +168,7 @@ import { files as api } from "@/api";
|
|||||||
import { createURL } from "@/api/utils";
|
import { createURL } from "@/api/utils";
|
||||||
import { resizePreview } from "@/utils/constants";
|
import { resizePreview } from "@/utils/constants";
|
||||||
import url from "@/utils/url";
|
import url from "@/utils/url";
|
||||||
import throttle from "lodash/throttle";
|
import { throttle } from "lodash-es";
|
||||||
import HeaderBar from "@/components/header/HeaderBar.vue";
|
import HeaderBar from "@/components/header/HeaderBar.vue";
|
||||||
import Action from "@/components/header/Action.vue";
|
import Action from "@/components/header/Action.vue";
|
||||||
import ExtendedImage from "@/components/files/ExtendedImage.vue";
|
import ExtendedImage from "@/components/files/ExtendedImage.vue";
|
||||||
@ -353,7 +353,7 @@ const updatePreview = async () => {
|
|||||||
autoPlay.value = false;
|
autoPlay.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let dirs = route.fullPath.split("/");
|
const dirs = route.fullPath.split("/");
|
||||||
name.value = decodeURIComponent(dirs[dirs.length - 1]);
|
name.value = decodeURIComponent(dirs[dirs.length - 1]);
|
||||||
|
|
||||||
if (!listing.value) {
|
if (!listing.value) {
|
||||||
@ -422,7 +422,7 @@ const toggleNavigation = throttle(function () {
|
|||||||
const close = () => {
|
const close = () => {
|
||||||
fileStore.updateRequest(null);
|
fileStore.updateRequest(null);
|
||||||
|
|
||||||
let uri = url.removeLastDir(route.path) + "/";
|
const uri = url.removeLastDir(route.path) + "/";
|
||||||
router.push({ path: uri });
|
router.push({ path: uri });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -282,11 +282,11 @@ const formattedChunkSize = computed({
|
|||||||
// Define funcs
|
// Define funcs
|
||||||
const capitalize = (name: string, where: string | RegExp = "_") => {
|
const capitalize = (name: string, where: string | RegExp = "_") => {
|
||||||
if (where === "caps") where = /(?=[A-Z])/;
|
if (where === "caps") where = /(?=[A-Z])/;
|
||||||
let splitted = name.split(where);
|
const split = name.split(where);
|
||||||
name = "";
|
name = "";
|
||||||
|
|
||||||
for (let i = 0; i < splitted.length; i++) {
|
for (let i = 0; i < split.length; i++) {
|
||||||
name += splitted[i].charAt(0).toUpperCase() + splitted[i].slice(1) + " ";
|
name += split[i].charAt(0).toUpperCase() + split[i].slice(1) + " ";
|
||||||
}
|
}
|
||||||
|
|
||||||
return name.slice(0, -1);
|
return name.slice(0, -1);
|
||||||
@ -294,7 +294,7 @@ const capitalize = (name: string, where: string | RegExp = "_") => {
|
|||||||
|
|
||||||
const save = async () => {
|
const save = async () => {
|
||||||
if (settings.value === null) return false;
|
if (settings.value === null) return false;
|
||||||
let newSettings: ISettings = {
|
const newSettings: ISettings = {
|
||||||
...settings.value,
|
...settings.value,
|
||||||
shell:
|
shell:
|
||||||
settings.value?.shell
|
settings.value?.shell
|
||||||
@ -376,7 +376,7 @@ onMounted(async () => {
|
|||||||
try {
|
try {
|
||||||
layoutStore.loading = true;
|
layoutStore.loading = true;
|
||||||
const original: ISettings = await api.get();
|
const original: ISettings = await api.get();
|
||||||
let newSettings: ISettings = { ...original, commands: {} };
|
const newSettings: ISettings = { ...original, commands: {} };
|
||||||
|
|
||||||
const keys = Object.keys(original.commands) as Array<keyof SettingsCommand>;
|
const keys = Object.keys(original.commands) as Array<keyof SettingsCommand>;
|
||||||
for (const key of keys) {
|
for (const key of keys) {
|
||||||
|
@ -87,12 +87,12 @@ onMounted(async () => {
|
|||||||
layoutStore.loading = true;
|
layoutStore.loading = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let newLinks = await api.list();
|
const newLinks = await api.list();
|
||||||
if (authStore.user?.perm.admin) {
|
if (authStore.user?.perm.admin) {
|
||||||
let userMap = new Map<number, string>();
|
const userMap = new Map<number, string>();
|
||||||
for (let user of await users.getAll())
|
for (const user of await users.getAll())
|
||||||
userMap.set(user.id, user.username);
|
userMap.set(user.id, user.username);
|
||||||
for (let link of newLinks) {
|
for (const link of newLinks) {
|
||||||
if (link.userID && userMap.has(link.userID))
|
if (link.userID && userMap.has(link.userID))
|
||||||
link.username = userMap.get(link.userID);
|
link.username = userMap.get(link.userID);
|
||||||
}
|
}
|
||||||
@ -108,13 +108,23 @@ onMounted(async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const copyToClipboard = (text: string) => {
|
const copyToClipboard = (text: string) => {
|
||||||
copy(text).then(
|
copy({ text }).then(
|
||||||
() => {
|
() => {
|
||||||
// clipboard successfully set
|
// clipboard successfully set
|
||||||
$showSuccess(t("success.linkCopied"));
|
$showSuccess(t("success.linkCopied"));
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
// clipboard write failed
|
// clipboard write failed
|
||||||
|
copy({ text }, { permission: true }).then(
|
||||||
|
() => {
|
||||||
|
// clipboard successfully set
|
||||||
|
$showSuccess(t("success.linkCopied"));
|
||||||
|
},
|
||||||
|
(e) => {
|
||||||
|
// clipboard write failed
|
||||||
|
$showError(e);
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -90,7 +90,7 @@ const fetchData = async () => {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (isNew.value) {
|
if (isNew.value) {
|
||||||
let { defaults, createUserDir: _createUserDir } = await settings.get();
|
const { defaults, createUserDir: _createUserDir } = await settings.get();
|
||||||
createUserDir.value = _createUserDir;
|
createUserDir.value = _createUserDir;
|
||||||
user.value = {
|
user.value = {
|
||||||
...defaults,
|
...defaults,
|
||||||
|
13
frontend/tsconfig.app.json
Normal file
13
frontend/tsconfig.app.json
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"extends": "@vue/tsconfig/tsconfig.dom.json",
|
||||||
|
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
|
||||||
|
"exclude": ["src/**/__tests__/*"],
|
||||||
|
"compilerOptions": {
|
||||||
|
"composite": true,
|
||||||
|
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
||||||
|
"types": ["vite/client", "@intlify/unplugin-vue-i18n/messages"],
|
||||||
|
"paths": {
|
||||||
|
"@/*": ["./src/*"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,24 +1,11 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"files": [],
|
||||||
"baseUrl": ".",
|
"references": [
|
||||||
"allowJs": true,
|
{
|
||||||
"target": "ESNext",
|
"path": "./tsconfig.node.json"
|
||||||
"useDefineForClassFields": true,
|
|
||||||
"module": "ESNext",
|
|
||||||
"moduleResolution": "Node10",
|
|
||||||
"strict": true,
|
|
||||||
"sourceMap": true,
|
|
||||||
"noImplicitReturns": true,
|
|
||||||
"resolveJsonModule": true,
|
|
||||||
"isolatedModules": true,
|
|
||||||
"esModuleInterop": true,
|
|
||||||
"lib": ["ESNext", "DOM"],
|
|
||||||
"skipLibCheck": true,
|
|
||||||
"types": ["vite/client", "@intlify/unplugin-vue-i18n/messages"],
|
|
||||||
"paths": {
|
|
||||||
"@/*": ["./src/*"]
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"include": ["src/**/*.ts", "src/**/*.vue"],
|
{
|
||||||
"exclude": ["node_modules", "dist"]
|
"path": "./tsconfig.app.json"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
18
frontend/tsconfig.node.json
Normal file
18
frontend/tsconfig.node.json
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"extends": "@tsconfig/node22/tsconfig.json",
|
||||||
|
"include": [
|
||||||
|
"vite.config.*",
|
||||||
|
"vitest.config.*",
|
||||||
|
"cypress.config.*",
|
||||||
|
"nightwatch.conf.*",
|
||||||
|
"playwright.config.*"
|
||||||
|
],
|
||||||
|
"compilerOptions": {
|
||||||
|
"composite": true,
|
||||||
|
"noEmit": true,
|
||||||
|
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
||||||
|
"module": "ESNext",
|
||||||
|
"moduleResolution": "Bundler",
|
||||||
|
"types": ["node"]
|
||||||
|
}
|
||||||
|
}
|
14
frontend/tsconfig.tsc.json
Normal file
14
frontend/tsconfig.tsc.json
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"extends": "./tsconfig.app.json",
|
||||||
|
// vue-tsc wont shut up about error TS9005
|
||||||
|
// in non-TS vue files so exclude them
|
||||||
|
"exclude": [
|
||||||
|
"src/components/Shell.vue",
|
||||||
|
"src/components/prompts/Copy.vue",
|
||||||
|
"src/components/prompts/Delete.vue",
|
||||||
|
"src/components/prompts/FileList.vue",
|
||||||
|
"src/components/prompts/Rename.vue",
|
||||||
|
"src/components/prompts/Share.vue",
|
||||||
|
"src/components/prompts/UploadFiles.vue"
|
||||||
|
]
|
||||||
|
}
|
10
go.mod
10
go.mod
@ -8,7 +8,7 @@ require (
|
|||||||
github.com/disintegration/imaging v1.6.2
|
github.com/disintegration/imaging v1.6.2
|
||||||
github.com/dsoprea/go-exif/v3 v3.0.1
|
github.com/dsoprea/go-exif/v3 v3.0.1
|
||||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568
|
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.0
|
github.com/golang-jwt/jwt/v4 v4.5.1
|
||||||
github.com/gorilla/mux v1.8.1
|
github.com/gorilla/mux v1.8.1
|
||||||
github.com/gorilla/websocket v1.5.3
|
github.com/gorilla/websocket v1.5.3
|
||||||
github.com/maruel/natural v1.1.1
|
github.com/maruel/natural v1.1.1
|
||||||
@ -24,9 +24,9 @@ require (
|
|||||||
github.com/stretchr/testify v1.9.0
|
github.com/stretchr/testify v1.9.0
|
||||||
github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce
|
github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce
|
||||||
go.etcd.io/bbolt v1.3.11
|
go.etcd.io/bbolt v1.3.11
|
||||||
golang.org/x/crypto v0.26.0
|
golang.org/x/crypto v0.31.0
|
||||||
golang.org/x/image v0.19.0
|
golang.org/x/image v0.19.0
|
||||||
golang.org/x/text v0.17.0
|
golang.org/x/text v0.21.0
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
||||||
gopkg.in/yaml.v2 v2.4.0
|
gopkg.in/yaml.v2 v2.4.0
|
||||||
)
|
)
|
||||||
@ -64,8 +64,8 @@ require (
|
|||||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||||
go.uber.org/multierr v1.11.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 // indirect
|
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 // indirect
|
||||||
golang.org/x/net v0.23.0 // indirect
|
golang.org/x/net v0.33.0 // indirect
|
||||||
golang.org/x/sys v0.23.0 // indirect
|
golang.org/x/sys v0.28.0 // indirect
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
24
go.sum
24
go.sum
@ -57,8 +57,8 @@ github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8b
|
|||||||
github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
|
github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
|
||||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
|
github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo=
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||||
github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
|
github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
|
||||||
github.com/golang/geo v0.0.0-20200319012246-673a6f80352d/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
|
github.com/golang/geo v0.0.0-20200319012246-673a6f80352d/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
|
||||||
github.com/golang/geo v0.0.0-20210211234256-740aa86cb551/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
|
github.com/golang/geo v0.0.0-20210211234256-740aa86cb551/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
|
||||||
@ -174,8 +174,8 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
|||||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
|
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
|
||||||
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
|
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||||
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 h1:aAcj0Da7eBAtrTp03QXWvm88pSyOt+UgdZw2BFZ+lEw=
|
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 h1:aAcj0Da7eBAtrTp03QXWvm88pSyOt+UgdZw2BFZ+lEw=
|
||||||
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ=
|
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ=
|
||||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
@ -190,10 +190,10 @@ golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/
|
|||||||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||||
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
|
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
|
||||||
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||||
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
|
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
||||||
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@ -204,14 +204,14 @@ golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM=
|
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
||||||
golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
|
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||||
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||||
|
@ -47,7 +47,7 @@ func errToStatus(err error) int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is an addaptation if http.StripPrefix in which we don't
|
// This is an adaptation if http.StripPrefix in which we don't
|
||||||
// return 404 if the page doesn't have the needed prefix.
|
// return 404 if the page doesn't have the needed prefix.
|
||||||
func stripPrefix(prefix string, h http.Handler) http.Handler {
|
func stripPrefix(prefix string, h http.Handler) http.Handler {
|
||||||
if prefix == "" || prefix == "/" {
|
if prefix == "" || prefix == "/" {
|
||||||
|
@ -535,9 +535,9 @@ create-require@^1.1.0:
|
|||||||
integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
|
integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
|
||||||
|
|
||||||
cross-spawn@^7.0.3:
|
cross-spawn@^7.0.3:
|
||||||
version "7.0.3"
|
version "7.0.6"
|
||||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
|
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f"
|
||||||
integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
|
integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==
|
||||||
dependencies:
|
dependencies:
|
||||||
path-key "^3.1.0"
|
path-key "^3.1.0"
|
||||||
shebang-command "^2.0.0"
|
shebang-command "^2.0.0"
|
||||||
|
@ -3,6 +3,6 @@ package version
|
|||||||
var (
|
var (
|
||||||
// Version is the current File Browser version.
|
// Version is the current File Browser version.
|
||||||
Version = "(untracked)"
|
Version = "(untracked)"
|
||||||
// CommitSHA is the commmit sha.
|
// CommitSHA is the commit sha.
|
||||||
CommitSHA = "(unknown)"
|
CommitSHA = "(unknown)"
|
||||||
)
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user