diff --git a/komga-webui/package-lock.json b/komga-webui/package-lock.json index 525a337c3..a52520907 100644 --- a/komga-webui/package-lock.json +++ b/komga-webui/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "@saekitominaga/isbn-verify": "^1.4.1", "axios": "^0.25.0", + "chart.js": "^2.9.4", "core-js": "^3.20.3", "date-fns": "^2.28.0", "filesize": "^8.0.7", @@ -19,6 +20,7 @@ "qs": "^6.10.3", "screenfull": "^5.2.0", "vue": "^2.6.14", + "vue-chartkick": "^0.6.1", "vue-horizontal": "^0.8.12", "vue-i18n": "^8.27.0", "vue-line-clamp": "^1.3.2", @@ -35,8 +37,10 @@ "devDependencies": { "@babel/core": "^7.16.12", "@mdi/font": "^6.5.95", + "@types/chart.js": "^2.9.35", "@types/jest": "^24.9.1", "@types/lodash": "^4.14.178", + "@types/vue-chartkick": "^0.5.1", "@types/vuelidate": "^0.7.15", "@types/webpack": "^4.41.32", "@typescript-eslint/eslint-plugin": "^4.33.0", @@ -2288,6 +2292,15 @@ "@types/node": "*" } }, + "node_modules/@types/chart.js": { + "version": "2.9.35", + "resolved": "https://registry.npmjs.org/@types/chart.js/-/chart.js-2.9.35.tgz", + "integrity": "sha512-MWx/zZlh4wHBbM4Tm4YsZyYGb1/LkTiFLFwX/FXb0EJCvXX2xWTRHwlJ2RAAEXWxLrOdaAWP8vFtJXny+4CpEw==", + "dev": true, + "dependencies": { + "moment": "^2.10.2" + } + }, "node_modules/@types/color-name": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", @@ -2520,6 +2533,15 @@ "node": ">=0.10.0" } }, + "node_modules/@types/vue-chartkick": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@types/vue-chartkick/-/vue-chartkick-0.5.1.tgz", + "integrity": "sha512-YKqoHltCEK1h2UWUydKbrpiQjrbMLtVvtNM6xVbXIYcL+g8rupccUSMF08QrMZO4iSVQgK6D1Lt0ZcT4d3v3CQ==", + "dev": true, + "dependencies": { + "vue": "^2.0.0" + } + }, "node_modules/@types/vuelidate": { "version": "0.7.15", "resolved": "https://registry.npmjs.org/@types/vuelidate/-/vuelidate-0.7.15.tgz", @@ -5741,6 +5763,37 @@ "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", "dev": true }, + "node_modules/chart.js": { + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-2.9.4.tgz", + "integrity": "sha512-B07aAzxcrikjAPyV+01j7BmOpxtQETxTSlQ26BEYJ+3iUkbNKaOJ/nDbT6JjyqYxseM0ON12COHYdU2cTIjC7A==", + "dependencies": { + "chartjs-color": "^2.1.0", + "moment": "^2.10.2" + } + }, + "node_modules/chartjs-color": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chartjs-color/-/chartjs-color-2.4.1.tgz", + "integrity": "sha512-haqOg1+Yebys/Ts/9bLo/BqUcONQOdr/hoEr2LLTRl6C5LXctUdHxsCYfvQVg5JIxITrfCNUDr4ntqmQk9+/0w==", + "dependencies": { + "chartjs-color-string": "^0.6.0", + "color-convert": "^1.9.3" + } + }, + "node_modules/chartjs-color-string": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/chartjs-color-string/-/chartjs-color-string-0.6.0.tgz", + "integrity": "sha512-TIB5OKn1hPJvO7JcteW4WY/63v6KwEdt6udfnDE9iCAZgy+V4SrbSxoIbTw/xkUIapjEI4ExGtD0+6D3KyFd7A==", + "dependencies": { + "color-name": "^1.0.0" + } + }, + "node_modules/chartkick": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/chartkick/-/chartkick-3.2.1.tgz", + "integrity": "sha512-zV0kUeZNqrX28AmPt10QEDXHKadbVFOTAFkCMyJifHzGFkKzGCDXxVR8orZ0fC1HbePzRn5w6kLCOVxDQbMUCg==" + }, "node_modules/check-types": { "version": "8.0.3", "resolved": "https://registry.npmjs.org/check-types/-/check-types-8.0.3.tgz", @@ -6248,7 +6301,6 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, "dependencies": { "color-name": "1.1.3" } @@ -6256,8 +6308,7 @@ "node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, "node_modules/color-string": { "version": "1.9.0", @@ -7188,7 +7239,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", - "dev": true, "dependencies": { "is-arguments": "^1.0.4", "is-date-object": "^1.0.1", @@ -7380,7 +7430,6 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, "dependencies": { "object-keys": "^1.0.12" }, @@ -7967,7 +8016,6 @@ "version": "1.19.1", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", @@ -8001,7 +8049,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, "dependencies": { "is-callable": "^1.1.4", "is-date-object": "^1.0.1", @@ -10789,7 +10836,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.1.1" @@ -10981,7 +11027,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -11010,7 +11055,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, "dependencies": { "has-symbols": "^1.0.2" }, @@ -11768,7 +11812,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "dev": true, "dependencies": { "get-intrinsic": "^1.1.0", "has": "^1.0.3", @@ -11857,7 +11900,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz", "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==", - "dev": true, "engines": { "node": ">= 0.4" } @@ -11872,7 +11914,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, "dependencies": { "has-bigints": "^1.0.1" }, @@ -11896,7 +11937,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -11918,7 +11958,6 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -11992,7 +12031,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", - "dev": true, "engines": { "node": ">= 0.4" } @@ -12090,7 +12128,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -12114,7 +12151,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", - "dev": true, "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -12204,7 +12240,6 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -12226,7 +12261,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -12244,7 +12278,6 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -12259,7 +12292,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", - "dev": true, "dependencies": { "has-symbols": "^1.0.1" }, @@ -12286,7 +12318,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dev": true, "dependencies": { "call-bind": "^1.0.2" }, @@ -14213,6 +14244,14 @@ "mkdirp": "bin/cmd.js" } }, + "node_modules/moment": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", + "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==", + "engines": { + "node": "*" + } + }, "node_modules/moo-color": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/moo-color/-/moo-color-1.0.2.tgz", @@ -14694,7 +14733,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.2.tgz", "integrity": "sha512-5lHCz+0uufF6wZ7CRFWJN3hp8Jqblpgve06U5CMQ3f//6iDjPr2PEo9MWCjEssDsa+UZEL4PkFpr+BMop6aKzQ==", - "dev": true, "dependencies": { "define-properties": "^1.1.3", "es-abstract": "^1.17.5" @@ -14707,7 +14745,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, "engines": { "node": ">= 0.4" } @@ -14728,7 +14765,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", - "dev": true, "dependencies": { "call-bind": "^1.0.0", "define-properties": "^1.1.3", @@ -16524,7 +16560,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz", "integrity": "sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==", - "dev": true, "dependencies": { "define-properties": "^1.1.3", "es-abstract": "^1.17.0-next.1" @@ -18252,7 +18287,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3" @@ -18265,7 +18299,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3" @@ -19116,7 +19149,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", - "dev": true, "dependencies": { "function-bind": "^1.1.1", "has-bigints": "^1.0.1", @@ -19477,6 +19509,19 @@ "resolved": "https://registry.npmjs.org/vue/-/vue-2.6.14.tgz", "integrity": "sha512-x2284lgYvjOMj3Za7kqzRcUSxBboHqtgRE2zlos1qWaOye5yUmHn42LB1250NJBLRwEcdrB0JRwyPTEPhfQjiQ==" }, + "node_modules/vue-chartkick": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/vue-chartkick/-/vue-chartkick-0.6.1.tgz", + "integrity": "sha512-upUJKnx3irrRiMWudCkEVRpFvfy1hiVDKqv1e11Ap0qcFYCHJ231+SRDmQPcCypnKhfwc/Tm6REvsHkqRfc+Zg==", + "dependencies": { + "chartkick": "^3.2.0", + "deep-equal": "^1.0.1", + "deepmerge": "^4.2.0" + }, + "peerDependencies": { + "vue": ">=2.0.0" + } + }, "node_modules/vue-cli-plugin-i18n": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/vue-cli-plugin-i18n/-/vue-cli-plugin-i18n-2.3.1.tgz", @@ -20580,7 +20625,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, "dependencies": { "is-bigint": "^1.0.1", "is-boolean-object": "^1.1.0", @@ -22564,6 +22608,15 @@ "@types/node": "*" } }, + "@types/chart.js": { + "version": "2.9.35", + "resolved": "https://registry.npmjs.org/@types/chart.js/-/chart.js-2.9.35.tgz", + "integrity": "sha512-MWx/zZlh4wHBbM4Tm4YsZyYGb1/LkTiFLFwX/FXb0EJCvXX2xWTRHwlJ2RAAEXWxLrOdaAWP8vFtJXny+4CpEw==", + "dev": true, + "requires": { + "moment": "^2.10.2" + } + }, "@types/color-name": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", @@ -22795,6 +22848,15 @@ } } }, + "@types/vue-chartkick": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@types/vue-chartkick/-/vue-chartkick-0.5.1.tgz", + "integrity": "sha512-YKqoHltCEK1h2UWUydKbrpiQjrbMLtVvtNM6xVbXIYcL+g8rupccUSMF08QrMZO4iSVQgK6D1Lt0ZcT4d3v3CQ==", + "dev": true, + "requires": { + "vue": "^2.0.0" + } + }, "@types/vuelidate": { "version": "0.7.15", "resolved": "https://registry.npmjs.org/@types/vuelidate/-/vuelidate-0.7.15.tgz", @@ -25421,6 +25483,37 @@ "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", "dev": true }, + "chart.js": { + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-2.9.4.tgz", + "integrity": "sha512-B07aAzxcrikjAPyV+01j7BmOpxtQETxTSlQ26BEYJ+3iUkbNKaOJ/nDbT6JjyqYxseM0ON12COHYdU2cTIjC7A==", + "requires": { + "chartjs-color": "^2.1.0", + "moment": "^2.10.2" + } + }, + "chartjs-color": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chartjs-color/-/chartjs-color-2.4.1.tgz", + "integrity": "sha512-haqOg1+Yebys/Ts/9bLo/BqUcONQOdr/hoEr2LLTRl6C5LXctUdHxsCYfvQVg5JIxITrfCNUDr4ntqmQk9+/0w==", + "requires": { + "chartjs-color-string": "^0.6.0", + "color-convert": "^1.9.3" + } + }, + "chartjs-color-string": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/chartjs-color-string/-/chartjs-color-string-0.6.0.tgz", + "integrity": "sha512-TIB5OKn1hPJvO7JcteW4WY/63v6KwEdt6udfnDE9iCAZgy+V4SrbSxoIbTw/xkUIapjEI4ExGtD0+6D3KyFd7A==", + "requires": { + "color-name": "^1.0.0" + } + }, + "chartkick": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/chartkick/-/chartkick-3.2.1.tgz", + "integrity": "sha512-zV0kUeZNqrX28AmPt10QEDXHKadbVFOTAFkCMyJifHzGFkKzGCDXxVR8orZ0fC1HbePzRn5w6kLCOVxDQbMUCg==" + }, "check-types": { "version": "8.0.3", "resolved": "https://registry.npmjs.org/check-types/-/check-types-8.0.3.tgz", @@ -25823,7 +25916,6 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, "requires": { "color-name": "1.1.3" } @@ -25831,8 +25923,7 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, "color-string": { "version": "1.9.0", @@ -26609,7 +26700,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", - "dev": true, "requires": { "is-arguments": "^1.0.4", "is-date-object": "^1.0.1", @@ -26758,7 +26848,6 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, "requires": { "object-keys": "^1.0.12" } @@ -27266,7 +27355,6 @@ "version": "1.19.1", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", - "dev": true, "requires": { "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", @@ -27294,7 +27382,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, "requires": { "is-callable": "^1.1.4", "is-date-object": "^1.0.1", @@ -29432,7 +29519,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dev": true, "requires": { "call-bind": "^1.0.2", "get-intrinsic": "^1.1.1" @@ -29588,8 +29674,7 @@ "has-bigints": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", - "dev": true + "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==" }, "has-flag": { "version": "3.0.0", @@ -29606,7 +29691,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, "requires": { "has-symbols": "^1.0.2" } @@ -30234,7 +30318,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "dev": true, "requires": { "get-intrinsic": "^1.1.0", "has": "^1.0.3", @@ -30303,8 +30386,7 @@ "is-arguments": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz", - "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==", - "dev": true + "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==" }, "is-arrayish": { "version": "0.2.1", @@ -30316,7 +30398,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, "requires": { "has-bigints": "^1.0.1" } @@ -30334,7 +30415,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, "requires": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -30349,8 +30429,7 @@ "is-callable": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", - "dev": true + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==" }, "is-ci": { "version": "1.2.1", @@ -30407,8 +30486,7 @@ "is-date-object": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", - "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", - "dev": true + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==" }, "is-descriptor": { "version": "0.1.6", @@ -30477,8 +30555,7 @@ "is-negative-zero": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", - "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", - "dev": true + "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==" }, "is-number": { "version": "3.0.0", @@ -30504,7 +30581,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", - "dev": true, "requires": { "has-tostringtag": "^1.0.0" } @@ -30558,7 +30634,6 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, "requires": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -30573,8 +30648,7 @@ "is-shared-array-buffer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", - "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", - "dev": true + "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==" }, "is-stream": { "version": "1.1.0", @@ -30586,7 +30660,6 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, "requires": { "has-tostringtag": "^1.0.0" } @@ -30595,7 +30668,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", - "dev": true, "requires": { "has-symbols": "^1.0.1" } @@ -30616,7 +30688,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dev": true, "requires": { "call-bind": "^1.0.2" } @@ -32218,6 +32289,11 @@ "minimist": "^1.2.5" } }, + "moment": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", + "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==" + }, "moo-color": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/moo-color/-/moo-color-1.0.2.tgz", @@ -32626,7 +32702,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.2.tgz", "integrity": "sha512-5lHCz+0uufF6wZ7CRFWJN3hp8Jqblpgve06U5CMQ3f//6iDjPr2PEo9MWCjEssDsa+UZEL4PkFpr+BMop6aKzQ==", - "dev": true, "requires": { "define-properties": "^1.1.3", "es-abstract": "^1.17.5" @@ -32635,8 +32710,7 @@ "object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" }, "object-visit": { "version": "1.0.1", @@ -32651,7 +32725,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", - "dev": true, "requires": { "call-bind": "^1.0.0", "define-properties": "^1.1.3", @@ -34155,7 +34228,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz", "integrity": "sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==", - "dev": true, "requires": { "define-properties": "^1.1.3", "es-abstract": "^1.17.0-next.1" @@ -35554,7 +35626,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", - "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3" @@ -35564,7 +35635,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", - "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3" @@ -36252,7 +36322,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", - "dev": true, "requires": { "function-bind": "^1.1.1", "has-bigints": "^1.0.1", @@ -36563,6 +36632,16 @@ "resolved": "https://registry.npmjs.org/vue/-/vue-2.6.14.tgz", "integrity": "sha512-x2284lgYvjOMj3Za7kqzRcUSxBboHqtgRE2zlos1qWaOye5yUmHn42LB1250NJBLRwEcdrB0JRwyPTEPhfQjiQ==" }, + "vue-chartkick": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/vue-chartkick/-/vue-chartkick-0.6.1.tgz", + "integrity": "sha512-upUJKnx3irrRiMWudCkEVRpFvfy1hiVDKqv1e11Ap0qcFYCHJ231+SRDmQPcCypnKhfwc/Tm6REvsHkqRfc+Zg==", + "requires": { + "chartkick": "^3.2.0", + "deep-equal": "^1.0.1", + "deepmerge": "^4.2.0" + } + }, "vue-cli-plugin-i18n": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/vue-cli-plugin-i18n/-/vue-cli-plugin-i18n-2.3.1.tgz", @@ -37451,7 +37530,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, "requires": { "is-bigint": "^1.0.1", "is-boolean-object": "^1.1.0", diff --git a/komga-webui/package.json b/komga-webui/package.json index 30a03510d..cc20a6161 100644 --- a/komga-webui/package.json +++ b/komga-webui/package.json @@ -11,6 +11,7 @@ "dependencies": { "@saekitominaga/isbn-verify": "^1.4.1", "axios": "^0.25.0", + "chart.js": "^2.9.4", "core-js": "^3.20.3", "date-fns": "^2.28.0", "filesize": "^8.0.7", @@ -20,6 +21,7 @@ "qs": "^6.10.3", "screenfull": "^5.2.0", "vue": "^2.6.14", + "vue-chartkick": "^0.6.1", "vue-horizontal": "^0.8.12", "vue-i18n": "^8.27.0", "vue-line-clamp": "^1.3.2", @@ -36,8 +38,10 @@ "devDependencies": { "@babel/core": "^7.16.12", "@mdi/font": "^6.5.95", + "@types/chart.js": "^2.9.35", "@types/jest": "^24.9.1", "@types/lodash": "^4.14.178", + "@types/vue-chartkick": "^0.5.1", "@types/vuelidate": "^0.7.15", "@types/webpack": "^4.41.32", "@typescript-eslint/eslint-plugin": "^4.33.0", diff --git a/komga-webui/src/locales/en.json b/komga-webui/src/locales/en.json index 473e9470c..30bf0f57e 100644 --- a/komga-webui/src/locales/en.json +++ b/komga-webui/src/locales/en.json @@ -187,6 +187,7 @@ "collections": "Collections", "create": "Create", "delete": "Delete", + "disk_space": "Disk space", "dismiss": "Dismiss", "download": "Download", "email": "Email", @@ -216,6 +217,7 @@ "reset_filters": "Reset filters", "roles": "Roles", "series": "Series", + "sidecars": "Sidecars", "tags": "Tags", "unavailable": "Unavailable", "unlock_all": "Unlock all", @@ -542,11 +544,11 @@ "size": "Size", "total_size": "Total size" }, + "info": "Deleting duplicate pages will modify your files. Backup your files and use manual deletion before using automatic deletion.", "matches_n": "No matches | 1 match | {count} matches", "saved_size": "Saved {size}", "title": "Duplicate pages", - "unknown_size": "Unknown size", - "info": "Deleting duplicate pages will modify your files. Backup your files and use manual deletion before using automatic deletion." + "unknown_size": "Unknown size" }, "duplicates": { "file_hash": "File hash", @@ -680,6 +682,15 @@ "scan_library_files": "Scan library files", "select_all": "Select all" }, + "metrics": { + "library_books": "Books per library", + "library_disk_space": "Library disk space", + "library_series": "Series per library", + "library_sidecars": "Sidecars per library", + "tasks_executed": "Tasks executed", + "tasks_total_time": "Tasks total time", + "title": "Metrics" + }, "navigation": { "home": "Home", "libraries": "Libraries", diff --git a/komga-webui/src/main.ts b/komga-webui/src/main.ts index 989028e4c..ba507ec44 100644 --- a/komga-webui/src/main.ts +++ b/komga-webui/src/main.ts @@ -3,6 +3,10 @@ import Vue from 'vue' // @ts-ignore import * as lineClamp from 'vue-line-clamp' import Vuelidate from 'vuelidate' +// @ts-ignore +import Chartkick from 'vue-chartkick' +// @ts-ignore +import Chart from 'chart.js' import {sync} from 'vuex-router-sync' import App from './App.vue' import actuator from './plugins/actuator.plugin' @@ -22,6 +26,7 @@ import komgaTasks from './plugins/komga-tasks.plugin' import komgaOauth2 from './plugins/komga-oauth2.plugin' import komgaLogin from './plugins/komga-login.plugin' import komgaPageHashes from './plugins/komga-pagehashes.plugin' +import komgaMetrics from './plugins/komga-metrics.plugin' import vuetify from './plugins/vuetify' import logger from './plugins/logger.plugin' import './public-path' @@ -32,8 +37,19 @@ import i18n from './i18n' Vue.prototype.$_ = _ Vue.prototype.$eventHub = new Vue() +Chartkick.options = { + colors: [ + '#7eb0d5', '#fd7f6f', '#b2e061', '#ffb55a', + '#8bd3c7', '#ffee65', '#bd7ebe', '#fdcce5', + '#beb9db', '#ea5545', '#f46a9b', '#ef9b20', + '#edbf33', '#ede15b', '#bdcf32', '#87bc45', + '#27aeef', '#b33dc6', + ], +} + Vue.use(Vuelidate) Vue.use(lineClamp) +Vue.use(Chartkick.use(Chart)) Vue.use(httpPlugin) Vue.use(logger) @@ -53,6 +69,7 @@ Vue.use(komgaTasks, {http: Vue.prototype.$http}) Vue.use(komgaOauth2, {http: Vue.prototype.$http}) Vue.use(komgaLogin, {http: Vue.prototype.$http}) Vue.use(komgaPageHashes, {http: Vue.prototype.$http}) +Vue.use(komgaMetrics, {http: Vue.prototype.$http}) Vue.config.productionTip = false diff --git a/komga-webui/src/plugins/komga-metrics.plugin.ts b/komga-webui/src/plugins/komga-metrics.plugin.ts new file mode 100644 index 000000000..ae28cc3b8 --- /dev/null +++ b/komga-webui/src/plugins/komga-metrics.plugin.ts @@ -0,0 +1,17 @@ +import {AxiosInstance} from 'axios' +import _Vue from 'vue' +import KomgaMetricsService from '@/services/komga-metrics.service' + +export default { + install( + Vue: typeof _Vue, + {http}: { http: AxiosInstance }) { + Vue.prototype.$komgaMetrics = new KomgaMetricsService(http) + }, +} + +declare module 'vue/types/vue' { + interface Vue { + $komgaMetrics: KomgaMetricsService; + } +} diff --git a/komga-webui/src/router.ts b/komga-webui/src/router.ts index 80cb31d6a..a92098460 100644 --- a/komga-webui/src/router.ts +++ b/komga-webui/src/router.ts @@ -120,6 +120,12 @@ const router = new Router({ beforeEnter: adminGuard, component: () => import(/* webpackChunkName: "settings-server" */ './views/SettingsServer.vue'), }, + { + path: '/settings/metrics', + name: 'metrics', + beforeEnter: adminGuard, + component: () => import(/* webpackChunkName: "metrics" */ './views/Metrics.vue'), + }, ], }, { diff --git a/komga-webui/src/services/komga-metrics.service.ts b/komga-webui/src/services/komga-metrics.service.ts new file mode 100644 index 000000000..4ceee8c27 --- /dev/null +++ b/komga-webui/src/services/komga-metrics.service.ts @@ -0,0 +1,36 @@ +import {AxiosInstance} from 'axios' +import {MetricDto, Tag} from '@/types/komga-metrics' + +const qs = require('qs') + +const API_METRICS = '/actuator/metrics' + +export default class KomgaMetricsService { + private http: AxiosInstance + + constructor(http: AxiosInstance) { + this.http = http + } + + async getMetric(metric: string, tags?: Tag[]): Promise { + try { + const params = {} as any + if (tags) params.tag = KomgaMetricsService.tagQuery(tags) + + return (await this.http.get(`${API_METRICS}/${metric}`, { + params: params, + paramsSerializer: params => qs.stringify(params, {indices: false}), + })).data + } catch (e) { + let msg = `An error occurred while trying to retrieve metric: ${metric}, tags: ${tags}` + if (e.response.data.message) { + msg += `: ${e.response.data.message}` + } + throw new Error(msg) + } + } + + private static tagQuery(tags: Tag[]): string[] { + return tags.map(t => `${t.key}:${t.value}`) + } +} diff --git a/komga-webui/src/types/komga-metrics.ts b/komga-webui/src/types/komga-metrics.ts new file mode 100644 index 000000000..0cd015dff --- /dev/null +++ b/komga-webui/src/types/komga-metrics.ts @@ -0,0 +1,22 @@ +export interface Tag { + key: string, + value: string, +} + +export interface MetricDto { + name: string, + description?: string, + baseUnit?: string, + measurements: MeasurementDto[], + availableTags: TagDto[], +} + +export interface MeasurementDto { + statistic: string, + value: number, +} + +export interface TagDto { + tag: string, + values: string[], +} diff --git a/komga-webui/src/views/Metrics.vue b/komga-webui/src/views/Metrics.vue new file mode 100644 index 000000000..4a4b24578 --- /dev/null +++ b/komga-webui/src/views/Metrics.vue @@ -0,0 +1,174 @@ + + + + + diff --git a/komga-webui/src/views/SettingsHolder.vue b/komga-webui/src/views/SettingsHolder.vue index 9a5f97445..506955548 100644 --- a/komga-webui/src/views/SettingsHolder.vue +++ b/komga-webui/src/views/SettingsHolder.vue @@ -14,6 +14,7 @@ {{ $t('duplicate_pages.title') }} {{ $t('users.users') }} {{ $t('server.tab_title') }} + {{ $t('metrics.title') }}