scripts rework

This commit is contained in:
Josh
2020-12-14 04:39:02 +00:00
parent 2b33279f25
commit 287f0ac813
13 changed files with 1044 additions and 480 deletions

275
package-lock.json generated
View File

@@ -3572,9 +3572,9 @@
"dev": true
},
"@quasar/app": {
"version": "2.1.9",
"resolved": "https://registry.npmjs.org/@quasar/app/-/app-2.1.9.tgz",
"integrity": "sha512-KhO78w0BBRVGkH5OQhr6IuP9pg26c8DeI/E26TMekjD9DVHgWV8jtxIC6kBseo0NiC6noYHf632aNjXklruwnQ==",
"version": "2.1.11",
"resolved": "https://registry.npmjs.org/@quasar/app/-/app-2.1.11.tgz",
"integrity": "sha512-MX01izfk1cAFcRVj4IpU6fneQW14oeq4oAPdCqJDjYY1I1M3kYBFG+WvgfvZJxfTGiaVNP6xKWKkU1wIUNgbIw==",
"dev": true,
"requires": {
"@quasar/babel-preset-app": "2.0.1",
@@ -3603,7 +3603,6 @@
"express": "4.17.1",
"fast-glob": "3.2.4",
"file-loader": "6.2.0",
"flat": "^5.0.2",
"fork-ts-checker-webpack-plugin": "4.1.6",
"friendly-errors-webpack-plugin": "1.7.0",
"fs-extra": "9.0.1",
@@ -4071,9 +4070,9 @@
}
},
"@quasar/extras": {
"version": "1.9.10",
"resolved": "https://registry.npmjs.org/@quasar/extras/-/extras-1.9.10.tgz",
"integrity": "sha512-pVM2lLiX2vHhibL4VUCjAfYhhYtQLDLYccq/ee6PdpyJ394lJQSkFnnGntcmpQk4QPcgIQ8GZSVpsUd1qgabaw=="
"version": "1.9.11",
"resolved": "https://registry.npmjs.org/@quasar/extras/-/extras-1.9.11.tgz",
"integrity": "sha512-HI50hWZVfdcdg1TKldQxgZRr05tEX4sSJQ5TAx8no5RghjrHpSuVuwDstIFmsUM0WgTGzE89S3Aqgvr7tS4dIg=="
},
"@quasar/fastclick": {
"version": "1.1.4",
@@ -4082,23 +4081,145 @@
"dev": true
},
"@quasar/quasar-app-extension-testing": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@quasar/quasar-app-extension-testing/-/quasar-app-extension-testing-1.0.0.tgz",
"integrity": "sha512-IuHseh5YIaf4JPlsjehkB2pLUaWuFMsAxFq83+06btO9dMSQpvBXrGhA6O0N1rXUM/EXBI8Mi7pwJWi+78i4LA==",
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@quasar/quasar-app-extension-testing/-/quasar-app-extension-testing-1.0.3.tgz",
"integrity": "sha512-x3uQpsshEfSyDW/mnQeS5nUOsr3thHQn74qdlXRr7NlxzlsiV+vHSZiGlCj5Q+WNdEecWsjjqAVrwlb7FkP1CQ==",
"dev": true,
"requires": {
"chalk": "^2.4.2",
"execa": "^1.0.0",
"strip-ansi": "^5.0.0"
"chalk": "^4.1.0",
"execa": "^4.1.0",
"strip-ansi": "^6.0.0"
},
"dependencies": {
"strip-ansi": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
"integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
"ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"requires": {
"ansi-regex": "^4.1.0"
"color-convert": "^2.0.1"
}
},
"chalk": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
"integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
"dev": true,
"requires": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
}
},
"color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"requires": {
"color-name": "~1.1.4"
}
},
"color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
"cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
"dev": true,
"requires": {
"path-key": "^3.1.0",
"shebang-command": "^2.0.0",
"which": "^2.0.1"
}
},
"execa": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz",
"integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==",
"dev": true,
"requires": {
"cross-spawn": "^7.0.0",
"get-stream": "^5.0.0",
"human-signals": "^1.1.1",
"is-stream": "^2.0.0",
"merge-stream": "^2.0.0",
"npm-run-path": "^4.0.0",
"onetime": "^5.1.0",
"signal-exit": "^3.0.2",
"strip-final-newline": "^2.0.0"
}
},
"get-stream": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
"integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
"dev": true,
"requires": {
"pump": "^3.0.0"
}
},
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true
},
"is-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz",
"integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==",
"dev": true
},
"npm-run-path": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
"integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
"dev": true,
"requires": {
"path-key": "^3.0.0"
}
},
"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
},
"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,
"requires": {
"shebang-regex": "^3.0.0"
}
},
"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
},
"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,
"requires": {
"has-flag": "^4.0.0"
}
},
"which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
"dev": true,
"requires": {
"isexe": "^2.0.0"
}
}
}
@@ -4206,9 +4327,9 @@
"dev": true
},
"@types/connect": {
"version": "3.4.33",
"resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.33.tgz",
"integrity": "sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A==",
"version": "3.4.34",
"resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.34.tgz",
"integrity": "sha512-ePPA/JuI+X0vb+gSWlPKOY0NdNAie/rPUqX2GUPpbZwiKTkSPhjXWuee47E4MtE54QVzGCQMQkAL6JhV2E1+cQ==",
"dev": true,
"requires": {
"@types/node": "*"
@@ -4255,9 +4376,9 @@
}
},
"@types/express-serve-static-core": {
"version": "4.17.14",
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.14.tgz",
"integrity": "sha512-uFTLwu94TfUFMToXNgRZikwPuZdOtDgs3syBtAIr/OXorL1kJqUJT9qCLnRZ5KBOWfZQikQ2xKgR2tnDj1OgDA==",
"version": "4.17.15",
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.15.tgz",
"integrity": "sha512-pb71P0BrBAx7cQE+/7QnA1HTQUkdBKMlkPY7lHUMn0YvPJkL2UA+KW3BdWQ309IT+i9En/qm45ZxpjIcpgEhNQ==",
"dev": true,
"requires": {
"@types/node": "*",
@@ -6524,6 +6645,18 @@
"integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==",
"dev": true
},
"clipboard": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.6.tgz",
"integrity": "sha512-g5zbiixBRk/wyKakSwCKd7vQXDjFnAMGHoEyBogG/bw9kTD9GvdAvaoRR1ALcEzt3pVKxZR0pViekPMIS0QyGg==",
"dev": true,
"optional": true,
"requires": {
"good-listener": "^1.2.2",
"select": "^1.1.2",
"tiny-emitter": "^2.0.0"
}
},
"cliui": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
@@ -7287,9 +7420,9 @@
}
},
"core-js": {
"version": "3.6.5",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.5.tgz",
"integrity": "sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA==",
"version": "3.8.1",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.8.1.tgz",
"integrity": "sha512-9Id2xHY1W7m8hCl8NkhQn5CufmF/WuR30BTRewvCXc1aZd3kMECwNZ69ndLbekKfakw9Rf2Xyc+QR6E7Gg+obg==",
"dev": true
},
"core-js-compat": {
@@ -8126,6 +8259,13 @@
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
"dev": true
},
"delegate": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz",
"integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==",
"dev": true,
"optional": true
},
"depd": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
@@ -8671,9 +8811,9 @@
}
},
"electron-to-chromium": {
"version": "1.3.616",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.616.tgz",
"integrity": "sha512-CI8L38UN2BEnqXw3/oRIQTmde0LiSeqWSRlPA42ZTYgJQ8fYenzAM2Z3ni+jtILTcrs5aiXZCGJ96Pm+3/yGyQ==",
"version": "1.3.620",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.620.tgz",
"integrity": "sha512-YbgWXUR2Mu+Fp6rm3GZ5YJdNo8SgZKLUTNSl2PNvdOcM8OIz07jRJnRkIaV9vdszFv9UUuGChh19w9qSuoLJgw==",
"dev": true
},
"elementtree": {
@@ -9618,12 +9758,6 @@
}
}
},
"flat": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz",
"integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==",
"dev": true
},
"flush-promises": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/flush-promises/-/flush-promises-1.0.2.tgz",
@@ -10053,6 +10187,16 @@
}
}
},
"good-listener": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz",
"integrity": "sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=",
"dev": true,
"optional": true,
"requires": {
"delegate": "^3.1.2"
}
},
"got": {
"version": "9.6.0",
"resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz",
@@ -10583,6 +10727,12 @@
"integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=",
"dev": true
},
"human-signals": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz",
"integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==",
"dev": true
},
"iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
@@ -14183,9 +14333,9 @@
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"dev": true
}
}
@@ -14882,6 +15032,15 @@
"integrity": "sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ==",
"dev": true
},
"prismjs": {
"version": "1.22.0",
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.22.0.tgz",
"integrity": "sha512-lLJ/Wt9yy0AiSYBf212kK3mM5L8ycwlyTlSxHBAneXLR0nzFMlZ5y7riFPF3E33zXOF2IH95xdY5jIyZbM9z/w==",
"dev": true,
"requires": {
"clipboard": "^2.0.0"
}
},
"process": {
"version": "0.11.10",
"resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
@@ -15047,9 +15206,9 @@
"dev": true
},
"quasar": {
"version": "1.14.6",
"resolved": "https://registry.npmjs.org/quasar/-/quasar-1.14.6.tgz",
"integrity": "sha512-EuVld48G2UiIOU3t2xRfLqYEj0choawWFd4cWs5Ea2TaDF+BR+JTTXovUI1kar8QBKMhU6i6ChTt8fyNATdbfQ=="
"version": "1.14.7",
"resolved": "https://registry.npmjs.org/quasar/-/quasar-1.14.7.tgz",
"integrity": "sha512-AP++F9xNEmzdK4zEjYBgEF0lifg3LBIrE24weUyQqS/jNQ22YT1cGyqDzWrfScaGLmRdm27R6eWLsbT4Qnh3Pg=="
},
"query-string": {
"version": "4.3.4",
@@ -15915,6 +16074,13 @@
"commander": "^2.8.1"
}
},
"select": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz",
"integrity": "sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=",
"dev": true,
"optional": true
},
"select-hose": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz",
@@ -16415,9 +16581,9 @@
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"dev": true
}
}
@@ -16881,6 +17047,12 @@
"integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=",
"dev": true
},
"strip-final-newline": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
"integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
"dev": true
},
"strip-json-comments": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
@@ -17333,6 +17505,13 @@
"integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=",
"dev": true
},
"tiny-emitter": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz",
"integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==",
"dev": true,
"optional": true
},
"tmp": {
"version": "0.0.33",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
@@ -18157,6 +18336,12 @@
"vue-style-loader": "^4.1.0"
}
},
"vue-prism-editor": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/vue-prism-editor/-/vue-prism-editor-1.2.2.tgz",
"integrity": "sha512-Lq2VgVygTx3Whn/tC8gD4m1ajA4lzSyCTqPLZA1Dq/ErbBaZA93FWRblwCoDR7AD2nXhGWuiTzb5ih3guzB7DA==",
"dev": true
},
"vue-router": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.2.0.tgz",

