Merge remote-tracking branch 'kloon15/vue3' into vue3
This commit is contained in:
commit
ee619adda3
220
frontend/package-lock.json
generated
220
frontend/package-lock.json
generated
@ -8,7 +8,6 @@
|
||||
"name": "filebrowser-frontend",
|
||||
"version": "2.0.0",
|
||||
"dependencies": {
|
||||
"@vue/compat": "^3.3.4",
|
||||
"@vueuse/core": "^10.4.1",
|
||||
"ace-builds": "^1.24.1",
|
||||
"clipboard": "^2.0.11",
|
||||
@ -21,7 +20,6 @@
|
||||
"material-icons": "^1.13.10",
|
||||
"moment": "^2.29.4",
|
||||
"normalize.css": "^8.0.1",
|
||||
"noty": "^3.2.0-beta",
|
||||
"pinia": "^2.1.6",
|
||||
"pretty-bytes": "^6.1.1",
|
||||
"qrcode.vue": "^3.4.1",
|
||||
@ -31,11 +29,10 @@
|
||||
"vue-i18n": "^9.2.2",
|
||||
"vue-lazyload": "^3.0.0",
|
||||
"vue-router": "^4.2.4",
|
||||
"vue-simple-progress": "^1.1.1"
|
||||
"vue-toastification": "^2.0.0-rc.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@intlify/unplugin-vue-i18n": "^0.12.3",
|
||||
"@types/node": "^20.5.9",
|
||||
"@vitejs/plugin-legacy": "^4.1.1",
|
||||
"@vitejs/plugin-vue": "^4.3.3",
|
||||
"@vue/eslint-config-prettier": "^8.0.0",
|
||||
@ -47,11 +44,9 @@
|
||||
"postcss": "^8.4.28",
|
||||
"prettier": "^3.0.2",
|
||||
"terser": "^5.19.2",
|
||||
"typescript": "^5.2.2",
|
||||
"vite": "^4.4.9",
|
||||
"vite-plugin-compression2": "^0.10.4",
|
||||
"vite-plugin-rewrite-all": "^1.0.1",
|
||||
"vue-tsc": "^1.8.10"
|
||||
"vite-plugin-rewrite-all": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@aashutoshrathi/word-wrap": {
|
||||
@ -2493,12 +2488,6 @@
|
||||
"integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.5.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.9.tgz",
|
||||
"integrity": "sha512-PcGNd//40kHAS3sTlzKB9C9XL4K0sTup8nbG5lC14kzEteTNuAFh9u5nA0o5TWnSG2r/JNPRXFVcHJIIeRlmqQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/web-bluetooth": {
|
||||
"version": "0.0.17",
|
||||
"resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.17.tgz",
|
||||
@ -2542,46 +2531,6 @@
|
||||
"vue": "^3.2.25"
|
||||
}
|
||||
},
|
||||
"node_modules/@volar/language-core": {
|
||||
"version": "1.10.1",
|
||||
"resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-1.10.1.tgz",
|
||||
"integrity": "sha512-JnsM1mIPdfGPxmoOcK1c7HYAsL6YOv0TCJ4aW3AXPZN/Jb4R77epDyMZIVudSGjWMbvv/JfUa+rQ+dGKTmgwBA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@volar/source-map": "1.10.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@volar/source-map": {
|
||||
"version": "1.10.1",
|
||||
"resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-1.10.1.tgz",
|
||||
"integrity": "sha512-3/S6KQbqa7pGC8CxPrg69qHLpOvkiPHGJtWPkI/1AXCsktkJ6gIk/5z4hyuMp8Anvs6eS/Kvp/GZa3ut3votKA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"muggle-string": "^0.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@volar/typescript": {
|
||||
"version": "1.10.1",
|
||||
"resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-1.10.1.tgz",
|
||||
"integrity": "sha512-+iiO9yUSRHIYjlteT+QcdRq8b44qH19/eiUZtjNtuh6D9ailYM7DVR0zO2sEgJlvCaunw/CF9Ov2KooQBpR4VQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@volar/language-core": "1.10.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compat": {
|
||||
"version": "3.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compat/-/compat-3.3.4.tgz",
|
||||
"integrity": "sha512-VwAsPqUqRJVxeLQPUC03Sa5d+T8UG2Qv4VItq74KmNvtQlRXICpa/sqq12BcyBB4Tz1U5paOEZxWCUoXkrZ9QQ==",
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.21.3",
|
||||
"estree-walker": "^2.0.2",
|
||||
"source-map-js": "^1.0.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vue": "3.3.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-core": {
|
||||
"version": "3.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.3.4.tgz",
|
||||
@ -2647,54 +2596,6 @@
|
||||
"prettier": ">= 3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/language-core": {
|
||||
"version": "1.8.10",
|
||||
"resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-1.8.10.tgz",
|
||||
"integrity": "sha512-db8PtM4ZZr7SYNH30XpKxUYnUBYaTvcuJ4c2whKK04fuAjbtjAIZ2al5GzGEfUlesmvkpgdbiSviRXUxgD9Omw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@volar/language-core": "~1.10.0",
|
||||
"@volar/source-map": "~1.10.0",
|
||||
"@vue/compiler-dom": "^3.3.0",
|
||||
"@vue/reactivity": "^3.3.0",
|
||||
"@vue/shared": "^3.3.0",
|
||||
"minimatch": "^9.0.0",
|
||||
"muggle-string": "^0.3.1",
|
||||
"vue-template-compiler": "^2.7.14"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "*"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"typescript": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/language-core/node_modules/brace-expansion": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/language-core/node_modules/minimatch": {
|
||||
"version": "9.0.3",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
|
||||
"integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/reactivity": {
|
||||
"version": "3.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.3.4.tgz",
|
||||
@ -2751,16 +2652,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.4.tgz",
|
||||
"integrity": "sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ=="
|
||||
},
|
||||
"node_modules/@vue/typescript": {
|
||||
"version": "1.8.10",
|
||||
"resolved": "https://registry.npmjs.org/@vue/typescript/-/typescript-1.8.10.tgz",
|
||||
"integrity": "sha512-vPSpTXMk4chYwvyTGjM891cKgnx2r6vtbdANOp2mRU31f4HYGyLrZBlGgiua7SaO2cLjUg8y91OipJe0t8OFhA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@volar/typescript": "~1.10.0",
|
||||
"@vue/language-core": "1.8.10"
|
||||
}
|
||||
},
|
||||
"node_modules/@vueuse/core": {
|
||||
"version": "10.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@vueuse/core/-/core-10.4.1.tgz",
|
||||
@ -3387,12 +3278,6 @@
|
||||
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.9.tgz",
|
||||
"integrity": "sha512-QvzAURSbQ0pKdIye2txOzNaHmxtUBXerpY0FJsFXUMKbIZeFm5ht1LS/jFsrncjnmtv8HsG0W2g6c0zUjZWmpA=="
|
||||
},
|
||||
"node_modules/de-indent": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz",
|
||||
"integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
@ -4286,15 +4171,6 @@
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/he": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
|
||||
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"he": "bin/he"
|
||||
}
|
||||
},
|
||||
"node_modules/html-encoding-sniffer": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz",
|
||||
@ -4959,12 +4835,6 @@
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/muggle-string": {
|
||||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.3.1.tgz",
|
||||
"integrity": "sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "3.3.6",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
|
||||
@ -5017,12 +4887,6 @@
|
||||
"resolved": "https://registry.npmjs.org/normalize.css/-/normalize.css-8.0.1.tgz",
|
||||
"integrity": "sha512-qizSNPO93t1YUuUhP22btGOo3chcvDFqFaj2TRybP0DMxkHOCTYwp3n34fel4a31ORXy4m1Xq0Gyqpb5m33qIg=="
|
||||
},
|
||||
"node_modules/noty": {
|
||||
"version": "3.2.0-beta-deprecated",
|
||||
"resolved": "https://registry.npmjs.org/noty/-/noty-3.2.0-beta-deprecated.tgz",
|
||||
"integrity": "sha512-ntRbHuQ9SnnnVFZm/oq5L1DBCaHQUvsU24AwZH3PGjAWx2YqR/IhOadMk11vmJovYiQo00oqTj6Hp+D6PGtmLA==",
|
||||
"deprecated": "no longer supported"
|
||||
},
|
||||
"node_modules/npm-run-path": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz",
|
||||
@ -6066,19 +5930,6 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.2.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz",
|
||||
"integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==",
|
||||
"devOptional": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/ufo": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ufo/-/ufo-1.3.0.tgz",
|
||||
@ -6423,71 +6274,14 @@
|
||||
"vue": "^3.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vue-simple-progress": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/vue-simple-progress/-/vue-simple-progress-1.1.1.tgz",
|
||||
"integrity": "sha512-ltLWYBA5eVQHWyt1NwZeGeK0VQC69JVh1oqUdro0po7r8Hc8SEMEyEfuwyCO4s27h5I3jbD99BKKkyPSQZgoZA=="
|
||||
},
|
||||
"node_modules/vue-template-compiler": {
|
||||
"version": "2.7.14",
|
||||
"resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.14.tgz",
|
||||
"integrity": "sha512-zyA5Y3ArvVG0NacJDkkzJuPQDF8RFeRlzV2vLeSnhSpieO6LK2OVbdLPi5MPPs09Ii+gMO8nY4S3iKQxBxDmWQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"de-indent": "^1.0.2",
|
||||
"he": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vue-tsc": {
|
||||
"version": "1.8.10",
|
||||
"resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-1.8.10.tgz",
|
||||
"integrity": "sha512-ptpTFFDoHQgkWJF7i5iERxooiQzOGtG1uKTfmAUuS3qPuSQGq+Ky/S8BFHhnFGwoOxq/PjmGN2QSZEfg1rtzQA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@vue/language-core": "1.8.10",
|
||||
"@vue/typescript": "1.8.10",
|
||||
"semver": "^7.3.8"
|
||||
},
|
||||
"bin": {
|
||||
"vue-tsc": "bin/vue-tsc.js"
|
||||
},
|
||||
"node_modules/vue-toastification": {
|
||||
"version": "2.0.0-rc.5",
|
||||
"resolved": "https://registry.npmjs.org/vue-toastification/-/vue-toastification-2.0.0-rc.5.tgz",
|
||||
"integrity": "sha512-q73e5jy6gucEO/U+P48hqX+/qyXDozAGmaGgLFm5tXX4wJBcVsnGp4e/iJqlm9xzHETYOilUuwOUje2Qg1JdwA==",
|
||||
"peerDependencies": {
|
||||
"typescript": "*"
|
||||
"vue": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/vue-tsc/node_modules/lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/vue-tsc/node_modules/semver": {
|
||||
"version": "7.5.4",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
|
||||
"integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"lru-cache": "^6.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/vue-tsc/node_modules/yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/w3c-xmlserializer": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz",
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
"scripts": {
|
||||
"dev": "vite dev",
|
||||
"serve": "vite serve",
|
||||
"build": "vue-tsc -p ./tsconfig.json --noEmit && vite build --emptyOutDir",
|
||||
"build": "vite build",
|
||||
"watch": "vite build --watch",
|
||||
"clean": "find ./dist -maxdepth 1 -mindepth 1 ! -name '.gitkeep' -exec rm -r {} +",
|
||||
"lint": "eslint --ext .vue,.js src/",
|
||||
@ -14,7 +14,6 @@
|
||||
"format": "prettier --write ."
|
||||
},
|
||||
"dependencies": {
|
||||
"@vue/compat": "^3.3.4",
|
||||
"@vueuse/core": "^10.4.1",
|
||||
"ace-builds": "^1.24.1",
|
||||
"clipboard": "^2.0.11",
|
||||
@ -27,7 +26,6 @@
|
||||
"material-icons": "^1.13.10",
|
||||
"moment": "^2.29.4",
|
||||
"normalize.css": "^8.0.1",
|
||||
"noty": "^3.2.0-beta",
|
||||
"pinia": "^2.1.6",
|
||||
"pretty-bytes": "^6.1.1",
|
||||
"qrcode.vue": "^3.4.1",
|
||||
@ -37,11 +35,10 @@
|
||||
"vue-i18n": "^9.2.2",
|
||||
"vue-lazyload": "^3.0.0",
|
||||
"vue-router": "^4.2.4",
|
||||
"vue-simple-progress": "^1.1.1"
|
||||
"vue-toastification": "^2.0.0-rc.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@intlify/unplugin-vue-i18n": "^0.12.3",
|
||||
"@types/node": "^20.5.9",
|
||||
"@vitejs/plugin-legacy": "^4.1.1",
|
||||
"@vitejs/plugin-vue": "^4.3.3",
|
||||
"@vue/eslint-config-prettier": "^8.0.0",
|
||||
@ -53,15 +50,8 @@
|
||||
"postcss": "^8.4.28",
|
||||
"prettier": "^3.0.2",
|
||||
"terser": "^5.19.2",
|
||||
"typescript": "^5.2.2",
|
||||
"vite": "^4.4.9",
|
||||
"vite-plugin-compression2": "^0.10.4",
|
||||
"vite-plugin-rewrite-all": "^1.0.1",
|
||||
"vue-tsc": "^1.8.10"
|
||||
},
|
||||
"browserslist": [
|
||||
"> 1%",
|
||||
"last 2 versions",
|
||||
"not ie < 11"
|
||||
]
|
||||
"vite-plugin-rewrite-all": "^1.0.1"
|
||||
}
|
||||
}
|
||||
|
||||
41
frontend/src/components/CustomToast.vue
Normal file
41
frontend/src/components/CustomToast.vue
Normal file
@ -0,0 +1,41 @@
|
||||
<template>
|
||||
<div class="t-container">
|
||||
<span>{{ message }}</span>
|
||||
<button v-if="isReport" class="action" @click.stop="clicked">
|
||||
{{ reportText }}
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "error-toast",
|
||||
props: ["message", "reportText", "isReport"],
|
||||
methods: {
|
||||
clicked() {
|
||||
window.open(
|
||||
"https://github.com/filebrowser/filebrowser/issues/new/choose"
|
||||
);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.t-container {
|
||||
width: 100%;
|
||||
padding: 5px 0;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
.action {
|
||||
text-align: center;
|
||||
height: 40px;
|
||||
padding: 0 10px;
|
||||
border-radius: 5px;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
border: thin solid currentColor;
|
||||
}
|
||||
</style>
|
||||
223
frontend/src/components/ProgressBar.vue
Normal file
223
frontend/src/components/ProgressBar.vue
Normal file
@ -0,0 +1,223 @@
|
||||
<!-- This component taken directly from vue-simple-progress
|
||||
since it didnt support Vue 3 but the component itself does
|
||||
https://raw.githubusercontent.com/dzwillia/vue-simple-progress/master/src/components/Progress.vue -->
|
||||
<template>
|
||||
<div>
|
||||
<div
|
||||
class="vue-simple-progress-text"
|
||||
:style="text_style"
|
||||
v-if="text.length > 0 && textPosition == 'top'"
|
||||
>
|
||||
{{ text }}
|
||||
</div>
|
||||
<div class="vue-simple-progress" :style="progress_style">
|
||||
<div
|
||||
class="vue-simple-progress-text"
|
||||
:style="text_style"
|
||||
v-if="text.length > 0 && textPosition == 'middle'"
|
||||
>
|
||||
{{ text }}
|
||||
</div>
|
||||
<div
|
||||
style="position: relative; left: -9999px"
|
||||
:style="text_style"
|
||||
v-if="text.length > 0 && textPosition == 'inside'"
|
||||
>
|
||||
{{ text }}
|
||||
</div>
|
||||
<div class="vue-simple-progress-bar" :style="bar_style">
|
||||
<div
|
||||
:style="text_style"
|
||||
v-if="text.length > 0 && textPosition == 'inside'"
|
||||
>
|
||||
{{ text }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="vue-simple-progress-text"
|
||||
:style="text_style"
|
||||
v-if="text.length > 0 && textPosition == 'bottom'"
|
||||
>
|
||||
{{ text }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
var isNumber = function (n) {
|
||||
return !isNaN(parseFloat(n)) && isFinite(n);
|
||||
};
|
||||
|
||||
export default {
|
||||
name: "progress-bar",
|
||||
props: {
|
||||
val: {
|
||||
default: 0,
|
||||
},
|
||||
max: {
|
||||
default: 100,
|
||||
},
|
||||
size: {
|
||||
// either a number (pixel width/height) or 'tiny', 'small',
|
||||
// 'medium', 'large', 'huge', 'massive' for common sizes
|
||||
default: 3,
|
||||
},
|
||||
"bg-color": {
|
||||
type: String,
|
||||
default: "#eee",
|
||||
},
|
||||
"bar-color": {
|
||||
type: String,
|
||||
default: "#2196f3", // match .blue color to Material Design's 'Blue 500' color
|
||||
},
|
||||
"bar-transition": {
|
||||
type: String,
|
||||
default: "all 0.5s ease",
|
||||
},
|
||||
"bar-border-radius": {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
spacing: {
|
||||
type: Number,
|
||||
default: 4,
|
||||
},
|
||||
text: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
"text-align": {
|
||||
type: String,
|
||||
default: "center", // 'left', 'right'
|
||||
},
|
||||
"text-position": {
|
||||
type: String,
|
||||
default: "bottom", // 'bottom', 'top', 'middle', 'inside'
|
||||
},
|
||||
"font-size": {
|
||||
type: Number,
|
||||
default: 13,
|
||||
},
|
||||
"text-fg-color": {
|
||||
type: String,
|
||||
default: "#222",
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
pct() {
|
||||
var pct = (this.val / this.max) * 100;
|
||||
pct = pct.toFixed(2);
|
||||
return Math.min(pct, this.max);
|
||||
},
|
||||
size_px() {
|
||||
switch (this.size) {
|
||||
case "tiny":
|
||||
return 2;
|
||||
case "small":
|
||||
return 4;
|
||||
case "medium":
|
||||
return 8;
|
||||
case "large":
|
||||
return 12;
|
||||
case "big":
|
||||
return 16;
|
||||
case "huge":
|
||||
return 32;
|
||||
case "massive":
|
||||
return 64;
|
||||
}
|
||||
|
||||
return isNumber(this.size) ? this.size : 32;
|
||||
},
|
||||
text_padding() {
|
||||
switch (this.size) {
|
||||
case "tiny":
|
||||
case "small":
|
||||
case "medium":
|
||||
case "large":
|
||||
case "big":
|
||||
case "huge":
|
||||
case "massive":
|
||||
return Math.min(Math.max(Math.ceil(this.size_px / 8), 3), 12);
|
||||
}
|
||||
|
||||
return isNumber(this.spacing) ? this.spacing : 4;
|
||||
},
|
||||
text_font_size() {
|
||||
switch (this.size) {
|
||||
case "tiny":
|
||||
case "small":
|
||||
case "medium":
|
||||
case "large":
|
||||
case "big":
|
||||
case "huge":
|
||||
case "massive":
|
||||
return Math.min(Math.max(Math.ceil(this.size_px * 1.4), 11), 32);
|
||||
}
|
||||
|
||||
return isNumber(this.fontSize) ? this.fontSize : 13;
|
||||
},
|
||||
progress_style() {
|
||||
var style = {
|
||||
background: this.bgColor,
|
||||
};
|
||||
|
||||
if (this.textPosition == "middle" || this.textPosition == "inside") {
|
||||
style["position"] = "relative";
|
||||
style["min-height"] = this.size_px + "px";
|
||||
style["z-index"] = "-2";
|
||||
}
|
||||
|
||||
if (this.barBorderRadius > 0) {
|
||||
style["border-radius"] = this.barBorderRadius + "px";
|
||||
}
|
||||
|
||||
return style;
|
||||
},
|
||||
bar_style() {
|
||||
var style = {
|
||||
background: this.barColor,
|
||||
width: this.pct + "%",
|
||||
height: this.size_px + "px",
|
||||
transition: this.barTransition,
|
||||
};
|
||||
|
||||
if (this.barBorderRadius > 0) {
|
||||
style["border-radius"] = this.barBorderRadius + "px";
|
||||
}
|
||||
|
||||
if (this.textPosition == "middle" || this.textPosition == "inside") {
|
||||
style["position"] = "absolute";
|
||||
style["top"] = "0";
|
||||
style["height"] = "100%";
|
||||
(style["min-height"] = this.size_px + "px"), (style["z-index"] = "-1");
|
||||
}
|
||||
|
||||
return style;
|
||||
},
|
||||
text_style() {
|
||||
var style = {
|
||||
color: this.textFgColor,
|
||||
"font-size": this.text_font_size + "px",
|
||||
"text-align": this.textAlign,
|
||||
};
|
||||
|
||||
if (
|
||||
this.textPosition == "top" ||
|
||||
this.textPosition == "middle" ||
|
||||
this.textPosition == "inside"
|
||||
)
|
||||
style["padding-bottom"] = this.text_padding + "px";
|
||||
if (
|
||||
this.textPosition == "bottom" ||
|
||||
this.textPosition == "middle" ||
|
||||
this.textPosition == "inside"
|
||||
)
|
||||
style["padding-top"] = this.text_padding + "px";
|
||||
|
||||
return style;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@ -82,9 +82,7 @@
|
||||
|
||||
<div
|
||||
class="credits"
|
||||
v-if="
|
||||
$router.currentRoute.path?.includes('/files/') && !disableUsedPercentage
|
||||
"
|
||||
v-if="isFiles && !disableUsedPercentage"
|
||||
style="width: 90%; margin: 2em 2.5em 3em 2.5em"
|
||||
>
|
||||
<progress-bar :val="usage.usedPercentage" size="small"></progress-bar>
|
||||
@ -112,8 +110,10 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { reactive } from "vue";
|
||||
import { mapActions, mapState } from "pinia";
|
||||
import { useAuthStore } from "@/stores/auth";
|
||||
import { useFileStore } from "@/stores/file";
|
||||
import { useLayoutStore } from "@/stores/layout";
|
||||
|
||||
import * as auth from "@/utils/auth";
|
||||
@ -126,17 +126,24 @@ import {
|
||||
loginPage,
|
||||
} from "@/utils/constants";
|
||||
import { files as api } from "@/api";
|
||||
import ProgressBar from "vue-simple-progress";
|
||||
import ProgressBar from "@/components/ProgressBar.vue";
|
||||
import prettyBytes from "pretty-bytes";
|
||||
|
||||
const USAGE_DEFAULT = { used: "0 B", total: "0 B", usedPercentage: 0 };
|
||||
|
||||
export default {
|
||||
name: "sidebar",
|
||||
setup() {
|
||||
const usage = reactive(USAGE_DEFAULT);
|
||||
return { usage };
|
||||
},
|
||||
components: {
|
||||
ProgressBar,
|
||||
},
|
||||
inject: ["$showError"],
|
||||
computed: {
|
||||
...mapState(useAuthStore, ["user", "isLoggedIn"]),
|
||||
...mapState(useFileStore, ["isFiles", "reload"]),
|
||||
...mapState(useLayoutStore, ["show"]),
|
||||
active() {
|
||||
return this.show === "sidebar";
|
||||
@ -147,36 +154,28 @@ export default {
|
||||
disableUsedPercentage: () => disableUsedPercentage,
|
||||
canLogout: () => !noAuth && loginPage,
|
||||
},
|
||||
asyncComputed: {
|
||||
usage: {
|
||||
async get() {
|
||||
let path = this.$route.path.endsWith("/")
|
||||
? this.$route.path
|
||||
: this.$route.path + "/";
|
||||
let usageStats = { used: 0, total: 0, usedPercentage: 0 };
|
||||
if (this.disableUsedPercentage) {
|
||||
return usageStats;
|
||||
}
|
||||
try {
|
||||
let usage = await api.usage(path);
|
||||
usageStats = {
|
||||
used: prettyBytes(usage.used, { binary: true }),
|
||||
total: prettyBytes(usage.total, { binary: true }),
|
||||
usedPercentage: Math.round((usage.used / usage.total) * 100),
|
||||
};
|
||||
} catch (error) {
|
||||
this.$showError(error);
|
||||
}
|
||||
return usageStats;
|
||||
},
|
||||
default: { used: "0 B", total: "0 B", usedPercentage: 0 },
|
||||
shouldUpdate() {
|
||||
return this.$router.currentRoute.path.includes("/files/");
|
||||
},
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
...mapActions(useLayoutStore, ["closeHovers", "showHover"]),
|
||||
async fetchUsage() {
|
||||
let path = this.$route.path.endsWith("/")
|
||||
? this.$route.path
|
||||
: this.$route.path + "/";
|
||||
let usageStats = USAGE_DEFAULT;
|
||||
if (this.disableUsedPercentage) {
|
||||
return Object.assign(this.usage, usageStats);
|
||||
}
|
||||
try {
|
||||
let usage = await api.usage(path);
|
||||
usageStats = {
|
||||
used: prettyBytes(usage.used, { binary: true }),
|
||||
total: prettyBytes(usage.total, { binary: true }),
|
||||
usedPercentage: Math.round((usage.used / usage.total) * 100),
|
||||
};
|
||||
} catch (error) {
|
||||
this.$showError(error);
|
||||
}
|
||||
return Object.assign(this.usage, usageStats);
|
||||
},
|
||||
toRoot() {
|
||||
this.$router.push({ path: "/files" });
|
||||
this.closeHovers();
|
||||
@ -190,5 +189,10 @@ export default {
|
||||
},
|
||||
logout: auth.logout,
|
||||
},
|
||||
watch: {
|
||||
isFiles(newValue) {
|
||||
newValue && this.fetchUsage();
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@ -48,9 +48,6 @@ import * as upload from "@/utils/upload";
|
||||
|
||||
export default {
|
||||
name: "item",
|
||||
compatConfig: {
|
||||
ATTR_FALSE_VALUE: "suppress-warning",
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
touches: 0,
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
@import "normalize.css/normalize.css";
|
||||
@import "noty/lib/noty.css";
|
||||
@import "noty/lib/themes/mint.css";
|
||||
@import "vue-toastification/dist/index.css";
|
||||
@import "./_variables.css";
|
||||
@import "./_buttons.css";
|
||||
@import "./_inputs.css";
|
||||
|
||||
@ -1,14 +1,12 @@
|
||||
import { disableExternal } from "@/utils/constants";
|
||||
import { createApp } from "vue";
|
||||
import Noty from "noty";
|
||||
import VueLazyload from "vue-lazyload";
|
||||
import Toast, { useToast } from "vue-toastification";
|
||||
import createPinia from "@/stores";
|
||||
import router from "@/router";
|
||||
import i18n from "@/i18n";
|
||||
import i18n, { rtlLanguages } from "@/i18n";
|
||||
import App from "@/App.vue";
|
||||
import '@/css/styles.css'
|
||||
|
||||
// configureCompat({ RENDER_FUNCTION: false });
|
||||
import CustomToast from "@/components/CustomToast.vue";
|
||||
|
||||
import dayjs from "dayjs";
|
||||
import localizedFormat from "dayjs/plugin/localizedFormat";
|
||||
@ -24,6 +22,11 @@ const pinia = createPinia(router);
|
||||
const app = createApp(App);
|
||||
|
||||
app.use(VueLazyload);
|
||||
app.use(Toast, {
|
||||
transition: "Vue-Toastification__bounce",
|
||||
maxToasts: 10,
|
||||
newestOnTop: true,
|
||||
});
|
||||
|
||||
app.use(i18n);
|
||||
app.use(pinia);
|
||||
@ -44,54 +47,51 @@ app.directive("focus", {
|
||||
},
|
||||
});
|
||||
|
||||
const notyDefault: Noty.Options = {
|
||||
type: "info",
|
||||
layout: "bottomCenter",
|
||||
timeout: 1000,
|
||||
progressBar: true,
|
||||
const toastConfig = {
|
||||
position: "bottom-center",
|
||||
timeout: 4000,
|
||||
closeOnClick: true,
|
||||
pauseOnFocusLoss: true,
|
||||
pauseOnHover: true,
|
||||
draggable: true,
|
||||
draggablePercent: 0.6,
|
||||
showCloseButtonOnHover: false,
|
||||
hideProgressBar: false,
|
||||
closeButton: "button",
|
||||
icon: true,
|
||||
};
|
||||
|
||||
// app.provide("$noty", (opts) => {
|
||||
// new Noty(Object.assign({}, notyDefault, opts)).show();
|
||||
// });
|
||||
|
||||
app.provide("$showSuccess", (message: any) => {
|
||||
new Noty(
|
||||
Object.assign({}, notyDefault, {
|
||||
text: message,
|
||||
type: "success",
|
||||
})
|
||||
).show();
|
||||
app.provide("$showSuccess", (message) => {
|
||||
const $toast = useToast();
|
||||
$toast.success(
|
||||
{
|
||||
component: CustomToast,
|
||||
props: {
|
||||
message: message,
|
||||
},
|
||||
},
|
||||
{ ...toastConfig, rtl: rtlLanguages.includes(i18n.global.locale) }
|
||||
);
|
||||
});
|
||||
|
||||
app.provide("$showError", (error: any, displayReport = true) => {
|
||||
let btns = [
|
||||
// @ts-ignore
|
||||
Noty.button(i18n.global.t("buttons.close"), "", function () {
|
||||
n.close();
|
||||
}),
|
||||
];
|
||||
|
||||
if (!disableExternal && displayReport) {
|
||||
btns.unshift(
|
||||
Noty.button(i18n.global.t("buttons.reportIssue"), "", function () {
|
||||
window.open(
|
||||
"https://github.com/filebrowser/filebrowser/issues/new/choose"
|
||||
);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
let n = new Noty(
|
||||
Object.assign({}, notyDefault, {
|
||||
text: error.message || error,
|
||||
type: "error",
|
||||
timeout: null,
|
||||
buttons: btns,
|
||||
})
|
||||
app.provide("$showError", (error, displayReport = true) => {
|
||||
const $toast = useToast();
|
||||
$toast.error(
|
||||
{
|
||||
component: CustomToast,
|
||||
props: {
|
||||
message: error.message || error,
|
||||
isReport: !disableExternal && displayReport,
|
||||
// TODO: i couldnt use $t inside the component
|
||||
reportText: i18n.global.t("buttons.reportIssue"),
|
||||
},
|
||||
},
|
||||
{
|
||||
...toastConfig,
|
||||
timeout: 0,
|
||||
rtl: rtlLanguages.includes(i18n.global.locale),
|
||||
}
|
||||
);
|
||||
|
||||
n.show();
|
||||
});
|
||||
|
||||
router.isReady().then(() => app.mount("#app"));
|
||||
|
||||
@ -27,6 +27,7 @@ export const useUploadStore = defineStore("upload", {
|
||||
progress: [],
|
||||
queue: [],
|
||||
uploads: {},
|
||||
error: null,
|
||||
}),
|
||||
getters: {
|
||||
// user and jwt getter removed, no longer needed
|
||||
@ -78,6 +79,9 @@ export const useUploadStore = defineStore("upload", {
|
||||
const { id, loaded } = obj
|
||||
this.progress[id] = loaded;
|
||||
},
|
||||
setError(error) {
|
||||
this.error = error;
|
||||
},
|
||||
reset() {
|
||||
this.id = 0;
|
||||
this.sizes = [];
|
||||
@ -140,8 +144,7 @@ export const useUploadStore = defineStore("upload", {
|
||||
this.moveJob();
|
||||
|
||||
if (item.file.isDir) {
|
||||
// TODO: find a way to display notification
|
||||
await api.post(item.path).catch(console.error);
|
||||
await api.post(item.path).catch(this.setError);
|
||||
} else {
|
||||
let onUpload = throttle(
|
||||
(event) =>
|
||||
@ -153,10 +156,9 @@ export const useUploadStore = defineStore("upload", {
|
||||
{ leading: true, trailing: false }
|
||||
);
|
||||
|
||||
// TODO: find a way to display notification
|
||||
await api
|
||||
.post(item.path, item.file, item.overwrite, onUpload)
|
||||
.catch(console.error);
|
||||
.catch(this.setError);
|
||||
}
|
||||
|
||||
this.finishUpload(item);
|
||||
|
||||
@ -25,12 +25,13 @@ import { files as api } from "@/api";
|
||||
import { mapState, mapActions, mapWritableState } from "pinia";
|
||||
import { useFileStore } from "@/stores/file";
|
||||
import { useLayoutStore } from "@/stores/layout";
|
||||
import { useUploadStore } from "@/stores/upload";
|
||||
|
||||
import HeaderBar from "@/components/header/HeaderBar.vue";
|
||||
import Breadcrumbs from "@/components/Breadcrumbs.vue";
|
||||
import Errors from "@/views/Errors.vue";
|
||||
import Preview from "@/views/files/Preview.vue";
|
||||
import Listing from "@/views/files/Listing.vue";
|
||||
import FileListing from "@/views/files/FileListing.vue";
|
||||
|
||||
function clean(path) {
|
||||
return path.endsWith("/") ? path.slice(0, -1) : path;
|
||||
@ -43,7 +44,7 @@ export default {
|
||||
Breadcrumbs,
|
||||
Errors,
|
||||
Preview,
|
||||
Listing,
|
||||
FileListing,
|
||||
Editor: defineAsyncComponent(() => import("@/views/files/Editor.vue")),
|
||||
},
|
||||
data: function () {
|
||||
@ -52,6 +53,7 @@ export default {
|
||||
width: window.innerWidth,
|
||||
};
|
||||
},
|
||||
inject: ["$showError"],
|
||||
computed: {
|
||||
...mapWritableState(useFileStore, [
|
||||
"req",
|
||||
@ -62,13 +64,16 @@ export default {
|
||||
]),
|
||||
...mapState(useLayoutStore, ["show", "showShell"]),
|
||||
...mapWritableState(useLayoutStore, ["loading"]),
|
||||
...mapState(useUploadStore, {
|
||||
uploadError: "error",
|
||||
}),
|
||||
currentView() {
|
||||
if (this.req.type == undefined) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (this.req.isDir) {
|
||||
return "listing";
|
||||
return "file-listing";
|
||||
} else if (
|
||||
this.req.type === "text" ||
|
||||
this.req.type === "textImmutable"
|
||||
@ -89,6 +94,9 @@ export default {
|
||||
this.fetchData();
|
||||
}
|
||||
},
|
||||
uploadError(newValue, oldValue) {
|
||||
newValue && newValue !== oldValue && this.$showError(this.uploadError);
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.isFiles = true;
|
||||
|
||||
@ -267,7 +267,6 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Vue from "vue";
|
||||
import { mapState, mapWritableState, mapActions, mapStores } from "pinia";
|
||||
import { useAuthStore } from "@/stores/auth";
|
||||
import { useClipboardStore } from "@/stores/clipboard";
|
||||
@ -287,7 +286,7 @@ import Search from "@/components/Search.vue";
|
||||
import Item from "@/components/files/ListingItem.vue";
|
||||
|
||||
export default {
|
||||
name: "listing",
|
||||
name: "file-listing",
|
||||
components: {
|
||||
HeaderBar,
|
||||
Action,
|
||||
@ -403,7 +402,7 @@ export default {
|
||||
this.showLimit = 50;
|
||||
|
||||
// Ensures that the listing is displayed
|
||||
Vue.nextTick(() => {
|
||||
this.$nextTick(() => {
|
||||
// How much every listing item affects the window height
|
||||
this.setItemWeight();
|
||||
|
||||
@ -97,7 +97,7 @@ export default {
|
||||
},
|
||||
inject: ["$showError", "$showSuccess"],
|
||||
computed: {
|
||||
...mapState(useAuthStore, ["user"]),
|
||||
...mapState(useAuthStore, { sUser: "user" }),
|
||||
...mapState(useLayoutStore, ["show"]),
|
||||
...mapWritableState(useLayoutStore, ["loading"]),
|
||||
isNew() {
|
||||
@ -170,7 +170,7 @@ export default {
|
||||
} else {
|
||||
await api.update(user);
|
||||
|
||||
if (user.id === this.user.id) {
|
||||
if (user.id === this.sUser.id) {
|
||||
this.setUser({ ...cloneDeep(user) });
|
||||
}
|
||||
|
||||
|
||||
@ -2,27 +2,24 @@ import path from "node:path";
|
||||
import { defineConfig } from "vite";
|
||||
import vue from "@vitejs/plugin-vue";
|
||||
import VueI18nPlugin from "@intlify/unplugin-vue-i18n/vite";
|
||||
import legacy from "@vitejs/plugin-legacy";
|
||||
import { compression } from "vite-plugin-compression2";
|
||||
import pluginRewriteAll from "vite-plugin-rewrite-all";
|
||||
|
||||
const plugins = [
|
||||
vue({
|
||||
template: {
|
||||
compilerOptions: {
|
||||
compatConfig: {
|
||||
MODE: 3,
|
||||
},
|
||||
},
|
||||
},
|
||||
vue(),
|
||||
VueI18nPlugin(),
|
||||
legacy({
|
||||
// defaults already drop IE support
|
||||
targets: ["defaults"],
|
||||
}),
|
||||
VueI18nPlugin({}),
|
||||
compression({ include: /\.js$/i, deleteOriginalAssets: true }),
|
||||
pluginRewriteAll(), // fixes 404 error with paths containing dot in dev server
|
||||
];
|
||||
|
||||
const resolve = {
|
||||
alias: {
|
||||
vue: "@vue/compat",
|
||||
// vue: "@vue/compat",
|
||||
"@/": `${path.resolve(__dirname, "src")}/`,
|
||||
},
|
||||
};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user