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
-}