diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 00000000..dfe07704
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,2 @@
+# Auto detect text files and perform LF normalization
+* text=auto
diff --git a/README.md b/README.md
index 15cfcc91..4f33f2b8 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# OpenTOSCA UI
+# OpenTOSCA UI 2.0
[](https://travis-ci.org/OpenTOSCA/ui)
[](https://opensource.org/licenses/EPL-1.0)
diff --git a/package-lock.json b/package-lock.json
index f87046af..e98d5812 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -102,6 +102,55 @@
"uri-js": "^4.2.2"
}
},
+ "ansi-styles": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+ "dev": true,
+ "optional": true
+ },
+ "chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ }
+ },
+ "node-sass": {
+ "version": "4.11.0",
+ "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.11.0.tgz",
+ "integrity": "sha512-bHUdHTphgQJZaF1LASx0kAviPH7sGlcyNhWade4eVIpFp6tsn7SV8xNMTbsQFpEV9VXpnwTTnNYlfsZXgGgmkA==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "async-foreach": "^0.1.3",
+ "chalk": "^1.1.1",
+ "cross-spawn": "^3.0.0",
+ "gaze": "^1.0.0",
+ "get-stdin": "^4.0.1",
+ "glob": "^7.0.3",
+ "in-publish": "^2.0.0",
+ "lodash.assign": "^4.2.0",
+ "lodash.clonedeep": "^4.3.2",
+ "lodash.mergewith": "^4.6.0",
+ "meow": "^3.7.0",
+ "mkdirp": "^0.5.1",
+ "nan": "^2.10.0",
+ "node-gyp": "^3.8.0",
+ "npmlog": "^4.0.0",
+ "request": "^2.88.0",
+ "sass-graph": "^2.2.4",
+ "stdout-stream": "^1.4.0",
+ "true-case-path": "^1.0.2"
+ }
+ },
"opn": {
"version": "5.4.0",
"resolved": "https://registry.npmjs.org/opn/-/opn-5.4.0.tgz",
@@ -134,6 +183,13 @@
"dev": true
}
}
+ },
+ "supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true,
+ "optional": true
}
}
},
@@ -1396,9 +1452,9 @@
"dev": true
},
"@types/node": {
- "version": "10.12.18",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.18.tgz",
- "integrity": "sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ==",
+ "version": "10.17.44",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.44.tgz",
+ "integrity": "sha512-vHPAyBX1ffLcy4fQHmDyIUMUb42gHZjPHU66nhvbMzAWJqHnySGZ6STwN3rwrnSd1FHB0DI/RWgGELgKSYRDmw==",
"dev": true
},
"@types/q": {
@@ -1665,8 +1721,7 @@
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
- "dev": true,
- "optional": true
+ "dev": true
},
"accepts": {
"version": "1.3.5",
@@ -1819,7 +1874,6 @@
"resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz",
"integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
"dev": true,
- "optional": true,
"requires": {
"delegates": "^1.0.0",
"readable-stream": "^2.0.6"
@@ -1856,8 +1910,7 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz",
"integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=",
- "dev": true,
- "optional": true
+ "dev": true
},
"array-flatten": {
"version": "2.1.2",
@@ -1988,8 +2041,7 @@
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/async-foreach/-/async-foreach-0.1.3.tgz",
"integrity": "sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=",
- "dev": true,
- "optional": true
+ "dev": true
},
"async-limiter": {
"version": "1.0.0",
@@ -2302,7 +2354,6 @@
"resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz",
"integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=",
"dev": true,
- "optional": true,
"requires": {
"inherits": "~2.0.0"
}
@@ -2638,15 +2689,13 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz",
"integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=",
- "dev": true,
- "optional": true
+ "dev": true
},
"camelcase-keys": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz",
"integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=",
"dev": true,
- "optional": true,
"requires": {
"camelcase": "^2.0.0",
"map-obj": "^1.0.0"
@@ -3058,8 +3107,7 @@
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
- "dev": true,
- "optional": true
+ "dev": true
},
"constants-browserify": {
"version": "1.0.0",
@@ -3213,7 +3261,6 @@
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-3.0.1.tgz",
"integrity": "sha1-ElYDfsufDF9549bvE14wdwGEuYI=",
"dev": true,
- "optional": true,
"requires": {
"lru-cache": "^4.0.1",
"which": "^1.2.9"
@@ -3275,7 +3322,6 @@
"resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz",
"integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=",
"dev": true,
- "optional": true,
"requires": {
"array-find-index": "^1.0.1"
}
@@ -3467,8 +3513,7 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
"integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=",
- "dev": true,
- "optional": true
+ "dev": true
},
"depd": {
"version": "1.1.2",
@@ -3644,6 +3689,12 @@
"minimalistic-crypto-utils": "^1.0.0"
}
},
+ "emoji-regex": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
+ "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
+ "dev": true
+ },
"emojis-list": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz",
@@ -4427,11 +4478,10 @@
}
},
"fstream": {
- "version": "1.0.11",
- "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz",
- "integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=",
+ "version": "1.0.12",
+ "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz",
+ "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==",
"dev": true,
- "optional": true,
"requires": {
"graceful-fs": "^4.1.2",
"inherits": "~2.0.0",
@@ -4449,7 +4499,6 @@
"resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
"integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
"dev": true,
- "optional": true,
"requires": {
"aproba": "^1.0.3",
"console-control-strings": "^1.0.0",
@@ -4466,7 +4515,6 @@
"resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz",
"integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==",
"dev": true,
- "optional": true,
"requires": {
"globule": "^1.0.0"
}
@@ -4487,8 +4535,7 @@
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz",
"integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=",
- "dev": true,
- "optional": true
+ "dev": true
},
"get-stream": {
"version": "3.0.0",
@@ -4567,11 +4614,10 @@
}
},
"globule": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/globule/-/globule-1.2.1.tgz",
- "integrity": "sha512-g7QtgWF4uYSL5/dn71WxubOrS7JVGCnFPEnoeChJmBnyR9Mw8nGoEwOgJL/RC2Te0WhbsEUCejfH8SZNJ+adYQ==",
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.2.tgz",
+ "integrity": "sha512-7IDTQTIu2xzXkT+6mlluidnWo+BypnbSoEVVQCGfzqnl5Ik8d3e1d4wycb8Rj9tWW+Z39uPWsdlquqiqPCd/pA==",
"dev": true,
- "optional": true,
"requires": {
"glob": "~7.1.1",
"lodash": "~4.17.10",
@@ -4648,8 +4694,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
"integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=",
- "dev": true,
- "optional": true
+ "dev": true
},
"has-value": {
"version": "1.0.0",
@@ -5008,18 +5053,16 @@
"dev": true
},
"in-publish": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.0.tgz",
- "integrity": "sha1-4g/146KvwmkDILbcVSaCqcf631E=",
- "dev": true,
- "optional": true
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.1.tgz",
+ "integrity": "sha512-oDM0kUSNFC31ShNxHKUyfZKy8ZeXZBWMjMdZHKLOk13uvT27VTL/QzRGfRUcevJhpkZAvlhPYuXkF7eNWrtyxQ==",
+ "dev": true
},
"indent-string": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz",
"integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=",
"dev": true,
- "optional": true,
"requires": {
"repeating": "^2.0.0"
}
@@ -5383,8 +5426,7 @@
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
"integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=",
- "dev": true,
- "optional": true
+ "dev": true
},
"is-windows": {
"version": "1.0.2",
@@ -5692,11 +5734,10 @@
"dev": true
},
"js-base64": {
- "version": "2.5.1",
- "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.5.1.tgz",
- "integrity": "sha512-M7kLczedRMYX4L8Mdh4MzyAMM9O5osx+4FcOQuTvr3A9F2D9S5JXheN0ewNbrvK2UatkTRhL5ejGmGSjNMiZuw==",
- "dev": true,
- "optional": true
+ "version": "2.6.4",
+ "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.4.tgz",
+ "integrity": "sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==",
+ "dev": true
},
"js-tokens": {
"version": "4.0.0",
@@ -6019,7 +6060,6 @@
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
"integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
"dev": true,
- "optional": true,
"requires": {
"graceful-fs": "^4.1.2",
"parse-json": "^2.2.0",
@@ -6032,8 +6072,7 @@
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
- "dev": true,
- "optional": true
+ "dev": true
}
}
},
@@ -6095,9 +6134,9 @@
"dev": true
},
"lodash.mergewith": {
- "version": "4.6.1",
- "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.1.tgz",
- "integrity": "sha512-eWw5r+PYICtEBgrBE5hhlT6aAa75f411bgDz/ZL2KZqYV03USvucsxcHUIlGTDTECs1eunpI7HOV7U+WLDvNdQ==",
+ "version": "4.6.2",
+ "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz",
+ "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==",
"dev": true,
"optional": true
},
@@ -6156,7 +6195,6 @@
"resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz",
"integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=",
"dev": true,
- "optional": true,
"requires": {
"currently-unhandled": "^0.4.1",
"signal-exit": "^3.0.0"
@@ -6314,8 +6352,7 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz",
"integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=",
- "dev": true,
- "optional": true
+ "dev": true
},
"map-visit": {
"version": "1.0.0",
@@ -6377,7 +6414,6 @@
"resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz",
"integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=",
"dev": true,
- "optional": true,
"requires": {
"camelcase-keys": "^2.0.0",
"decamelize": "^1.1.2",
@@ -6392,11 +6428,10 @@
},
"dependencies": {
"minimist": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
- "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
- "dev": true,
- "optional": true
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
+ "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
+ "dev": true
}
}
},
@@ -6719,7 +6754,6 @@
"resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.8.0.tgz",
"integrity": "sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA==",
"dev": true,
- "optional": true,
"requires": {
"fstream": "^1.0.0",
"glob": "^7.0.3",
@@ -6740,7 +6774,6 @@
"resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz",
"integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=",
"dev": true,
- "optional": true,
"requires": {
"abbrev": "1"
}
@@ -6749,18 +6782,16 @@
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
"integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=",
- "dev": true,
- "optional": true
+ "dev": true
},
"tar": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz",
- "integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=",
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.2.tgz",
+ "integrity": "sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA==",
"dev": true,
- "optional": true,
"requires": {
"block-stream": "*",
- "fstream": "^1.0.2",
+ "fstream": "^1.0.12",
"inherits": "2"
}
}
@@ -6834,11 +6865,10 @@
}
},
"node-sass": {
- "version": "4.11.0",
- "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.11.0.tgz",
- "integrity": "sha512-bHUdHTphgQJZaF1LASx0kAviPH7sGlcyNhWade4eVIpFp6tsn7SV8xNMTbsQFpEV9VXpnwTTnNYlfsZXgGgmkA==",
+ "version": "4.14.1",
+ "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.14.1.tgz",
+ "integrity": "sha512-sjCuOlvGyCJS40R8BscF5vhVlQjNN069NtQ1gSxyK1u9iqvn6tf7O1R4GNowVZfiZUCRt5MmMs1xd+4V/7Yr0g==",
"dev": true,
- "optional": true,
"requires": {
"async-foreach": "^0.1.3",
"chalk": "^1.1.1",
@@ -6847,16 +6877,14 @@
"get-stdin": "^4.0.1",
"glob": "^7.0.3",
"in-publish": "^2.0.0",
- "lodash.assign": "^4.2.0",
- "lodash.clonedeep": "^4.3.2",
- "lodash.mergewith": "^4.6.0",
+ "lodash": "^4.17.15",
"meow": "^3.7.0",
"mkdirp": "^0.5.1",
- "nan": "^2.10.0",
+ "nan": "^2.13.2",
"node-gyp": "^3.8.0",
"npmlog": "^4.0.0",
"request": "^2.88.0",
- "sass-graph": "^2.2.4",
+ "sass-graph": "2.2.5",
"stdout-stream": "^1.4.0",
"true-case-path": "^1.0.2"
},
@@ -6865,15 +6893,13 @@
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
"integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
- "dev": true,
- "optional": true
+ "dev": true
},
"chalk": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
"dev": true,
- "optional": true,
"requires": {
"ansi-styles": "^2.2.1",
"escape-string-regexp": "^1.0.2",
@@ -6882,12 +6908,23 @@
"supports-color": "^2.0.0"
}
},
+ "lodash": {
+ "version": "4.17.20",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
+ "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==",
+ "dev": true
+ },
+ "nan": {
+ "version": "2.14.2",
+ "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz",
+ "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==",
+ "dev": true
+ },
"supports-color": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
"integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
- "dev": true,
- "optional": true
+ "dev": true
}
}
},
@@ -6996,7 +7033,6 @@
"resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
"integrity": "sha1-CKfyqL9zRgR3mp76StXMcXq7lUs=",
"dev": true,
- "optional": true,
"requires": {
"are-we-there-yet": "~1.1.2",
"console-control-strings": "~1.1.0",
@@ -7176,16 +7212,6 @@
"integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
"dev": true
},
- "os-locale": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
- "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=",
- "dev": true,
- "optional": true,
- "requires": {
- "lcid": "^1.0.0"
- }
- },
"os-tmpdir": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
@@ -8063,7 +8089,6 @@
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
"integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=",
"dev": true,
- "optional": true,
"requires": {
"load-json-file": "^1.0.0",
"normalize-package-data": "^2.3.2",
@@ -8075,7 +8100,6 @@
"resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
"integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=",
"dev": true,
- "optional": true,
"requires": {
"graceful-fs": "^4.1.2",
"pify": "^2.0.0",
@@ -8086,8 +8110,7 @@
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
- "dev": true,
- "optional": true
+ "dev": true
}
}
},
@@ -8096,7 +8119,6 @@
"resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",
"integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=",
"dev": true,
- "optional": true,
"requires": {
"find-up": "^1.0.0",
"read-pkg": "^1.0.0"
@@ -8107,7 +8129,6 @@
"resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
"integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=",
"dev": true,
- "optional": true,
"requires": {
"path-exists": "^2.0.0",
"pinkie-promise": "^2.0.0"
@@ -8118,7 +8139,6 @@
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
"integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",
"dev": true,
- "optional": true,
"requires": {
"pinkie-promise": "^2.0.0"
}
@@ -8165,7 +8185,6 @@
"resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz",
"integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=",
"dev": true,
- "optional": true,
"requires": {
"indent-string": "^2.1.0",
"strip-indent": "^1.0.1"
@@ -8460,20 +8479,18 @@
"safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
- "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
- "dev": true
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"sass-graph": {
- "version": "2.2.4",
- "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.4.tgz",
- "integrity": "sha1-E/vWPNHK8JCLn9k0dq1DpR0eC0k=",
+ "version": "2.2.5",
+ "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.5.tgz",
+ "integrity": "sha512-VFWDAHOe6mRuT4mZRd4eKE+d8Uedrk6Xnh7Sh9b4NGufQLQjOrvf/MQoOdx+0s92L89FeyUUNfU597j/3uNpag==",
"dev": true,
- "optional": true,
"requires": {
"glob": "^7.0.0",
"lodash": "^4.0.0",
"scss-tokenizer": "^0.2.3",
- "yargs": "^7.0.0"
+ "yargs": "^13.3.2"
}
},
"sass-loader": {
@@ -8521,7 +8538,6 @@
"resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz",
"integrity": "sha1-jrBtualyMzOCTT9VMGQRSYR85dE=",
"dev": true,
- "optional": true,
"requires": {
"js-base64": "^2.1.8",
"source-map": "^0.4.2"
@@ -8532,7 +8548,6 @@
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
"integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=",
"dev": true,
- "optional": true,
"requires": {
"amdefine": ">=0.0.4"
}
@@ -9317,7 +9332,6 @@
"resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.1.tgz",
"integrity": "sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA==",
"dev": true,
- "optional": true,
"requires": {
"readable-stream": "^2.0.1"
}
@@ -9424,7 +9438,6 @@
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
"integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
"dev": true,
- "optional": true,
"requires": {
"is-utf8": "^0.2.0"
}
@@ -9440,7 +9453,6 @@
"resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz",
"integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=",
"dev": true,
- "optional": true,
"requires": {
"get-stdin": "^4.0.1"
}
@@ -9893,8 +9905,7 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz",
"integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=",
- "dev": true,
- "optional": true
+ "dev": true
},
"trim-right": {
"version": "1.0.1",
@@ -9907,7 +9918,6 @@
"resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.3.tgz",
"integrity": "sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew==",
"dev": true,
- "optional": true,
"requires": {
"glob": "^7.1.2"
}
@@ -10791,18 +10801,16 @@
}
},
"which-module": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz",
- "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=",
- "dev": true,
- "optional": true
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
+ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
+ "dev": true
},
"wide-align": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
"integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
"dev": true,
- "optional": true,
"requires": {
"string-width": "^1.0.2 || 2"
}
@@ -10890,59 +10898,149 @@
"dev": true
},
"yargs": {
- "version": "7.1.0",
- "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz",
- "integrity": "sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=",
+ "version": "13.3.2",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz",
+ "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==",
"dev": true,
- "optional": true,
"requires": {
- "camelcase": "^3.0.0",
- "cliui": "^3.2.0",
- "decamelize": "^1.1.1",
- "get-caller-file": "^1.0.1",
- "os-locale": "^1.4.0",
- "read-pkg-up": "^1.0.1",
+ "cliui": "^5.0.0",
+ "find-up": "^3.0.0",
+ "get-caller-file": "^2.0.1",
"require-directory": "^2.1.1",
- "require-main-filename": "^1.0.1",
+ "require-main-filename": "^2.0.0",
"set-blocking": "^2.0.0",
- "string-width": "^1.0.2",
- "which-module": "^1.0.0",
- "y18n": "^3.2.1",
- "yargs-parser": "^5.0.0"
+ "string-width": "^3.0.0",
+ "which-module": "^2.0.0",
+ "y18n": "^4.0.0",
+ "yargs-parser": "^13.1.2"
},
"dependencies": {
- "camelcase": {
+ "ansi-regex": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+ "dev": true
+ },
+ "cliui": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
+ "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==",
+ "dev": true,
+ "requires": {
+ "string-width": "^3.1.0",
+ "strip-ansi": "^5.2.0",
+ "wrap-ansi": "^5.1.0"
+ }
+ },
+ "find-up": {
"version": "3.0.0",
- "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz",
- "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
+ "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
"dev": true,
- "optional": true
+ "requires": {
+ "locate-path": "^3.0.0"
+ }
},
- "y18n": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz",
- "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=",
+ "get-caller-file": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+ "dev": true
+ },
+ "is-fullwidth-code-point": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+ "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
+ "dev": true
+ },
+ "locate-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
+ "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
"dev": true,
- "optional": true
+ "requires": {
+ "p-locate": "^3.0.0",
+ "path-exists": "^3.0.0"
+ }
+ },
+ "p-limit": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+ "dev": true,
+ "requires": {
+ "p-try": "^2.0.0"
+ }
+ },
+ "p-locate": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
+ "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
+ "dev": true,
+ "requires": {
+ "p-limit": "^2.0.0"
+ }
+ },
+ "p-try": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+ "dev": true
+ },
+ "require-main-filename": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
+ "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
+ "dev": true
+ },
+ "string-width": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
+ "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
+ "dev": true,
+ "requires": {
+ "emoji-regex": "^7.0.1",
+ "is-fullwidth-code-point": "^2.0.0",
+ "strip-ansi": "^5.1.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+ "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^4.1.0"
+ }
+ },
+ "wrap-ansi": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
+ "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.0",
+ "string-width": "^3.0.0",
+ "strip-ansi": "^5.0.0"
+ }
}
}
},
"yargs-parser": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0.tgz",
- "integrity": "sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=",
+ "version": "13.1.2",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz",
+ "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==",
"dev": true,
- "optional": true,
"requires": {
- "camelcase": "^3.0.0"
+ "camelcase": "^5.0.0",
+ "decamelize": "^1.2.0"
},
"dependencies": {
"camelcase": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz",
- "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=",
- "dev": true,
- "optional": true
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+ "dev": true
}
}
},
diff --git a/package.json b/package.json
index 2b1cf54e..634cb1cf 100644
--- a/package.json
+++ b/package.json
@@ -29,6 +29,7 @@
"fuse.js": "^3.4.4",
"lodash": "^4.17.11",
"ng-spin-kit": "^5.1.1",
+ "node-sass": "^4.14.1",
"primeflex": "^1.0.0-rc.1",
"primeicons": "^1.0.0",
"primeng": "^7.1.0",
@@ -48,7 +49,7 @@
"@types/jasmine": "~3.3.5",
"@types/jasminewd2": "~2.0.6",
"@types/lodash": "^4.14.119",
- "@types/node": "~10.12.18",
+ "@types/node": "^10.12.30",
"@types/redux-logger": "^3.0.6",
"codelyzer": "~4.5.0",
"jasmine-core": "~3.3.0",
@@ -58,6 +59,7 @@
"karma-coverage-istanbul-reporter": "~2.0.4",
"karma-jasmine": "~2.0.1",
"karma-jasmine-html-reporter": "^1.4.0",
+ "node-sass": "^4.14.1",
"protractor": "~5.4.2",
"ts-node": "~7.0.1",
"tslint": "~5.12.1",
diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts
index 9f6fc804..314f662d 100644
--- a/src/app/app-routing.module.ts
+++ b/src/app/app-routing.module.ts
@@ -15,12 +15,17 @@ import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { PageNotFoundComponent } from './page-not-found.component';
import { AboutComponent } from './about.component';
+import { SituationComponent } from './situations/situation.component';
const routes: Routes = [
{
path: 'about',
component: AboutComponent
},
+ {
+ path: 'situation',
+ component: SituationComponent
+ },
{
path: '',
redirectTo: '/applications',
diff --git a/src/app/app.component.ts b/src/app/app.component.ts
index b460dfcf..f425107f 100644
--- a/src/app/app.component.ts
+++ b/src/app/app.component.ts
@@ -44,6 +44,11 @@ export class AppComponent {
icon: 'fa fa-cogs',
routerLink: ['/administration']
},
+ {
+ label: 'Situation',
+ icon: 'fas fa-tasks',
+ routerLink: ['/situation']
+ },
{
label: 'About',
icon: 'fa fa-info-circle',
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index f760161c..b89a5f67 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -16,6 +16,7 @@ import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { AboutComponent } from './about.component';
+import { SituationModule } from './situations/situation.module';
import { AppRoutingModule } from './app-routing.module';
import { PageNotFoundComponent } from './page-not-found.component';
import { ApplicationManagementModule } from './application-management/application-management.module';
@@ -44,6 +45,7 @@ import { TabMenuModule } from 'primeng/tabmenu';
NgReduxModule,
NgReduxRouterModule,
GrowlModule,
+ SituationModule,
TabMenuModule,
CardModule,
ApplicationManagementModule,
diff --git a/src/app/application-management/application-detail/application-detail.component.html b/src/app/application-management/application-detail/application-detail.component.html
index 29fd4a3a..37e955d8 100644
--- a/src/app/application-management/application-detail/application-detail.component.html
+++ b/src/app/application-management/application-detail/application-detail.component.html
@@ -31,16 +31,16 @@
{{ csar.display_name }}
Instances
-
-
+ (click)="selectBuildPlan()">
-
+ pTooltip="Reload instances" showDelay="300" tooltipPosition="right"
+ (click)="triggerReloadAppInstances()" style="margin-right:10px">
+
{{ csar.display_name }}
[instanceId]="instanceId"
[inputValidation]="true">
+
+
diff --git a/src/app/application-management/application-detail/application-detail.component.ts b/src/app/application-management/application-detail/application-detail.component.ts
index 9d44ada6..d20477b7 100644
--- a/src/app/application-management/application-detail/application-detail.component.ts
+++ b/src/app/application-management/application-detail/application-detail.component.ts
@@ -34,6 +34,7 @@ export class ApplicationDetailComponent implements OnInit, OnDestroy {
@select(['container', 'application', 'csar']) csar: Observable;
public dialogVisible = false;
+ public csarSelectDialogVisible = false;
public selectedPlanType: PlanTypes;
public buildPlanExists = false;
public terminationPlanExists = false;
@@ -108,4 +109,8 @@ export class ApplicationDetailComponent implements OnInit, OnDestroy {
this.instanceId = instanceId;
this.dialogVisible = true;
}
+
+ selectCSARForMigrationPlan(app: Csar): void {
+ this.csarSelectDialogVisible = true;
+ }
}
diff --git a/src/app/application-management/application-instance-detail/application-instance-detail.component.html b/src/app/application-management/application-instance-detail/application-instance-detail.component.html
index 77ef65f4..703bfeca 100644
--- a/src/app/application-management/application-instance-detail/application-instance-detail.component.html
+++ b/src/app/application-management/application-instance-detail/application-instance-detail.component.html
@@ -64,119 +64,3 @@
[instance]="serviceTemplateInstance">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/app/application-management/application-management.module.ts b/src/app/application-management/application-management.module.ts
index d318e7a8..ef0c28f8 100644
--- a/src/app/application-management/application-management.module.ts
+++ b/src/app/application-management/application-management.module.ts
@@ -55,6 +55,7 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { ManagementPlanInstanceListComponent } from './management-plan-instance-list/management-plan-instance-list.component';
import { TableModule } from 'primeng/table';
import { ApplicationInstanceBoundaryDefinitionInterfacesListComponent } from './application-instance-boundary-definition-interfaces-list/application-instance-boundary-definition-interfaces-list.component';
+import {MigrationPlanCreationDialogComponent} from "./migration-plan-creation-dialog/migration-plan-creation-dialog.component";
// tslint:disable-line:max-line-length
@NgModule({
@@ -100,6 +101,7 @@ import { ApplicationInstanceBoundaryDefinitionInterfacesListComponent } from './
BuildplanMonitorComponent,
ManagementPlanListComponent,
ManagementPlanExecutionDialogComponent,
+ MigrationPlanCreationDialogComponent,
ManagementPlanInstanceListComponent,
ApplicationInstanceBoundaryDefinitionInterfacesListComponent
],
diff --git a/src/app/application-management/management-plan-execution-dialog/management-plan-execution-dialog.component.html b/src/app/application-management/management-plan-execution-dialog/management-plan-execution-dialog.component.html
index 2c924d9c..74cda18b 100644
--- a/src/app/application-management/management-plan-execution-dialog/management-plan-execution-dialog.component.html
+++ b/src/app/application-management/management-plan-execution-dialog/management-plan-execution-dialog.component.html
@@ -111,7 +111,7 @@
-
diff --git a/src/app/application-management/management-plan-execution-dialog/management-plan-execution-dialog.component.ts b/src/app/application-management/management-plan-execution-dialog/management-plan-execution-dialog.component.ts
index c9feea51..c8915120 100644
--- a/src/app/application-management/management-plan-execution-dialog/management-plan-execution-dialog.component.ts
+++ b/src/app/application-management/management-plan-execution-dialog/management-plan-execution-dialog.component.ts
@@ -109,6 +109,7 @@ export class ManagementPlanExecutionDialogComponent implements OnInit, OnChanges
if (this.plan) {
this.showInputs = true;
this.selectedPlan = this.plan
+ this.checkInputs();
}
}
}
diff --git a/src/app/application-management/migration-plan-creation-dialog/migration-plan-creation-dialog.component.html b/src/app/application-management/migration-plan-creation-dialog/migration-plan-creation-dialog.component.html
new file mode 100644
index 00000000..15b8f2b2
--- /dev/null
+++ b/src/app/application-management/migration-plan-creation-dialog/migration-plan-creation-dialog.component.html
@@ -0,0 +1,43 @@
+
+
+
+
+ Select Application to create Migration Plan for migrating instances to instances of the selected Application
+
+
+
+
+
+
+
+
+
+
+ Plan generation in progress
+
+
+
+
+
+
+
+
diff --git a/src/app/application-management/migration-plan-creation-dialog/migration-plan-creation-dialog.component.ts b/src/app/application-management/migration-plan-creation-dialog/migration-plan-creation-dialog.component.ts
new file mode 100644
index 00000000..6cfd6c0b
--- /dev/null
+++ b/src/app/application-management/migration-plan-creation-dialog/migration-plan-creation-dialog.component.ts
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2018 University of Stuttgart.
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0, or the Apache Software License 2.0
+ * which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ */
+import { Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core';
+import { Plan } from '../../core/model/plan.model';
+import { GrowlActions } from '../../core/growl/growl-actions';
+import { NgRedux, select } from '@angular-redux/store';
+import { AppState } from '../../store/app-state.model';
+import { ApplicationManagementService } from '../../core/service/application-management.service';
+import { LoggerService } from '../../core/service/logger.service';
+import { globals } from '../../globals';
+import { Observable } from 'rxjs';
+import { Interface } from '../../core/model/interface.model';
+import {SelectItem, SelectItemGroup} from 'primeng/api';
+import { PlanTypes } from '../../core/model/plan-types.model';
+import { PlacementService } from '../../core/service/placement.service';
+import { PlacementModel } from '../../core/model/placement.model';
+import { Path } from '../../core/path';
+import { PlacementNodeTemplate } from '../../core/model/placement-node-template.model';
+import { NodeTemplateInstance } from '../../core/model/node-template-instance.model';
+import { PlacementPair } from '../../core/model/placement-pair.model';
+import { PlanParameter } from '../../core/model/plan-parameter.model';
+import {Csar} from "../../core/model/csar.model";
+
+@Component({
+ selector: 'opentosca-migration-plan-creation-dialog',
+ templateUrl: './migration-plan-creation-dialog.component.html'
+})
+export class MigrationPlanCreationDialogComponent implements OnInit, OnChanges {
+
+ @Input() visible = false;
+ @Output() visibleChange = new EventEmitter();
+ @Input() csar: Observable;
+
+ @select(['container', 'applications']) public readonly apps: Observable>;
+
+ public loading = false;
+ public selectedApp: Csar;
+ public runnable: boolean;
+ public csars: Csar[];
+ public selection : SelectItem[];
+ public creationInProgress: boolean;
+
+
+ constructor(
+ private appService: ApplicationManagementService,
+ private ngRedux: NgRedux,
+ private logger: LoggerService) {
+ }
+
+ operationSelected(app: Csar): void {
+ if (app) {
+ console.log("Selected following app:");
+ console.log(app);
+ this.selectedApp = app;
+ }
+ }
+
+
+ ngOnInit(): void {
+ this.appService.getResolvedApplications().subscribe(value => {console.log("Found following csars:"); console.log(value); this.updateSelectionList(value)});
+ this.creationInProgress = false;
+ }
+
+ private updateSelectionList(csars: Csar[]): void {
+ this.selection = [];
+ this.csar.subscribe(value => {
+ csars.forEach(csar => {
+ if (value.id != csar.id){
+ this.selection.push({ label: csar.name, value: csar });
+ }
+ });
+ });
+
+
+ }
+
+ ngOnChanges(changes: SimpleChanges): void {
+
+ }
+
+ /**
+ * Closes the modal and emits change event.
+ */
+ closeInputModal(): void {
+ this.visible = false;
+ this.creationInProgress = false;
+ // TODO: remove this or place elsewhere
+ this.selectedApp = null;
+ this.visibleChange.emit(false);
+ }
+
+ createMigrationPlan(): void {
+ this.creationInProgress = true;
+ this.csar.subscribe(value => {
+ this.appService.createMigrationPlan(value.id, this.selectedApp.id).subscribe( value => {
+ console.log("Following result was received:");
+ console.log(value);
+ this.creationInProgress = false;
+ this.visible = false;
+ // TODO: remove this or place elsewhere
+ this.selectedApp = null;
+ this.visibleChange.emit(false);
+
+ });
+ });
+
+
+
+
+ }
+}
diff --git a/src/app/core/service/application-management.service.ts b/src/app/core/service/application-management.service.ts
index 3e0bf0ee..6681c3b9 100644
--- a/src/app/core/service/application-management.service.ts
+++ b/src/app/core/service/application-management.service.ts
@@ -22,7 +22,7 @@ import { Plan } from '../model/plan.model';
import { NgRedux } from '@angular-redux/store';
import { AppState } from '../../store/app-state.model';
import { Interface } from '../model/interface.model';
-import { HttpClient, HttpHeaders } from '@angular/common/http';
+import {HttpClient, HttpHeaders, HttpResponse} from '@angular/common/http';
import { forkJoin, Observable, of, throwError } from 'rxjs';
import { catchError, flatMap, map } from 'rxjs/operators';
import { InterfaceList } from '../model/interface-list.model';
@@ -129,6 +129,18 @@ export class ApplicationManagementService {
return this.http.get(url, this.httpOptionsAcceptJson);
}
+ createMigrationPlan(sourceCsarId: string, targetCsarId: string): Observable> {
+ console.log("requesting migration plan creation");
+ const url = new Path(this.ngRedux.getState().administration.containerUrl).append('csars').append('transform').toString();
+
+ const httpOptions = {
+ headers: new HttpHeaders({
+ 'Accept': 'application/json'
+ }),
+ };
+ return this.http.post(url, {source_csar_name: sourceCsarId, target_csar_name: targetCsarId}, { ...httpOptions, responseType: 'text', observe: 'response' });
+ }
+
getFirstServiceTemplateOfCsar(csarId: string): Observable {
const url = new Path(this.ngRedux.getState().administration.containerUrl)
.append('csars')
diff --git a/src/app/globals.ts b/src/app/globals.ts
index ee5d604f..a5ad55ec 100644
--- a/src/app/globals.ts
+++ b/src/app/globals.ts
@@ -21,6 +21,7 @@ export const globals = {
'instanceDataAPIUrl',
'planCallbackAddress_invoker',
'csarEntrypoint',
- 'OpenTOSCAContainerAPIServiceInstanceID'
+ 'OpenTOSCAContainerAPIServiceInstanceID',
+ 'OpenTOSCAContainerAPIServiceInstanceURL'
]
};
diff --git a/src/app/situations/model/agggregatedSituation.module.ts b/src/app/situations/model/agggregatedSituation.module.ts
new file mode 100644
index 00000000..413c9086
--- /dev/null
+++ b/src/app/situations/model/agggregatedSituation.module.ts
@@ -0,0 +1,8 @@
+import { ResourceSupport } from '../../core/model/resource-support.model';
+
+export class AggregatedSituation extends ResourceSupport {
+ id: string;
+ situation_ids: Array;
+ logic_expression: string;
+ active: string;
+}
\ No newline at end of file
diff --git a/src/app/situations/model/situation.module.ts b/src/app/situations/model/situation.module.ts
new file mode 100644
index 00000000..a373deba
--- /dev/null
+++ b/src/app/situations/model/situation.module.ts
@@ -0,0 +1,8 @@
+import { ResourceSupport } from '../../core/model/resource-support.model';
+
+export class Situation extends ResourceSupport {
+ id: string;
+ situation_template_id: string;
+ active: string;
+ thing_id: string;
+}
\ No newline at end of file
diff --git a/src/app/situations/model/situationtrigger.module.ts b/src/app/situations/model/situationtrigger.module.ts
new file mode 100644
index 00000000..d9217a94
--- /dev/null
+++ b/src/app/situations/model/situationtrigger.module.ts
@@ -0,0 +1,17 @@
+import { ResourceSupport } from '../../core/model/resource-support.model';
+import { Situation } from './situation.module';
+import { PlanParameter } from '../../core/model/plan-parameter.model';
+
+
+export class SituationTrigger extends ResourceSupport {
+ id: string;
+ situation_ids: Array;
+ service_instance_id: string;
+ aggregated_situation_ids: Array;
+ csar_id: string;
+ on_activation: string;
+ single_instance: string;
+ interface_name: string;
+ operation_name: string;
+ input_params: Array;
+}
diff --git a/src/app/situations/situation.component.html b/src/app/situations/situation.component.html
new file mode 100644
index 00000000..66c2936b
--- /dev/null
+++ b/src/app/situations/situation.component.html
@@ -0,0 +1,166 @@
+
+ Situations
+
+
+
+
+
+
+
+
+
+
+ Situation Template ID :
+ Thing ID:
+ Active:
+
+
+
+
+
+
+ {{col.header}}
+
+ |
+
+
+
+
+
+
+ {{instance[col.field] | date:'yyyy-MM-dd HH:mm'}}
+
+
+
+
+
+
+
+ {{instance[col.field]}}
+ |
+
+
+
+
+
+
+ Situation Triggers
+
+
+
+
+
+
+
+
+
+
+ Situation IDs:
+
+
+ CSAR ID:
+
+
+ ServiceInstance:
+
+ Interface:
+
+ Operation:
+
+ Single Instance? :
+ On Activation? :
+
+
+
+
+
+
+ Input Parameter |
+ Type |
+ value |
+
+
+
+
+
+
+
+
+
+
+ {{parameter.name}}
+
+
+ |
+
+
+
+
+
+
+ {{parameter.type}}
+
+
+ |
+
+
+
+
+
+
+ {{parameter.value}}
+
+
+ |
+
+
+
+
+
+
+
+
+ {{col.header}}
+
+ |
+
+
+
+
+
+
+
+
+ {{params["name"]}} : {{params["value"]}}
+
+
+
+
+
+
+
+ {{instance[col.field]}}
+ |
+
+
+
+
diff --git a/src/app/situations/situation.component.scss b/src/app/situations/situation.component.scss
new file mode 100644
index 00000000..9fb9e403
--- /dev/null
+++ b/src/app/situations/situation.component.scss
@@ -0,0 +1,20 @@
+/*!
+ * Copyright (c) 2018 University of Stuttgart.
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0, or the Apache Software License 2.0
+ * which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ */
+
+
+.weiss{
+ background:#ffffff;
+ color: #000000;
+}
+
diff --git a/src/app/situations/situation.component.ts b/src/app/situations/situation.component.ts
new file mode 100644
index 00000000..7f9baeec
--- /dev/null
+++ b/src/app/situations/situation.component.ts
@@ -0,0 +1,956 @@
+/*
+ * Copyright (c) 2018 University of Stuttgart.
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0, or the Apache Software License 2.0
+ * which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ */
+import { ApplicationManagementService } from './../core/service/application-management.service';
+import { Observable } from 'rxjs';
+import { Component, OnInit } from '@angular/core';
+import { BreadcrumbActions } from './../core/component/breadcrumb/breadcrumb-actions';
+import { AppState } from './../store/app-state.model';
+import { NgRedux, select } from '@angular-redux/store';
+import { HttpClient } from '@angular/common/http';
+import { Situation } from './model/situation.module';
+import { SituationTrigger } from './model/situationtrigger.module';
+import { AggregatedSituation } from './model/agggregatedSituation.module';
+import { PlanParameter } from './../core/model/plan-parameter.model';
+import { Item } from './../configuration/repository-configuration/repository-configuration.component';
+import { Plan } from '../core/model/plan.model';
+import {SelectItem} from "primeng/api";
+import {Csar} from "../core/model/csar.model";
+import {Interface} from "../core/model/interface.model";
+import {Operation} from "../core/model/operation.model";
+import {globals} from "../globals";
+import {ServiceTemplateInstance} from "../core/model/service-template-instance.model";
+import {ApplicationInstanceManagementService} from "../core/service/application-instance-management.service";
+import {GrowlActions} from "../core/growl/growl-actions";
+
+
+@Component({
+ selector: 'opentosca-situation',
+ templateUrl: './situation.component.html',
+ styleUrls: ['./situation.component.scss'],
+})
+
+/**
+ * This class contains the management of situations, aggregated situations and situation triggers. It also contains the
+ * situational execution of management plans.
+ *
+ * ! Note that a new version of the container must be used because aggregated situations did not exist.
+ *
+ * @author Lavinia Stiliadou
+ */
+export class SituationComponent implements OnInit {
+
+ // select the containerURL from the administration component
+ @select(['administration', 'containerUrl']) administrationItems$: Observable>;
+
+ administrationItems: Array- = [];
+ selectedRepository: string;
+
+ console = console;
+
+ public instanceId: string;
+
+ situations: Array;
+ csars: Csar[];
+ csar2interface: Map = new Map();
+ csar2instance: Map = new Map();
+ situationtriggers: Array;
+ aggregatedSituations = new Array();
+
+
+ hiddenParams: string[];
+
+ cols;
+ colsOfTriggers;
+ colsOfAggregatedSituations;
+
+ //inputs and selection
+ situationTemplateInput: string;
+ situationThingInput: string;
+ situationStateInput: boolean = false;
+
+ selectableSituations: Situation[];
+ selectedSituations: Situation[];
+ selectOnActivation: boolean = false;
+ selectSingleInstance: boolean = false;
+ selectedCsar: Csar;
+ selectedInstance : ServiceTemplateInstance;
+ selectedInterface: Interface;
+ selectedOperation: Operation;
+
+ /**
+ * The constructor of the class.
+ *
+ * @param ngRedux to dispatch the feedback
+ * @param http for the communication with the Situation API
+ * @param appService to access the normal execution of management plans
+ */
+ constructor(private ngRedux: NgRedux, private http: HttpClient, private appService: ApplicationManagementService,private instancesService: ApplicationInstanceManagementService) { }
+
+ /**
+ * Initialize the table for situations, aggregated situations and situationtriggers.
+ */
+ ngOnInit(): void {
+ this.administrationItems$.subscribe(items => { let temp = ""; this.administrationItems = items; temp = temp + items });
+
+ // sets the selectedRepository to the API Endpoint
+ this.selectedRepository = this.administrationItems + "/situationsapi";
+
+ this.hiddenParams = globals.hiddenElements;
+
+ this.appService.getResolvedApplications().subscribe(value => {
+ this.csars = value;
+ this.csars.forEach(value => {
+ this.appService.getInterfaces(value.id).subscribe(val => this.csar2interface.set(value,val));
+ this.instancesService.getServiceTemplateInstancesOfCsar(value).subscribe(val => this.csar2instance.set(value,Array.from(val.values())));
+ });
+ });
+
+
+
+ this.ngRedux.dispatch(BreadcrumbActions.updateBreadcrumb([
+ { label: 'Situation', routerLink: ['/situation'] }
+ ]));
+
+
+ // situation table columns
+ this.cols = [
+ { field: 'id', header: 'Situation ID', sortable: true },
+ { field: 'situation_template_id', header: 'Situation Template ID', sortable: true },
+ { field: 'active', header: 'active', sortable: true },
+ { field: 'thing_id', header: 'Thing ID', sortable: true },
+ { field: 'actions', header: 'actions', sortable: false }
+ ];
+
+ // aggregated situation table columns
+ this.colsOfAggregatedSituations = [
+ { field: 'id', header: 'Aggregated Situation ID', sortable: true },
+ { field: 'situation_ids', header: 'Situation IDs', sortable: true },
+ { field: 'logic_expression', header: 'Logic Expression', sortable: true },
+ { field: 'active', header: 'active', sortable: true },
+ { field: 'actions', header: 'actions', sortable: false }
+ ];
+
+ // situationtrigger table columns
+ this.colsOfTriggers = [
+ { field: 'id', header: 'Trigger ID', sortable: true },
+ { field: 'situation_ids', header: 'Situation IDs', sortable: true },
+ { field: 'csar_id', header: 'CSAR ID', sortable: true },
+ { field: 'on_activation', header: 'active', sortable: true },
+ { field: 'interface_name', header: 'Interface Name', sortable: true },
+ { field: 'operation_name', header: 'Operation Name', sortable: true },
+ { field: 'input_params', header: 'Input Parameter', sortable: true },
+ { field: 'single_instance', header: 'Single Instance', sortable: true },
+ { field: 'actions', header: 'actions', sortable: false }
+ ];
+
+ this.refresh();
+ }
+
+ /**
+ * Sends multiple @GET requests to the Situation API
+ */
+ refresh(): void {
+ console.log('Starting to refresh situations and triggers');
+ this.refreshSituations();
+ //this.refreshAggrSituations();
+ this.refreshTriggers();
+
+ //this.situations = new Array();
+ //this.situationtriggers = new Array();
+ //this.aggregatedSituations = new Array();
+ }
+
+ // situations
+
+
+
+ /**
+ * Format the @GET response and adds the situations from the API to the table.
+ * @param jsonText
+ */
+ editGetResponseSituations(jsonText: string): void {
+ this.situations = this.parseSituationsResponse(jsonText);
+ this.selectableSituations = this.situations;
+ }
+
+ /**
+ * Format the @GET response and adds the situations from the API to the table.
+ * @param jsonText
+ */
+ parseSituationsResponse(jsonText: string): Situation[] {
+ let o = jsonText;
+ while (o.includes('_links')) {
+ o = o.replace(",\"_links\"", "");
+ }
+ let situations = o;
+ let obj = JSON.parse(situations);
+ let situationsA: Situation[] = [];
+ // number of situations
+ if (obj.situations != undefined) {
+ let length = obj.situations.length;
+
+ // goes over all situations in the API and adds them to the table
+ for (let i = 0; i < length; i++) {
+ let situation = new Situation();
+ situation.id = obj.situations[i].id;
+ situation.situation_template_id = obj.situations[i].situation_template_id;
+ situation.active = obj.situations[i].active;
+ situation.thing_id = obj.situations[i].thing_id;
+ situationsA.push(situation);
+ }
+ console.log('Fetched situations');
+ return situationsA;
+ }
+ console.log('Couldnt fetch situations');
+ return null;
+ }
+
+ createSituation(){
+ let check: boolean = true;
+ check = check && this.checkString(this.situationThingInput);
+ check = check && this.checkString(this.situationTemplateInput);
+ if(check) {
+ let sit: Situation = new Situation();
+ sit.situation_template_id = this.situationTemplateInput;
+ sit.thing_id = this.situationThingInput;
+ sit.active = String(this.situationStateInput);
+ this.postSituation(sit);
+ }
+ }
+
+ checkString(string: String): boolean {
+ if(string == "" || string == null) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * Sends a @POST request to the API to create a new situation.
+ * @param situation
+ */
+ postSituation(situation: Situation): void {
+ let post = this.http.post(this.selectedRepository + '/situations', {
+ situation_template_id: situation.situation_template_id,
+ thing_id: situation.thing_id,
+ active: situation.active
+ });
+
+ post.subscribe(() => { this.onCompletionSuccess('post'); this.refresh() },
+ () => { this.onCompletionError('post'); this.refresh() });
+ }
+
+
+ /**
+ * Changes the active from true/false to false/true.
+ *
+ * @param index column index where the active attribut need to be changed
+ */
+ switchActive(index) {
+ let table = document.getElementById('sit'),
+ active;
+ for (let i = 1; i < table.getElementsByTagName("tr").length; i++) {
+ // sucht die Tabellenzeile, dessen erste Spalte dem Index der Situation entspricht
+ if (table.getElementsByTagName("tr").item(i).cells.item(0).innerText == index) {
+ active = table.getElementsByTagName("tr").item(i).cells.item(2).innerText;
+ if (active === 'true') {
+ active = 'false';
+ } else {
+ active = 'true';
+ }
+ table.getElementsByTagName("tr").item(i).cells.item(2).innerText = active;
+ };
+ }
+ return active;
+ }
+
+
+ /**
+ * Format the @GET response and adds the aggregated situations from the API to the table.
+ * @param jsonText
+ */
+ editGetResponseAggregatedSituations(jsonText: string): Array {
+ let o = jsonText;
+ while (o.includes('_links')) {
+ o = o.replace(",\"_links\"", "");
+ }
+ let aggregated_situations = o;
+ let obj = JSON.parse(aggregated_situations);
+
+ let aggregatedSituations = new Array();
+ if (obj.aggregated_situations != undefined) {
+ // number of aggregated situations
+ let length = obj.aggregated_situations.length;
+
+
+ // goes over all aggregated situations in the API and adds them to the table
+ for (let i = 0; i < length; i++) {
+ let aggregatedsituation = new AggregatedSituation();
+ aggregatedsituation.id = obj.aggregated_situations[i].id;
+ aggregatedsituation.situation_ids = obj.aggregated_situations[i].situation_ids;
+ aggregatedsituation.logic_expression = obj.aggregated_situations[i].logic_expression;
+ aggregatedsituation.active = obj.aggregated_situations[i].active;
+
+ aggregatedSituations.push(aggregatedsituation);
+ }
+
+ return aggregatedSituations;
+ }
+ return null;
+
+ }
+
+ /**
+ * Sends a @PUT request to the API to activate/deactivate a situation with the given id.
+ *
+ * @param id
+ */
+ putSituation(id: string): void {
+ let active = this.switchActive(id);
+ let put = this.http.put(this.selectedRepository + '/situations/' + id.toString(), {
+ id: id,
+ active: active
+ }, { responseType: 'text' });
+ put.subscribe(() => {
+ this.onCompletionSuccess(id + ',P'); this.refresh();
+ }, () => {
+ this.onCompletionError(id + ',P'); this.refresh();
+ });
+ }
+
+ /**
+ * Deletes the situation with the given id.
+ *
+ * @param id
+ */
+ deleteSituation(id: string): void {
+ let deleteRequest = this.http.delete(this.selectedRepository + '/situations/' + id, {});
+ deleteRequest.subscribe(() => { this.onCompletionSuccess(id + ',D'); this.refresh() },
+ err => this.onCompletionError(id + ',D'));
+ }
+
+ /**
+ * Deletes all situations.
+ */
+ deleteAllSituations(): void {
+ let arrayOfSituationIds: string[] = new Array();
+ this.situations.forEach(function (value) {
+ arrayOfSituationIds.push(value.id);
+ })
+ for (let i = 0; i < arrayOfSituationIds.length; i++) {
+ let id = arrayOfSituationIds[i];
+ this.deleteSituation(id);
+ }
+ }
+
+
+ /**
+ * Format the @GET response and adds the situationtrigger from the API to the table.
+ * @param jsonText
+ */
+ editGetResponseTriggers(jsonText: string): Array {
+ let o = jsonText;
+
+ console.log("Received following json:");
+ console.log(jsonText);
+
+ while (o.includes('_links')) {
+ o = o.replace(",\"_links\"", "");
+ }
+
+ let situation_triggers = o;
+ let obj = JSON.parse(situation_triggers);
+
+ let situationtriggers = new Array();
+ if (obj.situation_triggers != undefined) {
+ // number of situationtriggers
+ let length = obj.situation_triggers.length;
+
+ for (let i = 0; i < length; i++) {
+ let trigger = new SituationTrigger();
+ trigger.id = obj.situation_triggers[i].id;
+ trigger.situation_ids = obj.situation_triggers[i].situation_ids;
+ trigger.aggregated_situation_ids = obj.situation_triggers[i].aggregated_situations_ids;
+ trigger.csar_id = obj.situation_triggers[i].csar_id;
+ trigger.on_activation = obj.situation_triggers[i].on_activation;
+ trigger.interface_name = obj.situation_triggers[i].interface_name;
+ trigger.operation_name = obj.situation_triggers[i].operation_name;
+ trigger.single_instance = obj.situation_triggers[i].single_instance;
+ let lengthInput = obj.situation_triggers[i].input_params.length;
+ console.log("Inputparams length:");
+ console.log(lengthInput);
+ let inputParameter = new Array();
+ for (let j = 0; j < lengthInput; j++) {
+ let planParam = new PlanParameter();
+ planParam.name = obj.situation_triggers[i].input_params[j].name;
+ planParam.type = obj.situation_triggers[i].input_params[j].type;
+ planParam.value = obj.situation_triggers[i].input_params[j].value;
+ inputParameter.push(planParam);
+ }
+ trigger.input_params = inputParameter;
+ console.log("Parsed following trigger:");
+ console.log(trigger);
+ situationtriggers.push(trigger);
+ }
+ this.situationtriggers = situationtriggers;
+ return situationtriggers;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Colors the row where the situationtrigger is activated.
+ * @param trigger
+ */
+ colorTriggerRow(trigger: SituationTrigger) {
+ let table = document.getElementById("triggers");
+ let colorCells;
+
+ for (let i = 1; i < table.getElementsByTagName("tr").length; i++) {
+ if (table.getElementsByTagName("tr").item(i).cells.item(0).innerText === trigger.id) {
+ colorCells = table.getElementsByTagName("tr").item(i).cells;
+ for (let j = 0; j < colorCells.length; j++) {
+ table.getElementsByTagName("tr").item(i).cells.item(j).style.background = "#c1c3c5";
+ }
+ };
+ }
+ }
+
+ /**
+ * Starts the situation-dependent execution of the plan if trigger active = all situations active.
+ * @param trigger
+ */
+ activateTrigger(trigger: SituationTrigger, situations: Array, aggregated_situations: Array): boolean {
+ let active = trigger.on_activation;
+ let success = true;
+ let index;
+
+ // situationtriggers must contain at least one situation or aggregated situation
+ if (trigger.aggregated_situation_ids.length == 0 && trigger.situation_ids.length == 0) {
+ return false;
+ }
+
+ // check if trigger active = all situations active
+ for (let i = 0; i < trigger.situation_ids.length; i++) {
+ for (let j = 0; j < situations.length; j++) {
+ if (situations[j].id == trigger.situation_ids[i]) {
+ index = j;
+ if (situations[index].active.toString() != active) {
+ return false;
+ }
+ }
+ }
+ }
+
+ // check if trigger active = all aggr situations active
+ for (let i = 0; i < trigger.aggregated_situation_ids.length; i++) {
+ for (let j = 0; j < aggregated_situations.length; j++) {
+ if (aggregated_situations[j].id == trigger.aggregated_situation_ids[i]) {
+ index = j;
+ if (aggregated_situations[index].active.toString() != active) {
+ return false;
+ }
+ }
+ }
+ }
+
+ return success;
+ }
+
+
+ /**
+ *
+ * Returns the plan based on the operation and interface of the trigger.
+ *
+ * @param text response from the http Request to the interface
+ * @param trigger responsible for the situation-dependent execution
+ */
+ getPlan(text: string, trigger: SituationTrigger) {
+ let o = text;
+ let obj = JSON.parse(o);
+ let operation_name = trigger.operation_name;
+ if (operation_name !== null) {
+ let temp = obj.operations[operation_name]._embedded.plan;
+
+ let plan = new Plan();
+ plan.id = temp.id;
+ plan.plan_type = temp.plan_type;
+ plan.plan_language = temp.plan_language;
+ for (let j = 0; j < trigger.input_params.length; j++) {
+ for (let i = 0; i < temp.input_parameters.length; i++) {
+ if (typeof trigger.input_params !== 'undefined') {
+ if (temp.input_parameters[i].name === trigger.input_params[j].name) {
+ temp.input_parameters[i].value = trigger.input_params[j].value;
+ }
+ }
+ }
+ }
+ plan.input_parameters = temp.input_parameters;
+ plan.output_parameters = temp.output_parameters;
+ plan.plan_model_reference = temp.plan_model_reference;
+ plan._links = temp._links;
+
+ return plan;
+ }
+ }
+
+
+
+ /**
+ * Sends a @GET requests to the Situation API.
+ */
+ refreshSituations(): void {
+ this.http.get(this.selectedRepository + '/situations', { responseType: 'text' }).subscribe(response => this.editGetResponseSituations(response));
+ }
+ /**
+ * Sends a @GET request to the Situation API to get all triggers.
+ */
+ refreshTriggers(): void {
+ let triggers = this.http.get(this.selectedRepository + '/triggers', { responseType: 'text' });
+ triggers.subscribe(response2 => this.editGetResponseTriggers(response2));
+ }
+
+ createSituationTrigger(): void {
+ let trigger: SituationTrigger = new SituationTrigger();
+ trigger.situation_ids = new Array();
+ this.selectedSituations.forEach(value => trigger.situation_ids.push(value.id));
+ trigger.csar_id = this.selectedCsar.id;
+ trigger.interface_name = this.selectedInterface.name;
+ trigger.operation_name = this.selectedOperation.name;
+ trigger.single_instance = String(this.selectSingleInstance);
+ trigger.on_activation = String(this.selectOnActivation);
+ trigger.input_params = this.selectedOperation._embedded.plan.input_parameters;
+
+ if(this.selectedInstance !== null && this.selectedInstance !== undefined) {
+ trigger.service_instance_id = String(this.selectedInstance.id);
+ }
+
+ this.postSituationTrigger(trigger);
+ }
+
+ resetSituationTriggerInput(): void {
+ this.selectedSituations = new Array();
+ this.selectedCsar = null;
+ this.selectedInterface = null;
+ this.selectedOperation = null;
+ this.selectedInstance = null;
+
+ }
+
+ /**
+ * Sends a @POST request to the API to create a new situationtrigger.
+ * @param trigger
+ */
+ postSituationTrigger(trigger: SituationTrigger): void {
+ let result = trigger.situation_ids;
+
+ let post = this.http.post(this.selectedRepository + '/triggers', {
+ situation_ids: result,
+ //aggregatedsituation_ids: trigger.aggregated_situation_ids,
+ csar_id: trigger.csar_id,
+ interface_name: trigger.interface_name,
+ operation_name: trigger.operation_name,
+ input_params: trigger.input_params,
+ on_activation: trigger.on_activation,
+ service_instance_id: trigger.service_instance_id,
+ single_instance: trigger.single_instance
+ });
+ post.subscribe(() => { this.onCompletionSuccess('post'); this.refresh() }, err => { this.onCompletionErrorTrigger('post'); this.refresh() });
+ }
+
+ /**
+ * Deletes the situationtrigger with the given id.
+ *
+ * @param id
+ */
+ deleteTrigger(id: string): void {
+ let deleteRequest = this.http.delete(this.selectedRepository + '/triggers/' + id, {});
+ deleteRequest.subscribe(() => { this.onCompletionSuccessTrigger('delete'); this.refresh() },
+ err => { this.onCompletionErrorTrigger(id +',D'); this.refresh(); });
+ }
+
+ /**
+ * Deletes all situationtriggers.
+ */
+ deleteAllTriggers(): void {
+ let arrayOfTriggerIds: string[] = new Array();
+ this.situations.forEach(function (value) {
+ arrayOfTriggerIds.push(value.id);
+ })
+ for (let i = 0; i < arrayOfTriggerIds.length; i++) {
+ let id = arrayOfTriggerIds[i];
+ this.deleteTrigger(id);
+ }
+ }
+
+ /**
+ * Starts the situation-dependent execution of the plan if trigger active = all situations active.
+ * @param trigger
+ */
+ activate(trigger: SituationTrigger): void {
+ let success = this.activateTrigger(trigger, this.situations, this.aggregatedSituations);
+ if (success) {
+ this.selectPlan(trigger);
+ }else{
+ this.onCompletionError('activate');
+ }
+ }
+
+ /**
+ * Executes the plan (based on the interface and operation)
+ * @param trigger
+ */
+ selectPlan(trigger: SituationTrigger) {
+ this.instanceId = null;
+
+ let csar_id = trigger.csar_id;
+ let interface_name = trigger.interface_name;
+
+ let csarRepo = this.selectedRepository.replace('/situationsapi', '/csars/');
+ if (csar_id !== '' && interface_name !== '') {
+ let temp = this.http.get(csarRepo + csar_id, { responseType: 'text' });
+ temp.subscribe(response => {
+ let interfacesOfCSAR = this.getServiceTemplateCsar(response) + '/boundarydefinitions/interfaces/'+ interface_name;
+ let httpPlanRequest = this.http.get(interfacesOfCSAR, { responseType: 'text' });
+ let plan : Plan;
+ httpPlanRequest.subscribe(response => {
+ plan = this.getPlan(response, trigger);
+ if (plan.plan_type.match('BuildPlan')) {
+ this.appService.triggerManagementPlan(plan, this.instanceId).subscribe(() => { this.colorTriggerRow(trigger) }, () => this.onCompletionErrorTrigger(plan.id +',P'));
+ } else {
+ if (typeof trigger.input_params !== 'undefined') {
+ for (let i = 0; i < trigger.input_params.length; i++) {
+ if (trigger.input_params[i].name === 'OpenTOSCAContainerAPIServiceInstanceURL') {
+ this.instanceId = trigger.input_params[i].value
+ }
+ }
+ this.appService.triggerManagementPlan(plan, this.instanceId).subscribe(() => { this.colorTriggerRow(trigger) }, () => this.onCompletionErrorTrigger(plan.id +',P'));
+ }
+ }
+ }, () => this.onCompletionErrorTrigger(interface_name + ',I'));
+ }, () => this.onCompletionErrorTrigger(csar_id + ',C'));
+ }
+ }
+
+
+ /**
+ * Returns the servicetemplate link from the CSAR.
+ * @param text
+ */
+ getServiceTemplateCsar(text: any) {
+ let o = text;
+ o = JSON.parse(text);
+ return o._links.servicetemplate.href;
+ }
+
+ /**
+ * Confirmation messages
+ * @param typeOfRequest @POST / @DELETE / @PUT
+ */
+ onCompletionSuccess(typeOfRequest: string) {
+ let filterRequest = typeOfRequest.split(',');
+ if (typeOfRequest === 'post') {
+ this.ngRedux.dispatch(GrowlActions.addGrowl(
+ {
+ severity: 'success',
+ summary: 'Creation of situation ',
+ detail: `The situation is successfully created.`
+ }
+ ));
+ } else if (filterRequest[1] === 'D') {
+ this.ngRedux.dispatch(GrowlActions.addGrowl(
+ {
+ severity: 'success',
+ summary: 'Delete of situation ' + filterRequest[0],
+ detail: `The aggregated situations and the situationtriggers which contains the situation and the situation are successfully deleted.`
+ }
+ ));
+ } else {
+ this.ngRedux.dispatch(GrowlActions.addGrowl(
+ {
+ severity: 'success',
+ summary: 'Update of situation ' + filterRequest[0],
+ detail: `The situation is successfully updated.`
+ }
+ ));
+ }
+
+ }
+
+ /**
+ * Error messages
+ * @param typeOfRequest @POST / activateTrigger / @DELETE / @PUT
+ */
+ onCompletionError(typeOfRequest: string): void {
+ let filterRequest = typeOfRequest.split(',');
+ if (typeOfRequest === 'post') {
+ this.ngRedux.dispatch(GrowlActions.addGrowl(
+ {
+ severity: 'error',
+ summary: 'Error at creation of situation',
+ detail: `The situation is not created.`
+ }
+ ));
+ } else if (typeOfRequest === 'activate') {
+ this.ngRedux.dispatch(GrowlActions.addGrowl(
+ {
+ severity: 'error',
+ summary: 'Error',
+ detail: 'The active attribute of the situation trigger and of it is situations and aggregated situations are not corresponding.'
+ }
+ ));
+ } else if (filterRequest[1] === 'D') {
+ this.ngRedux.dispatch(GrowlActions.addGrowl(
+ {
+ severity: 'error',
+ summary: 'Error at delete of situation',
+ detail: 'The aggregated situations which contains the situation and the situation are not deleted.'
+ }
+ ));
+ } else {
+ this.ngRedux.dispatch(GrowlActions.addGrowl(
+ {
+ severity: 'error',
+ summary: 'Error at update of situation' + typeOfRequest,
+ detail: `The situation is not updated.`
+ }
+ ));
+ }
+ }
+
+ /**
+ * Confirmation messages
+ * @param typeOfRequest @POST / @DELETE / @PUT
+ */
+ onCompletionSuccessAggregatedSituation(typeOfRequest: string) {
+ let filterRequest = typeOfRequest.split(',');
+ if (typeOfRequest === 'post') {
+ this.ngRedux.dispatch(GrowlActions.addGrowl(
+ {
+ severity: 'success',
+ summary: 'Creation of a aggregated situation ',
+ detail: `The aggregated situation is successfully created.`
+ }
+ ));
+ } else if (filterRequest[1] === 'D') {
+ this.ngRedux.dispatch(GrowlActions.addGrowl(
+ {
+ severity: 'success',
+ summary: 'Delete of aggregated situation ' + filterRequest[0],
+ detail: `The aggregated situation is successfully deleted and the corresponding situationtriggers are deleted.`
+ }
+ ));
+ } else {
+ this.ngRedux.dispatch(GrowlActions.addGrowl(
+ {
+ severity: 'success',
+ summary: 'Update of aggregated situation ' + filterRequest[0],
+ detail: `The aggregated situation is successfully updated.`
+ }
+ ));
+ }
+ }
+
+ /**
+ * Error messages
+ * @param typeOfRequest @POST
+ */
+ onCompletionErrorAggregatedSituation(typeOfRequest: string) {
+ let filterRequest = typeOfRequest.split(',');
+ if (typeOfRequest === 'post') {
+ this.ngRedux.dispatch(GrowlActions.addGrowl(
+ {
+ severity: 'error',
+ summary: 'Creation of aggregation situation failed',
+ detail: `The aggregated situation is not created.`
+ }
+ ));
+ } else if (filterRequest[1] === 'D') {
+ this.ngRedux.dispatch(GrowlActions.addGrowl(
+ {
+ severity: 'error',
+ summary: 'Delete of aggregation situation ' + filterRequest[0] + ' failed.',
+ detail: `The aggregated situation is not deleted.`
+ }
+ ));
+ } else {
+ this.ngRedux.dispatch(GrowlActions.addGrowl(
+ {
+ severity: 'error',
+ summary: 'Update of aggregation situation ' + filterRequest[0] + ' failed.',
+ detail: `The aggregated situation is not updated.`
+ }
+ ));
+ }
+ }
+
+ /**
+ * Error messages if the input is invalid.
+ * @param failedInput
+ */
+ failedAggregatedSituationTextInput(failedInput: string) {
+ if (failedInput === 'Expression') {
+ this.ngRedux.dispatch(GrowlActions.addGrowl(
+ {
+ severity: 'error',
+ summary: 'Invalid ' + failedInput,
+ detail: failedInput + ' does not correspond to the scheme NumberOperatorNumber.'
+ }));
+ } else if (failedInput === 'ExpressionSit') {
+ this.ngRedux.dispatch(GrowlActions.addGrowl(
+ {
+ severity: 'error',
+ summary: 'Invalid ' + failedInput,
+ detail: failedInput + ' contains situation ids which are not in situation ids.'
+ }));
+ } else {
+ this.ngRedux.dispatch(GrowlActions.addGrowl(
+ {
+ severity: 'error',
+ summary: 'Invalid ' + failedInput,
+ detail: failedInput + ' contains some unknown situation ids.'
+ }));
+ }
+ }
+
+ /**
+ * Error messages
+ * @param typeOfRequest @POST / @DELETE
+ */
+ onCompletionErrorTrigger(typeOfRequest: string) {
+ let filterRequest = typeOfRequest.split(',');
+ if (typeOfRequest === 'post') {
+ this.ngRedux.dispatch(GrowlActions.addGrowl(
+ {
+ severity: 'error',
+ summary: 'Creation of situationtrigger failed',
+ detail: `The situationtrigger is not created.`
+ }
+ ));
+ } else if (filterRequest[1] === 'C') {
+ this.ngRedux.dispatch(GrowlActions.addGrowl(
+ {
+ severity: 'error',
+ summary: 'Activation of situationtrigger failed',
+ detail: `The situationtrigger is not started because the CSAR ` + filterRequest[0] + ' not exists.'
+ }
+ ));
+ } else if (filterRequest[1] === 'I') {
+ this.ngRedux.dispatch(GrowlActions.addGrowl(
+ {
+ severity: 'error',
+ summary: 'Activation of situationtrigger failed',
+ detail: `The situationtrigger is not started because the Interface ` + filterRequest[0] + ' not exists.'
+ }
+ ));
+ } else if ( filterRequest[1] === 'D'){
+ this.ngRedux.dispatch(GrowlActions.addGrowl(
+ {
+ severity: 'error',
+ summary: 'Delete of situationtrigger ' + filterRequest[0]+' failed',
+ detail: `The situationtrigger is not deleted.`
+ }
+ ));
+ }else{
+ this.ngRedux.dispatch(GrowlActions.addGrowl(
+ {
+ severity: 'error',
+ summary: 'Execution of plan failed',
+ detail: 'The plan ' + filterRequest[0]+ ' is not executed.'
+ }
+ ));
+ }
+ }
+
+ /**
+ * Confirmation messages
+ * @param typeOfRequest @POST / @DELETE
+ */
+ onCompletionSuccessTrigger(typeOfRequest: string) {
+ if (typeOfRequest === 'post') {
+ this.ngRedux.dispatch(GrowlActions.addGrowl(
+ {
+ severity: 'success',
+ summary: 'Creation of situationtrigger',
+ detail: `The situationtrigger is successfully created.`
+ }
+ ));
+ } else {
+ this.ngRedux.dispatch(GrowlActions.addGrowl(
+ {
+ severity: 'success',
+ summary: 'Delete of situationtrigger',
+ detail: `The situationtrigger is successfully deleted.`
+ }
+ ));
+ }
+ }
+
+ /**
+ * Error messages if the input is invalid
+ * @param failedInput
+ */
+ failedSituationTriggerTextInput(failedInput: string) {
+ let filterInput = failedInput.split(',');
+ if (failedInput === 'Active' || failedInput === 'Single Instance') {
+ this.ngRedux.dispatch(GrowlActions.addGrowl(
+ {
+ severity: 'error',
+ summary: 'Invalid ' + failedInput,
+ detail: failedInput + ' must be false or true.'
+ }));
+ } else if (filterInput[1] === 'O') {
+ this.ngRedux.dispatch(GrowlActions.addGrowl(
+ {
+ severity: 'error',
+ summary: 'Creation of situationtrigger failed',
+ detail: 'The operation ' + filterInput[0] + ' not exists for the given interface.'
+ }
+ ));
+ } else if (failedInput === 'Situation IDs' || failedInput === 'Aggregated Situation IDs') {
+ this.ngRedux.dispatch(GrowlActions.addGrowl(
+ {
+ severity: 'error',
+ summary: 'Invalid ' + failedInput,
+ detail: 'Some ' + failedInput + ' are unknown'
+ }));
+ } else if (failedInput === 'Empty') {
+ this.ngRedux.dispatch(GrowlActions.addGrowl(
+ {
+ severity: 'error',
+ summary: 'Invalid Input',
+ detail: 'The Id of the situations and aggregated situations can never be empty at the same time.'
+ }));
+ } else if (failedInput === 'Value') {
+ this.ngRedux.dispatch(GrowlActions.addGrowl(
+ {
+ severity: 'error',
+ summary: 'Error',
+ detail: `The value of an input parameter can not be empty.`
+ }
+ ));
+ } else {
+ this.ngRedux.dispatch(GrowlActions.addGrowl(
+ {
+ severity: 'error',
+ summary: 'Invalid ' + failedInput,
+ detail: failedInput + ' can not be empty.'
+ }));
+ }
+ }
+
+
+}
diff --git a/src/app/situations/situation.module.ts b/src/app/situations/situation.module.ts
new file mode 100644
index 00000000..c8790151
--- /dev/null
+++ b/src/app/situations/situation.module.ts
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2018 University of Stuttgart.
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0, or the Apache Software License 2.0
+ * which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ */
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { SituationComponent } from './situation.component';
+import { RouterModule } from '@angular/router';
+import { NgSpinKitModule } from 'ng-spin-kit';
+import {
+ ButtonModule, CardModule, CheckboxModule, ConfirmDialogModule, DialogModule,
+ DropdownModule, ScrollPanelModule, ToolbarModule, FieldsetModule,
+ TooltipModule, MultiSelect, MultiSelectModule, ToggleButtonModule, InputTextModule
+} from 'primeng/primeng';
+import { TableModule } from 'primeng/table';
+import { FormsModule } from '@angular/forms';
+
+
+@NgModule({
+ imports: [
+ CommonModule,
+ CheckboxModule,
+ FormsModule,
+ RouterModule,
+ TooltipModule,
+ TableModule,
+ FieldsetModule,
+ CardModule,
+ ButtonModule,
+ ScrollPanelModule,
+ ToolbarModule,
+ DropdownModule,
+ DialogModule,
+ NgSpinKitModule,
+ ConfirmDialogModule,
+ MultiSelectModule,
+ ToggleButtonModule,
+ InputTextModule
+ ],
+ declarations: [SituationComponent],
+})
+export class SituationModule {
+}
+
+