diff --git a/package-lock.json b/package-lock.json index 5313cec..1136145 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2074,15 +2074,16 @@ } }, "frontblock-generic": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/frontblock-generic/-/frontblock-generic-0.34.1.tgz", - "integrity": "sha512-BiVUzpJSFV3FbnpdP3mxQTi1ivzlA9BXNrVp6rjuvNuxJYK1JIcd7Lhfaw1xR5v9XRPCBVVgksH37zfMUAPMjg==", + "version": "0.34.8", + "resolved": "https://registry.npmjs.org/frontblock-generic/-/frontblock-generic-0.34.8.tgz", + "integrity": "sha512-3Nx+muI2qz3PS/5372EtNd0nTyrQaflJk3qCpG4gSppDW6zb+BVACe2RNyF2IfoFVBwJByQ2yVVhN18Gcrl2dQ==", "requires": { "@types/lowdb": "^1.0.9", "@types/node": "^12.7.1", "bsock": "^0.1.9", "express": "^4.17.1", "fs": "0.0.1-security", + "git-describe": "^4.0.4", "http": "0.0.0", "key-file-storage": "^2.2.4", "knex": "^0.19.2", @@ -2090,6 +2091,7 @@ "lowdb": "^1.0.0", "minimist": "^1.2.0", "path": "^0.12.7", + "simple-git": "^1.126.0", "uuid": "^3.3.2" }, "dependencies": { @@ -2097,6 +2099,14 @@ "version": "12.7.5", "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.5.tgz", "integrity": "sha512-9fq4jZVhPNW8r+UYKnxF1e2HkDWOWKM5bC2/7c9wPV835I0aOrVbS/Hw/pWPk2uKrNXQqg9Z959Kz+IYDd5p3w==" + }, + "simple-git": { + "version": "1.126.0", + "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-1.126.0.tgz", + "integrity": "sha512-47mqHxgZnN8XRa9HbpWprzUv3Ooqz9RY/LSZgvA7jCkW8jcwLahMz7LKugY91KZehfG0sCVPtgXiU72hd6b1Bw==", + "requires": { + "debug": "^4.0.1" + } } } }, @@ -2153,25 +2163,29 @@ "dependencies": { "abbrev": { "version": "1.1.1", - "bundled": true, + "resolved": false, + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "dev": true, "optional": true }, "ansi-regex": { "version": "2.1.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", "dev": true, "optional": true }, "aproba": { "version": "1.2.0", - "bundled": true, + "resolved": false, + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", "dev": true, "optional": true }, "are-we-there-yet": { "version": "1.1.5", - "bundled": true, + "resolved": false, + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", "dev": true, "optional": true, "requires": { @@ -2181,13 +2195,15 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true, "optional": true }, "brace-expansion": { "version": "1.1.11", - "bundled": true, + "resolved": false, + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "optional": true, "requires": { @@ -2197,37 +2213,43 @@ }, "chownr": { "version": "1.1.1", - "bundled": true, + "resolved": false, + "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==", "dev": true, "optional": true }, "code-point-at": { "version": "1.1.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true, "optional": true }, "concat-map": { "version": "0.0.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true, "optional": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", "dev": true, "optional": true }, "core-util-is": { "version": "1.0.2", - "bundled": true, + "resolved": false, + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true, "optional": true }, "debug": { "version": "4.1.1", - "bundled": true, + "resolved": false, + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "dev": true, "optional": true, "requires": { @@ -2236,25 +2258,29 @@ }, "deep-extend": { "version": "0.6.0", - "bundled": true, + "resolved": false, + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", "dev": true, "optional": true }, "delegates": { "version": "1.0.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", "dev": true, "optional": true }, "detect-libc": { "version": "1.0.3", - "bundled": true, + "resolved": false, + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", "dev": true, "optional": true }, "fs-minipass": { "version": "1.2.5", - "bundled": true, + "resolved": false, + "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==", "dev": true, "optional": true, "requires": { @@ -2263,13 +2289,15 @@ }, "fs.realpath": { "version": "1.0.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true, "optional": true }, "gauge": { "version": "2.7.4", - "bundled": true, + "resolved": false, + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "dev": true, "optional": true, "requires": { @@ -2285,7 +2313,8 @@ }, "glob": { "version": "7.1.3", - "bundled": true, + "resolved": false, + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", "dev": true, "optional": true, "requires": { @@ -2299,13 +2328,15 @@ }, "has-unicode": { "version": "2.0.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", "dev": true, "optional": true }, "iconv-lite": { "version": "0.4.24", - "bundled": true, + "resolved": false, + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, "optional": true, "requires": { @@ -2314,7 +2345,8 @@ }, "ignore-walk": { "version": "3.0.1", - "bundled": true, + "resolved": false, + "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", "dev": true, "optional": true, "requires": { @@ -2323,7 +2355,8 @@ }, "inflight": { "version": "1.0.6", - "bundled": true, + "resolved": false, + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "optional": true, "requires": { @@ -2333,19 +2366,22 @@ }, "inherits": { "version": "2.0.3", - "bundled": true, + "resolved": false, + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true, "optional": true }, "ini": { "version": "1.3.5", - "bundled": true, + "resolved": false, + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "dev": true, "optional": true }, "is-fullwidth-code-point": { "version": "1.0.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, "optional": true, "requires": { @@ -2354,13 +2390,15 @@ }, "isarray": { "version": "1.0.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true, "optional": true }, "minimatch": { "version": "3.0.4", - "bundled": true, + "resolved": false, + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "optional": true, "requires": { @@ -2369,13 +2407,15 @@ }, "minimist": { "version": "0.0.8", - "bundled": true, + "resolved": false, + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true, "optional": true }, "minipass": { "version": "2.3.5", - "bundled": true, + "resolved": false, + "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==", "dev": true, "optional": true, "requires": { @@ -2385,7 +2425,8 @@ }, "minizlib": { "version": "1.2.1", - "bundled": true, + "resolved": false, + "integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==", "dev": true, "optional": true, "requires": { @@ -2394,7 +2435,8 @@ }, "mkdirp": { "version": "0.5.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, "optional": true, "requires": { @@ -2403,13 +2445,15 @@ }, "ms": { "version": "2.1.1", - "bundled": true, + "resolved": false, + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", "dev": true, "optional": true }, "needle": { "version": "2.3.0", - "bundled": true, + "resolved": false, + "integrity": "sha512-QBZu7aAFR0522EyaXZM0FZ9GLpq6lvQ3uq8gteiDUp7wKdy0lSd2hPlgFwVuW1CBkfEs9PfDQsQzZghLs/psdg==", "dev": true, "optional": true, "requires": { @@ -2420,7 +2464,8 @@ }, "node-pre-gyp": { "version": "0.12.0", - "bundled": true, + "resolved": false, + "integrity": "sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A==", "dev": true, "optional": true, "requires": { @@ -2438,7 +2483,8 @@ }, "nopt": { "version": "4.0.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", "dev": true, "optional": true, "requires": { @@ -2448,13 +2494,15 @@ }, "npm-bundled": { "version": "1.0.6", - "bundled": true, + "resolved": false, + "integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==", "dev": true, "optional": true }, "npm-packlist": { "version": "1.4.1", - "bundled": true, + "resolved": false, + "integrity": "sha512-+TcdO7HJJ8peiiYhvPxsEDhF3PJFGUGRcFsGve3vxvxdcpO2Z4Z7rkosRM0kWj6LfbK/P0gu3dzk5RU1ffvFcw==", "dev": true, "optional": true, "requires": { @@ -2464,7 +2512,8 @@ }, "npmlog": { "version": "4.1.2", - "bundled": true, + "resolved": false, + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "dev": true, "optional": true, "requires": { @@ -2476,19 +2525,22 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true, "optional": true }, "object-assign": { "version": "4.1.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true, "optional": true }, "once": { "version": "1.4.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "optional": true, "requires": { @@ -2497,19 +2549,22 @@ }, "os-homedir": { "version": "1.0.2", - "bundled": true, + "resolved": false, + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "dev": true, "optional": true }, "os-tmpdir": { "version": "1.0.2", - "bundled": true, + "resolved": false, + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true, "optional": true }, "osenv": { "version": "0.1.5", - "bundled": true, + "resolved": false, + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", "dev": true, "optional": true, "requires": { @@ -2519,19 +2574,22 @@ }, "path-is-absolute": { "version": "1.0.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true, "optional": true }, "process-nextick-args": { "version": "2.0.0", - "bundled": true, + "resolved": false, + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", "dev": true, "optional": true }, "rc": { "version": "1.2.8", - "bundled": true, + "resolved": false, + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "dev": true, "optional": true, "requires": { @@ -2543,7 +2601,8 @@ "dependencies": { "minimist": { "version": "1.2.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true, "optional": true } @@ -2551,7 +2610,8 @@ }, "readable-stream": { "version": "2.3.6", - "bundled": true, + "resolved": false, + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "optional": true, "requires": { @@ -2566,7 +2626,8 @@ }, "rimraf": { "version": "2.6.3", - "bundled": true, + "resolved": false, + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", "dev": true, "optional": true, "requires": { @@ -2575,43 +2636,50 @@ }, "safe-buffer": { "version": "5.1.2", - "bundled": true, + "resolved": false, + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true, "optional": true }, "safer-buffer": { "version": "2.1.2", - "bundled": true, + "resolved": false, + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true, "optional": true }, "sax": { "version": "1.2.4", - "bundled": true, + "resolved": false, + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "dev": true, "optional": true }, "semver": { "version": "5.7.0", - "bundled": true, + "resolved": false, + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", "dev": true, "optional": true }, "set-blocking": { "version": "2.0.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true, "optional": true }, "signal-exit": { "version": "3.0.2", - "bundled": true, + "resolved": false, + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true, "optional": true }, "string-width": { "version": "1.0.2", - "bundled": true, + "resolved": false, + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "optional": true, "requires": { @@ -2622,7 +2690,8 @@ }, "string_decoder": { "version": "1.1.1", - "bundled": true, + "resolved": false, + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "optional": true, "requires": { @@ -2631,7 +2700,8 @@ }, "strip-ansi": { "version": "3.0.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "optional": true, "requires": { @@ -2640,13 +2710,15 @@ }, "strip-json-comments": { "version": "2.0.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "dev": true, "optional": true }, "tar": { "version": "4.4.8", - "bundled": true, + "resolved": false, + "integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==", "dev": true, "optional": true, "requires": { @@ -2661,13 +2733,15 @@ }, "util-deprecate": { "version": "1.0.2", - "bundled": true, + "resolved": false, + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true, "optional": true }, "wide-align": { "version": "1.1.3", - "bundled": true, + "resolved": false, + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", "dev": true, "optional": true, "requires": { @@ -2676,13 +2750,15 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true, + "resolved": false, + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true, "optional": true }, "yallist": { "version": "3.0.3", - "bundled": true, + "resolved": false, + "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", "dev": true, "optional": true } @@ -3698,9 +3774,9 @@ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" }, "minipass": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.6.2.tgz", - "integrity": "sha512-38Jwdc8AttUDaQAIRX8Iaw3QoCDWjAwKMGeGDF9JUi9QCPMjH5qAQg/hdO8o1nC7Nmh1/CqzMg5FQPEKuKwznQ==", + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.6.4.tgz", + "integrity": "sha512-D/+wBy2YykFsCcWvaIslCKKus5tqGQZ8MhEzNx4mujLNgHhXWaaUOZkok6/kztAlTt0QkYLEyIShrybNmzoeTA==", "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" diff --git a/package.json b/package.json index 2a91ce5..f031ef2 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "build-frontend": "npm run build-dashboard; cp ./dist/FrontblockLib.js ./dist/static", "build-dashboard": "git submodule init && git submodule update --merge; cd src/frontend; npm i && npm run build; mkdir ../../dist/static; cp -r dist/* ../../dist/static", "clean": "rm -rf lib static plugins conf dist widget .rpt2_cache *.js *.ts src/frontend/dist data", - "update-frontblock": " npm install frontblock-generic@latest frontblock@latest", + "update-frontblock": "npm remove frontblock frontblock-generic; npm install frontblock-generic@latest frontblock@latest", "webpack": "webpack --config src/backend/webpack.prod.js --progress --colors" }, "repository": { @@ -26,7 +26,7 @@ "debug": "^4.1.1", "express": "^4.16.4", "frontblock": "^0.15.1", - "frontblock-generic": "^0.34.1", + "frontblock-generic": "^0.34.8", "git-cherrypicker": "0.0.3", "git-describe": "^4.0.4", "http": "0.0.0", diff --git a/src/backend/Admin.ts b/src/backend/Admin.ts index 279d876..a95957c 100644 --- a/src/backend/Admin.ts +++ b/src/backend/Admin.ts @@ -3,28 +3,25 @@ import * as Logger from 'log4js' import * as Knex from 'knex' import * as Path from 'path' import { FrontblockApiClient, FrontblockApiConf } from 'frontblock'; -import { getLogger } from 'frontblock-generic/Types'; -import { AdminBase, NotificationSeverity } from 'frontblock-generic/Admin'; -import { IFrontblockApiClient } from 'frontblock-generic/Api'; -import { Plugin } from 'frontblock-generic/Plugin'; -import { socketioRPC } from 'frontblock-generic/RPC'; -import { GitUpdater, RepoFolderStatus } from './GitUpdater'; +import { getLogger, SubscriptionResponse, Coin, AccountMap, TransactionMap } from 'frontblock-generic/Types'; +import { AdminBase, NotificationSeverity, TableDefiniton } from 'frontblock-generic/Admin'; +import { IFrontblockApiClient, FrontblockApi } from 'frontblock-generic/Api'; +import { Plugin, RPCExporter } from 'frontblock-generic/Plugin'; const logger:Logger.Logger = getLogger("admin", 'debug') - -export type AdminConf = { httpPort: number} +export type AdminConf = { + httpPort: number, + apiConf: FrontblockApiConf + dbConf:Knex.Config, + eventBusConf: { [topic in string]: NotificationSeverity} +} export class FrontblockAdmin extends AdminBase{ - - private pluginUpdaters:{[name in string]:GitUpdater} = {} - - constructor(runningPlugins: Plugin[] = []){ - super(runningPlugins) - this.initialize().then(() => this.makeKnex(this.getConfigKey('dbConf'))).then(() => logger.debug("Admin initialization finished")) - } - getDefaultConfig(): { apiConf: FrontblockApiConf; } & AdminConf & { dbConf:Knex.Config; eventBusConf: { [topic in string]: NotificationSeverity}} { + public apiClient: IFrontblockApiClient = this.makeApiClient(this.getConfigKey("apiConf")) + + getDefaultConfig(): AdminConf { return { httpPort: 8080, eventBusConf: { @@ -45,131 +42,163 @@ export class FrontblockAdmin extends AdminBase{ } } } + + constructor(runningPlugins: Plugin[] = []){ + super(runningPlugins) + this.initialize().then(() => this.makeKnex(this.getConfigKey('dbConf'))).then(() => logger.debug("Admin initialization finished")) + } + initApis(socket){ + const quit = async(uid:string) => {return await this.quit(this.getConfigKey('apiConf').apiKey, uid) } + const exporter:RPCExporter = { + name: 'ApiClient', + exportRPCs: () => { + return [{ + name: "subscribe", + func: async (coin: C, account: AccountMap[C]) => { return await this.subscribe(this.getConfigKey('apiConf').apiKey, coin, account)}, + type: 'call', + visibility: 'private' + },{ + name: "subsume", + func: async (coin: C, account: AccountMap[C], callback: (tx: TransactionMap[C]) => void) => { return await this.subsume(this.getConfigKey('apiConf').apiKey, coin, account, callback)}, + type: 'hook', + unhook: quit, + visibility: 'private' + },{ + name: 'unsubscribe', + func: async(uid:string) => { return await this.unsubscribe(this.getConfigKey('apiConf').apiKey, uid) }, + type: 'call', + visibility: 'private' + },{ + name: 'consume', + func: async(uid: string, callback: (tx: TransactionMap[C]) => void) => {return await this.consume(this.getConfigKey('apiConf').apiKey, uid, callback)}, + type: 'hook', + unhook: quit, + visibility: 'private' + },{ + name: 'quit', + func: quit, + type: 'call', + visibility: 'private' + },{ + name: "getSubscriptions", + func: async() => { return await this.getSubscriptions() }, + type: "call", + visibility: "private" + },{ + name: "getConsumers", + func: async() => { return await this.getConsumers() }, + type: "call", + visibility: "private" + }] + } + } + super.initApis(socket, [exporter]) + } + + async getConsumers(): Promise { + const records = await this.knex.select('*').from('consumers') + return records.map(r => JSON.parse(r.JSON)) + } + + async getSubscriptions(): Promise { + const records = await this.knex.select('*').from('subscriptions') + return records.map(r => JSON.parse(r.JSON)) + } + + private subscribe:FrontblockApi['subscribe'] = async (apiKey, coin, account) => { + const res = await this.apiClient.subscribe(apiKey, coin, account) + if(res instanceof SubscriptionResponse){ + await this.insert('subscriptions', [{uuid: res.uid, coin:coin, JSON: JSON.stringify(res)}], "apiclient", "Info") + } + return res + } + + private consume:FrontblockApi['consume'] = async (apikey, uuid, callback) => { + const res = await this.apiClient.consume(apikey, uuid, callback) + if(res instanceof SubscriptionResponse){ + await this.insert('consumers', [{uuid: res.uid, coin:undefined, JSON: JSON.stringify(res)}], "apiclient", "Info") + } + return res + } + + private unsubscribe:FrontblockApi['unsubscribe'] = async (apikey, uuid) => { + const res = await this.apiClient.unsubscribe(apikey, uuid) + await this.knex('subscriptions') + .where('uuid', uuid) + .del() + return res + } + + private quit:FrontblockApi['quit'] = async (apikey, uuid) => { + const res = await this.apiClient.quit(apikey, uuid) + await this.knex('consumers') + .where('uuid', uuid) + .del() + return res + } + + private subsume:FrontblockApi['subsume'] = async (apikey, coin, account, callback) => { + const res = await this.apiClient.subsume(apikey, coin, account, callback) + if(res instanceof SubscriptionResponse){ + await Promise.all([ + this.insert('consumers', [{ + uuid: res.uid, + coin:coin, + JSON: JSON.stringify(res) + }], "apiclient", "Info"), + + this.insert('subscriptions', [{ + uuid: res.uid, + coin:coin, + JSON: JSON.stringify(new SubscriptionResponse(res.message!)) + }], "apiclient", "Info") + ]) + } + return res + } + + setConfig(conf:AdminConf & { dbConf: Knex.Config; eventBusConf: {[x in string]:NotificationSeverity} }):AdminConf & { dbConf: Knex.Config; eventBusConf: {[x in string]:NotificationSeverity} }{ + const currConf = this.getConfig() + if(JSON.stringify(currConf.apiConf) !== JSON.stringify(conf.apiConf)){ + this.makeApiClient(conf.apiConf) + } + return super.setConfig(conf) + } + + setConfigKey(key: string, value: any):AdminConf & { dbConf: Knex.Config; eventBusConf: {[x in string]:NotificationSeverity} }{ + if(key === 'apiConf'){ + this.makeApiClient(value) + } + return super.setConfigKey(key, value) + } + + getTableDefinitions(): TableDefiniton[] { + return [ + ...super.getTableDefinitions(), + { + name: 'subscriptions', + tableBuilder: function (table) { + table.string('uuid').primary(); + table.string('coin'); + table.string('JSON'); + } + },{ + name: 'consumers', + tableBuilder: function (table) { + table.string('uuid').primary(); + table.string('coin'); + table.string('JSON'); + } + }] + } + protected makeApiClient(conf: FrontblockApiConf): IFrontblockApiClient { if(this.apiClient) this.apiClient.disconnect() this.apiClient = new FrontblockApiClient(conf) this.apiClient.connect() return this.apiClient } - - exportRPCs():socketioRPC[]{ - return [ - ...super.exportRPCs(), - { - name: 'installPlugin', - func: async (name:string, force = false) => {return await this.installPlugin(name, force)}, - type: 'call', - visibility: 'private' - },{ - name: 'startPlugin', - func: async (name:string) => {return await this.startPlugin(name)}, - type: 'call', - visibility: 'private' - },{ - name: 'updatePlugin', - func: async (name) => {return await this.updatePlugin(name)}, - type: 'call', - visibility: 'private' - },{ - name: 'setPluginVersion', - func: async (name, tag) => {return await this.setPluginVersion(name, tag)}, - type: 'call', - visibility: 'private' - },{ - name: 'getLoadedPluginNames', - func: async () => {return await this.getPlugins().map(p => p.name)}, - type: 'call', - visibility: 'private' - },{ - name: 'selfUpdate', - type:'call', - func: async (force: boolean) => {return await this.selfUpdate(force)}, - visibility: 'private' - }, - ] - } - - private async selfUpdate(force:boolean = false){ - const updater = new GitUpdater("./dist") - let status = await updater.getStatus() - if(force || !status.remote || !status.remote.includes("fb-dist/admin") || !status.exists || status.empty || !status.currentTag){ - logger.warn("Cloning fb-dist/admin into ./dist ..."+(force?" USING FORCE!":"")) - status = await updater.cloneRepo("https://gitea.frontblock.me/fb-dist/admin.git", force) - - this.destroy() - const installer = require("./Installer").installAdmin - installer(this.getPlugins()) - } - return status - } - - async installPlugin(name: string, force:boolean = false):Promise{ - logger.warn("Cloning fb-dist/"+name+".git into ./plugins/"+name+" ..."+(force?" USING FORCE!":"")) - this.pluginUpdaters[name] = new GitUpdater("./plugins/"+name) - const status = await this.pluginUpdaters[name].cloneRepo("https://gitea.frontblock.me/fb-dist/"+name.toLowerCase()+".git", force) - return status - } - - async startPlugin(name:string):Promise{ - if(!this.pluginUpdaters[name]) return false - const status = await this.pluginUpdaters[name].getStatus() - if(!status.exists || status.empty || !status.tags || status.tags.length === 0){ - if(status.currentTag && !status.latestTag){ - //git glitches sometimes if you check immediately after clone - logger.warn("re-fetching tag for "+name+"...") - return await this.startPlugin(name) - } - logger.error("Bad repo status", name, status) - return false - } - -/* if(this.loadedPlugins[name]){ - logger.error("Plugin", name, "is already started") - return false - } -*/ - - let str = "../plugins/"+name+"/Plugin" - const pluginClass = await eval('require')(str) - const pluginObj = new pluginClass.default() - await pluginObj.start() - this.addPlugin(pluginObj) - return true - } - - async updatePlugin(name:string):Promise{ - if(!this.pluginUpdaters[name]) return false - const status = await this.pluginUpdaters[name].getStatus() - if(!status.exists || status.empty || !status.tags || status.tags.length === 0){ - logger.error("Bad repo status", name, status) - return false - } - if(status.currentTag == status.latestTag){ - logger.warn(name, "already at latest tag") - return false - } - - /* - if(this.loadedPlugins[name]){ - logger.error("Plugin", name, "is running. Stop it first") - return false - } - */ - - this.pluginUpdaters[name].checkoutTag(status.latestTag!) - return true - } - - async setPluginVersion(pluginName:string, tag:string):Promise{ - const status = await this.pluginUpdaters[pluginName].getStatus() - if(!status.exists || !status.tags || status.tags.length === 0 || !status.tags.includes(tag)){ - logger.error("Bad repo status", pluginName, status) - return status - } - - return await this.pluginUpdaters[pluginName].checkoutTag(tag) - } } process.on( 'SIGINT', function() { diff --git a/src/backend/webpack.prod.js b/src/backend/webpack.prod.js index c5a264a..c3e2337 100644 --- a/src/backend/webpack.prod.js +++ b/src/backend/webpack.prod.js @@ -68,9 +68,7 @@ module.exports = [{ ] }, - externals:{ - "./Installer": "./Installer" - }, + externals:["./Installer"], optimization: { minimize: false }, diff --git a/src/frontend/angular.json b/src/frontend/angular.json index 1ad2fe2..f6170ea 100644 --- a/src/frontend/angular.json +++ b/src/frontend/angular.json @@ -15,8 +15,10 @@ "prefix": "app", "architect": { "build": { - "builder": "@angular-devkit/build-angular:browser", + "builder": "@angular-builders/custom-webpack:browser", "options": { + "customWebpackConfig": {"path": "./custom-webpack.config.js"}, + "outputPath": "dist", "index": "src/index.html", "main": "src/main.ts", @@ -78,7 +80,7 @@ } }, "serve": { - "builder": "@angular-devkit/build-angular:dev-server", + "builder": "@angular-builders/custom-webpack:dev-server", "tsConfig": "tsconfig.app.json", "options": { "browserTarget": "dashboard:build" @@ -99,7 +101,7 @@ } }, "test": { - "builder": "@angular-devkit/build-angular:karma", + "builder": "@angular-builders/custom-webpack:karma", "options": { "main": "src/test.ts", "polyfills": "src/polyfills.ts", @@ -116,7 +118,7 @@ } }, "lint": { - "builder": "@angular-devkit/build-angular:tslint", + "builder": "@angular-builders/custom-webpack:tslint", "options": { "tsConfig": [ "tsconfig.app.json", @@ -130,7 +132,7 @@ } }, "e2e": { - "builder": "@angular-devkit/build-angular:protractor", + "builder": "@angular-builders/custom-webpack:protractor", "options": { "protractorConfig": "e2e/protractor.conf.js", "devServerTarget": "dashboard:serve" diff --git a/src/frontend/package-lock.json b/src/frontend/package-lock.json index 6c71523..2bcba84 100644 --- a/src/frontend/package-lock.json +++ b/src/frontend/package-lock.json @@ -4795,9 +4795,9 @@ } }, "frontblock": { - "version": "0.14.9", - "resolved": "https://registry.npmjs.org/frontblock/-/frontblock-0.14.9.tgz", - "integrity": "sha512-iEjOdJ92pxg18Y9mVfjfRYzuAfxXElREoDfz8FFPaNvbO3mPv+8Y2m3jtTo8FoOpFGgA+jwOw40nT1iWKRS72A==", + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/frontblock/-/frontblock-0.15.1.tgz", + "integrity": "sha512-nRSoAT5HZhJmYkCdX8YGya+YTnvzw0W7eG0ISr+HBUO5u4hjmnHwwA1U7VewbTNokan9JvA7TF6/QijLeSCCVA==", "requires": { "@angular/common": "^8.2.1", "@angular/core": "^8.2.1", @@ -4806,7 +4806,7 @@ "@angular/router": "^8.2.1", "@clr/angular": "^2.1.1", "@types/node": "^11.13.10", - "frontblock-generic": "^0.33.7", + "frontblock-generic": "^0.34.0", "fs": "0.0.1-security", "knex": "^0.19.2", "log4js": "^4.3.1", @@ -4820,52 +4820,26 @@ "version": "11.13.20", "resolved": "https://registry.npmjs.org/@types/node/-/node-11.13.20.tgz", "integrity": "sha512-JE0UpLWZTV1sGcaj0hN+Q0760OEjpgyFJ06DOMVW6qKBducKdJQaIw0TGL6ccj7VXRduIOHLWQi+tHwulZJHVQ==" - }, - "frontblock-generic": { - "version": "0.33.12", - "resolved": "https://registry.npmjs.org/frontblock-generic/-/frontblock-generic-0.33.12.tgz", - "integrity": "sha512-6tQIIdqzsJxqPefxWXBfGs02ux3zKCAqyruFThlUiMxBnPPaqS13R6m74yH/lgpIDom1aPf+vwASiRUI3+5dXw==", - "requires": { - "@types/lowdb": "^1.0.9", - "@types/node": "^12.7.1", - "bsock": "^0.1.9", - "express": "^4.17.1", - "fs": "0.0.1-security", - "http": "0.0.0", - "key-file-storage": "^2.2.4", - "knex": "^0.19.2", - "log4js": "^4.2.0", - "lowdb": "^1.0.0", - "minimist": "^1.2.0", - "path": "^0.12.7", - "uuid": "^3.3.2" - }, - "dependencies": { - "@types/node": { - "version": "12.7.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.5.tgz", - "integrity": "sha512-9fq4jZVhPNW8r+UYKnxF1e2HkDWOWKM5bC2/7c9wPV835I0aOrVbS/Hw/pWPk2uKrNXQqg9Z959Kz+IYDd5p3w==" - } - } - }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" } } }, "frontblock-generic": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/frontblock-generic/-/frontblock-generic-0.23.0.tgz", - "integrity": "sha512-5KukScUCAsomGP9xMp6gQjA5xKBMfctTSQhIoaoxEkXpXoX9F2pjlYIkfP11NYNSsk2gVf3xg7VIhhSzhizy/A==", + "version": "0.34.1", + "resolved": "https://registry.npmjs.org/frontblock-generic/-/frontblock-generic-0.34.1.tgz", + "integrity": "sha512-BiVUzpJSFV3FbnpdP3mxQTi1ivzlA9BXNrVp6rjuvNuxJYK1JIcd7Lhfaw1xR5v9XRPCBVVgksH37zfMUAPMjg==", "requires": { + "@types/lowdb": "^1.0.9", "@types/node": "^12.7.1", "bsock": "^0.1.9", + "express": "^4.17.1", + "fs": "0.0.1-security", "http": "0.0.0", "key-file-storage": "^2.2.4", + "knex": "^0.19.2", "log4js": "^4.2.0", + "lowdb": "^1.0.0", "minimist": "^1.2.0", + "path": "^0.12.7", "uuid": "^3.3.2" }, "dependencies": { diff --git a/src/frontend/package.json b/src/frontend/package.json index 01c73f6..fcea7ed 100644 --- a/src/frontend/package.json +++ b/src/frontend/package.json @@ -7,13 +7,13 @@ "start-prodlike": "npm run build-assets && ng serve --aot=false --optimization=false --proxy-config proxy.conf.json --configuration=prodlike", "build": "rm -f src/assets/*.js; ng build --prod --aot=false --optimization=false --build-optimizer=false", "build-assets": "npm run copy-frontends; npm run deep-clean-plugins", - "update-frontblock": "rm -rf node_modules/frontblock*; npm install", "get-submodules": "git submodule update --init && git submodule foreach git checkout master", "copy-frontends": "for module in $(git config --file .gitmodules --get-regexp path | awk '{ print $2 }'); do npm i --prefix $module && npm run --prefix $module build && cp $module/dist/FrontendPlugin.js ./src/assets/$(basename $module).js; done", "deep-clean-plugins": "for module in $(git config --file .gitmodules --get-regexp path | awk '{ print $2 }'); do rm -rf $module/node_modules; done", "test": "ng test", "lint": "ng lint", - "e2e": "ng e2e" + "e2e": "ng e2e", + "update-frontblock": "npm remove frontblock frontblock-generic; npm install frontblock-generic@latest frontblock@latest" }, "private": true, "dependencies": { @@ -32,8 +32,8 @@ "@webcomponents/custom-elements": "^1.0.0", "btc-hdkey": "0.0.17", "coinselect": "^3.1.11", - "frontblock": "latest", - "frontblock-generic": "^0.23.0", + "frontblock": "^0.15.1", + "frontblock-generic": "^0.34.1", "key-file-storage": "^2.2.4", "node-fetch": "^2.6.0", "rxjs": "~6.5.2", diff --git a/src/frontend/src/app/apiclient/module.ts b/src/frontend/src/app/apiclient/module.ts index 1f2f1c1..742bdc0 100644 --- a/src/frontend/src/app/apiclient/module.ts +++ b/src/frontend/src/app/apiclient/module.ts @@ -10,6 +10,7 @@ import { ClarityModule } from '@clr/angular'; import { FormsModule } from '@angular/forms'; import {FrontendPlugin, SidebarEntries, SidebarEntry} from 'frontblock-generic/Plugin' +import { ApiclientWidgetComponent } from './apiclient-widget.component'; @NgModule({ imports: [ @@ -27,14 +28,14 @@ import {FrontendPlugin, SidebarEntries, SidebarEntry} from 'frontblock-generic/P ApiclientConsumptionComponent, ApiclientSubscriptionComponent, ApiclientFormComponent, - + ApiclientWidgetComponent ], entryComponents: [ ApiclientFormComponent, - + ApiclientWidgetComponent ] }) -export class ApiclientModule implements FrontendPlugin{ +export class ApiclientModule implements FrontendPlugin{ getSidebarEntry(): SidebarEntry | SidebarEntries { return { icon: "terminal", @@ -50,7 +51,11 @@ export class ApiclientModule implements FrontendPlugin{ } } - getSettingsComponentClassName(): any{ + getSettingsComponent(): typeof ApiclientFormComponent{ return ApiclientFormComponent } + + getWidget(): typeof ApiclientWidgetComponent{ + return ApiclientWidgetComponent + } } diff --git a/src/frontend/src/app/app-routing.module.ts b/src/frontend/src/app/app-routing.module.ts index 66ff633..62aed1b 100644 --- a/src/frontend/src/app/app-routing.module.ts +++ b/src/frontend/src/app/app-routing.module.ts @@ -5,6 +5,9 @@ import { ErrorDisplayComponent } from './error-display/error-display.component'; import { SettingsComponent } from './settings/settings.component'; const routes: Routes = [{ + path: "apiclient", + loadChildren: () => import('./apiclient/module').then(mod => mod.ApiclientModule) + },{ path: "pluginmanager", loadChildren: () => import('./pluginmanager/module').then(mod => mod.PluginmanagerModule) },{ diff --git a/src/frontend/src/app/dynamic-loader/dynamic-loader.component.ts b/src/frontend/src/app/dynamic-loader/dynamic-loader.component.ts index 1d703e1..346a0ad 100644 --- a/src/frontend/src/app/dynamic-loader/dynamic-loader.component.ts +++ b/src/frontend/src/app/dynamic-loader/dynamic-loader.component.ts @@ -86,6 +86,7 @@ export class DynamicLoaderComponent implements AfterViewInit { private async installWidget(pluginName: string) { let module; if (!angularCore.isDevMode()){ + console.log("Loading "+pluginName+" from backend") module = await SystemJS.import("plugins/" + pluginName + ".js"); }else{ if(environment.loadLocal){ @@ -97,16 +98,18 @@ export class DynamicLoaderComponent implements AfterViewInit { } } - const plugin:FrontendPlugin = new module['PluginModule']() - this.injectPlugin(plugin) - this.compileModule(plugin) + this.injectPlugin(module) + this.compileModule(module) } compileModule(module:any){ } - injectPlugin(plugin:FrontendPlugin):void{ + injectPlugin(module:any):void{ + const plugin:FrontendPlugin = new module['PluginModule']() + if(!plugin.getSidebarEntry) return + const entry: SidebarEntries | SidebarEntry = plugin.getSidebarEntry() const rc = this.router.config diff --git a/src/frontend/src/app/header-bar/header-bar.component.html b/src/frontend/src/app/header-bar/header-bar.component.html index 169347c..5e89772 100644 --- a/src/frontend/src/app/header-bar/header-bar.component.html +++ b/src/frontend/src/app/header-bar/header-bar.component.html @@ -1,17 +1,17 @@ - +
- Frontblock + + +   Frontblock +
- -
- - + diff --git a/src/frontend/src/app/home/home.component.html b/src/frontend/src/app/home/home.component.html index 5f2c53f..6338c93 100644 --- a/src/frontend/src/app/home/home.component.html +++ b/src/frontend/src/app/home/home.component.html @@ -1 +1 @@ -

