From a1ca679c3c754937f1cd19a0b77ddaeda58b91b4 Mon Sep 17 00:00:00 2001 From: Kloon ImKloon Date: Thu, 7 Sep 2023 15:18:05 +0200 Subject: [PATCH 1/8] Fix usage progressbar not showing --- frontend/src/components/Sidebar.vue | 66 +++++++++++++++------------- frontend/src/utils/vue.js | 68 ----------------------------- 2 files changed, 35 insertions(+), 99 deletions(-) delete mode 100644 frontend/src/utils/vue.js diff --git a/frontend/src/components/Sidebar.vue b/frontend/src/components/Sidebar.vue index b223cfc4..2826f3a5 100644 --- a/frontend/src/components/Sidebar.vue +++ b/frontend/src/components/Sidebar.vue @@ -82,9 +82,7 @@
@@ -112,8 +110,10 @@ diff --git a/frontend/src/utils/vue.js b/frontend/src/utils/vue.js deleted file mode 100644 index 962a7f9d..00000000 --- a/frontend/src/utils/vue.js +++ /dev/null @@ -1,68 +0,0 @@ -import Vue from "vue"; -import Noty from "noty"; -import VueLazyload from "vue-lazyload"; -import i18n from "@/i18n"; -import { disableExternal } from "@/utils/constants"; -import AsyncComputed from "vue-async-computed"; - -Vue.use(VueLazyload); -Vue.use(AsyncComputed); - -Vue.config.productionTip = true; - -const notyDefault = { - type: "info", - layout: "bottomRight", - timeout: 1000, - progressBar: true, -}; - -Vue.prototype.$noty = (opts) => { - new Noty(Object.assign({}, notyDefault, opts)).show(); -}; - -Vue.prototype.$showSuccess = (message) => { - new Noty( - Object.assign({}, notyDefault, { - text: message, - type: "success", - }) - ).show(); -}; - -Vue.prototype.$showError = (error, displayReport = true) => { - let btns = [ - Noty.button(i18n.t("buttons.close"), "", function () { - n.close(); - }), - ]; - - if (!disableExternal && displayReport) { - btns.unshift( - Noty.button(i18n.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, - }) - ); - - n.show(); -}; - -Vue.directive("focus", { - inserted: function (el) { - el.focus(); - }, -}); - -export default Vue; From 808cd1d20ec57d51ff26dcf0cb53c589b351046b Mon Sep 17 00:00:00 2001 From: Kloon ImKloon Date: Thu, 7 Sep 2023 15:29:30 +0200 Subject: [PATCH 2/8] Fix duplicate user var from refactoring --- frontend/src/views/settings/User.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/views/settings/User.vue b/frontend/src/views/settings/User.vue index 00090e2e..1f75fc2f 100644 --- a/frontend/src/views/settings/User.vue +++ b/frontend/src/views/settings/User.vue @@ -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) }); } From 856de2a69c0f049f5e0ee38a77a01a2a43eb67d7 Mon Sep 17 00:00:00 2001 From: Kloon ImKloon Date: Thu, 7 Sep 2023 15:48:05 +0200 Subject: [PATCH 3/8] Fix error display during upload after refactor --- frontend/src/stores/upload.js | 10 ++++++---- frontend/src/views/Files.vue | 8 ++++++++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/frontend/src/stores/upload.js b/frontend/src/stores/upload.js index 95eb4dbc..f09773eb 100644 --- a/frontend/src/stores/upload.js +++ b/frontend/src/stores/upload.js @@ -19,6 +19,7 @@ export const useUploadStore = defineStore("upload", { progress: [], queue: [], uploads: {}, + error: null, }), getters: { // user and jwt getter removed, no longer needed @@ -68,6 +69,9 @@ export const useUploadStore = defineStore("upload", { // Vue.set(this.progress, id, loaded); this.progress[id] = loaded; }, + setError(error) { + this.error = error; + }, reset() { this.id = 0; this.sizes = []; @@ -130,8 +134,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) => @@ -143,10 +146,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); diff --git a/frontend/src/views/Files.vue b/frontend/src/views/Files.vue index e519bbeb..6119c529 100644 --- a/frontend/src/views/Files.vue +++ b/frontend/src/views/Files.vue @@ -25,6 +25,7 @@ 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"; @@ -52,6 +53,7 @@ export default { width: window.innerWidth, }; }, + inject: ["$showError"], computed: { ...mapWritableState(useFileStore, [ "req", @@ -62,6 +64,9 @@ export default { ]), ...mapState(useLayoutStore, ["show", "showShell"]), ...mapWritableState(useLayoutStore, ["loading"]), + ...mapState(useUploadStore, { + uploadError: "error", + }), currentView() { if (this.req.type == undefined) { return null; @@ -89,6 +94,9 @@ export default { this.fetchData(); } }, + uploadError(newValue, oldValue) { + newValue && newValue !== oldValue && this.$showError(this.uploadError); + }, }, mounted() { this.isFiles = true; From b25758940561e2cc3697786e9cc7239fe7a99f92 Mon Sep 17 00:00:00 2001 From: Kloon ImKloon Date: Thu, 7 Sep 2023 21:38:02 +0200 Subject: [PATCH 4/8] Replace noty with vue-toastification --- frontend/package-lock.json | 142 ++++--------------------- frontend/package.json | 4 +- frontend/src/components/ErrorToast.vue | 39 +++++++ frontend/src/css/styles.css | 1 + frontend/src/main.js | 79 +++++++------- 5 files changed, 101 insertions(+), 164 deletions(-) create mode 100644 frontend/src/components/ErrorToast.vue diff --git a/frontend/package-lock.json b/frontend/package-lock.json index a3ff1096..6047da8b 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -21,7 +21,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,7 +30,8 @@ "vue-i18n": "^9.2.2", "vue-lazyload": "^3.0.0", "vue-router": "^4.2.4", - "vue-simple-progress": "^1.1.1" + "vue-simple-progress": "^1.1.1", + "vue-toastification": "^2.0.0-rc.5" }, "devDependencies": { "@intlify/unplugin-vue-i18n": "^0.12.3", @@ -3681,15 +3681,6 @@ "url": "https://github.com/sponsors/mysticatea" } }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/eslint-visitor-keys": { "version": "3.4.3", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", @@ -3799,108 +3790,6 @@ "node": ">=8" } }, - "node_modules/eslint/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/espree": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", @@ -3930,6 +3819,19 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/esquery": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", @@ -5000,12 +4902,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", @@ -6398,6 +6294,14 @@ "resolved": "https://registry.npmjs.org/vue-simple-progress/-/vue-simple-progress-1.1.1.tgz", "integrity": "sha512-ltLWYBA5eVQHWyt1NwZeGeK0VQC69JVh1oqUdro0po7r8Hc8SEMEyEfuwyCO4s27h5I3jbD99BKKkyPSQZgoZA==" }, + "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": { + "vue": "^3.0.2" + } + }, "node_modules/w3c-xmlserializer": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index 8b80f7f6..9d2b7095 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -27,7 +27,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,7 +36,8 @@ "vue-i18n": "^9.2.2", "vue-lazyload": "^3.0.0", "vue-router": "^4.2.4", - "vue-simple-progress": "^1.1.1" + "vue-simple-progress": "^1.1.1", + "vue-toastification": "^2.0.0-rc.5" }, "devDependencies": { "@intlify/unplugin-vue-i18n": "^0.12.3", diff --git a/frontend/src/components/ErrorToast.vue b/frontend/src/components/ErrorToast.vue new file mode 100644 index 00000000..348df52b --- /dev/null +++ b/frontend/src/components/ErrorToast.vue @@ -0,0 +1,39 @@ + + + + + diff --git a/frontend/src/css/styles.css b/frontend/src/css/styles.css index 00442507..0a81f4ae 100644 --- a/frontend/src/css/styles.css +++ b/frontend/src/css/styles.css @@ -1,4 +1,5 @@ @import "normalize.css/normalize.css"; +@import "vue-toastification/dist/index.css"; @import "noty/lib/noty.css"; @import "noty/lib/themes/mint.css"; @import "./_variables.css"; diff --git a/frontend/src/main.js b/frontend/src/main.js index cc019092..0ff5ebc6 100644 --- a/frontend/src/main.js +++ b/frontend/src/main.js @@ -1,13 +1,13 @@ import { disableExternal } from "@/utils/constants"; -import { createApp, configureCompat } from "vue"; +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 App from "@/App.vue"; - -configureCompat({ RENDER_FUNCTION: false }); +import ErrorToast from "@/components/ErrorToast.vue"; import dayjs from "dayjs"; import localizedFormat from "dayjs/plugin/localizedFormat"; @@ -23,6 +23,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); @@ -43,53 +48,41 @@ app.directive("focus", { }, }); -const notyDefault = { - 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, + // TODO: add RTL support + // rtl: false, }; -// app.provide("$noty", (opts) => { -// new Noty(Object.assign({}, notyDefault, opts)).show(); -// }); - app.provide("$showSuccess", (message) => { - new Noty( - Object.assign({}, notyDefault, { - text: message, - type: "success", - }) - ).show(); + const $toast = useToast(); + $toast.success(message, { ...toastConfig }); }); app.provide("$showError", (error, displayReport = true) => { - let btns = [ - 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, - }) + const $toast = useToast(); + $toast.error( + { + component: ErrorToast, + 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 } ); - - n.show(); }); router.isReady().then(() => app.mount("#app")); From 9b0dcaae65a234d3a36de3fe262a3ae672c47e01 Mon Sep 17 00:00:00 2001 From: Kloon ImKloon Date: Fri, 8 Sep 2023 10:48:14 +0200 Subject: [PATCH 5/8] Set toast style to scoped and remove noty css imports --- .../{ErrorToast.vue => CustomToast.vue} | 6 ++-- frontend/src/css/styles.css | 2 -- frontend/src/main.js | 29 +++++++++++++------ 3 files changed, 24 insertions(+), 13 deletions(-) rename frontend/src/components/{ErrorToast.vue => CustomToast.vue} (90%) diff --git a/frontend/src/components/ErrorToast.vue b/frontend/src/components/CustomToast.vue similarity index 90% rename from frontend/src/components/ErrorToast.vue rename to frontend/src/components/CustomToast.vue index 348df52b..9ba426e6 100644 --- a/frontend/src/components/ErrorToast.vue +++ b/frontend/src/components/CustomToast.vue @@ -21,16 +21,18 @@ export default { }; -