From be564bab65067e719e84850896ad8958d8684266 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan-Gerrit=20G=C3=B6bel?=
<86782124+jggoebel@users.noreply.github.com>
Date: Fri, 8 Mar 2024 14:00:46 +0100
Subject: [PATCH 1/6] Add mermaid-js to admin-ui (#202)
---
package-lock.json | 904 ++++++++++++++++++++++----
package.json | 1 +
src/app/step/hf-markdown.component.ts | 77 ++-
3 files changed, 844 insertions(+), 138 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index e401ce09..d60a7b0a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -30,6 +30,7 @@
"chartjs-plugin-datalabels": "^2.1.0",
"font-awesome": "^4.7.0",
"marked": "^4.3.0",
+ "mermaid": "^10.6.0",
"moment": "^2.29.4",
"ng2-charts": "^4.0.0",
"ng2-dragula": "^5.0.0",
@@ -2470,8 +2471,7 @@
},
"node_modules/@braintree/sanitize-url": {
"version": "6.0.4",
- "license": "MIT",
- "optional": true
+ "license": "MIT"
},
"node_modules/@cds/city": {
"version": "1.1.0",
@@ -3427,6 +3427,32 @@
"@types/node": "*"
}
},
+ "node_modules/@types/d3-scale": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.8.tgz",
+ "integrity": "sha512-gkK1VVTr5iNiYJ7vWDI+yUFFlszhNMtVeneJ6lUTKPjprsvLLI9/tgEGiXJOnlINJA8FyA88gfnQsHbybVZrYQ==",
+ "dependencies": {
+ "@types/d3-time": "*"
+ }
+ },
+ "node_modules/@types/d3-scale-chromatic": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.0.3.tgz",
+ "integrity": "sha512-laXM4+1o5ImZv3RpFAsTRn3TEkzqkytiOY0Dz0sq5cnd1dtNlk6sHLon4OvqaiJb28T0S/TdsBI3Sjsy+keJrw=="
+ },
+ "node_modules/@types/d3-time": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.3.tgz",
+ "integrity": "sha512-2p6olUZ4w3s+07q3Tm2dbiMZy5pCDfYwtLXXHUnVzXgQlZ/OyPtUz6OL382BkOuGlLXqfT+wqv8Fw2v8/0geBw=="
+ },
+ "node_modules/@types/debug": {
+ "version": "4.1.12",
+ "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz",
+ "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==",
+ "dependencies": {
+ "@types/ms": "*"
+ }
+ },
"node_modules/@types/dragula": {
"version": "2.1.39",
"resolved": "https://registry.npmjs.org/@types/dragula/-/dragula-2.1.39.tgz",
@@ -3510,11 +3536,24 @@
"version": "4.3.2",
"license": "MIT"
},
+ "node_modules/@types/mdast": {
+ "version": "3.0.15",
+ "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.15.tgz",
+ "integrity": "sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ==",
+ "dependencies": {
+ "@types/unist": "^2"
+ }
+ },
"node_modules/@types/mime": {
"version": "1.3.5",
"dev": true,
"license": "MIT"
},
+ "node_modules/@types/ms": {
+ "version": "0.7.34",
+ "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz",
+ "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g=="
+ },
"node_modules/@types/node": {
"version": "12.20.55",
"dev": true,
@@ -3587,6 +3626,11 @@
"version": "2.0.7",
"license": "MIT"
},
+ "node_modules/@types/unist": {
+ "version": "2.0.10",
+ "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz",
+ "integrity": "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA=="
+ },
"node_modules/@types/ws": {
"version": "8.5.10",
"dev": true,
@@ -5010,6 +5054,15 @@
"node": ">=4"
}
},
+ "node_modules/character-entities": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz",
+ "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
"node_modules/chardet": {
"version": "0.7.0",
"dev": true,
@@ -5187,7 +5240,6 @@
"node_modules/commander": {
"version": "8.3.0",
"license": "MIT",
- "optional": true,
"engines": {
"node": ">= 12"
}
@@ -5457,7 +5509,6 @@
"node_modules/cose-base": {
"version": "1.0.3",
"license": "MIT",
- "optional": true,
"dependencies": {
"layout-base": "^1.0.0"
}
@@ -5693,7 +5744,6 @@
"node_modules/cytoscape": {
"version": "3.28.1",
"license": "MIT",
- "optional": true,
"dependencies": {
"heap": "^0.2.6",
"lodash": "^4.17.21"
@@ -5705,7 +5755,6 @@
"node_modules/cytoscape-cose-bilkent": {
"version": "4.1.0",
"license": "MIT",
- "optional": true,
"dependencies": {
"cose-base": "^1.0.0"
},
@@ -5715,7 +5764,8 @@
},
"node_modules/cytoscape-fcose": {
"version": "2.2.0",
- "license": "MIT",
+ "resolved": "https://registry.npmjs.org/cytoscape-fcose/-/cytoscape-fcose-2.2.0.tgz",
+ "integrity": "sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ==",
"optional": true,
"dependencies": {
"cose-base": "^2.2.0"
@@ -5726,7 +5776,8 @@
},
"node_modules/cytoscape-fcose/node_modules/cose-base": {
"version": "2.2.0",
- "license": "MIT",
+ "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-2.2.0.tgz",
+ "integrity": "sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==",
"optional": true,
"dependencies": {
"layout-base": "^2.0.0"
@@ -5734,13 +5785,14 @@
},
"node_modules/cytoscape-fcose/node_modules/layout-base": {
"version": "2.0.1",
- "license": "MIT",
+ "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-2.0.1.tgz",
+ "integrity": "sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==",
"optional": true
},
"node_modules/d3": {
"version": "7.8.5",
- "license": "ISC",
- "optional": true,
+ "resolved": "https://registry.npmjs.org/d3/-/d3-7.8.5.tgz",
+ "integrity": "sha512-JgoahDG51ncUfJu6wX/1vWQEqOflgXyl4MaHqlcSruTez7yhaRKR9i8VjjcQGeS2en/jnFivXuaIMnseMMt0XA==",
"dependencies": {
"d3-array": "3",
"d3-axis": "3",
@@ -5779,8 +5831,8 @@
},
"node_modules/d3-array": {
"version": "3.2.4",
- "license": "ISC",
- "optional": true,
+ "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz",
+ "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==",
"dependencies": {
"internmap": "1 - 2"
},
@@ -5790,16 +5842,16 @@
},
"node_modules/d3-axis": {
"version": "3.0.0",
- "license": "ISC",
- "optional": true,
+ "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz",
+ "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==",
"engines": {
"node": ">=12"
}
},
"node_modules/d3-brush": {
"version": "3.0.0",
- "license": "ISC",
- "optional": true,
+ "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz",
+ "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==",
"dependencies": {
"d3-dispatch": "1 - 3",
"d3-drag": "2 - 3",
@@ -5813,8 +5865,8 @@
},
"node_modules/d3-chord": {
"version": "3.0.1",
- "license": "ISC",
- "optional": true,
+ "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz",
+ "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==",
"dependencies": {
"d3-path": "1 - 3"
},
@@ -5824,16 +5876,16 @@
},
"node_modules/d3-color": {
"version": "3.1.0",
- "license": "ISC",
- "optional": true,
+ "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz",
+ "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==",
"engines": {
"node": ">=12"
}
},
"node_modules/d3-contour": {
"version": "4.0.2",
- "license": "ISC",
- "optional": true,
+ "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz",
+ "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==",
"dependencies": {
"d3-array": "^3.2.0"
},
@@ -5843,8 +5895,8 @@
},
"node_modules/d3-delaunay": {
"version": "6.0.4",
- "license": "ISC",
- "optional": true,
+ "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz",
+ "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==",
"dependencies": {
"delaunator": "5"
},
@@ -5854,16 +5906,16 @@
},
"node_modules/d3-dispatch": {
"version": "3.0.1",
- "license": "ISC",
- "optional": true,
+ "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz",
+ "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==",
"engines": {
"node": ">=12"
}
},
"node_modules/d3-drag": {
"version": "3.0.0",
- "license": "ISC",
- "optional": true,
+ "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz",
+ "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==",
"dependencies": {
"d3-dispatch": "1 - 3",
"d3-selection": "3"
@@ -5874,8 +5926,8 @@
},
"node_modules/d3-dsv": {
"version": "3.0.1",
- "license": "ISC",
- "optional": true,
+ "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz",
+ "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==",
"dependencies": {
"commander": "7",
"iconv-lite": "0.6",
@@ -5898,16 +5950,16 @@
},
"node_modules/d3-dsv/node_modules/commander": {
"version": "7.2.0",
- "license": "MIT",
- "optional": true,
+ "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
+ "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
"engines": {
"node": ">= 10"
}
},
"node_modules/d3-dsv/node_modules/iconv-lite": {
"version": "0.6.3",
- "license": "MIT",
- "optional": true,
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+ "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3.0.0"
},
@@ -5917,16 +5969,16 @@
},
"node_modules/d3-ease": {
"version": "3.0.1",
- "license": "BSD-3-Clause",
- "optional": true,
+ "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz",
+ "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==",
"engines": {
"node": ">=12"
}
},
"node_modules/d3-fetch": {
"version": "3.0.1",
- "license": "ISC",
- "optional": true,
+ "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz",
+ "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==",
"dependencies": {
"d3-dsv": "1 - 3"
},
@@ -5936,8 +5988,8 @@
},
"node_modules/d3-force": {
"version": "3.0.0",
- "license": "ISC",
- "optional": true,
+ "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz",
+ "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==",
"dependencies": {
"d3-dispatch": "1 - 3",
"d3-quadtree": "1 - 3",
@@ -5949,16 +6001,16 @@
},
"node_modules/d3-format": {
"version": "3.1.0",
- "license": "ISC",
- "optional": true,
+ "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz",
+ "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==",
"engines": {
"node": ">=12"
}
},
"node_modules/d3-geo": {
"version": "3.1.0",
- "license": "ISC",
- "optional": true,
+ "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.0.tgz",
+ "integrity": "sha512-JEo5HxXDdDYXCaWdwLRt79y7giK8SbhZJbFWXqbRTolCHFI5jRqteLzCsq51NKbUoX0PjBVSohxrx+NoOUujYA==",
"dependencies": {
"d3-array": "2.5.0 - 3"
},
@@ -5968,16 +6020,16 @@
},
"node_modules/d3-hierarchy": {
"version": "3.1.2",
- "license": "ISC",
- "optional": true,
+ "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz",
+ "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==",
"engines": {
"node": ">=12"
}
},
"node_modules/d3-interpolate": {
"version": "3.0.1",
- "license": "ISC",
- "optional": true,
+ "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
+ "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==",
"dependencies": {
"d3-color": "1 - 3"
},
@@ -5987,40 +6039,75 @@
},
"node_modules/d3-path": {
"version": "3.1.0",
- "license": "ISC",
- "optional": true,
+ "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz",
+ "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==",
"engines": {
"node": ">=12"
}
},
"node_modules/d3-polygon": {
"version": "3.0.1",
- "license": "ISC",
- "optional": true,
+ "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz",
+ "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==",
"engines": {
"node": ">=12"
}
},
"node_modules/d3-quadtree": {
"version": "3.0.1",
- "license": "ISC",
- "optional": true,
+ "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz",
+ "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==",
"engines": {
"node": ">=12"
}
},
"node_modules/d3-random": {
"version": "3.0.1",
- "license": "ISC",
- "optional": true,
+ "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz",
+ "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==",
"engines": {
"node": ">=12"
}
},
+ "node_modules/d3-sankey": {
+ "version": "0.12.3",
+ "resolved": "https://registry.npmjs.org/d3-sankey/-/d3-sankey-0.12.3.tgz",
+ "integrity": "sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==",
+ "dependencies": {
+ "d3-array": "1 - 2",
+ "d3-shape": "^1.2.0"
+ }
+ },
+ "node_modules/d3-sankey/node_modules/d3-array": {
+ "version": "2.12.1",
+ "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz",
+ "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==",
+ "dependencies": {
+ "internmap": "^1.0.0"
+ }
+ },
+ "node_modules/d3-sankey/node_modules/d3-path": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz",
+ "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg=="
+ },
+ "node_modules/d3-sankey/node_modules/d3-shape": {
+ "version": "1.3.7",
+ "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz",
+ "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==",
+ "dependencies": {
+ "d3-path": "1"
+ }
+ },
+ "node_modules/d3-sankey/node_modules/internmap": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz",
+ "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw=="
+ },
"node_modules/d3-scale": {
"version": "4.0.2",
- "license": "ISC",
- "optional": true,
+ "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz",
+ "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==",
"dependencies": {
"d3-array": "2.10.0 - 3",
"d3-format": "1 - 3",
@@ -6034,8 +6121,8 @@
},
"node_modules/d3-scale-chromatic": {
"version": "3.0.0",
- "license": "ISC",
- "optional": true,
+ "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz",
+ "integrity": "sha512-Lx9thtxAKrO2Pq6OO2Ua474opeziKr279P/TKZsMAhYyNDD3EnCffdbgeSYN5O7m2ByQsxtuP2CSDczNUIZ22g==",
"dependencies": {
"d3-color": "1 - 3",
"d3-interpolate": "1 - 3"
@@ -6046,16 +6133,16 @@
},
"node_modules/d3-selection": {
"version": "3.0.0",
- "license": "ISC",
- "optional": true,
+ "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
+ "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==",
"engines": {
"node": ">=12"
}
},
"node_modules/d3-shape": {
"version": "3.2.0",
- "license": "ISC",
- "optional": true,
+ "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz",
+ "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==",
"dependencies": {
"d3-path": "^3.1.0"
},
@@ -6065,8 +6152,8 @@
},
"node_modules/d3-time": {
"version": "3.1.0",
- "license": "ISC",
- "optional": true,
+ "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz",
+ "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==",
"dependencies": {
"d3-array": "2 - 3"
},
@@ -6076,8 +6163,8 @@
},
"node_modules/d3-time-format": {
"version": "4.1.0",
- "license": "ISC",
- "optional": true,
+ "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz",
+ "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==",
"dependencies": {
"d3-time": "1 - 3"
},
@@ -6087,16 +6174,16 @@
},
"node_modules/d3-timer": {
"version": "3.0.1",
- "license": "ISC",
- "optional": true,
+ "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz",
+ "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==",
"engines": {
"node": ">=12"
}
},
"node_modules/d3-transition": {
"version": "3.0.1",
- "license": "ISC",
- "optional": true,
+ "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz",
+ "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==",
"dependencies": {
"d3-color": "1 - 3",
"d3-dispatch": "1 - 3",
@@ -6113,8 +6200,8 @@
},
"node_modules/d3-zoom": {
"version": "3.0.0",
- "license": "ISC",
- "optional": true,
+ "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz",
+ "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==",
"dependencies": {
"d3-dispatch": "1 - 3",
"d3-drag": "2 - 3",
@@ -6127,9 +6214,9 @@
}
},
"node_modules/dagre-d3-es": {
- "version": "7.0.9",
- "license": "MIT",
- "optional": true,
+ "version": "7.0.10",
+ "resolved": "https://registry.npmjs.org/dagre-d3-es/-/dagre-d3-es-7.0.10.tgz",
+ "integrity": "sha512-qTCQmEhcynucuaZgY5/+ti3X/rnszKZhEQH/ZdWdtP1tA/y3VoHJzcVrO9pjjJCNpigfscAtoUB5ONcd2wNn0A==",
"dependencies": {
"d3": "^7.8.2",
"lodash-es": "^4.17.21"
@@ -6158,12 +6245,10 @@
},
"node_modules/dayjs": {
"version": "1.11.10",
- "license": "MIT",
- "optional": true
+ "license": "MIT"
},
"node_modules/debug": {
"version": "4.3.4",
- "dev": true,
"license": "MIT",
"dependencies": {
"ms": "2.1.2"
@@ -6182,6 +6267,18 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/decode-named-character-reference": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz",
+ "integrity": "sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==",
+ "dependencies": {
+ "character-entities": "^2.0.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
"node_modules/deep-is": {
"version": "0.1.4",
"dev": true,
@@ -6251,8 +6348,8 @@
},
"node_modules/delaunator": {
"version": "5.0.1",
- "license": "ISC",
- "optional": true,
+ "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz",
+ "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==",
"dependencies": {
"robust-predicates": "^3.0.2"
}
@@ -6285,7 +6382,6 @@
},
"node_modules/dequal": {
"version": "2.0.3",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
@@ -6310,6 +6406,14 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/diff": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz",
+ "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==",
+ "engines": {
+ "node": ">=0.3.1"
+ }
+ },
"node_modules/dir-glob": {
"version": "3.0.1",
"dev": true,
@@ -6412,9 +6516,9 @@
}
},
"node_modules/dompurify": {
- "version": "2.4.3",
- "license": "(MPL-2.0 OR Apache-2.0)",
- "optional": true
+ "version": "3.0.9",
+ "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.0.9.tgz",
+ "integrity": "sha512-uyb4NDIvQ3hRn6NiC+SIFaP4mJ/MdXlvtunaqK9Bn6dD3RuB/1S/gasEjDHD8eiaqdSael2vBv+hOs7Y+jhYOQ=="
},
"node_modules/domutils": {
"version": "3.1.0",
@@ -6482,9 +6586,9 @@
"license": "ISC"
},
"node_modules/elkjs": {
- "version": "0.8.2",
- "license": "EPL-2.0",
- "optional": true
+ "version": "0.9.2",
+ "resolved": "https://registry.npmjs.org/elkjs/-/elkjs-0.9.2.tgz",
+ "integrity": "sha512-2Y/RaA1pdgSHpY0YG4TYuYCD2wh97CRvu22eLG3Kz0pgQ/6KbIFTxsTnDc4MH/6hFlg2L/9qXrDMG0nMjP63iw=="
},
"node_modules/emoji-regex": {
"version": "8.0.0",
@@ -8272,8 +8376,7 @@
},
"node_modules/heap": {
"version": "0.2.7",
- "license": "MIT",
- "optional": true
+ "license": "MIT"
},
"node_modules/hosted-git-info": {
"version": "6.1.1",
@@ -8770,8 +8873,8 @@
},
"node_modules/internmap": {
"version": "2.0.3",
- "license": "ISC",
- "optional": true,
+ "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz",
+ "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==",
"engines": {
"node": ">=12"
}
@@ -9751,7 +9854,6 @@
"https://github.com/sponsors/katex"
],
"license": "MIT",
- "optional": true,
"dependencies": {
"commander": "^8.3.0"
},
@@ -9768,8 +9870,7 @@
}
},
"node_modules/khroma": {
- "version": "2.1.0",
- "optional": true
+ "version": "2.1.0"
},
"node_modules/kind-of": {
"version": "6.0.3",
@@ -9779,6 +9880,14 @@
"node": ">=0.10.0"
}
},
+ "node_modules/kleur": {
+ "version": "4.1.5",
+ "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz",
+ "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/klona": {
"version": "2.0.6",
"dev": true,
@@ -9798,8 +9907,7 @@
},
"node_modules/layout-base": {
"version": "1.0.2",
- "license": "MIT",
- "optional": true
+ "license": "MIT"
},
"node_modules/less": {
"version": "4.1.3",
@@ -9978,7 +10086,6 @@
},
"node_modules/lodash": {
"version": "4.17.21",
- "devOptional": true,
"license": "MIT"
},
"node_modules/lodash-es": {
@@ -10335,6 +10442,41 @@
"node": ">= 12"
}
},
+ "node_modules/mdast-util-from-markdown": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-1.3.1.tgz",
+ "integrity": "sha512-4xTO/M8c82qBcnQc1tgpNtubGUW/Y1tBQ1B0i5CtSoelOLKFYlElIr3bvgREYYO5iRqbMY1YuqZng0GVOI8Qww==",
+ "dependencies": {
+ "@types/mdast": "^3.0.0",
+ "@types/unist": "^2.0.0",
+ "decode-named-character-reference": "^1.0.0",
+ "mdast-util-to-string": "^3.1.0",
+ "micromark": "^3.0.0",
+ "micromark-util-decode-numeric-character-reference": "^1.0.0",
+ "micromark-util-decode-string": "^1.0.0",
+ "micromark-util-normalize-identifier": "^1.0.0",
+ "micromark-util-symbol": "^1.0.0",
+ "micromark-util-types": "^1.0.0",
+ "unist-util-stringify-position": "^3.0.0",
+ "uvu": "^0.5.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-to-string": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-3.2.0.tgz",
+ "integrity": "sha512-V4Zn/ncyN1QNSqSBxTrMOLpjr+IKdHl2v3KVLoWmDPscP4r9GcCi71gjgvUV1SFSKh92AjAG4peFuBl2/YgCJg==",
+ "dependencies": {
+ "@types/mdast": "^3.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
"node_modules/media-typer": {
"version": "0.3.0",
"dev": true,
@@ -10373,23 +10515,27 @@
}
},
"node_modules/mermaid": {
- "version": "9.4.3",
- "license": "MIT",
- "optional": true,
- "dependencies": {
- "@braintree/sanitize-url": "^6.0.0",
- "cytoscape": "^3.23.0",
+ "version": "10.9.0",
+ "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-10.9.0.tgz",
+ "integrity": "sha512-swZju0hFox/B/qoLKK0rOxxgh8Cf7rJSfAUc1u8fezVihYMvrJAS45GzAxTVf4Q+xn9uMgitBcmWk7nWGXOs/g==",
+ "dependencies": {
+ "@braintree/sanitize-url": "^6.0.1",
+ "@types/d3-scale": "^4.0.3",
+ "@types/d3-scale-chromatic": "^3.0.0",
+ "cytoscape": "^3.28.1",
"cytoscape-cose-bilkent": "^4.1.0",
- "cytoscape-fcose": "^2.1.0",
"d3": "^7.4.0",
- "dagre-d3-es": "7.0.9",
+ "d3-sankey": "^0.12.3",
+ "dagre-d3-es": "7.0.10",
"dayjs": "^1.11.7",
- "dompurify": "2.4.3",
- "elkjs": "^0.8.2",
+ "dompurify": "^3.0.5",
+ "elkjs": "^0.9.0",
+ "katex": "^0.16.9",
"khroma": "^2.0.0",
"lodash-es": "^4.17.21",
+ "mdast-util-from-markdown": "^1.3.0",
"non-layered-tidy-tree-layout": "^2.0.2",
- "stylis": "^4.1.2",
+ "stylis": "^4.1.3",
"ts-dedent": "^2.2.0",
"uuid": "^9.0.0",
"web-worker": "^1.2.0"
@@ -10403,6 +10549,427 @@
"node": ">= 0.6"
}
},
+ "node_modules/micromark": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/micromark/-/micromark-3.2.0.tgz",
+ "integrity": "sha512-uD66tJj54JLYq0De10AhWycZWGQNUvDI55xPgk2sQM5kn1JYlhbCMTtEeT27+vAhW2FBQxLlOmS3pmA7/2z4aA==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "dependencies": {
+ "@types/debug": "^4.0.0",
+ "debug": "^4.0.0",
+ "decode-named-character-reference": "^1.0.0",
+ "micromark-core-commonmark": "^1.0.1",
+ "micromark-factory-space": "^1.0.0",
+ "micromark-util-character": "^1.0.0",
+ "micromark-util-chunked": "^1.0.0",
+ "micromark-util-combine-extensions": "^1.0.0",
+ "micromark-util-decode-numeric-character-reference": "^1.0.0",
+ "micromark-util-encode": "^1.0.0",
+ "micromark-util-normalize-identifier": "^1.0.0",
+ "micromark-util-resolve-all": "^1.0.0",
+ "micromark-util-sanitize-uri": "^1.0.0",
+ "micromark-util-subtokenize": "^1.0.0",
+ "micromark-util-symbol": "^1.0.0",
+ "micromark-util-types": "^1.0.1",
+ "uvu": "^0.5.0"
+ }
+ },
+ "node_modules/micromark-core-commonmark": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-1.1.0.tgz",
+ "integrity": "sha512-BgHO1aRbolh2hcrzL2d1La37V0Aoz73ymF8rAcKnohLy93titmv62E0gP8Hrx9PKcKrqCZ1BbLGbP3bEhoXYlw==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "dependencies": {
+ "decode-named-character-reference": "^1.0.0",
+ "micromark-factory-destination": "^1.0.0",
+ "micromark-factory-label": "^1.0.0",
+ "micromark-factory-space": "^1.0.0",
+ "micromark-factory-title": "^1.0.0",
+ "micromark-factory-whitespace": "^1.0.0",
+ "micromark-util-character": "^1.0.0",
+ "micromark-util-chunked": "^1.0.0",
+ "micromark-util-classify-character": "^1.0.0",
+ "micromark-util-html-tag-name": "^1.0.0",
+ "micromark-util-normalize-identifier": "^1.0.0",
+ "micromark-util-resolve-all": "^1.0.0",
+ "micromark-util-subtokenize": "^1.0.0",
+ "micromark-util-symbol": "^1.0.0",
+ "micromark-util-types": "^1.0.1",
+ "uvu": "^0.5.0"
+ }
+ },
+ "node_modules/micromark-factory-destination": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-1.1.0.tgz",
+ "integrity": "sha512-XaNDROBgx9SgSChd69pjiGKbV+nfHGDPVYFs5dOoDd7ZnMAE+Cuu91BCpsY8RT2NP9vo/B8pds2VQNCLiu0zhg==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "dependencies": {
+ "micromark-util-character": "^1.0.0",
+ "micromark-util-symbol": "^1.0.0",
+ "micromark-util-types": "^1.0.0"
+ }
+ },
+ "node_modules/micromark-factory-label": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-1.1.0.tgz",
+ "integrity": "sha512-OLtyez4vZo/1NjxGhcpDSbHQ+m0IIGnT8BoPamh+7jVlzLJBH98zzuCoUeMxvM6WsNeh8wx8cKvqLiPHEACn0w==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "dependencies": {
+ "micromark-util-character": "^1.0.0",
+ "micromark-util-symbol": "^1.0.0",
+ "micromark-util-types": "^1.0.0",
+ "uvu": "^0.5.0"
+ }
+ },
+ "node_modules/micromark-factory-space": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-1.1.0.tgz",
+ "integrity": "sha512-cRzEj7c0OL4Mw2v6nwzttyOZe8XY/Z8G0rzmWQZTBi/jjwyw/U4uqKtUORXQrR5bAZZnbTI/feRV/R7hc4jQYQ==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "dependencies": {
+ "micromark-util-character": "^1.0.0",
+ "micromark-util-types": "^1.0.0"
+ }
+ },
+ "node_modules/micromark-factory-title": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-1.1.0.tgz",
+ "integrity": "sha512-J7n9R3vMmgjDOCY8NPw55jiyaQnH5kBdV2/UXCtZIpnHH3P6nHUKaH7XXEYuWwx/xUJcawa8plLBEjMPU24HzQ==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "dependencies": {
+ "micromark-factory-space": "^1.0.0",
+ "micromark-util-character": "^1.0.0",
+ "micromark-util-symbol": "^1.0.0",
+ "micromark-util-types": "^1.0.0"
+ }
+ },
+ "node_modules/micromark-factory-whitespace": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-1.1.0.tgz",
+ "integrity": "sha512-v2WlmiymVSp5oMg+1Q0N1Lxmt6pMhIHD457whWM7/GUlEks1hI9xj5w3zbc4uuMKXGisksZk8DzP2UyGbGqNsQ==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "dependencies": {
+ "micromark-factory-space": "^1.0.0",
+ "micromark-util-character": "^1.0.0",
+ "micromark-util-symbol": "^1.0.0",
+ "micromark-util-types": "^1.0.0"
+ }
+ },
+ "node_modules/micromark-util-character": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-1.2.0.tgz",
+ "integrity": "sha512-lXraTwcX3yH/vMDaFWCQJP1uIszLVebzUa3ZHdrgxr7KEU/9mL4mVgCpGbyhvNLNlauROiNUq7WN5u7ndbY6xg==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "dependencies": {
+ "micromark-util-symbol": "^1.0.0",
+ "micromark-util-types": "^1.0.0"
+ }
+ },
+ "node_modules/micromark-util-chunked": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-1.1.0.tgz",
+ "integrity": "sha512-Ye01HXpkZPNcV6FiyoW2fGZDUw4Yc7vT0E9Sad83+bEDiCJ1uXu0S3mr8WLpsz3HaG3x2q0HM6CTuPdcZcluFQ==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "dependencies": {
+ "micromark-util-symbol": "^1.0.0"
+ }
+ },
+ "node_modules/micromark-util-classify-character": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-1.1.0.tgz",
+ "integrity": "sha512-SL0wLxtKSnklKSUplok1WQFoGhUdWYKggKUiqhX+Swala+BtptGCu5iPRc+xvzJ4PXE/hwM3FNXsfEVgoZsWbw==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "dependencies": {
+ "micromark-util-character": "^1.0.0",
+ "micromark-util-symbol": "^1.0.0",
+ "micromark-util-types": "^1.0.0"
+ }
+ },
+ "node_modules/micromark-util-combine-extensions": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-1.1.0.tgz",
+ "integrity": "sha512-Q20sp4mfNf9yEqDL50WwuWZHUrCO4fEyeDCnMGmG5Pr0Cz15Uo7KBs6jq+dq0EgX4DPwwrh9m0X+zPV1ypFvUA==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "dependencies": {
+ "micromark-util-chunked": "^1.0.0",
+ "micromark-util-types": "^1.0.0"
+ }
+ },
+ "node_modules/micromark-util-decode-numeric-character-reference": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-1.1.0.tgz",
+ "integrity": "sha512-m9V0ExGv0jB1OT21mrWcuf4QhP46pH1KkfWy9ZEezqHKAxkj4mPCy3nIH1rkbdMlChLHX531eOrymlwyZIf2iw==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "dependencies": {
+ "micromark-util-symbol": "^1.0.0"
+ }
+ },
+ "node_modules/micromark-util-decode-string": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-1.1.0.tgz",
+ "integrity": "sha512-YphLGCK8gM1tG1bd54azwyrQRjCFcmgj2S2GoJDNnh4vYtnL38JS8M4gpxzOPNyHdNEpheyWXCTnnTDY3N+NVQ==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "dependencies": {
+ "decode-named-character-reference": "^1.0.0",
+ "micromark-util-character": "^1.0.0",
+ "micromark-util-decode-numeric-character-reference": "^1.0.0",
+ "micromark-util-symbol": "^1.0.0"
+ }
+ },
+ "node_modules/micromark-util-encode": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-1.1.0.tgz",
+ "integrity": "sha512-EuEzTWSTAj9PA5GOAs992GzNh2dGQO52UvAbtSOMvXTxv3Criqb6IOzJUBCmEqrrXSblJIJBbFFv6zPxpreiJw==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ]
+ },
+ "node_modules/micromark-util-html-tag-name": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-1.2.0.tgz",
+ "integrity": "sha512-VTQzcuQgFUD7yYztuQFKXT49KghjtETQ+Wv/zUjGSGBioZnkA4P1XXZPT1FHeJA6RwRXSF47yvJ1tsJdoxwO+Q==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ]
+ },
+ "node_modules/micromark-util-normalize-identifier": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-1.1.0.tgz",
+ "integrity": "sha512-N+w5vhqrBihhjdpM8+5Xsxy71QWqGn7HYNUvch71iV2PM7+E3uWGox1Qp90loa1ephtCxG2ftRV/Conitc6P2Q==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "dependencies": {
+ "micromark-util-symbol": "^1.0.0"
+ }
+ },
+ "node_modules/micromark-util-resolve-all": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-1.1.0.tgz",
+ "integrity": "sha512-b/G6BTMSg+bX+xVCshPTPyAu2tmA0E4X98NSR7eIbeC6ycCqCeE7wjfDIgzEbkzdEVJXRtOG4FbEm/uGbCRouA==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "dependencies": {
+ "micromark-util-types": "^1.0.0"
+ }
+ },
+ "node_modules/micromark-util-sanitize-uri": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.2.0.tgz",
+ "integrity": "sha512-QO4GXv0XZfWey4pYFndLUKEAktKkG5kZTdUNaTAkzbuJxn2tNBOr+QtxR2XpWaMhbImT2dPzyLrPXLlPhph34A==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "dependencies": {
+ "micromark-util-character": "^1.0.0",
+ "micromark-util-encode": "^1.0.0",
+ "micromark-util-symbol": "^1.0.0"
+ }
+ },
+ "node_modules/micromark-util-subtokenize": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-1.1.0.tgz",
+ "integrity": "sha512-kUQHyzRoxvZO2PuLzMt2P/dwVsTiivCK8icYTeR+3WgbuPqfHgPPy7nFKbeqRivBvn/3N3GBiNC+JRTMSxEC7A==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "dependencies": {
+ "micromark-util-chunked": "^1.0.0",
+ "micromark-util-symbol": "^1.0.0",
+ "micromark-util-types": "^1.0.0",
+ "uvu": "^0.5.0"
+ }
+ },
+ "node_modules/micromark-util-symbol": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-1.1.0.tgz",
+ "integrity": "sha512-uEjpEYY6KMs1g7QfJ2eX1SQEV+ZT4rUD3UcF6l57acZvLNK7PBZL+ty82Z1qhK1/yXIY4bdx04FKMgR0g4IAag==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ]
+ },
+ "node_modules/micromark-util-types": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-1.1.0.tgz",
+ "integrity": "sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ]
+ },
"node_modules/micromatch": {
"version": "4.0.5",
"dev": true,
@@ -10725,6 +11292,14 @@
"node": "*"
}
},
+ "node_modules/mri": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz",
+ "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==",
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/mrmime": {
"version": "1.0.1",
"dev": true,
@@ -10735,7 +11310,6 @@
},
"node_modules/ms": {
"version": "2.1.2",
- "dev": true,
"license": "MIT"
},
"node_modules/multicast-dns": {
@@ -10888,6 +11462,52 @@
"zone.js": "~0.13.0"
}
},
+ "node_modules/ngx-markdown/node_modules/dagre-d3-es": {
+ "version": "7.0.9",
+ "resolved": "https://registry.npmjs.org/dagre-d3-es/-/dagre-d3-es-7.0.9.tgz",
+ "integrity": "sha512-rYR4QfVmy+sR44IBDvVtcAmOReGBvRCWDpO2QjYwqgh9yijw6eSHBqaPG/LIOEy7aBsniLvtMW6pg19qJhq60w==",
+ "optional": true,
+ "dependencies": {
+ "d3": "^7.8.2",
+ "lodash-es": "^4.17.21"
+ }
+ },
+ "node_modules/ngx-markdown/node_modules/dompurify": {
+ "version": "2.4.3",
+ "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.4.3.tgz",
+ "integrity": "sha512-q6QaLcakcRjebxjg8/+NP+h0rPfatOgOzc46Fst9VAA3jF2ApfKBNKMzdP4DYTqtUMXSCd5pRS/8Po/OmoCHZQ==",
+ "optional": true
+ },
+ "node_modules/ngx-markdown/node_modules/elkjs": {
+ "version": "0.8.2",
+ "resolved": "https://registry.npmjs.org/elkjs/-/elkjs-0.8.2.tgz",
+ "integrity": "sha512-L6uRgvZTH+4OF5NE/MBbzQx/WYpru1xCBE9respNj6qznEewGUIfhzmm7horWWxbNO2M0WckQypGctR8lH79xQ==",
+ "optional": true
+ },
+ "node_modules/ngx-markdown/node_modules/mermaid": {
+ "version": "9.4.3",
+ "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-9.4.3.tgz",
+ "integrity": "sha512-TLkQEtqhRSuEHSE34lh5bCa94KATCyluAXmFnNI2PRZwOpXFeqiJWwZl+d2CcemE1RS6QbbueSSq9QIg8Uxcyw==",
+ "optional": true,
+ "dependencies": {
+ "@braintree/sanitize-url": "^6.0.0",
+ "cytoscape": "^3.23.0",
+ "cytoscape-cose-bilkent": "^4.1.0",
+ "cytoscape-fcose": "^2.1.0",
+ "d3": "^7.4.0",
+ "dagre-d3-es": "7.0.9",
+ "dayjs": "^1.11.7",
+ "dompurify": "2.4.3",
+ "elkjs": "^0.8.2",
+ "khroma": "^2.0.0",
+ "lodash-es": "^4.17.21",
+ "non-layered-tidy-tree-layout": "^2.0.2",
+ "stylis": "^4.1.2",
+ "ts-dedent": "^2.2.0",
+ "uuid": "^9.0.0",
+ "web-worker": "^1.2.0"
+ }
+ },
"node_modules/node-addon-api": {
"version": "3.2.1",
"dev": true,
@@ -10942,8 +11562,7 @@
},
"node_modules/non-layered-tidy-tree-layout": {
"version": "2.0.2",
- "license": "MIT",
- "optional": true
+ "license": "MIT"
},
"node_modules/nopt": {
"version": "6.0.0",
@@ -12691,8 +13310,8 @@
},
"node_modules/robust-predicates": {
"version": "3.0.2",
- "license": "Unlicense",
- "optional": true
+ "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz",
+ "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg=="
},
"node_modules/rollup": {
"version": "3.29.4",
@@ -12741,8 +13360,8 @@
},
"node_modules/rw": {
"version": "1.3.3",
- "license": "BSD-3-Clause",
- "optional": true
+ "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz",
+ "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ=="
},
"node_modules/rxjs": {
"version": "7.8.1",
@@ -12751,6 +13370,17 @@
"tslib": "^2.1.0"
}
},
+ "node_modules/sade": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz",
+ "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==",
+ "dependencies": {
+ "mri": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/safe-array-concat": {
"version": "1.1.0",
"dev": true,
@@ -12805,7 +13435,6 @@
},
"node_modules/safer-buffer": {
"version": "2.1.2",
- "devOptional": true,
"license": "MIT"
},
"node_modules/sass": {
@@ -13754,8 +14383,7 @@
},
"node_modules/stylis": {
"version": "4.3.1",
- "license": "MIT",
- "optional": true
+ "license": "MIT"
},
"node_modules/supports-color": {
"version": "5.5.0",
@@ -14112,7 +14740,6 @@
"node_modules/ts-dedent": {
"version": "2.2.0",
"license": "MIT",
- "optional": true,
"engines": {
"node": ">=6.10"
}
@@ -14474,6 +15101,18 @@
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
}
},
+ "node_modules/unist-util-stringify-position": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz",
+ "integrity": "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==",
+ "dependencies": {
+ "@types/unist": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
"node_modules/universalify": {
"version": "2.0.1",
"dev": true,
@@ -14556,11 +15195,27 @@
"https://github.com/sponsors/ctavan"
],
"license": "MIT",
- "optional": true,
"bin": {
"uuid": "dist/bin/uuid"
}
},
+ "node_modules/uvu": {
+ "version": "0.5.6",
+ "resolved": "https://registry.npmjs.org/uvu/-/uvu-0.5.6.tgz",
+ "integrity": "sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==",
+ "dependencies": {
+ "dequal": "^2.0.0",
+ "diff": "^5.0.0",
+ "kleur": "^4.0.3",
+ "sade": "^1.7.3"
+ },
+ "bin": {
+ "uvu": "bin.js"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/v8-compile-cache": {
"version": "2.3.0",
"dev": true,
@@ -14660,8 +15315,7 @@
},
"node_modules/web-worker": {
"version": "1.3.0",
- "license": "Apache-2.0",
- "optional": true
+ "license": "Apache-2.0"
},
"node_modules/webidl-conversions": {
"version": "6.1.0",
diff --git a/package.json b/package.json
index 7577da07..e91eb764 100644
--- a/package.json
+++ b/package.json
@@ -36,6 +36,7 @@
"chartjs-plugin-datalabels": "^2.1.0",
"font-awesome": "^4.7.0",
"marked": "^4.3.0",
+ "mermaid": "^10.6.0",
"moment": "^2.29.4",
"ng2-charts": "^4.0.0",
"ng2-dragula": "^5.0.0",
diff --git a/src/app/step/hf-markdown.component.ts b/src/app/step/hf-markdown.component.ts
index a14deec7..3253da4f 100644
--- a/src/app/step/hf-markdown.component.ts
+++ b/src/app/step/hf-markdown.component.ts
@@ -1,7 +1,23 @@
import { Component, Input, OnChanges } from '@angular/core';
import { MarkdownService } from 'ngx-markdown';
-import { VirtualMachine as VM } from '../data/virtualmachine';
import { CtrService } from '../data/ctr.service';
+import { VirtualMachine as VM } from '../data/virtualmachine';
+
+import Prism from 'prismjs';
+import mermaid from 'mermaid';
+// Load desired languages
+// TODO: Import all available languages
+import 'prismjs/components/prism-css';
+import 'prismjs/components/prism-javascript';
+import 'prismjs/components/prism-java';
+import 'prismjs/components/prism-markup';
+import 'prismjs/components/prism-typescript';
+import 'prismjs/components/prism-sass';
+import 'prismjs/components/prism-scss';
+import 'prismjs/components/prism-go';
+import 'prismjs/components/prism-docker';
+import 'prismjs/components/prism-python';
+import 'prismjs/components/prism-yaml';
// Replacement for lodash's escape
const escape = (s: string) =>
@@ -31,8 +47,11 @@ export class HfMarkdownComponent implements OnChanges {
constructor(
public markdownService: MarkdownService,
- private ctrService: CtrService
+ private ctrService: CtrService,
) {
+ mermaid.initialize({
+ startOnLoad: false,
+ });
this.markdownService.renderer.code = (code: string, language = '') => {
const [tag, ...args] = language.split(':');
if (tag in this.taggedCodeRenderers) {
@@ -103,8 +122,7 @@ export class HfMarkdownComponent implements OnChanges {
const filename = parts[parts.length - 1];
const n = 5; //Length of randomized token
// Using only EOF as a token can cause trouble when the token is inside the file content. Let's use EOL together with a random string
- const token =
- 'EOF_' + (Math.random().toString(36) + '0000').slice(2, n + 2);
+ const token = 'EOF_' + this.uniqueString(n);
const fileContent = `cat << ${token} > ${filepath}
${code}
${token}`;
@@ -116,19 +134,46 @@ ${token}`;
title="Click to create ${filepath} on ${target}"
>${this.renderHighlightedCode(code, language, filename)}`;
},
+
+ mermaid(code: string) {
+ const n = 5;
+ const containerId = `mermaid-${this.uniqueString(n)}`;
+ // Start the async rendering process
+ setTimeout(() => this.renderMermaidGraph(code, containerId), 0);
+ // Return a placeholder with the unique ID
+ return `
Loading mermaid graph...
`;
+ },
};
private renderHighlightedCode(
code: string,
language: string,
- fileName?: string
+ fileName?: string,
) {
const fileNameTag = fileName
? `${fileName}
`
: `${language}
`;
- const classAttr = `class="language-${language}"`;
- const codeNode = `${escape(code)}
`;
- return `${fileNameTag}${codeNode}
`;
+ const classAttr = `language-${language}`;
+
+ if (Prism.languages[language]) {
+ code = Prism.highlight(code, Prism.languages[language], language);
+ }
+
+ return `${fileNameTag}${code}
`;
+ }
+
+ private renderMermaidGraph(code: string, containerId: string) {
+ mermaid
+ .render('svg-' + containerId, code)
+ .then((renderResult) => {
+ const container = document.getElementById(containerId);
+ if (container) {
+ container.innerHTML = renderResult.svg;
+ }
+ })
+ .catch((error) => {
+ console.error('Mermaid rendering failed:', error);
+ });
}
private renderNestedPlainCode(code: string) {
@@ -175,21 +220,27 @@ ${token}`;
const contentWithReplacedTokens = this.replaceSessionToken(
this.replaceVmInfoTokens(this.content),
);
- // the compile method internally uses the Angular Dom Sanitizer and is therefore safe to use
- this.processedContent = this.markdownService.parse(contentWithReplacedTokens);
+ // the parse method internally uses the Angular Dom Sanitizer and is therefore safe to use
+ this.processedContent = this.markdownService.parse(
+ contentWithReplacedTokens,
+ );
}
private replaceVmInfoTokens(content: string) {
- return content?.replace(
+ return content.replace(
/\$\{vminfo:([^:]*):([^}]*)\}/g,
(match, vmName, propName) => {
const vm = this.context.vmInfo?.[vmName.toLowerCase()];
return String(vm?.[propName as keyof VM] ?? match);
- }
+ },
);
}
private replaceSessionToken(content: string) {
- return content?.replace(/\$\{session\}/g, this.context.session);
+ return content.replace(/\$\{session\}/g, this.context.session);
+ }
+
+ private uniqueString(n: number) {
+ return `${(Math.random().toString(36) + '0000').slice(2, n + 2)}`;
}
}
From 8eb82283098e0d1f3eb0e18832023ed0a3919a5c Mon Sep 17 00:00:00 2001
From: maxsva <110593497+maxsva@users.noreply.github.com>
Date: Fri, 8 Mar 2024 15:41:52 +0100
Subject: [PATCH 2/6] configuration fix new VMTemplate create (#200)
Co-authored-by: Maksym Veres
---
.../edit-vmtemplate.component.html | 100 +++++++++++-------
.../edit-vmtemplate.component.ts | 4 +-
2 files changed, 64 insertions(+), 40 deletions(-)
diff --git a/src/app/configuration/vmtemplates/edit-vmtemplate/edit-vmtemplate.component.html b/src/app/configuration/vmtemplates/edit-vmtemplate/edit-vmtemplate.component.html
index a8c8baf7..9cf52726 100644
--- a/src/app/configuration/vmtemplates/edit-vmtemplate/edit-vmtemplate.component.html
+++ b/src/app/configuration/vmtemplates/edit-vmtemplate/edit-vmtemplate.component.html
@@ -86,22 +86,35 @@ Basic Information
-
- Name |
- {{ template.name }} |
-
- {{ uneditedTemplate.name }}
- {{ template.name }}
- |
-
-
- Image |
- {{ template.image }} |
-
- {{ uneditedTemplate.image }}
- {{ template.image }}
- |
-
+
+
+ Name |
+ {{ template.name }} |
+
+ {{ uneditedTemplate.name }}
+ {{ template.name }}
+ |
+
+
+ Image |
+ {{ template.image }} |
+
+ {{ uneditedTemplate.image }}
+ {{ template.image }}
+ |
+
+
+
+
+ Name |
+ {{ template.name }} |
+
+
+ Image |
+ {{ template.image }} |
+
+
+
@@ -147,31 +160,40 @@ Cloud Config
-
-
- {{ item.key }} |
- {{ item.value }} |
-
-
- {{ item.key }} |
- {{ item.value }} |
-
-
-
- {{ uneditedTemplate.config_map[item.key] }}
- {{ item.value }}
- |
-
+
+
+
+ {{ item.key }} |
+ {{ item.value }} |
+
+
+ {{ item.key }} |
+ {{ item.value }} |
+
+
+
+ {{ uneditedTemplate.config_map[item.key] }}
+ {{ item.value }}
+ |
+
+
+ {{ item.key }} |
+ {{ item.value }} |
+
-
-
-
-
- {{ item.key }} |
- {{ item.value }} |
-
-
+
+
+
+
+
+ {{ item.key }} |
+ {{ item.value }} |
+
+
+
+
+
diff --git a/src/app/configuration/vmtemplates/edit-vmtemplate/edit-vmtemplate.component.ts b/src/app/configuration/vmtemplates/edit-vmtemplate/edit-vmtemplate.component.ts
index d1b47dd1..83893fbf 100644
--- a/src/app/configuration/vmtemplates/edit-vmtemplate/edit-vmtemplate.component.ts
+++ b/src/app/configuration/vmtemplates/edit-vmtemplate/edit-vmtemplate.component.ts
@@ -61,7 +61,7 @@ export class EditVmtemplateComponent implements OnInit, OnChanges {
) {}
ngOnInit(): void {
- this._build();
+ this._build();
}
@ViewChild('wizard', { static: true }) wizard: ClrWizard;
@@ -242,4 +242,6 @@ export class EditVmtemplateComponent implements OnInit, OnChanges {
}
this.uneditedTemplate = JSON.parse(JSON.stringify(this.template));
}
+
}
+
From 430a434e49b61060445e04edb4fdc499347b71fc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan-Gerrit=20G=C3=B6bel?=
<86782124+jggoebel@users.noreply.github.com>
Date: Fri, 8 Mar 2024 15:45:11 +0100
Subject: [PATCH 3/6] Add scopes to configuration menu (#203)
* Add scopes to menu
* remove logs
---
src/app/app-routing.module.ts | 76 ++++++++-----------
.../configuration.component.html | 26 +++++--
.../configuration/configuration.component.ts | 32 ++++++--
.../edit-environment.component.ts | 1 -
.../environment-detail.component.ts | 1 -
.../settings/settings.component.html | 76 ++++++-------------
.../settings/settings.component.ts | 39 ++++++++--
src/app/content/content.component.ts | 2 +-
.../course-wizard/course-wizard.component.ts | 1 -
9 files changed, 134 insertions(+), 120 deletions(-)
diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts
index e8f4bf31..09ce80b4 100644
--- a/src/app/app-routing.module.ts
+++ b/src/app/app-routing.module.ts
@@ -17,93 +17,85 @@ import { StepComponent } from './step/step-component/step.component';
import { TerminalComponent } from './step/terminal/terminal.component';
import { RolesComponent } from './configuration/roles/roles/roles.component';
import { SessionStatisticsComponent } from './session-statistics/session-statistics.component';
-import {SettingsComponent} from './configuration/settings/settings.component';
+import { SettingsComponent } from './configuration/settings/settings.component';
import { DashboardDetailsComponent } from './dashboards/dashboard-details/dashboard-details.component';
const routes: Routes = [
- {path: '', redirectTo: '/home', pathMatch: 'full'},
- {path: 'login', component: LoginComponent},
+ { path: '', redirectTo: '/home', pathMatch: 'full' },
+ { path: 'login', component: LoginComponent },
{
path: 'home',
component: HomeComponent,
- canActivate: [
- AuthGuard
- ],
+ canActivate: [AuthGuard],
children: [
{
path: 'statistics/sessions',
- component: SessionStatisticsComponent
- }
- ]
+ component: SessionStatisticsComponent,
+ },
+ ],
},
{
path: 'dashboards',
component: DashboardsComponent,
- canActivate: [
- AuthGuard
- ],
+ canActivate: [AuthGuard],
children: [
{
path: 'event/:id',
- component: DashboardDetailsComponent
- }
- ]
+ component: DashboardDetailsComponent,
+ },
+ ],
},
{
path: 'events',
component: EventComponent,
- canActivate: [
- AuthGuard
- ]
+ canActivate: [AuthGuard],
},
{
path: 'content',
component: ContentComponent,
- canActivate: [
- AuthGuard
- ],
+ canActivate: [AuthGuard],
children: [
{
path: 'scenarios',
- component: ScenarioComponent
+ component: ScenarioComponent,
},
{
path: 'courses',
- component: CourseComponent
- }
- ]
+ component: CourseComponent,
+ },
+ ],
},
{
path: 'users',
component: UserComponent,
- canActivate: [
- AuthGuard
- ]
+ canActivate: [AuthGuard],
},
{
path: 'configuration',
component: ConfigurationComponent,
- canActivate: [
- AuthGuard
- ],
+ canActivate: [AuthGuard],
children: [
+ {
+ path: 'settings/:scope',
+ component: SettingsComponent,
+ },
{
path: 'settings',
- component: SettingsComponent
+ component: SettingsComponent,
},
{
path: 'environments',
- component: EnvironmentsComponent
+ component: EnvironmentsComponent,
},
{
path: 'vmtemplates',
- component: VmtemplatesComponent
+ component: VmtemplatesComponent,
},
{
path: 'roles',
- component: RolesComponent
- }
- ]
+ component: RolesComponent,
+ },
+ ],
},
{
path: 'session/:session/steps/:step',
@@ -113,14 +105,12 @@ const routes: Routes = [
{
path: 'scenario/:scenario/printable',
component: PrintableComponent,
- canActivate: [
- AuthGuard
- ]
- }
+ canActivate: [AuthGuard],
+ },
];
@NgModule({
imports: [RouterModule.forRoot(routes, {})],
- exports: [RouterModule]
+ exports: [RouterModule],
})
-export class AppRoutingModule { }
\ No newline at end of file
+export class AppRoutingModule {}
diff --git a/src/app/configuration/configuration.component.html b/src/app/configuration/configuration.component.html
index 453ff1d6..d6409d1b 100644
--- a/src/app/configuration/configuration.component.html
+++ b/src/app/configuration/configuration.component.html
@@ -2,13 +2,6 @@
- Settings
Roles
+
+
+
+ Settings
+
+
+ {{ scope.displayName }}
+
+
+
diff --git a/src/app/configuration/configuration.component.ts b/src/app/configuration/configuration.component.ts
index 3bf3d97e..0dfcd654 100644
--- a/src/app/configuration/configuration.component.ts
+++ b/src/app/configuration/configuration.component.ts
@@ -1,6 +1,10 @@
import { Component, OnInit } from '@angular/core';
import { RbacService } from '../data/rbac.service';
import { Router } from '@angular/router';
+import {
+ PreparedScope,
+ TypedSettingsService,
+} from '../data/typedSettings.service';
@Component({
selector: 'app-configuration',
@@ -12,7 +16,15 @@ export class ConfigurationComponent implements OnInit {
public listVMTemplates = false;
public listRoles = false;
- constructor(private rbacService: RbacService, private router: Router) {}
+ public scopes: PreparedScope[] = [];
+ public scopesLoading: boolean = true;
+ public expandedSettingsGroup = true;
+
+ constructor(
+ private rbacService: RbacService,
+ private router: Router,
+ private typedSettingsService: TypedSettingsService
+ ) {}
ngOnInit() {
const authorizationRequests = Promise.all([
@@ -31,15 +43,19 @@ export class ConfigurationComponent implements OnInit {
this.listRoles = permissions[4];
if (this.showSettings) {
- this.router.navigateByUrl(`/configuration/settings`);
- } else if (this.listEnvironments) {
- this.router.navigateByUrl(`/configuration/environments`);
- } else if (this.listVMTemplates) {
- this.router.navigateByUrl(`/configuration/vmtemplates`);
- } else if (this.listRoles) {
- this.router.navigateByUrl(`/configuration/roles`);
+ this.getScopes();
}
}
);
}
+
+ getScopes() {
+ this.scopes = [];
+ this.typedSettingsService.listScopes().subscribe({
+ next: (scopes: PreparedScope[]) => {
+ this.scopes = scopes;
+ this.scopesLoading = false;
+ },
+ });
+ }
}
diff --git a/src/app/configuration/environments/edit-environment/edit-environment.component.ts b/src/app/configuration/environments/edit-environment/edit-environment.component.ts
index 6871e64f..641caabd 100644
--- a/src/app/configuration/environments/edit-environment/edit-environment.component.ts
+++ b/src/app/configuration/environments/edit-environment/edit-environment.component.ts
@@ -81,7 +81,6 @@ export class EditEnvironmentComponent implements OnInit, OnChanges {
.Grants('virtualmachinetemplates', 'list')
.then((allowVMTemplateList: boolean) => {
if (!allowVMTemplateList) {
- console.log('Disallow');
return;
}
vmTemplateService
diff --git a/src/app/configuration/environments/environment-detail/environment-detail.component.ts b/src/app/configuration/environments/environment-detail/environment-detail.component.ts
index 79aae051..8df7f788 100644
--- a/src/app/configuration/environments/environment-detail/environment-detail.component.ts
+++ b/src/app/configuration/environments/environment-detail/environment-detail.component.ts
@@ -29,7 +29,6 @@ export class EnvironmentDetailComponent implements OnInit {
.Grants('virtualmachinetemplates', 'list')
.then((allowVMTemplateList: boolean) => {
if (!allowVMTemplateList) {
- console.log("Disallow")
return;
}
vmTemplateService
diff --git a/src/app/configuration/settings/settings.component.html b/src/app/configuration/settings/settings.component.html
index a74ca3c4..c39684e2 100644
--- a/src/app/configuration/settings/settings.component.html
+++ b/src/app/configuration/settings/settings.component.html
@@ -2,64 +2,34 @@
Settings
- {{ this.selectedScope?.displayName ?? "scope" }}
+ {{
+ this.selectedScope?.displayName ?? "scope"
+ }}
-
-
+
+
+
+
Please wait...
- Scopes are being loaded...
+ Settings are being loaded...
-
-
-
-
-
-
-
- {{ sc.displayName }}
-
-
-
-
-
-
- Please wait...
- Settings are being loaded...
-
-
-
- 0"
- [typedInputs]="settings"
- (syncedInputs)="onFormChange($event)"
- (inputsValid)="changeFormValidity($event)"
- [groupType]="FormGroupType.TABS"
- >
-
- No settings available for scope
- {{ this.selectedScope.displayName }}
.
-
-
+
+ 0"
+ [typedInputs]="settings"
+ (syncedInputs)="onFormChange($event)"
+ (inputsValid)="changeFormValidity($event)"
+ [groupType]="FormGroupType.TABS"
+ >
+
+ No settings available for scope
+ {{ this.selectedScope.displayName }}
.
+
diff --git a/src/app/configuration/settings/settings.component.ts b/src/app/configuration/settings/settings.component.ts
index 7c19fccc..12f3cde9 100644
--- a/src/app/configuration/settings/settings.component.ts
+++ b/src/app/configuration/settings/settings.component.ts
@@ -1,4 +1,4 @@
-import { Component, ViewChild } from '@angular/core';
+import { Component, OnChanges, OnInit, ViewChild } from '@angular/core';
import { TypedInput, FormGroupType } from '../../typed-form/TypedInput';
import {
PreparedScope,
@@ -6,6 +6,7 @@ import {
} from 'src/app/data/typedSettings.service';
import { AlertComponent } from 'src/app/alert/alert.component';
import { ServerResponse } from 'src/app/step/ServerResponse';
+import { ActivatedRoute, NavigationEnd, Router } from '@angular/router';
@Component({
selector: 'app-settings',
@@ -27,9 +28,19 @@ export class SettingsComponent {
private alertTime = 2000;
private alertErrorTime = 10000;
+ public alertClosed: boolean = true;
- constructor(public typedSettingsService: TypedSettingsService) {
+ constructor(
+ public typedSettingsService: TypedSettingsService,
+ private route: ActivatedRoute,
+ private router: Router
+ ) {
this.getScopes();
+ this.router.events.subscribe((val) => {
+ if (val instanceof NavigationEnd) {
+ this.testPath();
+ }
+ });
}
onFormChange(data: TypedInput[]) {
@@ -45,10 +56,8 @@ export class SettingsComponent {
if (!this.updatedSettings) {
return;
}
- console.log(this.updatedSettings);
this.typedSettingsService.updateCollection(this.updatedSettings).subscribe({
next: (resp: ServerResponse) => {
- console.log(resp);
this.hasChanges = false;
this.alert.success(
'Settings successfully saved',
@@ -82,11 +91,31 @@ export class SettingsComponent {
next: (scopes: PreparedScope[]) => {
this.scopes = scopes;
this.scopesLoading = false;
- this.setScope(this.scopes[0]);
+ this.testPath();
},
error: (err) => {
this.alert.danger(err.error.message, true, this.alertErrorTime);
},
});
}
+
+ testPath() {
+ const { paramMap } = this.route.snapshot;
+ const scope = paramMap.get('scope')!;
+ if (this.scopes.length < 1) {
+ return;
+ }
+
+ if (scope != '') {
+ const findScope = this.scopes.filter((a) => {
+ return a.name == scope;
+ });
+
+ if (findScope && findScope[0]) {
+ this.setScope(findScope[0]);
+ }
+ } else {
+ this.setScope(this.scopes[0]);
+ }
+ }
}
diff --git a/src/app/content/content.component.ts b/src/app/content/content.component.ts
index 03edfd5b..70dd8144 100644
--- a/src/app/content/content.component.ts
+++ b/src/app/content/content.component.ts
@@ -20,7 +20,7 @@ export class ContentComponent implements OnInit {
ngOnInit(): void {
this.contentNavigation();
}
- ngOnChanges(changes: SimpleChanges): void {
+ ngOnChanges(): void {
this.contentNavigation();
}
diff --git a/src/app/course/course-wizard/course-wizard.component.ts b/src/app/course/course-wizard/course-wizard.component.ts
index 955ae6e4..b4d17479 100644
--- a/src/app/course/course-wizard/course-wizard.component.ts
+++ b/src/app/course/course-wizard/course-wizard.component.ts
@@ -214,7 +214,6 @@ export class CourseWizardComponent implements OnChanges, OnInit {
}
setVM(vms: {}[]) {
- console.log("vms = " + vms)
this.editVirtualMachines = vms;
this.VMSAllow();
this.setModified();
From e0586ad32f1e60c21609b9c8baddab7f3507b946 Mon Sep 17 00:00:00 2001
From: Abdellah Brahimi <119412567+abrahimi93@users.noreply.github.com>
Date: Tue, 12 Mar 2024 17:00:43 +0100
Subject: [PATCH 4/6] Refactor Scenario Modal to use a Wizard (#177)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* Replace New Scenario workflow with Wizard with 3 steps instead of modal
* Saving some commit
* increment some changes
* Making new functionalities
* Validation pattern for Input when creating a new scenario that validate only latin letter and number strings
* Fixing the bug issue #327
* Refactoring Scenario
Replacing modal for creating scenario by a Step by step Wizard
* Create a button to edit the available Scenario by Wizard
* Fixing Bug mention in the issue #327
* Adding the functionality for deleting Scenario
* Change var to const in scenario.component and scenerio.service
* Fixing the step when adding VM to scenario during the creation of the Scenario,
* Fixing the bug with Step Scenario, and quality code.
* Fixing some bugs, and changing style
fixing the bug with step, and enlarging datagrid to dominate the whole screen
* Adding Virtual Machine in stepNav in Edit Scenario wizard
* Checking all Set of VM if they have VM
* Checking all Set of VM if they have VM
* Checking all Set of VM if they have VM
* Checking all Set of VM if they have VM
* refactoring Scenario, creating Scenario-Wizard component
* Correcting Edit course to Edit Scenario in Scenario-wizard
* Prettify the code
* add Scenario-detail component to the scenario component
* create steps-scenario component
* Fixing the bug with Steps Component, step content now will retain its default value after it was cancelled.
* fixing the bug with step content
* Fixing the alert notification when creating, updating or deleting scenario. Fixing a bug in Step-Scenario component
* Giving access to delete and edit to user that have the persmission.
* Adding an error alert for Scenario details to emit to parent component Scenario
* Fixing caching with filtered-scenario when choosing category in Scenario component
* fixing bug with scenario component with error emitting from scenario details.
* Fixing some bugs
* Fixing bug
* Fixing the issue with Steps
* optimize code in step
* Fix deprecated subscription syntax
* Refactoring: Use alert component & rm unused code
* Some more refactoring
* Prevent warning that form is not connected to button
---------
Co-authored-by: Jan-Gerrit Göbel <86782124+jggoebel@users.noreply.github.com>
Co-authored-by: philipab
---
src/app/alert/alert.component.ts | 2 +-
src/app/alert/alert.ts | 8 +
src/app/app.module.ts | 6 +
src/app/content/content.component.ts | 6 +-
src/app/data/scenario.service.ts | 17 +-
.../filter-scenarios.component.ts | 8 +
.../scenario-detail.component.html | 60 ++
.../scenario-detail.component.scss | 0
.../scenario-detail.component.ts | 29 +
.../scenario-wizard.component.html | 489 ++++++++++++
.../scenario-wizard.component.scss | 0
.../scenario-wizard.component.ts | 394 ++++++++++
src/app/scenario/scenario.component.html | 735 +-----------------
src/app/scenario/scenario.component.ts | 505 ++----------
.../steps-scenario.component.html | 141 ++++
.../steps-scenario.component.scss | 0
.../steps-scenario.component.ts | 122 +++
17 files changed, 1387 insertions(+), 1135 deletions(-)
create mode 100644 src/app/alert/alert.ts
create mode 100644 src/app/scenario/scenario-detail/scenario-detail.component.html
create mode 100644 src/app/scenario/scenario-detail/scenario-detail.component.scss
create mode 100644 src/app/scenario/scenario-detail/scenario-detail.component.ts
create mode 100644 src/app/scenario/scenario-wizard/scenario-wizard.component.html
create mode 100644 src/app/scenario/scenario-wizard/scenario-wizard.component.scss
create mode 100644 src/app/scenario/scenario-wizard/scenario-wizard.component.ts
create mode 100644 src/app/scenario/steps-scenario/steps-scenario.component.html
create mode 100644 src/app/scenario/steps-scenario/steps-scenario.component.scss
create mode 100644 src/app/scenario/steps-scenario/steps-scenario.component.ts
diff --git a/src/app/alert/alert.component.ts b/src/app/alert/alert.component.ts
index 93d4ad6f..95c19fe8 100644
--- a/src/app/alert/alert.component.ts
+++ b/src/app/alert/alert.component.ts
@@ -32,7 +32,7 @@ export class AlertComponent {
this.doAlert(text, ClrAlertType.Warning, closable, timeout)
}
- private doAlert(text: string, type: ClrAlertType = ClrAlertType.Info, closable: boolean = true, timeout: number = 0) {
+ public doAlert(text: string, type: ClrAlertType = ClrAlertType.Info, closable: boolean = true, timeout: number = 0) {
this.alert.alertType = type;
this.text = text;
this.alert.closable = closable;
diff --git a/src/app/alert/alert.ts b/src/app/alert/alert.ts
new file mode 100644
index 00000000..e1966158
--- /dev/null
+++ b/src/app/alert/alert.ts
@@ -0,0 +1,8 @@
+import { ClrAlertType } from '../clr-alert-type';
+
+export class AlertDetails {
+ type: ClrAlertType;
+ message: string;
+ closable?: boolean = true;
+ duration?: number = 0;
+}
\ No newline at end of file
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index 2ba33b0d..5343e63a 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -102,6 +102,9 @@ import { TypedArrayNumberComponent } from './typed-form/typed-array-number.compo
import { TypedArrayBooleanComponent } from './typed-form/typed-array-boolean.component';
import { CourseWizardComponent } from './course/course-wizard/course-wizard.component';
import { CourseDetailsComponent } from './course/course-details/course-details.component';
+import { ScenarioWizardComponent } from './scenario/scenario-wizard/scenario-wizard.component';
+import { ScenarioDetailComponent } from './scenario/scenario-detail/scenario-detail.component';
+import { StepsScenarioComponent } from './scenario/steps-scenario/steps-scenario.component';
import { DashboardDetailsComponent } from './dashboards/dashboard-details/dashboard-details.component';
import '@cds/core/icon/register.js';
import {
@@ -270,6 +273,9 @@ export function jwtOptionsFactory(): JwtConfig {
TypedArrayNumberComponent,
TypedArrayBooleanComponent,
CourseWizardComponent,
+ ScenarioWizardComponent,
+ ScenarioDetailComponent,
+ StepsScenarioComponent,
DashboardDetailsComponent,
],
imports: [
diff --git a/src/app/content/content.component.ts b/src/app/content/content.component.ts
index 70dd8144..73bd4cff 100644
--- a/src/app/content/content.component.ts
+++ b/src/app/content/content.component.ts
@@ -1,10 +1,6 @@
import { Component, OnChanges, OnInit, SimpleChanges } from '@angular/core';
import { RbacService } from '../data/rbac.service';
-import { ScenarioService } from '../data/scenario.service';
-import { CourseService } from '../data/course.service';
-import { Scenario } from '../data/scenario';
-import { Course } from '../data/course';
-import { ActivatedRoute, Router, RouterLink } from '@angular/router';
+import { ActivatedRoute, Router } from '@angular/router';
@Component({
selector: 'app-content',
diff --git a/src/app/data/scenario.service.ts b/src/app/data/scenario.service.ts
index 99e7fc35..9b016058 100644
--- a/src/app/data/scenario.service.ts
+++ b/src/app/data/scenario.service.ts
@@ -117,7 +117,7 @@ export class ScenarioService {
st.content = utoa(st.content);
});
- var params = new HttpParams({ encoder: new CustomEncoder() })
+ const params = new HttpParams({ encoder: new CustomEncoder() })
.set('name', utoa(s.name))
.set('description', utoa(s.description))
.set('steps', JSON.stringify(steps))
@@ -146,10 +146,19 @@ export class ScenarioService {
}
public create(s: Scenario) {
- var params = new HttpParams()
+ s.steps.forEach((st: Step) => {
+ st.title = utoa(st.title);
+ st.content = utoa(st.content);
+ });
+
+ const params = new HttpParams()
.set('name', utoa(s.name))
.set('description', utoa(s.description))
+ .set('virtualmachines', JSON.stringify(s.virtualmachines))
+ .set('steps', JSON.stringify(s.steps))
.set('pause_duration', s.pause_duration)
+ .set('categories', JSON.stringify(s.categories))
+ .set('tags', JSON.stringify(s.tags))
.set('keepalive_duration', s.keepalive_duration);
return this.http.post(environment.server + '/a/scenario/new', params).pipe(
@@ -178,4 +187,8 @@ export class ScenarioService {
{ responseType: 'text' }
);
}
+
+ public delete(id: string) {
+ return this.http.delete(environment.server + '/a/scenario/' + id);
+ }
}
diff --git a/src/app/filter-scenarios/filter-scenarios.component.ts b/src/app/filter-scenarios/filter-scenarios.component.ts
index 0fcbbd9f..36901282 100644
--- a/src/app/filter-scenarios/filter-scenarios.component.ts
+++ b/src/app/filter-scenarios/filter-scenarios.component.ts
@@ -43,6 +43,14 @@ export class FilterScenariosComponent implements OnInit {
this.categoryFilterForm.reset({ categoryControl: [] });
}
+ reloadScenarios(){
+ this.scenarioService.list(true).subscribe((s: Scenario[]) => {
+ this.scenarios = s;
+ this.clearCategoryFilter();
+ this.emitScenarios(this.scenarios);
+ });
+ }
+
filterScenarioList() {
if (this.selectedCategories.length === 0) {
this.filteredScenarios = this.scenarios;
diff --git a/src/app/scenario/scenario-detail/scenario-detail.component.html b/src/app/scenario/scenario-detail/scenario-detail.component.html
new file mode 100644
index 00000000..71ee8aad
--- /dev/null
+++ b/src/app/scenario/scenario-detail/scenario-detail.component.html
@@ -0,0 +1,60 @@
+
+
+
+ Basic Information
+
+
+
+
+
+ Name
+ {{ scenario.name }}
+
+
+ Description
+ {{ scenario.description }}
+
+
+ Keepalive Duration
+ {{ scenario.keepalive_duration }}
+
+
+ Pause Duration
+ {{ scenario.pause_duration }}
+
+
+ Virtual Machine
+ {{
+ scenario.virtualmachines.length
+ }}
+
+
+ Steps
+
+ {{ step.title }}
+
+
+ 0 || scenario.tags.length >0">
+ Categories & Tags
+ 0">
+ Categories
+
+ {{ categorie }}
+
+ 0">
+ Tags
+
+ {{ tag }}
+
+
+
+
diff --git a/src/app/scenario/scenario-detail/scenario-detail.component.scss b/src/app/scenario/scenario-detail/scenario-detail.component.scss
new file mode 100644
index 00000000..e69de29b
diff --git a/src/app/scenario/scenario-detail/scenario-detail.component.ts b/src/app/scenario/scenario-detail/scenario-detail.component.ts
new file mode 100644
index 00000000..61ab9b63
--- /dev/null
+++ b/src/app/scenario/scenario-detail/scenario-detail.component.ts
@@ -0,0 +1,29 @@
+import { HttpErrorResponse } from '@angular/common/http';
+import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
+import { Observable } from 'rxjs';
+import { Scenario } from 'src/app/data/scenario';
+import { ScenarioService } from 'src/app/data/scenario.service';
+
+@Component({
+ selector: 'scenario-detail',
+ templateUrl: './scenario-detail.component.html',
+ styleUrls: ['./scenario-detail.component.scss'],
+})
+export class ScenarioDetailComponent implements OnInit {
+ @Input()
+ scenario: Scenario;
+
+ constructor(public scenarioService: ScenarioService) {}
+ ngOnInit(): void {
+ let scenarioObservable: Observable;
+ scenarioObservable = this.scenarioService.get(this.scenario.id);
+ scenarioObservable.subscribe({
+ next: (S: Scenario) => {
+ this.scenario = S;
+ },
+ error: (e: HttpErrorResponse) => {
+ console.log(e);
+ },
+ });
+ }
+}
diff --git a/src/app/scenario/scenario-wizard/scenario-wizard.component.html b/src/app/scenario/scenario-wizard/scenario-wizard.component.html
new file mode 100644
index 00000000..409fc82d
--- /dev/null
+++ b/src/app/scenario/scenario-wizard/scenario-wizard.component.html
@@ -0,0 +1,489 @@
+
+ {{ wizardTitle }}
+
+ Cancel
+ Back
+ Next
+ Finish
+
+
+ Basic Information
+
+
+
+
+ Virtual Machine
+
+
+
+
+
+
+
You have to add virtual Machine in order to create a functional
+ scenario
+
+
+
+
+
+
+
+ Virtual Machines
+
+
+
+ Virtual Machine Set {{ i + 1 }}
+
+
+
+
+ {{ item.key }}
+ {{ item.value }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Steps
+
+
+
+
+
+
+ Categories
+
+
+
+
+
+ You can provide multiple categories by passing them as a
+ Comma-separated List
+
+
+
+
+ Category
+
+
+
+
+ {{ a }}
+
+
+
+
+
+
+ Tags
+
+
+
+
+ You can provide multiple tags by passing them as a Comma-separated
+ List
+
+
+
+
+ Tag
+
+
+
+
+ {{ a }}
+
+
+
+
+
+
+ Finalize
+ Confirm the following details before finishing
+ Scenario
+
+
+
+ Option |
+ Value |
+
+
+
+
+ Name |
+ {{ selectedscenario.name }} |
+
+
+ Description |
+ {{ selectedscenario.description }} |
+
+
+ Keepalive Duration |
+ {{ selectedscenario.keepalive_duration }} |
+
+
+ Pause Duration |
+ {{ selectedscenario.pause_duration }} |
+
+
+ Virtual Machine |
+ {{ selectedscenario.virtualmachines.length }} |
+
+
+ Steps |
+
+
+ {{ step.title }}
+ |
+
+
+ Categories |
+
+
+ {{ categorie }}
+ |
+
+
+ Tags |
+
+
+ {{ tag }}
+
+ |
+
+
+
+
+
+
+
+ Create VM
+
+
+
+
+
+
+
+ Delete VM Set
+
+
+ Are you sure you want to delete this VM set? This will remove any VM name
+ -> template mappings you have created.
+
+
+
+
+
+
diff --git a/src/app/scenario/scenario-wizard/scenario-wizard.component.scss b/src/app/scenario/scenario-wizard/scenario-wizard.component.scss
new file mode 100644
index 00000000..e69de29b
diff --git a/src/app/scenario/scenario-wizard/scenario-wizard.component.ts b/src/app/scenario/scenario-wizard/scenario-wizard.component.ts
new file mode 100644
index 00000000..ebd22db8
--- /dev/null
+++ b/src/app/scenario/scenario-wizard/scenario-wizard.component.ts
@@ -0,0 +1,394 @@
+import {
+ Component,
+ EventEmitter,
+ Input,
+ OnInit,
+ Output,
+ ViewChild,
+} from '@angular/core';
+import { FormControl, FormGroup, Validators } from '@angular/forms';
+import { ClrModal, ClrWizard } from '@clr/angular';
+import { RbacService } from 'src/app/data/rbac.service';
+import { Scenario } from 'src/app/data/scenario';
+import { ScenarioService } from 'src/app/data/scenario.service';
+import { ServerResponse } from 'src/app/data/serverresponse';
+import { VMTemplate } from 'src/app/data/vmtemplate';
+import { VmtemplateService } from 'src/app/data/vmtemplate.service';
+import { KeepaliveValidator } from 'src/app/validators/keepalive.validator';
+import { StepsScenarioComponent } from '../steps-scenario/steps-scenario.component';
+import { HttpErrorResponse } from '@angular/common/http';
+import { CategoryFormGroup, ScenarioFormGroup } from 'src/app/data/forms';
+import { AlertDetails } from 'src/app/alert/alert';
+import { ClrAlertType } from 'src/app/clr-alert-type';
+
+@Component({
+ selector: 'scenario-wizard',
+ templateUrl: './scenario-wizard.component.html',
+ styleUrls: ['./scenario-wizard.component.scss'],
+})
+export class ScenarioWizardComponent implements OnInit {
+ @Output()
+ onWizardFinished: EventEmitter =
+ new EventEmitter();
+
+ public wizardMode: 'create' | 'edit' = 'create';
+ public wizardTitle: 'Create new Scenario' | 'Edit Scenario' =
+ 'Create new Scenario';
+
+ public _open: boolean = false;
+ public selectRbac: boolean = false;
+ public deleteVMSetOpen: boolean = false;
+ public createVMOpen: boolean = false;
+ public newCategory: boolean = false;
+ public newTag: boolean = false;
+
+ public deletingVMSetIndex: number = 0;
+ public newvmindex: number = 0;
+ public stepsToBeAdded: number = 0;
+ public deletingStepIndex: number = 0;
+ public editingIndex: number = 0;
+
+ public vmtemplates: VMTemplate[] = [];
+
+ public selectedscenario: Scenario;
+
+ get keepaliveRequired() {
+ const ka = this.scenarioDetails.controls.keepalive_amount;
+ const ku = this.scenarioDetails.controls.keepalive_unit;
+
+ // validate
+ if ((ka.dirty || ka.touched) && ka.invalid && ka.errors.required) {
+ return true;
+ } else if ((ku.dirty || ku.touched) && ku.invalid && ku.errors.required) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @ViewChild('deletevmsetmodal', { static: true }) deleteVMSetModal: ClrModal;
+ @ViewChild('createvmmodal', { static: true }) createVMModal: ClrModal;
+ @ViewChild('stepsscenario', { static: true })
+ stepScenario: StepsScenarioComponent;
+
+ constructor(
+ public scenarioService: ScenarioService,
+ public vmTemplateService: VmtemplateService,
+ public rbacService: RbacService
+ ) {}
+
+ @ViewChild('wizard', { static: true }) wizard: ClrWizard;
+
+ public scenarioDetails: ScenarioFormGroup = new FormGroup(
+ {
+ scenario_name: new FormControl(null, [
+ Validators.required,
+ Validators.minLength(4),
+ ]),
+ scenario_description: new FormControl(null, [
+ Validators.required,
+ Validators.minLength(4),
+ ]),
+ keepalive_amount: new FormControl(10, {
+ validators: Validators.required,
+ nonNullable: true,
+ }),
+ keepalive_unit: new FormControl('m', {
+ validators: Validators.required,
+ nonNullable: true,
+ }),
+ pause_duration: new FormControl(1, {
+ validators: [
+ Validators.required,
+ Validators.min(1),
+ Validators.pattern('^[0-9]+$'),
+ ],
+ nonNullable: true,
+ }),
+ },
+ { validators: KeepaliveValidator }
+ );
+
+ public vmform: FormGroup<{
+ vm_name: FormControl;
+ vm_template: FormControl;
+ }> = new FormGroup({
+ vm_name: new FormControl(null, [
+ Validators.required,
+ Validators.minLength(4),
+ ]),
+ vm_template: new FormControl(null, [Validators.required]),
+ });
+
+ public newCategoryForm: CategoryFormGroup = new FormGroup({
+ category: new FormControl(null, [Validators.required]),
+ });
+ public newTagForm: FormGroup<{
+ tag: FormControl;
+ }> = new FormGroup({
+ tag: new FormControl(null, [Validators.required]),
+ });
+
+ ngOnInit() {
+ // let's initialize our selected scenario to prevent TypeErrors in our HTML template
+ this._initSelectedScenario();
+ // "Get" Permission on scenarios is required to load step content
+ this.rbacService.Grants('scenarios', 'get').then((allowed: boolean) => {
+ this.selectRbac = allowed;
+ });
+
+ this.rbacService
+ .Grants('virtualmachinesets', 'list')
+ .then((listVmSets: boolean) => {
+ if (listVmSets) {
+ this.vmTemplateService.list().subscribe((v: VMTemplate[]) => {
+ this.vmtemplates = v;
+ });
+ }
+ });
+ }
+
+ open(wizardMode: 'create' | 'edit', scenario?: Scenario) {
+ this.wizardMode = wizardMode;
+ if (this.wizardMode == 'create') {
+ this._createScenarioWizardfunction();
+ } else {
+ // this wizardMode == 'edit'
+ this._editScenarioWizardfunction(scenario);
+ }
+ }
+
+ doCancel(): void {
+ this.wizard.reset();
+ this.resetScenarioForm();
+
+ this.wizard.close();
+ }
+
+ finishScenario() {
+ if (this.wizardMode == 'create') this.saveCreatedScenario();
+ if (this.wizardMode == 'edit') this.saveUpdatedScenario();
+ }
+
+ saveCreatedScenario() {
+ this.scenarioService.create(this.selectedscenario).subscribe({
+ next: (s: Scenario) => {
+ this.onWizardFinished.emit({
+ type: ClrAlertType.Success,
+ message: `Scenario ${s.name} created`,
+ closable: true,
+ duration: 3000,
+ });
+ },
+ error: (e: HttpErrorResponse) => {
+ const errorMessage: string = e.message;
+ this.onWizardFinished.emit({
+ type: ClrAlertType.Danger,
+ message: errorMessage,
+ closable: true,
+ duration: 3000,
+ });
+ },
+ });
+ this.resetScenarioForm();
+ }
+
+ public copyScenarioDetails() {
+ this.selectedscenario.keepalive_duration =
+ this.scenarioDetails.controls.keepalive_amount.value +
+ this.scenarioDetails.controls.keepalive_unit.value;
+ this.selectedscenario.pause_duration =
+ this.scenarioDetails.controls.pause_duration.value + 'h';
+ this.selectedscenario.name =
+ this.scenarioDetails.controls.scenario_name.value;
+ this.selectedscenario.description =
+ this.scenarioDetails.controls.scenario_description.value;
+ }
+
+ saveUpdatedScenario() {
+ this.scenarioService
+ .update(this.selectedscenario)
+ .subscribe((s: ServerResponse) => {
+ if (s.type == 'updated') {
+ this.onWizardFinished.emit({
+ type: ClrAlertType.Success,
+ message: `Scenario updated`,
+ closable: true,
+ duration: 3000,
+ });
+ } else {
+ const errorMsg = 'Unable to update scenario: ' + s.message;
+ this.onWizardFinished.emit({
+ type: ClrAlertType.Success,
+ message: errorMsg,
+ closable: true,
+ duration: 3000,
+ });
+ }
+ });
+ }
+ resetScenarioForm() {
+ this.wizard.reset();
+ this.scenarioDetails.reset({
+ keepalive_amount: 10,
+ keepalive_unit: 'm',
+ pause_duration: 1,
+ });
+ this.selectedscenario.virtualmachines = [];
+ this.selectedscenario.steps = [];
+ this.selectedscenario.categories = [];
+ this.selectedscenario.tags = [];
+ }
+ addCategory() {
+ const categories: string[] | undefined =
+ this.newCategoryForm.controls.category.value?.split(',');
+ categories?.forEach((category) => {
+ category = category.replace(/\s/g, ''); //remove all whitespaces
+ if (
+ category != '' &&
+ !this.selectedscenario.categories.includes(category)
+ ) {
+ this.selectedscenario.categories.push(category);
+ }
+ });
+ this.newCategoryForm.reset();
+ this.newCategory = false;
+ }
+ deleteCategory(category: string) {
+ this.selectedscenario.categories.forEach((element, index) => {
+ if (element == category)
+ this.selectedscenario.categories.splice(index, 1);
+ });
+ }
+ addTag() {
+ const tags: string[] | undefined =
+ this.newTagForm.controls.tag.value?.split(',');
+ tags?.forEach((tag) => {
+ tag = tag.replace(/\s/g, ''); //remove all whitespaces
+ if (tag != '' && !this.selectedscenario.tags.includes(tag)) {
+ this.selectedscenario.tags.push(tag);
+ }
+ });
+ this.newTagForm.reset();
+ this.newTag = false;
+ }
+ deleteTag(tag: string) {
+ this.selectedscenario.tags.forEach((element, index) => {
+ if (element == tag) this.selectedscenario.tags.splice(index, 1);
+ });
+ }
+ selectedScenarioHasVM(): boolean {
+ if (this.selectedscenario.virtualmachines.length != 0) {
+ const validVMSet = this.selectedscenario.virtualmachines.filter(
+ (virtualmachine, i) => {
+ if (Object.keys(virtualmachine).length != 0) {
+ return true;
+ }
+ return false;
+ }
+ );
+ if (validVMSet.length == this.selectedscenario.virtualmachines.length) {
+ return true;
+ }
+ }
+ return false;
+ }
+ addVMSet() {
+ this.selectedscenario.virtualmachines.push({});
+ }
+ addVM() {
+ this.selectedScenarioHasVM();
+ this.selectedscenario.virtualmachines[this.newvmindex][
+ this.vmform.controls.vm_name.value
+ ] = this.vmform.controls.vm_template.value;
+ this.createVMModal.close();
+ }
+
+ deleteVMSet(i: number) {
+ this.deletingVMSetIndex = i;
+ this.deleteVMSetModal.open();
+ }
+
+ public deleteVM(setIndex: number, key: string) {
+ delete this.selectedscenario.virtualmachines[setIndex][key];
+ }
+ doDeleteVMSet() {
+ this.selectedscenario.virtualmachines.splice(this.deletingVMSetIndex, 1);
+ this.deleteVMSetModal.close();
+ }
+ public openCreateVM(i: number) {
+ this.vmform.reset();
+ this.newvmindex = i;
+ this.createVMModal.open();
+ }
+
+ private _editScenarioWizardfunction(scenario?: Scenario) {
+ if (!scenario) {
+ // somehow scenario is undefined -> display an error alert
+ this.onWizardFinished.emit({
+ type: ClrAlertType.Danger,
+ message:
+ 'Could not edit scenario. The provided scenario is not defined.',
+ });
+ }
+ this.wizardTitle = 'Edit Scenario';
+ this._editScenario(scenario);
+ }
+
+ private _editScenario(s: Scenario) {
+ if (s != undefined) {
+ // this is only a partial scenario, we need to get the full
+ this.scenarioService.get(s.id).subscribe({
+ next: (s: Scenario) => {
+ this.selectedscenario = s;
+ this.scenarioDetails.reset({
+ scenario_name: s.name,
+ scenario_description: s.description,
+ keepalive_amount: Number(
+ s.keepalive_duration.substring(0, s.keepalive_duration.length - 1)
+ ),
+ keepalive_unit: s.keepalive_duration.substring(
+ s.keepalive_duration.length - 1,
+ s.keepalive_duration.length
+ ),
+ });
+ const pauseDuration = Number(s.pause_duration?.slice(0, -1));
+ if (!Number.isNaN(pauseDuration)) {
+ this.scenarioDetails.patchValue({
+ pause_duration: pauseDuration,
+ });
+ }
+ this.wizard.navService.goTo(this.wizard.pages.last, true);
+ this.wizard.pages.first.makeCurrent();
+ this.wizard.open();
+ },
+ error: () => {
+ this.onWizardFinished.emit({
+ type: ClrAlertType.Danger,
+ message: 'error editing scenario',
+ closable: true,
+ duration: 3000,
+ });
+ },
+ });
+ }
+ }
+
+ private _createScenarioWizardfunction() {
+ this.wizardTitle = 'Create new Scenario';
+ this.resetScenarioForm();
+ this._initSelectedScenario();
+ this.wizard.open();
+ }
+
+ private _initSelectedScenario() {
+ this.selectedscenario = new Scenario();
+ this.selectedscenario.id = '';
+ this.selectedscenario.name = '';
+ this.selectedscenario.virtualmachines = [];
+ this.selectedscenario.tags = [];
+ this.selectedscenario.steps = [];
+ this.selectedscenario.virtualmachines[0] = {};
+ this.selectedscenario.categories = [];
+ }
+}
diff --git a/src/app/scenario/scenario.component.html b/src/app/scenario/scenario.component.html
index 045c9b24..754d7fe8 100644
--- a/src/app/scenario/scenario.component.html
+++ b/src/app/scenario/scenario.component.html
@@ -1,42 +1,10 @@
-
-
-
- Scenario has been modified. Save your changes.
-
-
-
-
-
-
- {{ scenarioDangerAlert }}
-
-
-
-
-
-
- {{ scenarioSuccessAlert }}
-
-
-
+
Scenarios
-
+
@@ -58,687 +26,56 @@ Scenarios
>Name
+
+
+
+
{{ s.id }}
{{ s.name }}
+
-
-
-
-
-
-
-
-
-
-
- Virtual Machines
-
-
-
- Virtual Machine Set {{ i + 1 }}
-
-
-
-
-
- {{ item.key }}
- {{ item.value }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Index
- Title
-
-
-
-
-
-
-
-
-
- {{ i + 1 }}
- {{ s.title }}
-
-
-
-
-
-
-
-
-
-
-
-
-
- You can provide multiple categories by passing them as a
- Comma-separated List
-
-
-
-
- Category
-
-
-
-
- {{ a }}
-
-
-
-
-
-
-
-
-
-
-
- You can provide multiple tags by passing them as a
- Comma-separated List
-
-
-
-
- Tag
-
-
-
-
- {{ a }}
-
-
-
-
-
-
-
-
-
-
- Edit Step {{ this.editingIndex + 1 }} of
- {{ this.selectedscenario?.steps.length }}
-
+
+
+
+ Delete Scenario
-
-
-
- {{ editDangerAlert }}
-
-
-
-
-
-
- {{ editSuccessAlert }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
Are you sure you want to delete this scenario?
-
-
- Delete VM Set
-
-
- Are you sure you want to delete this VM set? This will remove any VM name
- -> template mappings you have created.
-
-
-
-
-
- Delete Step
-
-
Are you sure you want to delete this step?
-
-
-
-
-
- Create VM
-
-
-
-
-
-
-
- Create New Scenario
-
-
-
diff --git a/src/app/scenario/scenario.component.ts b/src/app/scenario/scenario.component.ts
index 3e1dd381..e1ccf083 100644
--- a/src/app/scenario/scenario.component.ts
+++ b/src/app/scenario/scenario.component.ts
@@ -2,17 +2,13 @@ import { Component, OnInit, ViewChild } from '@angular/core';
import { Scenario } from '../data/scenario';
import { ScenarioService } from '../data/scenario.service';
import { ClrDatagridSortOrder, ClrModal } from '@clr/angular';
-import { Step } from '../data/step';
import { ServerResponse } from '../data/serverresponse';
-import { deepCopy } from '../deepcopy';
-import { VmtemplateService } from '../data/vmtemplate.service';
-import { VMTemplate } from '../data/vmtemplate';
-import { VirtualMachine } from '../data/virtualmachine';
-import { Validators, FormGroup, FormControl } from '@angular/forms';
-import { KeepaliveValidator } from '../validators/keepalive.validator';
+import { FilterScenariosComponent } from '../filter-scenarios/filter-scenarios.component';
+import { HttpErrorResponse } from '@angular/common/http';
+import { ScenarioWizardComponent } from './scenario-wizard/scenario-wizard.component';
import { RbacService } from '../data/rbac.service';
-import { CategoryFormGroup, ScenarioFormGroup } from '../data/forms';
-import { delay, tap } from 'rxjs';
+import { AlertDetails } from '../alert/alert';
+import { AlertComponent } from '../alert/alert.component';
@Component({
selector: 'app-scenario',
@@ -20,42 +16,11 @@ import { delay, tap } from 'rxjs';
styleUrls: ['./scenario.component.scss'],
})
export class ScenarioComponent implements OnInit {
- public unusedSelectedScenario: any = {}; // only exists to satisfy a datagrid requirement
-
public filteredScenarios: Scenario[] = [];
- public vmtemplates: VMTemplate[] = [];
public selectedscenario: Scenario;
- public editingStep: Step = new Step();
- public editingIndex: number = 0;
-
- public scenarioNotTainted: boolean = true;
-
- public editDangerClosed: boolean = true;
- public editSuccessClosed: boolean = true;
- public scenarioDangerClosed: boolean = true;
- public scenarioSuccessClosed: boolean = true;
-
- public editDangerAlert: string = '';
- public editSuccessAlert: string = '';
- public scenarioDangerAlert: string = '';
- public scenarioSuccessAlert: string = '';
- public newvmindex: number = 0;
-
- public deletingVMSetIndex: number = 0;
- public deletingStepIndex: number = 0;
-
- public editOpen: boolean = false;
- public deleteVMSetOpen: boolean = false;
- public deleteStepOpen: boolean = false;
- public createVMOpen: boolean = false;
- public newScenarioOpen: boolean = false;
- public newCategory: boolean = false;
- public newTag: boolean = false;
-
- public newScenario: Scenario = new Scenario();
-
- public vmProps: string[] = Object.keys(new VirtualMachine());
+ public deleteScenarioSetOpen: boolean = false;
+ public showActionOverflow: boolean = false;
public selectRbac: boolean = false;
@@ -63,426 +28,110 @@ export class ScenarioComponent implements OnInit {
constructor(
public scenarioService: ScenarioService,
- public vmTemplateService: VmtemplateService,
- public rbacService: RbacService,
+ public rbacService: RbacService
) {}
- public vmform: FormGroup<{
- vm_name: FormControl;
- vm_template: FormControl;
- }> = new FormGroup({
- vm_name: new FormControl(null, [
- Validators.required,
- Validators.minLength(4),
- ]),
- vm_template: new FormControl(null, [Validators.required]),
- });
-
- public editScenarioForm: ScenarioFormGroup = new FormGroup(
- {
- scenario_name: new FormControl(null, [
- Validators.required,
- Validators.minLength(4),
- ]),
- scenario_description: new FormControl(null, [
- Validators.required,
- Validators.minLength(4),
- ]),
- keepalive_amount: new FormControl(10, {
- validators: Validators.required,
- nonNullable: true,
- }),
- keepalive_unit: new FormControl('m', {
- validators: Validators.required,
- nonNullable: true,
- }),
- pause_duration: new FormControl(1, {
- validators: [
- Validators.required,
- Validators.min(1),
- Validators.pattern('^[0-9]+$'),
- ],
- nonNullable: true,
- }),
- },
- { validators: KeepaliveValidator }
- );
-
- public scenarioDetails: ScenarioFormGroup = new FormGroup(
- {
- scenario_name: new FormControl(null, [
- Validators.required,
- Validators.minLength(4),
- ]),
- scenario_description: new FormControl(null, [
- Validators.required,
- Validators.minLength(4),
- ]),
- keepalive_amount: new FormControl(10, {
- validators: Validators.required,
- nonNullable: true,
- }),
- keepalive_unit: new FormControl('m', {
- validators: Validators.required,
- nonNullable: true,
- }),
- pause_duration: new FormControl(1, {
- validators: [
- Validators.required,
- Validators.min(1),
- Validators.pattern('^[0-9]+$'),
- ],
- nonNullable: true,
- }),
- },
- { validators: KeepaliveValidator }
- );
-
- public newCategoryForm: CategoryFormGroup = new FormGroup({
- category: new FormControl(null, [Validators.required]),
- });
+ @ViewChild('deletescenariomodal', { static: true })
+ deleteScenarioModal: ClrModal;
- public newTagForm: FormGroup<{
- tag: FormControl;
- }> = new FormGroup({
- tag: new FormControl(null, [Validators.required]),
- });
-
- get keepaliveAmount() {
- return this.scenarioDetails.controls.keepalive_amount;
- }
-
- get keepaliveUnit() {
- return this.scenarioDetails.controls.keepalive_unit;
- }
-
- get keepaliveRequired() {
- const ka = this.keepaliveAmount;
- const ku = this.keepaliveUnit;
-
- // validate
- if ((ka.dirty || ka.touched) && ka.invalid && ka.errors.required) {
- return true;
- } else if ((ku.dirty || ku.touched) && ku.invalid && ku.errors.required) {
- return true;
- } else {
- return false;
- }
- }
-
- @ViewChild('editmodal', { static: true }) editModal: ClrModal;
- @ViewChild('deletevmsetmodal', { static: true }) deleteVMSetModal: ClrModal;
- @ViewChild('createvmmodal', { static: true }) createVMModal: ClrModal;
- @ViewChild('deletestepmodal', { static: true }) deleteStepModal: ClrModal;
- @ViewChild('newscenariomodal', { static: true }) newScenarioModal: ClrModal;
-
- openEdit(s: Step, i: number) {
- if (this.selectedscenario.steps.length == 0) {
- this.openNewStep();
- return;
- }
- this.editingStep = s;
- this.editingIndex = i;
- this.editModal.open();
- }
+ @ViewChild('scenarioFilter', { static: true })
+ scenarioFilter: FilterScenariosComponent;
+ @ViewChild('scenariowizard', { static: true })
+ scenarioWizard: ScenarioWizardComponent;
+ @ViewChild('alert') alert: AlertComponent;
editScenario(s: Scenario) {
if (s != undefined) {
// this is only a partial scenario, we need to get the full
- this.scenarioService.get(s.id).subscribe((s: Scenario) => {
- this.selectedscenario = s;
- this.editScenarioForm.reset({
- scenario_name: s.name,
- scenario_description: s.description,
- keepalive_amount: Number(
- s.keepalive_duration.substring(0, s.keepalive_duration.length - 1)
- ),
- keepalive_unit: s.keepalive_duration.substring(
- s.keepalive_duration.length - 1,
- s.keepalive_duration.length
- ),
- });
- const pauseDuration = Number(s.pause_duration?.slice(0, -1));
- if (!Number.isNaN(pauseDuration)) {
- this.editScenarioForm.patchValue({
- pause_duration: pauseDuration,
- });
- }
+ this.scenarioService.get(s.id).subscribe({
+ next: (s: Scenario) => {
+ this.selectedscenario = s;
+ },
+ error: (e: HttpErrorResponse) => {
+ this.alert.danger('Error retrieving object: ' + e.error.message, true, 3000);
+ },
});
}
}
- openNewScenario() {
- this.newScenario = new Scenario();
- this.newScenarioModal.open();
- }
-
- openNewStep() {
- this.editingIndex = this.selectedscenario.steps.length;
- this.editingStep = new Step();
- this.editingStep.title = 'Step ' + (this.editingIndex + 1);
- // Provide default content with syntax examples
- this.editingStep.content =
- "## Your Content\n```ctr:node1\necho 'hello world'\n```\n```hidden:Syntax reference\navailable at [the hobbyfarm docs](https://hobbyfarm.github.io/docs/appendix/markdown_syntax/)\n```";
- this.selectedscenario.steps[this.editingIndex] = this.editingStep;
- this.editModal.open();
- }
-
- isFirstStep() {
- return this.editingIndex == 0;
- }
-
- isLastStep() {
- return this.editingIndex >= this.selectedscenario?.steps.length - 1;
- }
-
- nextStep() {
- if (this.isLastStep()) {
- return;
- }
- this.selectedscenario.steps[this.editingIndex] = this.editingStep;
- this.editingIndex++;
- this.editingStep = this.selectedscenario.steps[this.editingIndex];
- }
-
- previousStep() {
- if (this.isFirstStep()) {
- return;
- }
- this.selectedscenario.steps[this.editingIndex] = this.editingStep;
- this.editingIndex--;
- this.editingStep = this.selectedscenario.steps[this.editingIndex];
- }
-
- public openDeleteStep(i: number) {
- this.deletingStepIndex = i;
- this.deleteStepModal.open();
- }
-
- public doDeleteStep() {
- this.selectedscenario.steps.splice(this.deletingStepIndex, 1);
- this.deleteStepModal.close();
- this.savescenario();
+ openScenarioWizard(wizardMode: 'create' | 'edit', scenario?: Scenario) {
+ this.scenarioWizard.open(wizardMode, scenario);
}
- private _displayAlert(alert: string, success: boolean, duration?: number) {
- if (success) {
- this.scenarioSuccessAlert = alert;
- this.scenarioSuccessClosed = false;
- setTimeout(() => {
- this.scenarioSuccessClosed = true;
- }, duration || 1000);
- } else {
- this.scenarioDangerAlert = alert;
- this.scenarioDangerClosed = false;
- setTimeout(() => {
- this.scenarioDangerClosed = true;
- }, duration || 1000);
- }
- }
-
- public addNewScenario() {
- this.newScenario.name = this.scenarioDetails.controls.scenario_name.value;
- this.newScenario.description =
- this.scenarioDetails.controls.scenario_description.value;
- this.newScenario.keepalive_duration =
- this.scenarioDetails.controls.keepalive_amount.value +
- this.scenarioDetails.controls.keepalive_unit.value;
- this.newScenario.pause_duration =
- this.scenarioDetails.controls.pause_duration.value + 'h';
-
- // should be able to save at this point
- this.scenarioService.create(this.newScenario).subscribe({
- next: (s: Scenario) => {
- this._displayAlert(s.name, true);
- },
- error: (s: string) => {
- this._displayAlert(s, false);
+ openDeleteScenario(scenario: Scenario) {
+ this.scenarioService.get(scenario.id).subscribe({
+ next: (scenario) => (this.selectedscenario = scenario),
+ error: (e: HttpErrorResponse) => {
+ this.alert.danger('Error deleting object: ' + e.error.message, true, 3000);
},
});
-
- this.newScenarioModal.close();
- }
-
- cancelEdit() {
- this.editModal.close();
- }
-
- saveStep() {
- this.selectedscenario.steps[this.editingIndex] = this.editingStep;
- this.scenarioService
- .update(this.selectedscenario)
- .subscribe((s: ServerResponse) => {
- if (s.type == 'updated') {
- this.editSuccessAlert = 'Steps successfully saved';
- this.editSuccessClosed = false;
- setTimeout(() => {
- this.editSuccessClosed = true;
- this.editModal.close();
- }, 1000);
- } else {
- this.editDangerAlert = 'Unable to save steps: ' + s.message;
- this.editDangerClosed = false;
- setTimeout(() => {
- this.editDangerClosed = true;
- }, 1000);
- }
- });
- }
-
- public openCreateVM(i: number) {
- this.vmform.reset();
- this.newvmindex = i;
- this.createVMModal.open();
- }
-
- public deleteVM(setIndex: number, key: string) {
- this.scenarioNotTainted = false;
- delete this.selectedscenario.virtualmachines[setIndex][key];
- }
-
- addVM() {
- this.scenarioNotTainted = false;
- // TODO: As soon as we introduce strictNullChecks, this will fail...
- // ... and we need to check if this.vmform.controls.vm_name.value and this.vmform.controls.vm_template.value are not null
- this.selectedscenario.virtualmachines[this.newvmindex][
- this.vmform.controls.vm_name.value
- ] = this.vmform.controls.vm_template.value;
- this.createVMModal.close();
- }
-
- savescenario() {
- this.selectedscenario.keepalive_duration =
- this.editScenarioForm.controls.keepalive_amount.value +
- this.editScenarioForm.controls.keepalive_unit.value;
- this.selectedscenario.pause_duration =
- this.editScenarioForm.controls.pause_duration.value + 'h';
- this.selectedscenario.name =
- this.editScenarioForm.controls.scenario_name.value;
- this.selectedscenario.description =
- this.editScenarioForm.controls.scenario_description.value;
-
- this.scenarioService
- .update(this.selectedscenario)
- .pipe(
- tap((s: ServerResponse) => {
- if (s.type == 'updated') {
- this.scenarioSuccessAlert = 'Scenario updated';
- this.scenarioSuccessClosed = false;
- } else {
- this.scenarioDangerAlert =
- 'Unable to update scenario: ' + s.message;
- this.scenarioDangerClosed = false;
- }
- }),
- delay(1000),
- tap((s: ServerResponse) => {
- if (s.type == 'updated') {
- this.scenarioSuccessClosed = true;
- this.scenarioNotTainted = true;
- } else {
- this.scenarioDangerClosed = true;
- }
- })
- )
- .subscribe();
- }
-
- moveStepUp(i: number) {
- this.scenarioNotTainted = false;
- // get a copy of the to-be-moved item
- var obj = deepCopy(this.selectedscenario.steps[i]);
- // delete at the index currently
- this.selectedscenario.steps.splice(i, 1);
- // put into the i-1 index
- this.selectedscenario.steps.splice(i - 1, 0, obj);
- }
-
- moveStepDown(i: number) {
- this.scenarioNotTainted = false;
- // get a copy of the to-be-moved item
- var obj = deepCopy(this.selectedscenario.steps[i]);
- // delete at the index currently
- this.selectedscenario.steps.splice(i, 1);
- // put into the i+1 index
- this.selectedscenario.steps.splice(i + 1, 0, obj);
- }
-
- deleteCategory(category: string) {
- this.selectedscenario.categories.forEach((element, index) => {
- if (element == category)
- this.selectedscenario.categories.splice(index, 1);
- });
+ this.deleteScenarioModal.open();
}
- addCategory() {
- const categories: string[] | undefined =
- this.newCategoryForm.controls.category.value?.split(',');
- categories?.forEach((category) => {
- category = category.replace(/\s/g, ''); //remove all whitespaces
- if (
- category != '' &&
- !this.selectedscenario.categories.includes(category)
- ) {
- this.selectedscenario.categories.push(category);
- }
- });
- this.newCategoryForm.reset();
- this.newCategory = false;
+ setScenarioList(scenarios: Scenario[]) {
+ this.filteredScenarios = scenarios;
}
- deleteTag(tag: string) {
- this.selectedscenario.tags.forEach((element, index) => {
- if (element == tag) this.selectedscenario.tags.splice(index, 1);
+ refresh(): void {
+ this.scenarioService.list(true).subscribe({
+ next: (sList: Scenario[]) => (this.filteredScenarios = sList),
+ error: (e: HttpErrorResponse) => {
+ this.alert.danger('Error listing objects: ' + e.error.message, true, 3000);
+ },
});
}
- addTag() {
- const tags: string[] | undefined =
- this.newTagForm.controls.tag.value?.split(',');
- tags?.forEach((tag) => {
- tag = tag.replace(/\s/g, ''); //remove all whitespaces
- if (tag != '' && !this.selectedscenario.tags.includes(tag)) {
- this.selectedscenario.tags.push(tag);
- }
+ deleteScenario(scenarioId: string) {
+ this.scenarioService.delete(scenarioId).subscribe({
+ next: (_s: ServerResponse) => {
+ this.alert.success('Scenario deleted', true, 3000);
+ this.refresh();
+ },
+ error: (e: HttpErrorResponse) => {
+ this.alert.danger('Error deleting object: ' + e.error.message, true, 3000);
+ },
});
- this.newTagForm.reset();
- this.newTag = false;
- }
-
- addVMSet() {
- this.scenarioNotTainted = false;
- this.selectedscenario.virtualmachines.push({});
}
- deleteVMSet(i: number) {
- this.scenarioNotTainted = false;
- this.deletingVMSetIndex = i;
- this.deleteVMSetModal.open();
+ doDeleteScenario() {
+ this.deleteScenario(this.selectedscenario.id);
+ this.deleteScenarioModal.close();
+ this.selectedscenario =
+ this.filteredScenarios[this.filteredScenarios.length - 1];
}
- doDeleteVMSet() {
- this.selectedscenario.virtualmachines.splice(this.deletingVMSetIndex, 1);
- this.deleteVMSetModal.close();
- }
- setScenarioList(scenarios: Scenario[]) {
- this.filteredScenarios = scenarios;
+ refreshAndDisplayAlert(alertDetails: AlertDetails) {
+ this._reloadScenario();
+ this.alert.doAlert(alertDetails.message, alertDetails.type, alertDetails.closable, alertDetails.duration);
}
ngOnInit() {
+ this.selectedscenario = new Scenario();
+ this.selectedscenario.name = '';
+ this.selectedscenario.virtualmachines = [];
+ this.selectedscenario.steps = [];
+ this.selectedscenario.virtualmachines[0] = {};
// "Get" Permission on scenarios is required to load step content
this.rbacService.Grants('scenarios', 'get').then((allowed: boolean) => {
this.selectRbac = allowed;
});
- this.rbacService
- .Grants('virtualmachinesets', 'list')
- .then((listVmSets: boolean) => {
- if (listVmSets) {
- this.vmTemplateService.list().subscribe((v: VMTemplate[]) => {
- this.vmtemplates = v;
- });
- }
- });
+ const authorizationRequests = Promise.all([
+ this.rbacService.Grants('scenarios', 'get'),
+ this.rbacService.Grants('scenarios', 'update'),
+ this.rbacService.Grants('scenarios', 'delete'),
+ ]);
+ authorizationRequests.then((permissions: [boolean, boolean, boolean]) => {
+ const allowGet: boolean = permissions[0];
+ const allowUpdate: boolean = permissions[1];
+ const allowDelete: boolean = permissions[2];
+ this.showActionOverflow = allowDelete || (allowGet && allowUpdate);
+ });
+ this.refresh();
+ }
+
+ private _reloadScenario() {
+ this.scenarioFilter.reloadScenarios();
+ this.refresh();
}
}
diff --git a/src/app/scenario/steps-scenario/steps-scenario.component.html b/src/app/scenario/steps-scenario/steps-scenario.component.html
new file mode 100644
index 00000000..ebbafa49
--- /dev/null
+++ b/src/app/scenario/steps-scenario/steps-scenario.component.html
@@ -0,0 +1,141 @@
+
+
+
+ Index
+ Title
+
+
+
+
+
+
+
+
+ {{ i + 1 }}
+ {{ s.title }}
+
+
+
+
+
+ Edit Step {{ this.editingIndex + 1 }} of
+ {{ this.editingSteps.length }}
+
+
+
+
+
+ {{ editDangerAlert }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Delete Step
+
+
Are you sure you want to delete this step?
+
+
+
diff --git a/src/app/scenario/steps-scenario/steps-scenario.component.scss b/src/app/scenario/steps-scenario/steps-scenario.component.scss
new file mode 100644
index 00000000..e69de29b
diff --git a/src/app/scenario/steps-scenario/steps-scenario.component.ts b/src/app/scenario/steps-scenario/steps-scenario.component.ts
new file mode 100644
index 00000000..402e09e1
--- /dev/null
+++ b/src/app/scenario/steps-scenario/steps-scenario.component.ts
@@ -0,0 +1,122 @@
+import { Component, Input, OnInit, ViewChild } from '@angular/core';
+import { ClrModal } from '@clr/angular';
+import { Scenario } from 'src/app/data/scenario';
+import { Step } from 'src/app/data/step';
+import { deepCopy } from 'src/app/deepcopy';
+
+@Component({
+ selector: 'steps-scenario',
+ templateUrl: './steps-scenario.component.html',
+ styleUrls: ['./steps-scenario.component.scss'],
+})
+export class StepsScenarioComponent {
+ @Input()
+ scenario: Scenario;
+
+
+
+ public scenarioTainted: boolean = false;
+ public editOpen: boolean = false;
+ public editDangerClosed: boolean = true;
+ public editSuccessClosed: boolean = true;
+ public deleteStepOpen: boolean = false;
+ public isStepsLengthNull: boolean = true;
+
+ public editingStep: Step = new Step();
+ public editingSteps: Step[] = [];
+
+ public editingIndex: number = 0;
+ public stepsToBeAdded: number = 0;
+ public deletingStepIndex: number = 0;
+
+ public editDangerAlert: string = '';
+ public editSuccessAlert: string = '';
+
+ @ViewChild('editmodal', { static: true }) editModal: ClrModal;
+ @ViewChild('deletestepmodal', { static: true }) deleteStepModal: ClrModal;
+
+ moveStepUp(i: number) {
+ this.scenarioTainted = true;
+ // get a copy of the to-be-moved item
+ const obj = deepCopy(this.scenario.steps[i]);
+ // delete at the index currently
+ this.scenario.steps.splice(i, 1);
+ // put into the i-1 index
+ this.scenario.steps.splice(i - 1, 0, obj);
+ }
+ moveStepDown(i: number) {
+ this.scenarioTainted = true;
+ // get a copy of the to-be-moved item
+ const obj = deepCopy(this.scenario.steps[i]);
+ // delete at the index currently
+ this.scenario.steps.splice(i, 1);
+ // put into the i+1 index
+ this.scenario.steps.splice(i + 1, 0, obj);
+ }
+
+ openEdit(s: Step, i: number) {
+ this.editingSteps = deepCopy(this.scenario.steps);
+ if (this.editingSteps.length == 0) {
+ this.openNewStep();
+ return;
+ }
+ this.editingIndex = i;
+ this.editingStep = this.editingSteps[i];
+ this.editModal.open();
+ }
+
+ openNewStep() {
+ this.editingSteps = deepCopy(this.scenario.steps);
+ this.editingIndex = this.editingSteps.length;
+ this.editingStep = new Step();
+ this.editingStep.title = 'Step ' + (this.editingIndex + 1);
+ // Provide default content with syntax examples
+ this.editingStep.content =
+ "## Your Content\n```ctr:node1\necho 'hello world'\n```\n```hidden:Syntax reference\navailable at [the hobbyfarm docs](https://hobbyfarm.github.io/docs/appendix/markdown_syntax/)\n```";
+ this.editingSteps[this.editingIndex] = this.editingStep;
+ this.editModal.open();
+ }
+
+ public openDeleteStep(i: number) {
+ this.deletingStepIndex = i;
+ this.deleteStepModal.open();
+ }
+
+ previousStep() {
+ if (this.isFirstStep()) {
+ return;
+ }
+ this.editingSteps[this.editingIndex] = this.editingStep;
+ this.editingIndex--;
+ this.editingStep = this.editingSteps[this.editingIndex];
+ }
+ isFirstStep() {
+ return this.editingIndex == 0;
+ }
+ nextStep() {
+ if (this.isLastStep()) {
+ return;
+ }
+ this.editingSteps[this.editingIndex] = this.editingStep;
+ this.editingIndex++;
+ this.editingStep = this.editingSteps[this.editingIndex];
+ }
+ isLastStep() {
+ return this.editingIndex >= this.editingSteps?.length - 1;
+ }
+ cancelEdit() {
+ this.editModal.close();
+ }
+
+ saveCreatedStep() {
+ this.scenario.steps = deepCopy(this.editingSteps);
+ this.isStepsLengthNull = false;
+ this.stepsToBeAdded = 0;
+ this.editModal.close();
+ }
+ public doDeleteStep() {
+ this.scenario.steps.splice(this.deletingStepIndex, 1);
+ this.deleteStepModal.close();
+ if (this.scenario.steps.length == 0) this.isStepsLengthNull = true;
+ }
+}
From 5518bd5f94c6e3821974e447ae7754e76e350211 Mon Sep 17 00:00:00 2001
From: maxsva <110593497+maxsva@users.noreply.github.com>
Date: Tue, 12 Mar 2024 17:06:41 +0100
Subject: [PATCH 5/6] fix new environment param create (#204)
Co-authored-by: Maksym Veres
---
.../edit-environment.component.html | 131 +++++++++++++-----
1 file changed, 96 insertions(+), 35 deletions(-)
diff --git a/src/app/configuration/environments/edit-environment/edit-environment.component.html b/src/app/configuration/environments/edit-environment/edit-environment.component.html
index 86504d85..c6feb4d0 100644
--- a/src/app/configuration/environments/edit-environment/edit-environment.component.html
+++ b/src/app/configuration/environments/edit-environment/edit-environment.component.html
@@ -346,38 +346,58 @@ Basic Information
-
- Display Name |
- {{ env.display_name }} |
-
- {{ uneditedEnv.display_name }}
- {{ env.display_name }}
- |
-
-
- DNS Suffix |
- {{ env.dnssuffix }} |
-
- {{ uneditedEnv.dnssuffix }}
- {{ env.dnssuffix }}
- |
-
-
- Provider |
- {{ env.provider }} |
-
- {{ uneditedEnv.provider }}
- {{ env.provider }}
- |
-
-
- Websocket Endpoint |
- {{ env.ws_endpoint }} |
-
- {{ uneditedEnv.ws_endpoint }}
- {{ env.ws_endpoint }}
- |
-
+
+
+ Display Name |
+ {{ env.display_name }} |
+
+ {{ uneditedEnv.display_name }}
+ {{ env.display_name }}
+ |
+
+
+ DNS Suffix |
+ {{ env.dnssuffix }} |
+
+ {{ uneditedEnv.dnssuffix }}
+ {{ env.dnssuffix }}
+ |
+
+
+ Provider |
+ {{ env.provider }} |
+
+ {{ uneditedEnv.provider }}
+ {{ env.provider }}
+ |
+
+
+ Websocket Endpoint |
+ {{ env.ws_endpoint }} |
+
+ {{ uneditedEnv.ws_endpoint }}
+ {{ env.ws_endpoint }}
+ |
+
+
+
+
+ Display Name |
+ {{ env.display_name }} |
+
+
+ DNS Suffix |
+ {{ env.dnssuffix }} |
+
+
+ Provider |
+ {{ env.provider }} |
+
+
+ Websocket Endpoint |
+ {{ env.ws_endpoint }} |
+
+
@@ -390,6 +410,7 @@ Environment Specifics
+
{{ item.key }} |
@@ -411,7 +432,14 @@ Environment Specifics
{{ item.key }} |
{{ item.value }} |
-
+
+
+
+ {{ item.key }} |
+ {{ item.value }} |
+
+
+
@@ -425,7 +453,8 @@ Template Mappings
-
+
+
{{ getVirtualMachineTemplateName(template.key) }} |
{{ getTemplateCount(template.key) }} |
@@ -481,6 +510,30 @@ Template Mappings
+
+
+
+ {{ template.key }} |
+ {{ getTemplateCount(template.key) }} |
+
+
+
+
+ Key |
+ Value |
+
+
+
+
+ {{ item.key }} |
+ {{ item.value }} |
+
+
+
+ |
+
+
+
@@ -493,7 +546,8 @@ IP Mappings
-
+
+
{{ item.key }} |
{{ item.value }} |
@@ -515,6 +569,13 @@ IP Mappings
{{ item.value }} |
+
+
+
+ {{ item.key }} |
+ {{ item.value }} |
+
+
From 3a4a465e6039291a4d2c1c696f32998a004665a1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan-Gerrit=20G=C3=B6bel?=
<86782124+jggoebel@users.noreply.github.com>
Date: Wed, 13 Mar 2024 09:32:51 +0100
Subject: [PATCH 6/6] Fix markdown no content (#205)
---
src/app/step/hf-markdown.component.ts | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/src/app/step/hf-markdown.component.ts b/src/app/step/hf-markdown.component.ts
index 3253da4f..93fe6ead 100644
--- a/src/app/step/hf-markdown.component.ts
+++ b/src/app/step/hf-markdown.component.ts
@@ -217,6 +217,10 @@ ${token}`;
}
ngOnChanges() {
+ if(!this.content){
+ return
+ }
+
const contentWithReplacedTokens = this.replaceSessionToken(
this.replaceVmInfoTokens(this.content),
);