@cryptotaxi247 / CoPilot / commits / dbd1b490

Frontend improvements (#218)

* . * updated helper class * added shikijs * removed highlightjs * updated markdown component * refactor * new pakcages --------- Co-authored-by: Davide Di Modica <webmaster.ddm@gmail.com>

taylor_socfortress committed May 20, 2024 at 11:03 UTC dbd1b490ef994970ff2e77514263536ac4b8b345
20 files changed +206 -283
.vscode/settings.json
+1
@@ -34,6 +34,7 @@
34 "redoc",
35 "rushstack",
36 "Shiki",
37 + "shikijs",
38 "signin",
39 "Socfortress",
40 "sparkline",
backend/app/agents/services/sync.py
+2 -1
@@ -21,7 +21,8 @@ from app.db.universal_models import Agents
21
22
23 async def fetch_wazuh_agents() -> WazuhAgentsList:
24 - """Fetch agents from Wazuh service.
24 + """
25 + Fetch agents from Wazuh service.
26
27 This function retrieves a list of agents from the Wazuh service.
28 It calls the `collect_wazuh_agents` function from the `wazuh_services` module
frontend/index.html
+1 -1
@@ -1,5 +1,5 @@
1 <!doctype html>
2 -<html lang="it">
2 +<html lang="en">
3 <head>
4 <meta name="robots" content="noindex, nofollow" />
5
frontend/package-lock.json
+30 -137
@@ -14,6 +14,7 @@
14 "@fontsource/lexend": "^5.0.20",
15 "@fontsource/public-sans": "^5.0.18",
16 "@popperjs/core": "^2.11.8",
17 + "@shikijs/markdown-it": "^1.6.0",
18 "@vueuse/components": "^10.9.0",
19 "@vueuse/core": "^10.9.0",
20 "apexcharts": "^3.49.1",
@@ -28,13 +29,13 @@
29 "jose": "^5.3.0",
30 "js-md5": "^0.8.3",
31 "lodash": "^4.17.21",
31 - "markdown-it-highlightjs": "^4.1.0",
32 "mitt": "^3.0.1",
33 "naive-ui": "^2.38.2",
34 "password-validator": "^5.3.0",
35 "pinia": "^2.1.7",
36 "pinia-plugin-persistedstate": "^3.2.1",
37 "secure-ls": "^1.2.6",
38 + "shiki": "^1.6.0",
39 "validator": "^13.12.0",
40 "vue": "^3.4.27",
41 "vue-advanced-cropper": "^2.8.8",
@@ -54,13 +55,9 @@
55 "@types/bytes": "^3.1.4",
56 "@types/file-saver": "^2.0.7",
57 "@types/fs-extra": "^11.0.4",
57 - "@types/highlight.js": "^10.1.0",
58 - "@types/html2canvas": "^1.0.0",
58 "@types/inquirer": "^9.0.7",
59 "@types/jsdom": "^21.1.6",
60 "@types/lodash": "^4.17.4",
62 - "@types/markdown-it": "^14.1.1",
63 - "@types/markdown-it-highlightjs": "^3.3.4",
61 "@types/node": "^20.12.12",
62 "@types/validator": "^13.11.10",
63 "@vitejs/plugin-vue": "^5.0.4",
@@ -84,7 +81,6 @@
81 "postcss": "^8.4.38",
82 "prettier": "^3.2.5",
83 "sass": "^1.77.2",
87 - "shiki": "^1.5.2",
84 "start-server-and-test": "^2.0.3",
85 "tailwind-config-viewer": "^2.0.2",
86 "tailwindcss": "^3.4.3",
@@ -664,7 +660,6 @@
660 },
661 "node_modules/@clack/prompts/node_modules/is-unicode-supported": {
662 "version": "1.3.0",
667 - "dev": true,
663 "inBundle": true,
664 "license": "MIT",
665 "engines": {
@@ -1844,10 +1839,27 @@
1839 "dev": true
1840 },
1841 "node_modules/@shikijs/core": {
1847 - "version": "1.5.2",
1848 - "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.5.2.tgz",
1849 - "integrity": "sha512-wSAOgaz48GmhILFElMCeQypSZmj6Ru6DttOOtl3KNkdJ17ApQuGNCfzpk4cClasVrnIu45++2DBwG4LNMQAfaA==",
1850 - "dev": true
1842 + "version": "1.6.0",
1843 + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.6.0.tgz",
1844 + "integrity": "sha512-NIEAi5U5R7BLkbW1pG/ZKu3eb1lzc3/+jD0lFsuxMT7zjaf9bbNwdNyMr7zh/Zl8EXQtQ+MYBAt5G+JLu+5DlA=="
1845 + },
1846 + "node_modules/@shikijs/markdown-it": {
1847 + "version": "1.6.0",
1848 + "resolved": "https://registry.npmjs.org/@shikijs/markdown-it/-/markdown-it-1.6.0.tgz",
1849 + "integrity": "sha512-FZBOyjgtRb3SgV5MSRdpS8h0fHkhVH7MlCJSVatA4RAYgFwjxuUtH22lGHnnn353cCQvx2Z/9t2qIV9bXXfcsQ==",
1850 + "dependencies": {
1851 + "@shikijs/transformers": "1.6.0",
1852 + "markdown-it": "^14.1.0",
1853 + "shiki": "1.6.0"
1854 + }
1855 + },
1856 + "node_modules/@shikijs/transformers": {
1857 + "version": "1.6.0",
1858 + "resolved": "https://registry.npmjs.org/@shikijs/transformers/-/transformers-1.6.0.tgz",
1859 + "integrity": "sha512-qGfHe1ECiqfE2STPWvfogIj/9Q0SK+MCRJdoITkW7AmFuB7DmbFnBT2US84+zklJOB51MzNO8RUXZiauWssJlQ==",
1860 + "dependencies": {
1861 + "shiki": "1.6.0"
1862 + }
1863 },
1864 "node_modules/@sideway/address": {
1865 "version": "4.1.5",
@@ -1919,26 +1931,6 @@
1931 "@types/node": "*"
1932 }
1933 },
1922 - "node_modules/@types/highlight.js": {
1923 - "version": "10.1.0",
1924 - "resolved": "https://registry.npmjs.org/@types/highlight.js/-/highlight.js-10.1.0.tgz",
1925 - "integrity": "sha512-77hF2dGBsOgnvZll1vymYiNUtqJ8cJfXPD6GG/2M0aLRc29PkvB7Au6sIDjIEFcSICBhCh2+Pyq6WSRS7LUm6A==",
1926 - "deprecated": "This is a stub types definition. highlight.js provides its own type definitions, so you do not need this installed.",
1927 - "dev": true,
1928 - "dependencies": {
1929 - "highlight.js": "*"
1930 - }
1931 - },
1932 - "node_modules/@types/html2canvas": {
1933 - "version": "1.0.0",
1934 - "resolved": "https://registry.npmjs.org/@types/html2canvas/-/html2canvas-1.0.0.tgz",
1935 - "integrity": "sha512-BJpVf+FIN9UERmzhbtUgpXj6XBZpG67FMgBLLoj9HZKd9XifcCpSV+UnFcwTZfEyun4U/KmCrrVOG7829L589w==",
1936 - "deprecated": "This is a stub types definition. html2canvas provides its own type definitions, so you do not need this installed.",
1937 - "dev": true,
1938 - "dependencies": {
1939 - "html2canvas": "*"
1940 - }
1941 - },
1934 "node_modules/@types/inquirer": {
1935 "version": "9.0.7",
1936 "resolved": "https://registry.npmjs.org/@types/inquirer/-/inquirer-9.0.7.tgz",
@@ -1979,12 +1971,6 @@
1971 "resolved": "https://registry.npmjs.org/@types/katex/-/katex-0.16.7.tgz",
1972 "integrity": "sha512-HMwFiRujE5PjrgwHQ25+bsLJgowjGjm5Z8FVSf0N6PwgJrwxH0QxzHYDcKsTfV3wva0vzrpqMTJS2jXPr5BMEQ=="
1973 },
1982 - "node_modules/@types/linkify-it": {
1983 - "version": "5.0.0",
1984 - "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz",
1985 - "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==",
1986 - "dev": true
1987 - },
1974 "node_modules/@types/lodash": {
1975 "version": "4.17.4",
1976 "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.4.tgz",
@@ -1998,41 +1984,6 @@
1984 "@types/lodash": "*"
1985 }
1986 },
2001 - "node_modules/@types/markdown-it": {
2002 - "version": "14.1.1",
2003 - "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.1.tgz",
2004 - "integrity": "sha512-4NpsnpYl2Gt1ljyBGrKMxFYAYvpqbnnkgP/i/g+NLpjEUa3obn1XJCur9YbEXKDAkaXqsR1LbDnGEJ0MmKFxfg==",
2005 - "dev": true,
2006 - "dependencies": {
2007 - "@types/linkify-it": "^5",
2008 - "@types/mdurl": "^2"
2009 - }
2010 - },
2011 - "node_modules/@types/markdown-it-highlightjs": {
2012 - "version": "3.3.4",
2013 - "resolved": "https://registry.npmjs.org/@types/markdown-it-highlightjs/-/markdown-it-highlightjs-3.3.4.tgz",
2014 - "integrity": "sha512-hERRPIvWifT0006DIjg1IvuoBzlksk97kPmWjynejzTW9AISS92b/mpu3PFkAWlXYNFC52RqdhNKjdJZ6GC4wg==",
2015 - "dev": true,
2016 - "dependencies": {
2017 - "@types/markdown-it": "*",
2018 - "highlight.js": "^10.1.0"
2019 - }
2020 - },
2021 - "node_modules/@types/markdown-it-highlightjs/node_modules/highlight.js": {
2022 - "version": "10.7.3",
2023 - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz",
2024 - "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==",
2025 - "dev": true,
2026 - "engines": {
2027 - "node": "*"
2028 - }
2029 - },
2030 - "node_modules/@types/mdurl": {
2031 - "version": "2.0.0",
2032 - "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz",
2033 - "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==",
2034 - "dev": true
2035 - },
1987 "node_modules/@types/node": {
1988 "version": "20.12.12",
1989 "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.12.tgz",
@@ -3455,9 +3406,9 @@
3406 "dev": true
3407 },
3408 "node_modules/axios": {
3458 - "version": "1.6.8",
3459 - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz",
3460 - "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==",
3409 + "version": "1.7.1",
3410 + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.1.tgz",
3411 + "integrity": "sha512-+LV37nQcd1EpFalkXksWNBiA17NZ5m5/WspmHGmZmdx1qBOg/VNq/c4eRJiA9VQQHBOs+N0ZhhdU10h2TyNK7Q==",
3412 "dev": true,
3413 "dependencies": {
3414 "follow-redirects": "^1.15.6",
@@ -3490,15 +3441,6 @@
3441 "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
3442 "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
3443 },
3493 - "node_modules/base64-arraybuffer": {
3494 - "version": "1.0.2",
3495 - "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
3496 - "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==",
3497 - "dev": true,
3498 - "engines": {
3499 - "node": ">= 0.6.0"
3500 - }
3501 - },
3444 "node_modules/base64-js": {
3445 "version": "1.5.1",
3446 "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
@@ -4160,15 +4102,6 @@
4102 "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz",
4103 "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q=="
4104 },
4163 - "node_modules/css-line-break": {
4164 - "version": "2.1.0",
4165 - "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",
4166 - "integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
4167 - "dev": true,
4168 - "dependencies": {
4169 - "utrie": "^1.0.2"
4170 - }
4171 - },
4105 "node_modules/css-render": {
4106 "version": "0.15.14",
4107 "resolved": "https://registry.npmjs.org/css-render/-/css-render-0.15.14.tgz",
@@ -6252,19 +6185,6 @@
6185 "url": "https://github.com/sponsors/sindresorhus"
6186 }
6187 },
6255 - "node_modules/html2canvas": {
6256 - "version": "1.4.1",
6257 - "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz",
6258 - "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
6259 - "dev": true,
6260 - "dependencies": {
6261 - "css-line-break": "^2.1.0",
6262 - "text-segmentation": "^1.0.3"
6263 - },
6264 - "engines": {
6265 - "node": ">=8.0.0"
6266 - }
6267 - },
6188 "node_modules/http-assert": {
6189 "version": "1.5.0",
6190 "resolved": "https://registry.npmjs.org/http-assert/-/http-assert-1.5.0.tgz",
@@ -7777,14 +7697,6 @@
7697 "markdown-it": "bin/markdown-it.mjs"
7698 }
7699 },
7780 - "node_modules/markdown-it-highlightjs": {
7781 - "version": "4.1.0",
7782 - "resolved": "https://registry.npmjs.org/markdown-it-highlightjs/-/markdown-it-highlightjs-4.1.0.tgz",
7783 - "integrity": "sha512-aYcgme5aYn10BHEvLZaCNgwxU2oaAX9inK9dwCv38wJdq7tal5FzZrLdQQY8MR3I1H07S3BKgYGRX2kKuPT+sA==",
7784 - "dependencies": {
7785 - "highlight.js": "^11.9.0"
7786 - }
7787 - },
7700 "node_modules/mdn-data": {
7701 "version": "2.0.30",
7702 "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz",
@@ -9765,12 +9677,11 @@
9677 }
9678 },
9679 "node_modules/shiki": {
9768 - "version": "1.5.2",
9769 - "resolved": "https://registry.npmjs.org/shiki/-/shiki-1.5.2.tgz",
9770 - "integrity": "sha512-fpPbuSaatinmdGijE7VYUD3hxLozR3ZZ+iAx8Iy2X6REmJGyF5hQl94SgmiUNTospq346nXUVZx0035dyGvIVw==",
9771 - "dev": true,
9680 + "version": "1.6.0",
9681 + "resolved": "https://registry.npmjs.org/shiki/-/shiki-1.6.0.tgz",
9682 + "integrity": "sha512-P31ROeXcVgW/k3Z+vUUErcxoTah7ZRaimctOpzGuqAntqnnSmx1HOsvnbAB8Z2qfXPRhw61yptAzCsuKOhTHwQ==",
9683 "dependencies": {
9773 - "@shikijs/core": "1.5.2"
9684 + "@shikijs/core": "1.6.0"
9685 }
9686 },
9687 "node_modules/side-channel": {
@@ -10535,15 +10446,6 @@
10446 "url": "https://github.com/sponsors/antfu"
10447 }
10448 },
10538 - "node_modules/text-segmentation": {
10539 - "version": "1.0.3",
10540 - "resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz",
10541 - "integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
10542 - "dev": true,
10543 - "dependencies": {
10544 - "utrie": "^1.0.2"
10545 - }
10546 - },
10449 "node_modules/text-table": {
10450 "version": "0.2.0",
10451 "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
@@ -11050,15 +10952,6 @@
10952 "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
10953 "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
10954 },
11053 - "node_modules/utrie": {
11054 - "version": "1.0.2",
11055 - "resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz",
11056 - "integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
11057 - "dev": true,
11058 - "dependencies": {
11059 - "base64-arraybuffer": "^1.0.2"
11060 - }
11061 - },
10955 "node_modules/uuid": {
10956 "version": "8.3.2",
10957 "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
frontend/package.json
+3 -5
@@ -40,6 +40,7 @@
40 "@fontsource/lexend": "^5.0.20",
41 "@fontsource/public-sans": "^5.0.18",
42 "@popperjs/core": "^2.11.8",
43 + "@shikijs/markdown-it": "^1.6.0",
44 "@vueuse/components": "^10.9.0",
45 "@vueuse/core": "^10.9.0",
46 "apexcharts": "^3.49.1",
@@ -54,14 +55,13 @@
55 "jose": "^5.3.0",
56 "js-md5": "^0.8.3",
57 "lodash": "^4.17.21",
57 - "markdown-it-highlightjs": "^4.1.0",
58 "mitt": "^3.0.1",
59 "naive-ui": "^2.38.2",
60 "password-validator": "^5.3.0",
61 "pinia": "^2.1.7",
62 "pinia-plugin-persistedstate": "^3.2.1",
63 "secure-ls": "^1.2.6",
64 - "shiki": "^1.5.2",
64 + "shiki": "^1.6.0",
65 "validator": "^13.12.0",
66 "vue": "^3.4.27",
67 "vue-advanced-cropper": "^2.8.8",
@@ -84,8 +84,6 @@
84 "@types/inquirer": "^9.0.7",
85 "@types/jsdom": "^21.1.6",
86 "@types/lodash": "^4.17.4",
87 - "@types/markdown-it": "^14.1.1",
88 - "@types/markdown-it-highlightjs": "^3.3.4",
87 "@types/node": "^20.12.12",
88 "@types/validator": "^13.11.10",
89 "@vitejs/plugin-vue": "^5.0.4",
@@ -124,4 +122,4 @@
122 "engines": {
123 "node": ">=18.0.0"
124 }
127 -}
125 +}
\ No newline at end of file
frontend/src/App.vue
+9 -5
@@ -45,13 +45,17 @@ const layoutComponents = {
45 Blank
46 }
47
48 +const mainStore = useMainStore()
49 +const themeStore = useThemeStore()
50 +const authStore = useAuthStore()
51 +
52 const forceLayout = ref<Layout | null>(null)
49 -const forceRefresh = computed<number>(() => useMainStore().forceRefresh)
50 -const layout = computed<Layout>(() => useThemeStore().layout)
53 +const forceRefresh = computed<number>(() => mainStore.forceRefresh)
54 +const layout = computed<Layout>(() => themeStore.layout)
55 const layoutComponent = computed<Component>(() => layoutComponents[forceLayout.value || layout.value])
52 -const routerTransition = computed<RouterTransition>(() => useThemeStore().routerTransition)
53 -const themeName = computed<ThemeName>(() => useThemeStore().themeName)
54 -const isLogged = computed(() => useAuthStore().isLogged)
56 +const routerTransition = computed<RouterTransition>(() => themeStore.routerTransition)
57 +const themeName = computed<ThemeName>(() => themeStore.themeName)
58 +const isLogged = computed(() => authStore.isLogged)
59
60 function checkForcedLayout(route: RouteLocationNormalized) {
61 if (route.meta?.forceLayout) {
frontend/src/assets/scss/helpers.scss
+6
@@ -23,6 +23,12 @@
23 }
24 }
25
26 +.code-bg-transparent {
27 + code {
28 + background-color: transparent;
29 + }
30 +}
31 +
32 .item-appear {
33 &.item-appear-bottom {
34 animation: item-fade-bottom 0.3s forwards;
frontend/src/assets/scss/index.scss
+21
@@ -198,3 +198,24 @@ mark {
198 }
199 }
200 }
201 +
202 +html.theme-dark .shiki,
203 +html.theme-dark .shiki span {
204 + color: var(--shiki-dark) !important;
205 + //background-color: var(--shiki-dark-bg) !important;
206 + /* Optional, if you also want font styles */
207 + font-style: var(--shiki-dark-font-style) !important;
208 + font-weight: var(--shiki-dark-font-weight) !important;
209 + text-decoration: var(--shiki-dark-text-decoration) !important;
210 +}
211 +html.theme-dark,
212 +html.theme-light {
213 + .shiki {
214 + overflow: hidden;
215 + background-color: transparent !important;
216 +
217 + span {
218 + background-color: transparent !important;
219 + }
220 + }
221 +}
frontend/src/components/activeResponse/ActiveResponseDetails.vue
+5 -1
@@ -1,7 +1,11 @@
1 <template>
2 <div class="active-response-details">
3 <n-spin :show="loadingActiveResponse" class="min-h-48">
4 - <Markdown v-if="activeResponseDetails?.markdown_content" :source="activeResponseDetails.markdown_content" />
4 + <template v-if="activeResponseDetails?.markdown_content">
5 + <Suspense>
6 + <Markdown :source="activeResponseDetails.markdown_content" />
7 + </Suspense>
8 + </template>
9 <template v-else>
10 <n-empty description="No description found" class="justify-center h-48" v-if="!loadingActiveResponse" />
11 </template>
frontend/src/components/agents/sca/ScaResultItemDetails.vue
+4 -9
@@ -11,8 +11,8 @@
11 data.result === 'failed'
12 ? 'text-error-color'
13 : data.result === 'not applicable'
14 - ? 'text-warning-color'
15 - : 'text-success-color'
14 + ? 'text-warning-color'
15 + : 'text-success-color'
16 "
17 >
18 {{ data.result }}
@@ -30,8 +30,8 @@
30 <div class="px-7">
31 <n-card content-class="bg-secondary-color !p-0" class="overflow-hidden">
32 <div
33 - class="scrollbar-styled overflow-hidden"
34 - v-shiki="{ theme: codeTheme, lang: 'shell', decode: true }"
33 + class="scrollbar-styled overflow-hidden code-bg-transparent"
34 + v-shiki="{ lang: 'shell', decode: true }"
35 >
36 <pre v-html="data.command"></pre>
37 </div>
@@ -143,17 +143,12 @@ import KVCard from "@/components/common/KVCard.vue"
143 import { computed } from "vue"
144 import { NTabs, NTabPane, NStatistic, NInput, NCard } from "naive-ui"
145 import type { ScaPolicyResult } from "@/types/agents"
146 -import { useThemeStore } from "@/stores/theme"
146
147 const { data } = defineProps<{
148 data: ScaPolicyResult
149 }>()
150
152 -const themeStore = useThemeStore()
153 -const codeTheme = computed(() => (themeStore.isThemeDark ? "dark" : "light"))
151 const properties = computed(() => {
152 return _pick(data, ["id", "policy_id", "title"])
153 })
154 </script>
158 -
159 -<style lang="scss" scoped></style>
frontend/src/components/alerts/AlertWazuhRules.vue
+1 -4
@@ -1,7 +1,7 @@
1 <template>
2 <n-tabs type="line" animated :tabs-padding="24">
3 <n-tab-pane name="Wazuh Rules" tab="Wazuh Rules" display-directive="show">
4 - <div class="p-7 pt-4 scrollbar-styled" v-shiki="{ theme: codeTheme, lang: 'xml' }">
4 + <div class="p-7 pt-4 scrollbar-styled code-bg-transparent" v-shiki="{ lang: 'xml' }">
5 <pre v-html="wazuh_rule"></pre>
6 </div>
7 </n-tab-pane>
@@ -24,7 +24,6 @@
24
25 <script setup lang="ts">
26 import vShiki from "@/directives/v-shiki"
27 -import { useThemeStore } from "@/stores/theme"
27 import { computed, toRefs } from "vue"
28 import { NTabs, NTabPane, NInput } from "naive-ui"
29 import type { WazuhRuleExclude } from "@/types/alerts.d"
@@ -32,8 +31,6 @@ import type { WazuhRuleExclude } from "@/types/alerts.d"
31 const props = defineProps<{ data: WazuhRuleExclude }>()
32 const { data } = toRefs(props)
33
35 -const themeStore = useThemeStore()
36 -const codeTheme = computed(() => (themeStore.isThemeDark ? "dark" : "light"))
34 const wazuh_rule = computed(() => data.value.wazuh_rule.replace(/\\\\/gim, "\\\\\\\\"))
35 </script>
36
frontend/src/components/auth/SignIn.vue
+3 -1
@@ -27,7 +27,9 @@
27 </div>
28 -->
29 <div class="w-full">
30 - <n-button type="primary" @click="signIn" class="!w-full" size="large">Sign in</n-button>
30 + <n-button type="primary" @click="signIn" class="!w-full" size="large" :loading="loading">
31 + Sign in
32 + </n-button>
33 </div>
34 </div>
35 </n-form>
frontend/src/components/common/Markdown.vue
+22 -25
@@ -1,38 +1,35 @@
1 <template>
2 - <vue-markdown-it
3 - :source="source"
4 - preset="commonmark"
5 - :plugins="[[markdownItHighlightjs, { hljs, auto: true, code: true, inline: false, ignoreIllegals: true }]]"
6 - class="markdown-style scrollbar-styled"
7 - :class="{ transparent }"
8 - />
2 + <Suspense>
3 + <vue-markdown-it
4 + :source="source"
5 + preset="commonmark"
6 + :plugins="[
7 + [
8 + fromHighlighter(highlighter, {
9 + themes: codeThemes
10 + })
11 + ]
12 + ]"
13 + class="markdown-style scrollbar-styled"
14 + :class="{ codeBgTransparent }"
15 + />
16 + </Suspense>
17 </template>
18
19 <script setup lang="ts">
12 -// TODO: replace highlightjs with shiki
20 import { toRefs } from "vue"
14 -import markdownItHighlightjs from "markdown-it-highlightjs/core"
15 -import "@/assets/scss/hljs.scss"
21 import { VueMarkdownIt } from "@f3ve/vue-markdown-it"
22 +import { getHighlighter, codeThemes } from "@/utils/highlighter"
23 +import { fromHighlighter } from "@shikijs/markdown-it/core"
24 +import type { HighlighterGeneric } from "shiki/core"
25
18 -import hljs from "highlight.js/lib/core"
19 -import powershell from "highlight.js/lib/languages/powershell"
20 -import bash from "highlight.js/lib/languages/bash"
21 -import json from "highlight.js/lib/languages/json"
22 -import xml from "highlight.js/lib/languages/xml"
23 -import yaml from "highlight.js/lib/languages/yaml"
24 -
25 -hljs.registerLanguage("powershell", powershell)
26 -hljs.registerLanguage("bash", bash)
27 -hljs.registerLanguage("json", json)
28 -hljs.registerLanguage("xml", xml)
29 -hljs.registerLanguage("yaml", yaml)
26 +const highlighter: HighlighterGeneric<any, any> = (await getHighlighter()) as unknown as HighlighterGeneric<any, any>
27
28 const props = defineProps<{
29 source: string
33 - transparent?: boolean
30 + codeBgTransparent?: boolean
31 }>()
35 -const { source, transparent } = toRefs(props)
32 +const { source, codeBgTransparent } = toRefs(props)
33 </script>
34
35 <style lang="scss" scoped>
@@ -43,7 +40,7 @@ const { source, transparent } = toRefs(props)
40 }
41 }
42
46 - &.transparent {
43 + &.codeBgTransparent {
44 :deep() {
45 & > pre {
46 & > code {
frontend/src/components/license/LicenseDetails.vue
+3 -1
@@ -72,7 +72,9 @@
72 </span>
73 </template>
74 <template #value>
75 - <Markdown :source="dockerCompose" transparent />
75 + <Suspense>
76 + <Markdown :source="dockerCompose" codeBgTransparent />
77 + </Suspense>
78 </template>
79 </KVCard>
80 </div>
frontend/src/components/services/Item.vue
+3 -1
@@ -41,7 +41,9 @@
41 :bordered="false"
42 segmented
43 >
44 - <Markdown :source="data.details" />
44 + <Suspense>
45 + <Markdown :source="data.details" />
46 + </Suspense>
47 </n-modal>
48 </div>
49 </template>
frontend/src/directives/v-hl.ts deleted
-61
@@ -1,61 +0,0 @@
1 -import hljs from "highlight.js/lib/core"
2 -import javascript from "highlight.js/lib/languages/javascript"
3 -import typescript from "highlight.js/lib/languages/typescript"
4 -import xml from "highlight.js/lib/languages/xml"
5 -import scss from "highlight.js/lib/languages/scss"
6 -import css from "highlight.js/lib/languages/css"
7 -import powershell from "highlight.js/lib/languages/powershell"
8 -import bash from "highlight.js/lib/languages/bash"
9 -import json from "highlight.js/lib/languages/json"
10 -import yaml from "highlight.js/lib/languages/yaml"
11 -//import "highlight.js/styles/monokai.css"
12 -import "highlight.js/styles/atom-one-dark.css"
13 -
14 -hljs.registerLanguage("javascript", javascript)
15 -hljs.registerLanguage("typescript", typescript)
16 -hljs.registerLanguage("html", xml)
17 -hljs.registerLanguage("scss", scss)
18 -hljs.registerLanguage("css", css)
19 -hljs.registerLanguage("powershell", powershell)
20 -hljs.registerLanguage("bash", bash)
21 -hljs.registerLanguage("json", json)
22 -hljs.registerLanguage("xml", xml)
23 -hljs.registerLanguage("yaml", yaml)
24 -
25 -const vHl = {
26 - created: (el: HTMLElement, binding: { arg: string }) => {
27 - if (binding.arg) {
28 - el.innerHTML = hljs.highlight(el.children[0].innerHTML, { language: binding.arg }).value
29 - } else {
30 - el.innerHTML = hljs.highlightAuto(el.children[0].innerHTML).value
31 - }
32 - resetIndent(el)
33 - }
34 -}
35 -
36 -function resetIndent(el: HTMLElement) {
37 - if (el) {
38 - let lines: string[] = el.innerHTML?.split("\n")
39 -
40 - if (lines?.length) {
41 - if (lines[0] === "") {
42 - lines.shift()
43 - }
44 -
45 - const matches = /^[\s\t]+/.exec(lines[0])
46 - const indentation = matches !== null ? matches[0] : null
47 - if (indentation) {
48 - lines = lines.map(line => {
49 - line = line.replace(indentation, "")
50 - return line.replace(/\t/g, " ")
51 - })
52 -
53 - el.innerHTML = lines.join("\n").trim()
54 - }
55 - }
56 - }
57 -}
58 -
59 -export { hljs, resetIndent }
60 -
61 -export default vHl
frontend/src/directives/v-shiki.ts
+4 -9
@@ -1,12 +1,9 @@
1 -import { codeToHtml } from "shiki"
1 import flourite from "flourite"
2 import { decode } from "html-entities"
3 +import { codeThemes, getHighlighter } from "@/utils/highlighter"
4
5 const vShiki = {
6 - created: async (
7 - el: HTMLElement,
8 - binding: { value: { theme?: "dark" | "light"; lang?: string; decode?: boolean } }
9 - ) => {
6 + created: async (el: HTMLElement, binding: { value: { lang?: string; decode?: boolean } }) => {
7 const code = binding?.value?.decode ? decode(el.children[0].innerHTML) : el.children[0].innerHTML
8
9 let flouriteDetect = null
@@ -18,14 +15,12 @@ const vShiki = {
15 }
16
17 const language = binding?.value?.lang || flouriteDetect || "text"
21 - const html = await codeToHtml(code, {
18 + const html = (await getHighlighter()).codeToHtml(code, {
19 lang: language,
23 - theme: binding?.value?.theme === "light" ? "slack-ochin" : "aurora-x"
20 + themes: codeThemes
21 })
22 el.innerHTML = html
23 }
24 }
25
29 -export { codeToHtml }
30 -
26 export default vShiki
frontend/src/layouts/common/Provider.vue
+36 -14
@@ -16,7 +16,7 @@
16 </template>
17
18 <script lang="ts" setup>
19 -import { computed, onBeforeMount, watch } from "vue"
19 +import { computed, watch } from "vue"
20 import {
21 NGlobalStyle,
22 NConfigProvider,
@@ -29,19 +29,38 @@ import {
29 import { useThemeStore } from "@/stores/theme"
30 import { useWindowSize } from "@vueuse/core"
31 import GlobalListener from "@/layouts/common/GlobalListener.vue"
32 +import type { ThemeName } from "@/types/theme.d"
33
34 const { width } = useWindowSize()
35
35 -const theme = computed(() => useThemeStore().naiveTheme)
36 -const themeOverrides = computed<GlobalThemeOverrides>(() => useThemeStore().themeOverrides)
37 -const style = computed<CSSStyleDeclaration>(() => useThemeStore().style)
36 +const themeStore = useThemeStore()
37
39 -watch(style, () => {
40 - setGlobalVars()
41 -})
42 -watch(width, () => {
43 - useThemeStore().updateVars()
44 -})
38 +const theme = computed(() => themeStore.naiveTheme)
39 +const themeOverrides = computed<GlobalThemeOverrides>(() => themeStore.themeOverrides)
40 +const style = computed<CSSStyleDeclaration>(() => themeStore.style)
41 +const themeName = computed<ThemeName>(() => themeStore.themeName)
42 +
43 +watch(
44 + style,
45 + () => {
46 + setGlobalVars()
47 + },
48 + { immediate: true }
49 +)
50 +watch(
51 + themeName,
52 + (val, old) => {
53 + setThemeName(val, old)
54 + },
55 + { immediate: true }
56 +)
57 +watch(
58 + width,
59 + () => {
60 + themeStore.updateVars()
61 + },
62 + { immediate: true }
63 +)
64
65 function setGlobalVars() {
66 const html = document.children[0] as HTMLElement
@@ -51,8 +70,11 @@ function setGlobalVars() {
70 }
71 }
72
54 -onBeforeMount(() => {
55 - useThemeStore().updateVars()
56 - setGlobalVars()
57 -})
73 +function setThemeName(val: ThemeName, old?: ThemeName) {
74 + const html = document.children[0] as HTMLElement
75 + if (old) {
76 + html.classList.remove(`theme-${old}`)
77 + }
78 + html.classList.add(`theme-${val}`)
79 +}
80 </script>
frontend/src/utils/highlighter.ts new
+52
@@ -0,0 +1,52 @@
1 +import { getHighlighterCore } from "shiki/core"
2 +import getWasm from "shiki/wasm"
3 +
4 +const THEME_LIGHT = "slack-ochin"
5 +const THEME_DARK = "aurora-x"
6 +
7 +export async function getHighlighter() {
8 + return await getHighlighterCore({
9 + themes: [import("shiki/themes/slack-ochin.mjs"), import("shiki/themes/aurora-x.mjs")],
10 + langs: [
11 + import("shiki/langs/javascript.mjs"),
12 + import("shiki/langs/typescript.mjs"),
13 + import("shiki/langs/powershell.mjs"),
14 + import("shiki/langs/shellscript.mjs"),
15 + import("shiki/langs/json.mjs"),
16 + import("shiki/langs/xml.mjs"),
17 + import("shiki/langs/yaml.mjs"),
18 + import("shiki/langs/html.mjs"),
19 + import("shiki/langs/scss.mjs"),
20 + import("shiki/langs/css.mjs")
21 + ],
22 + loadWasm: getWasm
23 + })
24 +}
25 +
26 +export const codeThemes = {
27 + light: THEME_LIGHT,
28 + dark: THEME_DARK
29 +}
30 +
31 +export function resetIndent(el: HTMLElement) {
32 + if (el) {
33 + let lines: string[] = el.innerHTML?.split("\n")
34 +
35 + if (lines?.length) {
36 + if (lines[0] === "") {
37 + lines.shift()
38 + }
39 +
40 + const matches = /^[\s\t]+/.exec(lines[0])
41 + const indentation = matches !== null ? matches[0] : null
42 + if (indentation) {
43 + lines = lines.map(line => {
44 + line = line.replace(indentation, "")
45 + return line.replace(/\t/g, " ")
46 + })
47 +
48 + el.innerHTML = lines.join("\n").trim()
49 + }
50 + }
51 + }
52 +}
frontend/src/vite-env.d.ts
-8
@@ -11,11 +11,3 @@ declare module "*.svg" {
11 const component: DefineComponent
12 export default component
13 }
14 -
15 -declare module "markdown-it-highlightjs/core" {
16 - export { default } from "markdown-it-highlightjs/types/core.d.ts"
17 -}
18 -
19 -declare module "highlight.js/lib/core" {
20 - export { default } from "highlight.js/types/index.d.ts"
21 -}