summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJannik Schönartz2018-07-17 00:22:55 +0200
committerJannik Schönartz2018-07-17 00:22:55 +0200
commite1d4375f741e5c67e0304c7fda36eda41df4b4c1 (patch)
treeff13e78bf7ae322923b2b6c4f371d41f7655752a
parent[server/ipxe] Building ipxe with external configs. (diff)
downloadbas-e1d4375f741e5c67e0304c7fda36eda41df4b4c1.tar.gz
bas-e1d4375f741e5c67e0304c7fda36eda41df4b4c1.tar.xz
bas-e1d4375f741e5c67e0304c7fda36eda41df4b4c1.zip
[external-backends] Added API and Frontend module external-backends.
-rw-r--r--server/api/backends.js75
-rw-r--r--server/lib/external-backends/backends/another-backend.js9
-rw-r--r--server/lib/external-backends/backends/dummy-backend.js9
-rw-r--r--server/lib/external-backends/backends/template-backend.js9
-rw-r--r--server/lib/external-backends/external-backends.js30
-rw-r--r--server/migrations/20180715193710-create-backend.js25
-rw-r--r--server/models/backend.js20
-rw-r--r--server/router.js13
-rw-r--r--webapp/config/index.js2
-rw-r--r--webapp/package-lock.json80
-rw-r--r--webapp/package.json16
-rw-r--r--webapp/src/components/BackendEditComponent.vue191
-rw-r--r--webapp/src/components/BackendModule.vue57
-rw-r--r--webapp/src/components/BackendTableComponent.vue133
-rw-r--r--webapp/src/main.js15
15 files changed, 600 insertions, 84 deletions
diff --git a/server/api/backends.js b/server/api/backends.js
new file mode 100644
index 0000000..e3e6014
--- /dev/null
+++ b/server/api/backends.js
@@ -0,0 +1,75 @@
+/* global __appdir */
+const path = require('path');
+const ExternalBackends = require(path.join(__appdir, 'lib', 'external-backends', 'external-backends.js'));
+var db = require(path.join(__appdir, 'lib', 'sequelize'));
+
+module.exports = {
+ getCredentialsByType: function(req, res) {
+ const backendType = req.query.type;
+ const b = new ExternalBackends();
+ const instance = b.getInstance(backendType);
+ res.status(200).send(instance.getCredentials());
+ },
+
+ getBackendInfoById: function(req, res) {
+ // TODO: Test (Not used for now) needed for edit // TODO: // TODO:
+ const backendId = req.query.id;
+ db.backend.findOne({ where: { id: backendId } }).then(backend => {
+ const b = {
+ backendId: backendId,
+ backendName: backend.name,
+ backendType: backend.type,
+ backendCredentials: backend.credentials
+ }
+ res.status(200).send(b);
+ });
+ },
+
+ getBackendTypes: function(req, res) {
+
+ const backends = new ExternalBackends();
+ var files = backends.getBackends();
+
+ for (var i = 0; i < files.length; i++) {
+
+ // Cut off -backends.js
+ files[i] = files[i].slice(0, -11);
+ }
+
+ res.status(200).send(files);
+ },
+
+ getBackendList: function(req, res) {
+ db.backend.findAll({
+ attributes: ['id', 'name', 'type']
+ }).then(function (backends) {
+ res.status(200).send(backends);
+ });
+ },
+
+ // POST REQUESTS
+ saveBackend: function(req, res) {
+ // Save credentials in the db.
+ const formData = req.body;
+ const credentialString = JSON.stringify(formData.backendCredentials);
+
+ if (formData.backendId == 0) {
+ // Insert new backend in the db.
+ db.backend.create({ name: formData.backendName, type: formData.backendType, credentials: credentialString });
+ } else {
+ // Update an existing backend in the db.
+ db.backend.update({ name: formData.backendName, type: formData.backendType, credentials: credentialString }, {where: {id: formData.backendId} });
+ }
+ //db.backend.findOne({})
+
+ res.status(200).send('success');
+ },
+
+ deleteBackendById: function(req, res) {
+ const backendId = req.body.id;
+
+ db.backend.destroy({ where: { id: backendId } }).then(function() {
+ res.status(200).send('success');
+ });
+ }
+}
diff --git a/server/lib/external-backends/backends/another-backend.js b/server/lib/external-backends/backends/another-backend.js
new file mode 100644
index 0000000..9458e1e
--- /dev/null
+++ b/server/lib/external-backends/backends/another-backend.js
@@ -0,0 +1,9 @@
+var ExternalBackends = require('../external-backends.js');
+
+class AnotherBackend extends ExternalBackends {
+ getCredentials() {
+ return [{ type: "text", name: "text 1" }, { type: "text", name: "text 2" }, { type: "password", name: "password 1", show: false}, { type: "password", name: "password 2", show: true}, { type: "password", name: "password 3", show: false}];
+ }
+}
+
+module.exports = AnotherBackend; \ No newline at end of file
diff --git a/server/lib/external-backends/backends/dummy-backend.js b/server/lib/external-backends/backends/dummy-backend.js
new file mode 100644
index 0000000..205eeb1
--- /dev/null
+++ b/server/lib/external-backends/backends/dummy-backend.js
@@ -0,0 +1,9 @@
+var ExternalBackends = require('../external-backends.js');
+
+class DummyBackend extends ExternalBackends {
+ getCredentials() {
+ return [{ type: "switch", name: "switch 1", value: false }, { type: "switch", name: "switch 2", value: false }, { type: "switch", name: "switch 3", value: true }, { type: "select", name: "selection 1", items: ["wasd", "asdf", "qwertz"] }, { type: "select", name: "selection 2", items: ["1", "2", "3"] }];
+ }
+}
+
+module.exports = DummyBackend; \ No newline at end of file
diff --git a/server/lib/external-backends/backends/template-backend.js b/server/lib/external-backends/backends/template-backend.js
new file mode 100644
index 0000000..3271447
--- /dev/null
+++ b/server/lib/external-backends/backends/template-backend.js
@@ -0,0 +1,9 @@
+var ExternalBackends = require('../external-backends.js');
+
+class TemplateBackend extends ExternalBackends {
+ getCredentials() {
+ return [{ type: "text", name: "text test" }, { type: "password", name: "password test", show: true}, { type: "password", name: "password test nr2", show: false}, { type: "switch", name: "bool test", value: false }, { type: "select", name: "selection test", items: ["wasd", "asdf", "qwertz"] }];
+ }
+}
+
+module.exports = TemplateBackend; \ No newline at end of file
diff --git a/server/lib/external-backends/external-backends.js b/server/lib/external-backends/external-backends.js
new file mode 100644
index 0000000..5ab2adf
--- /dev/null
+++ b/server/lib/external-backends/external-backends.js
@@ -0,0 +1,30 @@
+/* global __appdir */
+const fs = require('fs');
+const path = require('path');
+
+class ExternalBackends {
+ getBackends() {
+ var files = fs.readdirSync(path.join(__appdir, 'lib', 'external-backends', 'backends'));
+ return files;
+ }
+
+ getCredentials() {
+ return "If this method gets called the backend class has NOT IMPLEMENTED the getCredentials method!";
+ }
+
+ getInstance(type) {
+ const bList = this.getBackends();
+ const bType = type + '-backend.js';
+
+ // Check if it's a valid backend type.
+ if (bList.indexOf(bType) == -1) {
+ console.log(bType + " is not a valid backend type.");
+ return null;
+ }
+
+ const backend = new (require(path.join(__appdir, 'lib', 'external-backends', 'backends', bType)))();
+ return backend;
+ }
+}
+
+module.exports = ExternalBackends;
diff --git a/server/migrations/20180715193710-create-backend.js b/server/migrations/20180715193710-create-backend.js
new file mode 100644
index 0000000..3b1a730
--- /dev/null
+++ b/server/migrations/20180715193710-create-backend.js
@@ -0,0 +1,25 @@
+'use strict';
+module.exports = {
+ up: (queryInterface, Sequelize) => {
+ return queryInterface.createTable('backends', {
+ id: {
+ allowNull: false,
+ autoIncrement: true,
+ primaryKey: true,
+ type: Sequelize.INTEGER
+ },
+ name: {
+ type: Sequelize.STRING
+ },
+ type: {
+ type: Sequelize.STRING
+ },
+ credentials: {
+ type: Sequelize.STRING(2048)
+ }
+ });
+ },
+ down: (queryInterface, Sequelize) => {
+ return queryInterface.dropTable('backends');
+ }
+}; \ No newline at end of file
diff --git a/server/models/backend.js b/server/models/backend.js
new file mode 100644
index 0000000..b8b0313
--- /dev/null
+++ b/server/models/backend.js
@@ -0,0 +1,20 @@
+'use strict';
+module.exports = (sequelize, DataTypes) => {
+ var backend = sequelize.define('backend', {
+ id: {
+ allowNull: false,
+ autoIncrement: true,
+ primaryKey: true,
+ type: DataTypes.INTEGER
+ },
+ name: DataTypes.STRING,
+ type: DataTypes.STRING,
+ credentials: DataTypes.STRING(2048)
+ }, {
+ timestamps: false
+ });
+ backend.associate = function(models) {
+ // associations can be defined here
+ };
+ return backend;
+}; \ No newline at end of file
diff --git a/server/router.js b/server/router.js
index 6ae1316..263abed 100644
--- a/server/router.js
+++ b/server/router.js
@@ -37,4 +37,17 @@ router.get('/shell/buildipxe', shell.buildIPXE);
var nodemailer = require(path.join(__dirname, 'lib', 'nodemailer'));
router.get('/mail/send', nodemailer.sendMail);
+// External backends API
+var backends = require(path.join(__dirname, 'api', 'backends'));
+router.get('/backends/getCredentialsByType', auth.verifyToken, backends.getCredentialsByType);
+router.get('/backends/getBackendInfoById', auth.verifyToken, backends.getBackendInfoById);
+router.get('/backends/getBackendList', auth.verifyToken, backends.getBackendList);
+router.get('/backends/getBackendTypes', backends.getBackendTypes);
+router.post('/backends/saveBackend', auth.verifyToken, backends.saveBackend);
+router.post('/backends/deleteBackendById', auth.verifyToken, backends.deleteBackendById)
+
+// Load ipxe scipts API
+var ipxeloader = require(path.join(__dirname, 'api', 'ipxe-loader'));
+router.get('/ipxe-loader/load-script', ipxeloader.loadScript);
+
module.exports = router; \ No newline at end of file
diff --git a/webapp/config/index.js b/webapp/config/index.js
index 89dda2a..0c04bab 100644
--- a/webapp/config/index.js
+++ b/webapp/config/index.js
@@ -44,7 +44,7 @@ module.exports = {
proxyTable: {
// proxy all requests starting with /api to express server
'/api': {
- target: 'https://bas.stfu-kthx.net:8001/'
+ target: 'https://bas.stfu-kthx.net:8888/'
}
}
},
diff --git a/webapp/package-lock.json b/webapp/package-lock.json
index a0231c5..91e680d 100644
--- a/webapp/package-lock.json
+++ b/webapp/package-lock.json
@@ -134,9 +134,9 @@
}
},
"globals": {
- "version": "11.5.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-11.5.0.tgz",
- "integrity": "sha512-hYyf+kI8dm3nORsiiXUQigOU62hDLfJ9G01uyGMxhc6BKsircrUhC4uJPQPUSuq2GrTmiiEt7ewxlMdBewfmKQ==",
+ "version": "11.7.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-11.7.0.tgz",
+ "integrity": "sha512-K8BNSPySfeShBQXsahYB/AbbWruVOTyVpgoIDnl8odPpeSfP2J5QO2oLFFdl2j7GfDCtZj2bMKar2T49itTPCg==",
"dev": true
}
}
@@ -519,9 +519,9 @@
}
},
"babel-eslint": {
- "version": "8.2.3",
- "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-8.2.3.tgz",
- "integrity": "sha512-0HeSTtaXg/Em7FCUWxwOT+KeFSO1O7LuRuzhk7g+1BjwdlQGlHq4OyMi3GqGxrNfEq8jEi6Hmt5ylEQUhurgiQ==",
+ "version": "8.2.5",
+ "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-8.2.5.tgz",
+ "integrity": "sha512-TcdEGCHHquOPQOlH6Fe6MLwPWWWJLdeKhcGoLfOTShETpoH8XYWhjWJw38KCKaTca7c/EdxLolnbakixKxnXDg==",
"dev": true,
"requires": {
"@babel/code-frame": "7.0.0-beta.44",
@@ -2215,9 +2215,9 @@
"dev": true
},
"copy-webpack-plugin": {
- "version": "4.5.1",
- "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-4.5.1.tgz",
- "integrity": "sha512-OlTo6DYg0XfTKOF8eLf79wcHm4Ut10xU2cRBRPMW/NA5F9VMjZGTfRHWDIYC3s+1kObGYrBLshXWU1K0hILkNQ==",
+ "version": "4.5.2",
+ "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-4.5.2.tgz",
+ "integrity": "sha512-zmC33E8FFSq3AbflTvqvPvBo621H36Afsxlui91d+QyZxPIuXghfnTsa1CuqiAaCPgJoSUWfTFbKJnadZpKEbQ==",
"dev": true,
"requires": {
"cacache": "^10.0.4",
@@ -3393,9 +3393,9 @@
}
},
"eslint-plugin-import": {
- "version": "2.12.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.12.0.tgz",
- "integrity": "sha1-2tMXgSktZmSyUxf9BJ0uKy8CIF0=",
+ "version": "2.13.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.13.0.tgz",
+ "integrity": "sha512-t6hGKQDMIt9N8R7vLepsYXgDfeuhp6ZJSgtrLEDxonpSubyxUZHjhm6LsAaZX8q6GYVxkbT3kTsV9G5mBCFR6A==",
"dev": true,
"requires": {
"contains-path": "^0.1.0",
@@ -9015,9 +9015,9 @@
"integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks="
},
"prettier": {
- "version": "1.12.1",
- "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.12.1.tgz",
- "integrity": "sha1-wa0g6APndJ+vkFpAnSNn4Gu+cyU=",
+ "version": "1.13.7",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.13.7.tgz",
+ "integrity": "sha512-KIU72UmYPGk4MujZGYMFwinB7lOf2LsDNGSOC8ufevsrPLISrZbNJlWstRi3m0AMuszbH+EFSQ/r6w56RSPK6w==",
"dev": true
},
"pretty-error": {
@@ -9106,9 +9106,9 @@
}
},
"pumpify": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.0.tgz",
- "integrity": "sha512-UWi0klDoq8xtVzlMRgENV9F7iCTZExaJQSQL187UXsxpk9NnrKGqTqqUNYAKGOzucSOxs2+jUnRNI+rLviPhJg==",
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz",
+ "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==",
"dev": true,
"requires": {
"duplexify": "^3.6.0",
@@ -10702,9 +10702,9 @@
"optional": true
},
"uglifyjs-webpack-plugin": {
- "version": "1.2.5",
- "resolved": "https://registry.npmjs.org/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.2.5.tgz",
- "integrity": "sha512-hIQJ1yxAPhEA2yW/i7Fr+SXZVMp+VEI3d42RTHBgQd2yhp/1UdBcR3QEWPV5ahBxlqQDMEMTuTEvDHSFINfwSw==",
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.2.7.tgz",
+ "integrity": "sha512-1VicfKhCYHLS8m1DCApqBhoulnASsEoJ/BvpUpP4zoNAPpKzdH+ghk0olGJMmwX2/jprK2j3hAHdUbczBSy2FA==",
"dev": true,
"requires": {
"cacache": "^10.0.4",
@@ -10718,14 +10718,14 @@
},
"dependencies": {
"ajv": {
- "version": "6.5.0",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.0.tgz",
- "integrity": "sha512-VDUX1oSajablmiyFyED9L1DFndg0P9h7p1F+NO8FkIzei6EPrR6Zu1n18rd5P8PqaSRd/FrWv3G1TVBqpM83gA==",
+ "version": "6.5.2",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.2.tgz",
+ "integrity": "sha512-hOs7GfvI6tUI1LfZddH82ky6mOMyTuY0mk7kE2pWpmhhUSkumzaTO5vbVwij39MdwPQWCV4Zv57Eo06NtL/GVA==",
"dev": true,
"requires": {
"fast-deep-equal": "^2.0.1",
"fast-json-stable-stringify": "^2.0.0",
- "json-schema-traverse": "^0.3.0",
+ "json-schema-traverse": "^0.4.1",
"uri-js": "^4.2.1"
}
},
@@ -10747,6 +10747,12 @@
"integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=",
"dev": true
},
+ "json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true
+ },
"schema-utils": {
"version": "0.4.5",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.5.tgz",
@@ -11128,14 +11134,14 @@
"dev": true
},
"vue-i18n": {
- "version": "7.7.0",
- "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-7.7.0.tgz",
- "integrity": "sha512-9SfunO1I7cK8NIe5nv7p9UBmjo6bq3QRy/vijawVoAnR7c+8S0OrB9ToQhpEE3kvrW0XpBww0FeSS86jaERv5Q=="
+ "version": "7.8.1",
+ "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-7.8.1.tgz",
+ "integrity": "sha512-BzB+EAPo/iFyFn/GXd/qVdDe67jfk+gmQaWUKD5BANhUclGrFxzRExzW2pYEAbhNm2pg0F12Oo+gL2IMLDcTAw=="
},
"vue-loader": {
- "version": "13.7.1",
- "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-13.7.1.tgz",
- "integrity": "sha512-v6PbKMGl/hWHGPxB2uGHsA66vusrXF66J/h1QiFXtU6z5zVSK8jq5xl95M1p3QNXmuEJKNP3nxoXfbgQNs7hJg==",
+ "version": "13.7.2",
+ "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-13.7.2.tgz",
+ "integrity": "sha512-pgFWFsUjYO1v+J+3r7K0Q4lCp0eOyI24/q9j+cCudWyCTjgpjpcAa1MdwjlDUUettt9xkkUBbQ9fkAN1NC8t9w==",
"dev": true,
"requires": {
"consolidate": "^0.14.0",
@@ -11204,9 +11210,9 @@
}
},
"vuetify": {
- "version": "1.0.18",
- "resolved": "https://registry.npmjs.org/vuetify/-/vuetify-1.0.18.tgz",
- "integrity": "sha512-adOZaSCgoeGgyL3bgm0bpAfbUJWQ9WVD6CBpJriQJ6JUMaKNoEvKnuhY5LGRlR209QOx4LB8e6HBlKtGwbFtIA=="
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/vuetify/-/vuetify-1.1.1.tgz",
+ "integrity": "sha512-Nxbs52NLYt+4I6Gxx9nW0OY9Irxv+pZnWngslGwL8wEp0Iwo2uS7YiNxAqWYuGYCz+R1IOvgeZZd0KI/HIZY5w=="
},
"vuex": {
"version": "3.0.1",
@@ -11638,9 +11644,9 @@
}
},
"webpack-merge": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.1.2.tgz",
- "integrity": "sha512-/0QYwW/H1N/CdXYA2PNPVbsxO3u2Fpz34vs72xm03SRfg6bMNGfMJIQEpQjKRvkG2JvT6oRJFpDtSrwbX8Jzvw==",
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.1.3.tgz",
+ "integrity": "sha512-zxwAIGK7nKdu5CIZL0BjTQoq3elV0t0MfB7rUC1zj668geid52abs6hN/ACwZdK6LeMS8dC9B6WmtF978zH5mg==",
"dev": true,
"requires": {
"lodash": "^4.17.5"
diff --git a/webapp/package.json b/webapp/package.json
index 2f939aa..a92988f 100644
--- a/webapp/package.json
+++ b/webapp/package.json
@@ -13,18 +13,18 @@
"dependencies": {
"axios": "^0.18.0",
"vue": "^2.5.2",
- "vue-i18n": "^7.7.0",
+ "vue-i18n": "^7.8.1",
"vue-router": "^3.0.1",
"vue-touch": "^2.0.0-beta.4",
"vue2-hammer": "^1.0.6",
- "vuetify": "^1.0.18",
+ "vuetify": "^1.1.1",
"vuex": "^3.0.1"
},
"devDependencies": {
"@kazupon/vue-i18n-loader": "^0.3.0",
"autoprefixer": "^7.1.2",
"babel-core": "^6.22.1",
- "babel-eslint": "^8.2.1",
+ "babel-eslint": "^8.2.5",
"babel-helper-vue-jsx-merge-props": "^2.0.3",
"babel-loader": "^7.1.1",
"babel-plugin-syntax-jsx": "^6.18.0",
@@ -33,13 +33,13 @@
"babel-preset-env": "^1.3.2",
"babel-preset-stage-2": "^6.22.0",
"chalk": "^2.0.1",
- "copy-webpack-plugin": "^4.0.1",
+ "copy-webpack-plugin": "^4.5.2",
"css-loader": "^0.28.0",
"eslint": "^4.15.0",
"eslint-config-standard": "^10.2.1",
"eslint-friendly-formatter": "^3.0.0",
"eslint-loader": "^1.7.1",
- "eslint-plugin-import": "^2.12.0",
+ "eslint-plugin-import": "^2.13.0",
"eslint-plugin-node": "^5.2.0",
"eslint-plugin-promise": "^3.8.0",
"eslint-plugin-standard": "^3.0.1",
@@ -58,15 +58,15 @@
"rimraf": "^2.6.0",
"semver": "^5.3.0",
"shelljs": "^0.7.6",
- "uglifyjs-webpack-plugin": "^1.1.1",
+ "uglifyjs-webpack-plugin": "^1.2.7",
"url-loader": "^1.0.1",
- "vue-loader": "^13.3.0",
+ "vue-loader": "^13.7.2",
"vue-style-loader": "^3.0.1",
"vue-template-compiler": "^2.5.2",
"webpack": "^3.6.0",
"webpack-bundle-analyzer": "^2.13.1",
"webpack-dev-server": "^2.9.1",
- "webpack-merge": "^4.1.0"
+ "webpack-merge": "^4.1.3"
},
"engines": {
"node": ">= 6.0.0",
diff --git a/webapp/src/components/BackendEditComponent.vue b/webapp/src/components/BackendEditComponent.vue
new file mode 100644
index 0000000..0dcbd9b
--- /dev/null
+++ b/webapp/src/components/BackendEditComponent.vue
@@ -0,0 +1,191 @@
+<i18n>
+{
+ "en": {
+ "select_backend_type": "Select a backend type.",
+ "input_credentials": "Fill in the backend credentials.",
+ "backend_name": "Backend name",
+ "backend_empty_error": "This field can not be empty.",
+ "backendtype_empty_error": "Please choose a backend type."
+ },
+ "de": {
+ "select_backend_type": "Wähle einen Backend typ aus.",
+ "input_credentials": "Gib die benötigten Backend Daten ein.",
+ "backend_name": "Backend Name",
+ "backend_empty_error": "Dieses Feld darf nicht leer sein.",
+ "backendtype_empty_error": "Bitte wähle einen Backendtyp aus."
+ }
+}
+</i18n>
+
+<template>
+ <v-container>
+ <v-layout>
+ <v-flex md8 offset-md2 sm10 offset-sm1>
+ <v-form class="edit-backend-form" ref="form" v-model="valid" @submit.prevent="submit" lazy-validation>
+ <v-stepper v-model="step" vertical>
+ <v-stepper-step
+ :complete="stepCompleted >= 1"
+ step="1"
+ :editable="stepCompleted >= 1"
+ edit-icon="check"
+ :rules="[() => true]"
+ >{{ $t('select_backend_type') }}</v-stepper-step>
+ <v-stepper-content step="1">
+ <v-text-field solo
+ class="backend-select"
+ v-model="backendName"
+ :label="$t('backend_name')"
+ :rules="[() => !!backendName || $t('backend_empty_error')]"
+ ref="backendName"
+ ></v-text-field>
+ <v-select
+ solo
+ offset-y
+ class="backend-select"
+ v-model="backendType"
+ :items="backendChoices"
+ :rules="[() => !!backendType || $t('backendtype_empty_error')]"
+ @change="loadInputFields"
+ ></v-select>
+ <v-btn color="primary" @click.native="completeStepOne();">{{ $t('continue') }}</v-btn>
+ <v-btn flat @click.native="$emit('cancel-edit')">{{ $t('cancel') }}</v-btn>
+ </v-stepper-content>
+ <v-stepper-step
+ :complete="stepCompleted >= 2"
+ step="2"
+ :editable="stepCompleted >= 2"
+ edit-icon="check"
+ >{{ $t('input_credentials') }}</v-stepper-step>
+ <v-stepper-content step="2">
+ <template v-for="element in elements">
+ <v-text-field
+ solo
+ v-if="element.type == 'text'"
+ label="Regular"
+ :key="element.name"
+ v-model="element.value"
+ ></v-text-field>
+ <v-text-field
+ solo
+ v-if="element.type == 'password'"
+ label="Regular"
+ :key="element.name"
+ :append-icon="element.show ? 'visibility_off' : 'visibility'"
+ :type="element.show ? 'text' : 'password'"
+ @click:append="element.show = !element.show"
+ v-model="element.value"
+ ></v-text-field>
+ <v-switch
+ v-if="element.type == 'switch'"
+ v-model="element.value"
+ :label="element.name"
+ :key="element.name"
+ ></v-switch>
+ <v-select
+ solo
+ offset-y
+ v-if="element.type == 'select'"
+ :items="element.items"
+ label="Standard"
+ :key="element.name"
+ v-model="element.value"
+ ></v-select>
+ </template>
+ <!--<v-btn color="primary" @click.native="step = 3; stepCompleted = Math.max(2, stepCompleted)">{{ $t('continue') }}</v-btn>-->
+ <v-btn type="submit" class="primary" raised>{{ $t('submit') }}</v-btn>
+ <v-btn flat @click.native="$emit('cancel-edit')">{{ $t('cancel') }}</v-btn>
+ </v-stepper-content>
+ <!--<v-stepper-step :complete="stepCompleted >= 3" step="3" :editable="stepCompleted >= 3" edit-icon="check">Select an ad format and name ad unit</v-stepper-step>-->
+ </v-stepper>
+ </v-form>
+ </v-flex>
+ </v-layout>
+ </v-container>
+</template>
+
+<script>
+
+export default {
+ name: 'BackendEditComponent',
+ props: ['backendId'],
+ data () {
+ return {
+ valid: true,
+ step: 1,
+ stepCompleted: 0,
+ backendType: '',
+ backendChoices: [],
+ elements: [],
+ show: false,
+ backendName: '',
+ loadData: false
+ }
+ },
+ methods: {
+ submit (event) {
+ if (this.$refs.form.validate()) {
+ this.$http.post('/api/backends/saveBackend', {
+ backendId: this.backendId,
+ backendName: this.backendName,
+ backendType: this.backendType,
+ backendCredentials: this.elements
+ }).then(response => {
+ // TODO: Add backend saved successfull msg.
+ console.log('TODO: Implement snackbar and print backend added successfully msg.')
+ this.$emit('cancel-edit')
+ }).catch(error => {
+ console.log(error)
+ // if (error.response.data.status === '') {
+ // }
+ // this.$refs.form.validate()
+ })
+ }
+ },
+ loadBackendTypes () {
+ this.$http('/api/backends/getBackendTypes').then(response => {
+ this.backendChoices = response.data
+ })
+ },
+ loadInputFields () {
+ if (!this.loadData) {
+ this.$http('/api/backends/getCredentialsByType?type=' + this.backendType).then(response => {
+ this.elements = response.data
+ })
+ }
+ },
+ loadBackend (backendId) {
+ this.$http('/api/backends/getBackendInfoById?id=' + this.backendId).then(response => {
+ this.backendName = response.data.backendName
+ this.loadData = true
+ this.backendType = response.data.backendType
+ this.elements = JSON.parse(response.data.backendCredentials)
+ })
+ },
+ completeStepOne () {
+ // Error handling
+ if (this.backendName !== '' && this.backendType !== '') {
+ this.step = 2
+ this.stepCompleted = Math.max(1, this.stepCompleted)
+ } else {
+ this.$refs.form.validate()
+ }
+ }
+ },
+ computed: {
+ },
+ beforeMount () {
+ this.loadBackendTypes()
+ if (this.backendId !== 0) {
+ this.loadBackend(this.backendId)
+ }
+ }
+}
+
+</script>
+
+<!-- Add "scoped" attribute to limit CSS to this component only -->
+<style scoped>
+.backend-select {
+ margin: 6px;
+}
+</style>
diff --git a/webapp/src/components/BackendModule.vue b/webapp/src/components/BackendModule.vue
index 8774db4..46ac728 100644
--- a/webapp/src/components/BackendModule.vue
+++ b/webapp/src/components/BackendModule.vue
@@ -8,54 +8,37 @@
</i18n>
<template>
- <v-container>
- <v-layout>
- <v-flex md8 offset-md2 sm10 offset-sm1>
- <v-stepper v-model="step" vertical>
- <v-stepper-step :complete="stepCompleted >= 1" step="1" :editable="stepCompleted >= 1" edit-icon="check">
- Select an app
- <small>Summarize if needed</small>
- </v-stepper-step>
- <v-stepper-content step="1">
- <v-card color="grey lighten-1" class="mb-5" height="200px"></v-card>
- <v-btn color="primary" @click.native="step = 2; stepCompleted = Math.max(1, stepCompleted)">Continue</v-btn>
- <v-btn flat>Cancel</v-btn>
- </v-stepper-content>
- <v-stepper-step :complete="stepCompleted >= 2" step="2" :editable="stepCompleted >= 2" edit-icon="check">Configure analytics for this app</v-stepper-step>
- <v-stepper-content step="2">
- <v-card color="grey lighten-1" class="mb-5" height="200px"></v-card>
- <v-btn color="primary" @click.native="step = 3; stepCompleted = Math.max(2, stepCompleted)">Continue</v-btn>
- <v-btn flat>Cancel</v-btn>
- </v-stepper-content>
- <v-stepper-step :complete="stepCompleted >= 3" step="3" :editable="stepCompleted >= 3" edit-icon="check">Select an ad format and name ad unit</v-stepper-step>
- <v-stepper-content step="3">
- <v-card color="grey lighten-1" class="mb-5" height="200px"></v-card>
- <v-btn color="primary" @click.native="step = 4; stepCompleted = Math.max(3, stepCompleted)">Continue</v-btn>
- <v-btn flat>Cancel</v-btn>
- </v-stepper-content>
- <v-stepper-step step="4" edit-icon="check">View setup instructions</v-stepper-step>
- <v-stepper-content step="4" :editable="step > 3">
- <v-card color="grey lighten-1" class="mb-5" height="200px"></v-card>
- <v-btn color="primary" @click.native="step = 1">Continue</v-btn>
- <v-btn flat>Cancel</v-btn>
- </v-stepper-content>
- </v-stepper>
- </v-flex>
- </v-layout>
- </v-container>
+ <component :is="component" @edit-backend="setEditComponent" @cancel-edit="setTableComponent" :backend-id="backendId"></component>
</template>
<script>
+import BackendTableComponent from '@/components/BackendTableComponent'
+import BackendEditComponent from '@/components/BackendEditComponent'
export default {
name: 'BackendModule',
+ components: {
+ BackendTableComponent,
+ BackendEditComponent
+ },
data () {
return {
- step: 1,
- stepCompleted: 0
+ component: 'BackendTableComponent',
+ backendId: 0
}
},
methods: {
+ setEditComponent (value) {
+ this.component = 'BackendEditComponent'
+ this.backendId = value
+ },
+ setTableComponent () {
+ this.component = 'BackendTableComponent'
+ }
+ },
+ computed: {
+ },
+ beforeMount () {
}
}
diff --git a/webapp/src/components/BackendTableComponent.vue b/webapp/src/components/BackendTableComponent.vue
new file mode 100644
index 0000000..6601672
--- /dev/null
+++ b/webapp/src/components/BackendTableComponent.vue
@@ -0,0 +1,133 @@
+<i18n>
+{
+ "en": {
+ "add-backend-btn": "Add Backend",
+ "delete-backend": "Delete",
+ "delete-are-you-sure": "Are you sure you want to delete this backend?",
+ "backend-id": "id",
+ "backend-name": "name",
+ "backend-type": "type"
+ },
+ "de": {
+ "add-backend-btn": "Backend hinzufügen",
+ "delete-backend": "Lösche",
+ "delete-are-you-sure": "Sind sie sicher, dass sie dieses Backend Löschen wollen?",
+ "backend-id": "id",
+ "backend-name": "name",
+ "backend-type": "typ"
+ }
+}
+</i18n>
+
+<template>
+ <v-container>
+ <v-layout>
+ <v-flex md8 offset-md2 sm10 offset-sm1>
+ <v-card>
+ <v-list>
+ <template v-for="item in items">
+ <v-list-tile :key="item.name" avatar @click="">
+
+ <v-list-tile-avatar>
+ <v-list-tile-title v-text="item.id"></v-list-tile-title>
+ </v-list-tile-avatar>
+
+ <v-list-tile-content>
+ <v-list-tile-title v-text="item.name"></v-list-tile-title>
+ <v-list-tile-sub-title v-text="item.type"></v-list-tile-sub-title>
+ </v-list-tile-content>
+
+ <v-list-tile-action>
+ <v-btn flat icon color="blue" @click="editBackend(item.id)">
+ <v-icon>edit</v-icon>
+ </v-btn>
+ </v-list-tile-action>
+
+ <v-list-tile-action>
+ <v-btn flat icon color="red" @click.stop="clickOnBackend(item.id, item.name, item.type); dialog = true">
+ <v-icon>delete</v-icon>
+ </v-btn>
+ </v-list-tile-action>
+
+ </v-list-tile>
+ </template>
+ </v-list>
+
+ </v-card>
+ </v-flex>
+ </v-layout>
+ <v-layout>
+ <v-flex md8 offset-md2 sm10 offset-sm1 text-xs-right>
+ <v-btn color="success" flat @click="$emit('edit-backend', 0)">
+ <v-icon left>add_circle_outline</v-icon>{{ $t('add-backend-btn') }}
+ </v-btn>
+ </v-flex>
+ </v-layout>
+
+ <v-dialog v-model="dialog" max-width="290">
+ <v-card>
+
+ <v-card-title primary-title>
+ <div>
+ <div class="headline">{{ $t('delete-backend') }} "{{ backendName }}"</div>
+ <span class="grey--text">{{ $t('backend-id') }}: {{ backendId }}, {{ $t('backend-type') }}: {{ backendType }}</span>
+ </div>
+ </v-card-title>
+
+ <v-card-text>
+ {{ $t('delete-are-you-sure') }}
+ </v-card-text>
+ <v-card-actions>
+ <v-spacer></v-spacer>
+ <v-btn flat="flat" @click="dialog = false">{{ $t('cancel') }}</v-btn>
+ <v-btn color="error" @click="dialog = false; deleteBackend()">{{ $t('delete') }}</v-btn>
+ </v-card-actions>
+ </v-card>
+ </v-dialog>
+
+ </v-container>
+</template>
+<script>
+export default {
+ name: 'BackendTableComponent',
+ data () {
+ return {
+ items: [],
+ dialog: false,
+ backendName: '',
+ backendId: '',
+ backendType: ''
+ }
+ },
+ methods: {
+ loadData () {
+ this.$http('/api/backends/getBackendList').then(response => {
+ this.items = response.data
+ })
+ },
+ deleteBackend () {
+ this.$http.post('/api/backends/deleteBackendById', {
+ id: this.backendId
+ }).then(response => {
+ this.loadData()
+ })
+ },
+ editBackend (backendId) {
+ this.$emit('edit-backend', backendId)
+ },
+ clickOnBackend (id, name, type) {
+ this.backendId = id
+ this.backendName = name
+ this.backendType = type
+ }
+ },
+ computed: {
+ },
+ beforeMount () {
+ this.loadData()
+ }
+}
+</script>
+<!-- Add "scoped" attribute to limit CSS to this component only -->
+<style scoped>
+</style>
diff --git a/webapp/src/main.js b/webapp/src/main.js
index 4a553aa..5d4f494 100644
--- a/webapp/src/main.js
+++ b/webapp/src/main.js
@@ -21,7 +21,20 @@ Vue.use(VueTouch)
Vue.use(VueI18n)
const i18n = new VueI18n({
- locale: store.state.locale
+ locale: store.state.locale,
+ silentTranslationWarn: true,
+ messages: {
+ 'en': {
+ 'continue': 'Continue',
+ 'cancel': 'Cancel',
+ 'delete': 'Delete'
+ },
+ 'de': {
+ 'continue': 'Weiter',
+ 'cancel': 'Abbrechen',
+ 'delete': 'Löschen'
+ }
+ }
})
axios.interceptors.response.use(null, error => {