home works!

+ diff --git a/src/frontend/src/app/home/home.component.ts b/src/frontend/src/app/home/home.component.ts index f56c8c1..88054f3 100644 --- a/src/frontend/src/app/home/home.component.ts +++ b/src/frontend/src/app/home/home.component.ts @@ -1,15 +1,35 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit, ViewChild, ViewContainerRef, Injector, ComponentFactoryResolver, AfterViewInit } from '@angular/core'; +import { FrontendPlugin } from 'frontblock-generic/Plugin'; +import { ApiclientModule } from '../apiclient/module'; @Component({ selector: 'app-home', templateUrl: './home.component.html', styleUrls: ['./home.component.scss'] }) -export class HomeComponent implements OnInit { +export class HomeComponent implements AfterViewInit { - constructor() { } + @ViewChild('dynamicWidgets', {read: ViewContainerRef, static: false}) + settingsContainer: ViewContainerRef + + constructor( + private componentFactoryResolver: ComponentFactoryResolver, + private injector: Injector + ) { } + + ngAfterViewInit() { + this.injectModule(new ApiclientModule()) - ngOnInit() { } + injectModule(module:FrontendPlugin) { + if(!module.getSettingsComponent) return + + //@ts-ignore + const factory = this.componentFactoryResolver.resolveComponentFactory(module.getWidget()) + const component = factory.create(this.injector) + setTimeout(() => this.settingsContainer.insert(component.hostView), 1) + } + + } diff --git a/src/frontend/src/app/knex-config/knex-config.component.ts b/src/frontend/src/app/knex-config/knex-config.component.ts index 3d7b4ac..7323e22 100644 --- a/src/frontend/src/app/knex-config/knex-config.component.ts +++ b/src/frontend/src/app/knex-config/knex-config.component.ts @@ -136,6 +136,16 @@ export class KnexConfigComponent implements OnInit{ } async ngOnInit(){ + await new Promise((resolve, reject)=>{ + let awaitAdmin: { (): void; (...args: any[]): void; } + (awaitAdmin = () => { + if(fb.Admin != null){ + resolve() + } + setTimeout(awaitAdmin,25) + })() + }) + const c = await fb.Admin.getConfig() this.conf = c.dbConf diff --git a/src/frontend/src/app/settings/settings.component.ts b/src/frontend/src/app/settings/settings.component.ts index bbc7eb4..a1067ad 100644 --- a/src/frontend/src/app/settings/settings.component.ts +++ b/src/frontend/src/app/settings/settings.component.ts @@ -1,5 +1,6 @@ import { Component, ViewChild, ViewContainerRef, ComponentFactoryResolver, Injector, AfterViewInit } from '@angular/core'; import { ApiclientModule } from '../apiclient/module' +import { FrontendPlugin } from 'frontblock-generic/Plugin'; @Component({ selector: 'app-settings', @@ -9,7 +10,7 @@ import { ApiclientModule } from '../apiclient/module' export class SettingsComponent implements AfterViewInit { ngAfterViewInit(): void { this.injectModule(new ApiclientModule()) - this.injectModule(new ApiclientModule()) +// this.injectModule(new ApiclientModule()) } @ViewChild('dynamicSettings', {read: ViewContainerRef, static: false}) @@ -21,10 +22,11 @@ export class SettingsComponent implements AfterViewInit { ) { } - injectModule(module:any) { - const factory = this.componentFactoryResolver.resolveComponentFactory(module.getSettingsComponentClassName()) + injectModule(module:FrontendPlugin) { + if(!module.getSettingsComponent) return + + const factory = this.componentFactoryResolver.resolveComponentFactory(module.getSettingsComponent()) const component = factory.create(this.injector) setTimeout(() => this.settingsContainer.insert(component.hostView), 1) } - } diff --git a/src/frontend/src/app/sidebar/sidebar.component.ts b/src/frontend/src/app/sidebar/sidebar.component.ts index 1ab4dda..a2f367f 100644 --- a/src/frontend/src/app/sidebar/sidebar.component.ts +++ b/src/frontend/src/app/sidebar/sidebar.component.ts @@ -1,5 +1,6 @@ import { Component, OnInit } from '@angular/core'; import { SidebarEntries, SidebarEntry } from 'frontblock-generic/Plugin'; +import { ApiclientModule } from '../apiclient/module'; @Component({ selector: 'sidebar', @@ -12,7 +13,9 @@ export class SidebarComponent implements OnInit { entries:SidebarEntry[] = [] - multientires:SidebarEntries[] = [{ + multientires:SidebarEntries[] = [ + new ApiclientModule().getSidebarEntry(), + { icon: "bundle", text: "Update Manager", parentRoute: "pluginmanager", diff --git a/src/frontend/src/app/subnav/subnav.component.html b/src/frontend/src/app/subnav/subnav.component.html index d5a428c..da6b417 100644 --- a/src/frontend/src/app/subnav/subnav.component.html +++ b/src/frontend/src/app/subnav/subnav.component.html @@ -1,11 +1,17 @@ + \ No newline at end of file