Merge branch 'master' into text-share
commit
be69dbdcb6
|
@ -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,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.
|
||||||
|
|
|
@ -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
|
|
@ -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"]
|
|
||||||
}
|
|
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.0.1",
|
||||||
"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.4.6",
|
"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"
|
||||||
}
|
}
|
||||||
|
|
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();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -197,13 +197,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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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") {
|
} else {
|
||||||
// simple writeText should work for all modern browsers
|
writeToClipboard(data).then(resolve).catch(reject);
|
||||||
navigator.clipboard.writeText(text).then(resolve).catch(reject);
|
}
|
||||||
} else {
|
|
||||||
reject(new Error("Permission not granted!"));
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((e) => {
|
|
||||||
// Firefox doesn't support clipboard-write permission
|
|
||||||
if (navigator.userAgent.indexOf("Firefox") != -1) {
|
|
||||||
navigator.clipboard.writeText(text).then(resolve).catch(reject);
|
|
||||||
} else {
|
|
||||||
reject(e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} 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,7 +282,7 @@ 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 split = name.split(where);
|
const split = name.split(where);
|
||||||
name = "";
|
name = "";
|
||||||
|
|
||||||
for (let i = 0; i < split.length; i++) {
|
for (let i = 0; i < split.length; i++) {
|
||||||
|
@ -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,
|
||||||
|
|
|
@ -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",
|
"path": "./tsconfig.app.json"
|
||||||
"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"]
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"]
|
||||||
|
}
|
||||||
|
}
|
|
@ -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=
|
||||||
|
|
|
@ -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"
|
||||||
|
|
Loading…
Reference in New Issue