Merge remote-tracking branch 'kloon15/vue3' into vue3

This commit is contained in:
Joep 2023-09-08 21:33:19 +02:00
commit ee619adda3
13 changed files with 388 additions and 334 deletions

View File

@ -8,7 +8,6 @@
"name": "filebrowser-frontend", "name": "filebrowser-frontend",
"version": "2.0.0", "version": "2.0.0",
"dependencies": { "dependencies": {
"@vue/compat": "^3.3.4",
"@vueuse/core": "^10.4.1", "@vueuse/core": "^10.4.1",
"ace-builds": "^1.24.1", "ace-builds": "^1.24.1",
"clipboard": "^2.0.11", "clipboard": "^2.0.11",
@ -21,7 +20,6 @@
"material-icons": "^1.13.10", "material-icons": "^1.13.10",
"moment": "^2.29.4", "moment": "^2.29.4",
"normalize.css": "^8.0.1", "normalize.css": "^8.0.1",
"noty": "^3.2.0-beta",
"pinia": "^2.1.6", "pinia": "^2.1.6",
"pretty-bytes": "^6.1.1", "pretty-bytes": "^6.1.1",
"qrcode.vue": "^3.4.1", "qrcode.vue": "^3.4.1",
@ -31,11 +29,10 @@
"vue-i18n": "^9.2.2", "vue-i18n": "^9.2.2",
"vue-lazyload": "^3.0.0", "vue-lazyload": "^3.0.0",
"vue-router": "^4.2.4", "vue-router": "^4.2.4",
"vue-simple-progress": "^1.1.1" "vue-toastification": "^2.0.0-rc.5"
}, },
"devDependencies": { "devDependencies": {
"@intlify/unplugin-vue-i18n": "^0.12.3", "@intlify/unplugin-vue-i18n": "^0.12.3",
"@types/node": "^20.5.9",
"@vitejs/plugin-legacy": "^4.1.1", "@vitejs/plugin-legacy": "^4.1.1",
"@vitejs/plugin-vue": "^4.3.3", "@vitejs/plugin-vue": "^4.3.3",
"@vue/eslint-config-prettier": "^8.0.0", "@vue/eslint-config-prettier": "^8.0.0",
@ -47,11 +44,9 @@
"postcss": "^8.4.28", "postcss": "^8.4.28",
"prettier": "^3.0.2", "prettier": "^3.0.2",
"terser": "^5.19.2", "terser": "^5.19.2",
"typescript": "^5.2.2",
"vite": "^4.4.9", "vite": "^4.4.9",
"vite-plugin-compression2": "^0.10.4", "vite-plugin-compression2": "^0.10.4",
"vite-plugin-rewrite-all": "^1.0.1", "vite-plugin-rewrite-all": "^1.0.1"
"vue-tsc": "^1.8.10"
} }
}, },
"node_modules/@aashutoshrathi/word-wrap": { "node_modules/@aashutoshrathi/word-wrap": {
@ -2493,12 +2488,6 @@
"integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==", "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==",
"dev": true "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": { "node_modules/@types/web-bluetooth": {
"version": "0.0.17", "version": "0.0.17",
"resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.17.tgz", "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.17.tgz",
@ -2542,46 +2531,6 @@
"vue": "^3.2.25" "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": { "node_modules/@vue/compiler-core": {
"version": "3.3.4", "version": "3.3.4",
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.3.4.tgz", "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.3.4.tgz",
@ -2647,54 +2596,6 @@
"prettier": ">= 3.0.0" "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": { "node_modules/@vue/reactivity": {
"version": "3.3.4", "version": "3.3.4",
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.3.4.tgz", "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", "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.4.tgz",
"integrity": "sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ==" "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": { "node_modules/@vueuse/core": {
"version": "10.4.1", "version": "10.4.1",
"resolved": "https://registry.npmjs.org/@vueuse/core/-/core-10.4.1.tgz", "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", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.9.tgz",
"integrity": "sha512-QvzAURSbQ0pKdIye2txOzNaHmxtUBXerpY0FJsFXUMKbIZeFm5ht1LS/jFsrncjnmtv8HsG0W2g6c0zUjZWmpA==" "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": { "node_modules/debug": {
"version": "4.3.4", "version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
@ -4286,15 +4171,6 @@
"node": ">=4" "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": { "node_modules/html-encoding-sniffer": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", "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==", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true "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": { "node_modules/nanoid": {
"version": "3.3.6", "version": "3.3.6",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", "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", "resolved": "https://registry.npmjs.org/normalize.css/-/normalize.css-8.0.1.tgz",
"integrity": "sha512-qizSNPO93t1YUuUhP22btGOo3chcvDFqFaj2TRybP0DMxkHOCTYwp3n34fel4a31ORXy4m1Xq0Gyqpb5m33qIg==" "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": { "node_modules/npm-run-path": {
"version": "5.1.0", "version": "5.1.0",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", "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" "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": { "node_modules/ufo": {
"version": "1.3.0", "version": "1.3.0",
"resolved": "https://registry.npmjs.org/ufo/-/ufo-1.3.0.tgz", "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.3.0.tgz",
@ -6423,71 +6274,14 @@
"vue": "^3.2.0" "vue": "^3.2.0"
} }
}, },
"node_modules/vue-simple-progress": { "node_modules/vue-toastification": {
"version": "1.1.1", "version": "2.0.0-rc.5",
"resolved": "https://registry.npmjs.org/vue-simple-progress/-/vue-simple-progress-1.1.1.tgz", "resolved": "https://registry.npmjs.org/vue-toastification/-/vue-toastification-2.0.0-rc.5.tgz",
"integrity": "sha512-ltLWYBA5eVQHWyt1NwZeGeK0VQC69JVh1oqUdro0po7r8Hc8SEMEyEfuwyCO4s27h5I3jbD99BKKkyPSQZgoZA==" "integrity": "sha512-q73e5jy6gucEO/U+P48hqX+/qyXDozAGmaGgLFm5tXX4wJBcVsnGp4e/iJqlm9xzHETYOilUuwOUje2Qg1JdwA==",
},
"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"
},
"peerDependencies": { "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": { "node_modules/w3c-xmlserializer": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz",

View File

@ -6,7 +6,7 @@
"scripts": { "scripts": {
"dev": "vite dev", "dev": "vite dev",
"serve": "vite serve", "serve": "vite serve",
"build": "vue-tsc -p ./tsconfig.json --noEmit && vite build --emptyOutDir", "build": "vite build",
"watch": "vite build --watch", "watch": "vite build --watch",
"clean": "find ./dist -maxdepth 1 -mindepth 1 ! -name '.gitkeep' -exec rm -r {} +", "clean": "find ./dist -maxdepth 1 -mindepth 1 ! -name '.gitkeep' -exec rm -r {} +",
"lint": "eslint --ext .vue,.js src/", "lint": "eslint --ext .vue,.js src/",
@ -14,7 +14,6 @@
"format": "prettier --write ." "format": "prettier --write ."
}, },
"dependencies": { "dependencies": {
"@vue/compat": "^3.3.4",
"@vueuse/core": "^10.4.1", "@vueuse/core": "^10.4.1",
"ace-builds": "^1.24.1", "ace-builds": "^1.24.1",
"clipboard": "^2.0.11", "clipboard": "^2.0.11",
@ -27,7 +26,6 @@
"material-icons": "^1.13.10", "material-icons": "^1.13.10",
"moment": "^2.29.4", "moment": "^2.29.4",
"normalize.css": "^8.0.1", "normalize.css": "^8.0.1",
"noty": "^3.2.0-beta",
"pinia": "^2.1.6", "pinia": "^2.1.6",
"pretty-bytes": "^6.1.1", "pretty-bytes": "^6.1.1",
"qrcode.vue": "^3.4.1", "qrcode.vue": "^3.4.1",
@ -37,11 +35,10 @@
"vue-i18n": "^9.2.2", "vue-i18n": "^9.2.2",
"vue-lazyload": "^3.0.0", "vue-lazyload": "^3.0.0",
"vue-router": "^4.2.4", "vue-router": "^4.2.4",
"vue-simple-progress": "^1.1.1" "vue-toastification": "^2.0.0-rc.5"
}, },
"devDependencies": { "devDependencies": {
"@intlify/unplugin-vue-i18n": "^0.12.3", "@intlify/unplugin-vue-i18n": "^0.12.3",
"@types/node": "^20.5.9",
"@vitejs/plugin-legacy": "^4.1.1", "@vitejs/plugin-legacy": "^4.1.1",
"@vitejs/plugin-vue": "^4.3.3", "@vitejs/plugin-vue": "^4.3.3",
"@vue/eslint-config-prettier": "^8.0.0", "@vue/eslint-config-prettier": "^8.0.0",
@ -53,15 +50,8 @@
"postcss": "^8.4.28", "postcss": "^8.4.28",
"prettier": "^3.0.2", "prettier": "^3.0.2",
"terser": "^5.19.2", "terser": "^5.19.2",
"typescript": "^5.2.2",
"vite": "^4.4.9", "vite": "^4.4.9",
"vite-plugin-compression2": "^0.10.4", "vite-plugin-compression2": "^0.10.4",
"vite-plugin-rewrite-all": "^1.0.1", "vite-plugin-rewrite-all": "^1.0.1"
"vue-tsc": "^1.8.10" }
},
"browserslist": [
"> 1%",
"last 2 versions",
"not ie < 11"
]
} }

View 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>

View 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>

View File

@ -82,9 +82,7 @@
<div <div
class="credits" class="credits"
v-if=" v-if="isFiles && !disableUsedPercentage"
$router.currentRoute.path?.includes('/files/') && !disableUsedPercentage
"
style="width: 90%; margin: 2em 2.5em 3em 2.5em" style="width: 90%; margin: 2em 2.5em 3em 2.5em"
> >
<progress-bar :val="usage.usedPercentage" size="small"></progress-bar> <progress-bar :val="usage.usedPercentage" size="small"></progress-bar>
@ -112,8 +110,10 @@
</template> </template>
<script> <script>
import { reactive } from "vue";
import { mapActions, mapState } from "pinia"; import { mapActions, mapState } from "pinia";
import { useAuthStore } from "@/stores/auth"; import { useAuthStore } from "@/stores/auth";
import { useFileStore } from "@/stores/file";
import { useLayoutStore } from "@/stores/layout"; import { useLayoutStore } from "@/stores/layout";
import * as auth from "@/utils/auth"; import * as auth from "@/utils/auth";
@ -126,17 +126,24 @@ import {
loginPage, loginPage,
} from "@/utils/constants"; } from "@/utils/constants";
import { files as api } from "@/api"; import { files as api } from "@/api";
import ProgressBar from "vue-simple-progress"; import ProgressBar from "@/components/ProgressBar.vue";
import prettyBytes from "pretty-bytes"; import prettyBytes from "pretty-bytes";
const USAGE_DEFAULT = { used: "0 B", total: "0 B", usedPercentage: 0 };
export default { export default {
name: "sidebar", name: "sidebar",
setup() {
const usage = reactive(USAGE_DEFAULT);
return { usage };
},
components: { components: {
ProgressBar, ProgressBar,
}, },
inject: ["$showError"], inject: ["$showError"],
computed: { computed: {
...mapState(useAuthStore, ["user", "isLoggedIn"]), ...mapState(useAuthStore, ["user", "isLoggedIn"]),
...mapState(useFileStore, ["isFiles", "reload"]),
...mapState(useLayoutStore, ["show"]), ...mapState(useLayoutStore, ["show"]),
active() { active() {
return this.show === "sidebar"; return this.show === "sidebar";
@ -147,15 +154,15 @@ export default {
disableUsedPercentage: () => disableUsedPercentage, disableUsedPercentage: () => disableUsedPercentage,
canLogout: () => !noAuth && loginPage, canLogout: () => !noAuth && loginPage,
}, },
asyncComputed: { methods: {
usage: { ...mapActions(useLayoutStore, ["closeHovers", "showHover"]),
async get() { async fetchUsage() {
let path = this.$route.path.endsWith("/") let path = this.$route.path.endsWith("/")
? this.$route.path ? this.$route.path
: this.$route.path + "/"; : this.$route.path + "/";
let usageStats = { used: 0, total: 0, usedPercentage: 0 }; let usageStats = USAGE_DEFAULT;
if (this.disableUsedPercentage) { if (this.disableUsedPercentage) {
return usageStats; return Object.assign(this.usage, usageStats);
} }
try { try {
let usage = await api.usage(path); let usage = await api.usage(path);
@ -167,16 +174,8 @@ export default {
} catch (error) { } catch (error) {
this.$showError(error); this.$showError(error);
} }
return usageStats; return Object.assign(this.usage, usageStats);
}, },
default: { used: "0 B", total: "0 B", usedPercentage: 0 },
shouldUpdate() {
return this.$router.currentRoute.path.includes("/files/");
},
},
},
methods: {
...mapActions(useLayoutStore, ["closeHovers", "showHover"]),
toRoot() { toRoot() {
this.$router.push({ path: "/files" }); this.$router.push({ path: "/files" });
this.closeHovers(); this.closeHovers();
@ -190,5 +189,10 @@ export default {
}, },
logout: auth.logout, logout: auth.logout,
}, },
watch: {
isFiles(newValue) {
newValue && this.fetchUsage();
},
},
}; };
</script> </script>

View File

@ -48,9 +48,6 @@ import * as upload from "@/utils/upload";
export default { export default {
name: "item", name: "item",
compatConfig: {
ATTR_FALSE_VALUE: "suppress-warning",
},
data: function () { data: function () {
return { return {
touches: 0, touches: 0,

View File

@ -1,6 +1,5 @@
@import "normalize.css/normalize.css"; @import "normalize.css/normalize.css";
@import "noty/lib/noty.css"; @import "vue-toastification/dist/index.css";
@import "noty/lib/themes/mint.css";
@import "./_variables.css"; @import "./_variables.css";
@import "./_buttons.css"; @import "./_buttons.css";
@import "./_inputs.css"; @import "./_inputs.css";

View File

@ -1,14 +1,12 @@
import { disableExternal } from "@/utils/constants"; import { disableExternal } from "@/utils/constants";
import { createApp } from "vue"; import { createApp } from "vue";
import Noty from "noty";
import VueLazyload from "vue-lazyload"; import VueLazyload from "vue-lazyload";
import Toast, { useToast } from "vue-toastification";
import createPinia from "@/stores"; import createPinia from "@/stores";
import router from "@/router"; import router from "@/router";
import i18n from "@/i18n"; import i18n, { rtlLanguages } from "@/i18n";
import App from "@/App.vue"; import App from "@/App.vue";
import '@/css/styles.css' import CustomToast from "@/components/CustomToast.vue";
// configureCompat({ RENDER_FUNCTION: false });
import dayjs from "dayjs"; import dayjs from "dayjs";
import localizedFormat from "dayjs/plugin/localizedFormat"; import localizedFormat from "dayjs/plugin/localizedFormat";
@ -24,6 +22,11 @@ const pinia = createPinia(router);
const app = createApp(App); const app = createApp(App);
app.use(VueLazyload); app.use(VueLazyload);
app.use(Toast, {
transition: "Vue-Toastification__bounce",
maxToasts: 10,
newestOnTop: true,
});
app.use(i18n); app.use(i18n);
app.use(pinia); app.use(pinia);
@ -44,54 +47,51 @@ app.directive("focus", {
}, },
}); });
const notyDefault: Noty.Options = { const toastConfig = {
type: "info", position: "bottom-center",
layout: "bottomCenter", timeout: 4000,
timeout: 1000, closeOnClick: true,
progressBar: true, pauseOnFocusLoss: true,
pauseOnHover: true,
draggable: true,
draggablePercent: 0.6,
showCloseButtonOnHover: false,
hideProgressBar: false,
closeButton: "button",
icon: true,
}; };
// app.provide("$noty", (opts) => { app.provide("$showSuccess", (message) => {
// new Noty(Object.assign({}, notyDefault, opts)).show(); const $toast = useToast();
// }); $toast.success(
{
app.provide("$showSuccess", (message: any) => { component: CustomToast,
new Noty( props: {
Object.assign({}, notyDefault, { message: message,
text: message, },
type: "success", },
}) { ...toastConfig, rtl: rtlLanguages.includes(i18n.global.locale) }
).show(); );
}); });
app.provide("$showError", (error: any, displayReport = true) => { app.provide("$showError", (error, displayReport = true) => {
let btns = [ const $toast = useToast();
// @ts-ignore $toast.error(
Noty.button(i18n.global.t("buttons.close"), "", function () { {
n.close(); component: CustomToast,
}), props: {
]; message: error.message || error,
isReport: !disableExternal && displayReport,
if (!disableExternal && displayReport) { // TODO: i couldnt use $t inside the component
btns.unshift( reportText: i18n.global.t("buttons.reportIssue"),
Noty.button(i18n.global.t("buttons.reportIssue"), "", function () { },
window.open( },
"https://github.com/filebrowser/filebrowser/issues/new/choose" {
); ...toastConfig,
}) timeout: 0,
); rtl: rtlLanguages.includes(i18n.global.locale),
} }
let n = new Noty(
Object.assign({}, notyDefault, {
text: error.message || error,
type: "error",
timeout: null,
buttons: btns,
})
); );
n.show();
}); });
router.isReady().then(() => app.mount("#app")); router.isReady().then(() => app.mount("#app"));

View File

@ -27,6 +27,7 @@ export const useUploadStore = defineStore("upload", {
progress: [], progress: [],
queue: [], queue: [],
uploads: {}, uploads: {},
error: null,
}), }),
getters: { getters: {
// user and jwt getter removed, no longer needed // user and jwt getter removed, no longer needed
@ -78,6 +79,9 @@ export const useUploadStore = defineStore("upload", {
const { id, loaded } = obj const { id, loaded } = obj
this.progress[id] = loaded; this.progress[id] = loaded;
}, },
setError(error) {
this.error = error;
},
reset() { reset() {
this.id = 0; this.id = 0;
this.sizes = []; this.sizes = [];
@ -140,8 +144,7 @@ export const useUploadStore = defineStore("upload", {
this.moveJob(); this.moveJob();
if (item.file.isDir) { if (item.file.isDir) {
// TODO: find a way to display notification await api.post(item.path).catch(this.setError);
await api.post(item.path).catch(console.error);
} else { } else {
let onUpload = throttle( let onUpload = throttle(
(event) => (event) =>
@ -153,10 +156,9 @@ export const useUploadStore = defineStore("upload", {
{ leading: true, trailing: false } { leading: true, trailing: false }
); );
// TODO: find a way to display notification
await api await api
.post(item.path, item.file, item.overwrite, onUpload) .post(item.path, item.file, item.overwrite, onUpload)
.catch(console.error); .catch(this.setError);
} }
this.finishUpload(item); this.finishUpload(item);

View File

@ -25,12 +25,13 @@ import { files as api } from "@/api";
import { mapState, mapActions, mapWritableState } from "pinia"; import { mapState, mapActions, mapWritableState } from "pinia";
import { useFileStore } from "@/stores/file"; import { useFileStore } from "@/stores/file";
import { useLayoutStore } from "@/stores/layout"; import { useLayoutStore } from "@/stores/layout";
import { useUploadStore } from "@/stores/upload";
import HeaderBar from "@/components/header/HeaderBar.vue"; import HeaderBar from "@/components/header/HeaderBar.vue";
import Breadcrumbs from "@/components/Breadcrumbs.vue"; import Breadcrumbs from "@/components/Breadcrumbs.vue";
import Errors from "@/views/Errors.vue"; import Errors from "@/views/Errors.vue";
import Preview from "@/views/files/Preview.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) { function clean(path) {
return path.endsWith("/") ? path.slice(0, -1) : path; return path.endsWith("/") ? path.slice(0, -1) : path;
@ -43,7 +44,7 @@ export default {
Breadcrumbs, Breadcrumbs,
Errors, Errors,
Preview, Preview,
Listing, FileListing,
Editor: defineAsyncComponent(() => import("@/views/files/Editor.vue")), Editor: defineAsyncComponent(() => import("@/views/files/Editor.vue")),
}, },
data: function () { data: function () {
@ -52,6 +53,7 @@ export default {
width: window.innerWidth, width: window.innerWidth,
}; };
}, },
inject: ["$showError"],
computed: { computed: {
...mapWritableState(useFileStore, [ ...mapWritableState(useFileStore, [
"req", "req",
@ -62,13 +64,16 @@ export default {
]), ]),
...mapState(useLayoutStore, ["show", "showShell"]), ...mapState(useLayoutStore, ["show", "showShell"]),
...mapWritableState(useLayoutStore, ["loading"]), ...mapWritableState(useLayoutStore, ["loading"]),
...mapState(useUploadStore, {
uploadError: "error",
}),
currentView() { currentView() {
if (this.req.type == undefined) { if (this.req.type == undefined) {
return null; return null;
} }
if (this.req.isDir) { if (this.req.isDir) {
return "listing"; return "file-listing";
} else if ( } else if (
this.req.type === "text" || this.req.type === "text" ||
this.req.type === "textImmutable" this.req.type === "textImmutable"
@ -89,6 +94,9 @@ export default {
this.fetchData(); this.fetchData();
} }
}, },
uploadError(newValue, oldValue) {
newValue && newValue !== oldValue && this.$showError(this.uploadError);
},
}, },
mounted() { mounted() {
this.isFiles = true; this.isFiles = true;

View File

@ -267,7 +267,6 @@
</template> </template>
<script> <script>
import Vue from "vue";
import { mapState, mapWritableState, mapActions, mapStores } from "pinia"; import { mapState, mapWritableState, mapActions, mapStores } from "pinia";
import { useAuthStore } from "@/stores/auth"; import { useAuthStore } from "@/stores/auth";
import { useClipboardStore } from "@/stores/clipboard"; import { useClipboardStore } from "@/stores/clipboard";
@ -287,7 +286,7 @@ import Search from "@/components/Search.vue";
import Item from "@/components/files/ListingItem.vue"; import Item from "@/components/files/ListingItem.vue";
export default { export default {
name: "listing", name: "file-listing",
components: { components: {
HeaderBar, HeaderBar,
Action, Action,
@ -403,7 +402,7 @@ export default {
this.showLimit = 50; this.showLimit = 50;
// Ensures that the listing is displayed // Ensures that the listing is displayed
Vue.nextTick(() => { this.$nextTick(() => {
// How much every listing item affects the window height // How much every listing item affects the window height
this.setItemWeight(); this.setItemWeight();

View File

@ -97,7 +97,7 @@ export default {
}, },
inject: ["$showError", "$showSuccess"], inject: ["$showError", "$showSuccess"],
computed: { computed: {
...mapState(useAuthStore, ["user"]), ...mapState(useAuthStore, { sUser: "user" }),
...mapState(useLayoutStore, ["show"]), ...mapState(useLayoutStore, ["show"]),
...mapWritableState(useLayoutStore, ["loading"]), ...mapWritableState(useLayoutStore, ["loading"]),
isNew() { isNew() {
@ -170,7 +170,7 @@ export default {
} else { } else {
await api.update(user); await api.update(user);
if (user.id === this.user.id) { if (user.id === this.sUser.id) {
this.setUser({ ...cloneDeep(user) }); this.setUser({ ...cloneDeep(user) });
} }

View File

@ -2,27 +2,24 @@ import path from "node:path";
import { defineConfig } from "vite"; import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue"; import vue from "@vitejs/plugin-vue";
import VueI18nPlugin from "@intlify/unplugin-vue-i18n/vite"; import VueI18nPlugin from "@intlify/unplugin-vue-i18n/vite";
import legacy from "@vitejs/plugin-legacy";
import { compression } from "vite-plugin-compression2"; import { compression } from "vite-plugin-compression2";
import pluginRewriteAll from "vite-plugin-rewrite-all"; import pluginRewriteAll from "vite-plugin-rewrite-all";
const plugins = [ const plugins = [
vue({ vue(),
template: { VueI18nPlugin(),
compilerOptions: { legacy({
compatConfig: { // defaults already drop IE support
MODE: 3, targets: ["defaults"],
},
},
},
}), }),
VueI18nPlugin({}),
compression({ include: /\.js$/i, deleteOriginalAssets: true }), compression({ include: /\.js$/i, deleteOriginalAssets: true }),
pluginRewriteAll(), // fixes 404 error with paths containing dot in dev server pluginRewriteAll(), // fixes 404 error with paths containing dot in dev server
]; ];
const resolve = { const resolve = {
alias: { alias: {
vue: "@vue/compat", // vue: "@vue/compat",
"@/": `${path.resolve(__dirname, "src")}/`, "@/": `${path.resolve(__dirname, "src")}/`,
}, },
}; };