View File

@@ -9,20 +9,22 @@
"test:unit": "quasar test --unit jest"
},
"dependencies": {
"@quasar/extras": "^1.9.10",
"@quasar/extras": "^1.9.11",
"axios": "^0.21.0",
"dotenv": "^8.2.0",
"qrcode.vue": "^1.7.0",
"quasar": "^1.14.6"
"quasar": "^1.14.7"
},
"devDependencies": {
"@quasar/app": "^2.1.9",
"@quasar/app": "^2.1.11",
"@quasar/cli": "^1.1.2",
"@quasar/quasar-app-extension-testing": "^1.0.0",
"@quasar/quasar-app-extension-testing": "^1.0.3",
"@quasar/quasar-app-extension-testing-unit-jest": "^1.0.1",
"core-js": "^3.6.5",
"core-js": "^3.8.1",
"flush-promises": "^1.0.2",
"fs-extra": "^9.0.1"
"fs-extra": "^9.0.1",
"prismjs": "^1.22.0",
"vue-prism-editor": "^1.2.2"
},
"browserslist": [
"last 4 Chrome versions",

View File

@@ -96,7 +96,7 @@
<q-menu auto-close>
<q-list dense style="min-width: 100px">
<!-- script manager -->
<q-item clickable v-close-popup @click="showScriptManager">
<q-item clickable v-close-popup @click="showScriptManager = true">
<q-item-section>Script Manager</q-item-section>
</q-item>
<!-- automation manager -->
@@ -182,8 +182,11 @@
</q-dialog>
</div>
<!-- Script Manager -->
<ScriptManager />
<div class="q-pa-md q-gutter-sm">
<q-dialog v-model="showScriptManager">
<ScriptManager @close="showScriptManager = false" />
</q-dialog>
</div>
<!-- Automation Manager -->
<div class="q-pa-md q-gutter-sm">
<q-dialog v-model="showAutomationManager">
@@ -271,6 +274,7 @@ export default {
bulkMode: null,
showDeployment: false,
showDebugLog: false,
showScriptManager: false,
};
},
methods: {
@@ -296,9 +300,6 @@ export default {
this.bulkMode = null;
this.showBulkAction = false;
},
showScriptManager() {
this.$store.commit("TOGGLE_SCRIPT_MANAGER", true);
},
edited() {
this.$emit("edited");
},

View File

@@ -1,150 +1,250 @@
<template>
<div class="q-pa-md q-gutter-sm">
<q-dialog :value="toggleScriptManager" @hide="hideScriptManager" @show="getScripts">
<q-card style="min-width: 70vw">
<q-bar>
<q-btn @click="getScripts" class="q-mr-sm" dense flat push icon="refresh" />Script Manager
<q-space />
<q-btn dense flat icon="close" v-close-popup>
<q-tooltip content-class="bg-white text-primary">Close</q-tooltip>
</q-btn>
</q-bar>
<div class="q-pa-md">
<div class="q-gutter-sm row">
<div style="width: 60vw; max-width: 90vw">
<q-card>
<q-bar>
<q-btn @click="getScripts" class="q-mr-sm" dense flat push icon="refresh" />Script Manager
<q-space />
<q-btn dense flat icon="close" v-close-popup>
<q-tooltip content-class="bg-white text-primary">Close</q-tooltip>
</q-btn>
</q-bar>
<div class="q-pa-md">
<div class="q-gutter-sm row">
<q-btn-dropdown icon="add" label="New" no-caps dense flat>
<q-list dense>
<q-item clickable v-close-popup @click="newScript">
<q-item-section side>
<q-icon size="xs" name="add" />
</q-item-section>
<q-item-section>
<q-item-label>New Script</q-item-label>
</q-item-section>
</q-item>
<q-item clickable v-close-popup @click="showScriptUploadModal = true">
<q-item-section side>
<q-icon size="xs" name="cloud_upload" />
</q-item-section>
<q-item-section>
<q-item-label>Upload Script</q-item-label>
</q-item-section>
</q-item>
</q-list>
</q-btn-dropdown>
<q-btn
label="Edit"
:disable="!isRowSelected || isBuiltInScript(selectedScript.id)"
dense
flat
push
unelevated
no-caps
icon="edit"
@click="editScript(selectedScript)"
/>
<q-btn
label="Delete"
:disable="!isRowSelected || isBuiltInScript(selectedScript.id)"
dense
flat
push
unelevated
no-caps
icon="delete"
@click="deleteScript(selectedScript.id)"
/>
<q-btn
label="View Code"
:disable="!isRowSelected"
dense
flat
push
unelevated
no-caps
icon="remove_red_eye"
@click="viewCode(selectedScript)"
/>
<q-btn
label="Download Script"
:disable="!isRowSelected"
dense
flat
push
unelevated
no-caps
icon="cloud_download"
@click="downloadScript(selectedScript)"
/>
</div>
<q-table
style="min-height: 30vw; max-height: 30vw"
dense
:table-class="{ 'table-bgcolor': !$q.dark.isActive, 'table-bgcolor-dark': $q.dark.isActive }"
class="settings-tbl-sticky scroll"
:data="visibleScripts"
:columns="columns"
:visible-columns="visibleColumns"
:pagination.sync="pagination"
:filter="search"
row-key="id"
binary-state-sort
hide-bottom
virtual-scroll
flat
:rows-per-page-options="[0]"
>
<template v-slot:header-cell-favorite="props">
<q-th :props="props" auto-width>
<q-icon name="star" color="yellow-8" size="sm" />
</q-th>
</template>
<template v-slot:top>
<q-btn
label="New"
dense
flat
push
unelevated
no-caps
icon="add"
@click="
showScript('add');
clearRow();
"
/>
<q-btn
label="Edit"
:disable="scriptpk === null"
dense
flat
push
unelevated
no-caps
icon="edit"
@click="showScript('edit')"
/>
<q-btn
label="Delete"
:disable="scriptpk === null || isBuiltInScript(scriptpk)"
dense
flat
push
unelevated
no-caps
icon="delete"
@click="deleteScript"
/>
<q-btn
label="View Code"
:disable="scriptpk === null"
dense
flat
push
unelevated
no-caps
icon="remove_red_eye"
@click="viewCode"
/>
<q-btn
label="Download Script"
:disable="scriptpk === null"
dense
flat
push
unelevated
no-caps
icon="cloud_download"
@click="downloadScript"
class="q-ml-sm"
:label="showCommunityScripts ? 'Hide Community Scripts' : 'Show Community Scripts'"
@click="setShowCommunityScripts(!showCommunityScripts)"
/>
<q-space />
<q-toggle :value="showBuiltIn" label="Show Community Scripts" @input="showBuiltIn = !showBuiltIn" />
</div>
<q-table
dense
:table-class="{ 'table-bgcolor': !$q.dark.isActive, 'table-bgcolor-dark': $q.dark.isActive }"
class="settings-tbl-sticky"
:data="visibleScripts"
:columns="columns"
:visible-columns="visibleColumns"
:pagination.sync="pagination"
row-key="id"
binary-state-sort
hide-bottom
virtual-scroll
flat
:rows-per-page-options="[0]"
>
<template slot="body" slot-scope="props" :props="props">
<q-tr
:class="rowSelectedClass(props.row.id)"
@click="
scriptpk = props.row.id;
filename = props.row.filename;
code = props.row.code;
"
>
<q-td>{{ props.row.name }}</q-td>
<q-td>
{{ truncateText(props.row.description) }}
<q-tooltip v-if="props.row.description.length >= 60" content-style="font-size: 12px">{{
props.row.description
}}</q-tooltip>
</q-td>
<q-td>{{ props.row.filename }}</q-td>
<q-td>{{ props.row.shell }}</q-td>
<q-td v-show="props.row.script_type === 'userdefined'">User Defined</q-td>
<q-td v-show="props.row.script_type === 'builtin'">Community Uploaded</q-td>
</q-tr>
</template>
</q-table>
</div>
<q-card-section></q-card-section>
<q-separator />
<q-card-section></q-card-section>
</q-card>
</q-dialog>
<q-dialog v-model="showScriptModal">
<ScriptModal :mode="mode" :scriptpk="scriptpk" @close="showScriptModal = false" @uploaded="getScripts" />
<q-input
v-model="search"
style="width: 300px"
label="Search"
dense
outlined
clearable
class="q-pr-md q-pb-xs"
>
<template v-slot:prepend>
<q-icon name="search" color="primary" />
</template>
</q-input>
</template>
<template slot="body" slot-scope="props" :props="props">
<q-tr
:class="`${rowSelectedClass(props.row.id)} cursor-pointer`"
@click="selectedScript = props.row"
@contextmenu="selectedScript = props.row"
>
<!-- Context Menu -->
<q-menu context-menu>
<q-list dense style="min-width: 200px">
<q-item
clickable
v-close-popup
@click="editScript(props.row)"
id="context-edit"
v-if="props.row.script_type !== 'builtin'"
>
<q-item-section side>
<q-icon name="edit" />
</q-item-section>
<q-item-section>Edit</q-item-section>
</q-item>
<q-item
clickable
v-close-popup
@click="deleteScript(props.row.id)"
id="context-delete"
v-if="props.row.script_type !== 'builtin'"
>
<q-item-section side>
<q-icon name="delete" />
</q-item-section>
<q-item-section>Delete</q-item-section>
</q-item>
<q-item clickable v-close-popup @click="favoriteScript(props.row)">
<q-item-section side>
<q-icon name="star" />
</q-item-section>
<q-item-section>{{ favoriteText(props.row.favorite) }}</q-item-section>
</q-item>
<q-separator></q-separator>
<q-item clickable v-close-popup @click="viewCode(props.row)" id="context-view">
<q-item-section side>
<q-icon name="remove_red_eye" />
</q-item-section>
<q-item-section>View Code</q-item-section>
</q-item>
<q-item clickable v-close-popup @click="downloadScript(props.row)" id="context-download">
<q-item-section side>
<q-icon name="cloud_download" />
</q-item-section>
<q-item-section>Download Script</q-item-section>
</q-item>
<q-separator></q-separator>
<q-item clickable v-close-popup>
<q-item-section>Close</q-item-section>
</q-item>
</q-list>
</q-menu>
<q-td>
<q-icon v-if="props.row.favorite" color="yellow-8" name="star" size="sm" />
</q-td>
<q-td>{{ props.row.name }}</q-td>
<q-td>{{ props.row.category }}</q-td>
<q-td>{{ props.row.shell }}</q-td>
<q-td>
{{ truncateText(props.row.description) }}
<q-tooltip v-if="props.row.description.length >= 60" content-style="font-size: 12px">{{
props.row.description
}}</q-tooltip>
</q-td>
</q-tr>
</template>
</q-table>
</div>
<q-separator />
<q-card-section></q-card-section>
</q-card>
<q-dialog v-model="showScriptUploadModal">
<ScriptUploadModal
:script="selectedScript"
:categories="categories"
@close="showScriptUploadModal = false"
@added="getScripts"
/>
</q-dialog>
</div>
</template>
<script>
import axios from "axios";
import mixins from "@/mixins/mixins";
import { mapState } from "vuex";
import ScriptModal from "@/components/modals/scripts/ScriptModal";
import mixins from "@/mixins/mixins";
import ScriptUploadModal from "@/components/modals/scripts/ScriptUploadModal";
import ScriptFormModal from "@/components/modals/scripts/ScriptFormModal";
export default {
name: "ScriptManager",
components: { ScriptModal },
components: { ScriptUploadModal },
mixins: [mixins],
data() {
return {
mode: "add",
scriptpk: null,
showScriptModal: false,
filename: null,
code: null,
showBuiltIn: true,
scripts: [],
selectedScript: {},
showScriptUploadModal: false,
search: "",
pagination: {
rowsPerPage: 0,
sortBy: "script_type",
sortBy: "favorite",
descending: true,
},
columns: [
{ name: "id", label: "ID", field: "id" },
{
name: "favorite",
label: "",
field: "favorite",
align: "left",
sortable: true,
},
{
name: "name",
label: "Name",
@@ -153,16 +253,9 @@ export default {
sortable: true,
},
{
name: "desc",
label: "Description",
field: "description",
align: "left",
sortable: false,
},
{
name: "file",
label: "File",
field: "filename",
name: "category",
label: "Category",
field: "category",
align: "left",
sortable: true,
},
@@ -174,37 +267,57 @@ export default {
sortable: true,
},
{
name: "script_type",
label: "Type",
field: "script_type",
name: "desc",
label: "Description",
field: "description",
align: "left",
sortable: true,
sortable: false,
},
],
visibleColumns: ["name", "desc", "file", "shell", "script_type"],
visibleColumns: ["favorite", "name", "category", "desc", "shell"],
};
},
methods: {
getScripts() {
this.clearRow();
this.$store.dispatch("getScripts");
},
hideScriptManager() {
this.$store.commit("TOGGLE_SCRIPT_MANAGER", false);
},
clearRow() {
this.scriptpk = null;
this.filename = null;
},
viewCode() {
this.$q.dialog({
title: this.filename,
message: `<pre>${this.code}</pre>`,
html: true,
style: "width: 70vw; max-width: 80vw;",
this.$axios.get("/scripts/scripts/").then(r => {
this.scripts = r.data;
});
},
deleteScript() {
setShowCommunityScripts(show) {
this.$store.dispatch("setShowCommunityScripts", show);
},
clearRow() {
this.selectedScript = {};
},
viewCode(script) {
this.$q
.dialog({
component: ScriptFormModal,
parent: this,
script: script,
readonly: true,
})
.onDismiss(() => {
this.getScripts();
});
},
favoriteScript(script) {
this.$q.loading.show();
const notifyText = !script.favorite ? "Script was favorited!" : "Script was removed as a favorite!";
this.$axios
.put(`/scripts/${script.id}/script/`, { favorite: !script.favorite })
.then(() => {
this.getScripts();
this.$q.loading.hide();
this.notifySuccess(notifyText);
})
.catch(() => {
this.$q.loading.hide();
this.notifyError("Something went wrong");
});
},
deleteScript(scriptpk) {
this.$q
.dialog({
title: "Delete script?",
@@ -212,8 +325,8 @@ export default {
ok: { label: "Delete", color: "negative" },
})
.onOk(() => {
axios
.delete(`/scripts/${this.scriptpk}/script/`)
this.$axios
.delete(`/scripts/${scriptpk}/script/`)
.then(r => {
this.getScripts();
this.notifySuccess(r.data);
@@ -221,29 +334,18 @@ export default {
.catch(() => this.notifySuccess("Something went wrong"));
});
},
downloadScript() {
axios
.get(`/scripts/${this.scriptpk}/download/`, { responseType: "blob" })
downloadScript(script) {
this.$axios
.get(`/scripts/${script.id}/download/`)
.then(({ data }) => {
const blob = new Blob([data], { type: "text/plain" });
const blob = new Blob([data.code], { type: "text/plain;charset=utf-8" });
let link = document.createElement("a");
link.href = window.URL.createObjectURL(blob);
link.download = this.filename;
link.download = data.filename;
link.click();
})
.catch(() => this.notifyError("Something went wrong"));
},
showScript(mode) {
switch (mode) {
case "add":
this.mode = "add";
break;
case "edit":
this.mode = "edit";
break;
}
this.showScriptModal = true;
},
truncateText(txt) {
return txt.length >= 60 ? txt.substring(0, 60) + "..." : txt;
},
@@ -255,16 +357,55 @@ export default {
}
},
rowSelectedClass(id) {
if (this.scriptpk === id) return this.$q.dark.isActive ? "highlight-dark" : "highlight";
if (this.selectedScript.id === id) return this.$q.dark.isActive ? "highlight-dark" : "highlight";
},
favoriteText(isFavorite) {
return isFavorite ? "Remove as Favorite" : "Add as Favorite";
},
newScript() {
this.$q
.dialog({
component: ScriptFormModal,
parent: this,
categories: this.categories,
readonly: false,
})
.onDismiss(() => {
this.getScripts();
});
},
editScript(script) {
this.$q
.dialog({
component: ScriptFormModal,
parent: this,
script: script,
categories: this.categories,
readonly: false,
})
.onDismiss(() => {
this.getScripts();
});
},
},
computed: {
...mapState({
toggleScriptManager: state => state.toggleScriptManager,
scripts: state => state.scripts,
}),
...mapState(["showCommunityScripts"]),
visibleScripts() {
return this.showBuiltIn ? this.scripts : this.scripts.filter(i => i.script_type !== "builtin");
return this.showCommunityScripts ? this.scripts : this.scripts.filter(i => i.script_type !== "builtin");
},
categories() {
let list = [];
this.scripts.forEach(script => {
if (!!script.category && !list.includes(script.category)) {
if (script.category !== "Community") {
list.push(script.category);
}
}
});
return list;
},
isRowSelected() {
return this.selectedScript.id !== null && this.selectedScript.id !== undefined;
},
},
mounted() {

View File

@@ -155,7 +155,6 @@
<script>
import mixins from "@/mixins/mixins";
import { mapGetters } from "vuex";
export default {
name: "BulkAction",
@@ -167,6 +166,7 @@ export default {
return {
target: "client",
selected_mode: null,
scriptOptions: [],
scriptPK: null,
timeout: 900,
client: null,
@@ -182,16 +182,18 @@ export default {
};
},
computed: {
...mapGetters(["scripts"]),
sites() {
return !!this.client ? this.formatSiteOptions(this.client.sites) : [];
},
scriptOptions() {
const ret = this.scripts.map(script => ({ label: script.name, value: script.id }));
return ret.sort((a, b) => a.label.localeCompare(b.label));
},
},
methods: {
getScripts() {
this.$axios.get("/scripts/scripts/").then(r => {
this.scriptOptions = r.data.map(
script => ({ label: script.name, value: script.id })).sort((a, b) => a.label.localeCompare(b.label)
);
});
},
send() {
this.$q.loading.show();
const data = {
@@ -253,6 +255,7 @@ export default {
this.setTitles();
this.getClients();
this.getAgents();
this.getScripts()
this.selected_mode = this.mode;
},

View File

@@ -76,6 +76,7 @@ export default {
},
data() {
return {
scriptOptions: [],
loading: false,
scriptPK: null,
timeout: 30,
@@ -85,22 +86,21 @@ export default {
};
},
computed: {
...mapGetters(["scripts"]),
hostname() {
return this.$store.state.agentSummary.hostname;
},
width() {
return this.ret === null ? "40vw" : "70vw";
},
scriptOptions() {
const ret = [];
this.scripts.forEach(i => {
ret.push({ label: i.name, value: i.id });
});
return ret.sort((a, b) => a.label.localeCompare(b.label));
},
},
methods: {
getScripts() {
this.$axios.get("/scripts/scripts/").then(r => {
this.scriptOptions = r.data.map(
script => ({ label: script.name, value: script.id })).sort((a, b) => a.label.localeCompare(b.label)
);
});
},
send() {
this.ret = null;
this.loading = true;
@@ -129,5 +129,8 @@ export default {
});
},
},
created() {
this.getScripts()
}
};
</script>

View File

@@ -1,5 +1,5 @@
<template>
<q-card v-if="scripts.length === 0" style="min-width: 400px">
<q-card v-if="scriptOptions.length === 0" style="min-width: 400px">
<q-card-section class="row items-center">
<div class="text-h6">Add Script Check</div>
<q-space />
@@ -80,9 +80,7 @@
</template>
<script>
import axios from "axios";
import mixins from "@/mixins/mixins";
import { mapGetters, mapState } from "vuex";
export default {
name: "ScriptCheck",
props: {
@@ -101,22 +99,20 @@ export default {
timeout: 120,
fails_b4_alert: 1,
},
scriptOptions: [],
failOptions: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
};
},
computed: {
...mapGetters(["scripts"]),
scriptOptions() {
const ret = [];
this.scripts.forEach(i => {
ret.push({ label: i.name, value: i.id });
});
return ret.sort((a, b) => a.label.localeCompare(b.label));
},
},
methods: {
getScripts() {
this.$axios.get("/scripts/scripts/").then(r => {
this.scriptOptions = r.data.map(
script => ({ label: script.name, value: script.id })).sort((a, b) => a.label.localeCompare(b.label)
);
});
},
getCheck() {
axios.get(`/checks/${this.checkpk}/check/`).then(r => {
this.$axios.get(`/checks/${this.checkpk}/check/`).then(r => {
this.scriptcheck = r.data;
this.scriptcheck.script = r.data.script.id;
});
@@ -127,7 +123,7 @@ export default {
...pk,
check: this.scriptcheck,
};
axios
this.$axios
.post("/checks/checks/", data)
.then(r => {
this.$emit("close");
@@ -137,7 +133,7 @@ export default {
.catch(e => this.notifyError(e.response.data.non_field_errors));
},
editCheck() {
axios
this.$axios
.patch(`/checks/${this.checkpk}/check/`, this.scriptcheck)
.then(r => {
this.$emit("close");
@@ -158,6 +154,8 @@ export default {
if (this.mode === "edit") {
this.getCheck();
}
this.getScripts()
},
};
</script>

View File

@@ -0,0 +1,270 @@
<template>
<q-dialog ref="dialog" @hide="onHide" persistent :maximized="maximized">
<q-card class="q-dialog-plugin" :style="getMaxWidth">
<q-bar>
{{ title }}
<q-space />
<q-btn dense flat icon="minimize" @click="maximized = false" :disable="!maximized">
<q-tooltip v-if="maximized" content-class="bg-white text-primary">Minimize</q-tooltip>
</q-btn>
<q-btn dense flat icon="crop_square" @click="maximized = true" :disable="maximized">
<q-tooltip v-if="!maximized" content-class="bg-white text-primary">Maximize</q-tooltip>
</q-btn>
<q-btn dense flat icon="close" v-close-popup>
<q-tooltip content-class="bg-white text-primary">Close</q-tooltip>
</q-btn>
</q-bar>
<q-form @submit="submit">
<q-card-section class="row">
<div class="q-pa-sm col-1" style="width: auto">
<q-icon
class="cursor-pointer"
:name="favoriteIcon"
size="md"
color="yellow-8"
@[clickEvent]="localScript.favorite = !localScript.favorite"
/>
</div>
<div class="q-pa-sm col-2">
<q-input filled dense :readonly="readonly" v-model="localScript.name" label="Name" />
</div>
<div class="q-pa-sm col-2">
<q-select
:readonly="readonly"
options-dense
filled
dense
v-model="localScript.shell"
:options="shellOptions"
emit-value
map-options
label="Shell Type"
/>
</div>
<div class="q-pa-sm col-3">
<q-select
hint="Press Enter or Tab when adding a new value"
dense
options-dense
filled
v-model="localScript.category"
:options="filterOptions"
use-input
clearable
new-value-mode="add-unique"
debounce="0"
@filter="filterFn"
label="Category"
:readonly="readonly"
/>
</div>
<div class="q-pa-sm col-4">
<q-input filled dense :readonly="readonly" v-model="localScript.description" label="Description" />
</div>
</q-card-section>
<prism-editor
class="editor"
:readonly="readonly"
v-model="localScript.code"
:highlight="highlighter"
:style="heightVar"
lineNumbers
></prism-editor>
<q-card-actions v-if="!readonly">
<q-space />
<q-btn dense flat label="Cancel" v-close-popup />
<q-btn dense flat label="Save" color="primary" type="submit" />
</q-card-actions>
</q-form>
</q-card>
</q-dialog>
</template>
<script>
import mixins from "@/mixins/mixins";
import { PrismEditor } from "vue-prism-editor";
import "vue-prism-editor/dist/prismeditor.min.css";
import { highlight, languages } from "prismjs/components/prism-core";
import "prismjs/components/prism-batch";
import "prismjs/components/prism-python";
import "prismjs/components/prism-powershell";
import "prismjs/themes/prism-tomorrow.css";
export default {
name: "ScriptFormModal",
mixins: [mixins],
components: {
PrismEditor,
},
props: {
script: Object,
categories: !Array,
readonly: Boolean,
},
data() {
return {
localScript: {
name: "",
code: "",
shell: "powershell",
description: "",
category: "",
favorite: false,
script_type: "userdefined",
},
maximized: false,
filterOptions: [],
shellOptions: [
{ label: "Powershell", value: "powershell" },
{ label: "Batch", value: "cmd" },
{ label: "Python", value: "python" },
],
};
},
methods: {
submit() {
this.$q.loading.show();
if (!!this.script) {
this.$axios
.put(`/scripts/${this.script.id}/script/`, this.localScript)
.then(r => {
this.$q.loading.hide();
this.$emit("hide");
this.notifySuccess(r.data);
})
.catch(e => {
this.$q.loading.hide();
this.notifyError(e.response.data.non_field_errors, 4000);
});
} else {
this.$axios
.post(`/scripts/scripts/`, this.localScript)
.then(r => {
this.$q.loading.hide();
this.$emit("hide");
this.notifySuccess(r.data);
})
.catch(e => {
this.$q.loading.hide();
this.notifyError(e.response.data.non_field_errors, 4000);
});
}
},
getCode() {
this.$q.loading.show();
this.$axios
.get(`/scripts/${this.script.id}/download/`)
.then(r => {
this.$q.loading.hide();
this.localScript.code = r.data.code;
})
.catch(e => {
this.$q.loading.hide();
this.notifyError(e.response.data.non_field_errors, 4000);
});
},
highlighter(code) {
let lang = this.localScript.shell === "cmd" ? "batch" : this.localScript.shell;
return highlight(code, languages[lang]);
},
show() {
this.$refs.dialog.show();
},
hide() {
this.$refs.dialog.hide();
},
onHide() {
this.$emit("hide");
},
filterFn(val, update) {
update(() => {
if (val === "") {
this.filterOptions = this.categories;
} else {
const needle = val.toLowerCase();
this.filterOptions = this.categories.filter(v => v.toLowerCase().indexOf(needle) > -1);
}
});
},
},
computed: {
favoriteIcon() {
return this.localScript.favorite ? "star" : "star_outline";
},
title() {
if (!!this.script) {
return this.readonly ? `Viewing ${this.script.name}` : `Editing ${this.script.name}`;
} else {
return "Adding new script";
}
},
clickEvent() {
return !this.readonly ? "click" : null;
},
getMaxWidth() {
return this.maximized ? "" : "width: 60vw; max-width: 90vw";
},
heightVar() {
return this.maximized ? "--prism-height: 80vh" : "--prism-height: 70vh";
},
},
created() {
if (!!this.script) {
this.localScript.id = this.script.id;
this.localScript.name = this.script.name;
this.localScript.description = this.script.description;
this.localScript.favorite = this.script.favorite;
this.localScript.shell = this.script.shell;
this.localScript.category = this.script.category;
this.localScript.script_type = this.script.script_type;
this.getCode();
}
},
};
</script>
<style>
/* required class */
.editor {
/* we dont use `language-` classes anymore so thats why we need to add background and text color manually */
background: #2d2d2d;
color: #ccc;
/* you must provide font-family font-size line-height. Example: */
font-family: Fira code, Fira Mono, Consolas, Menlo, Courier, monospace;
font-size: 14px;
line-height: 1.5;
padding: 5px;
height: var(--prism-height);
}
.prism-editor__container {
height: 60000em;
}
/* optional class for removing the outline */
.prism-editor__textarea:focus {
outline: none;
}
.prism-editor__textarea,
.prism-editor__container {
width: 10000em !important;
-ms-overflow-style: none;
scrollbar-width: none;
}
.prism-editor__container::-webkit-scrollbar,
.prism-editor__textarea::-webkit-scrollbar {
display: none;
}
.prism-editor__editor {
white-space: pre !important;
}
.prism-editor__container {
overflow-x: auto !important;
}
</style>

View File

@@ -1,180 +0,0 @@
<template>
<q-card style="width: 40vw">
<q-form @submit.prevent="handleScript">
<q-card-section class="row items-center">
<div v-if="mode === 'add'" class="text-h6">Add Script</div>
<div v-else-if="mode === 'edit'" class="text-h6">Edit Script</div>
<q-space />
<q-btn icon="close" flat round dense v-close-popup />
</q-card-section>
<q-card-section class="row">
<div class="col-2">Name:</div>
<div class="col-10">
<q-input
:disable="isBuiltInScript"
outlined
dense
v-model="script.name"
:rules="[val => !!val || '*Required']"
/>
</div>
</q-card-section>
<q-card-section class="row">
<div class="col-2">Description:</div>
<div class="col-10">
<q-input :disable="isBuiltInScript" outlined dense v-model="script.description" type="textarea" />
</div>
</q-card-section>
<q-card-section class="row">
<div class="col-2">File Upload:</div>
<div v-if="mode === 'add'" class="col-10">
<q-file
v-model="script.filename"
label="Supported file types: .ps1, .bat, .py"
stack-label
filled
counter
accept=".ps1, .bat, .py"
:rules="[val => !!val || '*Required']"
>
<template v-slot:prepend>
<q-icon name="attach_file" />
</template>
</q-file>
</div>
<!-- don't enforce rules if edit mode -->
<div v-if="mode === 'edit'" class="col-10">
<q-file
v-model="script.filename"
:disable="isBuiltInScript"
label="Upload new script version"
stack-label
filled
counter
accept=".ps1, .bat, .py"
>
<template v-slot:prepend>
<q-icon name="attach_file" />
</template>
</q-file>
</div>
</q-card-section>
<q-card-section class="row">
<div class="col-2">Type:</div>
<q-select
:disable="isBuiltInScript"
dense
options-dense
class="col-10"
outlined
v-model="script.shell"
:options="shellOptions"
emit-value
map-options
:rules="[val => !!val || '*Required']"
/>
</q-card-section>
<q-card-section class="row items-center">
<q-btn v-if="mode === 'add'" label="Upload" color="primary" type="submit" />
<q-btn v-else-if="mode === 'edit'" :disable="isBuiltInScript" label="Edit" color="primary" type="submit" />
</q-card-section>
</q-form>
</q-card>
</template>
<script>
import axios from "axios";
import { mapState } from "vuex";
import mixins from "@/mixins/mixins";
export default {
name: "ScriptModal",
mixins: [mixins],
props: {
scriptpk: Number,
mode: String,
},
data() {
return {
script: {},
originalFile: null,
shellOptions: [
{ label: "Powershell", value: "powershell" },
{ label: "Batch (CMD)", value: "cmd" },
{ label: "Python", value: "python" },
],
};
},
methods: {
getScript() {
axios.get(`/scripts/${this.scriptpk}/script/`).then(r => {
this.originalFile = r.data.filename;
delete r.data.filename;
this.script = r.data;
});
},
handleScript() {
let formData = new FormData();
if (this.mode === "add") {
formData.append("filename", this.script.filename);
}
// only append file if uploading a new file
else if (this.mode === "edit" && this.script.filename) {
formData.append("filename", this.script.filename);
// filename needs to be the same if editing so we don't have a ghost file on server
if (this.script.filename.name !== this.originalFile) {
this.notifyError("Script filename must be the same if editing.", 4000);
return;
}
}
let url;
switch (this.mode) {
case "add":
url = "/scripts/scripts/";
break;
case "edit":
url = `/scripts/${this.scriptpk}/script/`;
break;
}
formData.append("name", this.script.name);
formData.append("shell", this.script.shell);
formData.append("description", this.script.description);
this.$q.loading.show();
axios
.put(url, formData)
.then(r => {
this.$q.loading.hide();
this.$emit("close");
this.$emit("uploaded");
this.notifySuccess(r.data);
})
.catch(e => {
this.$q.loading.hide();
this.notifyError(e.response.data.non_field_errors, 4000);
});
},
},
computed: {
...mapState({
scripts: state => state.scripts,
}),
isBuiltInScript() {
if (this.mode === "edit") {
return this.scripts.find(i => i.id === this.scriptpk).script_type === "builtin" ? true : false;
} else {
return false;
}
},
},
created() {
if (this.mode === "edit") {
this.getScript();
}
},
};
</script>

View File

@@ -0,0 +1,149 @@
<template>
<q-card style="width: 40vw">
<q-bar>
Add Script
<q-space />
<q-btn dense flat icon="close" v-close-popup>
<q-tooltip content-class="bg-white text-primary">Close</q-tooltip>
</q-btn>
</q-bar>
<q-form @submit.prevent="submit">
<q-card-section class="row">
<div class="col-2">Name:</div>
<div class="col-10">
<q-input outlined dense v-model="script.name" :rules="[val => !!val || '*Required']" />
</div>
</q-card-section>
<q-card-section class="row">
<div class="col-2">Description:</div>
<div class="col-10">
<q-input outlined dense v-model="script.description" type="textarea" />
</div>
</q-card-section>
<q-card-section class="row">
<div class="col-2">Category:</div>
<q-select
hint="Press Enter or Tab when adding a new value"
dense
options-dense
class="col-10"
outlined
v-model="script.category"
:options="filterOptions"
use-input
clearable
new-value-mode="add-unique"
debounce="0"
@filter="filterFn"
/>
</q-card-section>
<q-card-section class="row">
<div class="col-2">File Upload:</div>
<div class="col-10">
<q-file
v-model="script.filename"
label="Supported file types: .ps1, .bat, .py"
stack-label
filled
counter
accept=".ps1, .bat, .py"
>
<template v-slot:prepend>
<q-icon name="attach_file" />
</template>
</q-file>
</div>
</q-card-section>
<q-card-section class="row">
<div class="col-2">Type:</div>
<q-select
dense
options-dense
class="col-10"
outlined
v-model="script.shell"
:options="shellOptions"
emit-value
map-options
/>
</q-card-section>
<q-card-actions>
<q-space />
<q-btn dense flat label="Cancel" v-close-popup />
<q-btn dense flat label="Add" color="primary" type="submit" />
</q-card-actions>
</q-form>
</q-card>
</template>
<script>
import mixins from "@/mixins/mixins";
export default {
name: "ScriptModal",
mixins: [mixins],
props: {
categories: !Array,
},
data() {
return {
script: {
name: "",
description: "",
shell: "powershell",
category: null,
},
shellOptions: [
{ label: "Powershell", value: "powershell" },
{ label: "Batch (CMD)", value: "cmd" },
{ label: "Python", value: "python" },
],
filterOptions: [],
};
},
methods: {
submit() {
this.$q.loading.show();
let formData = new FormData();
if (!!this.script.filename) {
formData.append("filename", this.script.filename);
}
if (!!this.script.category) {
formData.append("category", this.script.category);
} else {
formData.append("category", "");
}
formData.append("name", this.script.name);
formData.append("shell", this.script.shell);
formData.append("description", this.script.description);
this.$axios
.post("/scripts/scripts/", formData)
.then(r => {
this.$q.loading.hide();
this.$emit("close");
this.$emit("added");
this.notifySuccess(r.data);
})
.catch(e => {
this.$q.loading.hide();
this.notifyError(e.response.data.non_field_errors, 4000);
});
},
filterFn(val, update) {
update(() => {
if (val === "") {
this.filterOptions = this.categories;
} else {
const needle = val.toLowerCase();
this.filterOptions = this.categories.filter(v => v.toLowerCase().indexOf(needle) > -1);
}
});
},
},
};
</script>

View File

@@ -1,5 +1,5 @@
<template>
<q-card v-if="scripts.length === 0" class="q-pa-xs" style="min-width: 400px">
<q-card v-if="scriptOptions.length === 0" class="q-pa-xs" style="min-width: 400px">
<q-card-section class="row items-center">
<div class="text-h6">Add Automated Task</div>
<q-space />
@@ -26,7 +26,7 @@
outlined
v-model="autotask.script"
:options="scriptOptions"
label="Select task"
label="Select script"
map-options
emit-value
/>
@@ -147,8 +147,7 @@
</template>
<script>
import axios from "axios";
import { mapState, mapGetters } from "vuex";
import { mapGetters } from "vuex";
import mixins from "@/mixins/mixins";
export default {
@@ -160,6 +159,7 @@ export default {
data() {
return {
step: 1,
scriptOptions: [],
autotask: {
script: null,
script_args: [],
@@ -202,7 +202,7 @@ export default {
autotask: this.autotask,
};
axios
this.$axios
.post("tasks/automatedtasks/", data)
.then(r => {
this.$emit("close");
@@ -220,11 +220,15 @@ export default {
}
},
getScripts() {
this.$store.dispatch("getScripts");
},
this.$axios.get("/scripts/scripts/").then(r => {
this.scriptOptions = r.data.map(
script => ({ label: script.name, value: script.id })).sort((a, b) => a.label.localeCompare(b.label)
);
});
}
},
computed: {
...mapGetters(["selectedAgentPk", "scripts"]),
...mapGetters(["selectedAgentPk"]),
checks() {
return this.policypk
? this.$store.state.automation.checks
@@ -237,13 +241,6 @@ export default {
});
return r.sort((a, b) => a.label.localeCompare(b.label));
},
scriptOptions() {
const r = [];
this.scripts.forEach(i => {
r.push({ label: i.name, value: i.id });
});
return r.sort((a, b) => a.label.localeCompare(b.label));
},
step1Done() {
return this.step > 1 && this.autotask.script !== null && this.autotask.name && this.autotask.timeout
? true
@@ -264,7 +261,7 @@ export default {
},
},
created() {
this.getScripts();
},
this.getScripts()
}
};
</script>

View File

@@ -29,12 +29,11 @@ export default function () {
agentTableLoading: false,
treeLoading: false,
installedSoftware: [],
scripts: [],
notes: [],
toggleScriptManager: false,
needrefresh: false,
tableHeight: "35vh",
tabHeight: "35vh",
showCommunityScripts: false
},
getters: {
loggedIn(state) {
@@ -68,9 +67,6 @@ export default function () {
agentHostname(state) {
return state.agentSummary.hostname;
},
scripts(state) {
return state.scripts;
},
needRefresh(state) {
return state.needrefresh;
},
@@ -82,9 +78,6 @@ export default function () {
},
},
mutations: {
TOGGLE_SCRIPT_MANAGER(state, action) {
state.toggleScriptManager = action;
},
AGENT_TABLE_LOADING(state, visible) {
state.agentTableLoading = visible;
},
@@ -128,9 +121,6 @@ export default function () {
(state.installedSoftware = []);
state.selectedRow = "";
},
SET_SCRIPTS(state, scripts) {
state.scripts = scripts;
},
SET_REFRESH_NEEDED(state, action) {
state.needrefresh = action;
},
@@ -142,9 +132,17 @@ export default function () {
},
SET_NOTES(state, notes) {
state.notes = notes;
},
setShowCommunityScripts(state, show) {
state.showCommunityScripts = show
}
},
actions: {
setShowCommunityScripts(context, data) {
axios.patch("/accounts/users/ui/", { show_community_scripts: data }).then(r => {
context.commit("setShowCommunityScripts", data)
})
},
toggleMaintenanceMode(context, data) {
return axios.post("/agents/maintenance/", data)
},
@@ -159,11 +157,6 @@ export default function () {
context.commit("SET_AUTOMATED_TASKS", r.data);
})
},
getScripts(context) {
axios.get("/scripts/scripts/").then(r => {
context.commit("SET_SCRIPTS", r.data);
});
},
loadInstalledSoftware(context, pk) {
axios.get(`/software/installed/${pk}`).then(r => {
context.commit("SET_INSTALLED_SOFTWARE", r.data.software);

View File

@@ -673,6 +673,8 @@ export default {
this.darkMode = r.data.dark_mode;
this.$q.dark.set(this.darkMode);
this.currentTRMMVersion = r.data.trmm_version;
this.$store.commit("setShowCommunityScripts", r.data.show_community_scripts);
});
},
showToggleMaintenance(node) {