@cryptotaxi247 / CoPilot / commits / 956dd25c

Update template (#327)

* `chore: Add route for markdown template` * refactor: lint tailwind classes * refactor: updated scss overrides path * refactor: update classes * refactor: common cards path * chore: update dependencies in frontend * feat: add CardEntity component * refactor: cards * fix: i18n store type * build latest image * back to main * refactor: update Wazuh API endpoint for agent retrieval * refactor: cards * refactor: lint * chore: update dependencies in frontend * refactor: cards * refactor: list & cards * refactor: cards * refactor: lint * refactor: cards * refactor: cards * refactor: cards * chore: update dependencies in frontend * precommit fixes --------- Co-authored-by: Davide Di Modica <webmaster.ddm@gmail.com>

taylor_socfortress committed Oct 25, 2024 at 13:53 UTC 956dd25c144557113679a3242c9236e2cf281ac5
272 files changed +15355 -20545
.github/workflows/docker.yml
+2 -2
@@ -27,7 +27,7 @@ jobs:
27 with:
28 context: ./backend
29 push: true
30 - tags: ghcr.io/socfortress/copilot-backend:lab
30 + tags: ghcr.io/socfortress/copilot-backend:latest
31 build-args: |
32 COPILOT_API_KEY=${{ secrets.COPILOT_API_KEY }}
33
@@ -60,7 +60,7 @@ jobs:
60 with:
61 context: ./frontend
62 push: true
63 - tags: ghcr.io/socfortress/copilot-frontend:lab
63 + tags: ghcr.io/socfortress/copilot-frontend:latest
64
65 - name: Notify Discord
66 uses: appleboy/discord-action@v1.0.0
.prettierrc.json
+4 -1
@@ -5,5 +5,8 @@
5 "printWidth": 120,
6 "trailingComma": "none",
7 "arrowParens": "avoid",
8 - "htmlWhitespaceSensitivity": "ignore"
8 + "htmlWhitespaceSensitivity": "ignore",
9 + "plugins": [
10 + "prettier-plugin-tailwindcss"
11 + ]
12 }
backend/app/customer_provisioning/services/wazuh_manager.py
+1 -1
@@ -181,7 +181,7 @@ async def get_agent_ids(group_code: str) -> List[str]:
181 """
182 try:
183 response = await send_wazuh_get_request(
184 - endpoint="agents",
184 + endpoint="/agents",
185 params={"group": group_code},
186 )
187 logger.info(f"Response for {group_code}: {response}")
backend/app/incidents/routes/incident_report.py
+3
@@ -199,3 +199,6 @@ async def get_cases_export_docx_route(
199 cleanup_temp_files([tmp_template_name])
200
201 return response
202 +
203 +
204 +# ! TODO: ROUTE FOR MARKDOWN TEMPLATE ! #
frontend/figma-tokens.json
+624
@@ -92,6 +92,18 @@
92 "value": "rgba(255, 182, 0, 0.6)",
93 "type": "color"
94 },
95 + "color-light-primary-070": {
96 + "value": "rgba(255, 182, 0, 0.7)",
97 + "type": "color"
98 + },
99 + "color-light-primary-080": {
100 + "value": "rgba(255, 182, 0, 0.8)",
101 + "type": "color"
102 + },
103 + "color-light-primary-090": {
104 + "value": "rgba(255, 182, 0, 0.9)",
105 + "type": "color"
106 + },
107 "color-light-info": {
108 "value": "#6267FF",
109 "type": "color"
@@ -112,18 +124,162 @@
124 "value": "rgba(98, 103, 255, 0.05)",
125 "type": "color"
126 },
127 + "color-light-info-010": {
128 + "value": "rgba(98, 103, 255, 0.1)",
129 + "type": "color"
130 + },
131 + "color-light-info-020": {
132 + "value": "rgba(98, 103, 255, 0.2)",
133 + "type": "color"
134 + },
135 + "color-light-info-030": {
136 + "value": "rgba(98, 103, 255, 0.3)",
137 + "type": "color"
138 + },
139 + "color-light-info-040": {
140 + "value": "rgba(98, 103, 255, 0.4)",
141 + "type": "color"
142 + },
143 + "color-light-info-050": {
144 + "value": "rgba(98, 103, 255, 0.5)",
145 + "type": "color"
146 + },
147 + "color-light-info-060": {
148 + "value": "rgba(98, 103, 255, 0.6)",
149 + "type": "color"
150 + },
151 + "color-light-info-070": {
152 + "value": "rgba(98, 103, 255, 0.7)",
153 + "type": "color"
154 + },
155 + "color-light-info-080": {
156 + "value": "rgba(98, 103, 255, 0.8)",
157 + "type": "color"
158 + },
159 + "color-light-info-090": {
160 + "value": "rgba(98, 103, 255, 0.9)",
161 + "type": "color"
162 + },
163 "color-light-success-005": {
164 "value": "rgba(0, 178, 123, 0.05)",
165 "type": "color"
166 },
167 + "color-light-success-010": {
168 + "value": "rgba(0, 178, 123, 0.1)",
169 + "type": "color"
170 + },
171 + "color-light-success-020": {
172 + "value": "rgba(0, 178, 123, 0.2)",
173 + "type": "color"
174 + },
175 + "color-light-success-030": {
176 + "value": "rgba(0, 178, 123, 0.3)",
177 + "type": "color"
178 + },
179 + "color-light-success-040": {
180 + "value": "rgba(0, 178, 123, 0.4)",
181 + "type": "color"
182 + },
183 + "color-light-success-050": {
184 + "value": "rgba(0, 178, 123, 0.5)",
185 + "type": "color"
186 + },
187 + "color-light-success-060": {
188 + "value": "rgba(0, 178, 123, 0.6)",
189 + "type": "color"
190 + },
191 + "color-light-success-070": {
192 + "value": "rgba(0, 178, 123, 0.7)",
193 + "type": "color"
194 + },
195 + "color-light-success-080": {
196 + "value": "rgba(0, 178, 123, 0.8)",
197 + "type": "color"
198 + },
199 + "color-light-success-090": {
200 + "value": "rgba(0, 178, 123, 0.9)",
201 + "type": "color"
202 + },
203 "color-light-warning-005": {
204 "value": "rgba(227, 194, 47, 0.05)",
205 "type": "color"
206 },
207 + "color-light-warning-010": {
208 + "value": "rgba(227, 194, 47, 0.1)",
209 + "type": "color"
210 + },
211 + "color-light-warning-020": {
212 + "value": "rgba(227, 194, 47, 0.2)",
213 + "type": "color"
214 + },
215 + "color-light-warning-030": {
216 + "value": "rgba(227, 194, 47, 0.3)",
217 + "type": "color"
218 + },
219 + "color-light-warning-040": {
220 + "value": "rgba(227, 194, 47, 0.4)",
221 + "type": "color"
222 + },
223 + "color-light-warning-050": {
224 + "value": "rgba(227, 194, 47, 0.5)",
225 + "type": "color"
226 + },
227 + "color-light-warning-060": {
228 + "value": "rgba(227, 194, 47, 0.6)",
229 + "type": "color"
230 + },
231 + "color-light-warning-070": {
232 + "value": "rgba(227, 194, 47, 0.7)",
233 + "type": "color"
234 + },
235 + "color-light-warning-080": {
236 + "value": "rgba(227, 194, 47, 0.8)",
237 + "type": "color"
238 + },
239 + "color-light-warning-090": {
240 + "value": "rgba(227, 194, 47, 0.9)",
241 + "type": "color"
242 + },
243 "color-light-error-005": {
244 "value": "rgba(255, 1, 86, 0.05)",
245 "type": "color"
246 },
247 + "color-light-error-010": {
248 + "value": "rgba(255, 1, 86, 0.1)",
249 + "type": "color"
250 + },
251 + "color-light-error-020": {
252 + "value": "rgba(255, 1, 86, 0.2)",
253 + "type": "color"
254 + },
255 + "color-light-error-030": {
256 + "value": "rgba(255, 1, 86, 0.3)",
257 + "type": "color"
258 + },
259 + "color-light-error-040": {
260 + "value": "rgba(255, 1, 86, 0.4)",
261 + "type": "color"
262 + },
263 + "color-light-error-050": {
264 + "value": "rgba(255, 1, 86, 0.5)",
265 + "type": "color"
266 + },
267 + "color-light-error-060": {
268 + "value": "rgba(255, 1, 86, 0.6)",
269 + "type": "color"
270 + },
271 + "color-light-error-070": {
272 + "value": "rgba(255, 1, 86, 0.7)",
273 + "type": "color"
274 + },
275 + "color-light-error-080": {
276 + "value": "rgba(255, 1, 86, 0.8)",
277 + "type": "color"
278 + },
279 + "color-light-error-090": {
280 + "value": "rgba(255, 1, 86, 0.9)",
281 + "type": "color"
282 + },
283 "color-light-secondary-1": {
284 "value": "rgb(98, 103, 255)",
285 "type": "color"
@@ -292,6 +448,18 @@
448 "value": "rgba(255, 182, 0, 0.6)",
449 "type": "color"
450 },
451 + "color-dark-primary-070": {
452 + "value": "rgba(255, 182, 0, 0.7)",
453 + "type": "color"
454 + },
455 + "color-dark-primary-080": {
456 + "value": "rgba(255, 182, 0, 0.8)",
457 + "type": "color"
458 + },
459 + "color-dark-primary-090": {
460 + "value": "rgba(255, 182, 0, 0.9)",
461 + "type": "color"
462 + },
463 "color-dark-info": {
464 "value": "#6267FF",
465 "type": "color"
@@ -312,18 +480,162 @@
480 "value": "rgba(98, 103, 255, 0.05)",
481 "type": "color"
482 },
483 + "color-dark-info-010": {
484 + "value": "rgba(98, 103, 255, 0.1)",
485 + "type": "color"
486 + },
487 + "color-dark-info-020": {
488 + "value": "rgba(98, 103, 255, 0.2)",
489 + "type": "color"
490 + },
491 + "color-dark-info-030": {
492 + "value": "rgba(98, 103, 255, 0.3)",
493 + "type": "color"
494 + },
495 + "color-dark-info-040": {
496 + "value": "rgba(98, 103, 255, 0.4)",
497 + "type": "color"
498 + },
499 + "color-dark-info-050": {
500 + "value": "rgba(98, 103, 255, 0.5)",
501 + "type": "color"
502 + },
503 + "color-dark-info-060": {
504 + "value": "rgba(98, 103, 255, 0.6)",
505 + "type": "color"
506 + },
507 + "color-dark-info-070": {
508 + "value": "rgba(98, 103, 255, 0.7)",
509 + "type": "color"
510 + },
511 + "color-dark-info-080": {
512 + "value": "rgba(98, 103, 255, 0.8)",
513 + "type": "color"
514 + },
515 + "color-dark-info-090": {
516 + "value": "rgba(98, 103, 255, 0.9)",
517 + "type": "color"
518 + },
519 "color-dark-success-005": {
520 "value": "rgba(0, 178, 123, 0.05)",
521 "type": "color"
522 },
523 + "color-dark-success-010": {
524 + "value": "rgba(0, 178, 123, 0.1)",
525 + "type": "color"
526 + },
527 + "color-dark-success-020": {
528 + "value": "rgba(0, 178, 123, 0.2)",
529 + "type": "color"
530 + },
531 + "color-dark-success-030": {
532 + "value": "rgba(0, 178, 123, 0.3)",
533 + "type": "color"
534 + },
535 + "color-dark-success-040": {
536 + "value": "rgba(0, 178, 123, 0.4)",
537 + "type": "color"
538 + },
539 + "color-dark-success-050": {
540 + "value": "rgba(0, 178, 123, 0.5)",
541 + "type": "color"
542 + },
543 + "color-dark-success-060": {
544 + "value": "rgba(0, 178, 123, 0.6)",
545 + "type": "color"
546 + },
547 + "color-dark-success-070": {
548 + "value": "rgba(0, 178, 123, 0.7)",
549 + "type": "color"
550 + },
551 + "color-dark-success-080": {
552 + "value": "rgba(0, 178, 123, 0.8)",
553 + "type": "color"
554 + },
555 + "color-dark-success-090": {
556 + "value": "rgba(0, 178, 123, 0.9)",
557 + "type": "color"
558 + },
559 "color-dark-warning-005": {
560 "value": "rgba(227, 194, 47, 0.05)",
561 "type": "color"
562 },
563 + "color-dark-warning-010": {
564 + "value": "rgba(227, 194, 47, 0.1)",
565 + "type": "color"
566 + },
567 + "color-dark-warning-020": {
568 + "value": "rgba(227, 194, 47, 0.2)",
569 + "type": "color"
570 + },
571 + "color-dark-warning-030": {
572 + "value": "rgba(227, 194, 47, 0.3)",
573 + "type": "color"
574 + },
575 + "color-dark-warning-040": {
576 + "value": "rgba(227, 194, 47, 0.4)",
577 + "type": "color"
578 + },
579 + "color-dark-warning-050": {
580 + "value": "rgba(227, 194, 47, 0.5)",
581 + "type": "color"
582 + },
583 + "color-dark-warning-060": {
584 + "value": "rgba(227, 194, 47, 0.6)",
585 + "type": "color"
586 + },
587 + "color-dark-warning-070": {
588 + "value": "rgba(227, 194, 47, 0.7)",
589 + "type": "color"
590 + },
591 + "color-dark-warning-080": {
592 + "value": "rgba(227, 194, 47, 0.8)",
593 + "type": "color"
594 + },
595 + "color-dark-warning-090": {
596 + "value": "rgba(227, 194, 47, 0.9)",
597 + "type": "color"
598 + },
599 "color-dark-error-005": {
600 "value": "rgba(255, 1, 86, 0.05)",
601 "type": "color"
602 },
603 + "color-dark-error-010": {
604 + "value": "rgba(255, 1, 86, 0.1)",
605 + "type": "color"
606 + },
607 + "color-dark-error-020": {
608 + "value": "rgba(255, 1, 86, 0.2)",
609 + "type": "color"
610 + },
611 + "color-dark-error-030": {
612 + "value": "rgba(255, 1, 86, 0.3)",
613 + "type": "color"
614 + },
615 + "color-dark-error-040": {
616 + "value": "rgba(255, 1, 86, 0.4)",
617 + "type": "color"
618 + },
619 + "color-dark-error-050": {
620 + "value": "rgba(255, 1, 86, 0.5)",
621 + "type": "color"
622 + },
623 + "color-dark-error-060": {
624 + "value": "rgba(255, 1, 86, 0.6)",
625 + "type": "color"
626 + },
627 + "color-dark-error-070": {
628 + "value": "rgba(255, 1, 86, 0.7)",
629 + "type": "color"
630 + },
631 + "color-dark-error-080": {
632 + "value": "rgba(255, 1, 86, 0.8)",
633 + "type": "color"
634 + },
635 + "color-dark-error-090": {
636 + "value": "rgba(255, 1, 86, 0.9)",
637 + "type": "color"
638 + },
639 "color-dark-secondary-1": {
640 "value": "rgb(98, 103, 255)",
641 "type": "color"
@@ -556,6 +868,18 @@
868 "value": "{color-light-primary-060}",
869 "type": "color"
870 },
871 + "color-primary-070": {
872 + "value": "{color-light-primary-070}",
873 + "type": "color"
874 + },
875 + "color-primary-080": {
876 + "value": "{color-light-primary-080}",
877 + "type": "color"
878 + },
879 + "color-primary-090": {
880 + "value": "{color-light-primary-090}",
881 + "type": "color"
882 + },
883 "color-info": {
884 "value": "{color-light-info}",
885 "type": "color"
@@ -576,18 +900,162 @@
900 "value": "{color-light-info-005}",
901 "type": "color"
902 },
903 + "color-info-010": {
904 + "value": "{color-light-info-010}",
905 + "type": "color"
906 + },
907 + "color-info-020": {
908 + "value": "{color-light-info-020}",
909 + "type": "color"
910 + },
911 + "color-info-030": {
912 + "value": "{color-light-info-030}",
913 + "type": "color"
914 + },
915 + "color-info-040": {
916 + "value": "{color-light-info-040}",
917 + "type": "color"
918 + },
919 + "color-info-050": {
920 + "value": "{color-light-info-050}",
921 + "type": "color"
922 + },
923 + "color-info-060": {
924 + "value": "{color-light-info-060}",
925 + "type": "color"
926 + },
927 + "color-info-070": {
928 + "value": "{color-light-info-070}",
929 + "type": "color"
930 + },
931 + "color-info-080": {
932 + "value": "{color-light-info-080}",
933 + "type": "color"
934 + },
935 + "color-info-090": {
936 + "value": "{color-light-info-090}",
937 + "type": "color"
938 + },
939 "color-success-005": {
940 "value": "{color-light-success-005}",
941 "type": "color"
942 },
943 + "color-success-010": {
944 + "value": "{color-light-success-010}",
945 + "type": "color"
946 + },
947 + "color-success-020": {
948 + "value": "{color-light-success-020}",
949 + "type": "color"
950 + },
951 + "color-success-030": {
952 + "value": "{color-light-success-030}",
953 + "type": "color"
954 + },
955 + "color-success-040": {
956 + "value": "{color-light-success-040}",
957 + "type": "color"
958 + },
959 + "color-success-050": {
960 + "value": "{color-light-success-050}",
961 + "type": "color"
962 + },
963 + "color-success-060": {
964 + "value": "{color-light-success-060}",
965 + "type": "color"
966 + },
967 + "color-success-070": {
968 + "value": "{color-light-success-070}",
969 + "type": "color"
970 + },
971 + "color-success-080": {
972 + "value": "{color-light-success-080}",
973 + "type": "color"
974 + },
975 + "color-success-090": {
976 + "value": "{color-light-success-090}",
977 + "type": "color"
978 + },
979 "color-warning-005": {
980 "value": "{color-light-warning-005}",
981 "type": "color"
982 },
983 + "color-warning-010": {
984 + "value": "{color-light-warning-010}",
985 + "type": "color"
986 + },
987 + "color-warning-020": {
988 + "value": "{color-light-warning-020}",
989 + "type": "color"
990 + },
991 + "color-warning-030": {
992 + "value": "{color-light-warning-030}",
993 + "type": "color"
994 + },
995 + "color-warning-040": {
996 + "value": "{color-light-warning-040}",
997 + "type": "color"
998 + },
999 + "color-warning-050": {
1000 + "value": "{color-light-warning-050}",
1001 + "type": "color"
1002 + },
1003 + "color-warning-060": {
1004 + "value": "{color-light-warning-060}",
1005 + "type": "color"
1006 + },
1007 + "color-warning-070": {
1008 + "value": "{color-light-warning-070}",
1009 + "type": "color"
1010 + },
1011 + "color-warning-080": {
1012 + "value": "{color-light-warning-080}",
1013 + "type": "color"
1014 + },
1015 + "color-warning-090": {
1016 + "value": "{color-light-warning-090}",
1017 + "type": "color"
1018 + },
1019 "color-error-005": {
1020 "value": "{color-light-error-005}",
1021 "type": "color"
1022 },
1023 + "color-error-010": {
1024 + "value": "{color-light-error-010}",
1025 + "type": "color"
1026 + },
1027 + "color-error-020": {
1028 + "value": "{color-light-error-020}",
1029 + "type": "color"
1030 + },
1031 + "color-error-030": {
1032 + "value": "{color-light-error-030}",
1033 + "type": "color"
1034 + },
1035 + "color-error-040": {
1036 + "value": "{color-light-error-040}",
1037 + "type": "color"
1038 + },
1039 + "color-error-050": {
1040 + "value": "{color-light-error-050}",
1041 + "type": "color"
1042 + },
1043 + "color-error-060": {
1044 + "value": "{color-light-error-060}",
1045 + "type": "color"
1046 + },
1047 + "color-error-070": {
1048 + "value": "{color-light-error-070}",
1049 + "type": "color"
1050 + },
1051 + "color-error-080": {
1052 + "value": "{color-light-error-080}",
1053 + "type": "color"
1054 + },
1055 + "color-error-090": {
1056 + "value": "{color-light-error-090}",
1057 + "type": "color"
1058 + },
1059 "color-secondary-1": {
1060 "value": "{color-light-secondary-1}",
1061 "type": "color"
@@ -758,6 +1226,18 @@
1226 "value": "{color-dark-primary-060}",
1227 "type": "color"
1228 },
1229 + "color-primary-070": {
1230 + "value": "{color-dark-primary-070}",
1231 + "type": "color"
1232 + },
1233 + "color-primary-080": {
1234 + "value": "{color-dark-primary-080}",
1235 + "type": "color"
1236 + },
1237 + "color-primary-090": {
1238 + "value": "{color-dark-primary-090}",
1239 + "type": "color"
1240 + },
1241 "color-info": {
1242 "value": "{color-dark-info}",
1243 "type": "color"
@@ -778,18 +1258,162 @@
1258 "value": "{color-dark-info-005}",
1259 "type": "color"
1260 },
1261 + "color-info-010": {
1262 + "value": "{color-dark-info-010}",
1263 + "type": "color"
1264 + },
1265 + "color-info-020": {
1266 + "value": "{color-dark-info-020}",
1267 + "type": "color"
1268 + },
1269 + "color-info-030": {
1270 + "value": "{color-dark-info-030}",
1271 + "type": "color"
1272 + },
1273 + "color-info-040": {
1274 + "value": "{color-dark-info-040}",
1275 + "type": "color"
1276 + },
1277 + "color-info-050": {
1278 + "value": "{color-dark-info-050}",
1279 + "type": "color"
1280 + },
1281 + "color-info-060": {
1282 + "value": "{color-dark-info-060}",
1283 + "type": "color"
1284 + },
1285 + "color-info-070": {
1286 + "value": "{color-dark-info-070}",
1287 + "type": "color"
1288 + },
1289 + "color-info-080": {
1290 + "value": "{color-dark-info-080}",
1291 + "type": "color"
1292 + },
1293 + "color-info-090": {
1294 + "value": "{color-dark-info-090}",
1295 + "type": "color"
1296 + },
1297 "color-success-005": {
1298 "value": "{color-dark-success-005}",
1299 "type": "color"
1300 },
1301 + "color-success-010": {
1302 + "value": "{color-dark-success-010}",
1303 + "type": "color"
1304 + },
1305 + "color-success-020": {
1306 + "value": "{color-dark-success-020}",
1307 + "type": "color"
1308 + },
1309 + "color-success-030": {
1310 + "value": "{color-dark-success-030}",
1311 + "type": "color"
1312 + },
1313 + "color-success-040": {
1314 + "value": "{color-dark-success-040}",
1315 + "type": "color"
1316 + },
1317 + "color-success-050": {
1318 + "value": "{color-dark-success-050}",
1319 + "type": "color"
1320 + },
1321 + "color-success-060": {
1322 + "value": "{color-dark-success-060}",
1323 + "type": "color"
1324 + },
1325 + "color-success-070": {
1326 + "value": "{color-dark-success-070}",
1327 + "type": "color"
1328 + },
1329 + "color-success-080": {
1330 + "value": "{color-dark-success-080}",
1331 + "type": "color"
1332 + },
1333 + "color-success-090": {
1334 + "value": "{color-dark-success-090}",
1335 + "type": "color"
1336 + },
1337 "color-warning-005": {
1338 "value": "{color-dark-warning-005}",
1339 "type": "color"
1340 },
1341 + "color-warning-010": {
1342 + "value": "{color-dark-warning-010}",
1343 + "type": "color"
1344 + },
1345 + "color-warning-020": {
1346 + "value": "{color-dark-warning-020}",
1347 + "type": "color"
1348 + },
1349 + "color-warning-030": {
1350 + "value": "{color-dark-warning-030}",
1351 + "type": "color"
1352 + },
1353 + "color-warning-040": {
1354 + "value": "{color-dark-warning-040}",
1355 + "type": "color"
1356 + },
1357 + "color-warning-050": {
1358 + "value": "{color-dark-warning-050}",
1359 + "type": "color"
1360 + },
1361 + "color-warning-060": {
1362 + "value": "{color-dark-warning-060}",
1363 + "type": "color"
1364 + },
1365 + "color-warning-070": {
1366 + "value": "{color-dark-warning-070}",
1367 + "type": "color"
1368 + },
1369 + "color-warning-080": {
1370 + "value": "{color-dark-warning-080}",
1371 + "type": "color"
1372 + },
1373 + "color-warning-090": {
1374 + "value": "{color-dark-warning-090}",
1375 + "type": "color"
1376 + },
1377 "color-error-005": {
1378 "value": "{color-dark-error-005}",
1379 "type": "color"
1380 },
1381 + "color-error-010": {
1382 + "value": "{color-dark-error-010}",
1383 + "type": "color"
1384 + },
1385 + "color-error-020": {
1386 + "value": "{color-dark-error-020}",
1387 + "type": "color"
1388 + },
1389 + "color-error-030": {
1390 + "value": "{color-dark-error-030}",
1391 + "type": "color"
1392 + },
1393 + "color-error-040": {
1394 + "value": "{color-dark-error-040}",
1395 + "type": "color"
1396 + },
1397 + "color-error-050": {
1398 + "value": "{color-dark-error-050}",
1399 + "type": "color"
1400 + },
1401 + "color-error-060": {
1402 + "value": "{color-dark-error-060}",
1403 + "type": "color"
1404 + },
1405 + "color-error-070": {
1406 + "value": "{color-dark-error-070}",
1407 + "type": "color"
1408 + },
1409 + "color-error-080": {
1410 + "value": "{color-dark-error-080}",
1411 + "type": "color"
1412 + },
1413 + "color-error-090": {
1414 + "value": "{color-dark-error-090}",
1415 + "type": "color"
1416 + },
1417 "color-secondary-1": {
1418 "value": "{color-dark-secondary-1}",
1419 "type": "color"
frontend/package-lock.json
+647 -1331
@@ -13,7 +13,8 @@
13 "@fontsource/jetbrains-mono": "^5.1.1",
14 "@fontsource/lexend": "^5.1.1",
15 "@fontsource/public-sans": "^5.1.1",
16 - "@shikijs/markdown-it": "^1.22.0",
16 + "@shikijs/markdown-it": "^1.22.1",
17 + "@tailwindcss/container-queries": "^0.1.1",
18 "@vueuse/core": "^11.1.0",
19 "axios": "^1.7.7",
20 "bytes": "^3.1.2",
@@ -23,7 +24,7 @@
24 "echarts": "^5.5.1",
25 "file-saver": "^2.0.5",
26 "html-entities": "^2.5.2",
26 - "jose": "^5.9.4",
27 + "jose": "^5.9.6",
28 "js-md5": "^0.8.3",
29 "lodash": "^4.17.21",
30 "mitt": "^3.0.1",
@@ -31,9 +32,9 @@
32 "nanoid": "^5.0.7",
33 "password-validator": "^5.3.0",
34 "pinia": "^2.2.4",
34 - "pinia-plugin-persistedstate": "^4.1.1",
35 + "pinia-plugin-persistedstate": "^4.1.2",
36 "secure-ls": "^2.0.0",
36 - "shiki": "^1.22.0",
37 + "shiki": "^1.22.1",
38 "validator": "^13.12.0",
39 "vue": "^3.5.12",
40 "vue-advanced-cropper": "^2.8.9",
@@ -46,7 +47,7 @@
47 "vuedraggable": "^4.1.0"
48 },
49 "devDependencies": {
49 - "@antfu/eslint-config": "^3.7.3",
50 + "@antfu/eslint-config": "^3.8.0",
51 "@clack/prompts": "^0.7.0",
52 "@iconify/vue": "^4.1.2",
53 "@tsconfig/node20": "^20.1.4",
@@ -54,34 +55,35 @@
55 "@types/file-saver": "^2.0.7",
56 "@types/fs-extra": "^11.0.4",
57 "@types/jsdom": "^21.1.7",
57 - "@types/lodash": "^4.17.10",
58 - "@types/node": "^22.7.5",
58 + "@types/lodash": "^4.17.12",
59 + "@types/node": "^22.8.0",
60 "@types/validator": "^13.12.2",
61 "@vitejs/plugin-vue": "^5.1.4",
62 "@vitejs/plugin-vue-jsx": "^4.0.1",
63 "@vue/test-utils": "^2.4.6",
64 "@vue/tsconfig": "^0.5.1",
65 "autoprefixer": "^10.4.20",
65 - "cypress": "^13.15.0",
66 + "cypress": "^13.15.1",
67 "depcheck": "^1.4.7",
67 - "eslint": "^9.12.0",
68 + "eslint": "^9.13.0",
69 "flourite": "^1.3.0",
70 "fs-extra": "^11.2.0",
71 "jsdom": "^25.0.1",
71 - "npm-run-all2": "^6.2.3",
72 + "npm-run-all2": "^7.0.1",
73 "postcss": "^8.4.47",
74 "prettier": "^3.3.3",
74 - "sass": "^1.79.5",
75 + "prettier-plugin-tailwindcss": "^0.6.8",
76 + "sass": "^1.80.4",
77 "start-server-and-test": "^2.0.8",
78 "tailwind-config-viewer": "^2.0.4",
77 - "tailwindcss": "^3.4.13",
79 + "tailwindcss": "^3.4.14",
80 "taze": "^0.17.2",
81 "type-fest": "^4.26.1",
80 - "typescript": "~5.5.4",
82 + "typescript": "~5.6.3",
83 "unplugin-vue-components": "^0.27.4",
82 - "vite": "^5.4.9",
84 + "vite": "^5.4.10",
85 "vite-bundle-visualizer": "^1.2.1",
84 - "vite-plugin-vue-devtools": "^7.4.6",
86 + "vite-plugin-vue-devtools": "^7.5.4",
87 "vite-svg-loader": "^5.1.0",
88 "vitest": "^2.1.3",
89 "vue-tsc": "^2.1.6"
@@ -105,7 +107,6 @@
107 "version": "5.2.0",
108 "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
109 "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==",
108 - "dev": true,
110 "engines": {
111 "node": ">=10"
112 },
@@ -126,42 +127,42 @@
127 }
128 },
129 "node_modules/@antfu/eslint-config": {
129 - "version": "3.7.3",
130 - "resolved": "https://registry.npmjs.org/@antfu/eslint-config/-/eslint-config-3.7.3.tgz",
131 - "integrity": "sha512-vzhKtzQT+f/xBV8T5U8SFy3D7uAqL2CEcjsJVqtA7F8tdKvGuC/96uWeEKMHk5lRfijgj+xRvb+c4qQn60YlIA==",
130 + "version": "3.8.0",
131 + "resolved": "https://registry.npmjs.org/@antfu/eslint-config/-/eslint-config-3.8.0.tgz",
132 + "integrity": "sha512-O5QSufPHpKTm0wk1OQ5c2mOZVzCqYV3hIDrt5zt+cOWqiG8YXLPkSOD4fFwjomATtOuUbcLUwkcgY5dErM7aIw==",
133 "dev": true,
134 "dependencies": {
135 "@antfu/install-pkg": "^0.4.1",
136 "@clack/prompts": "^0.7.0",
137 "@eslint-community/eslint-plugin-eslint-comments": "^4.4.0",
137 - "@eslint/markdown": "^6.1.0",
138 - "@stylistic/eslint-plugin": "^2.8.0",
139 - "@typescript-eslint/eslint-plugin": "^8.7.0",
140 - "@typescript-eslint/parser": "^8.7.0",
141 - "@vitest/eslint-plugin": "^1.1.4",
138 + "@eslint/markdown": "^6.2.0",
139 + "@stylistic/eslint-plugin": "^2.9.0",
140 + "@typescript-eslint/eslint-plugin": "^8.9.0",
141 + "@typescript-eslint/parser": "^8.9.0",
142 + "@vitest/eslint-plugin": "^1.1.7",
143 "eslint-config-flat-gitignore": "^0.3.0",
144 "eslint-flat-config-utils": "^0.4.0",
145 "eslint-merge-processors": "^0.1.0",
146 "eslint-plugin-antfu": "^2.7.0",
147 "eslint-plugin-command": "^0.2.6",
147 - "eslint-plugin-import-x": "^4.3.0",
148 - "eslint-plugin-jsdoc": "^50.3.0",
148 + "eslint-plugin-import-x": "^4.3.1",
149 + "eslint-plugin-jsdoc": "^50.4.1",
150 "eslint-plugin-jsonc": "^2.16.0",
150 - "eslint-plugin-n": "^17.10.3",
151 + "eslint-plugin-n": "^17.11.1",
152 "eslint-plugin-no-only-tests": "^3.3.0",
152 - "eslint-plugin-perfectionist": "^3.7.0",
153 + "eslint-plugin-perfectionist": "^3.9.0",
154 "eslint-plugin-regexp": "^2.6.0",
155 "eslint-plugin-toml": "^0.11.1",
155 - "eslint-plugin-unicorn": "^55.0.0",
156 + "eslint-plugin-unicorn": "^56.0.0",
157 "eslint-plugin-unused-imports": "^4.1.4",
157 - "eslint-plugin-vue": "^9.28.0",
158 + "eslint-plugin-vue": "^9.29.0",
159 "eslint-plugin-yml": "^1.14.0",
160 "eslint-processor-vue-blocks": "^0.1.2",
160 - "globals": "^15.9.0",
161 + "globals": "^15.11.0",
162 "jsonc-eslint-parser": "^2.4.0",
163 "local-pkg": "^0.5.0",
164 "parse-gitignore": "^2.0.0",
164 - "picocolors": "^1.1.0",
165 + "picocolors": "^1.1.1",
166 "toml-eslint-parser": "^0.10.0",
167 "vue-eslint-parser": "^9.4.3",
168 "yaml-eslint-parser": "^1.2.3",
@@ -181,7 +182,7 @@
182 "eslint": "^9.10.0",
183 "eslint-plugin-astro": "^1.2.0",
184 "eslint-plugin-format": ">=0.1.0",
184 - "eslint-plugin-react-hooks": "^4.6.0",
185 + "eslint-plugin-react-hooks": "^5.0.0",
186 "eslint-plugin-react-refresh": "^0.4.4",
187 "eslint-plugin-solid": "^0.14.3",
188 "eslint-plugin-svelte": ">=2.35.1",
@@ -268,11 +269,12 @@
269 }
270 },
271 "node_modules/@babel/code-frame": {
271 - "version": "7.25.7",
272 - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.25.7.tgz",
273 - "integrity": "sha512-0xZJFNE5XMpENsgfHYTw8FbX4kv53mFLn2i3XPoq69LyhYSCBJtitaHx9QnsVTrsogI4Z3+HtEfZ2/GFPOtf5g==",
272 + "version": "7.26.0",
273 + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.0.tgz",
274 + "integrity": "sha512-INCKxTtbXtcNbUZ3YXutwMpEleqttcswhAdee7dhuoVrD2cnuc3PqtERBtxkX5nziX9vnBL8WXmSGwv8CuPV6g==",
275 "dependencies": {
275 - "@babel/highlight": "^7.25.7",
276 + "@babel/helper-validator-identifier": "^7.25.9",
277 + "js-tokens": "^4.0.0",
278 "picocolors": "^1.0.0"
279 },
280 "engines": {
@@ -280,28 +282,28 @@
282 }
283 },
284 "node_modules/@babel/compat-data": {
283 - "version": "7.25.8",
284 - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.8.tgz",
285 - "integrity": "sha512-ZsysZyXY4Tlx+Q53XdnOFmqwfB9QDTHYxaZYajWRoBLuLEAwI2UIbtxOjWh/cFaa9IKUlcB+DDuoskLuKu56JA==",
285 + "version": "7.26.0",
286 + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.0.tgz",
287 + "integrity": "sha512-qETICbZSLe7uXv9VE8T/RWOdIE5qqyTucOt4zLYMafj2MRO271VGgLd4RACJMeBO37UPWhXiKMBk7YlJ0fOzQA==",
288 "engines": {
289 "node": ">=6.9.0"
290 }
291 },
292 "node_modules/@babel/core": {
291 - "version": "7.25.8",
292 - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.8.tgz",
293 - "integrity": "sha512-Oixnb+DzmRT30qu9d3tJSQkxuygWm32DFykT4bRoORPa9hZ/L4KhVB/XiRm6KG+roIEM7DBQlmg27kw2HZkdZg==",
293 + "version": "7.26.0",
294 + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz",
295 + "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==",
296 "dependencies": {
297 "@ampproject/remapping": "^2.2.0",
296 - "@babel/code-frame": "^7.25.7",
297 - "@babel/generator": "^7.25.7",
298 - "@babel/helper-compilation-targets": "^7.25.7",
299 - "@babel/helper-module-transforms": "^7.25.7",
300 - "@babel/helpers": "^7.25.7",
301 - "@babel/parser": "^7.25.8",
302 - "@babel/template": "^7.25.7",
303 - "@babel/traverse": "^7.25.7",
304 - "@babel/types": "^7.25.8",
298 + "@babel/code-frame": "^7.26.0",
299 + "@babel/generator": "^7.26.0",
300 + "@babel/helper-compilation-targets": "^7.25.9",
301 + "@babel/helper-module-transforms": "^7.26.0",
302 + "@babel/helpers": "^7.26.0",
303 + "@babel/parser": "^7.26.0",
304 + "@babel/template": "^7.25.9",
305 + "@babel/traverse": "^7.25.9",
306 + "@babel/types": "^7.26.0",
307 "convert-source-map": "^2.0.0",
308 "debug": "^4.1.0",
309 "gensync": "^1.0.0-beta.2",
@@ -325,11 +327,12 @@
327 }
328 },
329 "node_modules/@babel/generator": {
328 - "version": "7.25.7",
329 - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.7.tgz",
330 - "integrity": "sha512-5Dqpl5fyV9pIAD62yK9P7fcA768uVPUyrQmqpqstHWgMma4feF1x/oFysBCVZLY5wJ2GkMUCdsNDnGZrPoR6rA==",
330 + "version": "7.26.0",
331 + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.0.tgz",
332 + "integrity": "sha512-/AIkAmInnWwgEAJGQr9vY0c66Mj6kjkE2ZPB1PurTRaRAh3U+J45sAQMjQDJdh4WbR3l0x5xkimXBKyBXXAu2w==",
333 "dependencies": {
332 - "@babel/types": "^7.25.7",
334 + "@babel/parser": "^7.26.0",
335 + "@babel/types": "^7.26.0",
336 "@jridgewell/gen-mapping": "^0.3.5",
337 "@jridgewell/trace-mapping": "^0.3.25",
338 "jsesc": "^3.0.2"
@@ -339,24 +342,24 @@
342 }
343 },
344 "node_modules/@babel/helper-annotate-as-pure": {
342 - "version": "7.25.7",
343 - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.7.tgz",
344 - "integrity": "sha512-4xwU8StnqnlIhhioZf1tqnVWeQ9pvH/ujS8hRfw/WOza+/a+1qv69BWNy+oY231maTCWgKWhfBU7kDpsds6zAA==",
345 + "version": "7.25.9",
346 + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz",
347 + "integrity": "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==",
348 "dev": true,
349 "dependencies": {
347 - "@babel/types": "^7.25.7"
350 + "@babel/types": "^7.25.9"
351 },
352 "engines": {
353 "node": ">=6.9.0"
354 }
355 },
356 "node_modules/@babel/helper-compilation-targets": {
354 - "version": "7.25.7",
355 - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.7.tgz",
356 - "integrity": "sha512-DniTEax0sv6isaw6qSQSfV4gVRNtw2rte8HHM45t9ZR0xILaufBRNkpMifCRiAPyvL4ACD6v0gfCwCmtOQaV4A==",
357 + "version": "7.25.9",
358 + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.9.tgz",
359 + "integrity": "sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==",
360 "dependencies": {
358 - "@babel/compat-data": "^7.25.7",
359 - "@babel/helper-validator-option": "^7.25.7",
361 + "@babel/compat-data": "^7.25.9",
362 + "@babel/helper-validator-option": "^7.25.9",
363 "browserslist": "^4.24.0",
364 "lru-cache": "^5.1.1",
365 "semver": "^6.3.1"
@@ -374,17 +377,17 @@
377 }
378 },
379 "node_modules/@babel/helper-create-class-features-plugin": {
377 - "version": "7.25.7",
378 - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.7.tgz",
379 - "integrity": "sha512-bD4WQhbkx80mAyj/WCm4ZHcF4rDxkoLFO6ph8/5/mQ3z4vAzltQXAmbc7GvVJx5H+lk5Mi5EmbTeox5nMGCsbw==",
380 + "version": "7.25.9",
381 + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.9.tgz",
382 + "integrity": "sha512-UTZQMvt0d/rSz6KI+qdu7GQze5TIajwTS++GUozlw8VBJDEOAqSXwm1WvmYEZwqdqSGQshRocPDqrt4HBZB3fQ==",
383 "dev": true,
384 "dependencies": {
382 - "@babel/helper-annotate-as-pure": "^7.25.7",
383 - "@babel/helper-member-expression-to-functions": "^7.25.7",
384 - "@babel/helper-optimise-call-expression": "^7.25.7",
385 - "@babel/helper-replace-supers": "^7.25.7",
386 - "@babel/helper-skip-transparent-expression-wrappers": "^7.25.7",
387 - "@babel/traverse": "^7.25.7",
385 + "@babel/helper-annotate-as-pure": "^7.25.9",
386 + "@babel/helper-member-expression-to-functions": "^7.25.9",
387 + "@babel/helper-optimise-call-expression": "^7.25.9",
388 + "@babel/helper-replace-supers": "^7.25.9",
389 + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9",
390 + "@babel/traverse": "^7.25.9",
391 "semver": "^6.3.1"
392 },
393 "engines": {
@@ -404,39 +407,38 @@
407 }
408 },
409 "node_modules/@babel/helper-member-expression-to-functions": {
407 - "version": "7.25.7",
408 - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.7.tgz",
409 - "integrity": "sha512-O31Ssjd5K6lPbTX9AAYpSKrZmLeagt9uwschJd+Ixo6QiRyfpvgtVQp8qrDR9UNFjZ8+DO34ZkdrN+BnPXemeA==",
410 + "version": "7.25.9",
411 + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz",
412 + "integrity": "sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==",
413 "dev": true,
414 "dependencies": {
412 - "@babel/traverse": "^7.25.7",
413 - "@babel/types": "^7.25.7"
415 + "@babel/traverse": "^7.25.9",
416 + "@babel/types": "^7.25.9"
417 },
418 "engines": {
419 "node": ">=6.9.0"
420 }
421 },
422 "node_modules/@babel/helper-module-imports": {
420 - "version": "7.25.7",
421 - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.7.tgz",
422 - "integrity": "sha512-o0xCgpNmRohmnoWKQ0Ij8IdddjyBFE4T2kagL/x6M3+4zUgc+4qTOUBoNe4XxDskt1HPKO007ZPiMgLDq2s7Kw==",
423 + "version": "7.25.9",
424 + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz",
425 + "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==",
426 "dependencies": {
424 - "@babel/traverse": "^7.25.7",
425 - "@babel/types": "^7.25.7"
427 + "@babel/traverse": "^7.25.9",
428 + "@babel/types": "^7.25.9"
429 },
430 "engines": {
431 "node": ">=6.9.0"
432 }
433 },
434 "node_modules/@babel/helper-module-transforms": {
432 - "version": "7.25.7",
433 - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.7.tgz",
434 - "integrity": "sha512-k/6f8dKG3yDz/qCwSM+RKovjMix563SLxQFo0UhRNo239SP6n9u5/eLtKD6EAjwta2JHJ49CsD8pms2HdNiMMQ==",
435 + "version": "7.26.0",
436 + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz",
437 + "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==",
438 "dependencies": {
436 - "@babel/helper-module-imports": "^7.25.7",
437 - "@babel/helper-simple-access": "^7.25.7",
438 - "@babel/helper-validator-identifier": "^7.25.7",
439 - "@babel/traverse": "^7.25.7"
439 + "@babel/helper-module-imports": "^7.25.9",
440 + "@babel/helper-validator-identifier": "^7.25.9",
441 + "@babel/traverse": "^7.25.9"
442 },
443 "engines": {
444 "node": ">=6.9.0"
@@ -446,35 +448,35 @@
448 }
449 },
450 "node_modules/@babel/helper-optimise-call-expression": {
449 - "version": "7.25.7",
450 - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.7.tgz",
451 - "integrity": "sha512-VAwcwuYhv/AT+Vfr28c9y6SHzTan1ryqrydSTFGjU0uDJHw3uZ+PduI8plCLkRsDnqK2DMEDmwrOQRsK/Ykjng==",
451 + "version": "7.25.9",
452 + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.9.tgz",
453 + "integrity": "sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==",
454 "dev": true,
455 "dependencies": {
454 - "@babel/types": "^7.25.7"
456 + "@babel/types": "^7.25.9"
457 },
458 "engines": {
459 "node": ">=6.9.0"
460 }
461 },
462 "node_modules/@babel/helper-plugin-utils": {
461 - "version": "7.25.7",
462 - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.7.tgz",
463 - "integrity": "sha512-eaPZai0PiqCi09pPs3pAFfl/zYgGaE6IdXtYvmf0qlcDTd3WCtO7JWCcRd64e0EQrcYgiHibEZnOGsSY4QSgaw==",
463 + "version": "7.25.9",
464 + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.9.tgz",
465 + "integrity": "sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==",
466 "dev": true,
467 "engines": {
468 "node": ">=6.9.0"
469 }
470 },
471 "node_modules/@babel/helper-replace-supers": {
470 - "version": "7.25.7",
471 - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.25.7.tgz",
472 - "integrity": "sha512-iy8JhqlUW9PtZkd4pHM96v6BdJ66Ba9yWSE4z0W4TvSZwLBPkyDsiIU3ENe4SmrzRBs76F7rQXTy1lYC49n6Lw==",
472 + "version": "7.25.9",
473 + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.25.9.tgz",
474 + "integrity": "sha512-IiDqTOTBQy0sWyeXyGSC5TBJpGFXBkRynjBeXsvbhQFKj2viwJC76Epz35YLU1fpe/Am6Vppb7W7zM4fPQzLsQ==",
475 "dev": true,
476 "dependencies": {
475 - "@babel/helper-member-expression-to-functions": "^7.25.7",
476 - "@babel/helper-optimise-call-expression": "^7.25.7",
477 - "@babel/traverse": "^7.25.7"
477 + "@babel/helper-member-expression-to-functions": "^7.25.9",
478 + "@babel/helper-optimise-call-expression": "^7.25.9",
479 + "@babel/traverse": "^7.25.9"
480 },
481 "engines": {
482 "node": ">=6.9.0"
@@ -483,87 +485,61 @@
485 "@babel/core": "^7.0.0"
486 }
487 },
486 - "node_modules/@babel/helper-simple-access": {
487 - "version": "7.25.7",
488 - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.25.7.tgz",
489 - "integrity": "sha512-FPGAkJmyoChQeM+ruBGIDyrT2tKfZJO8NcxdC+CWNJi7N8/rZpSxK7yvBJ5O/nF1gfu5KzN7VKG3YVSLFfRSxQ==",
490 - "dependencies": {
491 - "@babel/traverse": "^7.25.7",
492 - "@babel/types": "^7.25.7"
493 - },
494 - "engines": {
495 - "node": ">=6.9.0"
496 - }
497 - },
488 "node_modules/@babel/helper-skip-transparent-expression-wrappers": {
499 - "version": "7.25.7",
500 - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.7.tgz",
501 - "integrity": "sha512-pPbNbchZBkPMD50K0p3JGcFMNLVUCuU/ABybm/PGNj4JiHrpmNyqqCphBk4i19xXtNV0JhldQJJtbSW5aUvbyA==",
489 + "version": "7.25.9",
490 + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz",
491 + "integrity": "sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==",
492 "dev": true,
493 "dependencies": {
504 - "@babel/traverse": "^7.25.7",
505 - "@babel/types": "^7.25.7"
494 + "@babel/traverse": "^7.25.9",
495 + "@babel/types": "^7.25.9"
496 },
497 "engines": {
498 "node": ">=6.9.0"
499 }
500 },
501 "node_modules/@babel/helper-string-parser": {
512 - "version": "7.25.7",
513 - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.7.tgz",
514 - "integrity": "sha512-CbkjYdsJNHFk8uqpEkpCvRs3YRp9tY6FmFY7wLMSYuGYkrdUi7r2lc4/wqsvlHoMznX3WJ9IP8giGPq68T/Y6g==",
502 + "version": "7.25.9",
503 + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz",
504 + "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==",
505 "engines": {
506 "node": ">=6.9.0"
507 }
508 },
509 "node_modules/@babel/helper-validator-identifier": {
520 - "version": "7.25.7",
521 - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.7.tgz",
522 - "integrity": "sha512-AM6TzwYqGChO45oiuPqwL2t20/HdMC1rTPAesnBCgPCSF1x3oN9MVUwQV2iyz4xqWrctwK5RNC8LV22kaQCNYg==",
510 + "version": "7.25.9",
511 + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz",
512 + "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==",
513 "engines": {
514 "node": ">=6.9.0"
515 }
516 },
517 "node_modules/@babel/helper-validator-option": {
528 - "version": "7.25.7",
529 - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.7.tgz",
530 - "integrity": "sha512-ytbPLsm+GjArDYXJ8Ydr1c/KJuutjF2besPNbIZnZ6MKUxi/uTA22t2ymmA4WFjZFpjiAMO0xuuJPqK2nvDVfQ==",
518 + "version": "7.25.9",
519 + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz",
520 + "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==",
521 "engines": {
522 "node": ">=6.9.0"
523 }
524 },
525 "node_modules/@babel/helpers": {
536 - "version": "7.25.7",
537 - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.7.tgz",
538 - "integrity": "sha512-Sv6pASx7Esm38KQpF/U/OXLwPPrdGHNKoeblRxgZRLXnAtnkEe4ptJPDtAZM7fBLadbc1Q07kQpSiGQ0Jg6tRA==",
539 - "dependencies": {
540 - "@babel/template": "^7.25.7",
541 - "@babel/types": "^7.25.7"
542 - },
543 - "engines": {
544 - "node": ">=6.9.0"
545 - }
546 - },
547 - "node_modules/@babel/highlight": {
548 - "version": "7.25.7",
549 - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.25.7.tgz",
550 - "integrity": "sha512-iYyACpW3iW8Fw+ZybQK+drQre+ns/tKpXbNESfrhNnPLIklLbXr7MYJ6gPEd0iETGLOK+SxMjVvKb/ffmk+FEw==",
526 + "version": "7.26.0",
527 + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.0.tgz",
528 + "integrity": "sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==",
529 "dependencies": {
552 - "@babel/helper-validator-identifier": "^7.25.7",
553 - "chalk": "^2.4.2",
554 - "js-tokens": "^4.0.0",
555 - "picocolors": "^1.0.0"
530 + "@babel/template": "^7.25.9",
531 + "@babel/types": "^7.26.0"
532 },
533 "engines": {
534 "node": ">=6.9.0"
535 }
536 },
537 "node_modules/@babel/parser": {
562 - "version": "7.25.8",
563 - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.8.tgz",
564 - "integrity": "sha512-HcttkxzdPucv3nNFmfOOMfFf64KgdJVqm1KaCm25dPGMLElo9nsLvXeJECQg8UzPuBGLyTSA0ZzqCtDSzKTEoQ==",
538 + "version": "7.26.0",
539 + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.0.tgz",
540 + "integrity": "sha512-aP8x5pIw3xvYr/sXT+SEUwyhrXT8rUJRZltK/qN3Db80dcKpTett8cJxHyjk+xYSVXvNnl2SfcJVjbwxpOSscA==",
541 "dependencies": {
566 - "@babel/types": "^7.25.8"
542 + "@babel/types": "^7.26.0"
543 },
544 "bin": {
545 "parser": "bin/babel-parser.js"
@@ -573,14 +549,14 @@
549 }
550 },
551 "node_modules/@babel/plugin-proposal-decorators": {
576 - "version": "7.25.7",
577 - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.25.7.tgz",
578 - "integrity": "sha512-q1mqqqH0e1lhmsEQHV5U8OmdueBC2y0RFr2oUzZoFRtN3MvPmt2fsFRcNQAoGLTSNdHBFUYGnlgcRFhkBbKjPw==",
552 + "version": "7.25.9",
553 + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.25.9.tgz",
554 + "integrity": "sha512-smkNLL/O1ezy9Nhy4CNosc4Va+1wo5w4gzSZeLe6y6dM4mmHfYOCPolXQPHQxonZCF+ZyebxN9vqOolkYrSn5g==",
555 "dev": true,
556 "dependencies": {
581 - "@babel/helper-create-class-features-plugin": "^7.25.7",
582 - "@babel/helper-plugin-utils": "^7.25.7",
583 - "@babel/plugin-syntax-decorators": "^7.25.7"
557 + "@babel/helper-create-class-features-plugin": "^7.25.9",
558 + "@babel/helper-plugin-utils": "^7.25.9",
559 + "@babel/plugin-syntax-decorators": "^7.25.9"
560 },
561 "engines": {
562 "node": ">=6.9.0"
@@ -590,12 +566,12 @@
566 }
567 },
568 "node_modules/@babel/plugin-syntax-decorators": {
593 - "version": "7.25.7",
594 - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.25.7.tgz",
595 - "integrity": "sha512-oXduHo642ZhstLVYTe2z2GSJIruU0c/W3/Ghr6A5yGMsVrvdnxO1z+3pbTcT7f3/Clnt+1z8D/w1r1f1SHaCHw==",
569 + "version": "7.25.9",
570 + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.25.9.tgz",
571 + "integrity": "sha512-ryzI0McXUPJnRCvMo4lumIKZUzhYUO/ScI+Mz4YVaTLt04DHNSjEUjKVvbzQjZFLuod/cYEc07mJWhzl6v4DPg==",
572 "dev": true,
573 "dependencies": {
598 - "@babel/helper-plugin-utils": "^7.25.7"
574 + "@babel/helper-plugin-utils": "^7.25.9"
575 },
576 "engines": {
577 "node": ">=6.9.0"
@@ -605,12 +581,12 @@
581 }
582 },
583 "node_modules/@babel/plugin-syntax-import-attributes": {
608 - "version": "7.25.7",
609 - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.25.7.tgz",
610 - "integrity": "sha512-AqVo+dguCgmpi/3mYBdu9lkngOBlQ2w2vnNpa6gfiCxQZLzV4ZbhsXitJ2Yblkoe1VQwtHSaNmIaGll/26YWRw==",
584 + "version": "7.26.0",
585 + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz",
586 + "integrity": "sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==",
587 "dev": true,
588 "dependencies": {
613 - "@babel/helper-plugin-utils": "^7.25.7"
589 + "@babel/helper-plugin-utils": "^7.25.9"
590 },
591 "engines": {
592 "node": ">=6.9.0"
@@ -632,12 +608,12 @@
608 }
609 },
610 "node_modules/@babel/plugin-syntax-jsx": {
635 - "version": "7.25.7",
636 - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.7.tgz",
637 - "integrity": "sha512-ruZOnKO+ajVL/MVx+PwNBPOkrnXTXoWMtte1MBpegfCArhqOe3Bj52avVj1huLLxNKYKXYaSxZ2F+woK1ekXfw==",
611 + "version": "7.25.9",
612 + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz",
613 + "integrity": "sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==",
614 "dev": true,
615 "dependencies": {
640 - "@babel/helper-plugin-utils": "^7.25.7"
616 + "@babel/helper-plugin-utils": "^7.25.9"
617 },
618 "engines": {
619 "node": ">=6.9.0"
@@ -647,12 +623,12 @@
623 }
624 },
625 "node_modules/@babel/plugin-syntax-typescript": {
650 - "version": "7.25.7",
651 - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.7.tgz",
652 - "integrity": "sha512-rR+5FDjpCHqqZN2bzZm18bVYGaejGq5ZkpVCJLXor/+zlSrSoc4KWcHI0URVWjl/68Dyr1uwZUz/1njycEAv9g==",
626 + "version": "7.25.9",
627 + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.9.tgz",
628 + "integrity": "sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==",
629 "dev": true,
630 "dependencies": {
655 - "@babel/helper-plugin-utils": "^7.25.7"
631 + "@babel/helper-plugin-utils": "^7.25.9"
632 },
633 "engines": {
634 "node": ">=6.9.0"
@@ -662,16 +638,16 @@
638 }
639 },
640 "node_modules/@babel/plugin-transform-typescript": {
665 - "version": "7.25.7",
666 - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.25.7.tgz",
667 - "integrity": "sha512-VKlgy2vBzj8AmEzunocMun2fF06bsSWV+FvVXohtL6FGve/+L217qhHxRTVGHEDO/YR8IANcjzgJsd04J8ge5Q==",
641 + "version": "7.25.9",
642 + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.25.9.tgz",
643 + "integrity": "sha512-7PbZQZP50tzv2KGGnhh82GSyMB01yKY9scIjf1a+GfZCtInOWqUH5+1EBU4t9fyR5Oykkkc9vFTs4OHrhHXljQ==",
644 "dev": true,
645 "dependencies": {
670 - "@babel/helper-annotate-as-pure": "^7.25.7",
671 - "@babel/helper-create-class-features-plugin": "^7.25.7",
672 - "@babel/helper-plugin-utils": "^7.25.7",
673 - "@babel/helper-skip-transparent-expression-wrappers": "^7.25.7",
674 - "@babel/plugin-syntax-typescript": "^7.25.7"
646 + "@babel/helper-annotate-as-pure": "^7.25.9",
647 + "@babel/helper-create-class-features-plugin": "^7.25.9",
648 + "@babel/helper-plugin-utils": "^7.25.9",
649 + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9",
650 + "@babel/plugin-syntax-typescript": "^7.25.9"
651 },
652 "engines": {
653 "node": ">=6.9.0"
@@ -681,36 +657,36 @@
657 }
658 },
659 "node_modules/@babel/standalone": {
684 - "version": "7.25.8",
685 - "resolved": "https://registry.npmjs.org/@babel/standalone/-/standalone-7.25.8.tgz",
686 - "integrity": "sha512-UvRanvLCGPRscJ5Rw9o6vUBS5P+E+gkhl6eaokrIN+WM1kUkmj254VZhyihFdDZVDlI3cPcZoakbJJw24QPISw==",
660 + "version": "7.26.0",
661 + "resolved": "https://registry.npmjs.org/@babel/standalone/-/standalone-7.26.0.tgz",
662 + "integrity": "sha512-jy7XdZWcJ24PTNy0l86eXQeCNryrtiWm/VUopiCtHoWe8v4TIg9mLoMPIRqY/AAVWzKt9ajpEtKZyg9YZJvxPA==",
663 "engines": {
664 "node": ">=6.9.0"
665 }
666 },
667 "node_modules/@babel/template": {
692 - "version": "7.25.7",
693 - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.7.tgz",
694 - "integrity": "sha512-wRwtAgI3bAS+JGU2upWNL9lSlDcRCqD05BZ1n3X2ONLH1WilFP6O1otQjeMK/1g0pvYcXC7b/qVUB1keofjtZA==",
668 + "version": "7.25.9",
669 + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz",
670 + "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==",
671 "dependencies": {
696 - "@babel/code-frame": "^7.25.7",
697 - "@babel/parser": "^7.25.7",
698 - "@babel/types": "^7.25.7"
672 + "@babel/code-frame": "^7.25.9",
673 + "@babel/parser": "^7.25.9",
674 + "@babel/types": "^7.25.9"
675 },
676 "engines": {
677 "node": ">=6.9.0"
678 }
679 },
680 "node_modules/@babel/traverse": {
705 - "version": "7.25.7",
706 - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.7.tgz",
707 - "integrity": "sha512-jatJPT1Zjqvh/1FyJs6qAHL+Dzb7sTb+xr7Q+gM1b+1oBsMsQQ4FkVKb6dFlJvLlVssqkRzV05Jzervt9yhnzg==",
708 - "dependencies": {
709 - "@babel/code-frame": "^7.25.7",
710 - "@babel/generator": "^7.25.7",
711 - "@babel/parser": "^7.25.7",
712 - "@babel/template": "^7.25.7",
713 - "@babel/types": "^7.25.7",
681 + "version": "7.25.9",
682 + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.9.tgz",
683 + "integrity": "sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==",
684 + "dependencies": {
685 + "@babel/code-frame": "^7.25.9",
686 + "@babel/generator": "^7.25.9",
687 + "@babel/parser": "^7.25.9",
688 + "@babel/template": "^7.25.9",
689 + "@babel/types": "^7.25.9",
690 "debug": "^4.3.1",
691 "globals": "^11.1.0"
692 },
@@ -727,13 +703,12 @@
703 }
704 },
705 "node_modules/@babel/types": {
730 - "version": "7.25.8",
731 - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.8.tgz",
732 - "integrity": "sha512-JWtuCu8VQsMladxVz/P4HzHUGCAwpuqacmowgXFs5XjxIgKuNjnLokQzuVjlTvIzODaDmpjT3oxcC48vyk9EWg==",
706 + "version": "7.26.0",
707 + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.0.tgz",
708 + "integrity": "sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==",
709 "dependencies": {
734 - "@babel/helper-string-parser": "^7.25.7",
735 - "@babel/helper-validator-identifier": "^7.25.7",
736 - "to-fast-properties": "^2.0.0"
710 + "@babel/helper-string-parser": "^7.25.9",
711 + "@babel/helper-validator-identifier": "^7.25.9"
712 },
713 "engines": {
714 "node": ">=6.9.0"
@@ -766,7 +741,6 @@
741 },
742 "node_modules/@clack/prompts/node_modules/is-unicode-supported": {
743 "version": "1.3.0",
769 - "dev": true,
744 "inBundle": true,
745 "license": "MIT",
746 "engines": {
@@ -1306,9 +1280,9 @@
1280 }
1281 },
1282 "node_modules/@eslint/compat": {
1309 - "version": "1.2.0",
1310 - "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.2.0.tgz",
1311 - "integrity": "sha512-CkPWddN7J9JPrQedEr2X7AjK9y1jaMJtxZ4A/+jTMFA2+n5BWhcKHW/EbJyARqg2zzQfgtWUtVmG3hrG6+nGpg==",
1283 + "version": "1.2.1",
1284 + "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.2.1.tgz",
1285 + "integrity": "sha512-JbHG2TWuCeNzh87fXo+/46Z1LEo9DBA9T188d0fZgGxAD+cNyS6sx9fdiyxjGPBMyQVRlCutTByZ6a5+YMkF7g==",
1286 "dev": true,
1287 "engines": {
1288 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -1356,9 +1330,9 @@
1330 }
1331 },
1332 "node_modules/@eslint/core": {
1359 - "version": "0.6.0",
1360 - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.6.0.tgz",
1361 - "integrity": "sha512-8I2Q8ykA4J0x0o7cg67FPVnehcqWTBehu/lmY+bolPFHGjh49YzGBMXTvpqVgEbBdvNCSxj6iFgiIyHzf03lzg==",
1333 + "version": "0.7.0",
1334 + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.7.0.tgz",
1335 + "integrity": "sha512-xp5Jirz5DyPYlPiKat8jaq0EmYvDXKKpzTbxXMpT9eqlRJkRKIz9AGMdlvYjih+im+QlhWrpvVjl8IPC/lHlUw==",
1336 "engines": {
1337 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
1338 }
@@ -1441,9 +1415,9 @@
1415 }
1416 },
1417 "node_modules/@eslint/markdown": {
1444 - "version": "6.2.0",
1445 - "resolved": "https://registry.npmjs.org/@eslint/markdown/-/markdown-6.2.0.tgz",
1446 - "integrity": "sha512-ZLWZ6RNy5flf1Nk2DBt0V77MQpQEo8snkjVT75P5J0SJkE/QNoqgy7+dBvNjlyZuj664pU43uDXWg3J8AfF0IQ==",
1418 + "version": "6.2.1",
1419 + "resolved": "https://registry.npmjs.org/@eslint/markdown/-/markdown-6.2.1.tgz",
1420 + "integrity": "sha512-cKVd110hG4ICHmWhIwZJfKmmJBvbiDWyrHODJknAtudKgZtlROGoLX9UEOA0o746zC0hCY4UV4vR+aOGW9S6JQ==",
1421 "dev": true,
1422 "dependencies": {
1423 "@eslint/plugin-kit": "^0.2.0",
@@ -1464,9 +1438,9 @@
1438 }
1439 },
1440 "node_modules/@eslint/plugin-kit": {
1467 - "version": "0.2.0",
1468 - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.0.tgz",
1469 - "integrity": "sha512-vH9PiIMMwvhCx31Af3HiGzsVNULDbyVkHXwlemn/B0TFj/00ho3y55efXrUZTfQipxoHC5u4xq6zblww1zm1Ig==",
1441 + "version": "0.2.1",
1442 + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.1.tgz",
1443 + "integrity": "sha512-HFZ4Mp26nbWk9d/BpvP0YNL6W4UoZF0VFcTw/aPPA8RpOxeFQgK+ClABGgAUXs9Y/RGX/l1vOmrqz1MQt9MNuw==",
1444 "dependencies": {
1445 "levn": "^0.4.1"
1446 },
@@ -1619,33 +1593,6 @@
1593 "url": "https://opencollective.com/typescript-eslint"
1594 }
1595 },
1622 - "node_modules/@f3ve/eslint-config/node_modules/@typescript-eslint/typescript-estree": {
1623 - "version": "6.21.0",
1624 - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz",
1625 - "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==",
1626 - "dependencies": {
1627 - "@typescript-eslint/types": "6.21.0",
1628 - "@typescript-eslint/visitor-keys": "6.21.0",
1629 - "debug": "^4.3.4",
1630 - "globby": "^11.1.0",
1631 - "is-glob": "^4.0.3",
1632 - "minimatch": "9.0.3",
1633 - "semver": "^7.5.4",
1634 - "ts-api-utils": "^1.0.1"
1635 - },
1636 - "engines": {
1637 - "node": "^16.0.0 || >=18.0.0"
1638 - },
1639 - "funding": {
1640 - "type": "opencollective",
1641 - "url": "https://opencollective.com/typescript-eslint"
1642 - },
1643 - "peerDependenciesMeta": {
1644 - "typescript": {
1645 - "optional": true
1646 - }
1647 - }
1648 - },
1596 "node_modules/@f3ve/eslint-config/node_modules/@typescript-eslint/utils": {
1597 "version": "6.21.0",
1598 "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz",
@@ -1711,47 +1658,6 @@
1658 "url": "https://github.com/sponsors/sindresorhus"
1659 }
1660 },
1714 - "node_modules/@f3ve/eslint-config/node_modules/globby": {
1715 - "version": "11.1.0",
1716 - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
1717 - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
1718 - "dependencies": {
1719 - "array-union": "^2.1.0",
1720 - "dir-glob": "^3.0.1",
1721 - "fast-glob": "^3.2.9",
1722 - "ignore": "^5.2.0",
1723 - "merge2": "^1.4.1",
1724 - "slash": "^3.0.0"
1725 - },
1726 - "engines": {
1727 - "node": ">=10"
1728 - },
1729 - "funding": {
1730 - "url": "https://github.com/sponsors/sindresorhus"
1731 - }
1732 - },
1733 - "node_modules/@f3ve/eslint-config/node_modules/minimatch": {
1734 - "version": "9.0.3",
1735 - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
1736 - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
1737 - "dependencies": {
1738 - "brace-expansion": "^2.0.1"
1739 - },
1740 - "engines": {
1741 - "node": ">=16 || 14 >=14.17"
1742 - },
1743 - "funding": {
1744 - "url": "https://github.com/sponsors/isaacs"
1745 - }
1746 - },
1747 - "node_modules/@f3ve/eslint-config/node_modules/slash": {
1748 - "version": "3.0.0",
1749 - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
1750 - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
1751 - "engines": {
1752 - "node": ">=8"
1753 - }
1754 - },
1661 "node_modules/@f3ve/eslint-config/node_modules/type-fest": {
1662 "version": "0.20.2",
1663 "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
@@ -1959,7 +1865,6 @@
1865 "version": "8.0.2",
1866 "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
1867 "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
1962 - "dev": true,
1868 "dependencies": {
1869 "string-width": "^5.1.2",
1870 "string-width-cjs": "npm:string-width@^4.2.0",
@@ -1976,7 +1881,6 @@
1881 "version": "6.1.0",
1882 "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
1883 "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
1979 - "dev": true,
1884 "engines": {
1885 "node": ">=12"
1886 },
@@ -1987,14 +1891,12 @@
1891 "node_modules/@isaacs/cliui/node_modules/emoji-regex": {
1892 "version": "9.2.2",
1893 "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
1990 - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
1991 - "dev": true
1894 + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="
1895 },
1896 "node_modules/@isaacs/cliui/node_modules/string-width": {
1897 "version": "5.1.2",
1898 "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
1899 "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
1997 - "dev": true,
1900 "dependencies": {
1901 "eastasianwidth": "^0.2.0",
1902 "emoji-regex": "^9.2.2",
@@ -2011,7 +1913,6 @@
1913 "version": "7.1.0",
1914 "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
1915 "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
2014 - "dev": true,
1916 "dependencies": {
1917 "ansi-regex": "^6.0.1"
1918 },
@@ -2453,7 +2354,6 @@
2354 "version": "0.11.0",
2355 "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
2356 "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
2456 - "dev": true,
2357 "optional": true,
2358 "engines": {
2359 "node": ">=14"
@@ -2477,13 +2377,13 @@
2377 "dev": true
2378 },
2379 "node_modules/@rollup/pluginutils": {
2480 - "version": "5.1.2",
2481 - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.2.tgz",
2482 - "integrity": "sha512-/FIdS3PyZ39bjZlwqFnWqCOVnW7o963LtKMwQOD0NhQqw22gSr2YY1afu3FxRip4ZCZNsD5jq6Aaz6QV3D/Njw==",
2380 + "version": "5.1.3",
2381 + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.3.tgz",
2382 + "integrity": "sha512-Pnsb6f32CD2W3uCaLZIzDmeFyQ2b8UWMFI7xtwUezpcGBDVDW6y9XgAWIlARiGAo6eNF5FK5aQTr0LFyNyqq5A==",
2383 "dependencies": {
2384 "@types/estree": "^1.0.0",
2385 "estree-walker": "^2.0.2",
2486 - "picomatch": "^2.3.1"
2386 + "picomatch": "^4.0.2"
2387 },
2388 "engines": {
2389 "node": ">=14.0.0"
@@ -2497,17 +2397,6 @@
2397 }
2398 }
2399 },
2500 - "node_modules/@rollup/pluginutils/node_modules/picomatch": {
2501 - "version": "2.3.1",
2502 - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
2503 - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
2504 - "engines": {
2505 - "node": ">=8.6"
2506 - },
2507 - "funding": {
2508 - "url": "https://github.com/sponsors/jonschlinkert"
2509 - }
2510 - },
2400 "node_modules/@rollup/rollup-android-arm-eabi": {
2401 "version": "4.24.0",
2402 "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.0.tgz",
@@ -2716,50 +2605,50 @@
2605 ]
2606 },
2607 "node_modules/@shikijs/core": {
2719 - "version": "1.22.0",
2720 - "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.22.0.tgz",
2721 - "integrity": "sha512-S8sMe4q71TJAW+qG93s5VaiihujRK6rqDFqBnxqvga/3LvqHEnxqBIOPkt//IdXVtHkQWKu4nOQNk0uBGicU7Q==",
2608 + "version": "1.22.1",
2609 + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.22.1.tgz",
2610 + "integrity": "sha512-bqAhT/Ri5ixV4oYsvJNH8UJjpjbINWlWyXY6tBTsP4OmD6XnFv43nRJ+lTdxd2rmG5pgam/x+zGR6kLRXrpEKA==",
2611 "dependencies": {
2723 - "@shikijs/engine-javascript": "1.22.0",
2724 - "@shikijs/engine-oniguruma": "1.22.0",
2725 - "@shikijs/types": "1.22.0",
2612 + "@shikijs/engine-javascript": "1.22.1",
2613 + "@shikijs/engine-oniguruma": "1.22.1",
2614 + "@shikijs/types": "1.22.1",
2615 "@shikijs/vscode-textmate": "^9.3.0",
2616 "@types/hast": "^3.0.4",
2617 "hast-util-to-html": "^9.0.3"
2618 }
2619 },
2620 "node_modules/@shikijs/engine-javascript": {
2732 - "version": "1.22.0",
2733 - "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-1.22.0.tgz",
2734 - "integrity": "sha512-AeEtF4Gcck2dwBqCFUKYfsCq0s+eEbCEbkUuFou53NZ0sTGnJnJ/05KHQFZxpii5HMXbocV9URYVowOP2wH5kw==",
2621 + "version": "1.22.1",
2622 + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-1.22.1.tgz",
2623 + "integrity": "sha512-540pyoy0LWe4jj2BVbgELwOFu1uFvRI7lg4hdsExrSXA9x7gqfzZ/Nnh4RfX86aDAgJ647gx4TCmRwACbnQSvw==",
2624 "dependencies": {
2736 - "@shikijs/types": "1.22.0",
2625 + "@shikijs/types": "1.22.1",
2626 "@shikijs/vscode-textmate": "^9.3.0",
2627 "oniguruma-to-js": "0.4.3"
2628 }
2629 },
2630 "node_modules/@shikijs/engine-oniguruma": {
2742 - "version": "1.22.0",
2743 - "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-1.22.0.tgz",
2744 - "integrity": "sha512-5iBVjhu/DYs1HB0BKsRRFipRrD7rqjxlWTj4F2Pf+nQSPqc3kcyqFFeZXnBMzDf0HdqaFVvhDRAGiYNvyLP+Mw==",
2631 + "version": "1.22.1",
2632 + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-1.22.1.tgz",
2633 + "integrity": "sha512-L+1Vmd+a2kk8HtogUFymQS6BjUfJnzcWoUp1BUgxoDiklbKSMvrsMuLZGevTOP1m0rEjgnC5MsDmsr8lX1lC+Q==",
2634 "dependencies": {
2746 - "@shikijs/types": "1.22.0",
2635 + "@shikijs/types": "1.22.1",
2636 "@shikijs/vscode-textmate": "^9.3.0"
2637 }
2638 },
2639 "node_modules/@shikijs/markdown-it": {
2751 - "version": "1.22.0",
2752 - "resolved": "https://registry.npmjs.org/@shikijs/markdown-it/-/markdown-it-1.22.0.tgz",
2753 - "integrity": "sha512-IAWi2pbzYndiuXOWnV5Ll4ULQJeWl45WUACl1Xc2KSiBl0JtQmqKvPOGKN7YSZbyIzkB6bWUItRrv5ucO35U+g==",
2640 + "version": "1.22.1",
2641 + "resolved": "https://registry.npmjs.org/@shikijs/markdown-it/-/markdown-it-1.22.1.tgz",
2642 + "integrity": "sha512-OlzsxMrICd/wrwXXEnA+gpcvBh9zbRCxtC6OssjVzBcMIIhc6Uz64KnWFW02T6G7Ac6FRsl8CNIIWIDVIlhU0w==",
2643 "dependencies": {
2644 "markdown-it": "^14.1.0",
2756 - "shiki": "1.22.0"
2645 + "shiki": "1.22.1"
2646 }
2647 },
2648 "node_modules/@shikijs/types": {
2760 - "version": "1.22.0",
2761 - "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-1.22.0.tgz",
2762 - "integrity": "sha512-Fw/Nr7FGFhlQqHfxzZY8Cwtwk5E9nKDUgeLjZgt3UuhcM3yJR9xj3ZGNravZZok8XmEZMiYkSMTPlPkULB8nww==",
2649 + "version": "1.22.1",
2650 + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-1.22.1.tgz",
2651 + "integrity": "sha512-+45f8mu/Hxqs6Kyhfm98Nld5n7Q7lwhjU8UtdQwrOPs7BnM4VAb929O3IQ2ce+4D7SlNFlZGd8CnKRSnwbQreQ==",
2652 "dependencies": {
2653 "@shikijs/vscode-textmate": "^9.3.0",
2654 "@types/hast": "^3.0.4"
@@ -2821,6 +2710,14 @@
2710 "eslint": ">=8.40.0"
2711 }
2712 },
2713 + "node_modules/@tailwindcss/container-queries": {
2714 + "version": "0.1.1",
2715 + "resolved": "https://registry.npmjs.org/@tailwindcss/container-queries/-/container-queries-0.1.1.tgz",
2716 + "integrity": "sha512-p18dswChx6WnTSaJCSGx6lTmrGzNNvm2FtXmiO6AuA1V4U5REyoqwmT6kgAsIMdjo07QdAfYXHJ4hnMtfHzWgA==",
2717 + "peerDependencies": {
2718 + "tailwindcss": ">=3.2.0"
2719 + }
2720 + },
2721 "node_modules/@trysound/sax": {
2722 "version": "0.2.0",
2723 "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz",
@@ -2911,9 +2808,9 @@
2808 "integrity": "sha512-HMwFiRujE5PjrgwHQ25+bsLJgowjGjm5Z8FVSf0N6PwgJrwxH0QxzHYDcKsTfV3wva0vzrpqMTJS2jXPr5BMEQ=="
2809 },
2810 "node_modules/@types/lodash": {
2914 - "version": "4.17.10",
2915 - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.10.tgz",
2916 - "integrity": "sha512-YpS0zzoduEhuOWjAotS6A5AVCva7X4lVlYLF0FYHAY9sdraBfnatttHItlWeZdGhuEkf+OzMNg2ZYAx8t+52uQ=="
2811 + "version": "4.17.12",
2812 + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.12.tgz",
2813 + "integrity": "sha512-sviUmCE8AYdaF/KIHLDJBQgeYzPBI0vf/17NaYehBJfYD1j6/L95Slh07NlyK2iNyBNaEkb3En2jRt+a8y3xZQ=="
2814 },
2815 "node_modules/@types/lodash-es": {
2816 "version": "4.17.12",
@@ -2944,12 +2841,12 @@
2841 "dev": true
2842 },
2843 "node_modules/@types/node": {
2947 - "version": "22.7.5",
2948 - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz",
2949 - "integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==",
2844 + "version": "22.8.0",
2845 + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.8.0.tgz",
2846 + "integrity": "sha512-84rafSBHC/z1i1E3p0cJwKA+CfYDNSXX9WSZBRopjIzLET8oNt6ht2tei4C7izwDeEiLLfdeSVBv1egOH916hg==",
2847 "dev": true,
2848 "dependencies": {
2952 - "undici-types": "~6.19.2"
2849 + "undici-types": "~6.19.8"
2850 }
2851 },
2852 "node_modules/@types/normalize-package-data": {
@@ -2976,9 +2873,9 @@
2873 "dev": true
2874 },
2875 "node_modules/@types/sizzle": {
2979 - "version": "2.3.8",
2980 - "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.8.tgz",
2981 - "integrity": "sha512-0vWLNK2D5MT9dg0iOo8GlKguPAU02QjmZitPEsXRuJXU/OGIOt9vT9Fc26wtYuavLxtO45v9PGleoL9Z0k1LHg==",
2876 + "version": "2.3.9",
2877 + "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.9.tgz",
2878 + "integrity": "sha512-xzLEyKB50yqCUPUJkIsrVvoWNfFUbIZI+RspLWt8u+tIW/BetMBZtgV2LY/2o+tYH8dRvQ+eoPf3NdhQCcLE2w==",
2879 "dev": true
2880 },
2881 "node_modules/@types/tough-cookie": {
@@ -3014,16 +2911,16 @@
2911 }
2912 },
2913 "node_modules/@typescript-eslint/eslint-plugin": {
3017 - "version": "8.9.0",
3018 - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.9.0.tgz",
3019 - "integrity": "sha512-Y1n621OCy4m7/vTXNlCbMVp87zSd7NH0L9cXD8aIpOaNlzeWxIK4+Q19A68gSmTNRZn92UjocVUWDthGxtqHFg==",
2914 + "version": "8.11.0",
2915 + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.11.0.tgz",
2916 + "integrity": "sha512-KhGn2LjW1PJT2A/GfDpiyOfS4a8xHQv2myUagTM5+zsormOmBlYsnQ6pobJ8XxJmh6hnHwa2Mbe3fPrDJoDhbA==",
2917 "dev": true,
2918 "dependencies": {
2919 "@eslint-community/regexpp": "^4.10.0",
3023 - "@typescript-eslint/scope-manager": "8.9.0",
3024 - "@typescript-eslint/type-utils": "8.9.0",
3025 - "@typescript-eslint/utils": "8.9.0",
3026 - "@typescript-eslint/visitor-keys": "8.9.0",
2920 + "@typescript-eslint/scope-manager": "8.11.0",
2921 + "@typescript-eslint/type-utils": "8.11.0",
2922 + "@typescript-eslint/utils": "8.11.0",
2923 + "@typescript-eslint/visitor-keys": "8.11.0",
2924 "graphemer": "^1.4.0",
2925 "ignore": "^5.3.1",
2926 "natural-compare": "^1.4.0",
@@ -3047,15 +2944,15 @@
2944 }
2945 },
2946 "node_modules/@typescript-eslint/parser": {
3050 - "version": "8.9.0",
3051 - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.9.0.tgz",
3052 - "integrity": "sha512-U+BLn2rqTTHnc4FL3FJjxaXptTxmf9sNftJK62XLz4+GxG3hLHm/SUNaaXP5Y4uTiuYoL5YLy4JBCJe3+t8awQ==",
2947 + "version": "8.11.0",
2948 + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.11.0.tgz",
2949 + "integrity": "sha512-lmt73NeHdy1Q/2ul295Qy3uninSqi6wQI18XwSpm8w0ZbQXUpjCAWP1Vlv/obudoBiIjJVjlztjQ+d/Md98Yxg==",
2950 "dev": true,
2951 "dependencies": {
3055 - "@typescript-eslint/scope-manager": "8.9.0",
3056 - "@typescript-eslint/types": "8.9.0",
3057 - "@typescript-eslint/typescript-estree": "8.9.0",
3058 - "@typescript-eslint/visitor-keys": "8.9.0",
2952 + "@typescript-eslint/scope-manager": "8.11.0",
2953 + "@typescript-eslint/types": "8.11.0",
2954 + "@typescript-eslint/typescript-estree": "8.11.0",
2955 + "@typescript-eslint/visitor-keys": "8.11.0",
2956 "debug": "^4.3.4"
2957 },
2958 "engines": {
@@ -3075,13 +2972,13 @@
2972 }
2973 },
2974 "node_modules/@typescript-eslint/scope-manager": {
3078 - "version": "8.9.0",
3079 - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.9.0.tgz",
3080 - "integrity": "sha512-bZu9bUud9ym1cabmOYH9S6TnbWRzpklVmwqICeOulTCZ9ue2/pczWzQvt/cGj2r2o1RdKoZbuEMalJJSYw3pHQ==",
2975 + "version": "8.11.0",
2976 + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.11.0.tgz",
2977 + "integrity": "sha512-Uholz7tWhXmA4r6epo+vaeV7yjdKy5QFCERMjs1kMVsLRKIrSdM6o21W2He9ftp5PP6aWOVpD5zvrvuHZC0bMQ==",
2978 "dev": true,
2979 "dependencies": {
3083 - "@typescript-eslint/types": "8.9.0",
3084 - "@typescript-eslint/visitor-keys": "8.9.0"
2980 + "@typescript-eslint/types": "8.11.0",
2981 + "@typescript-eslint/visitor-keys": "8.11.0"
2982 },
2983 "engines": {
2984 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -3092,13 +2989,13 @@
2989 }
2990 },
2991 "node_modules/@typescript-eslint/type-utils": {
3095 - "version": "8.9.0",
3096 - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.9.0.tgz",
3097 - "integrity": "sha512-JD+/pCqlKqAk5961vxCluK+clkppHY07IbV3vett97KOV+8C6l+CPEPwpUuiMwgbOz/qrN3Ke4zzjqbT+ls+1Q==",
2992 + "version": "8.11.0",
2993 + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.11.0.tgz",
2994 + "integrity": "sha512-ItiMfJS6pQU0NIKAaybBKkuVzo6IdnAhPFZA/2Mba/uBjuPQPet/8+zh5GtLHwmuFRShZx+8lhIs7/QeDHflOg==",
2995 "dev": true,
2996 "dependencies": {
3100 - "@typescript-eslint/typescript-estree": "8.9.0",
3101 - "@typescript-eslint/utils": "8.9.0",
2997 + "@typescript-eslint/typescript-estree": "8.11.0",
2998 + "@typescript-eslint/utils": "8.11.0",
2999 "debug": "^4.3.4",
3000 "ts-api-utils": "^1.3.0"
3001 },
@@ -3116,10 +3013,9 @@
3013 }
3014 },
3015 "node_modules/@typescript-eslint/types": {
3119 - "version": "8.9.0",
3120 - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.9.0.tgz",
3121 - "integrity": "sha512-SjgkvdYyt1FAPhU9c6FiYCXrldwYYlIQLkuc+LfAhCna6ggp96ACncdtlbn8FmnG72tUkXclrDExOpEYf1nfJQ==",
3122 - "dev": true,
3016 + "version": "8.11.0",
3017 + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.11.0.tgz",
3018 + "integrity": "sha512-tn6sNMHf6EBAYMvmPUaKaVeYvhUsrE6x+bXQTxjQRp360h1giATU0WvgeEys1spbvb5R+VpNOZ+XJmjD8wOUHw==",
3019 "engines": {
3020 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
3021 },
@@ -3129,13 +3025,12 @@
3025 }
3026 },
3027 "node_modules/@typescript-eslint/typescript-estree": {
3132 - "version": "8.9.0",
3133 - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.9.0.tgz",
3134 - "integrity": "sha512-9iJYTgKLDG6+iqegehc5+EqE6sqaee7kb8vWpmHZ86EqwDjmlqNNHeqDVqb9duh+BY6WCNHfIGvuVU3Tf9Db0g==",
3135 - "dev": true,
3028 + "version": "8.11.0",
3029 + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.11.0.tgz",
3030 + "integrity": "sha512-yHC3s1z1RCHoCz5t06gf7jH24rr3vns08XXhfEqzYpd6Hll3z/3g23JRi0jM8A47UFKNc3u/y5KIMx8Ynbjohg==",
3031 "dependencies": {
3137 - "@typescript-eslint/types": "8.9.0",
3138 - "@typescript-eslint/visitor-keys": "8.9.0",
3032 + "@typescript-eslint/types": "8.11.0",
3033 + "@typescript-eslint/visitor-keys": "8.11.0",
3034 "debug": "^4.3.4",
3035 "fast-glob": "^3.3.2",
3036 "is-glob": "^4.0.3",
@@ -3157,15 +3052,15 @@
3052 }
3053 },
3054 "node_modules/@typescript-eslint/utils": {
3160 - "version": "8.9.0",
3161 - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.9.0.tgz",
3162 - "integrity": "sha512-PKgMmaSo/Yg/F7kIZvrgrWa1+Vwn036CdNUvYFEkYbPwOH4i8xvkaRlu148W3vtheWK9ckKRIz7PBP5oUlkrvQ==",
3055 + "version": "8.11.0",
3056 + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.11.0.tgz",
3057 + "integrity": "sha512-CYiX6WZcbXNJV7UNB4PLDIBtSdRmRI/nb0FMyqHPTQD1rMjA0foPLaPUV39C/MxkTd/QKSeX+Gb34PPsDVC35g==",
3058 "dev": true,
3059 "dependencies": {
3060 "@eslint-community/eslint-utils": "^4.4.0",
3166 - "@typescript-eslint/scope-manager": "8.9.0",
3167 - "@typescript-eslint/types": "8.9.0",
3168 - "@typescript-eslint/typescript-estree": "8.9.0"
3061 + "@typescript-eslint/scope-manager": "8.11.0",
3062 + "@typescript-eslint/types": "8.11.0",
3063 + "@typescript-eslint/typescript-estree": "8.11.0"
3064 },
3065 "engines": {
3066 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -3179,12 +3074,11 @@
3074 }
3075 },
3076 "node_modules/@typescript-eslint/visitor-keys": {
3182 - "version": "8.9.0",
3183 - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.9.0.tgz",
3184 - "integrity": "sha512-Ht4y38ubk4L5/U8xKUBfKNYGmvKvA1CANoxiTRMM+tOLk3lbF3DvzZCxJCRSE+2GdCMSh6zq9VZJc3asc1XuAA==",
3185 - "dev": true,
3077 + "version": "8.11.0",
3078 + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.11.0.tgz",
3079 + "integrity": "sha512-EaewX6lxSjRJnc+99+dqzTeoDZUfyrA52d2/HRrkI830kgovWsmIiTfmr0NZorzqic7ga+1bS60lRBUgR3n/Bw==",
3080 "dependencies": {
3187 - "@typescript-eslint/types": "8.9.0",
3081 + "@typescript-eslint/types": "8.11.0",
3082 "eslint-visitor-keys": "^3.4.3"
3083 },
3084 "engines": {
@@ -3199,7 +3093,6 @@
3093 "version": "3.4.3",
3094 "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
3095 "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
3202 - "dev": true,
3096 "engines": {
3097 "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
3098 },
@@ -3290,28 +3183,6 @@
3183 "url": "https://opencollective.com/eslint"
3184 }
3185 },
3293 - "node_modules/@unocss/eslint-plugin/node_modules/@eslint/eslintrc/node_modules/brace-expansion": {
3294 - "version": "1.1.11",
3295 - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
3296 - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
3297 - "peer": true,
3298 - "dependencies": {
3299 - "balanced-match": "^1.0.0",
3300 - "concat-map": "0.0.1"
3301 - }
3302 - },
3303 - "node_modules/@unocss/eslint-plugin/node_modules/@eslint/eslintrc/node_modules/minimatch": {
3304 - "version": "3.1.2",
3305 - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
3306 - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
3307 - "peer": true,
3308 - "dependencies": {
3309 - "brace-expansion": "^1.1.7"
3310 - },
3311 - "engines": {
3312 - "node": "*"
3313 - }
3314 - },
3186 "node_modules/@unocss/eslint-plugin/node_modules/@typescript-eslint/scope-manager": {
3187 "version": "6.21.0",
3188 "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz",
@@ -3340,33 +3211,6 @@
3211 "url": "https://opencollective.com/typescript-eslint"
3212 }
3213 },
3343 - "node_modules/@unocss/eslint-plugin/node_modules/@typescript-eslint/typescript-estree": {
3344 - "version": "6.21.0",
3345 - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz",
3346 - "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==",
3347 - "dependencies": {
3348 - "@typescript-eslint/types": "6.21.0",
3349 - "@typescript-eslint/visitor-keys": "6.21.0",
3350 - "debug": "^4.3.4",
3351 - "globby": "^11.1.0",
3352 - "is-glob": "^4.0.3",
3353 - "minimatch": "9.0.3",
3354 - "semver": "^7.5.4",
3355 - "ts-api-utils": "^1.0.1"
3356 - },
3357 - "engines": {
3358 - "node": "^16.0.0 || >=18.0.0"
3359 - },
3360 - "funding": {
3361 - "type": "opencollective",
3362 - "url": "https://opencollective.com/typescript-eslint"
3363 - },
3364 - "peerDependenciesMeta": {
3365 - "typescript": {
3366 - "optional": true
3367 - }
3368 - }
3369 - },
3214 "node_modules/@unocss/eslint-plugin/node_modules/@typescript-eslint/utils": {
3215 "version": "6.21.0",
3216 "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz",
@@ -3407,61 +3251,22 @@
3251 "url": "https://opencollective.com/typescript-eslint"
3252 }
3253 },
3410 - "node_modules/@unocss/eslint-plugin/node_modules/ansi-styles": {
3411 - "version": "4.3.0",
3412 - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
3413 - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
3414 - "peer": true,
3415 - "dependencies": {
3416 - "color-convert": "^2.0.1"
3417 - },
3418 - "engines": {
3419 - "node": ">=8"
3420 - },
3421 - "funding": {
3422 - "url": "https://github.com/chalk/ansi-styles?sponsor=1"
3423 - }
3424 - },
3254 "node_modules/@unocss/eslint-plugin/node_modules/argparse": {
3255 "version": "2.0.1",
3256 "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
3257 "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
3258 "peer": true
3259 },
3431 - "node_modules/@unocss/eslint-plugin/node_modules/chalk": {
3432 - "version": "4.1.2",
3433 - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
3434 - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
3435 - "peer": true,
3436 - "dependencies": {
3437 - "ansi-styles": "^4.1.0",
3438 - "supports-color": "^7.1.0"
3439 - },
3440 - "engines": {
3441 - "node": ">=10"
3442 - },
3443 - "funding": {
3444 - "url": "https://github.com/chalk/chalk?sponsor=1"
3445 - }
3446 - },
3447 - "node_modules/@unocss/eslint-plugin/node_modules/color-convert": {
3448 - "version": "2.0.1",
3449 - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
3450 - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
3260 + "node_modules/@unocss/eslint-plugin/node_modules/brace-expansion": {
3261 + "version": "1.1.11",
3262 + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
3263 + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
3264 "peer": true,
3265 "dependencies": {
3453 - "color-name": "~1.1.4"
3454 - },
3455 - "engines": {
3456 - "node": ">=7.0.0"
3266 + "balanced-match": "^1.0.0",
3267 + "concat-map": "0.0.1"
3268 }
3269 },
3459 - "node_modules/@unocss/eslint-plugin/node_modules/color-name": {
3460 - "version": "1.1.4",
3461 - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
3462 - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
3463 - "peer": true
3464 - },
3270 "node_modules/@unocss/eslint-plugin/node_modules/eslint": {
3271 "version": "8.57.1",
3272 "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz",
@@ -3545,28 +3350,6 @@
3350 "url": "https://opencollective.com/eslint"
3351 }
3352 },
3548 - "node_modules/@unocss/eslint-plugin/node_modules/eslint/node_modules/brace-expansion": {
3549 - "version": "1.1.11",
3550 - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
3551 - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
3552 - "peer": true,
3553 - "dependencies": {
3554 - "balanced-match": "^1.0.0",
3555 - "concat-map": "0.0.1"
3556 - }
3557 - },
3558 - "node_modules/@unocss/eslint-plugin/node_modules/eslint/node_modules/minimatch": {
3559 - "version": "3.1.2",
3560 - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
3561 - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
3562 - "peer": true,
3563 - "dependencies": {
3564 - "brace-expansion": "^1.1.7"
3565 - },
3566 - "engines": {
3567 - "node": "*"
3568 - }
3569 - },
3353 "node_modules/@unocss/eslint-plugin/node_modules/espree": {
3354 "version": "9.6.1",
3355 "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
@@ -3625,34 +3408,6 @@
3408 "url": "https://github.com/sponsors/sindresorhus"
3409 }
3410 },
3628 - "node_modules/@unocss/eslint-plugin/node_modules/globby": {
3629 - "version": "11.1.0",
3630 - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
3631 - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
3632 - "dependencies": {
3633 - "array-union": "^2.1.0",
3634 - "dir-glob": "^3.0.1",
3635 - "fast-glob": "^3.2.9",
3636 - "ignore": "^5.2.0",
3637 - "merge2": "^1.4.1",
3638 - "slash": "^3.0.0"
3639 - },
3640 - "engines": {
3641 - "node": ">=10"
3642 - },
3643 - "funding": {
3644 - "url": "https://github.com/sponsors/sindresorhus"
3645 - }
3646 - },
3647 - "node_modules/@unocss/eslint-plugin/node_modules/has-flag": {
3648 - "version": "4.0.0",
3649 - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
3650 - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
3651 - "peer": true,
3652 - "engines": {
3653 - "node": ">=8"
3654 - }
3655 - },
3411 "node_modules/@unocss/eslint-plugin/node_modules/js-yaml": {
3412 "version": "4.1.0",
3413 "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
@@ -3666,37 +3421,15 @@
3421 }
3422 },
3423 "node_modules/@unocss/eslint-plugin/node_modules/minimatch": {
3669 - "version": "9.0.3",
3670 - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
3671 - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
3672 - "dependencies": {
3673 - "brace-expansion": "^2.0.1"
3674 - },
3675 - "engines": {
3676 - "node": ">=16 || 14 >=14.17"
3677 - },
3678 - "funding": {
3679 - "url": "https://github.com/sponsors/isaacs"
3680 - }
3681 - },
3682 - "node_modules/@unocss/eslint-plugin/node_modules/slash": {
3683 - "version": "3.0.0",
3684 - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
3685 - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
3686 - "engines": {
3687 - "node": ">=8"
3688 - }
3689 - },
3690 - "node_modules/@unocss/eslint-plugin/node_modules/supports-color": {
3691 - "version": "7.2.0",
3692 - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
3693 - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
3424 + "version": "3.1.2",
3425 + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
3426 + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
3427 "peer": true,
3428 "dependencies": {
3696 - "has-flag": "^4.0.0"
3429 + "brace-expansion": "^1.1.7"
3430 },
3431 "engines": {
3699 - "node": ">=8"
3432 + "node": "*"
3433 }
3434 },
3435 "node_modules/@unocss/eslint-plugin/node_modules/type-fest": {
@@ -3879,27 +3612,27 @@
3612 }
3613 },
3614 "node_modules/@volar/language-core": {
3882 - "version": "2.4.6",
3883 - "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.6.tgz",
3884 - "integrity": "sha512-FxUfxaB8sCqvY46YjyAAV6c3mMIq/NWQMVvJ+uS4yxr1KzOvyg61gAuOnNvgCvO4TZ7HcLExBEsWcDu4+K4E8A==",
3615 + "version": "2.4.7",
3616 + "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.7.tgz",
3617 + "integrity": "sha512-G/EB0vkArVB04F8DVBf30AlRK/QAOx63CzsuKKuda2ZIJamQlv4t6gEJrFVmYF560kbslFtaAJcmn8cyg7QmLA==",
3618 "dev": true,
3619 "dependencies": {
3887 - "@volar/source-map": "2.4.6"
3620 + "@volar/source-map": "2.4.7"
3621 }
3622 },
3623 "node_modules/@volar/source-map": {
3891 - "version": "2.4.6",
3892 - "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.6.tgz",
3893 - "integrity": "sha512-Nsh7UW2ruK+uURIPzjJgF0YRGP5CX9nQHypA2OMqdM2FKy7rh+uv3XgPnWPw30JADbKvZ5HuBzG4gSbVDYVtiw==",
3624 + "version": "2.4.7",
3625 + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.7.tgz",
3626 + "integrity": "sha512-c+7IJrD4mht1s8FLlCf6dAUC1aTUY9leKeLosfUiuMxavcG/sY3IPBiD1rdLL5qrhzYVmUWRGxhWvJeyYa/bsQ==",
3627 "dev": true
3628 },
3629 "node_modules/@volar/typescript": {
3897 - "version": "2.4.6",
3898 - "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.6.tgz",
3899 - "integrity": "sha512-NMIrA7y5OOqddL9VtngPWYmdQU03htNKFtAYidbYfWA0TOhyGVd9tfcP4TsLWQ+RBWDZCbBqsr8xzU0ZOxYTCQ==",
3630 + "version": "2.4.7",
3631 + "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.7.tgz",
3632 + "integrity": "sha512-sp3mFLmMtXY47S8GrMwFnwjGiW7aVtCLMAwnePRJA4P7CfSkrRj2DjoSxl//0pt+KR7oGG/48T2q413b8TvPbg==",
3633 "dev": true,
3634 "dependencies": {
3902 - "@volar/language-core": "2.4.6",
3635 + "@volar/language-core": "2.4.7",
3636 "path-browserify": "^1.0.1",
3637 "vscode-uri": "^3.0.8"
3638 }
@@ -4014,13 +3747,13 @@
3747 "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g=="
3748 },
3749 "node_modules/@vue/devtools-core": {
4017 - "version": "7.4.6",
4018 - "resolved": "https://registry.npmjs.org/@vue/devtools-core/-/devtools-core-7.4.6.tgz",
4019 - "integrity": "sha512-7ATNPEbVqThOOAp2bg/YUIm9MqqgimbSk24D05hdXUp89JlXX12aTzdrWd9xZRwS78hDR+wCToHl1C/8sopBrg==",
3750 + "version": "7.5.4",
3751 + "resolved": "https://registry.npmjs.org/@vue/devtools-core/-/devtools-core-7.5.4.tgz",
3752 + "integrity": "sha512-igB2iUKsCUrXkp0wKLn3n5X8jz3AgXWk7if0QpLu3Do16QmlTO0e+/VvTpX0ZbLMh8OOAxDKyfPvJMMO/4QJ5w==",
3753 "dev": true,
3754 "dependencies": {
4022 - "@vue/devtools-kit": "^7.4.6",
4023 - "@vue/devtools-shared": "^7.4.6",
3755 + "@vue/devtools-kit": "^7.5.4",
3756 + "@vue/devtools-shared": "^7.5.4",
3757 "mitt": "^3.0.1",
3758 "nanoid": "^3.3.4",
3759 "pathe": "^1.1.2",
@@ -4049,13 +3782,13 @@
3782 }
3783 },
3784 "node_modules/@vue/devtools-kit": {
4052 - "version": "7.4.6",
4053 - "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.4.6.tgz",
4054 - "integrity": "sha512-NbYBwPWgEic1AOd9bWExz9weBzFdjiIfov0yRn4DrRfR+EQJCI9dn4I0XS7IxYGdkmUJi8mFW42LLk18WsGqew==",
3785 + "version": "7.5.4",
3786 + "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.5.4.tgz",
3787 + "integrity": "sha512-0i7WFgc1B2TL52tstn82zlb9opSA0aIiHfkUYFXtZb8CIpmlFMTkHtgwVl6PMWNBj3LNhYou1YJCLpCYvJYYoA==",
3788 "dev": true,
3789 "dependencies": {
4057 - "@vue/devtools-shared": "^7.4.6",
4058 - "birpc": "^0.2.17",
3790 + "@vue/devtools-shared": "^7.5.4",
3791 + "birpc": "^0.2.19",
3792 "hookable": "^5.5.3",
3793 "mitt": "^3.0.1",
3794 "perfect-debounce": "^1.0.0",
@@ -4064,9 +3797,9 @@
3797 }
3798 },
3799 "node_modules/@vue/devtools-shared": {
4067 - "version": "7.4.6",
4068 - "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.4.6.tgz",
4069 - "integrity": "sha512-rPeSBzElnHYMB05Cc056BQiJpgocQjY8XVulgni+O9a9Gr9tNXgPteSzFFD+fT/iWMxNuUgGKs9CuW5DZewfIg==",
3800 + "version": "7.5.4",
3801 + "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.5.4.tgz",
3802 + "integrity": "sha512-dwuq4YmwTyLc7eBOqX63s3JB8il7qnKsNgENglSMkUPwiItHkVAYYfPESN1rxSdYkl1RCux1l5TBidYqfUDNAA==",
3803 "dev": true,
3804 "dependencies": {
3805 "rfdc": "^1.4.1"
@@ -4269,9 +4002,9 @@
4002 }
4003 },
4004 "node_modules/acorn": {
4272 - "version": "8.12.1",
4273 - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz",
4274 - "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==",
4005 + "version": "8.13.0",
4006 + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.13.0.tgz",
4007 + "integrity": "sha512-8zSiw54Oxrdym50NlZ9sUusyO1Z1ZchgRLWRaK6c86XJFClyCgFKetdowBg5bKxyp/u+CDBJG4Mpp0m3HLZl9w==",
4008 "bin": {
4009 "acorn": "bin/acorn"
4010 },
@@ -4372,21 +4105,23 @@
4105 }
4106 },
4107 "node_modules/ansi-styles": {
4375 - "version": "3.2.1",
4376 - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
4377 - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
4108 + "version": "4.3.0",
4109 + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
4110 + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
4111 "dependencies": {
4379 - "color-convert": "^1.9.0"
4112 + "color-convert": "^2.0.1"
4113 },
4114 "engines": {
4382 - "node": ">=4"
4115 + "node": ">=8"
4116 + },
4117 + "funding": {
4118 + "url": "https://github.com/chalk/ansi-styles?sponsor=1"
4119 }
4120 },
4121 "node_modules/any-promise": {
4122 "version": "1.3.0",
4123 "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
4388 - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==",
4389 - "dev": true
4124 + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="
4125 },
4126 "node_modules/anymatch": {
4127 "version": "3.1.3",
@@ -4458,8 +4193,7 @@
4193 "node_modules/arg": {
4194 "version": "5.0.2",
4195 "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
4461 - "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==",
4462 - "dev": true
4196 + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="
4197 },
4198 "node_modules/argparse": {
4199 "version": "1.0.10",
@@ -4483,6 +4217,7 @@
4217 "version": "2.1.0",
4218 "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
4219 "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
4220 + "dev": true,
4221 "engines": {
4222 "node": ">=8"
4223 }
@@ -4710,9 +4445,9 @@
4445 }
4446 },
4447 "node_modules/browserslist": {
4713 - "version": "4.24.0",
4714 - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.0.tgz",
4715 - "integrity": "sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A==",
4448 + "version": "4.24.2",
4449 + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz",
4450 + "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==",
4451 "funding": [
4452 {
4453 "type": "opencollective",
@@ -4728,10 +4463,10 @@
4463 }
4464 ],
4465 "dependencies": {
4731 - "caniuse-lite": "^1.0.30001663",
4732 - "electron-to-chromium": "^1.5.28",
4466 + "caniuse-lite": "^1.0.30001669",
4467 + "electron-to-chromium": "^1.5.41",
4468 "node-releases": "^2.0.18",
4734 - "update-browserslist-db": "^1.1.0"
4469 + "update-browserslist-db": "^1.1.1"
4470 },
4471 "bin": {
4472 "browserslist": "cli.js"
@@ -4933,15 +4668,14 @@
4668 "version": "2.0.1",
4669 "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
4670 "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==",
4936 - "dev": true,
4671 "engines": {
4672 "node": ">= 6"
4673 }
4674 },
4675 "node_modules/caniuse-lite": {
4942 - "version": "1.0.30001668",
4943 - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001668.tgz",
4944 - "integrity": "sha512-nWLrdxqCdblixUO+27JtGJJE/txpJlyUy5YN1u53wLZkP0emYCo5zgS6QYft7VUYR42LGgi/S5hdLZTrnyIddw==",
4676 + "version": "1.0.30001669",
4677 + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001669.tgz",
4678 + "integrity": "sha512-DlWzFDJqstqtIVx1zeSpIMLjunf5SmwOw0N2Ck/QSQdS8PLS4+9HrLaYei4w8BIAL7IB/UEDu889d8vhCTPA0w==",
4679 "funding": [
4680 {
4681 "type": "opencollective",
@@ -4973,9 +4707,9 @@
4707 }
4708 },
4709 "node_modules/chai": {
4976 - "version": "5.1.1",
4977 - "resolved": "https://registry.npmjs.org/chai/-/chai-5.1.1.tgz",
4978 - "integrity": "sha512-pT1ZgP8rPNqUgieVaEY+ryQr6Q4HXNg8Ei9UnLUrjN4IA7dvQC5JB+/kxVcPNDHyBcc/26CXPkbNzq3qwrOEKA==",
4710 + "version": "5.1.2",
4711 + "resolved": "https://registry.npmjs.org/chai/-/chai-5.1.2.tgz",
4712 + "integrity": "sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw==",
4713 "dev": true,
4714 "dependencies": {
4715 "assertion-error": "^2.0.1",
@@ -4989,24 +4723,29 @@
4723 }
4724 },
4725 "node_modules/chalk": {
4992 - "version": "2.4.2",
4993 - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
4994 - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
4726 + "version": "4.1.2",
4727 + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
4728 + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
4729 "dependencies": {
4996 - "ansi-styles": "^3.2.1",
4997 - "escape-string-regexp": "^1.0.5",
4998 - "supports-color": "^5.3.0"
4730 + "ansi-styles": "^4.1.0",
4731 + "supports-color": "^7.1.0"
4732 },
4733 "engines": {
5001 - "node": ">=4"
4734 + "node": ">=10"
4735 + },
4736 + "funding": {
4737 + "url": "https://github.com/chalk/chalk?sponsor=1"
4738 }
4739 },
5004 - "node_modules/chalk/node_modules/escape-string-regexp": {
5005 - "version": "1.0.5",
5006 - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
5007 - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
4740 + "node_modules/chalk/node_modules/supports-color": {
4741 + "version": "7.2.0",
4742 + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
4743 + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
4744 + "dependencies": {
4745 + "has-flag": "^4.0.0"
4746 + },
4747 "engines": {
5009 - "node": ">=0.8.0"
4748 + "node": ">=8"
4749 }
4750 },
4751 "node_modules/character-entities": {
@@ -5212,39 +4951,6 @@
4951 "node": ">=12"
4952 }
4953 },
5215 - "node_modules/cliui/node_modules/ansi-styles": {
5216 - "version": "4.3.0",
5217 - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
5218 - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
5219 - "dev": true,
5220 - "dependencies": {
5221 - "color-convert": "^2.0.1"
5222 - },
5223 - "engines": {
5224 - "node": ">=8"
5225 - },
5226 - "funding": {
5227 - "url": "https://github.com/chalk/ansi-styles?sponsor=1"
5228 - }
5229 - },
5230 - "node_modules/cliui/node_modules/color-convert": {
5231 - "version": "2.0.1",
5232 - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
5233 - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
5234 - "dev": true,
5235 - "dependencies": {
5236 - "color-name": "~1.1.4"
5237 - },
5238 - "engines": {
5239 - "node": ">=7.0.0"
5240 - }
5241 - },
5242 - "node_modules/cliui/node_modules/color-name": {
5243 - "version": "1.1.4",
5244 - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
5245 - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
5246 - "dev": true
5247 - },
4954 "node_modules/cliui/node_modules/wrap-ansi": {
4955 "version": "7.0.0",
4956 "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
@@ -5273,17 +4979,20 @@
4979 }
4980 },
4981 "node_modules/color-convert": {
5276 - "version": "1.9.3",
5277 - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
5278 - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
4982 + "version": "2.0.1",
4983 + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
4984 + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
4985 "dependencies": {
5280 - "color-name": "1.1.3"
4986 + "color-name": "~1.1.4"
4987 + },
4988 + "engines": {
4989 + "node": ">=7.0.0"
4990 }
4991 },
4992 "node_modules/color-name": {
5284 - "version": "1.1.3",
5285 - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
5286 - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
4993 + "version": "1.1.4",
4994 + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
4995 + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
4996 },
4997 "node_modules/colord": {
4998 "version": "2.9.3",
@@ -5612,9 +5321,9 @@
5321 "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
5322 },
5323 "node_modules/cypress": {
5615 - "version": "13.15.0",
5616 - "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.15.0.tgz",
5617 - "integrity": "sha512-53aO7PwOfi604qzOkCSzNlWquCynLlKE/rmmpSPcziRH6LNfaDUAklQT6WJIsD8ywxlIy+uVZsnTMCCQVd2kTw==",
5324 + "version": "13.15.1",
5325 + "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.15.1.tgz",
5326 + "integrity": "sha512-DwUFiKXo4lef9kA0M4iEhixFqoqp2hw8igr0lTqafRb9qtU3X0XGxKbkSYsUFdkrAkphc7MPDxoNPhk5pj9PVg==",
5327 "dev": true,
5328 "hasInstallScript": true,
5329 "dependencies": {
@@ -5658,6 +5367,7 @@
5367 "semver": "^7.5.3",
5368 "supports-color": "^8.1.1",
5369 "tmp": "~0.2.3",
5370 + "tree-kill": "1.2.2",
5371 "untildify": "^4.0.0",
5372 "yauzl": "^2.10.0"
5373 },
@@ -5668,67 +5378,6 @@
5378 "node": "^16.0.0 || ^18.0.0 || >=20.0.0"
5379 }
5380 },
5671 - "node_modules/cypress/node_modules/ansi-styles": {
5672 - "version": "4.3.0",
5673 - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
5674 - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
5675 - "dev": true,
5676 - "dependencies": {
5677 - "color-convert": "^2.0.1"
5678 - },
5679 - "engines": {
5680 - "node": ">=8"
5681 - },
5682 - "funding": {
5683 - "url": "https://github.com/chalk/ansi-styles?sponsor=1"
5684 - }
5685 - },
5686 - "node_modules/cypress/node_modules/chalk": {
5687 - "version": "4.1.2",
5688 - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
5689 - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
5690 - "dev": true,
5691 - "dependencies": {
5692 - "ansi-styles": "^4.1.0",
5693 - "supports-color": "^7.1.0"
5694 - },
5695 - "engines": {
5696 - "node": ">=10"
5697 - },
5698 - "funding": {
5699 - "url": "https://github.com/chalk/chalk?sponsor=1"
5700 - }
5701 - },
5702 - "node_modules/cypress/node_modules/chalk/node_modules/supports-color": {
5703 - "version": "7.2.0",
5704 - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
5705 - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
5706 - "dev": true,
5707 - "dependencies": {
5708 - "has-flag": "^4.0.0"
5709 - },
5710 - "engines": {
5711 - "node": ">=8"
5712 - }
5713 - },
5714 - "node_modules/cypress/node_modules/color-convert": {
5715 - "version": "2.0.1",
5716 - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
5717 - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
5718 - "dev": true,
5719 - "dependencies": {
5720 - "color-name": "~1.1.4"
5721 - },
5722 - "engines": {
5723 - "node": ">=7.0.0"
5724 - }
5725 - },
5726 - "node_modules/cypress/node_modules/color-name": {
5727 - "version": "1.1.4",
5728 - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
5729 - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
5730 - "dev": true
5731 - },
5381 "node_modules/cypress/node_modules/fs-extra": {
5382 "version": "9.1.0",
5383 "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
@@ -5744,36 +5393,12 @@
5393 "node": ">=10"
5394 }
5395 },
5747 - "node_modules/cypress/node_modules/has-flag": {
5748 - "version": "4.0.0",
5749 - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
5750 - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
5751 - "dev": true,
5752 - "engines": {
5753 - "node": ">=8"
5754 - }
5755 - },
5396 "node_modules/cypress/node_modules/proxy-from-env": {
5397 "version": "1.0.0",
5398 "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz",
5399 "integrity": "sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A==",
5400 "dev": true
5401 },
5762 - "node_modules/cypress/node_modules/supports-color": {
5763 - "version": "8.1.1",
5764 - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
5765 - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
5766 - "dev": true,
5767 - "dependencies": {
5768 - "has-flag": "^4.0.0"
5769 - },
5770 - "engines": {
5771 - "node": ">=10"
5772 - },
5773 - "funding": {
5774 - "url": "https://github.com/chalk/supports-color?sponsor=1"
5775 - }
5776 - },
5402 "node_modules/dashdash": {
5403 "version": "1.14.1",
5404 "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
@@ -6002,21 +5627,6 @@
5627 "node": ">=10"
5628 }
5629 },
6005 - "node_modules/depcheck/node_modules/ansi-styles": {
6006 - "version": "4.3.0",
6007 - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
6008 - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
6009 - "dev": true,
6010 - "dependencies": {
6011 - "color-convert": "^2.0.1"
6012 - },
6013 - "engines": {
6014 - "node": ">=8"
6015 - },
6016 - "funding": {
6017 - "url": "https://github.com/chalk/ansi-styles?sponsor=1"
6018 - }
6019 - },
5630 "node_modules/depcheck/node_modules/cliui": {
5631 "version": "7.0.4",
5632 "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
@@ -6028,24 +5638,6 @@
5638 "wrap-ansi": "^7.0.0"
5639 }
5640 },
6031 - "node_modules/depcheck/node_modules/color-convert": {
6032 - "version": "2.0.1",
6033 - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
6034 - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
6035 - "dev": true,
6036 - "dependencies": {
6037 - "color-name": "~1.1.4"
6038 - },
6039 - "engines": {
6040 - "node": ">=7.0.0"
6041 - }
6042 - },
6043 - "node_modules/depcheck/node_modules/color-name": {
6044 - "version": "1.1.4",
6045 - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
6046 - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
6047 - "dev": true
6048 - },
5641 "node_modules/depcheck/node_modules/minimatch": {
5642 "version": "7.4.6",
5643 "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.6.tgz",
@@ -6184,25 +5776,12 @@
5776 "node_modules/didyoumean": {
5777 "version": "1.2.2",
5778 "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
6187 - "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==",
6188 - "dev": true
6189 - },
6190 - "node_modules/dir-glob": {
6191 - "version": "3.0.1",
6192 - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
6193 - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
6194 - "dependencies": {
6195 - "path-type": "^4.0.0"
6196 - },
6197 - "engines": {
6198 - "node": ">=8"
6199 - }
5779 + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw=="
5780 },
5781 "node_modules/dlv": {
5782 "version": "1.1.3",
5783 "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
6204 - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==",
6205 - "dev": true
5784 + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="
5785 },
5786 "node_modules/doctrine": {
5787 "version": "3.0.0",
@@ -6290,8 +5869,7 @@
5869 "node_modules/eastasianwidth": {
5870 "version": "0.2.0",
5871 "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
6293 - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
6294 - "dev": true
5872 + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="
5873 },
5874 "node_modules/easy-bem": {
5875 "version": "1.1.1",
@@ -6366,15 +5944,14 @@
5944 "dev": true
5945 },
5946 "node_modules/electron-to-chromium": {
6369 - "version": "1.5.38",
6370 - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.38.tgz",
6371 - "integrity": "sha512-VbeVexmZ1IFh+5EfrYz1I0HTzHVIlJa112UEWhciPyeOcKJGeTv6N8WnG4wsQB81DGCaVEGhpSb6o6a8WYFXXg=="
5947 + "version": "1.5.45",
5948 + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.45.tgz",
5949 + "integrity": "sha512-vOzZS6uZwhhbkZbcRyiy99Wg+pYFV5hk+5YaECvx0+Z31NR3Tt5zS6dze2OepT6PCTzVzT0dIJItti+uAW5zmw=="
5950 },
5951 "node_modules/emoji-regex": {
5952 "version": "8.0.0",
5953 "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
6376 - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
6377 - "dev": true
5954 + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
5955 },
5956 "node_modules/encodeurl": {
5957 "version": "1.0.2",
@@ -6540,16 +6117,16 @@
6117 }
6118 },
6119 "node_modules/eslint": {
6543 - "version": "9.12.0",
6544 - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.12.0.tgz",
6545 - "integrity": "sha512-UVIOlTEWxwIopRL1wgSQYdnVDcEvs2wyaO6DGo5mXqe3r16IoCNWkR29iHhyaP4cICWjbgbmFUGAhh0GJRuGZw==",
6120 + "version": "9.13.0",
6121 + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.13.0.tgz",
6122 + "integrity": "sha512-EYZK6SX6zjFHST/HRytOdA/zE72Cq/bfw45LSyuwrdvcclb/gqV8RRQxywOBEWO2+WDpva6UZa4CcDeJKzUCFA==",
6123 "dependencies": {
6124 "@eslint-community/eslint-utils": "^4.2.0",
6125 "@eslint-community/regexpp": "^4.11.0",
6126 "@eslint/config-array": "^0.18.0",
6550 - "@eslint/core": "^0.6.0",
6127 + "@eslint/core": "^0.7.0",
6128 "@eslint/eslintrc": "^3.1.0",
6552 - "@eslint/js": "9.12.0",
6129 + "@eslint/js": "9.13.0",
6130 "@eslint/plugin-kit": "^0.2.0",
6131 "@humanfs/node": "^0.16.5",
6132 "@humanwhocodes/module-importer": "^1.0.1",
@@ -6780,15 +6357,15 @@
6357 }
6358 },
6359 "node_modules/eslint-plugin-import-x/node_modules/tslib": {
6783 - "version": "2.7.0",
6784 - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz",
6785 - "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==",
6360 + "version": "2.8.0",
6361 + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz",
6362 + "integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==",
6363 "dev": true
6364 },
6365 "node_modules/eslint-plugin-jsdoc": {
6789 - "version": "50.4.1",
6790 - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-50.4.1.tgz",
6791 - "integrity": "sha512-OXIq+JJQPCLAKL473/esioFOwbXyRE5MAQ4HbZjcp3e+K3zdxt2uDpGs3FR+WezUXNStzEtTfgx15T+JFrVwBA==",
6366 + "version": "50.4.3",
6367 + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-50.4.3.tgz",
6368 + "integrity": "sha512-uWtwFxGRv6B8sU63HZM5dAGDhgsatb+LONwmILZJhdRALLOkCX2HFZhdL/Kw2ls8SQMAVEfK+LmnEfxInRN8HA==",
6369 "dev": true,
6370 "dependencies": {
6371 "@es-joy/jsdoccomment": "~0.49.0",
@@ -6841,9 +6418,9 @@
6418 }
6419 },
6420 "node_modules/eslint-plugin-jsdoc/node_modules/tslib": {
6844 - "version": "2.7.0",
6845 - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz",
6846 - "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==",
6421 + "version": "2.8.0",
6422 + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz",
6423 + "integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==",
6424 "dev": true
6425 },
6426 "node_modules/eslint-plugin-jsonc": {
@@ -6912,9 +6489,9 @@
6489 }
6490 },
6491 "node_modules/eslint-plugin-jsonc/node_modules/tslib": {
6915 - "version": "2.7.0",
6916 - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz",
6917 - "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==",
6492 + "version": "2.8.0",
6493 + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz",
6494 + "integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==",
6495 "dev": true
6496 },
6497 "node_modules/eslint-plugin-n": {
@@ -6952,13 +6529,13 @@
6529 }
6530 },
6531 "node_modules/eslint-plugin-perfectionist": {
6955 - "version": "3.8.0",
6956 - "resolved": "https://registry.npmjs.org/eslint-plugin-perfectionist/-/eslint-plugin-perfectionist-3.8.0.tgz",
6957 - "integrity": "sha512-BYJWbQVOjvIGK9V1xUfn790HuvkePjxti8epOi1H6sdzo0N4RehBmQ8coHPbgA/f12BUG1NIoDtQhI9mUm+o2A==",
6532 + "version": "3.9.1",
6533 + "resolved": "https://registry.npmjs.org/eslint-plugin-perfectionist/-/eslint-plugin-perfectionist-3.9.1.tgz",
6534 + "integrity": "sha512-9WRzf6XaAxF4Oi5t/3TqKP5zUjERhasHmLFHin2Yw6ZAp/EP/EVA2dr3BhQrrHWCm5SzTMZf0FcjDnBkO2xFkA==",
6535 "dev": true,
6536 "dependencies": {
6960 - "@typescript-eslint/types": "^8.8.0",
6961 - "@typescript-eslint/utils": "^8.8.0",
6537 + "@typescript-eslint/types": "^8.9.0",
6538 + "@typescript-eslint/utils": "^8.9.0",
6539 "minimatch": "^9.0.5",
6540 "natural-compare-lite": "^1.4.0"
6541 },
@@ -7032,9 +6609,9 @@
6609 }
6610 },
6611 "node_modules/eslint-plugin-prettier/node_modules/tslib": {
7035 - "version": "2.7.0",
7036 - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz",
7037 - "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA=="
6612 + "version": "2.8.0",
6613 + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz",
6614 + "integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA=="
6615 },
6616 "node_modules/eslint-plugin-regexp": {
6617 "version": "2.6.0",
@@ -7079,18 +6656,18 @@
6656 }
6657 },
6658 "node_modules/eslint-plugin-unicorn": {
7082 - "version": "55.0.0",
7083 - "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-55.0.0.tgz",
7084 - "integrity": "sha512-n3AKiVpY2/uDcGrS3+QsYDkjPfaOrNrsfQxU9nt5nitd9KuvVXrfAvgCO9DYPSfap+Gqjw9EOrXIsBp5tlHZjA==",
6659 + "version": "56.0.0",
6660 + "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-56.0.0.tgz",
6661 + "integrity": "sha512-aXpddVz/PQMmd69uxO98PA4iidiVNvA0xOtbpUoz1WhBd4RxOQQYqN618v68drY0hmy5uU2jy1bheKEVWBjlPw==",
6662 "dev": true,
6663 "dependencies": {
7087 - "@babel/helper-validator-identifier": "^7.24.5",
6664 + "@babel/helper-validator-identifier": "^7.24.7",
6665 "@eslint-community/eslint-utils": "^4.4.0",
6666 "ci-info": "^4.0.0",
6667 "clean-regexp": "^1.0.0",
7091 - "core-js-compat": "^3.37.0",
7092 - "esquery": "^1.5.0",
7093 - "globals": "^15.7.0",
6668 + "core-js-compat": "^3.38.1",
6669 + "esquery": "^1.6.0",
6670 + "globals": "^15.9.0",
6671 "indent-string": "^4.0.0",
6672 "is-builtin-module": "^3.2.1",
6673 "jsesc": "^3.0.2",
@@ -7098,7 +6675,7 @@
6675 "read-pkg-up": "^7.0.1",
6676 "regexp-tree": "^0.1.27",
6677 "regjsparser": "^0.10.0",
7101 - "semver": "^7.6.1",
6678 + "semver": "^7.6.3",
6679 "strip-indent": "^3.0.0"
6680 },
6681 "engines": {
@@ -7127,9 +6704,9 @@
6704 }
6705 },
6706 "node_modules/eslint-plugin-vue": {
7130 - "version": "9.29.0",
7131 - "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.29.0.tgz",
7132 - "integrity": "sha512-hamyjrBhNH6Li6R1h1VF9KHfshJlKgKEg3ARbGTn72CMNDSMhWbgC7NdkRDEh25AFW+4SDATzyNM+3gWuZii8g==",
6707 + "version": "9.29.1",
6708 + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.29.1.tgz",
6709 + "integrity": "sha512-MH/MbVae4HV/tM8gKAVWMPJbYgW04CK7SuzYRrlNERpxbO0P3+Zdsa2oAcFBW6xNu7W6lIkGOsFAMCRTYmrlWQ==",
6710 "dependencies": {
6711 "@eslint-community/eslint-utils": "^4.4.0",
6712 "globals": "^13.24.0",
@@ -7234,27 +6811,13 @@
6811 }
6812 },
6813 "node_modules/eslint/node_modules/@eslint/js": {
7237 - "version": "9.12.0",
7238 - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.12.0.tgz",
7239 - "integrity": "sha512-eohesHH8WFRUprDNyEREgqP6beG6htMeUYeCpkEgBCieCMme5r9zFWjzAJp//9S+Kub4rqE+jXe9Cp1a7IYIIA==",
6814 + "version": "9.13.0",
6815 + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.13.0.tgz",
6816 + "integrity": "sha512-IFLyoY4d72Z5y/6o/BazFBezupzI/taV8sGumxTAVw3lXG9A6md1Dc34T9s1FoD/an9pJH8RHbAxsaEbBed9lA==",
6817 "engines": {
6818 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
6819 }
6820 },
7244 - "node_modules/eslint/node_modules/ansi-styles": {
7245 - "version": "4.3.0",
7246 - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
7247 - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
7248 - "dependencies": {
7249 - "color-convert": "^2.0.1"
7250 - },
7251 - "engines": {
7252 - "node": ">=8"
7253 - },
7254 - "funding": {
7255 - "url": "https://github.com/chalk/ansi-styles?sponsor=1"
7256 - }
7257 - },
6821 "node_modules/eslint/node_modules/brace-expansion": {
6822 "version": "1.1.11",
6823 "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -7264,45 +6827,6 @@
6827 "concat-map": "0.0.1"
6828 }
6829 },
7267 - "node_modules/eslint/node_modules/chalk": {
7268 - "version": "4.1.2",
7269 - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
7270 - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
7271 - "dependencies": {
7272 - "ansi-styles": "^4.1.0",
7273 - "supports-color": "^7.1.0"
7274 - },
7275 - "engines": {
7276 - "node": ">=10"
7277 - },
7278 - "funding": {
7279 - "url": "https://github.com/chalk/chalk?sponsor=1"
7280 - }
7281 - },
7282 - "node_modules/eslint/node_modules/color-convert": {
7283 - "version": "2.0.1",
7284 - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
7285 - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
7286 - "dependencies": {
7287 - "color-name": "~1.1.4"
7288 - },
7289 - "engines": {
7290 - "node": ">=7.0.0"
7291 - }
7292 - },
7293 - "node_modules/eslint/node_modules/color-name": {
7294 - "version": "1.1.4",
7295 - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
7296 - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
7297 - },
7298 - "node_modules/eslint/node_modules/has-flag": {
7299 - "version": "4.0.0",
7300 - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
7301 - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
7302 - "engines": {
7303 - "node": ">=8"
7304 - }
7305 - },
6830 "node_modules/eslint/node_modules/minimatch": {
6831 "version": "3.1.2",
6832 "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
@@ -7314,17 +6838,6 @@
6838 "node": "*"
6839 }
6840 },
7317 - "node_modules/eslint/node_modules/supports-color": {
7318 - "version": "7.2.0",
7319 - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
7320 - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
7321 - "dependencies": {
7322 - "has-flag": "^4.0.0"
7323 - },
7324 - "engines": {
7325 - "node": ">=8"
7326 - }
7327 - },
6841 "node_modules/espree": {
6842 "version": "10.2.0",
6843 "resolved": "https://registry.npmjs.org/espree/-/espree-10.2.0.tgz",
@@ -7720,7 +7233,6 @@
7233 "version": "3.3.0",
7234 "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz",
7235 "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==",
7723 - "dev": true,
7236 "dependencies": {
7237 "cross-spawn": "^7.0.0",
7238 "signal-exit": "^4.0.1"
@@ -7736,7 +7248,6 @@
7248 "version": "4.1.0",
7249 "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
7250 "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
7739 - "dev": true,
7251 "engines": {
7252 "node": ">=14"
7253 },
@@ -7857,7 +7368,6 @@
7368 "version": "1.1.2",
7369 "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
7370 "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
7860 - "dev": true,
7371 "funding": {
7372 "url": "https://github.com/sponsors/ljharb"
7373 }
@@ -7965,7 +7475,6 @@
7475 "version": "10.4.5",
7476 "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
7477 "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
7968 - "dev": true,
7478 "dependencies": {
7479 "foreground-child": "^3.1.0",
7480 "jackspeak": "^3.1.2",
@@ -8121,11 +7630,11 @@
7630 "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag=="
7631 },
7632 "node_modules/has-flag": {
8124 - "version": "3.0.0",
8125 - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
8126 - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
7633 + "version": "4.0.0",
7634 + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
7635 + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
7636 "engines": {
8128 - "node": ">=4"
7637 + "node": ">=8"
7638 }
7639 },
7640 "node_modules/has-property-descriptors": {
@@ -8188,7 +7697,6 @@
7697 "version": "2.0.2",
7698 "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
7699 "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
8191 - "dev": true,
7700 "dependencies": {
7701 "function-bind": "^1.1.2"
7702 },
@@ -8657,7 +8165,6 @@
8165 "version": "2.15.1",
8166 "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz",
8167 "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==",
8660 - "dev": true,
8168 "dependencies": {
8169 "hasown": "^2.0.2"
8170 },
@@ -8695,7 +8202,6 @@
8202 "version": "3.0.0",
8203 "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
8204 "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
8698 - "dev": true,
8205 "engines": {
8206 "node": ">=8"
8207 }
@@ -8875,7 +8381,6 @@
8381 "version": "3.4.3",
8382 "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
8383 "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==",
8878 - "dev": true,
8384 "dependencies": {
8385 "@isaacs/cliui": "^8.0.2"
8386 },
@@ -8908,9 +8413,9 @@
8413 }
8414 },
8415 "node_modules/jose": {
8911 - "version": "5.9.4",
8912 - "resolved": "https://registry.npmjs.org/jose/-/jose-5.9.4.tgz",
8913 - "integrity": "sha512-WBBl6au1qg6OHj67yCffCgFR3BADJBXN8MdRvCgJDuMv3driV2nHr7jdGvaKX9IolosAsn+M0XRArqLXUhyJHQ==",
8416 + "version": "5.9.6",
8417 + "resolved": "https://registry.npmjs.org/jose/-/jose-5.9.6.tgz",
8418 + "integrity": "sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ==",
8419 "funding": {
8420 "url": "https://github.com/sponsors/panva"
8421 }
@@ -9394,7 +8899,6 @@
8899 "version": "2.1.0",
8900 "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
8901 "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==",
9397 - "dev": true,
8902 "engines": {
8903 "node": ">=10"
8904 }
@@ -9402,8 +8906,7 @@
8906 "node_modules/lines-and-columns": {
8907 "version": "1.2.4",
8908 "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
9405 - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
9406 - "dev": true
8909 + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="
8910 },
8911 "node_modules/linkify-it": {
8912 "version": "5.0.0",
@@ -9440,39 +8943,6 @@
8943 }
8944 }
8945 },
9443 - "node_modules/listr2/node_modules/ansi-styles": {
9444 - "version": "4.3.0",
9445 - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
9446 - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
9447 - "dev": true,
9448 - "dependencies": {
9449 - "color-convert": "^2.0.1"
9450 - },
9451 - "engines": {
9452 - "node": ">=8"
9453 - },
9454 - "funding": {
9455 - "url": "https://github.com/chalk/ansi-styles?sponsor=1"
9456 - }
9457 - },
9458 - "node_modules/listr2/node_modules/color-convert": {
9459 - "version": "2.0.1",
9460 - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
9461 - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
9462 - "dev": true,
9463 - "dependencies": {
9464 - "color-name": "~1.1.4"
9465 - },
9466 - "engines": {
9467 - "node": ">=7.0.0"
9468 - }
9469 - },
9470 - "node_modules/listr2/node_modules/color-name": {
9471 - "version": "1.1.4",
9472 - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
9473 - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
9474 - "dev": true
9475 - },
8946 "node_modules/listr2/node_modules/wrap-ansi": {
8947 "version": "7.0.0",
8948 "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
@@ -9565,76 +9035,6 @@
9035 "url": "https://github.com/sponsors/sindresorhus"
9036 }
9037 },
9568 - "node_modules/log-symbols/node_modules/ansi-styles": {
9569 - "version": "4.3.0",
9570 - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
9571 - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
9572 - "dev": true,
9573 - "dependencies": {
9574 - "color-convert": "^2.0.1"
9575 - },
9576 - "engines": {
9577 - "node": ">=8"
9578 - },
9579 - "funding": {
9580 - "url": "https://github.com/chalk/ansi-styles?sponsor=1"
9581 - }
9582 - },
9583 - "node_modules/log-symbols/node_modules/chalk": {
9584 - "version": "4.1.2",
9585 - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
9586 - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
9587 - "dev": true,
9588 - "dependencies": {
9589 - "ansi-styles": "^4.1.0",
9590 - "supports-color": "^7.1.0"
9591 - },
9592 - "engines": {
9593 - "node": ">=10"
9594 - },
9595 - "funding": {
9596 - "url": "https://github.com/chalk/chalk?sponsor=1"
9597 - }
9598 - },
9599 - "node_modules/log-symbols/node_modules/color-convert": {
9600 - "version": "2.0.1",
9601 - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
9602 - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
9603 - "dev": true,
9604 - "dependencies": {
9605 - "color-name": "~1.1.4"
9606 - },
9607 - "engines": {
9608 - "node": ">=7.0.0"
9609 - }
9610 - },
9611 - "node_modules/log-symbols/node_modules/color-name": {
9612 - "version": "1.1.4",
9613 - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
9614 - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
9615 - "dev": true
9616 - },
9617 - "node_modules/log-symbols/node_modules/has-flag": {
9618 - "version": "4.0.0",
9619 - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
9620 - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
9621 - "dev": true,
9622 - "engines": {
9623 - "node": ">=8"
9624 - }
9625 - },
9626 - "node_modules/log-symbols/node_modules/supports-color": {
9627 - "version": "7.2.0",
9628 - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
9629 - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
9630 - "dev": true,
9631 - "dependencies": {
9632 - "has-flag": "^4.0.0"
9633 - },
9634 - "engines": {
9635 - "node": ">=8"
9636 - }
9637 - },
9038 "node_modules/log-update": {
9039 "version": "4.0.0",
9040 "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz",
@@ -9653,39 +9053,6 @@
9053 "url": "https://github.com/sponsors/sindresorhus"
9054 }
9055 },
9656 - "node_modules/log-update/node_modules/ansi-styles": {
9657 - "version": "4.3.0",
9658 - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
9659 - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
9660 - "dev": true,
9661 - "dependencies": {
9662 - "color-convert": "^2.0.1"
9663 - },
9664 - "engines": {
9665 - "node": ">=8"
9666 - },
9667 - "funding": {
9668 - "url": "https://github.com/chalk/ansi-styles?sponsor=1"
9669 - }
9670 - },
9671 - "node_modules/log-update/node_modules/color-convert": {
9672 - "version": "2.0.1",
9673 - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
9674 - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
9675 - "dev": true,
9676 - "dependencies": {
9677 - "color-name": "~1.1.4"
9678 - },
9679 - "engines": {
9680 - "node": ">=7.0.0"
9681 - }
9682 - },
9683 - "node_modules/log-update/node_modules/color-name": {
9684 - "version": "1.1.4",
9685 - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
9686 - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
9687 - "dev": true
9688 - },
9056 "node_modules/log-update/node_modules/slice-ansi": {
9057 "version": "4.0.0",
9058 "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz",
@@ -9785,9 +9152,9 @@
9152 "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
9153 },
9154 "node_modules/markdown-table": {
9788 - "version": "3.0.3",
9789 - "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.3.tgz",
9790 - "integrity": "sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==",
9155 + "version": "3.0.4",
9156 + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz",
9157 + "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==",
9158 "dev": true,
9159 "funding": {
9160 "type": "github",
@@ -9823,9 +9190,9 @@
9190 }
9191 },
9192 "node_modules/mdast-util-from-markdown": {
9826 - "version": "2.0.1",
9827 - "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.1.tgz",
9828 - "integrity": "sha512-aJEUyzZ6TzlsX2s5B4Of7lN7EQtAxvtradMMglCQDyaTFgse6CmtmdJ15ElnVRlCg1vpNyVtbem0PWzlNieZsA==",
9193 + "version": "2.0.2",
9194 + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.2.tgz",
9195 + "integrity": "sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==",
9196 "dev": true,
9197 "dependencies": {
9198 "@types/mdast": "^4.0.0",
@@ -10687,7 +10054,6 @@
10054 "version": "9.0.5",
10055 "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
10056 "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
10690 - "dev": true,
10057 "dependencies": {
10058 "brace-expansion": "^2.0.1"
10059 },
@@ -10711,7 +10077,6 @@
10077 "version": "7.1.2",
10078 "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
10079 "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
10714 - "dev": true,
10080 "engines": {
10081 "node": ">=16 || 14 >=14.17"
10082 }
@@ -10845,7 +10210,6 @@
10210 "version": "2.7.0",
10211 "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
10212 "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==",
10848 - "dev": true,
10213 "dependencies": {
10214 "any-promise": "^1.0.0",
10215 "object-assign": "^4.0.1",
@@ -10988,18 +10352,18 @@
10352 }
10353 },
10354 "node_modules/npm-normalize-package-bin": {
10991 - "version": "3.0.1",
10992 - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz",
10993 - "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==",
10355 + "version": "4.0.0",
10356 + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-4.0.0.tgz",
10357 + "integrity": "sha512-TZKxPvItzai9kN9H/TkmCtx/ZN/hvr3vUycjlfmH0ootY9yFBzNOpiXAdIn1Iteqsvk4lQn6B5PTrt+n6h8k/w==",
10358 "dev": true,
10359 "engines": {
10996 - "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
10360 + "node": "^18.17.0 || >=20.5.0"
10361 }
10362 },
10363 "node_modules/npm-run-all2": {
11000 - "version": "6.2.3",
11001 - "resolved": "https://registry.npmjs.org/npm-run-all2/-/npm-run-all2-6.2.3.tgz",
11002 - "integrity": "sha512-5RsxC7jEc/RjxOYBVdEfrJf5FsJ0pHA7jr2/OxrThXknajETCTYjigOCG3iaGjdYIKEQlDuCG0ir0T1HTva8pg==",
10364 + "version": "7.0.1",
10365 + "resolved": "https://registry.npmjs.org/npm-run-all2/-/npm-run-all2-7.0.1.tgz",
10366 + "integrity": "sha512-Adbv+bJQ8UTAM03rRODqrO5cx0YU5KCG2CvHtSURiadvdTjjgGJXdbc1oQ9CXBh9dnGfHSoSB1Web/0Dzp6kOQ==",
10367 "dev": true,
10368 "dependencies": {
10369 "ansi-styles": "^6.2.1",
@@ -11007,8 +10371,9 @@
10371 "memorystream": "^0.3.1",
10372 "minimatch": "^9.0.0",
10373 "pidtree": "^0.6.0",
11010 - "read-package-json-fast": "^3.0.2",
11011 - "shell-quote": "^1.7.3"
10374 + "read-package-json-fast": "^4.0.0",
10375 + "shell-quote": "^1.7.3",
10376 + "which": "^5.0.0"
10377 },
10378 "bin": {
10379 "npm-run-all": "bin/npm-run-all/index.js",
@@ -11017,8 +10382,8 @@
10382 "run-s": "bin/run-s/index.js"
10383 },
10384 "engines": {
11020 - "node": "^14.18.0 || ^16.13.0 || >=18.0.0",
11021 - "npm": ">= 8"
10385 + "node": "^18.17.0 || >=20.5.0",
10386 + "npm": ">= 9"
10387 }
10388 },
10389 "node_modules/npm-run-all2/node_modules/ansi-styles": {
@@ -11029,8 +10394,32 @@
10394 "engines": {
10395 "node": ">=12"
10396 },
11032 - "funding": {
11033 - "url": "https://github.com/chalk/ansi-styles?sponsor=1"
10397 + "funding": {
10398 + "url": "https://github.com/chalk/ansi-styles?sponsor=1"
10399 + }
10400 + },
10401 + "node_modules/npm-run-all2/node_modules/isexe": {
10402 + "version": "3.1.1",
10403 + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz",
10404 + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==",
10405 + "dev": true,
10406 + "engines": {
10407 + "node": ">=16"
10408 + }
10409 + },
10410 + "node_modules/npm-run-all2/node_modules/which": {
10411 + "version": "5.0.0",
10412 + "resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz",
10413 + "integrity": "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==",
10414 + "dev": true,
10415 + "dependencies": {
10416 + "isexe": "^3.1.1"
10417 + },
10418 + "bin": {
10419 + "node-which": "bin/which.js"
10420 + },
10421 + "engines": {
10422 + "node": "^18.17.0 || >=20.5.0"
10423 }
10424 },
10425 "node_modules/npm-run-path": {
@@ -11209,7 +10598,6 @@
10598 "version": "4.1.1",
10599 "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
10600 "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
11212 - "dev": true,
10601 "engines": {
10602 "node": ">=0.10.0"
10603 }
@@ -11218,7 +10606,6 @@
10606 "version": "3.0.0",
10607 "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz",
10608 "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==",
11221 - "dev": true,
10609 "engines": {
10610 "node": ">= 6"
10611 }
@@ -11396,8 +10783,7 @@
10783 "node_modules/package-json-from-dist": {
10784 "version": "1.0.1",
10785 "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
11399 - "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==",
11400 - "dev": true
10786 + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="
10787 },
10788 "node_modules/package-manager-detector": {
10789 "version": "0.2.2",
@@ -11527,14 +10913,12 @@
10913 "node_modules/path-parse": {
10914 "version": "1.0.7",
10915 "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
11530 - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
11531 - "dev": true
10916 + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
10917 },
10918 "node_modules/path-scurry": {
10919 "version": "1.11.1",
10920 "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
10921 "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
11537 - "dev": true,
10922 "dependencies": {
10923 "lru-cache": "^10.2.0",
10924 "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
@@ -11549,8 +10933,7 @@
10933 "node_modules/path-scurry/node_modules/lru-cache": {
10934 "version": "10.4.3",
10935 "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
11552 - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
11553 - "dev": true
10936 + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="
10937 },
10938 "node_modules/path-to-regexp": {
10939 "version": "6.3.0",
@@ -11562,6 +10945,7 @@
10945 "version": "4.0.0",
10946 "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
10947 "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
10948 + "dev": true,
10949 "engines": {
10950 "node": ">=8"
10951 }
@@ -11607,15 +10991,14 @@
10991 "dev": true
10992 },
10993 "node_modules/picocolors": {
11610 - "version": "1.1.0",
11611 - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz",
11612 - "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw=="
10994 + "version": "1.1.1",
10995 + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
10996 + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="
10997 },
10998 "node_modules/picomatch": {
10999 "version": "4.0.2",
11000 "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
11001 "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
11618 - "dev": true,
11002 "engines": {
11003 "node": ">=12"
11004 },
@@ -11639,7 +11022,6 @@
11022 "version": "2.3.0",
11023 "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
11024 "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
11642 - "dev": true,
11025 "engines": {
11026 "node": ">=0.10.0"
11027 }
@@ -11670,9 +11052,9 @@
11052 }
11053 },
11054 "node_modules/pinia-plugin-persistedstate": {
11673 - "version": "4.1.1",
11674 - "resolved": "https://registry.npmjs.org/pinia-plugin-persistedstate/-/pinia-plugin-persistedstate-4.1.1.tgz",
11675 - "integrity": "sha512-fUiUsbfBetGUZzX28z+ImAZw7FDXzwRrk+fN+ljF5OhQMhsSYfYeUzI9FLLtpjekYbfFHWvJiECkLI60RIuiPA==",
11055 + "version": "4.1.2",
11056 + "resolved": "https://registry.npmjs.org/pinia-plugin-persistedstate/-/pinia-plugin-persistedstate-4.1.2.tgz",
11057 + "integrity": "sha512-oh4y4lmtXcgbE3BDWTDBUl9F4G1lhtgDI+GnF+cDDZ/fF6wnGYp4TKQ6FCuv9hMLAkNjs6IzADZHwPBYq10ksQ==",
11058 "dependencies": {
11059 "@nuxt/kit": "^3.13.2",
11060 "deep-pick-omit": "^1.2.1",
@@ -11721,7 +11103,6 @@
11103 "version": "4.0.6",
11104 "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz",
11105 "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==",
11724 - "dev": true,
11106 "engines": {
11107 "node": ">= 6"
11108 }
@@ -11817,7 +11198,6 @@
11198 "version": "15.1.0",
11199 "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz",
11200 "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==",
11820 - "dev": true,
11201 "dependencies": {
11202 "postcss-value-parser": "^4.0.0",
11203 "read-cache": "^1.0.0",
@@ -11834,7 +11214,6 @@
11214 "version": "4.0.1",
11215 "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz",
11216 "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==",
11837 - "dev": true,
11217 "dependencies": {
11218 "camelcase-css": "^2.0.1"
11219 },
@@ -11853,7 +11232,6 @@
11232 "version": "4.0.2",
11233 "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz",
11234 "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==",
11856 - "dev": true,
11235 "funding": [
11236 {
11237 "type": "opencollective",
@@ -11888,7 +11266,6 @@
11266 "version": "3.1.2",
11267 "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz",
11268 "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==",
11891 - "dev": true,
11269 "engines": {
11270 "node": ">=14"
11271 },
@@ -11900,7 +11277,6 @@
11277 "version": "2.6.0",
11278 "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.0.tgz",
11279 "integrity": "sha512-a6ae//JvKDEra2kdi1qzCyrJW/WZCgFi8ydDV+eXExl95t+5R+ijnqHJbz9tmMh8FUjx3iv2fCQ4dclAQlO2UQ==",
11903 - "dev": true,
11280 "bin": {
11281 "yaml": "bin.mjs"
11282 },
@@ -11912,7 +11288,6 @@
11288 "version": "6.2.0",
11289 "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz",
11290 "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==",
11915 - "dev": true,
11291 "funding": [
11292 {
11293 "type": "opencollective",
@@ -11948,8 +11323,7 @@
11323 "node_modules/postcss-value-parser": {
11324 "version": "4.2.0",
11325 "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
11951 - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
11952 - "dev": true
11326 + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
11327 },
11328 "node_modules/postcss/node_modules/nanoid": {
11329 "version": "3.3.7",
@@ -12001,6 +11375,84 @@
11375 "node": ">=6.0.0"
11376 }
11377 },
11378 + "node_modules/prettier-plugin-tailwindcss": {
11379 + "version": "0.6.8",
11380 + "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.6.8.tgz",
11381 + "integrity": "sha512-dGu3kdm7SXPkiW4nzeWKCl3uoImdd5CTZEJGxyypEPL37Wj0HT2pLqjrvSei1nTeuQfO4PUfjeW5cTUNRLZ4sA==",
11382 + "dev": true,
11383 + "engines": {
11384 + "node": ">=14.21.3"
11385 + },
11386 + "peerDependencies": {
11387 + "@ianvs/prettier-plugin-sort-imports": "*",
11388 + "@prettier/plugin-pug": "*",
11389 + "@shopify/prettier-plugin-liquid": "*",
11390 + "@trivago/prettier-plugin-sort-imports": "*",
11391 + "@zackad/prettier-plugin-twig-melody": "*",
11392 + "prettier": "^3.0",
11393 + "prettier-plugin-astro": "*",
11394 + "prettier-plugin-css-order": "*",
11395 + "prettier-plugin-import-sort": "*",
11396 + "prettier-plugin-jsdoc": "*",
11397 + "prettier-plugin-marko": "*",
11398 + "prettier-plugin-multiline-arrays": "*",
11399 + "prettier-plugin-organize-attributes": "*",
11400 + "prettier-plugin-organize-imports": "*",
11401 + "prettier-plugin-sort-imports": "*",
11402 + "prettier-plugin-style-order": "*",
11403 + "prettier-plugin-svelte": "*"
11404 + },
11405 + "peerDependenciesMeta": {
11406 + "@ianvs/prettier-plugin-sort-imports": {
11407 + "optional": true
11408 + },
11409 + "@prettier/plugin-pug": {
11410 + "optional": true
11411 + },
11412 + "@shopify/prettier-plugin-liquid": {
11413 + "optional": true
11414 + },
11415 + "@trivago/prettier-plugin-sort-imports": {
11416 + "optional": true
11417 + },
11418 + "@zackad/prettier-plugin-twig-melody": {
11419 + "optional": true
11420 + },
11421 + "prettier-plugin-astro": {
11422 + "optional": true
11423 + },
11424 + "prettier-plugin-css-order": {
11425 + "optional": true
11426 + },
11427 + "prettier-plugin-import-sort": {
11428 + "optional": true
11429 + },
11430 + "prettier-plugin-jsdoc": {
11431 + "optional": true
11432 + },
11433 + "prettier-plugin-marko": {
11434 + "optional": true
11435 + },
11436 + "prettier-plugin-multiline-arrays": {
11437 + "optional": true
11438 + },
11439 + "prettier-plugin-organize-attributes": {
11440 + "optional": true
11441 + },
11442 + "prettier-plugin-organize-imports": {
11443 + "optional": true
11444 + },
11445 + "prettier-plugin-sort-imports": {
11446 + "optional": true
11447 + },
11448 + "prettier-plugin-style-order": {
11449 + "optional": true
11450 + },
11451 + "prettier-plugin-svelte": {
11452 + "optional": true
11453 + }
11454 + }
11455 + },
11456 "node_modules/pretty-bytes": {
11457 "version": "5.6.0",
11458 "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz",
@@ -12142,31 +11594,30 @@
11594 "version": "1.0.0",
11595 "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
11596 "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==",
12145 - "dev": true,
11597 "dependencies": {
11598 "pify": "^2.3.0"
11599 }
11600 },
11601 "node_modules/read-package-json-fast": {
12151 - "version": "3.0.2",
12152 - "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz",
12153 - "integrity": "sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==",
11602 + "version": "4.0.0",
11603 + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-4.0.0.tgz",
11604 + "integrity": "sha512-qpt8EwugBWDw2cgE2W+/3oxC+KTez2uSVR8JU9Q36TXPAGCaozfQUs59v4j4GFpWTaw0i6hAZSvOmu1J0uOEUg==",
11605 "dev": true,
11606 "dependencies": {
12156 - "json-parse-even-better-errors": "^3.0.0",
12157 - "npm-normalize-package-bin": "^3.0.0"
11607 + "json-parse-even-better-errors": "^4.0.0",
11608 + "npm-normalize-package-bin": "^4.0.0"
11609 },
11610 "engines": {
12160 - "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
11611 + "node": "^18.17.0 || >=20.5.0"
11612 }
11613 },
11614 "node_modules/read-package-json-fast/node_modules/json-parse-even-better-errors": {
12164 - "version": "3.0.2",
12165 - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.2.tgz",
12166 - "integrity": "sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ==",
11615 + "version": "4.0.0",
11616 + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-4.0.0.tgz",
11617 + "integrity": "sha512-lR4MXjGNgkJc7tkQ97kb2nuEMnNCyU//XYVH0MKTGcXEiSudQ5MKGKen3C5QubYy0vmq+JGitUg92uuywGEwIA==",
11618 "dev": true,
11619 "engines": {
12169 - "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
11620 + "node": "^18.17.0 || >=20.5.0"
11621 }
11622 },
11623 "node_modules/read-pkg": {
@@ -12370,21 +11821,6 @@
11821 "node": ">=10"
11822 }
11823 },
12373 - "node_modules/replace-in-file/node_modules/ansi-styles": {
12374 - "version": "4.3.0",
12375 - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
12376 - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
12377 - "dev": true,
12378 - "dependencies": {
12379 - "color-convert": "^2.0.1"
12380 - },
12381 - "engines": {
12382 - "node": ">=8"
12383 - },
12384 - "funding": {
12385 - "url": "https://github.com/chalk/ansi-styles?sponsor=1"
12386 - }
12387 - },
11824 "node_modules/replace-in-file/node_modules/brace-expansion": {
11825 "version": "1.1.11",
11826 "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -12395,40 +11831,6 @@
11831 "concat-map": "0.0.1"
11832 }
11833 },
12398 - "node_modules/replace-in-file/node_modules/chalk": {
12399 - "version": "4.1.2",
12400 - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
12401 - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
12402 - "dev": true,
12403 - "dependencies": {
12404 - "ansi-styles": "^4.1.0",
12405 - "supports-color": "^7.1.0"
12406 - },
12407 - "engines": {
12408 - "node": ">=10"
12409 - },
12410 - "funding": {
12411 - "url": "https://github.com/chalk/chalk?sponsor=1"
12412 - }
12413 - },
12414 - "node_modules/replace-in-file/node_modules/color-convert": {
12415 - "version": "2.0.1",
12416 - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
12417 - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
12418 - "dev": true,
12419 - "dependencies": {
12420 - "color-name": "~1.1.4"
12421 - },
12422 - "engines": {
12423 - "node": ">=7.0.0"
12424 - }
12425 - },
12426 - "node_modules/replace-in-file/node_modules/color-name": {
12427 - "version": "1.1.4",
12428 - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
12429 - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
12430 - "dev": true
12431 - },
11834 "node_modules/replace-in-file/node_modules/glob": {
11835 "version": "7.2.3",
11836 "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
@@ -12450,15 +11852,6 @@
11852 "url": "https://github.com/sponsors/isaacs"
11853 }
11854 },
12453 - "node_modules/replace-in-file/node_modules/has-flag": {
12454 - "version": "4.0.0",
12455 - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
12456 - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
12457 - "dev": true,
12458 - "engines": {
12459 - "node": ">=8"
12460 - }
12461 - },
11855 "node_modules/replace-in-file/node_modules/minimatch": {
11856 "version": "3.1.2",
11857 "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
@@ -12471,18 +11864,6 @@
11864 "node": "*"
11865 }
11866 },
12474 - "node_modules/replace-in-file/node_modules/supports-color": {
12475 - "version": "7.2.0",
12476 - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
12477 - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
12478 - "dev": true,
12479 - "dependencies": {
12480 - "has-flag": "^4.0.0"
12481 - },
12482 - "engines": {
12483 - "node": ">=8"
12484 - }
12485 - },
11867 "node_modules/request-progress": {
11868 "version": "3.0.0",
11869 "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-3.0.0.tgz",
@@ -12517,7 +11898,6 @@
11898 "version": "1.22.8",
11899 "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
11900 "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
12520 - "dev": true,
11901 "dependencies": {
11902 "is-core-module": "^2.13.0",
11903 "path-parse": "^1.0.7",
@@ -12872,9 +12252,9 @@
12252 "dev": true
12253 },
12254 "node_modules/sass": {
12875 - "version": "1.79.5",
12876 - "resolved": "https://registry.npmjs.org/sass/-/sass-1.79.5.tgz",
12877 - "integrity": "sha512-W1h5kp6bdhqFh2tk3DsI771MoEJjvrSY/2ihJRJS4pjIyfJCw0nTsxqhnrUzaLMOJjFchj8rOvraI/YUVjtx5g==",
12255 + "version": "1.80.4",
12256 + "resolved": "https://registry.npmjs.org/sass/-/sass-1.80.4.tgz",
12257 + "integrity": "sha512-rhMQ2tSF5CsuuspvC94nPM9rToiAFw2h3JTrLlgmNw1MH79v8Cr3DH6KF6o6r+8oofY3iYVPUf66KzC8yuVN1w==",
12258 "dev": true,
12259 "dependencies": {
12260 "@parcel/watcher": "^2.4.1",
@@ -13034,14 +12414,14 @@
12414 }
12415 },
12416 "node_modules/shiki": {
13037 - "version": "1.22.0",
13038 - "resolved": "https://registry.npmjs.org/shiki/-/shiki-1.22.0.tgz",
13039 - "integrity": "sha512-/t5LlhNs+UOKQCYBtl5ZsH/Vclz73GIqT2yQsCBygr8L/ppTdmpL4w3kPLoZJbMKVWtoG77Ue1feOjZfDxvMkw==",
13040 - "dependencies": {
13041 - "@shikijs/core": "1.22.0",
13042 - "@shikijs/engine-javascript": "1.22.0",
13043 - "@shikijs/engine-oniguruma": "1.22.0",
13044 - "@shikijs/types": "1.22.0",
12417 + "version": "1.22.1",
12418 + "resolved": "https://registry.npmjs.org/shiki/-/shiki-1.22.1.tgz",
12419 + "integrity": "sha512-PbJ6XxrWLMwB2rm3qdjIHNm3zq4SfFnOx0B3rEoi4AN8AUngsdyZ1tRe5slMPtn6jQkbUURLNZPpLR7Do3k78g==",
12420 + "dependencies": {
12421 + "@shikijs/core": "1.22.1",
12422 + "@shikijs/engine-javascript": "1.22.1",
12423 + "@shikijs/engine-oniguruma": "1.22.1",
12424 + "@shikijs/types": "1.22.1",
12425 "@shikijs/vscode-textmate": "^9.3.0",
12426 "@types/hast": "^3.0.4"
12427 }
@@ -13077,9 +12457,9 @@
12457 "dev": true
12458 },
12459 "node_modules/sirv": {
13080 - "version": "2.0.4",
13081 - "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.4.tgz",
13082 - "integrity": "sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==",
12460 + "version": "3.0.0",
12461 + "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.0.tgz",
12462 + "integrity": "sha512-BPwJGUeDaDCHihkORDchNyyTvWFhcusy1XMmhEVTQTwGeybFbp8YEmB+njbPnth1FibULBSBVwCQni25XlCUDg==",
12463 "dev": true,
12464 "dependencies": {
12465 "@polka/url": "^1.0.0-next.24",
@@ -13087,7 +12467,7 @@
12467 "totalist": "^3.0.0"
12468 },
12469 "engines": {
13090 - "node": ">= 10"
12470 + "node": ">=18"
12471 }
12472 },
12473 "node_modules/sisteransi": {
@@ -13127,39 +12507,6 @@
12507 "node": ">=8"
12508 }
12509 },
13130 - "node_modules/slice-ansi/node_modules/ansi-styles": {
13131 - "version": "4.3.0",
13132 - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
13133 - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
13134 - "dev": true,
13135 - "dependencies": {
13136 - "color-convert": "^2.0.1"
13137 - },
13138 - "engines": {
13139 - "node": ">=8"
13140 - },
13141 - "funding": {
13142 - "url": "https://github.com/chalk/ansi-styles?sponsor=1"
13143 - }
13144 - },
13145 - "node_modules/slice-ansi/node_modules/color-convert": {
13146 - "version": "2.0.1",
13147 - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
13148 - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
13149 - "dev": true,
13150 - "dependencies": {
13151 - "color-name": "~1.1.4"
13152 - },
13153 - "engines": {
13154 - "node": ">=7.0.0"
13155 - }
13156 - },
13157 - "node_modules/slice-ansi/node_modules/color-name": {
13158 - "version": "1.1.4",
13159 - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
13160 - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
13161 - "dev": true
13162 - },
12510 "node_modules/sortablejs": {
12511 "version": "1.14.0",
12512 "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.14.0.tgz",
@@ -13392,7 +12739,6 @@
12739 "version": "4.2.3",
12740 "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
12741 "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
13395 - "dev": true,
12742 "dependencies": {
12743 "emoji-regex": "^8.0.0",
12744 "is-fullwidth-code-point": "^3.0.0",
@@ -13407,7 +12753,6 @@
12753 "version": "4.2.3",
12754 "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
12755 "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
13410 - "dev": true,
12756 "dependencies": {
12757 "emoji-regex": "^8.0.0",
12758 "is-fullwidth-code-point": "^3.0.0",
@@ -13446,7 +12791,6 @@
12791 "version": "6.0.1",
12792 "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
12793 "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
13449 - "dev": true,
12794 "dependencies": {
12795 "ansi-regex": "^5.0.1"
12796 },
@@ -13506,7 +12850,6 @@
12850 "version": "3.35.0",
12851 "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz",
12852 "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==",
13509 - "dev": true,
12853 "dependencies": {
12854 "@jridgewell/gen-mapping": "^0.3.2",
12855 "commander": "^4.0.0",
@@ -13528,7 +12871,6 @@
12871 "version": "4.1.1",
12872 "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
12873 "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==",
13531 - "dev": true,
12874 "engines": {
12875 "node": ">= 6"
12876 }
@@ -13546,21 +12888,24 @@
12888 }
12889 },
12890 "node_modules/supports-color": {
13549 - "version": "5.5.0",
13550 - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
13551 - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
12891 + "version": "8.1.1",
12892 + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
12893 + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
12894 + "dev": true,
12895 "dependencies": {
13553 - "has-flag": "^3.0.0"
12896 + "has-flag": "^4.0.0"
12897 },
12898 "engines": {
13556 - "node": ">=4"
12899 + "node": ">=10"
12900 + },
12901 + "funding": {
12902 + "url": "https://github.com/chalk/supports-color?sponsor=1"
12903 }
12904 },
12905 "node_modules/supports-preserve-symlinks-flag": {
12906 "version": "1.0.0",
12907 "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
12908 "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
13563 - "dev": true,
12909 "engines": {
12910 "node": ">= 0.4"
12911 },
@@ -13721,9 +13066,9 @@
13066 }
13067 },
13068 "node_modules/synckit/node_modules/tslib": {
13724 - "version": "2.7.0",
13725 - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz",
13726 - "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA=="
13069 + "version": "2.8.0",
13070 + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz",
13071 + "integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA=="
13072 },
13073 "node_modules/tailwind-config-viewer": {
13074 "version": "2.0.4",
@@ -13767,10 +13112,9 @@
13112 }
13113 },
13114 "node_modules/tailwindcss": {
13770 - "version": "3.4.13",
13771 - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.13.tgz",
13772 - "integrity": "sha512-KqjHOJKogOUt5Bs752ykCeiwvi0fKVkr5oqsFNt/8px/tA8scFPIlkygsf6jXrfCqGHz7VflA6+yytWuM+XhFw==",
13773 - "dev": true,
13115 + "version": "3.4.14",
13116 + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.14.tgz",
13117 + "integrity": "sha512-IcSvOcTRcUtQQ7ILQL5quRDg7Xs93PdJEk1ZLbhhvJc7uj/OAhYOnruEiwnGgBvUtaUAJ8/mhSw1o8L2jCiENA==",
13118 "dependencies": {
13119 "@alloc/quick-lru": "^5.2.0",
13120 "arg": "^5.0.2",
@@ -13914,7 +13258,6 @@
13258 "version": "3.3.1",
13259 "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
13260 "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==",
13917 - "dev": true,
13261 "dependencies": {
13262 "any-promise": "^1.0.0"
13263 }
@@ -13923,7 +13266,6 @@
13266 "version": "1.6.0",
13267 "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz",
13268 "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==",
13926 - "dev": true,
13269 "dependencies": {
13270 "thenify": ">= 3.1.0 < 4"
13271 },
@@ -13953,9 +13295,9 @@
13295 "dev": true
13296 },
13297 "node_modules/tinyexec": {
13956 - "version": "0.3.0",
13957 - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.0.tgz",
13958 - "integrity": "sha512-tVGE0mVJPGb0chKhqmsoosjsS+qUnJVGJpZgsHYQcGoPlG3B51R3PouqTgEGH2Dc9jjFyOqOpix6ZHNMXp1FZg==",
13298 + "version": "0.3.1",
13299 + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.1.tgz",
13300 + "integrity": "sha512-WiCJLEECkO18gwqIp6+hJg0//p23HXp4S+gGtAKu3mI2F2/sXC4FvHvXvB0zJVVaTPhx1/tOwdbRsa1sOBIKqQ==",
13301 "dev": true
13302 },
13303 "node_modules/tinypool": {
@@ -13986,21 +13328,21 @@
13328 }
13329 },
13330 "node_modules/tldts": {
13989 - "version": "6.1.51",
13990 - "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.51.tgz",
13991 - "integrity": "sha512-33lfQoL0JsDogIbZ8fgRyvv77GnRtwkNE/MOKocwUgPO1WrSfsq7+vQRKxRQZai5zd+zg97Iv9fpFQSzHyWdLA==",
13331 + "version": "6.1.55",
13332 + "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.55.tgz",
13333 + "integrity": "sha512-HxQR/9roQ07Pwc8RyyrJMAxRz5/ssoF3qIPPUiIo3zUt6yMdmYZjM2OZIFMiZ3jHyz9jrGHEHuQZrUhoc1LkDw==",
13334 "dev": true,
13335 "dependencies": {
13994 - "tldts-core": "^6.1.51"
13336 + "tldts-core": "^6.1.55"
13337 },
13338 "bin": {
13339 "tldts": "bin/cli.js"
13340 }
13341 },
13342 "node_modules/tldts-core": {
14001 - "version": "6.1.51",
14002 - "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.51.tgz",
14003 - "integrity": "sha512-bu9oCYYWC1iRjx+3UnAjqCsfrWNZV1ghNQf49b3w5xE8J/tNShHTzp5syWJfwGH+pxUgTTLUnzHnfuydW7wmbg==",
13343 + "version": "6.1.55",
13344 + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.55.tgz",
13345 + "integrity": "sha512-BL+BuKHHaOpntE5BGI6naXjULU6aRlgaYdfDHR3T/hdbNTWkWUZ9yuc11wGnwgpvRwlyUiIK+QohYK3olaVU6Q==",
13346 "dev": true
13347 },
13348 "node_modules/tmp": {
@@ -14012,14 +13354,6 @@
13354 "node": ">=14.14"
13355 }
13356 },
14015 - "node_modules/to-fast-properties": {
14016 - "version": "2.0.0",
14017 - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
14018 - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==",
14019 - "engines": {
14020 - "node": ">=4"
14021 - }
14022 - },
13357 "node_modules/to-regex-range": {
13358 "version": "5.0.1",
13359 "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
@@ -14112,6 +13446,15 @@
13446 "node": ">=18"
13447 }
13448 },
13449 + "node_modules/tree-kill": {
13450 + "version": "1.2.2",
13451 + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz",
13452 + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==",
13453 + "dev": true,
13454 + "bin": {
13455 + "tree-kill": "cli.js"
13456 + }
13457 + },
13458 "node_modules/treemate": {
13459 "version": "0.3.11",
13460 "resolved": "https://registry.npmjs.org/treemate/-/treemate-0.3.11.tgz",
@@ -14140,8 +13483,7 @@
13483 "node_modules/ts-interface-checker": {
13484 "version": "0.1.13",
13485 "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
14143 - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==",
14144 - "dev": true
13486 + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="
13487 },
13488 "node_modules/tslib": {
13489 "version": "2.3.0",
@@ -14638,9 +13980,9 @@
13980 }
13981 },
13982 "node_modules/typescript": {
14641 - "version": "5.5.4",
14642 - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz",
14643 - "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==",
13983 + "version": "5.6.3",
13984 + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz",
13985 + "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==",
13986 "bin": {
13987 "tsc": "bin/tsc",
13988 "tsserver": "bin/tsserver"
@@ -15065,9 +14407,9 @@
14407 }
14408 },
14409 "node_modules/vite": {
15068 - "version": "5.4.9",
15069 - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.9.tgz",
15070 - "integrity": "sha512-20OVpJHh0PAM0oSOELa5GaZNWeDjcAvQjGXy2Uyr+Tp+/D2/Hdz6NLgpJLsarPTA2QJ6v8mX2P1ZfbsSKvdMkg==",
14410 + "version": "5.4.10",
14411 + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.10.tgz",
14412 + "integrity": "sha512-1hvaPshuPUtxeQ0hsVH3Mud0ZanOLwVTneA1EgbAM5LhaZEqyPWGRQ7BtaMvUrTDeEaC8pxtj6a6jku3x4z6SQ==",
14413 "dev": true,
14414 "dependencies": {
14415 "esbuild": "^0.21.3",
@@ -15250,17 +14592,31 @@
14592 "url": "https://github.com/sponsors/sindresorhus"
14593 }
14594 },
14595 + "node_modules/vite-plugin-inspect/node_modules/sirv": {
14596 + "version": "2.0.4",
14597 + "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.4.tgz",
14598 + "integrity": "sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==",
14599 + "dev": true,
14600 + "dependencies": {
14601 + "@polka/url": "^1.0.0-next.24",
14602 + "mrmime": "^2.0.0",
14603 + "totalist": "^3.0.0"
14604 + },
14605 + "engines": {
14606 + "node": ">= 10"
14607 + }
14608 + },
14609 "node_modules/vite-plugin-vue-devtools": {
15254 - "version": "7.4.6",
15255 - "resolved": "https://registry.npmjs.org/vite-plugin-vue-devtools/-/vite-plugin-vue-devtools-7.4.6.tgz",
15256 - "integrity": "sha512-lOKur3qovCB3BQStL0qfHEoIusqya1ngfxfWuqn9DTa6h9rlw6+S3PV4geOP5YBGYQ4NW1hRX70OD8I+sYr1dA==",
14610 + "version": "7.5.4",
14611 + "resolved": "https://registry.npmjs.org/vite-plugin-vue-devtools/-/vite-plugin-vue-devtools-7.5.4.tgz",
14612 + "integrity": "sha512-6yTcGrF+YdplDhNiNCkwj23BQDHA/jp06FR4Bo3rui1GW+8VdFcc26au2gtynPwRDNJXNueTxiVtVb6dq+lNZA==",
14613 "dev": true,
14614 "dependencies": {
15259 - "@vue/devtools-core": "^7.4.6",
15260 - "@vue/devtools-kit": "^7.4.6",
15261 - "@vue/devtools-shared": "^7.4.6",
14615 + "@vue/devtools-core": "^7.5.4",
14616 + "@vue/devtools-kit": "^7.5.4",
14617 + "@vue/devtools-shared": "^7.5.4",
14618 "execa": "^8.0.1",
15263 - "sirv": "^2.0.4",
14619 + "sirv": "^3.0.0",
14620 "vite-plugin-inspect": "^0.8.7",
14621 "vite-plugin-vue-inspector": "^5.2.0"
14622 },
@@ -15873,7 +15229,6 @@
15229 "version": "8.1.0",
15230 "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
15231 "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
15876 - "dev": true,
15232 "dependencies": {
15233 "ansi-styles": "^6.1.0",
15234 "string-width": "^5.0.1",
@@ -15891,7 +15246,6 @@
15246 "version": "7.0.0",
15247 "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
15248 "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
15894 - "dev": true,
15249 "dependencies": {
15250 "ansi-styles": "^4.0.0",
15251 "string-width": "^4.1.0",
@@ -15904,44 +15258,10 @@
15258 "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
15259 }
15260 },
15907 - "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": {
15908 - "version": "4.3.0",
15909 - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
15910 - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
15911 - "dev": true,
15912 - "dependencies": {
15913 - "color-convert": "^2.0.1"
15914 - },
15915 - "engines": {
15916 - "node": ">=8"
15917 - },
15918 - "funding": {
15919 - "url": "https://github.com/chalk/ansi-styles?sponsor=1"
15920 - }
15921 - },
15922 - "node_modules/wrap-ansi-cjs/node_modules/color-convert": {
15923 - "version": "2.0.1",
15924 - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
15925 - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
15926 - "dev": true,
15927 - "dependencies": {
15928 - "color-name": "~1.1.4"
15929 - },
15930 - "engines": {
15931 - "node": ">=7.0.0"
15932 - }
15933 - },
15934 - "node_modules/wrap-ansi-cjs/node_modules/color-name": {
15935 - "version": "1.1.4",
15936 - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
15937 - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
15938 - "dev": true
15939 - },
15261 "node_modules/wrap-ansi/node_modules/ansi-regex": {
15262 "version": "6.1.0",
15263 "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
15264 "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
15944 - "dev": true,
15265 "engines": {
15266 "node": ">=12"
15267 },
@@ -15953,7 +15273,6 @@
15273 "version": "6.2.1",
15274 "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
15275 "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
15956 - "dev": true,
15276 "engines": {
15277 "node": ">=12"
15278 },
@@ -15964,14 +15283,12 @@
15283 "node_modules/wrap-ansi/node_modules/emoji-regex": {
15284 "version": "9.2.2",
15285 "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
15967 - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
15968 - "dev": true
15286 + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="
15287 },
15288 "node_modules/wrap-ansi/node_modules/string-width": {
15289 "version": "5.1.2",
15290 "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
15291 "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
15974 - "dev": true,
15292 "dependencies": {
15293 "eastasianwidth": "^0.2.0",
15294 "emoji-regex": "^9.2.2",
@@ -15988,7 +15305,6 @@
15305 "version": "7.1.0",
15306 "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
15307 "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
15991 - "dev": true,
15308 "dependencies": {
15309 "ansi-regex": "^6.0.1"
15310 },
frontend/package.json
+23 -20
@@ -40,7 +40,8 @@
40 "@fontsource/jetbrains-mono": "^5.1.1",
41 "@fontsource/lexend": "^5.1.1",
42 "@fontsource/public-sans": "^5.1.1",
43 - "@shikijs/markdown-it": "^1.22.0",
43 + "@shikijs/markdown-it": "^1.22.1",
44 + "@tailwindcss/container-queries": "^0.1.1",
45 "@vueuse/core": "^11.1.0",
46 "axios": "^1.7.7",
47 "bytes": "^3.1.2",
@@ -50,7 +51,7 @@
51 "echarts": "^5.5.1",
52 "file-saver": "^2.0.5",
53 "html-entities": "^2.5.2",
53 - "jose": "^5.9.4",
54 + "jose": "^5.9.6",
55 "js-md5": "^0.8.3",
56 "lodash": "^4.17.21",
57 "mitt": "^3.0.1",
@@ -58,9 +59,9 @@
59 "nanoid": "^5.0.7",
60 "password-validator": "^5.3.0",
61 "pinia": "^2.2.4",
61 - "pinia-plugin-persistedstate": "^4.1.1",
62 + "pinia-plugin-persistedstate": "^4.1.2",
63 "secure-ls": "^2.0.0",
63 - "shiki": "^1.22.0",
64 + "shiki": "^1.22.1",
65 "validator": "^13.12.0",
66 "vue": "^3.5.12",
67 "vue-advanced-cropper": "^2.8.9",
@@ -76,7 +77,7 @@
77 "@rollup/rollup-linux-x64-gnu": "^4.24.0"
78 },
79 "devDependencies": {
79 - "@antfu/eslint-config": "^3.7.3",
80 + "@antfu/eslint-config": "^3.8.0",
81 "@clack/prompts": "^0.7.0",
82 "@iconify/vue": "^4.1.2",
83 "@tsconfig/node20": "^20.1.4",
@@ -84,53 +85,55 @@
85 "@types/file-saver": "^2.0.7",
86 "@types/fs-extra": "^11.0.4",
87 "@types/jsdom": "^21.1.7",
87 - "@types/lodash": "^4.17.10",
88 - "@types/node": "^22.7.5",
88 + "@types/lodash": "^4.17.12",
89 + "@types/node": "^22.8.0",
90 "@types/validator": "^13.12.2",
91 "@vitejs/plugin-vue": "^5.1.4",
92 "@vitejs/plugin-vue-jsx": "^4.0.1",
93 "@vue/test-utils": "^2.4.6",
94 "@vue/tsconfig": "^0.5.1",
95 "autoprefixer": "^10.4.20",
95 - "cypress": "^13.15.0",
96 + "cypress": "^13.15.1",
97 "depcheck": "^1.4.7",
97 - "eslint": "^9.12.0",
98 + "eslint": "^9.13.0",
99 "flourite": "^1.3.0",
100 "fs-extra": "^11.2.0",
101 "jsdom": "^25.0.1",
101 - "npm-run-all2": "^6.2.3",
102 + "npm-run-all2": "^7.0.1",
103 "postcss": "^8.4.47",
104 "prettier": "^3.3.3",
104 - "sass": "^1.79.5",
105 + "prettier-plugin-tailwindcss": "^0.6.8",
106 + "sass": "^1.80.4",
107 "start-server-and-test": "^2.0.8",
108 "tailwind-config-viewer": "^2.0.4",
107 - "tailwindcss": "^3.4.13",
109 + "tailwindcss": "^3.4.14",
110 "taze": "^0.17.2",
111 "type-fest": "^4.26.1",
110 - "typescript": "~5.5.4",
112 + "typescript": "~5.6.3",
113 "unplugin-vue-components": "^0.27.4",
112 - "vite": "^5.4.9",
114 + "vite": "^5.4.10",
115 "vite-bundle-visualizer": "^1.2.1",
114 - "vite-plugin-vue-devtools": "^7.4.6",
116 + "vite-plugin-vue-devtools": "^7.5.4",
117 "vite-svg-loader": "^5.1.0",
118 "vitest": "^2.1.3",
119 "vue-tsc": "^2.1.6"
120 },
121 "pnpm": {
122 "overrides": {
121 - "@typescript-eslint/eslint-plugin": "^8.9.0",
123 + "@typescript-eslint/eslint-plugin": "^8.11.0",
124 "@typescript-eslint/eslint-plugin>eslint": "$eslint",
123 - "@typescript-eslint/parser": "^8.9.0",
125 + "@typescript-eslint/parser": "^8.11.0",
126 "@typescript-eslint/parser>eslint": "$eslint",
127 "eslint": "$eslint"
128 }
129 },
130 "overrides": {
131 "@typescript-eslint/eslint-plugin": {
130 - "eslint": "^9.12.0"
132 + "eslint": "^9.13.0"
133 },
134 "@typescript-eslint/parser": {
133 - "eslint": "^9.12.0"
134 - }
135 + "eslint": "^9.13.0"
136 + },
137 + "@typescript-eslint/typescript-estree": "^8.11.0"
138 }
139 }
frontend/pnpm-lock.yaml
+9608 -12411
@@ -1,13017 +1,10214 @@
1 -lockfileVersion: "9.0"
1 +lockfileVersion: '9.0'
2
3 settings:
4 - autoInstallPeers: true
5 - excludeLinksFromLockfile: false
4 + autoInstallPeers: true
5 + excludeLinksFromLockfile: false
6
7 overrides:
8 - "@typescript-eslint/eslint-plugin": ^8.6.0
9 - "@typescript-eslint/eslint-plugin>eslint": ^9.11.0
10 - "@typescript-eslint/parser": ^8.6.0
11 - "@typescript-eslint/parser>eslint": ^9.11.0
12 - eslint: ^9.11.0
8 + '@typescript-eslint/eslint-plugin': ^8.11.0
9 + '@typescript-eslint/eslint-plugin>eslint': ^9.13.0
10 + '@typescript-eslint/parser': ^8.11.0
11 + '@typescript-eslint/parser>eslint': ^9.13.0
12 + eslint: ^9.13.0
13
14 importers:
15 - .:
16 - dependencies:
17 - "@ajoelp/json-to-formdata":
18 - specifier: ^1.5.0
19 - version: 1.5.0
20 - "@f3ve/vue-markdown-it":
21 - specifier: ^0.2.2
22 - version: 0.2.2(eslint@9.11.0(jiti@1.21.6))(prettier@3.3.3)(typescript@5.6.2)(vue@3.5.8(typescript@5.6.2))
23 - "@fontsource/jetbrains-mono":
24 - specifier: ^5.1.0
25 - version: 5.1.0
26 - "@fontsource/lexend":
27 - specifier: ^5.1.0
28 - version: 5.1.0
29 - "@fontsource/public-sans":
30 - specifier: ^5.1.0
31 - version: 5.1.0
32 - "@popperjs/core":
33 - specifier: ^2.11.8
34 - version: 2.11.8
35 - "@shikijs/markdown-it":
36 - specifier: ^1.18.0
37 - version: 1.18.0
38 - "@vueuse/components":
39 - specifier: ^11.1.0
40 - version: 11.1.0(vue@3.5.8(typescript@5.6.2))
41 - "@vueuse/core":
42 - specifier: ^11.1.0
43 - version: 11.1.0(vue@3.5.8(typescript@5.6.2))
44 - apexcharts:
45 - specifier: ^3.53.0
46 - version: 3.53.0
47 - axios:
48 - specifier: ^1.7.7
49 - version: 1.7.7(debug@4.3.7)
50 - bytes:
51 - specifier: ^3.1.2
52 - version: 3.1.2
53 - colord:
54 - specifier: ^2.9.3
55 - version: 2.9.3
56 - crypto-js:
57 - specifier: ^4.2.0
58 - version: 4.2.0
59 - dayjs:
60 - specifier: ^1.11.13
61 - version: 1.11.13
62 - detect-touch-device:
63 - specifier: ^1.1.6
64 - version: 1.1.6
65 - echarts:
66 - specifier: ^5.5.1
67 - version: 5.5.1
68 - file-saver:
69 - specifier: ^2.0.5
70 - version: 2.0.5
71 - html-entities:
72 - specifier: ^2.5.2
73 - version: 2.5.2
74 - jose:
75 - specifier: ^5.9.3
76 - version: 5.9.3
77 - js-md5:
78 - specifier: ^0.8.3
79 - version: 0.8.3
80 - lodash:
81 - specifier: ^4.17.21
82 - version: 4.17.21
83 - mitt:
84 - specifier: ^3.0.1
85 - version: 3.0.1
86 - naive-ui:
87 - specifier: ^2.39.0
88 - version: 2.39.0(vue@3.5.8(typescript@5.6.2))
89 - password-validator:
90 - specifier: ^5.3.0
91 - version: 5.3.0
92 - pinia:
93 - specifier: ^2.2.2
94 - version: 2.2.2(typescript@5.6.2)(vue@3.5.8(typescript@5.6.2))
95 - pinia-plugin-persistedstate:
96 - specifier: ^4.0.2
97 - version: 4.0.2(pinia@2.2.2(typescript@5.6.2)(vue@3.5.8(typescript@5.6.2)))(rollup@4.22.4)
98 - secure-ls:
99 - specifier: ^2.0.0
100 - version: 2.0.0
101 - shiki:
102 - specifier: ^1.18.0
103 - version: 1.18.0
104 - validator:
105 - specifier: ^13.12.0
106 - version: 13.12.0
107 - vue:
108 - specifier: ^3.5.8
109 - version: 3.5.8(typescript@5.6.2)
110 - vue-advanced-cropper:
111 - specifier: ^2.8.9
112 - version: 2.8.9(vue@3.5.8(typescript@5.6.2))
113 - vue-highlight-words:
114 - specifier: ^3.0.1
115 - version: 3.0.1(vue@3.5.8(typescript@5.6.2))
116 - vue-i18n:
117 - specifier: ^10.0.3
118 - version: 10.0.3(vue@3.5.8(typescript@5.6.2))
119 - vue-router:
120 - specifier: ^4.4.5
121 - version: 4.4.5(vue@3.5.8(typescript@5.6.2))
122 - vue-sjv:
123 - specifier: ^0.0.6
124 - version: 0.0.6(vue@3.5.8(typescript@5.6.2))
125 - vue3-apexcharts:
126 - specifier: ^1.6.0
127 - version: 1.6.0(apexcharts@3.53.0)(vue@3.5.8(typescript@5.6.2))
128 - vue3-marquee:
129 - specifier: ^4.2.2
130 - version: 4.2.2(vue@3.5.8(typescript@5.6.2))
131 - vuedraggable:
132 - specifier: ^4.1.0
133 - version: 4.1.0(vue@3.5.8(typescript@5.6.2))
134 - optionalDependencies:
135 - "@rollup/rollup-linux-x64-gnu":
136 - specifier: ^4.22.4
137 - version: 4.22.4
138 - devDependencies:
139 - "@antfu/eslint-config":
140 - specifier: ^3.7.1
141 - version: 3.7.1(@typescript-eslint/utils@8.6.0(eslint@9.11.0(jiti@1.21.6))(typescript@5.6.2))(@unocss/eslint-plugin@0.56.5(eslint@9.11.0(jiti@1.21.6))(typescript@5.6.2))(@vue/compiler-sfc@3.5.8)(eslint@9.11.0(jiti@1.21.6))(typescript@5.6.2)(vitest@2.1.1(@types/node@22.5.5)(jsdom@25.0.1)(sass@1.79.3))
142 - "@clack/prompts":
143 - specifier: ^0.7.0
144 - version: 0.7.0
145 - "@iconify/vue":
146 - specifier: ^4.1.2
147 - version: 4.1.2(vue@3.5.8(typescript@5.6.2))
148 - "@tsconfig/node20":
149 - specifier: ^20.1.4
150 - version: 20.1.4
151 - "@types/bytes":
152 - specifier: ^3.1.4
153 - version: 3.1.4
154 - "@types/file-saver":
155 - specifier: ^2.0.7
156 - version: 2.0.7
157 - "@types/fs-extra":
158 - specifier: ^11.0.4
159 - version: 11.0.4
160 - "@types/inquirer":
161 - specifier: ^9.0.7
162 - version: 9.0.7
163 - "@types/jsdom":
164 - specifier: ^21.1.7
165 - version: 21.1.7
166 - "@types/lodash":
167 - specifier: ^4.17.7
168 - version: 4.17.7
169 - "@types/node":
170 - specifier: ^22.5.5
171 - version: 22.5.5
172 - "@types/validator":
173 - specifier: ^13.12.2
174 - version: 13.12.2
175 - "@vitejs/plugin-vue":
176 - specifier: ^5.1.4
177 - version: 5.1.4(vite@5.4.7(@types/node@22.5.5)(sass@1.79.3))(vue@3.5.8(typescript@5.6.2))
178 - "@vitejs/plugin-vue-jsx":
179 - specifier: ^4.0.1
180 - version: 4.0.1(vite@5.4.7(@types/node@22.5.5)(sass@1.79.3))(vue@3.5.8(typescript@5.6.2))
181 - "@vue/test-utils":
182 - specifier: ^2.4.6
183 - version: 2.4.6
184 - "@vue/tsconfig":
185 - specifier: ^0.5.1
186 - version: 0.5.1
187 - autoprefixer:
188 - specifier: ^10.4.20
189 - version: 10.4.20(postcss@8.4.47)
190 - cypress:
191 - specifier: ^13.14.2
192 - version: 13.14.2
193 - eslint:
194 - specifier: ^9.11.0
195 - version: 9.11.0(jiti@1.21.6)
196 - flourite:
197 - specifier: ^1.3.0
198 - version: 1.3.0
199 - fs-extra:
200 - specifier: ^11.2.0
201 - version: 11.2.0
202 - globals:
203 - specifier: ^15.9.0
204 - version: 15.9.0
205 - jsdom:
206 - specifier: ^25.0.1
207 - version: 25.0.1
208 - json5:
209 - specifier: ^2.2.3
210 - version: 2.2.3
211 - npm-run-all2:
212 - specifier: ^6.2.3
213 - version: 6.2.3
214 - picocolors:
215 - specifier: ^1.1.0
216 - version: 1.1.0
217 - postcss:
218 - specifier: ^8.4.47
219 - version: 8.4.47
220 - prettier:
221 - specifier: ^3.3.3
222 - version: 3.3.3
223 - sass:
224 - specifier: ^1.79.3
225 - version: 1.79.3
226 - start-server-and-test:
227 - specifier: ^2.0.8
228 - version: 2.0.8
229 - tailwind-config-viewer:
230 - specifier: ^2.0.4
231 - version: 2.0.4(tailwindcss@3.4.12)
232 - tailwindcss:
233 - specifier: ^3.4.12
234 - version: 3.4.12
235 - taze:
236 - specifier: ^0.16.9
237 - version: 0.16.9
238 - type-fest:
239 - specifier: ^4.26.1
240 - version: 4.26.1
241 - typescript:
242 - specifier: ~5.6.2
243 - version: 5.6.2
244 - unplugin-vue-components:
245 - specifier: ^0.27.4
246 - version: 0.27.4(@babel/parser@7.25.6)(@nuxt/kit@3.13.2(rollup@4.22.4))(rollup@4.22.4)(vue@3.5.8(typescript@5.6.2))
247 - vite:
248 - specifier: ^5.4.7
249 - version: 5.4.7(@types/node@22.5.5)(sass@1.79.3)
250 - vite-bundle-analyzer:
251 - specifier: ^0.11.1
252 - version: 0.11.1
253 - vite-bundle-visualizer:
254 - specifier: ^1.2.1
255 - version: 1.2.1(rollup@4.22.4)
256 - vite-plugin-vue-devtools:
257 - specifier: ^7.4.5
258 - version: 7.4.5(@nuxt/kit@3.13.2(rollup@4.22.4))(rollup@4.22.4)(vite@5.4.7(@types/node@22.5.5)(sass@1.79.3))(vue@3.5.8(typescript@5.6.2))
259 - vite-svg-loader:
260 - specifier: ^5.1.0
261 - version: 5.1.0(vue@3.5.8(typescript@5.6.2))
262 - vitest:
263 - specifier: ^2.1.1
264 - version: 2.1.1(@types/node@22.5.5)(jsdom@25.0.1)(sass@1.79.3)
265 - vue-tsc:
266 - specifier: ^2.1.6
267 - version: 2.1.6(typescript@5.6.2)
15 +
16 + .:
17 + dependencies:
18 + '@ajoelp/json-to-formdata':
19 + specifier: ^1.5.0
20 + version: 1.5.0
21 + '@f3ve/vue-markdown-it':
22 + specifier: ^0.2.2
23 + version: 0.2.2(eslint@9.13.0(jiti@2.3.3))(prettier@3.3.3)(typescript@5.6.3)(vue@3.5.12(typescript@5.6.3))
24 + '@fontsource/jetbrains-mono':
25 + specifier: ^5.1.1
26 + version: 5.1.1
27 + '@fontsource/lexend':
28 + specifier: ^5.1.1
29 + version: 5.1.1
30 + '@fontsource/public-sans':
31 + specifier: ^5.1.1
32 + version: 5.1.1
33 + '@shikijs/markdown-it':
34 + specifier: ^1.22.0
35 + version: 1.22.0
36 + '@tailwindcss/container-queries':
37 + specifier: ^0.1.1
38 + version: 0.1.1(tailwindcss@3.4.14)
39 + '@vueuse/core':
40 + specifier: ^11.1.0
41 + version: 11.1.0(vue@3.5.12(typescript@5.6.3))
42 + axios:
43 + specifier: ^1.7.7
44 + version: 1.7.7(debug@4.3.7)
45 + bytes:
46 + specifier: ^3.1.2
47 + version: 3.1.2
48 + colord:
49 + specifier: ^2.9.3
50 + version: 2.9.3
51 + dayjs:
52 + specifier: ^1.11.13
53 + version: 1.11.13
54 + detect-touch-device:
55 + specifier: ^1.1.6
56 + version: 1.1.6
57 + echarts:
58 + specifier: ^5.5.1
59 + version: 5.5.1
60 + file-saver:
61 + specifier: ^2.0.5
62 + version: 2.0.5
63 + html-entities:
64 + specifier: ^2.5.2
65 + version: 2.5.2
66 + jose:
67 + specifier: ^5.9.6
68 + version: 5.9.6
69 + js-md5:
70 + specifier: ^0.8.3
71 + version: 0.8.3
72 + lodash:
73 + specifier: ^4.17.21
74 + version: 4.17.21
75 + mitt:
76 + specifier: ^3.0.1
77 + version: 3.0.1
78 + naive-ui:
79 + specifier: ^2.40.1
80 + version: 2.40.1(vue@3.5.12(typescript@5.6.3))
81 + nanoid:
82 + specifier: ^5.0.7
83 + version: 5.0.7
84 + password-validator:
85 + specifier: ^5.3.0
86 + version: 5.3.0
87 + pinia:
88 + specifier: ^2.2.4
89 + version: 2.2.4(typescript@5.6.3)(vue@3.5.12(typescript@5.6.3))
90 + pinia-plugin-persistedstate:
91 + specifier: ^4.1.1
92 + version: 4.1.1(pinia@2.2.4(typescript@5.6.3)(vue@3.5.12(typescript@5.6.3)))(rollup@4.24.0)
93 + secure-ls:
94 + specifier: ^2.0.0
95 + version: 2.0.0
96 + shiki:
97 + specifier: ^1.22.0
98 + version: 1.22.0
99 + validator:
100 + specifier: ^13.12.0
101 + version: 13.12.0
102 + vue:
103 + specifier: ^3.5.12
104 + version: 3.5.12(typescript@5.6.3)
105 + vue-advanced-cropper:
106 + specifier: ^2.8.9
107 + version: 2.8.9(vue@3.5.12(typescript@5.6.3))
108 + vue-highlight-words:
109 + specifier: ^3.0.1
110 + version: 3.0.1(vue@3.5.12(typescript@5.6.3))
111 + vue-i18n:
112 + specifier: ^10.0.4
113 + version: 10.0.4(vue@3.5.12(typescript@5.6.3))
114 + vue-router:
115 + specifier: ^4.4.5
116 + version: 4.4.5(vue@3.5.12(typescript@5.6.3))
117 + vue-sjv:
118 + specifier: ^0.0.6
119 + version: 0.0.6(vue@3.5.12(typescript@5.6.3))
120 + vue3-apexcharts:
121 + specifier: ^1.7.0
122 + version: 1.7.0(apexcharts@3.54.1)(vue@3.5.12(typescript@5.6.3))
123 + vue3-marquee:
124 + specifier: ^4.2.2
125 + version: 4.2.2(vue@3.5.12(typescript@5.6.3))
126 + vuedraggable:
127 + specifier: ^4.1.0
128 + version: 4.1.0(vue@3.5.12(typescript@5.6.3))
129 + optionalDependencies:
130 + '@rollup/rollup-linux-x64-gnu':
131 + specifier: ^4.24.0
132 + version: 4.24.0
133 + devDependencies:
134 + '@antfu/eslint-config':
135 + specifier: ^3.8.0
136 + version: 3.8.0(@typescript-eslint/utils@8.11.0(eslint@9.13.0(jiti@2.3.3))(typescript@5.6.3))(@unocss/eslint-plugin@0.56.5(eslint@9.13.0(jiti@2.3.3))(typescript@5.6.3))(@vue/compiler-sfc@3.5.12)(eslint@9.13.0(jiti@2.3.3))(typescript@5.6.3)(vitest@2.1.3(@types/node@22.7.8)(jsdom@25.0.1)(sass@1.80.3))
137 + '@clack/prompts':
138 + specifier: ^0.7.0
139 + version: 0.7.0
140 + '@iconify/vue':
141 + specifier: ^4.1.2
142 + version: 4.1.2(vue@3.5.12(typescript@5.6.3))
143 + '@tsconfig/node20':
144 + specifier: ^20.1.4
145 + version: 20.1.4
146 + '@types/bytes':
147 + specifier: ^3.1.4
148 + version: 3.1.4
149 + '@types/file-saver':
150 + specifier: ^2.0.7
151 + version: 2.0.7
152 + '@types/fs-extra':
153 + specifier: ^11.0.4
154 + version: 11.0.4
155 + '@types/jsdom':
156 + specifier: ^21.1.7
157 + version: 21.1.7
158 + '@types/lodash':
159 + specifier: ^4.17.12
160 + version: 4.17.12
161 + '@types/node':
162 + specifier: ^22.7.8
163 + version: 22.7.8
164 + '@types/validator':
165 + specifier: ^13.12.2
166 + version: 13.12.2
167 + '@vitejs/plugin-vue':
168 + specifier: ^5.1.4
169 + version: 5.1.4(vite@5.4.9(@types/node@22.7.8)(sass@1.80.3))(vue@3.5.12(typescript@5.6.3))
170 + '@vitejs/plugin-vue-jsx':
171 + specifier: ^4.0.1
172 + version: 4.0.1(vite@5.4.9(@types/node@22.7.8)(sass@1.80.3))(vue@3.5.12(typescript@5.6.3))
173 + '@vue/test-utils':
174 + specifier: ^2.4.6
175 + version: 2.4.6
176 + '@vue/tsconfig':
177 + specifier: ^0.5.1
178 + version: 0.5.1
179 + autoprefixer:
180 + specifier: ^10.4.20
181 + version: 10.4.20(postcss@8.4.47)
182 + cypress:
183 + specifier: ^13.15.0
184 + version: 13.15.0
185 + depcheck:
186 + specifier: ^1.4.7
187 + version: 1.4.7
188 + eslint:
189 + specifier: ^9.13.0
190 + version: 9.13.0(jiti@2.3.3)
191 + flourite:
192 + specifier: ^1.3.0
193 + version: 1.3.0
194 + fs-extra:
195 + specifier: ^11.2.0
196 + version: 11.2.0
197 + jsdom:
198 + specifier: ^25.0.1
199 + version: 25.0.1
200 + npm-run-all2:
201 + specifier: ^7.0.0
202 + version: 7.0.0
203 + postcss:
204 + specifier: ^8.4.47
205 + version: 8.4.47
206 + prettier:
207 + specifier: ^3.3.3
208 + version: 3.3.3
209 + prettier-plugin-tailwindcss:
210 + specifier: ^0.6.8
211 + version: 0.6.8(prettier@3.3.3)
212 + sass:
213 + specifier: ^1.80.3
214 + version: 1.80.3
215 + start-server-and-test:
216 + specifier: ^2.0.8
217 + version: 2.0.8
218 + tailwind-config-viewer:
219 + specifier: ^2.0.4
220 + version: 2.0.4(tailwindcss@3.4.14)
221 + tailwindcss:
222 + specifier: ^3.4.14
223 + version: 3.4.14
224 + taze:
225 + specifier: ^0.17.2
226 + version: 0.17.2
227 + type-fest:
228 + specifier: ^4.26.1
229 + version: 4.26.1
230 + typescript:
231 + specifier: ~5.6.3
232 + version: 5.6.3
233 + unplugin-vue-components:
234 + specifier: ^0.27.4
235 + version: 0.27.4(@babel/parser@7.25.8)(@nuxt/kit@3.13.2(rollup@4.24.0))(rollup@4.24.0)(vue@3.5.12(typescript@5.6.3))
236 + vite:
237 + specifier: ^5.4.9
238 + version: 5.4.9(@types/node@22.7.8)(sass@1.80.3)
239 + vite-bundle-visualizer:
240 + specifier: ^1.2.1
241 + version: 1.2.1(rollup@4.24.0)
242 + vite-plugin-vue-devtools:
243 + specifier: ^7.5.2
244 + version: 7.5.2(@nuxt/kit@3.13.2(rollup@4.24.0))(rollup@4.24.0)(vite@5.4.9(@types/node@22.7.8)(sass@1.80.3))(vue@3.5.12(typescript@5.6.3))
245 + vite-svg-loader:
246 + specifier: ^5.1.0
247 + version: 5.1.0(vue@3.5.12(typescript@5.6.3))
248 + vitest:
249 + specifier: ^2.1.3
250 + version: 2.1.3(@types/node@22.7.8)(jsdom@25.0.1)(sass@1.80.3)
251 + vue-tsc:
252 + specifier: ^2.1.6
253 + version: 2.1.6(typescript@5.6.3)
254
255 packages:
270 - "@ajoelp/json-to-formdata@1.5.0":
271 - resolution:
272 - {
273 - integrity: sha512-nrlfeTSL0X0dtx5r2KpzPiqLSIQquiiJjUKsQAKzWaCmO2QoYZCyb5ENZwF3YoffKronOCJr25mxaD8JRJmK8w==
274 - }
275 -
276 - "@alloc/quick-lru@5.2.0":
277 - resolution:
278 - {
279 - integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==
280 - }
281 - engines: { node: ">=10" }
282 -
283 - "@ampproject/remapping@2.3.0":
284 - resolution:
285 - {
286 - integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==
287 - }
288 - engines: { node: ">=6.0.0" }
289 -
290 - "@antfu/eslint-config@3.7.1":
291 - resolution:
292 - {
293 - integrity: sha512-cDBAj+Le9XakAK83ZWVNxxyBJKeBfQ6H3VkUGnJPkXn/KJEzXC0fcHDtbu9k633hasLba5gXN5pjm4C70ik+Fg==
294 - }
295 - hasBin: true
296 - peerDependencies:
297 - "@eslint-react/eslint-plugin": ^1.5.8
298 - "@prettier/plugin-xml": ^3.4.1
299 - "@unocss/eslint-plugin": ">=0.50.0"
300 - astro-eslint-parser: ^1.0.2
301 - eslint: ^9.11.0
302 - eslint-plugin-astro: ^1.2.0
303 - eslint-plugin-format: ">=0.1.0"
304 - eslint-plugin-react-hooks: ^4.6.0
305 - eslint-plugin-react-refresh: ^0.4.4
306 - eslint-plugin-solid: ^0.14.3
307 - eslint-plugin-svelte: ">=2.35.1"
308 - prettier-plugin-astro: ^0.13.0
309 - prettier-plugin-slidev: ^1.0.5
310 - svelte-eslint-parser: ">=0.37.0"
311 - peerDependenciesMeta:
312 - "@eslint-react/eslint-plugin":
313 - optional: true
314 - "@prettier/plugin-xml":
315 - optional: true
316 - "@unocss/eslint-plugin":
317 - optional: true
318 - astro-eslint-parser:
319 - optional: true
320 - eslint-plugin-astro:
321 - optional: true
322 - eslint-plugin-format:
323 - optional: true
324 - eslint-plugin-react-hooks:
325 - optional: true
326 - eslint-plugin-react-refresh:
327 - optional: true
328 - eslint-plugin-solid:
329 - optional: true
330 - eslint-plugin-svelte:
331 - optional: true
332 - prettier-plugin-astro:
333 - optional: true
334 - prettier-plugin-slidev:
335 - optional: true
336 - svelte-eslint-parser:
337 - optional: true
338 -
339 - "@antfu/install-pkg@0.4.1":
340 - resolution:
341 - {
342 - integrity: sha512-T7yB5QNG29afhWVkVq7XeIMBa5U/vs9mX69YqayXypPRmYzUmzwnYltplHmPtZ4HPCn+sQKeXW8I47wCbuBOjw==
343 - }
344 -
345 - "@antfu/ni@0.23.0":
346 - resolution:
347 - {
348 - integrity: sha512-R5/GkA3PfGewAXLzz6lN5XagunF6PKeDtWt8dbZQXvHfebLS0qEczV+Azg/d+tKgSh6kRBpxvu8oSjARdPtw0A==
349 - }
350 - hasBin: true
351 -
352 - "@antfu/utils@0.7.10":
353 - resolution:
354 - {
355 - integrity: sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww==
356 - }
357 -
358 - "@babel/code-frame@7.24.7":
359 - resolution:
360 - {
361 - integrity: sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==
362 - }
363 - engines: { node: ">=6.9.0" }
364 -
365 - "@babel/compat-data@7.25.4":
366 - resolution:
367 - {
368 - integrity: sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ==
369 - }
370 - engines: { node: ">=6.9.0" }
371 -
372 - "@babel/core@7.25.2":
373 - resolution:
374 - {
375 - integrity: sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==
376 - }
377 - engines: { node: ">=6.9.0" }
378 -
379 - "@babel/generator@7.25.6":
380 - resolution:
381 - {
382 - integrity: sha512-VPC82gr1seXOpkjAAKoLhP50vx4vGNlF4msF64dSFq1P8RfB+QAuJWGHPXXPc8QyfVWwwB/TNNU4+ayZmHNbZw==
383 - }
384 - engines: { node: ">=6.9.0" }
385 -
386 - "@babel/helper-annotate-as-pure@7.24.7":
387 - resolution:
388 - {
389 - integrity: sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==
390 - }
391 - engines: { node: ">=6.9.0" }
392 -
393 - "@babel/helper-compilation-targets@7.25.2":
394 - resolution:
395 - {
396 - integrity: sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==
397 - }
398 - engines: { node: ">=6.9.0" }
399 -
400 - "@babel/helper-create-class-features-plugin@7.25.4":
401 - resolution:
402 - {
403 - integrity: sha512-ro/bFs3/84MDgDmMwbcHgDa8/E6J3QKNTk4xJJnVeFtGE+tL0K26E3pNxhYz2b67fJpt7Aphw5XcploKXuCvCQ==
404 - }
405 - engines: { node: ">=6.9.0" }
406 - peerDependencies:
407 - "@babel/core": ^7.0.0
408 -
409 - "@babel/helper-member-expression-to-functions@7.24.8":
410 - resolution:
411 - {
412 - integrity: sha512-LABppdt+Lp/RlBxqrh4qgf1oEH/WxdzQNDJIu5gC/W1GyvPVrOBiItmmM8wan2fm4oYqFuFfkXmlGpLQhPY8CA==
413 - }
414 - engines: { node: ">=6.9.0" }
415 -
416 - "@babel/helper-module-imports@7.24.7":
417 - resolution:
418 - {
419 - integrity: sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==
420 - }
421 - engines: { node: ">=6.9.0" }
422 -
423 - "@babel/helper-module-transforms@7.25.2":
424 - resolution:
425 - {
426 - integrity: sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==
427 - }
428 - engines: { node: ">=6.9.0" }
429 - peerDependencies:
430 - "@babel/core": ^7.0.0
431 -
432 - "@babel/helper-optimise-call-expression@7.24.7":
433 - resolution:
434 - {
435 - integrity: sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==
436 - }
437 - engines: { node: ">=6.9.0" }
438 -
439 - "@babel/helper-plugin-utils@7.24.8":
440 - resolution:
441 - {
442 - integrity: sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==
443 - }
444 - engines: { node: ">=6.9.0" }
445 -
446 - "@babel/helper-replace-supers@7.25.0":
447 - resolution:
448 - {
449 - integrity: sha512-q688zIvQVYtZu+i2PsdIu/uWGRpfxzr5WESsfpShfZECkO+d2o+WROWezCi/Q6kJ0tfPa5+pUGUlfx2HhrA3Bg==
450 - }
451 - engines: { node: ">=6.9.0" }
452 - peerDependencies:
453 - "@babel/core": ^7.0.0
454 -
455 - "@babel/helper-simple-access@7.24.7":
456 - resolution:
457 - {
458 - integrity: sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==
459 - }
460 - engines: { node: ">=6.9.0" }
461 -
462 - "@babel/helper-skip-transparent-expression-wrappers@7.24.7":
463 - resolution:
464 - {
465 - integrity: sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==
466 - }
467 - engines: { node: ">=6.9.0" }
468 -
469 - "@babel/helper-string-parser@7.24.8":
470 - resolution:
471 - {
472 - integrity: sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==
473 - }
474 - engines: { node: ">=6.9.0" }
475 -
476 - "@babel/helper-validator-identifier@7.24.7":
477 - resolution:
478 - {
479 - integrity: sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==
480 - }
481 - engines: { node: ">=6.9.0" }
482 -
483 - "@babel/helper-validator-option@7.24.8":
484 - resolution:
485 - {
486 - integrity: sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==
487 - }
488 - engines: { node: ">=6.9.0" }
489 -
490 - "@babel/helpers@7.25.6":
491 - resolution:
492 - {
493 - integrity: sha512-Xg0tn4HcfTijTwfDwYlvVCl43V6h4KyVVX2aEm4qdO/PC6L2YvzLHFdmxhoeSA3eslcE6+ZVXHgWwopXYLNq4Q==
494 - }
495 - engines: { node: ">=6.9.0" }
496 -
497 - "@babel/highlight@7.24.7":
498 - resolution:
499 - {
500 - integrity: sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==
501 - }
502 - engines: { node: ">=6.9.0" }
503 -
504 - "@babel/parser@7.25.6":
505 - resolution:
506 - {
507 - integrity: sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q==
508 - }
509 - engines: { node: ">=6.0.0" }
510 - hasBin: true
511 -
512 - "@babel/plugin-proposal-decorators@7.24.7":
513 - resolution:
514 - {
515 - integrity: sha512-RL9GR0pUG5Kc8BUWLNDm2T5OpYwSX15r98I0IkgmRQTXuELq/OynH8xtMTMvTJFjXbMWFVTKtYkTaYQsuAwQlQ==
516 - }
517 - engines: { node: ">=6.9.0" }
518 - peerDependencies:
519 - "@babel/core": ^7.0.0-0
520 -
521 - "@babel/plugin-syntax-decorators@7.24.7":
522 - resolution:
523 - {
524 - integrity: sha512-Ui4uLJJrRV1lb38zg1yYTmRKmiZLiftDEvZN2iq3kd9kUFU+PttmzTbAFC2ucRk/XJmtek6G23gPsuZbhrT8fQ==
525 - }
526 - engines: { node: ">=6.9.0" }
527 - peerDependencies:
528 - "@babel/core": ^7.0.0-0
529 -
530 - "@babel/plugin-syntax-import-attributes@7.25.6":
531 - resolution:
532 - {
533 - integrity: sha512-sXaDXaJN9SNLymBdlWFA+bjzBhFD617ZaFiY13dGt7TVslVvVgA6fkZOP7Ki3IGElC45lwHdOTrCtKZGVAWeLQ==
534 - }
535 - engines: { node: ">=6.9.0" }
536 - peerDependencies:
537 - "@babel/core": ^7.0.0-0
538 -
539 - "@babel/plugin-syntax-import-meta@7.10.4":
540 - resolution:
541 - {
542 - integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==
543 - }
544 - peerDependencies:
545 - "@babel/core": ^7.0.0-0
546 -
547 - "@babel/plugin-syntax-jsx@7.24.7":
548 - resolution:
549 - {
550 - integrity: sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ==
551 - }
552 - engines: { node: ">=6.9.0" }
553 - peerDependencies:
554 - "@babel/core": ^7.0.0-0
555 -
556 - "@babel/plugin-syntax-typescript@7.25.4":
557 - resolution:
558 - {
559 - integrity: sha512-uMOCoHVU52BsSWxPOMVv5qKRdeSlPuImUCB2dlPuBSU+W2/ROE7/Zg8F2Kepbk+8yBa68LlRKxO+xgEVWorsDg==
560 - }
561 - engines: { node: ">=6.9.0" }
562 - peerDependencies:
563 - "@babel/core": ^7.0.0-0
564 -
565 - "@babel/plugin-transform-typescript@7.25.2":
566 - resolution:
567 - {
568 - integrity: sha512-lBwRvjSmqiMYe/pS0+1gggjJleUJi7NzjvQ1Fkqtt69hBa/0t1YuW/MLQMAPixfwaQOHUXsd6jeU3Z+vdGv3+A==
569 - }
570 - engines: { node: ">=6.9.0" }
571 - peerDependencies:
572 - "@babel/core": ^7.0.0-0
573 -
574 - "@babel/runtime@7.25.6":
575 - resolution:
576 - {
577 - integrity: sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ==
578 - }
579 - engines: { node: ">=6.9.0" }
580 -
581 - "@babel/standalone@7.25.6":
582 - resolution:
583 - {
584 - integrity: sha512-Kf2ZcZVqsKbtYhlA7sP0z5A3q5hmCVYMKMWRWNK/5OVwHIve3JY1djVRmIVAx8FMueLIfZGKQDIILK2w8zO4mg==
585 - }
586 - engines: { node: ">=6.9.0" }
587 -
588 - "@babel/template@7.25.0":
589 - resolution:
590 - {
591 - integrity: sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==
592 - }
593 - engines: { node: ">=6.9.0" }
594 -
595 - "@babel/traverse@7.25.6":
596 - resolution:
597 - {
598 - integrity: sha512-9Vrcx5ZW6UwK5tvqsj0nGpp/XzqthkT0dqIc9g1AdtygFToNtTF67XzYS//dm+SAK9cp3B9R4ZO/46p63SCjlQ==
599 - }
600 - engines: { node: ">=6.9.0" }
601 -
602 - "@babel/types@7.25.6":
603 - resolution:
604 - {
605 - integrity: sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw==
606 - }
607 - engines: { node: ">=6.9.0" }
608 -
609 - "@clack/core@0.3.4":
610 - resolution:
611 - {
612 - integrity: sha512-H4hxZDXgHtWTwV3RAVenqcC4VbJZNegbBjlPvzOzCouXtS2y3sDvlO3IsbrPNWuLWPPlYVYPghQdSF64683Ldw==
613 - }
614 -
615 - "@clack/prompts@0.7.0":
616 - resolution:
617 - {
618 - integrity: sha512-0MhX9/B4iL6Re04jPrttDm+BsP8y6mS7byuv0BvXgdXhbV5PdlsHt55dvNsuBCPZ7xq1oTAOOuotR9NFbQyMSA==
619 - }
620 - bundledDependencies:
621 - - is-unicode-supported
622 -
623 - "@colors/colors@1.5.0":
624 - resolution:
625 - {
626 - integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==
627 - }
628 - engines: { node: ">=0.1.90" }
629 -
630 - "@css-render/plugin-bem@0.15.14":
631 - resolution:
632 - {
633 - integrity: sha512-QK513CJ7yEQxm/P3EwsI+d+ha8kSOcjGvD6SevM41neEMxdULE+18iuQK6tEChAWMOQNQPLG/Rw3Khb69r5neg==
634 - }
635 - peerDependencies:
636 - css-render: ~0.15.14
637 -
638 - "@css-render/vue3-ssr@0.15.14":
639 - resolution:
640 - {
641 - integrity: sha512-//8027GSbxE9n3QlD73xFY6z4ZbHbvrOVB7AO6hsmrEzGbg+h2A09HboUyDgu+xsmj7JnvJD39Irt+2D0+iV8g==
642 - }
643 - peerDependencies:
644 - vue: ^3.0.11
645 -
646 - "@cypress/request@3.0.5":
647 - resolution:
648 - {
649 - integrity: sha512-v+XHd9XmWbufxF1/bTaVm2yhbxY+TB4YtWRqF2zaXBlDNMkls34KiATz0AVDLavL3iB6bQk9/7n3oY1EoLSWGA==
650 - }
651 - engines: { node: ">= 6" }
652 -
653 - "@cypress/xvfb@1.2.4":
654 - resolution:
655 - {
656 - integrity: sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q==
657 - }
658 -
659 - "@emotion/hash@0.8.0":
660 - resolution:
661 - {
662 - integrity: sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==
663 - }
664 -
665 - "@es-joy/jsdoccomment@0.48.0":
666 - resolution:
667 - {
668 - integrity: sha512-G6QUWIcC+KvSwXNsJyDTHvqUdNoAVJPPgkc3+Uk4WBKqZvoXhlvazOgm9aL0HwihJLQf0l+tOE2UFzXBqCqgDw==
669 - }
670 - engines: { node: ">=16" }
671 -
672 - "@esbuild/aix-ppc64@0.21.5":
673 - resolution:
674 - {
675 - integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==
676 - }
677 - engines: { node: ">=12" }
678 - cpu: [ppc64]
679 - os: [aix]
680 -
681 - "@esbuild/aix-ppc64@0.23.1":
682 - resolution:
683 - {
684 - integrity: sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==
685 - }
686 - engines: { node: ">=18" }
687 - cpu: [ppc64]
688 - os: [aix]
689 -
690 - "@esbuild/android-arm64@0.21.5":
691 - resolution:
692 - {
693 - integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==
694 - }
695 - engines: { node: ">=12" }
696 - cpu: [arm64]
697 - os: [android]
698 -
699 - "@esbuild/android-arm64@0.23.1":
700 - resolution:
701 - {
702 - integrity: sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==
703 - }
704 - engines: { node: ">=18" }
705 - cpu: [arm64]
706 - os: [android]
707 -
708 - "@esbuild/android-arm@0.21.5":
709 - resolution:
710 - {
711 - integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==
712 - }
713 - engines: { node: ">=12" }
714 - cpu: [arm]
715 - os: [android]
716 -
717 - "@esbuild/android-arm@0.23.1":
718 - resolution:
719 - {
720 - integrity: sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==
721 - }
722 - engines: { node: ">=18" }
723 - cpu: [arm]
724 - os: [android]
725 -
726 - "@esbuild/android-x64@0.21.5":
727 - resolution:
728 - {
729 - integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==
730 - }
731 - engines: { node: ">=12" }
732 - cpu: [x64]
733 - os: [android]
734 -
735 - "@esbuild/android-x64@0.23.1":
736 - resolution:
737 - {
738 - integrity: sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==
739 - }
740 - engines: { node: ">=18" }
741 - cpu: [x64]
742 - os: [android]
743 -
744 - "@esbuild/darwin-arm64@0.21.5":
745 - resolution:
746 - {
747 - integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==
748 - }
749 - engines: { node: ">=12" }
750 - cpu: [arm64]
751 - os: [darwin]
752 -
753 - "@esbuild/darwin-arm64@0.23.1":
754 - resolution:
755 - {
756 - integrity: sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==
757 - }
758 - engines: { node: ">=18" }
759 - cpu: [arm64]
760 - os: [darwin]
761 -
762 - "@esbuild/darwin-x64@0.21.5":
763 - resolution:
764 - {
765 - integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==
766 - }
767 - engines: { node: ">=12" }
768 - cpu: [x64]
769 - os: [darwin]
770 -
771 - "@esbuild/darwin-x64@0.23.1":
772 - resolution:
773 - {
774 - integrity: sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==
775 - }
776 - engines: { node: ">=18" }
777 - cpu: [x64]
778 - os: [darwin]
779 -
780 - "@esbuild/freebsd-arm64@0.21.5":
781 - resolution:
782 - {
783 - integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==
784 - }
785 - engines: { node: ">=12" }
786 - cpu: [arm64]
787 - os: [freebsd]
788 -
789 - "@esbuild/freebsd-arm64@0.23.1":
790 - resolution:
791 - {
792 - integrity: sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==
793 - }
794 - engines: { node: ">=18" }
795 - cpu: [arm64]
796 - os: [freebsd]
797 -
798 - "@esbuild/freebsd-x64@0.21.5":
799 - resolution:
800 - {
801 - integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==
802 - }
803 - engines: { node: ">=12" }
804 - cpu: [x64]
805 - os: [freebsd]
806 -
807 - "@esbuild/freebsd-x64@0.23.1":
808 - resolution:
809 - {
810 - integrity: sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==
811 - }
812 - engines: { node: ">=18" }
813 - cpu: [x64]
814 - os: [freebsd]
815 -
816 - "@esbuild/linux-arm64@0.21.5":
817 - resolution:
818 - {
819 - integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==
820 - }
821 - engines: { node: ">=12" }
822 - cpu: [arm64]
823 - os: [linux]
824 -
825 - "@esbuild/linux-arm64@0.23.1":
826 - resolution:
827 - {
828 - integrity: sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==
829 - }
830 - engines: { node: ">=18" }
831 - cpu: [arm64]
832 - os: [linux]
833 -
834 - "@esbuild/linux-arm@0.21.5":
835 - resolution:
836 - {
837 - integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==
838 - }
839 - engines: { node: ">=12" }
840 - cpu: [arm]
841 - os: [linux]
842 -
843 - "@esbuild/linux-arm@0.23.1":
844 - resolution:
845 - {
846 - integrity: sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==
847 - }
848 - engines: { node: ">=18" }
849 - cpu: [arm]
850 - os: [linux]
851 -
852 - "@esbuild/linux-ia32@0.21.5":
853 - resolution:
854 - {
855 - integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==
856 - }
857 - engines: { node: ">=12" }
858 - cpu: [ia32]
859 - os: [linux]
860 -
861 - "@esbuild/linux-ia32@0.23.1":
862 - resolution:
863 - {
864 - integrity: sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==
865 - }
866 - engines: { node: ">=18" }
867 - cpu: [ia32]
868 - os: [linux]
869 -
870 - "@esbuild/linux-loong64@0.21.5":
871 - resolution:
872 - {
873 - integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==
874 - }
875 - engines: { node: ">=12" }
876 - cpu: [loong64]
877 - os: [linux]
878 -
879 - "@esbuild/linux-loong64@0.23.1":
880 - resolution:
881 - {
882 - integrity: sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==
883 - }
884 - engines: { node: ">=18" }
885 - cpu: [loong64]
886 - os: [linux]
887 -
888 - "@esbuild/linux-mips64el@0.21.5":
889 - resolution:
890 - {
891 - integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==
892 - }
893 - engines: { node: ">=12" }
894 - cpu: [mips64el]
895 - os: [linux]
896 -
897 - "@esbuild/linux-mips64el@0.23.1":
898 - resolution:
899 - {
900 - integrity: sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==
901 - }
902 - engines: { node: ">=18" }
903 - cpu: [mips64el]
904 - os: [linux]
905 -
906 - "@esbuild/linux-ppc64@0.21.5":
907 - resolution:
908 - {
909 - integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==
910 - }
911 - engines: { node: ">=12" }
912 - cpu: [ppc64]
913 - os: [linux]
914 -
915 - "@esbuild/linux-ppc64@0.23.1":
916 - resolution:
917 - {
918 - integrity: sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==
919 - }
920 - engines: { node: ">=18" }
921 - cpu: [ppc64]
922 - os: [linux]
923 -
924 - "@esbuild/linux-riscv64@0.21.5":
925 - resolution:
926 - {
927 - integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==
928 - }
929 - engines: { node: ">=12" }
930 - cpu: [riscv64]
931 - os: [linux]
932 -
933 - "@esbuild/linux-riscv64@0.23.1":
934 - resolution:
935 - {
936 - integrity: sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==
937 - }
938 - engines: { node: ">=18" }
939 - cpu: [riscv64]
940 - os: [linux]
941 -
942 - "@esbuild/linux-s390x@0.21.5":
943 - resolution:
944 - {
945 - integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==
946 - }
947 - engines: { node: ">=12" }
948 - cpu: [s390x]
949 - os: [linux]
950 -
951 - "@esbuild/linux-s390x@0.23.1":
952 - resolution:
953 - {
954 - integrity: sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==
955 - }
956 - engines: { node: ">=18" }
957 - cpu: [s390x]
958 - os: [linux]
959 -
960 - "@esbuild/linux-x64@0.21.5":
961 - resolution:
962 - {
963 - integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==
964 - }
965 - engines: { node: ">=12" }
966 - cpu: [x64]
967 - os: [linux]
968 -
969 - "@esbuild/linux-x64@0.23.1":
970 - resolution:
971 - {
972 - integrity: sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==
973 - }
974 - engines: { node: ">=18" }
975 - cpu: [x64]
976 - os: [linux]
977 -
978 - "@esbuild/netbsd-x64@0.21.5":
979 - resolution:
980 - {
981 - integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==
982 - }
983 - engines: { node: ">=12" }
984 - cpu: [x64]
985 - os: [netbsd]
986 -
987 - "@esbuild/netbsd-x64@0.23.1":
988 - resolution:
989 - {
990 - integrity: sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==
991 - }
992 - engines: { node: ">=18" }
993 - cpu: [x64]
994 - os: [netbsd]
995 -
996 - "@esbuild/openbsd-arm64@0.23.1":
997 - resolution:
998 - {
999 - integrity: sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==
1000 - }
1001 - engines: { node: ">=18" }
1002 - cpu: [arm64]
1003 - os: [openbsd]
1004 -
1005 - "@esbuild/openbsd-x64@0.21.5":
1006 - resolution:
1007 - {
1008 - integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==
1009 - }
1010 - engines: { node: ">=12" }
1011 - cpu: [x64]
1012 - os: [openbsd]
1013 -
1014 - "@esbuild/openbsd-x64@0.23.1":
1015 - resolution:
1016 - {
1017 - integrity: sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==
1018 - }
1019 - engines: { node: ">=18" }
1020 - cpu: [x64]
1021 - os: [openbsd]
1022 -
1023 - "@esbuild/sunos-x64@0.21.5":
1024 - resolution:
1025 - {
1026 - integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==
1027 - }
1028 - engines: { node: ">=12" }
1029 - cpu: [x64]
1030 - os: [sunos]
1031 -
1032 - "@esbuild/sunos-x64@0.23.1":
1033 - resolution:
1034 - {
1035 - integrity: sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==
1036 - }
1037 - engines: { node: ">=18" }
1038 - cpu: [x64]
1039 - os: [sunos]
1040 -
1041 - "@esbuild/win32-arm64@0.21.5":
1042 - resolution:
1043 - {
1044 - integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==
1045 - }
1046 - engines: { node: ">=12" }
1047 - cpu: [arm64]
1048 - os: [win32]
1049 -
1050 - "@esbuild/win32-arm64@0.23.1":
1051 - resolution:
1052 - {
1053 - integrity: sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==
1054 - }
1055 - engines: { node: ">=18" }
1056 - cpu: [arm64]
1057 - os: [win32]
1058 -
1059 - "@esbuild/win32-ia32@0.21.5":
1060 - resolution:
1061 - {
1062 - integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==
1063 - }
1064 - engines: { node: ">=12" }
1065 - cpu: [ia32]
1066 - os: [win32]
1067 -
1068 - "@esbuild/win32-ia32@0.23.1":
1069 - resolution:
1070 - {
1071 - integrity: sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==
1072 - }
1073 - engines: { node: ">=18" }
1074 - cpu: [ia32]
1075 - os: [win32]
1076 -
1077 - "@esbuild/win32-x64@0.21.5":
1078 - resolution:
1079 - {
1080 - integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==
1081 - }
1082 - engines: { node: ">=12" }
1083 - cpu: [x64]
1084 - os: [win32]
1085 -
1086 - "@esbuild/win32-x64@0.23.1":
1087 - resolution:
1088 - {
1089 - integrity: sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==
1090 - }
1091 - engines: { node: ">=18" }
1092 - cpu: [x64]
1093 - os: [win32]
1094 -
1095 - "@eslint-community/eslint-plugin-eslint-comments@4.4.0":
1096 - resolution:
1097 - {
1098 - integrity: sha512-yljsWl5Qv3IkIRmJ38h3NrHXFCm4EUl55M8doGTF6hvzvFF8kRpextgSrg2dwHev9lzBZyafCr9RelGIyQm6fw==
1099 - }
1100 - engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 }
1101 - peerDependencies:
1102 - eslint: ^9.11.0
1103 -
1104 - "@eslint-community/eslint-utils@4.4.0":
1105 - resolution:
1106 - {
1107 - integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==
1108 - }
1109 - engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 }
1110 - peerDependencies:
1111 - eslint: ^9.11.0
1112 -
1113 - "@eslint-community/regexpp@4.11.1":
1114 - resolution:
1115 - {
1116 - integrity: sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==
1117 - }
1118 - engines: { node: ^12.0.0 || ^14.0.0 || >=16.0.0 }
1119 -
1120 - "@eslint/compat@1.1.1":
1121 - resolution:
1122 - {
1123 - integrity: sha512-lpHyRyplhGPL5mGEh6M9O5nnKk0Gz4bFI+Zu6tKlPpDUN7XshWvH9C/px4UVm87IAANE0W81CEsNGbS1KlzXpA==
1124 - }
1125 - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 }
1126 -
1127 - "@eslint/config-array@0.18.0":
1128 - resolution:
1129 - {
1130 - integrity: sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==
1131 - }
1132 - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 }
1133 -
1134 - "@eslint/eslintrc@3.1.0":
1135 - resolution:
1136 - {
1137 - integrity: sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==
1138 - }
1139 - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 }
1140 -
1141 - "@eslint/js@8.57.1":
1142 - resolution:
1143 - {
1144 - integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==
1145 - }
1146 - engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 }
1147 -
1148 - "@eslint/js@9.11.0":
1149 - resolution:
1150 - {
1151 - integrity: sha512-LPkkenkDqyzTFauZLLAPhIb48fj6drrfMvRGSL9tS3AcZBSVTllemLSNyCvHNNL2t797S/6DJNSIwRwXgMO/eQ==
1152 - }
1153 - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 }
1154 -
1155 - "@eslint/markdown@6.1.0":
1156 - resolution:
1157 - {
1158 - integrity: sha512-cX1tyD+aIbhzKrCKe/9M5s2jZhldWGOR+cy7cIVpxG9RkoaN4XU+gG3dy6oEKtBFXjDx06GtP0OGO7jgbqa2DA==
1159 - }
1160 - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 }
1161 - peerDependencies:
1162 - eslint: ^9.11.0
1163 -
1164 - "@eslint/object-schema@2.1.4":
1165 - resolution:
1166 - {
1167 - integrity: sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==
1168 - }
1169 - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 }
1170 -
1171 - "@eslint/plugin-kit@0.2.0":
1172 - resolution:
1173 - {
1174 - integrity: sha512-vH9PiIMMwvhCx31Af3HiGzsVNULDbyVkHXwlemn/B0TFj/00ho3y55efXrUZTfQipxoHC5u4xq6zblww1zm1Ig==
1175 - }
1176 - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 }
1177 -
1178 - "@f3ve/eslint-config@1.0.6":
1179 - resolution:
1180 - {
1181 - integrity: sha512-DVLPAVZskaOUY6Gu/1VFaL0gGyY3VhjZBVExZVde2siwwgdwt+8XDSupLll0arKqVv4bqO2fRK21QomN3jy2yg==
1182 - }
1183 - peerDependencies:
1184 - eslint: ^9.11.0
1185 -
1186 - "@f3ve/vue-markdown-it@0.2.2":
1187 - resolution:
1188 - {
1189 - integrity: sha512-0LVoa7bCI+pKuMRp8iap7DNNSVgXH51xkAxFmBWjdY6gd9yXBwD64P0p7o1NSYFUXaQCGR+cfOpsudJY7zjeBg==
1190 - }
1191 - peerDependencies:
1192 - vue: ^3.3.4
1193 -
1194 - "@fontsource/jetbrains-mono@5.1.0":
1195 - resolution:
1196 - {
1197 - integrity: sha512-YzWpGYY3PoqvmvwW2Hb4NwkN5C7LO0FmZugEGcFe6cNNE/cMgH9JhW5LI6hjG+1+nwgSHyJtKmblHNrUqlyhWg==
1198 - }
1199 -
1200 - "@fontsource/lexend@5.1.0":
1201 - resolution:
1202 - {
1203 - integrity: sha512-mqwRfsRobLoj4iHqkvMGMMiTYU7n0hbgGftGBKFGKGyedseQOQ3k7iCBVTAU9wIyfq02Rypd9BrLXChHwFvg0Q==
1204 - }
1205 -
1206 - "@fontsource/public-sans@5.1.0":
1207 - resolution:
1208 - {
1209 - integrity: sha512-94+468XL9dUxsZ5edw/AtBHLdIwkvqr3WBUMBD30LUQzJpHw/Fxd7VrgkXSIKRIwYi3pTuQ1Q2Vj3COGIwi58Q==
1210 - }
1211 -
1212 - "@hapi/hoek@9.3.0":
1213 - resolution:
1214 - {
1215 - integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==
1216 - }
1217 -
1218 - "@hapi/topo@5.1.0":
1219 - resolution:
1220 - {
1221 - integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==
1222 - }
1223 -
1224 - "@humanwhocodes/module-importer@1.0.1":
1225 - resolution:
1226 - {
1227 - integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==
1228 - }
1229 - engines: { node: ">=12.22" }
1230 -
1231 - "@humanwhocodes/retry@0.3.0":
1232 - resolution:
1233 - {
1234 - integrity: sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==
1235 - }
1236 - engines: { node: ">=18.18" }
1237 -
1238 - "@iconify/types@2.0.0":
1239 - resolution:
1240 - {
1241 - integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==
1242 - }
1243 -
1244 - "@iconify/vue@4.1.2":
1245 - resolution:
1246 - {
1247 - integrity: sha512-CQnYqLiQD5LOAaXhBrmj1mdL2/NCJvwcC4jtW2Z8ukhThiFkLDkutarTOV2trfc9EXqUqRs0KqXOL9pZ/IyysA==
1248 - }
1249 - peerDependencies:
1250 - vue: ">=3"
1251 -
1252 - "@intlify/core-base@10.0.3":
1253 - resolution:
1254 - {
1255 - integrity: sha512-ysJnTGDtuXPa6R2Ii4JIvfMVvDahUUny3aY8+P4r6/0TYHkblgzIMjV6cAn60em67AB0M7OWNAdcAVfWWeN8Qg==
1256 - }
1257 - engines: { node: ">= 16" }
1258 -
1259 - "@intlify/message-compiler@10.0.3":
1260 - resolution:
1261 - {
1262 - integrity: sha512-KC2fG8nCzSYmXjHptEt6i/xM3k6S2szsPaHDCRgWKEYAbeHe6JFm6X4KRw3Csy112A8CxpavMi1dh3h7khwV5w==
1263 - }
1264 - engines: { node: ">= 16" }
1265 -
1266 - "@intlify/shared@10.0.3":
1267 - resolution:
1268 - {
1269 - integrity: sha512-PWxrCb6fDlnoGLnXLlWu6d7o/HdWACB9TjRnpLro+9uyfqgWA9hvqg5vekcPRyraTieV5srCbTk/ldYw9V3LHw==
1270 - }
1271 - engines: { node: ">= 16" }
1272 -
1273 - "@isaacs/cliui@8.0.2":
1274 - resolution:
1275 - {
1276 - integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==
1277 - }
1278 - engines: { node: ">=12" }
1279 -
1280 - "@jridgewell/gen-mapping@0.3.5":
1281 - resolution:
1282 - {
1283 - integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==
1284 - }
1285 - engines: { node: ">=6.0.0" }
1286 -
1287 - "@jridgewell/resolve-uri@3.1.2":
1288 - resolution:
1289 - {
1290 - integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==
1291 - }
1292 - engines: { node: ">=6.0.0" }
1293 -
1294 - "@jridgewell/set-array@1.2.1":
1295 - resolution:
1296 - {
1297 - integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==
1298 - }
1299 - engines: { node: ">=6.0.0" }
1300 -
1301 - "@jridgewell/sourcemap-codec@1.5.0":
1302 - resolution:
1303 - {
1304 - integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==
1305 - }
1306 -
1307 - "@jridgewell/trace-mapping@0.3.25":
1308 - resolution:
1309 - {
1310 - integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==
1311 - }
1312 -
1313 - "@juggle/resize-observer@3.4.0":
1314 - resolution:
1315 - {
1316 - integrity: sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==
1317 - }
1318 -
1319 - "@koa/router@12.0.2":
1320 - resolution:
1321 - {
1322 - integrity: sha512-sYcHglGKTxGF+hQ6x67xDfkE9o+NhVlRHBqq6gLywaMc6CojK/5vFZByphdonKinYlMLkEkacm+HEse9HzwgTA==
1323 - }
1324 - engines: { node: ">= 12" }
1325 -
1326 - "@nodelib/fs.scandir@2.1.5":
1327 - resolution:
1328 - {
1329 - integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==
1330 - }
1331 - engines: { node: ">= 8" }
1332 -
1333 - "@nodelib/fs.stat@2.0.5":
1334 - resolution:
1335 - {
1336 - integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
1337 - }
1338 - engines: { node: ">= 8" }
1339 -
1340 - "@nodelib/fs.walk@1.2.8":
1341 - resolution:
1342 - {
1343 - integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==
1344 - }
1345 - engines: { node: ">= 8" }
1346 -
1347 - "@nuxt/kit@3.13.2":
1348 - resolution:
1349 - {
1350 - integrity: sha512-KvRw21zU//wdz25IeE1E5m/aFSzhJloBRAQtv+evcFeZvuroIxpIQuUqhbzuwznaUwpiWbmwlcsp5uOWmi4vwA==
1351 - }
1352 - engines: { node: ^14.18.0 || >=16.10.0 }
1353 -
1354 - "@nuxt/schema@3.13.2":
1355 - resolution:
1356 - {
1357 - integrity: sha512-CCZgpm+MkqtOMDEgF9SWgGPBXlQ01hV/6+2reDEpJuqFPGzV8HYKPBcIFvn7/z5ahtgutHLzjP71Na+hYcqSpw==
1358 - }
1359 - engines: { node: ^14.18.0 || >=16.10.0 }
1360 -
1361 - "@one-ini/wasm@0.1.1":
1362 - resolution:
1363 - {
1364 - integrity: sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==
1365 - }
1366 -
1367 - "@pkgjs/parseargs@0.11.0":
1368 - resolution:
1369 - {
1370 - integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==
1371 - }
1372 - engines: { node: ">=14" }
1373 -
1374 - "@pkgr/core@0.1.1":
1375 - resolution:
1376 - {
1377 - integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==
1378 - }
1379 - engines: { node: ^12.20.0 || ^14.18.0 || >=16.0.0 }
1380 -
1381 - "@polka/url@1.0.0-next.28":
1382 - resolution:
1383 - {
1384 - integrity: sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==
1385 - }
1386 -
1387 - "@popperjs/core@2.11.8":
1388 - resolution:
1389 - {
1390 - integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==
1391 - }
1392 -
1393 - "@rollup/pluginutils@5.1.1":
1394 - resolution:
1395 - {
1396 - integrity: sha512-bVRmQqBIyGD+VMihdEV2IBurfIrdW9tD9yzJUL3CBRDbyPBVzQnBSMSgyUZHl1E335rpMRj7r4o683fXLYw8iw==
1397 - }
1398 - engines: { node: ">=14.0.0" }
1399 - peerDependencies:
1400 - rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0
1401 - peerDependenciesMeta:
1402 - rollup:
1403 - optional: true
1404 -
1405 - "@rollup/rollup-android-arm-eabi@4.22.4":
1406 - resolution:
1407 - {
1408 - integrity: sha512-Fxamp4aEZnfPOcGA8KSNEohV8hX7zVHOemC8jVBoBUHu5zpJK/Eu3uJwt6BMgy9fkvzxDaurgj96F/NiLukF2w==
1409 - }
1410 - cpu: [arm]
1411 - os: [android]
1412 -
1413 - "@rollup/rollup-android-arm64@4.22.4":
1414 - resolution:
1415 - {
1416 - integrity: sha512-VXoK5UMrgECLYaMuGuVTOx5kcuap1Jm8g/M83RnCHBKOqvPPmROFJGQaZhGccnsFtfXQ3XYa4/jMCJvZnbJBdA==
1417 - }
1418 - cpu: [arm64]
1419 - os: [android]
1420 -
1421 - "@rollup/rollup-darwin-arm64@4.22.4":
1422 - resolution:
1423 - {
1424 - integrity: sha512-xMM9ORBqu81jyMKCDP+SZDhnX2QEVQzTcC6G18KlTQEzWK8r/oNZtKuZaCcHhnsa6fEeOBionoyl5JsAbE/36Q==
1425 - }
1426 - cpu: [arm64]
1427 - os: [darwin]
1428 -
1429 - "@rollup/rollup-darwin-x64@4.22.4":
1430 - resolution:
1431 - {
1432 - integrity: sha512-aJJyYKQwbHuhTUrjWjxEvGnNNBCnmpHDvrb8JFDbeSH3m2XdHcxDd3jthAzvmoI8w/kSjd2y0udT+4okADsZIw==
1433 - }
1434 - cpu: [x64]
1435 - os: [darwin]
1436 -
1437 - "@rollup/rollup-linux-arm-gnueabihf@4.22.4":
1438 - resolution:
1439 - {
1440 - integrity: sha512-j63YtCIRAzbO+gC2L9dWXRh5BFetsv0j0va0Wi9epXDgU/XUi5dJKo4USTttVyK7fGw2nPWK0PbAvyliz50SCQ==
1441 - }
1442 - cpu: [arm]
1443 - os: [linux]
1444 -
1445 - "@rollup/rollup-linux-arm-musleabihf@4.22.4":
1446 - resolution:
1447 - {
1448 - integrity: sha512-dJnWUgwWBX1YBRsuKKMOlXCzh2Wu1mlHzv20TpqEsfdZLb3WoJW2kIEsGwLkroYf24IrPAvOT/ZQ2OYMV6vlrg==
1449 - }
1450 - cpu: [arm]
1451 - os: [linux]
1452 -
1453 - "@rollup/rollup-linux-arm64-gnu@4.22.4":
1454 - resolution:
1455 - {
1456 - integrity: sha512-AdPRoNi3NKVLolCN/Sp4F4N1d98c4SBnHMKoLuiG6RXgoZ4sllseuGioszumnPGmPM2O7qaAX/IJdeDU8f26Aw==
1457 - }
1458 - cpu: [arm64]
1459 - os: [linux]
1460 -
1461 - "@rollup/rollup-linux-arm64-musl@4.22.4":
1462 - resolution:
1463 - {
1464 - integrity: sha512-Gl0AxBtDg8uoAn5CCqQDMqAx22Wx22pjDOjBdmG0VIWX3qUBHzYmOKh8KXHL4UpogfJ14G4wk16EQogF+v8hmA==
1465 - }
1466 - cpu: [arm64]
1467 - os: [linux]
1468 -
1469 - "@rollup/rollup-linux-powerpc64le-gnu@4.22.4":
1470 - resolution:
1471 - {
1472 - integrity: sha512-3aVCK9xfWW1oGQpTsYJJPF6bfpWfhbRnhdlyhak2ZiyFLDaayz0EP5j9V1RVLAAxlmWKTDfS9wyRyY3hvhPoOg==
1473 - }
1474 - cpu: [ppc64]
1475 - os: [linux]
1476 -
1477 - "@rollup/rollup-linux-riscv64-gnu@4.22.4":
1478 - resolution:
1479 - {
1480 - integrity: sha512-ePYIir6VYnhgv2C5Xe9u+ico4t8sZWXschR6fMgoPUK31yQu7hTEJb7bCqivHECwIClJfKgE7zYsh1qTP3WHUA==
1481 - }
1482 - cpu: [riscv64]
1483 - os: [linux]
1484 -
1485 - "@rollup/rollup-linux-s390x-gnu@4.22.4":
1486 - resolution:
1487 - {
1488 - integrity: sha512-GqFJ9wLlbB9daxhVlrTe61vJtEY99/xB3C8e4ULVsVfflcpmR6c8UZXjtkMA6FhNONhj2eA5Tk9uAVw5orEs4Q==
1489 - }
1490 - cpu: [s390x]
1491 - os: [linux]
1492 -
1493 - "@rollup/rollup-linux-x64-gnu@4.22.4":
1494 - resolution:
1495 - {
1496 - integrity: sha512-87v0ol2sH9GE3cLQLNEy0K/R0pz1nvg76o8M5nhMR0+Q+BBGLnb35P0fVz4CQxHYXaAOhE8HhlkaZfsdUOlHwg==
1497 - }
1498 - cpu: [x64]
1499 - os: [linux]
1500 -
1501 - "@rollup/rollup-linux-x64-musl@4.22.4":
1502 - resolution:
1503 - {
1504 - integrity: sha512-UV6FZMUgePDZrFjrNGIWzDo/vABebuXBhJEqrHxrGiU6HikPy0Z3LfdtciIttEUQfuDdCn8fqh7wiFJjCNwO+g==
1505 - }
1506 - cpu: [x64]
1507 - os: [linux]
1508 -
1509 - "@rollup/rollup-win32-arm64-msvc@4.22.4":
1510 - resolution:
1511 - {
1512 - integrity: sha512-BjI+NVVEGAXjGWYHz/vv0pBqfGoUH0IGZ0cICTn7kB9PyjrATSkX+8WkguNjWoj2qSr1im/+tTGRaY+4/PdcQw==
1513 - }
1514 - cpu: [arm64]
1515 - os: [win32]
1516 -
1517 - "@rollup/rollup-win32-ia32-msvc@4.22.4":
1518 - resolution:
1519 - {
1520 - integrity: sha512-SiWG/1TuUdPvYmzmYnmd3IEifzR61Tragkbx9D3+R8mzQqDBz8v+BvZNDlkiTtI9T15KYZhP0ehn3Dld4n9J5g==
1521 - }
1522 - cpu: [ia32]
1523 - os: [win32]
1524 -
1525 - "@rollup/rollup-win32-x64-msvc@4.22.4":
1526 - resolution:
1527 - {
1528 - integrity: sha512-j8pPKp53/lq9lMXN57S8cFz0MynJk8OWNuUnXct/9KCpKU7DgU3bYMJhwWmcqC0UU29p8Lr0/7KEVcaM6bf47Q==
1529 - }
1530 - cpu: [x64]
1531 - os: [win32]
1532 -
1533 - "@shikijs/core@1.18.0":
1534 - resolution:
1535 - {
1536 - integrity: sha512-VK4BNVCd2leY62Nm2JjyxtRLkyrZT/tv104O81eyaCjHq4Adceq2uJVFJJAIof6lT1mBwZrEo2qT/T+grv3MQQ==
1537 - }
1538 -
1539 - "@shikijs/engine-javascript@1.18.0":
1540 - resolution:
1541 - {
1542 - integrity: sha512-qoP/aO/ATNwYAUw1YMdaip/YVEstMZEgrwhePm83Ll9OeQPuxDZd48szZR8oSQNQBT8m8UlWxZv8EA3lFuyI5A==
1543 - }
1544 -
1545 - "@shikijs/engine-oniguruma@1.18.0":
1546 - resolution:
1547 - {
1548 - integrity: sha512-B9u0ZKI/cud+TcmF8Chyh+R4V5qQVvyDOqXC2l2a4x73PBSBc6sZ0JRAX3eqyJswqir6ktwApUUGBYePdKnMJg==
1549 - }
1550 -
1551 - "@shikijs/markdown-it@1.18.0":
1552 - resolution:
1553 - {
1554 - integrity: sha512-acU44AAYYk7cESJbpEmcmLP5KJzuIUBzuCHcVd4glJPRK1UYc7Pqfg/chKv0DFYsC0u5BdFT15Od959tPA3xJQ==
1555 - }
1556 -
1557 - "@shikijs/types@1.18.0":
1558 - resolution:
1559 - {
1560 - integrity: sha512-O9N36UEaGGrxv1yUrN2nye7gDLG5Uq0/c1LyfmxsvzNPqlHzWo9DI0A4+fhW2y3bGKuQu/fwS7EPdKJJCowcVA==
1561 - }
1562 -
1563 - "@shikijs/vscode-textmate@9.2.2":
1564 - resolution:
1565 - {
1566 - integrity: sha512-TMp15K+GGYrWlZM8+Lnj9EaHEFmOen0WJBrfa17hF7taDOYthuPPV0GWzfd/9iMij0akS/8Yw2ikquH7uVi/fg==
1567 - }
1568 -
1569 - "@sideway/address@4.1.5":
1570 - resolution:
1571 - {
1572 - integrity: sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==
1573 - }
1574 -
1575 - "@sideway/formula@3.0.1":
1576 - resolution:
1577 - {
1578 - integrity: sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==
1579 - }
1580 -
1581 - "@sideway/pinpoint@2.0.0":
1582 - resolution:
1583 - {
1584 - integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==
1585 - }
1586 -
1587 - "@sindresorhus/merge-streams@2.3.0":
1588 - resolution:
1589 - {
1590 - integrity: sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==
1591 - }
1592 - engines: { node: ">=18" }
1593 -
1594 - "@stylistic/eslint-plugin@2.8.0":
1595 - resolution:
1596 - {
1597 - integrity: sha512-Ufvk7hP+bf+pD35R/QfunF793XlSRIC7USr3/EdgduK9j13i2JjmsM0LUz3/foS+jDYp2fzyWZA9N44CPur0Ow==
1598 - }
1599 - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 }
1600 - peerDependencies:
1601 - eslint: ^9.11.0
1602 -
1603 - "@trysound/sax@0.2.0":
1604 - resolution:
1605 - {
1606 - integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==
1607 - }
1608 - engines: { node: ">=10.13.0" }
1609 -
1610 - "@tsconfig/node20@20.1.4":
1611 - resolution:
1612 - {
1613 - integrity: sha512-sqgsT69YFeLWf5NtJ4Xq/xAF8p4ZQHlmGW74Nu2tD4+g5fAsposc4ZfaaPixVu4y01BEiDCWLRDCvDM5JOsRxg==
1614 - }
1615 -
1616 - "@types/bytes@3.1.4":
1617 - resolution:
1618 - {
1619 - integrity: sha512-A0uYgOj3zNc4hNjHc5lYUfJQ/HVyBXiUMKdXd7ysclaE6k9oJdavQzODHuwjpUu2/boCP8afjQYi8z/GtvNCWA==
1620 - }
1621 -
1622 - "@types/debug@4.1.12":
1623 - resolution:
1624 - {
1625 - integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==
1626 - }
1627 -
1628 - "@types/estree@1.0.5":
1629 - resolution:
1630 - {
1631 - integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==
1632 - }
1633 -
1634 - "@types/estree@1.0.6":
1635 - resolution:
1636 - {
1637 - integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==
1638 - }
1639 -
1640 - "@types/file-saver@2.0.7":
1641 - resolution:
1642 - {
1643 - integrity: sha512-dNKVfHd/jk0SkR/exKGj2ggkB45MAkzvWCaqLUUgkyjITkGNzH8H+yUwr+BLJUBjZOe9w8X3wgmXhZDRg1ED6A==
1644 - }
1645 -
1646 - "@types/fs-extra@11.0.4":
1647 - resolution:
1648 - {
1649 - integrity: sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==
1650 - }
1651 -
1652 - "@types/hast@3.0.4":
1653 - resolution:
1654 - {
1655 - integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==
1656 - }
1657 -
1658 - "@types/inquirer@9.0.7":
1659 - resolution:
1660 - {
1661 - integrity: sha512-Q0zyBupO6NxGRZut/JdmqYKOnN95Eg5V8Csg3PGKkP+FnvsUZx1jAyK7fztIszxxMuoBA6E3KXWvdZVXIpx60g==
1662 - }
1663 -
1664 - "@types/jsdom@21.1.7":
1665 - resolution:
1666 - {
1667 - integrity: sha512-yOriVnggzrnQ3a9OKOCxaVuSug3w3/SbOj5i7VwXWZEyUNl3bLF9V3MfxGbZKuwqJOQyRfqXyROBB1CoZLFWzA==
1668 - }
1669 -
1670 - "@types/json-schema@7.0.15":
1671 - resolution:
1672 - {
1673 - integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==
1674 - }
1675 -
1676 - "@types/jsonfile@6.1.4":
1677 - resolution:
1678 - {
1679 - integrity: sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==
1680 - }
1681 -
1682 - "@types/katex@0.16.7":
1683 - resolution:
1684 - {
1685 - integrity: sha512-HMwFiRujE5PjrgwHQ25+bsLJgowjGjm5Z8FVSf0N6PwgJrwxH0QxzHYDcKsTfV3wva0vzrpqMTJS2jXPr5BMEQ==
1686 - }
1687 -
1688 - "@types/lodash-es@4.17.12":
1689 - resolution:
1690 - {
1691 - integrity: sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==
1692 - }
1693 -
1694 - "@types/lodash@4.17.7":
1695 - resolution:
1696 - {
1697 - integrity: sha512-8wTvZawATi/lsmNu10/j2hk1KEP0IvjubqPE3cu1Xz7xfXXt5oCq3SNUz4fMIP4XGF9Ky+Ue2tBA3hcS7LSBlA==
1698 - }
1699 -
1700 - "@types/mdast@4.0.4":
1701 - resolution:
1702 - {
1703 - integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==
1704 - }
1705 -
1706 - "@types/ms@0.7.34":
1707 - resolution:
1708 - {
1709 - integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==
1710 - }
1711 -
1712 - "@types/node@22.5.5":
1713 - resolution:
1714 - {
1715 - integrity: sha512-Xjs4y5UPO/CLdzpgR6GirZJx36yScjh73+2NlLlkFRSoQN8B0DpfXPdZGnvVmLRLOsqDpOfTNv7D9trgGhmOIA==
1716 - }
1717 -
1718 - "@types/normalize-package-data@2.4.4":
1719 - resolution:
1720 - {
1721 - integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==
1722 - }
1723 -
1724 - "@types/semver@7.5.8":
1725 - resolution:
1726 - {
1727 - integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==
1728 - }
1729 -
1730 - "@types/sinonjs__fake-timers@8.1.1":
1731 - resolution:
1732 - {
1733 - integrity: sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==
1734 - }
1735 -
1736 - "@types/sizzle@2.3.8":
1737 - resolution:
1738 - {
1739 - integrity: sha512-0vWLNK2D5MT9dg0iOo8GlKguPAU02QjmZitPEsXRuJXU/OGIOt9vT9Fc26wtYuavLxtO45v9PGleoL9Z0k1LHg==
1740 - }
1741 -
1742 - "@types/through@0.0.33":
1743 - resolution:
1744 - {
1745 - integrity: sha512-HsJ+z3QuETzP3cswwtzt2vEIiHBk/dCcHGhbmG5X3ecnwFD/lPrMpliGXxSCg03L9AhrdwA4Oz/qfspkDW+xGQ==
1746 - }
1747 -
1748 - "@types/tough-cookie@4.0.5":
1749 - resolution:
1750 - {
1751 - integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==
1752 - }
1753 -
1754 - "@types/unist@3.0.3":
1755 - resolution:
1756 - {
1757 - integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==
1758 - }
1759 -
1760 - "@types/validator@13.12.2":
1761 - resolution:
1762 - {
1763 - integrity: sha512-6SlHBzUW8Jhf3liqrGGXyTJSIFe4nqlJ5A5KaMZ2l/vbM3Wh3KSybots/wfWVzNLK4D1NZluDlSQIbIEPx6oyA==
1764 - }
1765 -
1766 - "@types/web-bluetooth@0.0.20":
1767 - resolution:
1768 - {
1769 - integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==
1770 - }
1771 -
1772 - "@types/yauzl@2.10.3":
1773 - resolution:
1774 - {
1775 - integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==
1776 - }
1777 -
1778 - "@typescript-eslint/eslint-plugin@8.6.0":
1779 - resolution:
1780 - {
1781 - integrity: sha512-UOaz/wFowmoh2G6Mr9gw60B1mm0MzUtm6Ic8G2yM1Le6gyj5Loi/N+O5mocugRGY+8OeeKmkMmbxNqUCq3B4Sg==
1782 - }
1783 - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 }
1784 - peerDependencies:
1785 - "@typescript-eslint/parser": ^8.6.0
1786 - eslint: ^9.11.0
1787 - typescript: "*"
1788 - peerDependenciesMeta:
1789 - typescript:
1790 - optional: true
1791 -
1792 - "@typescript-eslint/parser@8.6.0":
1793 - resolution:
1794 - {
1795 - integrity: sha512-eQcbCuA2Vmw45iGfcyG4y6rS7BhWfz9MQuk409WD47qMM+bKCGQWXxvoOs1DUp+T7UBMTtRTVT+kXr7Sh4O9Ow==
1796 - }
1797 - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 }
1798 - peerDependencies:
1799 - eslint: ^9.11.0
1800 - typescript: "*"
1801 - peerDependenciesMeta:
1802 - typescript:
1803 - optional: true
1804 -
1805 - "@typescript-eslint/scope-manager@6.21.0":
1806 - resolution:
1807 - {
1808 - integrity: sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==
1809 - }
1810 - engines: { node: ^16.0.0 || >=18.0.0 }
1811 -
1812 - "@typescript-eslint/scope-manager@8.6.0":
1813 - resolution:
1814 - {
1815 - integrity: sha512-ZuoutoS5y9UOxKvpc/GkvF4cuEmpokda4wRg64JEia27wX+PysIE9q+lzDtlHHgblwUWwo5/Qn+/WyTUvDwBHw==
1816 - }
1817 - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 }
1818 -
1819 - "@typescript-eslint/type-utils@8.6.0":
1820 - resolution:
1821 - {
1822 - integrity: sha512-dtePl4gsuenXVwC7dVNlb4mGDcKjDT/Ropsk4za/ouMBPplCLyznIaR+W65mvCvsyS97dymoBRrioEXI7k0XIg==
1823 - }
1824 - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 }
1825 - peerDependencies:
1826 - typescript: "*"
1827 - peerDependenciesMeta:
1828 - typescript:
1829 - optional: true
1830 -
1831 - "@typescript-eslint/types@6.21.0":
1832 - resolution:
1833 - {
1834 - integrity: sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==
1835 - }
1836 - engines: { node: ^16.0.0 || >=18.0.0 }
1837 -
1838 - "@typescript-eslint/types@8.6.0":
1839 - resolution:
1840 - {
1841 - integrity: sha512-rojqFZGd4MQxw33SrOy09qIDS8WEldM8JWtKQLAjf/X5mGSeEFh5ixQlxssMNyPslVIk9yzWqXCsV2eFhYrYUw==
1842 - }
1843 - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 }
1844 -
1845 - "@typescript-eslint/typescript-estree@6.21.0":
1846 - resolution:
1847 - {
1848 - integrity: sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==
1849 - }
1850 - engines: { node: ^16.0.0 || >=18.0.0 }
1851 - peerDependencies:
1852 - typescript: "*"
1853 - peerDependenciesMeta:
1854 - typescript:
1855 - optional: true
1856 -
1857 - "@typescript-eslint/typescript-estree@8.6.0":
1858 - resolution:
1859 - {
1860 - integrity: sha512-MOVAzsKJIPIlLK239l5s06YXjNqpKTVhBVDnqUumQJja5+Y94V3+4VUFRA0G60y2jNnTVwRCkhyGQpavfsbq/g==
1861 - }
1862 - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 }
1863 - peerDependencies:
1864 - typescript: "*"
1865 - peerDependenciesMeta:
1866 - typescript:
1867 - optional: true
1868 -
1869 - "@typescript-eslint/utils@6.21.0":
1870 - resolution:
1871 - {
1872 - integrity: sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==
1873 - }
1874 - engines: { node: ^16.0.0 || >=18.0.0 }
1875 - peerDependencies:
1876 - eslint: ^9.11.0
1877 -
1878 - "@typescript-eslint/utils@8.6.0":
1879 - resolution:
1880 - {
1881 - integrity: sha512-eNp9cWnYf36NaOVjkEUznf6fEgVy1TWpE0o52e4wtojjBx7D1UV2WAWGzR+8Y5lVFtpMLPwNbC67T83DWSph4A==
1882 - }
1883 - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 }
1884 - peerDependencies:
1885 - eslint: ^9.11.0
1886 -
1887 - "@typescript-eslint/visitor-keys@6.21.0":
1888 - resolution:
1889 - {
1890 - integrity: sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==
1891 - }
1892 - engines: { node: ^16.0.0 || >=18.0.0 }
1893 -
1894 - "@typescript-eslint/visitor-keys@8.6.0":
1895 - resolution:
1896 - {
1897 - integrity: sha512-wapVFfZg9H0qOYh4grNVQiMklJGluQrOUiOhYRrQWhx7BY/+I1IYb8BczWNbbUpO+pqy0rDciv3lQH5E1bCLrg==
1898 - }
1899 - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 }
1900 -
1901 - "@ungap/structured-clone@1.2.0":
1902 - resolution:
1903 - {
1904 - integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==
1905 - }
1906 -
1907 - "@unocss/config@0.56.5":
1908 - resolution:
1909 - {
1910 - integrity: sha512-rscnFIYgUlN/0hXHdhANyjFcDjDutt3JO0ZRITdNLzoglh7GVNiDTURBJwUZejF/vGJ7IkMd3qOdNhPFuRY1Bg==
1911 - }
1912 - engines: { node: ">=14" }
1913 -
1914 - "@unocss/core@0.56.5":
1915 - resolution:
1916 - {
1917 - integrity: sha512-fx5VhOjSHn0HdV2D34pEwFMAHJcJQRTCp1xEE4GzxY1irXzaa+m2aYf5PZjmDxehiOC16IH7TO9FOWANXk1E0w==
1918 - }
1919 -
1920 - "@unocss/eslint-config@0.56.5":
1921 - resolution:
1922 - {
1923 - integrity: sha512-UP7EBTl4ORRO0yqptW7oUWxM0qNh1Nk+z4rufC0C2kI8vKc8yab+sWvlBSC8DeX3kzR7uJxvtUsHGcBcoqZujg==
1924 - }
1925 - engines: { node: ">=14" }
1926 -
1927 - "@unocss/eslint-plugin@0.56.5":
1928 - resolution:
1929 - {
1930 - integrity: sha512-nMVw/kc0sYU5i8UBU1rEahzKhZRPTUjCztpPzo2KUKFKLBPAbTv0gJAOmU/n2kV3YiGk5Tl6jmShxu1MHjk5rA==
1931 - }
1932 - engines: { node: ">=14" }
1933 -
1934 - "@vitejs/plugin-vue-jsx@4.0.1":
1935 - resolution:
1936 - {
1937 - integrity: sha512-7mg9HFGnFHMEwCdB6AY83cVK4A6sCqnrjFYF4WIlebYAQVVJ/sC/CiTruVdrRlhrFoeZ8rlMxY9wYpPTIRhhAg==
1938 - }
1939 - engines: { node: ^18.0.0 || >=20.0.0 }
1940 - peerDependencies:
1941 - vite: ^5.0.0
1942 - vue: ^3.0.0
1943 -
1944 - "@vitejs/plugin-vue@5.1.4":
1945 - resolution:
1946 - {
1947 - integrity: sha512-N2XSI2n3sQqp5w7Y/AN/L2XDjBIRGqXko+eDp42sydYSBeJuSm5a1sLf8zakmo8u7tA8NmBgoDLA1HeOESjp9A==
1948 - }
1949 - engines: { node: ^18.0.0 || >=20.0.0 }
1950 - peerDependencies:
1951 - vite: ^5.0.0
1952 - vue: ^3.2.25
1953 -
1954 - "@vitest/eslint-plugin@1.1.4":
1955 - resolution:
1956 - {
1957 - integrity: sha512-kudjgefmJJ7xQ2WfbUU6pZbm7Ou4gLYRaao/8Ynide3G0QhVKHd978sDyWX4KOH0CCMH9cyrGAkFd55eGzJ48Q==
1958 - }
1959 - peerDependencies:
1960 - "@typescript-eslint/utils": ">= 8.0"
1961 - eslint: ^9.11.0
1962 - typescript: ">= 5.0.0"
1963 - vitest: "*"
1964 - peerDependenciesMeta:
1965 - "@typescript-eslint/utils":
1966 - optional: true
1967 - typescript:
1968 - optional: true
1969 - vitest:
1970 - optional: true
1971 -
1972 - "@vitest/expect@2.1.1":
1973 - resolution:
1974 - {
1975 - integrity: sha512-YeueunS0HiHiQxk+KEOnq/QMzlUuOzbU1Go+PgAsHvvv3tUkJPm9xWt+6ITNTlzsMXUjmgm5T+U7KBPK2qQV6w==
1976 - }
1977 -
1978 - "@vitest/mocker@2.1.1":
1979 - resolution:
1980 - {
1981 - integrity: sha512-LNN5VwOEdJqCmJ/2XJBywB11DLlkbY0ooDJW3uRX5cZyYCrc4PI/ePX0iQhE3BiEGiQmK4GE7Q/PqCkkaiPnrA==
1982 - }
1983 - peerDependencies:
1984 - "@vitest/spy": 2.1.1
1985 - msw: ^2.3.5
1986 - vite: ^5.0.0
1987 - peerDependenciesMeta:
1988 - msw:
1989 - optional: true
1990 - vite:
1991 - optional: true
1992 -
1993 - "@vitest/pretty-format@2.1.1":
1994 - resolution:
1995 - {
1996 - integrity: sha512-SjxPFOtuINDUW8/UkElJYQSFtnWX7tMksSGW0vfjxMneFqxVr8YJ979QpMbDW7g+BIiq88RAGDjf7en6rvLPPQ==
1997 - }
1998 -
1999 - "@vitest/runner@2.1.1":
2000 - resolution:
2001 - {
2002 - integrity: sha512-uTPuY6PWOYitIkLPidaY5L3t0JJITdGTSwBtwMjKzo5O6RCOEncz9PUN+0pDidX8kTHYjO0EwUIvhlGpnGpxmA==
2003 - }
2004 -
2005 - "@vitest/snapshot@2.1.1":
2006 - resolution:
2007 - {
2008 - integrity: sha512-BnSku1WFy7r4mm96ha2FzN99AZJgpZOWrAhtQfoxjUU5YMRpq1zmHRq7a5K9/NjqonebO7iVDla+VvZS8BOWMw==
2009 - }
2010 -
2011 - "@vitest/spy@2.1.1":
2012 - resolution:
2013 - {
2014 - integrity: sha512-ZM39BnZ9t/xZ/nF4UwRH5il0Sw93QnZXd9NAZGRpIgj0yvVwPpLd702s/Cx955rGaMlyBQkZJ2Ir7qyY48VZ+g==
2015 - }
2016 -
2017 - "@vitest/utils@2.1.1":
2018 - resolution:
2019 - {
2020 - integrity: sha512-Y6Q9TsI+qJ2CC0ZKj6VBb+T8UPz593N113nnUykqwANqhgf3QkZeHFlusgKLTqrnVHbj/XDKZcDHol+dxVT+rQ==
2021 - }
2022 -
2023 - "@volar/language-core@2.4.5":
2024 - resolution:
2025 - {
2026 - integrity: sha512-F4tA0DCO5Q1F5mScHmca0umsi2ufKULAnMOVBfMsZdT4myhVl4WdKRwCaKcfOkIEuyrAVvtq1ESBdZ+rSyLVww==
2027 - }
2028 -
2029 - "@volar/source-map@2.4.5":
2030 - resolution:
2031 - {
2032 - integrity: sha512-varwD7RaKE2J/Z+Zu6j3mNNJbNT394qIxXwdvz/4ao/vxOfyClZpSDtLKkwWmecinkOVos5+PWkWraelfMLfpw==
2033 - }
2034 -
2035 - "@volar/typescript@2.4.5":
2036 - resolution:
2037 - {
2038 - integrity: sha512-mcT1mHvLljAEtHviVcBuOyAwwMKz1ibXTi5uYtP/pf4XxoAzpdkQ+Br2IC0NPCvLCbjPZmbf3I0udndkfB1CDg==
2039 - }
2040 -
2041 - "@vue/babel-helper-vue-transform-on@1.2.5":
2042 - resolution:
2043 - {
2044 - integrity: sha512-lOz4t39ZdmU4DJAa2hwPYmKc8EsuGa2U0L9KaZaOJUt0UwQNjNA3AZTq6uEivhOKhhG1Wvy96SvYBoFmCg3uuw==
2045 - }
2046 -
2047 - "@vue/babel-plugin-jsx@1.2.5":
2048 - resolution:
2049 - {
2050 - integrity: sha512-zTrNmOd4939H9KsRIGmmzn3q2zvv1mjxkYZHgqHZgDrXz5B1Q3WyGEjO2f+JrmKghvl1JIRcvo63LgM1kH5zFg==
2051 - }
2052 - peerDependencies:
2053 - "@babel/core": ^7.0.0-0
2054 - peerDependenciesMeta:
2055 - "@babel/core":
2056 - optional: true
2057 -
2058 - "@vue/babel-plugin-resolve-type@1.2.5":
2059 - resolution:
2060 - {
2061 - integrity: sha512-U/ibkQrf5sx0XXRnUZD1mo5F7PkpKyTbfXM3a3rC4YnUz6crHEz9Jg09jzzL6QYlXNto/9CePdOg/c87O4Nlfg==
2062 - }
2063 - peerDependencies:
2064 - "@babel/core": ^7.0.0-0
2065 -
2066 - "@vue/compiler-core@3.5.8":
2067 - resolution:
2068 - {
2069 - integrity: sha512-Uzlxp91EPjfbpeO5KtC0KnXPkuTfGsNDeaKQJxQN718uz+RqDYarEf7UhQJGK+ZYloD2taUbHTI2J4WrUaZQNA==
2070 - }
2071 -
2072 - "@vue/compiler-dom@3.5.8":
2073 - resolution:
2074 - {
2075 - integrity: sha512-GUNHWvoDSbSa5ZSHT9SnV5WkStWfzJwwTd6NMGzilOE/HM5j+9EB9zGXdtu/fCNEmctBqMs6C9SvVPpVPuk1Eg==
2076 - }
2077 -
2078 - "@vue/compiler-sfc@3.5.8":
2079 - resolution:
2080 - {
2081 - integrity: sha512-taYpngQtSysrvO9GULaOSwcG5q821zCoIQBtQQSx7Uf7DxpR6CIHR90toPr9QfDD2mqHQPCSgoWBvJu0yV9zjg==
2082 - }
2083 -
2084 - "@vue/compiler-ssr@3.5.8":
2085 - resolution:
2086 - {
2087 - integrity: sha512-W96PtryNsNG9u0ZnN5Q5j27Z/feGrFV6zy9q5tzJVyJaLiwYxvC0ek4IXClZygyhjm+XKM7WD9pdKi/wIRVC/Q==
2088 - }
2089 -
2090 - "@vue/compiler-vue2@2.7.16":
2091 - resolution:
2092 - {
2093 - integrity: sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==
2094 - }
2095 -
2096 - "@vue/devtools-api@6.6.4":
2097 - resolution:
2098 - {
2099 - integrity: sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==
2100 - }
2101 -
2102 - "@vue/devtools-core@7.4.5":
2103 - resolution:
2104 - {
2105 - integrity: sha512-QwrgKYxwafJUJrKRvJGbzQLuGt0BC1P4qTr4qlEKgOOs+GV0n6zTry2oeHiwmj5H6pOkLoHnwFMOTB9rFtn9QQ==
2106 - }
2107 - peerDependencies:
2108 - vue: ^3.0.0
2109 -
2110 - "@vue/devtools-kit@7.4.5":
2111 - resolution:
2112 - {
2113 - integrity: sha512-Uuki4Z6Bc/ExvtlPkeDNGSAe4580R+HPcVABfTE9TF7BTz3Nntk7vxIRUyWblZkUEcB/x+wn2uofyt5i2LaUew==
2114 - }
2115 -
2116 - "@vue/devtools-shared@7.4.5":
2117 - resolution:
2118 - {
2119 - integrity: sha512-2XgUOkL/7QDmyYI9J7cm+rz/qBhcGv+W5+i1fhwdQ0HQ1RowhdK66F0QBuJSz/5k12opJY8eN6m03/XZMs7imQ==
2120 - }
2121 -
2122 - "@vue/language-core@2.1.6":
2123 - resolution:
2124 - {
2125 - integrity: sha512-MW569cSky9R/ooKMh6xa2g1D0AtRKbL56k83dzus/bx//RDJk24RHWkMzbAlXjMdDNyxAaagKPRquBIxkxlCkg==
2126 - }
2127 - peerDependencies:
2128 - typescript: "*"
2129 - peerDependenciesMeta:
2130 - typescript:
2131 - optional: true
2132 -
2133 - "@vue/reactivity@3.5.8":
2134 - resolution:
2135 - {
2136 - integrity: sha512-mlgUyFHLCUZcAYkqvzYnlBRCh0t5ZQfLYit7nukn1GR96gc48Bp4B7OIcSfVSvlG1k3BPfD+p22gi1t2n9tsXg==
2137 - }
2138 -
2139 - "@vue/runtime-core@3.5.8":
2140 - resolution:
2141 - {
2142 - integrity: sha512-fJuPelh64agZ8vKkZgp5iCkPaEqFJsYzxLk9vSC0X3G8ppknclNDr61gDc45yBGTaN5Xqc1qZWU3/NoaBMHcjQ==
2143 - }
2144 -
2145 - "@vue/runtime-dom@3.5.8":
2146 - resolution:
2147 - {
2148 - integrity: sha512-DpAUz+PKjTZPUOB6zJgkxVI3GuYc2iWZiNeeHQUw53kdrparSTG6HeXUrYDjaam8dVsCdvQxDz6ZWxnyjccUjQ==
2149 - }
2150 -
2151 - "@vue/server-renderer@3.5.8":
2152 - resolution:
2153 - {
2154 - integrity: sha512-7AmC9/mEeV9mmXNVyUIm1a1AjUhyeeGNbkLh39J00E7iPeGks8OGRB5blJiMmvqSh8SkaS7jkLWSpXtxUCeagA==
2155 - }
2156 - peerDependencies:
2157 - vue: 3.5.8
2158 -
2159 - "@vue/shared@3.5.8":
2160 - resolution:
2161 - {
2162 - integrity: sha512-mJleSWbAGySd2RJdX1RBtcrUBX6snyOc0qHpgk3lGi4l9/P/3ny3ELqFWqYdkXIwwNN/kdm8nD9ky8o6l/Lx2A==
2163 - }
2164 -
2165 - "@vue/test-utils@2.4.6":
2166 - resolution:
2167 - {
2168 - integrity: sha512-FMxEjOpYNYiFe0GkaHsnJPXFHxQ6m4t8vI/ElPGpMWxZKpmRvQ33OIrvRXemy6yha03RxhOlQuy+gZMC3CQSow==
2169 - }
2170 -
2171 - "@vue/tsconfig@0.5.1":
2172 - resolution:
2173 - {
2174 - integrity: sha512-VcZK7MvpjuTPx2w6blwnwZAu5/LgBUtejFOi3pPGQFXQN5Ela03FUtd2Qtg4yWGGissVL0dr6Ro1LfOFh+PCuQ==
2175 - }
2176 -
2177 - "@vueuse/components@11.1.0":
2178 - resolution:
2179 - {
2180 - integrity: sha512-8CTbvH1rHfAlqsMdMg6G2OiIvHiHn8HRx0yyJ+Ri/C8J6cLylXAd7VESawoCAkRdAXT4ucPnj/uYHZqEb0JbBQ==
2181 - }
2182 -
2183 - "@vueuse/core@11.1.0":
2184 - resolution:
2185 - {
2186 - integrity: sha512-P6dk79QYA6sKQnghrUz/1tHi0n9mrb/iO1WTMk/ElLmTyNqgDeSZ3wcDf6fRBGzRJbeG1dxzEOvLENMjr+E3fg==
2187 - }
2188 -
2189 - "@vueuse/metadata@11.1.0":
2190 - resolution:
2191 - {
2192 - integrity: sha512-l9Q502TBTaPYGanl1G+hPgd3QX5s4CGnpXriVBR5fEZ/goI6fvDaVmIl3Td8oKFurOxTmbXvBPSsgrd6eu6HYg==
2193 - }
2194 -
2195 - "@vueuse/shared@11.1.0":
2196 - resolution:
2197 - {
2198 - integrity: sha512-YUtIpY122q7osj+zsNMFAfMTubGz0sn5QzE5gPzAIiCmtt2ha3uQUY1+JPyL4gRCTsLPX82Y9brNbo/aqlA91w==
2199 - }
2200 -
2201 - "@yr/monotone-cubic-spline@1.0.3":
2202 - resolution:
2203 - {
2204 - integrity: sha512-FQXkOta0XBSUPHndIKON2Y9JeQz5ZeMqLYZVVK93FliNBFm7LNMIZmY6FrMEB9XPcDbE2bekMbZD6kzDkxwYjA==
2205 - }
2206 -
2207 - abbrev@2.0.0:
2208 - resolution:
2209 - {
2210 - integrity: sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==
2211 - }
2212 - engines: { node: ^14.17.0 || ^16.13.0 || >=18.0.0 }
2213 -
2214 - accepts@1.3.8:
2215 - resolution:
2216 - {
2217 - integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==
2218 - }
2219 - engines: { node: ">= 0.6" }
2220 -
2221 - acorn-jsx@5.3.2:
2222 - resolution:
2223 - {
2224 - integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
2225 - }
2226 - peerDependencies:
2227 - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
2228 -
2229 - acorn@8.12.1:
2230 - resolution:
2231 - {
2232 - integrity: sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==
2233 - }
2234 - engines: { node: ">=0.4.0" }
2235 - hasBin: true
2236 -
2237 - agent-base@7.1.1:
2238 - resolution:
2239 - {
2240 - integrity: sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==
2241 - }
2242 - engines: { node: ">= 14" }
2243 -
2244 - aggregate-error@3.1.0:
2245 - resolution:
2246 - {
2247 - integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==
2248 - }
2249 - engines: { node: ">=8" }
2250 -
2251 - ajv@6.12.6:
2252 - resolution:
2253 - {
2254 - integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
2255 - }
2256 -
2257 - ansi-colors@4.1.3:
2258 - resolution:
2259 - {
2260 - integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==
2261 - }
2262 - engines: { node: ">=6" }
2263 -
2264 - ansi-escapes@4.3.2:
2265 - resolution:
2266 - {
2267 - integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==
2268 - }
2269 - engines: { node: ">=8" }
2270 -
2271 - ansi-regex@5.0.1:
2272 - resolution:
2273 - {
2274 - integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
2275 - }
2276 - engines: { node: ">=8" }
2277 -
2278 - ansi-regex@6.1.0:
2279 - resolution:
2280 - {
2281 - integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==
2282 - }
2283 - engines: { node: ">=12" }
2284 -
2285 - ansi-styles@3.2.1:
2286 - resolution:
2287 - {
2288 - integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
2289 - }
2290 - engines: { node: ">=4" }
2291 -
2292 - ansi-styles@4.3.0:
2293 - resolution:
2294 - {
2295 - integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
2296 - }
2297 - engines: { node: ">=8" }
2298 -
2299 - ansi-styles@6.2.1:
2300 - resolution:
2301 - {
2302 - integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==
2303 - }
2304 - engines: { node: ">=12" }
2305 -
2306 - any-promise@1.3.0:
2307 - resolution:
2308 - {
2309 - integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==
2310 - }
2311 -
2312 - anymatch@3.1.3:
2313 - resolution:
2314 - {
2315 - integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==
2316 - }
2317 - engines: { node: ">= 8" }
2318 -
2319 - apexcharts@3.53.0:
2320 - resolution:
2321 - {
2322 - integrity: sha512-QESZHZY3w9LPQ64PGh1gEdfjYjJ5Jp+Dfy0D/CLjsLOPTpXzdxwlNMqRj+vPbTcP0nAHgjWv1maDqcEq6u5olw==
2323 - }
2324 -
2325 - arch@2.2.0:
2326 - resolution:
2327 - {
2328 - integrity: sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==
2329 - }
2330 -
2331 - are-docs-informative@0.0.2:
2332 - resolution:
2333 - {
2334 - integrity: sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==
2335 - }
2336 - engines: { node: ">=14" }
2337 -
2338 - arg@5.0.2:
2339 - resolution:
2340 - {
2341 - integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==
2342 - }
2343 -
2344 - argparse@2.0.1:
2345 - resolution:
2346 - {
2347 - integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
2348 - }
2349 -
2350 - array-union@2.1.0:
2351 - resolution:
2352 - {
2353 - integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==
2354 - }
2355 - engines: { node: ">=8" }
2356 -
2357 - asn1@0.2.6:
2358 - resolution:
2359 - {
2360 - integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==
2361 - }
2362 -
2363 - assert-plus@1.0.0:
2364 - resolution:
2365 - {
2366 - integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==
2367 - }
2368 - engines: { node: ">=0.8" }
2369 -
2370 - assertion-error@2.0.1:
2371 - resolution:
2372 - {
2373 - integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==
2374 - }
2375 - engines: { node: ">=12" }
2376 -
2377 - astral-regex@2.0.0:
2378 - resolution:
2379 - {
2380 - integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==
2381 - }
2382 - engines: { node: ">=8" }
2383 -
2384 - async-validator@4.2.5:
2385 - resolution:
2386 - {
2387 - integrity: sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==
2388 - }
2389 -
2390 - async@2.6.4:
2391 - resolution:
2392 - {
2393 - integrity: sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==
2394 - }
2395 -
2396 - async@3.2.6:
2397 - resolution:
2398 - {
2399 - integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==
2400 - }
2401 -
2402 - asynckit@0.4.0:
2403 - resolution:
2404 - {
2405 - integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
2406 - }
2407 -
2408 - at-least-node@1.0.0:
2409 - resolution:
2410 - {
2411 - integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==
2412 - }
2413 - engines: { node: ">= 4.0.0" }
2414 -
2415 - autoprefixer@10.4.20:
2416 - resolution:
2417 - {
2418 - integrity: sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==
2419 - }
2420 - engines: { node: ^10 || ^12 || >=14 }
2421 - hasBin: true
2422 - peerDependencies:
2423 - postcss: ^8.1.0
2424 -
2425 - aws-sign2@0.7.0:
2426 - resolution:
2427 - {
2428 - integrity: sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==
2429 - }
2430 -
2431 - aws4@1.13.2:
2432 - resolution:
2433 - {
2434 - integrity: sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==
2435 - }
2436 -
2437 - axios@1.7.7:
2438 - resolution:
2439 - {
2440 - integrity: sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==
2441 - }
2442 -
2443 - balanced-match@1.0.2:
2444 - resolution:
2445 - {
2446 - integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
2447 - }
2448 -
2449 - base64-js@1.5.1:
2450 - resolution:
2451 - {
2452 - integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
2453 - }
2454 -
2455 - bcrypt-pbkdf@1.0.2:
2456 - resolution:
2457 - {
2458 - integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==
2459 - }
2460 -
2461 - binary-extensions@2.3.0:
2462 - resolution:
2463 - {
2464 - integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==
2465 - }
2466 - engines: { node: ">=8" }
2467 -
2468 - birpc@0.2.17:
2469 - resolution:
2470 - {
2471 - integrity: sha512-+hkTxhot+dWsLpp3gia5AkVHIsKlZybNT5gIYiDlNzJrmYPcTM9k5/w2uaj3IPpd7LlEYpmCj4Jj1nC41VhDFg==
2472 - }
2473 -
2474 - blob-util@2.0.2:
2475 - resolution:
2476 - {
2477 - integrity: sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==
2478 - }
2479 -
2480 - bluebird@3.7.2:
2481 - resolution:
2482 - {
2483 - integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==
2484 - }
2485 -
2486 - boolbase@1.0.0:
2487 - resolution:
2488 - {
2489 - integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==
2490 - }
2491 -
2492 - brace-expansion@1.1.11:
2493 - resolution:
2494 - {
2495 - integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
2496 - }
2497 -
2498 - brace-expansion@2.0.1:
2499 - resolution:
2500 - {
2501 - integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==
2502 - }
2503 -
2504 - braces@3.0.3:
2505 - resolution:
2506 - {
2507 - integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==
2508 - }
2509 - engines: { node: ">=8" }
2510 -
2511 - browserslist@4.23.3:
2512 - resolution:
2513 - {
2514 - integrity: sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==
2515 - }
2516 - engines: { node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7 }
2517 - hasBin: true
2518 -
2519 - buffer-crc32@0.2.13:
2520 - resolution:
2521 - {
2522 - integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==
2523 - }
2524 -
2525 - buffer@5.7.1:
2526 - resolution:
2527 - {
2528 - integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==
2529 - }
2530 -
2531 - builtin-modules@3.3.0:
2532 - resolution:
2533 - {
2534 - integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==
2535 - }
2536 - engines: { node: ">=6" }
2537 -
2538 - bundle-name@4.1.0:
2539 - resolution:
2540 - {
2541 - integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==
2542 - }
2543 - engines: { node: ">=18" }
2544 -
2545 - bundle-require@5.0.0:
2546 - resolution:
2547 - {
2548 - integrity: sha512-GuziW3fSSmopcx4KRymQEJVbZUfqlCqcq7dvs6TYwKRZiegK/2buMxQTPs6MGlNv50wms1699qYO54R8XfRX4w==
2549 - }
2550 - engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 }
2551 - peerDependencies:
2552 - esbuild: ">=0.18"
2553 -
2554 - bytes@3.1.2:
2555 - resolution:
2556 - {
2557 - integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==
2558 - }
2559 - engines: { node: ">= 0.8" }
2560 -
2561 - c12@1.11.2:
2562 - resolution:
2563 - {
2564 - integrity: sha512-oBs8a4uvSDO9dm8b7OCFW7+dgtVrwmwnrVXYzLm43ta7ep2jCn/0MhoUFygIWtxhyy6+/MG7/agvpY0U1Iemew==
2565 - }
2566 - peerDependencies:
2567 - magicast: ^0.3.4
2568 - peerDependenciesMeta:
2569 - magicast:
2570 - optional: true
2571 -
2572 - cac@6.7.14:
2573 - resolution:
2574 - {
2575 - integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==
2576 - }
2577 - engines: { node: ">=8" }
2578 -
2579 - cache-content-type@1.0.1:
2580 - resolution:
2581 - {
2582 - integrity: sha512-IKufZ1o4Ut42YUrZSo8+qnMTrFuKkvyoLXUywKz9GJ5BrhOFGhLdkx9sG4KAnVvbY6kEcSFjLQul+DVmBm2bgA==
2583 - }
2584 - engines: { node: ">= 6.0.0" }
2585 -
2586 - cachedir@2.4.0:
2587 - resolution:
2588 - {
2589 - integrity: sha512-9EtFOZR8g22CL7BWjJ9BUx1+A/djkofnyW3aOXZORNW2kxoUpx2h+uN2cOqwPmFhnpVmxg+KW2OjOSgChTEvsQ==
2590 - }
2591 - engines: { node: ">=6" }
2592 -
2593 - call-bind@1.0.7:
2594 - resolution:
2595 - {
2596 - integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==
2597 - }
2598 - engines: { node: ">= 0.4" }
2599 -
2600 - callsites@3.1.0:
2601 - resolution:
2602 - {
2603 - integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
2604 - }
2605 - engines: { node: ">=6" }
2606 -
2607 - camelcase-css@2.0.1:
2608 - resolution:
2609 - {
2610 - integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==
2611 - }
2612 - engines: { node: ">= 6" }
2613 -
2614 - caniuse-lite@1.0.30001663:
2615 - resolution:
2616 - {
2617 - integrity: sha512-o9C3X27GLKbLeTYZ6HBOLU1tsAcBZsLis28wrVzddShCS16RujjHp9GDHKZqrB3meE0YjhawvMFsGb/igqiPzA==
2618 - }
2619 -
2620 - caseless@0.12.0:
2621 - resolution:
2622 - {
2623 - integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==
2624 - }
2625 -
2626 - ccount@2.0.1:
2627 - resolution:
2628 - {
2629 - integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==
2630 - }
2631 -
2632 - chai@5.1.1:
2633 - resolution:
2634 - {
2635 - integrity: sha512-pT1ZgP8rPNqUgieVaEY+ryQr6Q4HXNg8Ei9UnLUrjN4IA7dvQC5JB+/kxVcPNDHyBcc/26CXPkbNzq3qwrOEKA==
2636 - }
2637 - engines: { node: ">=12" }
2638 -
2639 - chalk@2.4.2:
2640 - resolution:
2641 - {
2642 - integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
2643 - }
2644 - engines: { node: ">=4" }
2645 -
2646 - chalk@4.1.2:
2647 - resolution:
2648 - {
2649 - integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
2650 - }
2651 - engines: { node: ">=10" }
2652 -
2653 - character-entities-html4@2.1.0:
2654 - resolution:
2655 - {
2656 - integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==
2657 - }
2658 -
2659 - character-entities-legacy@3.0.0:
2660 - resolution:
2661 - {
2662 - integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==
2663 - }
2664 -
2665 - character-entities@2.0.2:
2666 - resolution:
2667 - {
2668 - integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==
2669 - }
2670 -
2671 - check-error@2.1.1:
2672 - resolution:
2673 - {
2674 - integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==
2675 - }
2676 - engines: { node: ">= 16" }
2677 -
2678 - check-more-types@2.24.0:
2679 - resolution:
2680 - {
2681 - integrity: sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==
2682 - }
2683 - engines: { node: ">= 0.8.0" }
2684 -
2685 - chokidar@3.6.0:
2686 - resolution:
2687 - {
2688 - integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==
2689 - }
2690 - engines: { node: ">= 8.10.0" }
2691 -
2692 - chokidar@4.0.1:
2693 - resolution:
2694 - {
2695 - integrity: sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==
2696 - }
2697 - engines: { node: ">= 14.16.0" }
2698 -
2699 - chownr@2.0.0:
2700 - resolution:
2701 - {
2702 - integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==
2703 - }
2704 - engines: { node: ">=10" }
2705 -
2706 - ci-info@3.9.0:
2707 - resolution:
2708 - {
2709 - integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==
2710 - }
2711 - engines: { node: ">=8" }
2712 -
2713 - ci-info@4.0.0:
2714 - resolution:
2715 - {
2716 - integrity: sha512-TdHqgGf9odd8SXNuxtUBVx8Nv+qZOejE6qyqiy5NtbYYQOeFa6zmHkxlPzmaLxWWHsU6nJmB7AETdVPi+2NBUg==
2717 - }
2718 - engines: { node: ">=8" }
2719 -
2720 - citty@0.1.6:
2721 - resolution:
2722 - {
2723 - integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==
2724 - }
2725 -
2726 - classnames@2.5.1:
2727 - resolution:
2728 - {
2729 - integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==
2730 - }
2731 -
2732 - clean-regexp@1.0.0:
2733 - resolution:
2734 - {
2735 - integrity: sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==
2736 - }
2737 - engines: { node: ">=4" }
2738 -
2739 - clean-stack@2.2.0:
2740 - resolution:
2741 - {
2742 - integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==
2743 - }
2744 - engines: { node: ">=6" }
2745 -
2746 - cli-cursor@3.1.0:
2747 - resolution:
2748 - {
2749 - integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==
2750 - }
2751 - engines: { node: ">=8" }
2752 -
2753 - cli-table3@0.6.5:
2754 - resolution:
2755 - {
2756 - integrity: sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==
2757 - }
2758 - engines: { node: 10.* || >= 12.* }
2759 -
2760 - cli-truncate@2.1.0:
2761 - resolution:
2762 - {
2763 - integrity: sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==
2764 - }
2765 - engines: { node: ">=8" }
2766 -
2767 - cliui@8.0.1:
2768 - resolution:
2769 - {
2770 - integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==
2771 - }
2772 - engines: { node: ">=12" }
2773 -
2774 - co@4.6.0:
2775 - resolution:
2776 - {
2777 - integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==
2778 - }
2779 - engines: { iojs: ">= 1.0.0", node: ">= 0.12.0" }
2780 -
2781 - color-convert@1.9.3:
2782 - resolution:
2783 - {
2784 - integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
2785 - }
2786 -
2787 - color-convert@2.0.1:
2788 - resolution:
2789 - {
2790 - integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
2791 - }
2792 - engines: { node: ">=7.0.0" }
2793 -
2794 - color-name@1.1.3:
2795 - resolution:
2796 - {
2797 - integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
2798 - }
2799 -
2800 - color-name@1.1.4:
2801 - resolution:
2802 - {
2803 - integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
2804 - }
2805 -
2806 - colord@2.9.3:
2807 - resolution:
2808 - {
2809 - integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==
2810 - }
2811 -
2812 - colorette@2.0.20:
2813 - resolution:
2814 - {
2815 - integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==
2816 - }
2817 -
2818 - combined-stream@1.0.8:
2819 - resolution:
2820 - {
2821 - integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
2822 - }
2823 - engines: { node: ">= 0.8" }
2824 -
2825 - comma-separated-tokens@2.0.3:
2826 - resolution:
2827 - {
2828 - integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==
2829 - }
2830 -
2831 - commander@10.0.1:
2832 - resolution:
2833 - {
2834 - integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==
2835 - }
2836 - engines: { node: ">=14" }
2837 -
2838 - commander@4.1.1:
2839 - resolution:
2840 - {
2841 - integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==
2842 - }
2843 - engines: { node: ">= 6" }
2844 -
2845 - commander@6.2.1:
2846 - resolution:
2847 - {
2848 - integrity: sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==
2849 - }
2850 - engines: { node: ">= 6" }
2851 -
2852 - commander@7.2.0:
2853 - resolution:
2854 - {
2855 - integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==
2856 - }
2857 - engines: { node: ">= 10" }
2858 -
2859 - comment-parser@1.4.1:
2860 - resolution:
2861 - {
2862 - integrity: sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==
2863 - }
2864 - engines: { node: ">= 12.0.0" }
2865 -
2866 - common-tags@1.8.2:
2867 - resolution:
2868 - {
2869 - integrity: sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==
2870 - }
2871 - engines: { node: ">=4.0.0" }
2872 -
2873 - compatx@0.1.8:
2874 - resolution:
2875 - {
2876 - integrity: sha512-jcbsEAR81Bt5s1qOFymBufmCbXCXbk0Ql+K5ouj6gCyx2yHlu6AgmGIi9HxfKixpUDO5bCFJUHQ5uM6ecbTebw==
2877 - }
2878 -
2879 - computeds@0.0.1:
2880 - resolution:
2881 - {
2882 - integrity: sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==
2883 - }
2884 -
2885 - concat-map@0.0.1:
2886 - resolution:
2887 - {
2888 - integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
2889 - }
2890 -
2891 - confbox@0.1.7:
2892 - resolution:
2893 - {
2894 - integrity: sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA==
2895 - }
2896 -
2897 - config-chain@1.1.13:
2898 - resolution:
2899 - {
2900 - integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==
2901 - }
2902 -
2903 - consola@3.2.3:
2904 - resolution:
2905 - {
2906 - integrity: sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==
2907 - }
2908 - engines: { node: ^14.18.0 || >=16.10.0 }
2909 -
2910 - content-disposition@0.5.4:
2911 - resolution:
2912 - {
2913 - integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==
2914 - }
2915 - engines: { node: ">= 0.6" }
2916 -
2917 - content-type@1.0.5:
2918 - resolution:
2919 - {
2920 - integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==
2921 - }
2922 - engines: { node: ">= 0.6" }
2923 -
2924 - convert-source-map@2.0.0:
2925 - resolution:
2926 - {
2927 - integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==
2928 - }
2929 -
2930 - cookies@0.9.1:
2931 - resolution:
2932 - {
2933 - integrity: sha512-TG2hpqe4ELx54QER/S3HQ9SRVnQnGBtKUz5bLQWtYAQ+o6GpgMs6sYUvaiJjVxb+UXwhRhAEP3m7LbsIZ77Hmw==
2934 - }
2935 - engines: { node: ">= 0.8" }
2936 -
2937 - copy-anything@3.0.5:
2938 - resolution:
2939 - {
2940 - integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==
2941 - }
2942 - engines: { node: ">=12.13" }
2943 -
2944 - core-js-compat@3.38.1:
2945 - resolution:
2946 - {
2947 - integrity: sha512-JRH6gfXxGmrzF3tZ57lFx97YARxCXPaMzPo6jELZhv88pBH5VXpQ+y0znKGlFnzuaihqhLbefxSJxWJMPtfDzw==
2948 - }
2949 -
2950 - core-util-is@1.0.2:
2951 - resolution:
2952 - {
2953 - integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==
2954 - }
2955 -
2956 - cross-spawn@7.0.3:
2957 - resolution:
2958 - {
2959 - integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
2960 - }
2961 - engines: { node: ">= 8" }
2962 -
2963 - crypto-js@4.2.0:
2964 - resolution:
2965 - {
2966 - integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==
2967 - }
2968 -
2969 - css-render@0.15.14:
2970 - resolution:
2971 - {
2972 - integrity: sha512-9nF4PdUle+5ta4W5SyZdLCCmFd37uVimSjg1evcTqKJCyvCEEj12WKzOSBNak6r4im4J4iYXKH1OWpUV5LBYFg==
2973 - }
2974 -
2975 - css-select@5.1.0:
2976 - resolution:
2977 - {
2978 - integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==
2979 - }
2980 -
2981 - css-tree@2.2.1:
2982 - resolution:
2983 - {
2984 - integrity: sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==
2985 - }
2986 - engines: { node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: ">=7.0.0" }
2987 -
2988 - css-tree@2.3.1:
2989 - resolution:
2990 - {
2991 - integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==
2992 - }
2993 - engines: { node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0 }
2994 -
2995 - css-what@6.1.0:
2996 - resolution:
2997 - {
2998 - integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==
2999 - }
3000 - engines: { node: ">= 6" }
3001 -
3002 - cssesc@3.0.0:
3003 - resolution:
3004 - {
3005 - integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==
3006 - }
3007 - engines: { node: ">=4" }
3008 - hasBin: true
3009 -
3010 - csso@5.0.5:
3011 - resolution:
3012 - {
3013 - integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==
3014 - }
3015 - engines: { node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: ">=7.0.0" }
3016 -
3017 - cssstyle@4.1.0:
3018 - resolution:
3019 - {
3020 - integrity: sha512-h66W1URKpBS5YMI/V8PyXvTMFT8SupJ1IzoIV8IeBC/ji8WVmrO8dGlTi+2dh6whmdk6BiKJLD/ZBkhWbcg6nA==
3021 - }
3022 - engines: { node: ">=18" }
3023 -
3024 - csstype@3.0.11:
3025 - resolution:
3026 - {
3027 - integrity: sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==
3028 - }
3029 -
3030 - csstype@3.1.3:
3031 - resolution:
3032 - {
3033 - integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==
3034 - }
3035 -
3036 - cypress@13.14.2:
3037 - resolution:
3038 - {
3039 - integrity: sha512-lsiQrN17vHMB2fnvxIrKLAjOr9bPwsNbPZNrWf99s4u+DVmCY6U+w7O3GGG9FvP4EUVYaDu+guWeNLiUzBrqvA==
3040 - }
3041 - engines: { node: ^16.0.0 || ^18.0.0 || >=20.0.0 }
3042 - hasBin: true
3043 -
3044 - dashdash@1.14.1:
3045 - resolution:
3046 - {
3047 - integrity: sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==
3048 - }
3049 - engines: { node: ">=0.10" }
3050 -
3051 - data-urls@5.0.0:
3052 - resolution:
3053 - {
3054 - integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==
3055 - }
3056 - engines: { node: ">=18" }
3057 -
3058 - date-fns-tz@2.0.1:
3059 - resolution:
3060 - {
3061 - integrity: sha512-fJCG3Pwx8HUoLhkepdsP7Z5RsucUi+ZBOxyM5d0ZZ6c4SdYustq0VMmOu6Wf7bli+yS/Jwp91TOCqn9jMcVrUA==
3062 - }
3063 - peerDependencies:
3064 - date-fns: 2.x
3065 -
3066 - date-fns@2.30.0:
3067 - resolution:
3068 - {
3069 - integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==
3070 - }
3071 - engines: { node: ">=0.11" }
3072 -
3073 - dayjs@1.11.13:
3074 - resolution:
3075 - {
3076 - integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==
3077 - }
3078 -
3079 - de-indent@1.0.2:
3080 - resolution:
3081 - {
3082 - integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==
3083 - }
3084 -
3085 - debounce@1.2.1:
3086 - resolution:
3087 - {
3088 - integrity: sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==
3089 - }
3090 -
3091 - debug@3.2.7:
3092 - resolution:
3093 - {
3094 - integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==
3095 - }
3096 - peerDependencies:
3097 - supports-color: "*"
3098 - peerDependenciesMeta:
3099 - supports-color:
3100 - optional: true
3101 -
3102 - debug@4.3.7:
3103 - resolution:
3104 - {
3105 - integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==
3106 - }
3107 - engines: { node: ">=6.0" }
3108 - peerDependencies:
3109 - supports-color: "*"
3110 - peerDependenciesMeta:
3111 - supports-color:
3112 - optional: true
3113 -
3114 - decimal.js@10.4.3:
3115 - resolution:
3116 - {
3117 - integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==
3118 - }
3119 -
3120 - decode-named-character-reference@1.0.2:
3121 - resolution:
3122 - {
3123 - integrity: sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==
3124 - }
3125 -
3126 - deep-eql@5.0.2:
3127 - resolution:
3128 - {
3129 - integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==
3130 - }
3131 - engines: { node: ">=6" }
3132 -
3133 - deep-equal@1.0.1:
3134 - resolution:
3135 - {
3136 - integrity: sha512-bHtC0iYvWhyaTzvV3CZgPeZQqCOBGyGsVV7v4eevpdkLHfiSrXUdBG+qAuSz4RI70sszvjQ1QSZ98An1yNwpSw==
3137 - }
3138 -
3139 - deep-is@0.1.4:
3140 - resolution:
3141 - {
3142 - integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==
3143 - }
3144 -
3145 - deep-pick-omit@1.2.0:
3146 - resolution:
3147 - {
3148 - integrity: sha512-2CGvfTM2c+IP/MhdRZMpaHhTc6zIlgz3tQXJ/VGAkc7mjMrjqSU28qiI63yEcy+fcYfd/K+NNJcGRzap4M4bqw==
3149 - }
3150 -
3151 - default-browser-id@5.0.0:
3152 - resolution:
3153 - {
3154 - integrity: sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==
3155 - }
3156 - engines: { node: ">=18" }
3157 -
3158 - default-browser@5.2.1:
3159 - resolution:
3160 - {
3161 - integrity: sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==
3162 - }
3163 - engines: { node: ">=18" }
3164 -
3165 - define-data-property@1.1.4:
3166 - resolution:
3167 - {
3168 - integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==
3169 - }
3170 - engines: { node: ">= 0.4" }
3171 -
3172 - define-lazy-prop@2.0.0:
3173 - resolution:
3174 - {
3175 - integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==
3176 - }
3177 - engines: { node: ">=8" }
3178 -
3179 - define-lazy-prop@3.0.0:
3180 - resolution:
3181 - {
3182 - integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==
3183 - }
3184 - engines: { node: ">=12" }
3185 -
3186 - defu@6.1.4:
3187 - resolution:
3188 - {
3189 - integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==
3190 - }
3191 -
3192 - delayed-stream@1.0.0:
3193 - resolution:
3194 - {
3195 - integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
3196 - }
3197 - engines: { node: ">=0.4.0" }
3198 -
3199 - delegates@1.0.0:
3200 - resolution:
3201 - {
3202 - integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==
3203 - }
3204 -
3205 - depd@1.1.2:
3206 - resolution:
3207 - {
3208 - integrity: sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==
3209 - }
3210 - engines: { node: ">= 0.6" }
3211 -
3212 - depd@2.0.0:
3213 - resolution:
3214 - {
3215 - integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==
3216 - }
3217 - engines: { node: ">= 0.8" }
3218 -
3219 - dequal@2.0.3:
3220 - resolution:
3221 - {
3222 - integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==
3223 - }
3224 - engines: { node: ">=6" }
3225 -
3226 - destr@2.0.3:
3227 - resolution:
3228 - {
3229 - integrity: sha512-2N3BOUU4gYMpTP24s5rF5iP7BDr7uNTCs4ozw3kf/eKfvWSIu93GEBi5m427YoyJoeOzQ5smuu4nNAPGb8idSQ==
3230 - }
3231 -
3232 - destroy@1.2.0:
3233 - resolution:
3234 - {
3235 - integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==
3236 - }
3237 - engines: { node: ">= 0.8", npm: 1.2.8000 || >= 1.4.16 }
3238 -
3239 - detect-touch-device@1.1.6:
3240 - resolution:
3241 - {
3242 - integrity: sha512-9DYLJE05EFGI9f8m/GyJtWjw7aMZMBQM2QVy6bb7zX8uC3iorOE3Erdrk3TWCj5FVOlHTfinU0bATTE9GWYebw==
3243 - }
3244 -
3245 - devlop@1.1.0:
3246 - resolution:
3247 - {
3248 - integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==
3249 - }
3250 -
3251 - didyoumean@1.2.2:
3252 - resolution:
3253 - {
3254 - integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==
3255 - }
3256 -
3257 - dir-glob@3.0.1:
3258 - resolution:
3259 - {
3260 - integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==
3261 - }
3262 - engines: { node: ">=8" }
3263 -
3264 - dlv@1.1.3:
3265 - resolution:
3266 - {
3267 - integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==
3268 - }
3269 -
3270 - doctrine@3.0.0:
3271 - resolution:
3272 - {
3273 - integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==
3274 - }
3275 - engines: { node: ">=6.0.0" }
3276 -
3277 - dom-serializer@2.0.0:
3278 - resolution:
3279 - {
3280 - integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==
3281 - }
3282 -
3283 - domelementtype@2.3.0:
3284 - resolution:
3285 - {
3286 - integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==
3287 - }
3288 -
3289 - domhandler@5.0.3:
3290 - resolution:
3291 - {
3292 - integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==
3293 - }
3294 - engines: { node: ">= 4" }
3295 -
3296 - domutils@3.1.0:
3297 - resolution:
3298 - {
3299 - integrity: sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==
3300 - }
3301 -
3302 - dotenv@16.4.5:
3303 - resolution:
3304 - {
3305 - integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==
3306 - }
3307 - engines: { node: ">=12" }
3308 -
3309 - duplexer@0.1.2:
3310 - resolution:
3311 - {
3312 - integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==
3313 - }
3314 -
3315 - eastasianwidth@0.2.0:
3316 - resolution:
3317 - {
3318 - integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==
3319 - }
3320 -
3321 - easy-bem@1.1.1:
3322 - resolution:
3323 - {
3324 - integrity: sha512-GJRqdiy2h+EXy6a8E6R+ubmqUM08BK0FWNq41k24fup6045biQ8NXxoXimiwegMQvFFV3t1emADdGNL1TlS61A==
3325 - }
3326 -
3327 - ecc-jsbn@0.1.2:
3328 - resolution:
3329 - {
3330 - integrity: sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==
3331 - }
3332 -
3333 - echarts@5.5.1:
3334 - resolution:
3335 - {
3336 - integrity: sha512-Fce8upazaAXUVUVsjgV6mBnGuqgO+JNDlcgF79Dksy4+wgGpQB2lmYoO4TSweFg/mZITdpGHomw/cNBJZj1icA==
3337 - }
3338 -
3339 - editorconfig@1.0.4:
3340 - resolution:
3341 - {
3342 - integrity: sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==
3343 - }
3344 - engines: { node: ">=14" }
3345 - hasBin: true
3346 -
3347 - ee-first@1.1.1:
3348 - resolution:
3349 - {
3350 - integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==
3351 - }
3352 -
3353 - electron-to-chromium@1.5.27:
3354 - resolution:
3355 - {
3356 - integrity: sha512-o37j1vZqCoEgBuWWXLHQgTN/KDKe7zwpiY5CPeq2RvUqOyJw9xnrULzZAEVQ5p4h+zjMk7hgtOoPdnLxr7m/jw==
3357 - }
3358 -
3359 - emoji-regex@8.0.0:
3360 - resolution:
3361 - {
3362 - integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
3363 - }
3364 -
3365 - emoji-regex@9.2.2:
3366 - resolution:
3367 - {
3368 - integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==
3369 - }
3370 -
3371 - encodeurl@1.0.2:
3372 - resolution:
3373 - {
3374 - integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==
3375 - }
3376 - engines: { node: ">= 0.8" }
3377 -
3378 - end-of-stream@1.4.4:
3379 - resolution:
3380 - {
3381 - integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==
3382 - }
3383 -
3384 - enhanced-resolve@5.17.1:
3385 - resolution:
3386 - {
3387 - integrity: sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==
3388 - }
3389 - engines: { node: ">=10.13.0" }
3390 -
3391 - enquirer@2.4.1:
3392 - resolution:
3393 - {
3394 - integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==
3395 - }
3396 - engines: { node: ">=8.6" }
3397 -
3398 - entities@4.5.0:
3399 - resolution:
3400 - {
3401 - integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==
3402 - }
3403 - engines: { node: ">=0.12" }
3404 -
3405 - error-ex@1.3.2:
3406 - resolution:
3407 - {
3408 - integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
3409 - }
3410 -
3411 - error-stack-parser-es@0.1.5:
3412 - resolution:
3413 - {
3414 - integrity: sha512-xHku1X40RO+fO8yJ8Wh2f2rZWVjqyhb1zgq1yZ8aZRQkv6OOKhKWRUaht3eSCUbAOBaKIgM+ykwFLE+QUxgGeg==
3415 - }
3416 -
3417 - es-define-property@1.0.0:
3418 - resolution:
3419 - {
3420 - integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==
3421 - }
3422 - engines: { node: ">= 0.4" }
3423 -
3424 - es-errors@1.3.0:
3425 - resolution:
3426 - {
3427 - integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==
3428 - }
3429 - engines: { node: ">= 0.4" }
3430 -
3431 - es-module-lexer@1.5.4:
3432 - resolution:
3433 - {
3434 - integrity: sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==
3435 - }
3436 -
3437 - esbuild@0.21.5:
3438 - resolution:
3439 - {
3440 - integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==
3441 - }
3442 - engines: { node: ">=12" }
3443 - hasBin: true
3444 -
3445 - esbuild@0.23.1:
3446 - resolution:
3447 - {
3448 - integrity: sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==
3449 - }
3450 - engines: { node: ">=18" }
3451 - hasBin: true
3452 -
3453 - escalade@3.2.0:
3454 - resolution:
3455 - {
3456 - integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==
3457 - }
3458 - engines: { node: ">=6" }
3459 -
3460 - escape-html@1.0.3:
3461 - resolution:
3462 - {
3463 - integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==
3464 - }
3465 -
3466 - escape-string-regexp@1.0.5:
3467 - resolution:
3468 - {
3469 - integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==
3470 - }
3471 - engines: { node: ">=0.8.0" }
3472 -
3473 - escape-string-regexp@4.0.0:
3474 - resolution:
3475 - {
3476 - integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
3477 - }
3478 - engines: { node: ">=10" }
3479 -
3480 - escape-string-regexp@5.0.0:
3481 - resolution:
3482 - {
3483 - integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==
3484 - }
3485 - engines: { node: ">=12" }
3486 -
3487 - eslint-compat-utils@0.5.1:
3488 - resolution:
3489 - {
3490 - integrity: sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==
3491 - }
3492 - engines: { node: ">=12" }
3493 - peerDependencies:
3494 - eslint: ^9.11.0
3495 -
3496 - eslint-config-flat-gitignore@0.3.0:
3497 - resolution:
3498 - {
3499 - integrity: sha512-0Ndxo4qGhcewjTzw52TK06Mc00aDtHNTdeeW2JfONgDcLkRO/n/BteMRzNVpLQYxdCC/dFEilfM9fjjpGIJ9Og==
3500 - }
3501 - peerDependencies:
3502 - eslint: ^9.11.0
3503 -
3504 - eslint-config-prettier@9.1.0:
3505 - resolution:
3506 - {
3507 - integrity: sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==
3508 - }
3509 - hasBin: true
3510 - peerDependencies:
3511 - eslint: ^9.11.0
3512 -
3513 - eslint-define-config@1.24.1:
3514 - resolution:
3515 - {
3516 - integrity: sha512-o36vBhPSWyIQlHoMqGhhcGmOOm2A2ccBVIdLTG/AWdm9YmjpsLpf+5ntf9LlHR6dduLREgxtGwvwPwSt7vnXJg==
3517 - }
3518 - engines: { node: ">=18.0.0", npm: ">=9.0.0", pnpm: ">= 8.6.0" }
3519 -
3520 - eslint-flat-config-utils@0.4.0:
3521 - resolution:
3522 - {
3523 - integrity: sha512-kfd5kQZC+BMO0YwTol6zxjKX1zAsk8JfSAopbKjKqmENTJcew+yBejuvccAg37cvOrN0Mh+DVbeyznuNWEjt4A==
3524 - }
3525 -
3526 - eslint-import-resolver-node@0.3.9:
3527 - resolution:
3528 - {
3529 - integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==
3530 - }
3531 -
3532 - eslint-merge-processors@0.1.0:
3533 - resolution:
3534 - {
3535 - integrity: sha512-IvRXXtEajLeyssvW4wJcZ2etxkR9mUf4zpNwgI+m/Uac9RfXHskuJefkHUcawVzePnd6xp24enp5jfgdHzjRdQ==
3536 - }
3537 - peerDependencies:
3538 - eslint: ^9.11.0
3539 -
3540 - eslint-plugin-antfu@2.7.0:
3541 - resolution:
3542 - {
3543 - integrity: sha512-gZM3jq3ouqaoHmUNszb1Zo2Ux7RckSvkGksjLWz9ipBYGSv1EwwBETN6AdiUXn+RpVHXTbEMPAPlXJazcA6+iA==
3544 - }
3545 - peerDependencies:
3546 - eslint: ^9.11.0
3547 -
3548 - eslint-plugin-command@0.2.5:
3549 - resolution:
3550 - {
3551 - integrity: sha512-mbCaSHD37MT8nVJnJUz2oeDfhz0wdOjfrqQVWkSpXuj3uU8m7/FK/niV2bL922af3M1js5x7Xcu3PwqWsrahfA==
3552 - }
3553 - peerDependencies:
3554 - eslint: ^9.11.0
3555 -
3556 - eslint-plugin-es-x@7.8.0:
3557 - resolution:
3558 - {
3559 - integrity: sha512-7Ds8+wAAoV3T+LAKeu39Y5BzXCrGKrcISfgKEqTS4BDN8SFEDQd0S43jiQ8vIa3wUKD07qitZdfzlenSi8/0qQ==
3560 - }
3561 - engines: { node: ^14.18.0 || >=16.0.0 }
3562 - peerDependencies:
3563 - eslint: ^9.11.0
3564 -
3565 - eslint-plugin-import-x@4.3.0:
3566 - resolution:
3567 - {
3568 - integrity: sha512-PxGzP7gAjF2DLeRnQtbYkkgZDg1intFyYr/XS1LgTYXUDrSXMHGkXx8++6i2eDv2jMs0jfeO6G6ykyeWxiFX7w==
3569 - }
3570 - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 }
3571 - peerDependencies:
3572 - eslint: ^9.11.0
3573 -
3574 - eslint-plugin-jsdoc@50.2.4:
3575 - resolution:
3576 - {
3577 - integrity: sha512-020jA+dXaXdb+TML3ZJBvpPmzwbNROjnYuTYi/g6A5QEmEjhptz4oPJDKkOGMIByNxsPpdTLzSU1HYVqebOX1w==
3578 - }
3579 - engines: { node: ">=18" }
3580 - peerDependencies:
3581 - eslint: ^9.11.0
3582 -
3583 - eslint-plugin-jsonc@2.16.0:
3584 - resolution:
3585 - {
3586 - integrity: sha512-Af/ZL5mgfb8FFNleH6KlO4/VdmDuTqmM+SPnWcdoWywTetv7kq+vQe99UyQb9XO3b0OWLVuTH7H0d/PXYCMdSg==
3587 - }
3588 - engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 }
3589 - peerDependencies:
3590 - eslint: ^9.11.0
3591 -
3592 - eslint-plugin-n@17.10.3:
3593 - resolution:
3594 - {
3595 - integrity: sha512-ySZBfKe49nQZWR1yFaA0v/GsH6Fgp8ah6XV0WDz6CN8WO0ek4McMzb7A2xnf4DCYV43frjCygvb9f/wx7UUxRw==
3596 - }
3597 - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 }
3598 - peerDependencies:
3599 - eslint: ^9.11.0
3600 -
3601 - eslint-plugin-no-only-tests@3.3.0:
3602 - resolution:
3603 - {
3604 - integrity: sha512-brcKcxGnISN2CcVhXJ/kEQlNa0MEfGRtwKtWA16SkqXHKitaKIMrfemJKLKX1YqDU5C/5JY3PvZXd5jEW04e0Q==
3605 - }
3606 - engines: { node: ">=5.0.0" }
3607 -
3608 - eslint-plugin-perfectionist@3.6.0:
3609 - resolution:
3610 - {
3611 - integrity: sha512-sA6ljy6dL/9cM5ruZ/pMqRVt0FQ4Z7mbQWlBYpyX9941LVfm65d2jl2k1ZbWD3ud9Wm+/NKgOvRnAatsKhMJbA==
3612 - }
3613 - engines: { node: ^18.0.0 || >=20.0.0 }
3614 - peerDependencies:
3615 - astro-eslint-parser: ^1.0.2
3616 - eslint: ^9.11.0
3617 - svelte: ">=3.0.0"
3618 - svelte-eslint-parser: ^0.41.1
3619 - vue-eslint-parser: ">=9.0.0"
3620 - peerDependenciesMeta:
3621 - astro-eslint-parser:
3622 - optional: true
3623 - svelte:
3624 - optional: true
3625 - svelte-eslint-parser:
3626 - optional: true
3627 - vue-eslint-parser:
3628 - optional: true
3629 -
3630 - eslint-plugin-prettier@5.2.1:
3631 - resolution:
3632 - {
3633 - integrity: sha512-gH3iR3g4JfF+yYPaJYkN7jEl9QbweL/YfkoRlNnuIEHEz1vHVlCmWOS+eGGiRuzHQXdJFCOTxRgvju9b8VUmrw==
3634 - }
3635 - engines: { node: ^14.18.0 || >=16.0.0 }
3636 - peerDependencies:
3637 - "@types/eslint": ">=8.0.0"
3638 - eslint: ^9.11.0
3639 - eslint-config-prettier: "*"
3640 - prettier: ">=3.0.0"
3641 - peerDependenciesMeta:
3642 - "@types/eslint":
3643 - optional: true
3644 - eslint-config-prettier:
3645 - optional: true
3646 -
3647 - eslint-plugin-regexp@2.6.0:
3648 - resolution:
3649 - {
3650 - integrity: sha512-FCL851+kislsTEQEMioAlpDuK5+E5vs0hi1bF8cFlPlHcEjeRhuAzEsGikXRreE+0j4WhW2uO54MqTjXtYOi3A==
3651 - }
3652 - engines: { node: ^18 || >=20 }
3653 - peerDependencies:
3654 - eslint: ^9.11.0
3655 -
3656 - eslint-plugin-toml@0.11.1:
3657 - resolution:
3658 - {
3659 - integrity: sha512-Y1WuMSzfZpeMIrmlP1nUh3kT8p96mThIq4NnHrYUhg10IKQgGfBZjAWnrg9fBqguiX4iFps/x/3Hb5TxBisfdw==
3660 - }
3661 - engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 }
3662 - peerDependencies:
3663 - eslint: ^9.11.0
3664 -
3665 - eslint-plugin-unicorn@55.0.0:
3666 - resolution:
3667 - {
3668 - integrity: sha512-n3AKiVpY2/uDcGrS3+QsYDkjPfaOrNrsfQxU9nt5nitd9KuvVXrfAvgCO9DYPSfap+Gqjw9EOrXIsBp5tlHZjA==
3669 - }
3670 - engines: { node: ">=18.18" }
3671 - peerDependencies:
3672 - eslint: ^9.11.0
3673 -
3674 - eslint-plugin-unused-imports@4.1.4:
3675 - resolution:
3676 - {
3677 - integrity: sha512-YptD6IzQjDardkl0POxnnRBhU1OEePMV0nd6siHaRBbd+lyh6NAhFEobiznKU7kTsSsDeSD62Pe7kAM1b7dAZQ==
3678 - }
3679 - peerDependencies:
3680 - "@typescript-eslint/eslint-plugin": ^8.6.0
3681 - eslint: ^9.11.0
3682 - peerDependenciesMeta:
3683 - "@typescript-eslint/eslint-plugin":
3684 - optional: true
3685 -
3686 - eslint-plugin-vue@9.28.0:
3687 - resolution:
3688 - {
3689 - integrity: sha512-ShrihdjIhOTxs+MfWun6oJWuk+g/LAhN+CiuOl/jjkG3l0F2AuK5NMTaWqyvBgkFtpYmyks6P4603mLmhNJW8g==
3690 - }
3691 - engines: { node: ^14.17.0 || >=16.0.0 }
3692 - peerDependencies:
3693 - eslint: ^9.11.0
3694 -
3695 - eslint-plugin-yml@1.14.0:
3696 - resolution:
3697 - {
3698 - integrity: sha512-ESUpgYPOcAYQO9czugcX5OqRvn/ydDVwGCPXY4YjPqc09rHaUVUA6IE6HLQys4rXk/S+qx3EwTd1wHCwam/OWQ==
3699 - }
3700 - engines: { node: ^14.17.0 || >=16.0.0 }
3701 - peerDependencies:
3702 - eslint: ^9.11.0
3703 -
3704 - eslint-processor-vue-blocks@0.1.2:
3705 - resolution:
3706 - {
3707 - integrity: sha512-PfpJ4uKHnqeL/fXUnzYkOax3aIenlwewXRX8jFinA1a2yCFnLgMuiH3xvCgvHHUlV2xJWQHbCTdiJWGwb3NqpQ==
3708 - }
3709 - peerDependencies:
3710 - "@vue/compiler-sfc": ^3.3.0
3711 - eslint: ^9.11.0
3712 -
3713 - eslint-scope@7.2.2:
3714 - resolution:
3715 - {
3716 - integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==
3717 - }
3718 - engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 }
3719 -
3720 - eslint-scope@8.0.2:
3721 - resolution:
3722 - {
3723 - integrity: sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA==
3724 - }
3725 - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 }
3726 -
3727 - eslint-visitor-keys@3.4.3:
3728 - resolution:
3729 - {
3730 - integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==
3731 - }
3732 - engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 }
3733 -
3734 - eslint-visitor-keys@4.0.0:
3735 - resolution:
3736 - {
3737 - integrity: sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==
3738 - }
3739 - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 }
3740 -
3741 - eslint@9.11.0:
3742 - resolution:
3743 - {
3744 - integrity: sha512-yVS6XODx+tMFMDFcG4+Hlh+qG7RM6cCJXtQhCKLSsr3XkLvWggHjCqjfh0XsPPnt1c56oaT6PMgW9XWQQjdHXA==
3745 - }
3746 - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 }
3747 - hasBin: true
3748 - peerDependencies:
3749 - jiti: "*"
3750 - peerDependenciesMeta:
3751 - jiti:
3752 - optional: true
3753 -
3754 - espree@10.1.0:
3755 - resolution:
3756 - {
3757 - integrity: sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==
3758 - }
3759 - engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 }
3760 -
3761 - espree@9.6.1:
3762 - resolution:
3763 - {
3764 - integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==
3765 - }
3766 - engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 }
3767 -
3768 - esquery@1.6.0:
3769 - resolution:
3770 - {
3771 - integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==
3772 - }
3773 - engines: { node: ">=0.10" }
3774 -
3775 - esrecurse@4.3.0:
3776 - resolution:
3777 - {
3778 - integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==
3779 - }
3780 - engines: { node: ">=4.0" }
3781 -
3782 - estraverse@5.3.0:
3783 - resolution:
3784 - {
3785 - integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==
3786 - }
3787 - engines: { node: ">=4.0" }
3788 -
3789 - estree-walker@2.0.2:
3790 - resolution:
3791 - {
3792 - integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==
3793 - }
3794 -
3795 - estree-walker@3.0.3:
3796 - resolution:
3797 - {
3798 - integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==
3799 - }
3800 -
3801 - esutils@2.0.3:
3802 - resolution:
3803 - {
3804 - integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
3805 - }
3806 - engines: { node: ">=0.10.0" }
3807 -
3808 - event-stream@3.3.4:
3809 - resolution:
3810 - {
3811 - integrity: sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g==
3812 - }
3813 -
3814 - eventemitter2@6.4.7:
3815 - resolution:
3816 - {
3817 - integrity: sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg==
3818 - }
3819 -
3820 - evtd@0.2.4:
3821 - resolution:
3822 - {
3823 - integrity: sha512-qaeGN5bx63s/AXgQo8gj6fBkxge+OoLddLniox5qtLAEY5HSnuSlISXVPxnSae1dWblvTh4/HoMIB+mbMsvZzw==
3824 - }
3825 -
3826 - execa@4.1.0:
3827 - resolution:
3828 - {
3829 - integrity: sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==
3830 - }
3831 - engines: { node: ">=10" }
3832 -
3833 - execa@5.1.1:
3834 - resolution:
3835 - {
3836 - integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==
3837 - }
3838 - engines: { node: ">=10" }
3839 -
3840 - execa@8.0.1:
3841 - resolution:
3842 - {
3843 - integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==
3844 - }
3845 - engines: { node: ">=16.17" }
3846 -
3847 - executable@4.1.1:
3848 - resolution:
3849 - {
3850 - integrity: sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==
3851 - }
3852 - engines: { node: ">=4" }
3853 -
3854 - extend@3.0.2:
3855 - resolution:
3856 - {
3857 - integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
3858 - }
3859 -
3860 - extract-zip@2.0.1:
3861 - resolution:
3862 - {
3863 - integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==
3864 - }
3865 - engines: { node: ">= 10.17.0" }
3866 - hasBin: true
3867 -
3868 - extsprintf@1.3.0:
3869 - resolution:
3870 - {
3871 - integrity: sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==
3872 - }
3873 - engines: { "0": node >=0.6.0 }
3874 -
3875 - fast-deep-equal@3.1.3:
3876 - resolution:
3877 - {
3878 - integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
3879 - }
3880 -
3881 - fast-diff@1.3.0:
3882 - resolution:
3883 - {
3884 - integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==
3885 - }
3886 -
3887 - fast-glob@3.3.2:
3888 - resolution:
3889 - {
3890 - integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==
3891 - }
3892 - engines: { node: ">=8.6.0" }
3893 -
3894 - fast-json-stable-stringify@2.1.0:
3895 - resolution:
3896 - {
3897 - integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
3898 - }
3899 -
3900 - fast-levenshtein@2.0.6:
3901 - resolution:
3902 - {
3903 - integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==
3904 - }
3905 -
3906 - fastq@1.17.1:
3907 - resolution:
3908 - {
3909 - integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==
3910 - }
3911 -
3912 - fd-slicer@1.1.0:
3913 - resolution:
3914 - {
3915 - integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==
3916 - }
3917 -
3918 - figures@3.2.0:
3919 - resolution:
3920 - {
3921 - integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==
3922 - }
3923 - engines: { node: ">=8" }
3924 -
3925 - file-entry-cache@8.0.0:
3926 - resolution:
3927 - {
3928 - integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==
3929 - }
3930 - engines: { node: ">=16.0.0" }
3931 -
3932 - file-saver@2.0.5:
3933 - resolution:
3934 - {
3935 - integrity: sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==
3936 - }
3937 -
3938 - fill-range@7.1.1:
3939 - resolution:
3940 - {
3941 - integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==
3942 - }
3943 - engines: { node: ">=8" }
3944 -
3945 - find-up-simple@1.0.0:
3946 - resolution:
3947 - {
3948 - integrity: sha512-q7Us7kcjj2VMePAa02hDAF6d+MzsdsAWEwYyOpwUtlerRBkOEPBCRZrAV4XfcSN8fHAgaD0hP7miwoay6DCprw==
3949 - }
3950 - engines: { node: ">=18" }
3951 -
3952 - find-up@4.1.0:
3953 - resolution:
3954 - {
3955 - integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==
3956 - }
3957 - engines: { node: ">=8" }
3958 -
3959 - find-up@5.0.0:
3960 - resolution:
3961 - {
3962 - integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==
3963 - }
3964 - engines: { node: ">=10" }
3965 -
3966 - flat-cache@4.0.1:
3967 - resolution:
3968 - {
3969 - integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==
3970 - }
3971 - engines: { node: ">=16" }
3972 -
3973 - flatted@3.3.1:
3974 - resolution:
3975 - {
3976 - integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==
3977 - }
3978 -
3979 - flourite@1.3.0:
3980 - resolution:
3981 - {
3982 - integrity: sha512-iuhWXuX07QwHMnJ1Irh4sD1bk/QFMHg8jVgWsjSAqoIqgIyJtRPnUNKyZAPXrw7pQkDvxb5AIz2KPihEoyVcqw==
3983 - }
3984 - engines: { node: ">=16" }
3985 -
3986 - follow-redirects@1.15.9:
3987 - resolution:
3988 - {
3989 - integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==
3990 - }
3991 - engines: { node: ">=4.0" }
3992 - peerDependencies:
3993 - debug: "*"
3994 - peerDependenciesMeta:
3995 - debug:
3996 - optional: true
3997 -
3998 - foreground-child@3.3.0:
3999 - resolution:
4000 - {
4001 - integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==
4002 - }
4003 - engines: { node: ">=14" }
4004 -
4005 - forever-agent@0.6.1:
4006 - resolution:
4007 - {
4008 - integrity: sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==
4009 - }
4010 -
4011 - form-data@4.0.0:
4012 - resolution:
4013 - {
4014 - integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==
4015 - }
4016 - engines: { node: ">= 6" }
4017 -
4018 - fraction.js@4.3.7:
4019 - resolution:
4020 - {
4021 - integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==
4022 - }
4023 -
4024 - fresh@0.5.2:
4025 - resolution:
4026 - {
4027 - integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==
4028 - }
4029 - engines: { node: ">= 0.6" }
4030 -
4031 - from@0.1.7:
4032 - resolution:
4033 - {
4034 - integrity: sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==
4035 - }
4036 -
4037 - fs-extra@11.2.0:
4038 - resolution:
4039 - {
4040 - integrity: sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==
4041 - }
4042 - engines: { node: ">=14.14" }
4043 -
4044 - fs-extra@9.1.0:
4045 - resolution:
4046 - {
4047 - integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==
4048 - }
4049 - engines: { node: ">=10" }
4050 -
4051 - fs-minipass@2.1.0:
4052 - resolution:
4053 - {
4054 - integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==
4055 - }
4056 - engines: { node: ">= 8" }
4057 -
4058 - fs.realpath@1.0.0:
4059 - resolution:
4060 - {
4061 - integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
4062 - }
4063 -
4064 - fsevents@2.3.3:
4065 - resolution:
4066 - {
4067 - integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
4068 - }
4069 - engines: { node: ^8.16.0 || ^10.6.0 || >=11.0.0 }
4070 - os: [darwin]
4071 -
4072 - function-bind@1.1.2:
4073 - resolution:
4074 - {
4075 - integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==
4076 - }
4077 -
4078 - gensync@1.0.0-beta.2:
4079 - resolution:
4080 - {
4081 - integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==
4082 - }
4083 - engines: { node: ">=6.9.0" }
4084 -
4085 - get-caller-file@2.0.5:
4086 - resolution:
4087 - {
4088 - integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
4089 - }
4090 - engines: { node: 6.* || 8.* || >= 10.* }
4091 -
4092 - get-func-name@2.0.2:
4093 - resolution:
4094 - {
4095 - integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==
4096 - }
4097 -
4098 - get-intrinsic@1.2.4:
4099 - resolution:
4100 - {
4101 - integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==
4102 - }
4103 - engines: { node: ">= 0.4" }
4104 -
4105 - get-stream@5.2.0:
4106 - resolution:
4107 - {
4108 - integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==
4109 - }
4110 - engines: { node: ">=8" }
4111 -
4112 - get-stream@6.0.1:
4113 - resolution:
4114 - {
4115 - integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==
4116 - }
4117 - engines: { node: ">=10" }
4118 -
4119 - get-stream@8.0.1:
4120 - resolution:
4121 - {
4122 - integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==
4123 - }
4124 - engines: { node: ">=16" }
4125 -
4126 - get-tsconfig@4.8.1:
4127 - resolution:
4128 - {
4129 - integrity: sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==
4130 - }
4131 -
4132 - getos@3.2.1:
4133 - resolution:
4134 - {
4135 - integrity: sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==
4136 - }
4137 -
4138 - getpass@0.1.7:
4139 - resolution:
4140 - {
4141 - integrity: sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==
4142 - }
4143 -
4144 - giget@1.2.3:
4145 - resolution:
4146 - {
4147 - integrity: sha512-8EHPljDvs7qKykr6uw8b+lqLiUc/vUg+KVTI0uND4s63TdsZM2Xus3mflvF0DDG9SiM4RlCkFGL+7aAjRmV7KA==
4148 - }
4149 - hasBin: true
4150 -
4151 - glob-parent@5.1.2:
4152 - resolution:
4153 - {
4154 - integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
4155 - }
4156 - engines: { node: ">= 6" }
4157 -
4158 - glob-parent@6.0.2:
4159 - resolution:
4160 - {
4161 - integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==
4162 - }
4163 - engines: { node: ">=10.13.0" }
4164 -
4165 - glob@10.4.5:
4166 - resolution:
4167 - {
4168 - integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==
4169 - }
4170 - hasBin: true
4171 -
4172 - glob@7.2.3:
4173 - resolution:
4174 - {
4175 - integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
4176 - }
4177 - deprecated: Glob versions prior to v9 are no longer supported
4178 -
4179 - global-dirs@3.0.1:
4180 - resolution:
4181 - {
4182 - integrity: sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==
4183 - }
4184 - engines: { node: ">=10" }
4185 -
4186 - globals@11.12.0:
4187 - resolution:
4188 - {
4189 - integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
4190 - }
4191 - engines: { node: ">=4" }
4192 -
4193 - globals@13.24.0:
4194 - resolution:
4195 - {
4196 - integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==
4197 - }
4198 - engines: { node: ">=8" }
4199 -
4200 - globals@14.0.0:
4201 - resolution:
4202 - {
4203 - integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==
4204 - }
4205 - engines: { node: ">=18" }
4206 -
4207 - globals@15.9.0:
4208 - resolution:
4209 - {
4210 - integrity: sha512-SmSKyLLKFbSr6rptvP8izbyxJL4ILwqO9Jg23UA0sDlGlu58V59D1//I3vlc0KJphVdUR7vMjHIplYnzBxorQA==
4211 - }
4212 - engines: { node: ">=18" }
4213 -
4214 - globby@11.1.0:
4215 - resolution:
4216 - {
4217 - integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==
4218 - }
4219 - engines: { node: ">=10" }
4220 -
4221 - globby@14.0.2:
4222 - resolution:
4223 - {
4224 - integrity: sha512-s3Fq41ZVh7vbbe2PN3nrW7yC7U7MFVc5c98/iTl9c2GawNMKx/J648KQRW6WKkuU8GIbbh2IXfIRQjOZnXcTnw==
4225 - }
4226 - engines: { node: ">=18" }
4227 -
4228 - gopd@1.0.1:
4229 - resolution:
4230 - {
4231 - integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==
4232 - }
4233 -
4234 - graceful-fs@4.2.11:
4235 - resolution:
4236 - {
4237 - integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
4238 - }
4239 -
4240 - graphemer@1.4.0:
4241 - resolution:
4242 - {
4243 - integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==
4244 - }
4245 -
4246 - has-flag@3.0.0:
4247 - resolution:
4248 - {
4249 - integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==
4250 - }
4251 - engines: { node: ">=4" }
4252 -
4253 - has-flag@4.0.0:
4254 - resolution:
4255 - {
4256 - integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
4257 - }
4258 - engines: { node: ">=8" }
4259 -
4260 - has-property-descriptors@1.0.2:
4261 - resolution:
4262 - {
4263 - integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==
4264 - }
4265 -
4266 - has-proto@1.0.3:
4267 - resolution:
4268 - {
4269 - integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==
4270 - }
4271 - engines: { node: ">= 0.4" }
4272 -
4273 - has-symbols@1.0.3:
4274 - resolution:
4275 - {
4276 - integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==
4277 - }
4278 - engines: { node: ">= 0.4" }
4279 -
4280 - has-tostringtag@1.0.2:
4281 - resolution:
4282 - {
4283 - integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==
4284 - }
4285 - engines: { node: ">= 0.4" }
4286 -
4287 - hash-sum@2.0.0:
4288 - resolution:
4289 - {
4290 - integrity: sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==
4291 - }
4292 -
4293 - hasown@2.0.2:
4294 - resolution:
4295 - {
4296 - integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==
4297 - }
4298 - engines: { node: ">= 0.4" }
4299 -
4300 - hast-util-to-html@9.0.3:
4301 - resolution:
4302 - {
4303 - integrity: sha512-M17uBDzMJ9RPCqLMO92gNNUDuBSq10a25SDBI08iCCxmorf4Yy6sYHK57n9WAbRAAaU+DuR4W6GN9K4DFZesYg==
4304 - }
4305 -
4306 - hast-util-whitespace@3.0.0:
4307 - resolution:
4308 - {
4309 - integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==
4310 - }
4311 -
4312 - he@1.2.0:
4313 - resolution:
4314 - {
4315 - integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
4316 - }
4317 - hasBin: true
4318 -
4319 - highlight-words-core@1.2.2:
4320 - resolution:
4321 - {
4322 - integrity: sha512-BXUKIkUuh6cmmxzi5OIbUJxrG8OAk2MqoL1DtO3Wo9D2faJg2ph5ntyuQeLqaHJmzER6H5tllCDA9ZnNe9BVGg==
4323 - }
4324 -
4325 - highlight.js@11.10.0:
4326 - resolution:
4327 - {
4328 - integrity: sha512-SYVnVFswQER+zu1laSya563s+F8VDGt7o35d4utbamowvUNLLMovFqwCLSocpZTz3MgaSRA1IbqRWZv97dtErQ==
4329 - }
4330 - engines: { node: ">=12.0.0" }
4331 -
4332 - hookable@5.5.3:
4333 - resolution:
4334 - {
4335 - integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==
4336 - }
4337 -
4338 - hosted-git-info@2.8.9:
4339 - resolution:
4340 - {
4341 - integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==
4342 - }
4343 -
4344 - html-encoding-sniffer@4.0.0:
4345 - resolution:
4346 - {
4347 - integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==
4348 - }
4349 - engines: { node: ">=18" }
4350 -
4351 - html-entities@2.5.2:
4352 - resolution:
4353 - {
4354 - integrity: sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==
4355 - }
4356 -
4357 - html-tags@3.3.1:
4358 - resolution:
4359 - {
4360 - integrity: sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==
4361 - }
4362 - engines: { node: ">=8" }
4363 -
4364 - html-void-elements@3.0.0:
4365 - resolution:
4366 - {
4367 - integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==
4368 - }
4369 -
4370 - http-assert@1.5.0:
4371 - resolution:
4372 - {
4373 - integrity: sha512-uPpH7OKX4H25hBmU6G1jWNaqJGpTXxey+YOUizJUAgu0AjLUeC8D73hTrhvDS5D+GJN1DN1+hhc/eF/wpxtp0w==
4374 - }
4375 - engines: { node: ">= 0.8" }
4376 -
4377 - http-errors@1.6.3:
4378 - resolution:
4379 - {
4380 - integrity: sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==
4381 - }
4382 - engines: { node: ">= 0.6" }
4383 -
4384 - http-errors@1.8.1:
4385 - resolution:
4386 - {
4387 - integrity: sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==
4388 - }
4389 - engines: { node: ">= 0.6" }
4390 -
4391 - http-errors@2.0.0:
4392 - resolution:
4393 - {
4394 - integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==
4395 - }
4396 - engines: { node: ">= 0.8" }
4397 -
4398 - http-proxy-agent@7.0.2:
4399 - resolution:
4400 - {
4401 - integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==
4402 - }
4403 - engines: { node: ">= 14" }
4404 -
4405 - http-signature@1.4.0:
4406 - resolution:
4407 - {
4408 - integrity: sha512-G5akfn7eKbpDN+8nPS/cb57YeA1jLTVxjpCj7tmm3QKPdyDy7T+qSC40e9ptydSWvkwjSXw1VbkpyEm39ukeAg==
4409 - }
4410 - engines: { node: ">=0.10" }
4411 -
4412 - https-proxy-agent@7.0.5:
4413 - resolution:
4414 - {
4415 - integrity: sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==
4416 - }
4417 - engines: { node: ">= 14" }
4418 -
4419 - human-signals@1.1.1:
4420 - resolution:
4421 - {
4422 - integrity: sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==
4423 - }
4424 - engines: { node: ">=8.12.0" }
4425 -
4426 - human-signals@2.1.0:
4427 - resolution:
4428 - {
4429 - integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==
4430 - }
4431 - engines: { node: ">=10.17.0" }
4432 -
4433 - human-signals@5.0.0:
4434 - resolution:
4435 - {
4436 - integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==
4437 - }
4438 - engines: { node: ">=16.17.0" }
4439 -
4440 - iconv-lite@0.6.3:
4441 - resolution:
4442 - {
4443 - integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==
4444 - }
4445 - engines: { node: ">=0.10.0" }
4446 -
4447 - ieee754@1.2.1:
4448 - resolution:
4449 - {
4450 - integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
4451 - }
4452 -
4453 - ignore@5.3.2:
4454 - resolution:
4455 - {
4456 - integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==
4457 - }
4458 - engines: { node: ">= 4" }
4459 -
4460 - immutable@4.3.7:
4461 - resolution:
4462 - {
4463 - integrity: sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==
4464 - }
4465 -
4466 - import-fresh@3.3.0:
4467 - resolution:
4468 - {
4469 - integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==
4470 - }
4471 - engines: { node: ">=6" }
4472 -
4473 - import-from-esm@1.3.4:
4474 - resolution:
4475 - {
4476 - integrity: sha512-7EyUlPFC0HOlBDpUFGfYstsU7XHxZJKAAMzCT8wZ0hMW7b+hG51LIKTDcsgtz8Pu6YC0HqRVbX+rVUtsGMUKvg==
4477 - }
4478 - engines: { node: ">=16.20" }
4479 -
4480 - import-meta-resolve@4.1.0:
4481 - resolution:
4482 - {
4483 - integrity: sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==
4484 - }
4485 -
4486 - importx@0.4.4:
4487 - resolution:
4488 - {
4489 - integrity: sha512-Lo1pukzAREqrBnnHC+tj+lreMTAvyxtkKsMxLY8H15M/bvLl54p3YuoTI70Tz7Il0AsgSlD7Lrk/FaApRcBL7w==
4490 - }
4491 -
4492 - imurmurhash@0.1.4:
4493 - resolution:
4494 - {
4495 - integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==
4496 - }
4497 - engines: { node: ">=0.8.19" }
4498 -
4499 - indent-string@4.0.0:
4500 - resolution:
4501 - {
4502 - integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==
4503 - }
4504 - engines: { node: ">=8" }
4505 -
4506 - inflight@1.0.6:
4507 - resolution:
4508 - {
4509 - integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==
4510 - }
4511 - deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
4512 -
4513 - inherits@2.0.3:
4514 - resolution:
4515 - {
4516 - integrity: sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==
4517 - }
4518 -
4519 - inherits@2.0.4:
4520 - resolution:
4521 - {
4522 - integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
4523 - }
4524 -
4525 - ini@1.3.8:
4526 - resolution:
4527 - {
4528 - integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==
4529 - }
4530 -
4531 - ini@2.0.0:
4532 - resolution:
4533 - {
4534 - integrity: sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==
4535 - }
4536 - engines: { node: ">=10" }
4537 -
4538 - is-arrayish@0.2.1:
4539 - resolution:
4540 - {
4541 - integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==
4542 - }
4543 -
4544 - is-binary-path@2.1.0:
4545 - resolution:
4546 - {
4547 - integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
4548 - }
4549 - engines: { node: ">=8" }
4550 -
4551 - is-builtin-module@3.2.1:
4552 - resolution:
4553 - {
4554 - integrity: sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==
4555 - }
4556 - engines: { node: ">=6" }
4557 -
4558 - is-ci@3.0.1:
4559 - resolution:
4560 - {
4561 - integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==
4562 - }
4563 - hasBin: true
4564 -
4565 - is-core-module@2.15.1:
4566 - resolution:
4567 - {
4568 - integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==
4569 - }
4570 - engines: { node: ">= 0.4" }
4571 -
4572 - is-docker@2.2.1:
4573 - resolution:
4574 - {
4575 - integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==
4576 - }
4577 - engines: { node: ">=8" }
4578 - hasBin: true
4579 -
4580 - is-docker@3.0.0:
4581 - resolution:
4582 - {
4583 - integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==
4584 - }
4585 - engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 }
4586 - hasBin: true
4587 -
4588 - is-extglob@2.1.1:
4589 - resolution:
4590 - {
4591 - integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
4592 - }
4593 - engines: { node: ">=0.10.0" }
4594 -
4595 - is-fullwidth-code-point@3.0.0:
4596 - resolution:
4597 - {
4598 - integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
4599 - }
4600 - engines: { node: ">=8" }
4601 -
4602 - is-generator-function@1.0.10:
4603 - resolution:
4604 - {
4605 - integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==
4606 - }
4607 - engines: { node: ">= 0.4" }
4608 -
4609 - is-glob@4.0.3:
4610 - resolution:
4611 - {
4612 - integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
4613 - }
4614 - engines: { node: ">=0.10.0" }
4615 -
4616 - is-inside-container@1.0.0:
4617 - resolution:
4618 - {
4619 - integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==
4620 - }
4621 - engines: { node: ">=14.16" }
4622 - hasBin: true
4623 -
4624 - is-installed-globally@0.4.0:
4625 - resolution:
4626 - {
4627 - integrity: sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==
4628 - }
4629 - engines: { node: ">=10" }
4630 -
4631 - is-number@7.0.0:
4632 - resolution:
4633 - {
4634 - integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
4635 - }
4636 - engines: { node: ">=0.12.0" }
4637 -
4638 - is-path-inside@3.0.3:
4639 - resolution:
4640 - {
4641 - integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==
4642 - }
4643 - engines: { node: ">=8" }
4644 -
4645 - is-potential-custom-element-name@1.0.1:
4646 - resolution:
4647 - {
4648 - integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==
4649 - }
4650 -
4651 - is-stream@2.0.1:
4652 - resolution:
4653 - {
4654 - integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==
4655 - }
4656 - engines: { node: ">=8" }
4657 -
4658 - is-stream@3.0.0:
4659 - resolution:
4660 - {
4661 - integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==
4662 - }
4663 - engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 }
4664 -
4665 - is-typedarray@1.0.0:
4666 - resolution:
4667 - {
4668 - integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==
4669 - }
4670 -
4671 - is-unicode-supported@0.1.0:
4672 - resolution:
4673 - {
4674 - integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==
4675 - }
4676 - engines: { node: ">=10" }
4677 -
4678 - is-what@4.1.16:
4679 - resolution:
4680 - {
4681 - integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==
4682 - }
4683 - engines: { node: ">=12.13" }
4684 -
4685 - is-wsl@2.2.0:
4686 - resolution:
4687 - {
4688 - integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==
4689 - }
4690 - engines: { node: ">=8" }
4691 -
4692 - is-wsl@3.1.0:
4693 - resolution:
4694 - {
4695 - integrity: sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==
4696 - }
4697 - engines: { node: ">=16" }
4698 -
4699 - isexe@2.0.0:
4700 - resolution:
4701 - {
4702 - integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==
4703 - }
4704 -
4705 - isstream@0.1.2:
4706 - resolution:
4707 - {
4708 - integrity: sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==
4709 - }
4710 -
4711 - jackspeak@3.4.3:
4712 - resolution:
4713 - {
4714 - integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==
4715 - }
4716 -
4717 - jiti@1.21.6:
4718 - resolution:
4719 - {
4720 - integrity: sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==
4721 - }
4722 - hasBin: true
4723 -
4724 - jiti@2.0.0-beta.3:
4725 - resolution:
4726 - {
4727 - integrity: sha512-pmfRbVRs/7khFrSAYnSiJ8C0D5GvzkE4Ey2pAvUcJsw1ly/p+7ut27jbJrjY79BpAJQJ4gXYFtK6d1Aub+9baQ==
4728 - }
4729 - hasBin: true
4730 -
4731 - joi@17.13.3:
4732 - resolution:
4733 - {
4734 - integrity: sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==
4735 - }
4736 -
4737 - jose@5.9.3:
4738 - resolution:
4739 - {
4740 - integrity: sha512-egLIoYSpcd+QUF+UHgobt5YzI2Pkw/H39ou9suW687MY6PmCwPmkNV/4TNjn1p2tX5xO3j0d0sq5hiYE24bSlg==
4741 - }
4742 -
4743 - js-beautify@1.15.1:
4744 - resolution:
4745 - {
4746 - integrity: sha512-ESjNzSlt/sWE8sciZH8kBF8BPlwXPwhR6pWKAw8bw4Bwj+iZcnKW6ONWUutJ7eObuBZQpiIb8S7OYspWrKt7rA==
4747 - }
4748 - engines: { node: ">=14" }
4749 - hasBin: true
4750 -
4751 - js-cookie@3.0.5:
4752 - resolution:

This file is too large to show in full.

frontend/src/App.vue
+4 -3
@@ -8,7 +8,7 @@
8 <transition :name="`router-${routerTransition}`" mode="out-in" appear>
9 <component
10 :is="RouterComponent"
11 - :key="forceRefresh"
11 + :key="(route?.name?.toString() || '') + forceRefresh"
12 :class="[`theme-${themeName}`, `layout-${layoutComponentName}`, themeName]"
13 />
14 </transition>
@@ -21,7 +21,7 @@
21 </template>
22
23 <script lang="ts" setup>
24 -import type { Layout, RouterTransition, ThemeName } from "@/types/theme.d"
24 +import type { Layout, RouterTransition, ThemeNameEnum } from "@/types/theme.d"
25 import Blank from "@/app-layouts/Blank/index.vue"
26 import Provider from "@/app-layouts/common/Provider.vue"
27 import SplashScreen from "@/app-layouts/common/SplashScreen.vue"
@@ -35,6 +35,7 @@ import { type RouteLocationNormalized, useRoute, useRouter } from "vue-router"
35 import "@/assets/scss/index.scss"
36
37 const router = useRouter()
38 +const route = useRoute()
39 const loading = ref(true)
40
41 const layoutComponents = {
@@ -52,7 +53,7 @@ const layout = computed<Layout>(() => themeStore.layout)
53 const layoutComponentName = computed<Layout>(() => forceLayout.value || layout.value)
54 const layoutComponent = computed<Component>(() => layoutComponents[layoutComponentName.value])
55 const routerTransition = computed<RouterTransition>(() => themeStore.routerTransition)
55 -const themeName = computed<ThemeName>(() => themeStore.themeName)
56 +const themeName = computed<ThemeNameEnum>(() => themeStore.themeName)
57 const isLogged = computed(() => authStore.isLogged)
58
59 function checkForcedLayout(route: RouteLocationNormalized) {
frontend/src/app-layouts/Blank/index.vue
+1 -1
@@ -14,7 +14,7 @@ import MainContainer from "./MainContainer.vue"
14 .layout {
15 width: 100vw;
16 height: 100vh;
17 - height: 100svh;
17 + height: 100dvh;
18 overflow: hidden;
19 perspective: 1000px;
20 }
frontend/src/app-layouts/HorizontalNav/HeaderBar.vue
+1 -1
@@ -19,7 +19,7 @@ const isDark = computed<boolean>(() => themeStore.isThemeDark)
19 </script>
20
21 <style lang="scss" scoped>
22 -@import "./variables";
22 +@import "variables";
23
24 .header-bar {
25 padding-left: var(--view-padding);
frontend/src/app-layouts/HorizontalNav/MainContainer.vue
+1 -1
@@ -38,7 +38,7 @@ onMounted(() => {
38 </script>
39
40 <style lang="scss" scoped>
41 -@import "./variables";
41 +@import "variables";
42
43 .main {
44 width: 100%;
frontend/src/app-layouts/HorizontalNav/Sidebar.vue
+3 -3
@@ -4,7 +4,7 @@
4 class="sidebar flex flex-col"
5 :class="{ collapsed: sidebarCollapsed, opened: !sidebarCollapsed }"
6 >
7 - <div ref="sidebar" class="sidebar-wrap grow flex flex-col">
7 + <div ref="sidebar" class="sidebar-wrap flex grow flex-col">
8 <SidebarHeader :logo-mini="sidebarClosed" />
9 <n-scrollbar>
10 <Navbar :collapsed="sidebarClosed" />
@@ -62,7 +62,7 @@ onMounted(() => {
62 </script>
63
64 <style lang="scss" scoped>
65 -@import "./variables";
65 +@import "variables";
66
67 .sidebar {
68 position: fixed;
@@ -74,7 +74,7 @@ onMounted(() => {
74 //padding-right: 1px;
75 width: var(--sidebar-open-width);
76 height: 100vh;
77 - height: 100svh;
77 + height: 100dvh;
78 overflow-x: hidden;
79 overflow-y: auto;
80 background-color: var(--bg-sidebar);
frontend/src/app-layouts/HorizontalNav/SidebarHeader.vue
+1 -1
@@ -54,7 +54,7 @@ const isLight = computed(() => themeStore.isThemeLight)
54 </script>
55
56 <style lang="scss" scoped>
57 -@import "./variables";
57 +@import "variables";
58
59 .sidebar-header {
60 height: var(--toolbar-height);
frontend/src/app-layouts/HorizontalNav/index.vue
+1 -1
@@ -19,7 +19,7 @@ import "./main.scss"
19 .layout {
20 width: 100vw;
21 height: 100vh;
22 - height: 100svh;
22 + height: 100dvh;
23 overflow: hidden;
24 perspective: 1000px;
25 }
frontend/src/app-layouts/HorizontalNav/main.scss
+5 -5
@@ -1,16 +1,16 @@
1 -@import "./variables";
1 +@use "variables";
2
3 .page-wrapped {
4 - @media (min-width: calc($sidebar-bp + 1px)) {
4 + @media (min-width: calc(variables.$sidebar-bp + 1px)) {
5 &.layout-HorizontalNav {
6 - height: calc(100svh - var(--toolbar-height) - var(--view-padding) - var(--header-bar-height));
6 + height: calc(100dvh - var(--toolbar-height) - var(--view-padding) - var(--header-bar-height));
7 }
8 }
9 }
10 .page-min-wrapped {
11 - @media (min-width: calc($sidebar-bp + 1px)) {
11 + @media (min-width: calc(variables.$sidebar-bp + 1px)) {
12 &.layout-HorizontalNav {
13 - min-height: calc(100svh - var(--toolbar-height) - var(--view-padding) - var(--header-bar-height));
13 + min-height: calc(100dvh - var(--toolbar-height) - var(--view-padding) - var(--header-bar-height));
14 }
15 }
16 }
frontend/src/app-layouts/common/Provider.vue
+8 -51
@@ -3,6 +3,8 @@
3 :rtl="rtlOptions"
4 :theme="theme"
5 :theme-overrides="themeOverrides"
6 + :locale="providerLocale"
7 + :date-locale="providerDateLocale"
8 preflight-style-disabled
9 inline-theme-disabled
10 >
@@ -22,11 +24,10 @@
24 </template>
25
26 <script lang="ts" setup>
25 -import type { ThemeName } from "@/types/theme.d"
27 import type { RtlItem } from "naive-ui/es/config-provider/src/internal-interface"
28 import GlobalListener from "@/app-layouts/common/GlobalListener.vue"
29 +import { useLocalesStore } from "@/stores/i18n"
30 import { useThemeStore } from "@/stores/theme"
29 -import { useWindowSize } from "@vueuse/core"
31 import {
32 type GlobalThemeOverrides,
33 NConfigProvider,
@@ -36,63 +37,19 @@ import {
37 NMessageProvider,
38 NNotificationProvider
39 } from "naive-ui"
39 -import { computed, onBeforeMount, watch } from "vue"
40 +import { computed, onBeforeMount } from "vue"
41 import { rtlStyles } from "./rtlProvider"
42
42 -const { width } = useWindowSize()
43 +const localesStore = useLocalesStore()
44 const themeStore = useThemeStore()
45 const theme = computed(() => themeStore.naiveTheme)
45 -const themeName = computed<ThemeName>(() => themeStore.themeName)
46 const themeOverrides = computed<GlobalThemeOverrides>(() => themeStore.themeOverrides)
47 -const style = computed(() => themeStore.style)
47 const isRTL = computed(() => themeStore.isRTL)
48 const rtlOptions = computed<RtlItem[] | undefined>(() => (isRTL.value ? rtlStyles : undefined))
50 -
51 -watch([isRTL, style], () => {
52 - setGlobalVars()
53 -})
54 -
55 -watch(themeName, (val, old) => {
56 - setThemeName(val, old)
57 -})
58 -
59 -watch(width, () => {
60 - themeStore.updateVars()
61 -})
62 -
63 -// This function allows you to utilize the values in the style object as variables within your CSS/SCSS code like: var(-–bg-color)
64 -function setGlobalVars() {
65 - if (document) {
66 - const html = document.children[0] as HTMLElement
67 - const body = document.getElementsByTagName("body")?.[0]
68 - if (isRTL.value && body) {
69 - body.classList.add("direction-rtl")
70 - body.classList.remove("direction-ltr")
71 - } else {
72 - body.classList.remove("direction-rtl")
73 - body.classList.add("direction-ltr")
74 - }
75 - // html.dir = isRTL.value ? "rtl" : "ltr"
76 - const { style: htmlStyle } = html
77 - for (const key in style.value) {
78 - htmlStyle.setProperty(`--${key}`, style.value[key])
79 - }
80 - }
81 -}
82 -
83 -function setThemeName(val: ThemeName, old?: ThemeName) {
84 - if (document) {
85 - const html = document.children[0] as HTMLElement
86 - if (old) {
87 - html.classList.remove(`theme-${old}`)
88 - }
89 - html.classList.add(`theme-${val}`)
90 - }
91 -}
49 +const providerLocale = computed(() => localesStore.naiveuiLocale)
50 +const providerDateLocale = computed(() => localesStore.naiveuiDateLocale)
51
52 onBeforeMount(() => {
94 - themeStore.updateVars()
95 - setGlobalVars()
96 - setThemeName(themeName.value)
53 + themeStore.initTheme()
54 })
55 </script>
frontend/src/app-layouts/common/Toolbar/LocaleSwitch.vue
+21 -11
@@ -6,25 +6,25 @@
6
7 <script lang="ts" setup>
8 import Icon from "@/components/common/Icon.vue"
9 -import { useStoreI18n } from "@/composables/useStoreI18n"
9 +import { useLocalesStore } from "@/stores/i18n"
10 import { NPopselect, type SelectOption } from "naive-ui"
11 import { computed, h, type VNodeChild } from "vue"
12
13 const MultiLanguageIcon = "ion:language-outline"
14
15 -const storeI18n = useStoreI18n()
15 +const localesStore = useLocalesStore()
16
17 -const { getAvailableLocales, getLocale, setLocale, t } = storeI18n
17 +const { setLocale, t } = localesStore
18
19 const list = computed(() =>
20 - getAvailableLocales().map(i => ({
20 + localesStore.availableLocales.map(i => ({
21 label: i,
22 value: i
23 }))
24 )
25
26 const currentLocale = computed({
27 - get: () => getLocale(),
27 + get: () => localesStore.locale,
28 set: v => setLocale(v)
29 })
30
@@ -43,12 +43,22 @@ function renderLabel(option: SelectOption): VNodeChild {
43 {},
44 {
45 default: () => {
46 - if (option.label === "it") return t("italian")
47 - if (option.label === "en") return t("english")
48 - if (option.label === "es") return t("spanish")
49 - if (option.label === "fr") return t("french")
50 - if (option.label === "de") return t("german")
51 - if (option.label === "jp") return t("japanese")
46 + switch (option.label) {
47 + case "it":
48 + return t("italian")
49 + case "en":
50 + return t("english")
51 + case "es":
52 + return t("spanish")
53 + case "fr":
54 + return t("french")
55 + case "de":
56 + return t("german")
57 + case "jp":
58 + return t("japanese")
59 + default:
60 + return option.label
61 + }
62 }
63 }
64 )
frontend/src/app-layouts/common/Toolbar/PinnedPages.vue
+33 -9
@@ -1,5 +1,5 @@
1 <template>
2 - <div class="flex pinned-pages items-center gap-5">
2 + <div class="pinned-pages flex items-center gap-5">
3 <TransitionGroup name="anim" tag="div" class="latest-list flex items-center gap-4 overflow-hidden">
4 <n-tag
5 v-for="page of latestSanitized"
@@ -20,16 +20,14 @@
20 </n-tag>
21 </TransitionGroup>
22
23 - <Transition name="anim" tag="div" class="flex items-center shortcuts-container">
23 + <Transition name="anim" tag="div" class="shortcuts-container flex items-center">
24 <div v-if="pinned.length" class="flex items-center">
25 - <n-popover :show-arrow="false" placement="bottom-end" trigger="hover" class="!p-1">
25 + <n-popover :show-arrow="false" placement="bottom" trigger="hover" class="!p-1">
26 <template #trigger>
27 - <n-button size="small" class="!h-8">
28 - <span class="flex items-center gap-2">
29 - Shortcuts
30 - <n-badge :value="pinned.length" :color="style['divider-030-color']" />
31 - </span>
32 - </n-button>
27 + <button class="shortcuts-btn flex items-center gap-2">
28 + <span>Shortcuts</span>
29 + <n-badge :value="pinned.length" :color="style['divider-030-color']" />
30 + </button>
31 </template>
32 <div class="flex flex-col">
33 <n-button
@@ -181,6 +179,23 @@ router.afterEach(route => {
179 }
180 }
181
182 + .shortcuts-btn {
183 + border-radius: 50px;
184 + background-color: var(--bg-color);
185 + gap: 10px;
186 + height: 32px;
187 + cursor: pointer;
188 + padding: 0px 8px;
189 + padding-left: 10px;
190 + outline: none;
191 + transition: all 0.2s var(--bezier-ease);
192 + border: none;
193 +
194 + &:hover {
195 + background-color: var(--bg-secondary-color);
196 + }
197 + }
198 +
199 .page-name {
200 cursor: pointer;
201 overflow: hidden;
@@ -230,4 +245,13 @@ router.afterEach(route => {
245 }
246 }
247 }
248 +
249 +.direction-rtl {
250 + .pinned-pages {
251 + .shortcuts-btn {
252 + padding-right: 10px;
253 + padding-left: 8px;
254 + }
255 + }
256 +}
257 </style>
frontend/src/app-layouts/common/Toolbar/Search.vue
+2 -2
@@ -1,12 +1,12 @@
1 <template>
2 - <div class="flex items-center search-btn" @click="openBox">
2 + <button class="search-btn flex items-center" @click="openBox">
3 <Icon :name="SearchIcon" :size="16" class="search-btn-icon" />
4 <span>Search</span>
5 <n-text code class="search-command">
6 <span :class="{ win: commandIcon === 'CTRL' }">{{ commandIcon }}</span>
7 K
8 </n-text>
9 - </div>
9 + </button>
10 </template>
11
12 <script lang="ts" setup>
frontend/src/app-layouts/common/Toolbar/index.vue
+1 -1
@@ -1,7 +1,7 @@
1 <template>
2 <header class="toolbar" :class="{ boxed }">
3 <div class="wrap flex items-center justify-end gap-3">
4 - <div class="logo-box flex items-center gap-2 cursor-pointer" @click="openNav()">
4 + <div class="logo-box flex cursor-pointer items-center gap-2" @click="openNav()">
5 <Logo mini />
6 <Icon :size="20" name="carbon:chevron-right" />
7 </div>
frontend/src/assets/scss/_functions.scss renamed
frontend/src/assets/scss/_mixin.scss renamed
+1 -1
@@ -1,5 +1,5 @@
1 @mixin page-full-view {
2 - height: calc(100svh - var(--toolbar-height));
2 + height: calc(100dvh - var(--toolbar-height));
3 position: relative;
4 top: calc(var(--view-padding) * -0.5);
5 left: calc(var(--view-padding) * -1);
frontend/src/assets/scss/common-animations.scss new
+45
@@ -0,0 +1,45 @@
1 +.item-appear {
2 + &.item-appear-bottom {
3 + animation: item-fade-bottom 0.3s forwards;
4 + opacity: 0;
5 + }
6 + &.item-appear-up {
7 + animation: item-fade-up 0.3s forwards;
8 + opacity: 0;
9 + }
10 +
11 + &.item-appear-005 {
12 + @for $i from 0 through 40 {
13 + &:nth-child(#{$i}) {
14 + animation-delay: $i * 0.05s;
15 + }
16 + }
17 + }
18 + &.item-appear-010 {
19 + @for $i from 0 through 40 {
20 + &:nth-child(#{$i}) {
21 + animation-delay: $i * 0.1s;
22 + }
23 + }
24 + }
25 +}
26 +
27 +@keyframes item-fade-bottom {
28 + from {
29 + opacity: 0;
30 + transform: translateY(10px);
31 + }
32 + to {
33 + opacity: 1;
34 + }
35 +}
36 +
37 +@keyframes item-fade-up {
38 + from {
39 + opacity: 0;
40 + transform: translateY(-10px);
41 + }
42 + to {
43 + opacity: 1;
44 + }
45 +}
frontend/src/assets/scss/common.scss
+73 -4
@@ -1,4 +1,4 @@
1 -@import "@/assets/scss/mixin.scss";
1 +@use "mixin";
2
3 .custom-label {
4 color: var(--label-color);
@@ -24,14 +24,14 @@
24 }
25
26 .page-wrapped {
27 - height: calc(100svh - var(--toolbar-height) - var(--view-padding) - (var(--view-padding) / 2));
27 + height: calc(100dvh - var(--toolbar-height) - var(--view-padding) - (var(--view-padding) / 2));
28 }
29 .page-min-wrapped {
30 - min-height: calc(100svh - var(--toolbar-height) - var(--view-padding) - (var(--view-padding) / 2));
30 + min-height: calc(100dvh - var(--toolbar-height) - var(--view-padding) - (var(--view-padding) / 2));
31 }
32 .page-mobile-full {
33 @media (max-width: 700px) {
34 - @include page-full-view;
34 + @include mixin.page-full-view;
35 }
36 }
37 .direction-rtl {
@@ -117,3 +117,72 @@
117 }
118 }
119 }
120 +
121 +.scrollbar-styled {
122 + /* Works on Firefox */
123 +
124 + scrollbar-width: thin;
125 + scrollbar-color: var(--hover-010-color) var(--bg-secondary-color);
126 +
127 + /* Works on Chrome, Edge, and Safari */
128 + &::-webkit-scrollbar,
129 + ::-webkit-scrollbar {
130 + width: 12px;
131 + }
132 +
133 + &::-webkit-scrollbar-track,
134 + ::-webkit-scrollbar-track {
135 + background: var(--bg-secondary-color);
136 + }
137 +
138 + &::-webkit-scrollbar-thumb,
139 + ::-webkit-scrollbar-thumb {
140 + background-color: var(--hover-010-color);
141 + border-radius: 20px;
142 + border: 2px solid var(--bg-secondary-color);
143 + }
144 +}
145 +
146 +.code-bg-transparent {
147 + code {
148 + background-color: transparent;
149 + }
150 +}
151 +
152 +.over-layer {
153 + background-color: rgba(var(--bg-body-rgb), 0.8);
154 + position: absolute;
155 + top: 0;
156 + left: 0;
157 + right: 0;
158 + bottom: 0;
159 + display: flex;
160 + align-items: center;
161 + justify-content: center;
162 + padding: 40px;
163 + text-align: center;
164 + font-size: 20px;
165 +
166 + .n-alert {
167 + width: 90vw;
168 + max-width: 500px;
169 + background-color: var(--bg-color);
170 + }
171 +}
172 +
173 +.grid-auto-fit-200 {
174 + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
175 + grid-auto-flow: row dense;
176 +}
177 +.grid-auto-fit-250 {
178 + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
179 + grid-auto-flow: row dense;
180 +}
181 +.grid-auto-fill-200 {
182 + grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
183 + grid-auto-flow: row dense;
184 +}
185 +.grid-auto-fill-250 {
186 + grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
187 + grid-auto-flow: row dense;
188 +}
frontend/src/assets/scss/fonts.scss
-16
@@ -1,19 +1,3 @@
1 @import "@fontsource/lexend/latin.css";
2 @import "@fontsource/public-sans/latin.css";
3 @import "@fontsource/jetbrains-mono/latin.css";
4 -
5 -// fontFamilyDisplay alternatives
6 -// @import "@fontsource/dm-serif-display/latin.css"; // DM Serif Display
7 -// @import "@fontsource/lexend/latin.css"; // Lexend
8 -// @import "@fontsource/eb-garamond/latin.css"; // EB Garamond
9 -// @import "@fontsource/jost/latin.css"; // Jost
10 -
11 -// fontFamily alternatives
12 -// @import "@fontsource/lexend/latin.css"; // Lexend
13 -// @import "@fontsource/public-sans/latin.css"; // Public Sans
14 -// @import "@fontsource/barlow/latin.css"; // Barlow
15 -// @import "@fontsource/jost/latin.css"; // Jost
16 -// @import "@fontsource/overpass/latin.css"; // Overpass
17 -
18 -// fontFamilyMono alternatives
19 -// @import "@fontsource/jetbrains-mono/latin.css"; // JetBrains Mono
frontend/src/assets/scss/helpers.scss deleted
-164
@@ -1,164 +0,0 @@
1 -.scrollbar-styled {
2 - /* Works on Firefox */
3 -
4 - scrollbar-width: thin;
5 - scrollbar-color: var(--hover-010-color) var(--bg-secondary-color);
6 -
7 - /* Works on Chrome, Edge, and Safari */
8 - &::-webkit-scrollbar,
9 - ::-webkit-scrollbar {
10 - width: 12px;
11 - }
12 -
13 - &::-webkit-scrollbar-track,
14 - ::-webkit-scrollbar-track {
15 - background: var(--bg-secondary-color);
16 - }
17 -
18 - &::-webkit-scrollbar-thumb,
19 - ::-webkit-scrollbar-thumb {
20 - background-color: var(--hover-010-color);
21 - border-radius: 20px;
22 - border: 2px solid var(--bg-secondary-color);
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;
35 - opacity: 0;
36 - }
37 - &.item-appear-up {
38 - animation: item-fade-up 0.3s forwards;
39 - opacity: 0;
40 - }
41 -
42 - &.item-appear-005 {
43 - @for $i from 0 through 40 {
44 - &:nth-child(#{$i}) {
45 - animation-delay: $i * 0.05s;
46 - }
47 - }
48 - }
49 - &.item-appear-010 {
50 - @for $i from 0 through 40 {
51 - &:nth-child(#{$i}) {
52 - animation-delay: $i * 0.1s;
53 - }
54 - }
55 - }
56 -}
57 -
58 -@keyframes item-fade-bottom {
59 - from {
60 - opacity: 0;
61 - transform: translateY(10px);
62 - }
63 - to {
64 - opacity: 1;
65 - }
66 -}
67 -
68 -@keyframes item-fade-up {
69 - from {
70 - opacity: 0;
71 - transform: translateY(-10px);
72 - }
73 - to {
74 - opacity: 1;
75 - }
76 -}
77 -
78 -.over-layer {
79 - background-color: rgba(var(--bg-body-rgb), 0.8);
80 - position: absolute;
81 - top: 0;
82 - left: 0;
83 - right: 0;
84 - bottom: 0;
85 - display: flex;
86 - align-items: center;
87 - justify-content: center;
88 - padding: 40px;
89 - text-align: center;
90 - font-size: 20px;
91 -
92 - .n-alert {
93 - width: 90vw;
94 - max-width: 500px;
95 - background-color: var(--bg-color);
96 - }
97 -}
98 -
99 -.grid-auto-fit-200 {
100 - grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
101 - grid-auto-flow: row dense;
102 -}
103 -.grid-auto-fit-250 {
104 - grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
105 - grid-auto-flow: row dense;
106 -}
107 -.grid-auto-fill-200 {
108 - grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
109 - grid-auto-flow: row dense;
110 -}
111 -.grid-auto-fill-250 {
112 - grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
113 - grid-auto-flow: row dense;
114 -}
115 -
116 -.bg-color {
117 - background-color: var(--bg-color);
118 -}
119 -
120 -.bg-secondary-color {
121 - background-color: var(--bg-secondary-color);
122 -}
123 -
124 -.border-radius {
125 - border-radius: var(--border-radius);
126 -}
127 -
128 -.font-mono {
129 - font-family: var(--font-family-mono);
130 -}
131 -.\!font-mono {
132 - font-family: var(--font-family-mono) !important;
133 -}
134 -
135 -.text-primary-color {
136 - color: var(--primary-color);
137 -}
138 -.hover\:text-primary-color {
139 - &:hover {
140 - color: var(--primary-color);
141 - }
142 -}
143 -
144 -.text-secondary-color {
145 - color: var(--fg-secondary-color);
146 -}
147 -.text-warning-color {
148 - color: var(--warning-color);
149 -}
150 -.text-error-color {
151 - color: var(--error-color);
152 -}
153 -.text-success-color {
154 - color: var(--success-color);
155 -}
156 -
157 -.border-primary-color {
158 - border-color: var(--primary-color) !important;
159 -}
160 -.hover\:border-primary-color {
161 - &:hover {
162 - border-color: var(--primary-color) !important;
163 - }
164 -}
frontend/src/assets/scss/index.scss
+8 -8
@@ -1,13 +1,13 @@
1 +@use "sass:meta";
2 @tailwind base;
3 @tailwind components;
4 @tailwind utilities;
5
5 -@import "_variables";
6 -@import "common";
7 -@import "helpers";
8 -@import "fonts";
9 -@import "router-animations";
10 -@import "naive-override";
6 +@include meta.load-css("fonts");
7 +@include meta.load-css("common");
8 +@include meta.load-css("common-animations");
9 +@include meta.load-css("router-animations");
10 +@include meta.load-css("overrides/naive-override");
11
12 html,
13 body {
@@ -26,9 +26,9 @@ body {
26 box-sizing: border-box;
27
28 width: 100vw;
29 - width: 100svw;
29 + width: 100dvw;
30 height: 100vh;
31 - height: 100svh;
31 + height: 100dvh;
32 overflow: hidden;
33
34 &:focus {
frontend/src/assets/scss/overrides/apexchart-override.scss renamed
frontend/src/assets/scss/overrides/naive-override.scss renamed
+18
@@ -99,6 +99,24 @@
99 }
100 }
101
102 +.n-spin-container .n-spin-body {
103 + inset: 0 !important;
104 + transform: none !important;
105 +
106 + .n-base-loading {
107 + position: sticky;
108 + top: 0;
109 + bottom: 0;
110 + height: min(450px, 100%);
111 +
112 + .n-base-loading__transition-wrapper {
113 + transform: translateY(-50%);
114 + height: fit-content;
115 + top: 50%;
116 + }
117 + }
118 +}
119 +
120 .direction-rtl {
121 .v-binder-follower-container {
122 direction: ltr;
frontend/src/assets/scss/overrides/vue-md-it-override.scss renamed
frontend/src/assets/scss/overrides/vuesjv-override.scss renamed
frontend/src/components/activeResponse/ActiveResponseActions.vue
+1 -1
@@ -1,5 +1,5 @@
1 <template>
2 - <div class="active-response-actions flex gap-2 justify-end">
2 + <div class="active-response-actions flex justify-end gap-2">
3 <n-button type="success" secondary :size :loading="loadingInvoke" @click="showInvokeForm = true">
4 <template #icon>
5 <Icon :name="InvokeIcon"></Icon>
frontend/src/components/activeResponse/ActiveResponseAgent.vue
+6 -11
@@ -1,7 +1,7 @@
1 <template>
2 <div class="active-response-list">
3 <n-spin :show="loadingActiveResponse">
4 - <div class="list">
4 + <div class="min-h-52">
5 <template v-if="activeResponseList.length">
6 <ActiveResponseItem
7 v-for="activeResponse of activeResponseList"
@@ -13,7 +13,7 @@
13 />
14 </template>
15 <template v-else>
16 - <n-empty v-if="!loadingActiveResponse" description="No items found" class="justify-center h-48" />
16 + <n-empty v-if="!loadingActiveResponse" description="No items found" class="h-48 justify-center" />
17 </template>
18 </div>
19 </n-spin>
@@ -48,6 +48,10 @@ function getAvailableIntegrations() {
48 } else {
49 message.warning(res.data?.message || "An error occurred. Please try again later.")
50 }
51 + // MOCK
52 + /*
53 + activeResponseList.value = supported_active_response
54 + */
55 })
56 .catch(err => {
57 message.error(err.response?.data?.message || "An error occurred. Please try again later.")
@@ -61,12 +65,3 @@ onBeforeMount(() => {
65 getAvailableIntegrations()
66 })
67 </script>
64 -
65 -<style lang="scss" scoped>
66 -.active-response-list {
67 - .list {
68 - container-type: inline-size;
69 - min-height: 200px;
70 - }
71 -}
72 -</style>
frontend/src/components/activeResponse/ActiveResponseDetails.vue
+1 -1
@@ -7,7 +7,7 @@
7 </Suspense>
8 </template>
9 <template v-else>
10 - <n-empty v-if="!loadingActiveResponse" description="No description found" class="justify-center h-48" />
10 + <n-empty v-if="!loadingActiveResponse" description="No description found" class="h-48 justify-center" />
11 </template>
12 </n-spin>
13 </div>
frontend/src/components/activeResponse/ActiveResponseInvokeForm.vue
+3 -3
@@ -1,9 +1,9 @@
1 <template>
2 - <div class="active-response-invoke-form flex flex-col justify-between grow">
2 + <div class="active-response-invoke-form flex grow flex-col justify-between">
3 <div class="form-box">
4 <n-spin v-model:show="loading">
5 <n-form ref="formRef" :label-width="80" :model="form" :rules="rules">
6 - <div class="grid gap-6 grid-auto-fit-200">
6 + <div class="grid-auto-fit-200 grid gap-6">
7 <n-form-item label="Action" path="action">
8 <n-select v-model:value="form.action" :options="invokeActionOptions" />
9 </n-form-item>
@@ -18,7 +18,7 @@
18 </p>
19 </n-spin>
20 </div>
21 - <div class="buttons-box flex justify-end gap-3">
21 + <div class="buttons-box flex justify-between gap-3">
22 <div class="flex gap-3">
23 <slot name="additionalActions"></slot>
24 </div>
frontend/src/components/activeResponse/ActiveResponseItem.vue
+22 -78
@@ -1,43 +1,30 @@
1 <template>
2 - <div class="active-response-item" :class="{ embedded }">
3 - <div class="px-4 py-3 flex flex-col gap-2">
4 - <div class="header-box flex justify-between items-center">
5 - <div class="title">
2 + <div>
3 + <CardEntity :embedded :clickable hoverable>
4 + <template #headerMain>
5 + <div class="text-default text-base">
6 {{ activeResponse.name }}
7 </div>
8 + </template>
9 +
10 + <template #headerExtra>
11 <n-button size="small" @click.stop="showDetails = true">
12 <template #icon>
13 <Icon :name="InfoIcon"></Icon>
14 </template>
15 </n-button>
13 - </div>
14 - <div class="main-box flex items-center gap-3">
15 - <div class="content flex flex-col gap-1 grow">
16 - <div class="description">
17 - {{ activeResponse.description }}
18 - </div>
19 - </div>
20 - <ActiveResponseActions
21 - v-if="!hideActions"
22 - class="actions-box"
23 - :agent-id="agentId"
24 - :active-response="activeResponse"
25 - @start-loading="loading = true"
26 - @stop-loading="loading = false"
27 - />
28 - </div>
29 - <div class="footer-box flex justify-between items-center gap-4">
30 - <ActiveResponseActions
31 - v-if="!hideActions"
32 - class="actions-box"
33 - :agent-id="agentId"
34 - :active-response="activeResponse"
35 - size="small"
36 - @start-loading="loading = true"
37 - @stop-loading="loading = false"
38 - />
39 - </div>
40 - </div>
16 + </template>
17 +
18 + <template #default>
19 + <p class="text-sm">
20 + {{ activeResponse.description }}
21 + </p>
22 + </template>
23 +
24 + <template v-if="!hideActions" #footerExtra>
25 + <ActiveResponseActions :agent-id="agentId" :active-response="activeResponse" size="small" />
26 + </template>
27 + </CardEntity>
28
29 <n-modal
30 v-model:show="showDetails"
@@ -54,6 +41,7 @@
41
42 <script setup lang="ts">
43 import type { SupportedActiveResponse } from "@/types/activeResponse.d"
44 +import CardEntity from "@/components/common/cards/CardEntity.vue"
45 import Icon from "@/components/common/Icon.vue"
46 import { NButton, NModal } from "naive-ui"
47 import { ref, toRefs } from "vue"
@@ -63,56 +51,12 @@ import ActiveResponseDetails from "./ActiveResponseDetails.vue"
51 const props = defineProps<{
52 activeResponse: SupportedActiveResponse
53 embedded?: boolean
54 + clickable?: boolean
55 hideActions?: boolean
56 agentId?: string | number
57 }>()
69 -const { activeResponse, embedded, agentId, hideActions } = toRefs(props)
58 +const { activeResponse, embedded, agentId, hideActions, clickable } = toRefs(props)
59
60 const InfoIcon = "carbon:information"
72 -const loading = ref(false)
61 const showDetails = ref(false)
62 </script>
75 -
76 -<style lang="scss" scoped>
77 -.active-response-item {
78 - border-radius: var(--border-radius);
79 - background-color: var(--bg-color);
80 - border: var(--border-small-050);
81 - transition: all 0.2s var(--bezier-ease);
82 -
83 - .main-box {
84 - .content {
85 - word-break: break-word;
86 -
87 - .description {
88 - color: var(--fg-secondary-color);
89 - font-size: 13px;
90 - }
91 - }
92 - }
93 -
94 - .footer-box {
95 - display: none;
96 - font-size: 13px;
97 - margin-top: 10px;
98 - }
99 -
100 - &.embedded {
101 - background-color: var(--bg-secondary-color);
102 - }
103 - &:hover {
104 - box-shadow: 0px 0px 0px 1px inset var(--primary-color);
105 - }
106 -
107 - @container (max-width: 650px) {
108 - .main-box {
109 - .actions-box {
110 - display: none;
111 - }
112 - }
113 - .footer-box {
114 - display: flex;
115 - }
116 - }
117 -}
118 -</style>
frontend/src/components/activeResponse/ActiveResponseWizard.vue
+32 -39
@@ -1,7 +1,7 @@
1 <template>
2 <n-spin :show="loading" class="active-response-wizard">
3 <div class="wrapper flex flex-col">
4 - <div class="grow flex flex-col">
4 + <div class="flex grow flex-col">
5 <n-scrollbar x-scrollable trigger="none">
6 <div class="p-7 pt-4">
7 <n-steps :current="current" size="small" :status="currentStatus">
@@ -12,48 +12,54 @@
12 </div>
13 </n-scrollbar>
14
15 - <div class="mt-4 grow flex flex-col">
15 + <div class="mt-4 flex grow flex-col">
16 <Transition :name="`slide-form-${slideFormDirection}`">
17 - <div v-if="current === 1" class="px-7 flex flex-col gap-2">
18 - <div class="os-button" @click="setOs('linux')">
19 - <Icon :size="18" :name="iconFromOs('linux')"></Icon>
20 - <span>LINUX</span>
21 - </div>
22 - <div class="os-button" @click="setOs('windows')">
23 - <Icon :size="18" :name="iconFromOs('windows')"></Icon>
24 - <span>WINDOWS</span>
25 - </div>
26 - <div class="os-button" @click="setOs('macos')">
27 - <Icon :size="18" :name="iconFromOs('macos')"></Icon>
28 - <span>MACOS</span>
29 - </div>
17 + <div v-if="current === 1" class="flex flex-col gap-2 px-7">
18 + <CardEntity embedded hoverable clickable @click.stop="setOs('linux')">
19 + <div class="flex items-center gap-3">
20 + <Icon :size="18" :name="iconFromOs('linux')"></Icon>
21 + <span>LINUX</span>
22 + </div>
23 + </CardEntity>
24 + <CardEntity embedded hoverable clickable @click.stop="setOs('windows')">
25 + <div class="flex items-center gap-3">
26 + <Icon :size="18" :name="iconFromOs('windows')"></Icon>
27 + <span>WINDOWS</span>
28 + </div>
29 + </CardEntity>
30 + <CardEntity embedded hoverable clickable @click.stop="setOs('macos')">
31 + <div class="flex items-center gap-3">
32 + <Icon :size="18" :name="iconFromOs('macos')"></Icon>
33 + <span>MACOS</span>
34 + </div>
35 + </CardEntity>
36 </div>
37
38 <div v-else-if="current === 2" class="px-7">
39 <n-spin :show="loadingActiveResponse">
34 - <div class="list">
40 + <div class="flex flex-col gap-2">
41 <template v-if="activeResponseFiltered.length">
42 <ActiveResponseItem
43 v-for="activeResponse of activeResponseFiltered"
44 :key="activeResponse.name"
45 :active-response="activeResponse"
46 embedded
47 + clickable
48 hide-actions
42 - class="mb-2 cursor-pointer"
43 - @click="setActiveResponse(activeResponse)"
49 + @click.stop="setActiveResponse(activeResponse)"
50 />
51 </template>
52 <template v-else>
53 <n-empty
54 v-if="!loadingActiveResponse"
55 description="No items found"
50 - class="justify-center h-48"
56 + class="h-48 justify-center"
57 />
58 </template>
59 </div>
60 </n-spin>
61 </div>
56 - <div v-else-if="current === 3" class="px-7 grow flex flex-col pb-7" style="min-height: 401px">
62 + <div v-else-if="current === 3" class="flex grow flex-col px-7 pb-7" style="min-height: 401px">
63 <ActiveResponseInvokeForm
64 v-if="selectedActiveResponse"
65 :active-response="selectedActiveResponse"
@@ -63,7 +69,7 @@
69 @stop-loading="loadingActiveResponseInvoke = false"
70 >
71 <template #additionalActions>
66 - <n-button :disabled="loadingActiveResponseInvoke" @click="prev()">
72 + <n-button :disabled="loadingActiveResponseInvoke" @click.stop="prev()">
73 <template #icon>
74 <Icon :name="ArrowLeftIcon"></Icon>
75 </template>
@@ -78,16 +84,16 @@
84
85 <div v-if="current !== 3" class="flex justify-between gap-4 p-7 pt-4">
86 <div class="flex gap-4">
81 - <slot name="additionalActions"></slot>
82 - </div>
83 - <div class="flex gap-4">
84 - <n-button v-if="isPrevStepEnabled" @click="prev()">
87 + <n-button v-if="isPrevStepEnabled" @click.stop="prev()">
88 <template #icon>
89 <Icon :name="ArrowLeftIcon"></Icon>
90 </template>
91 Prev
92 </n-button>
93 </div>
94 + <div class="flex gap-4">
95 + <slot name="additionalActions"></slot>
96 + </div>
97 </div>
98 </div>
99 </n-spin>
@@ -97,6 +103,7 @@
103 import type { SupportedActiveResponse } from "@/types/activeResponse.d"
104 import type { OsTypesLower } from "@/types/common.d"
105 import Api from "@/api"
106 +import CardEntity from "@/components/common/cards/CardEntity.vue"
107 import Icon from "@/components/common/Icon.vue"
108 import { iconFromOs } from "@/utils"
109 import { NButton, NEmpty, NScrollbar, NSpin, NStep, NSteps, type StepsProps, useMessage } from "naive-ui"
@@ -211,20 +218,6 @@ onMounted(() => {
218 min-height: 480px;
219 }
220
214 - .os-button {
215 - border-radius: var(--border-radius);
216 - background-color: var(--bg-secondary-color);
217 - border: var(--border-small-050);
218 - transition: all 0.2s var(--bezier-ease);
219 - cursor: pointer;
220 - line-height: 1;
221 - @apply p-4 flex gap-3 items-center;
222 -
223 - &:hover {
224 - box-shadow: 0px 0px 0px 1px inset var(--primary-color);
225 - }
226 - }
227 -
221 .slide-form-right-enter-active,
222 .slide-form-right-leave-active,
223 .slide-form-left-enter-active,
frontend/src/components/activeResponse/mock.ts new
+16
@@ -0,0 +1,16 @@
1 +import type { SupportedActiveResponse } from "@/types/activeResponse.d"
2 +
3 +export const supported_active_response: SupportedActiveResponse[] = [
4 + {
5 + name: "Response1",
6 + description: "This is the first supported active response."
7 + },
8 + {
9 + name: "Response2",
10 + description: "This is the second supported active response, used for monitoring."
11 + },
12 + {
13 + name: "Response3",
14 + description: "This active response is for error handling and notifications."
15 + }
16 +]
frontend/src/components/agents/AgentCard.vue
+59 -76
@@ -1,98 +1,94 @@
1 <template>
2 - <n-card
3 - class="agent-card py-3 px-4"
4 - :class="{ critical: agent.critical_asset, 'bg-secondary': bgSecondary }"
5 - content-style="padding:0"
6 - bordered
7 - >
8 - <n-spin :show="loading">
9 - <div class="wrapper">
10 - <div class="agent-header">
11 - <div class="title">
2 + <CardEntity class="agent-card" :loading :embedded :hoverable :clickable :class="{ critical: agent.critical_asset }">
3 + <div class="wrapper">
4 + <div class="agent-header">
5 + <div class="title">
6 + <n-tooltip>
7 + {{ `${isOnline ? "online" : "last seen"} - ${formatLastSeen}` }}
8 + <template #trigger>
9 + <div class="hostname" :class="{ online: isOnline }">
10 + {{ agent.hostname }}
11 + </div>
12 + </template>
13 + </n-tooltip>
14 + <div class="critical" :class="{ active: agent.critical_asset }">
15 <n-tooltip>
13 - {{ `${isOnline ? "online" : "last seen"} - ${formatLastSeen}` }}
16 + Toggle Critical Assets
17 <template #trigger>
15 - <div class="hostname" :class="{ online: isOnline }">
16 - {{ agent.hostname }}
17 - </div>
18 + <n-button
19 + quaternary
20 + circle
21 + :type="agent.critical_asset ? 'warning' : 'default'"
22 + @click.stop="toggleCritical(agent.agent_id, agent.critical_asset)"
23 + >
24 + <template #icon>
25 + <Icon :name="StarIcon"></Icon>
26 + </template>
27 + </n-button>
28 </template>
29 </n-tooltip>
20 - <div class="critical" :class="{ active: agent.critical_asset }">
21 - <n-tooltip>
22 - Toggle Critical Assets
23 - <template #trigger>
24 - <n-button
25 - quaternary
26 - circle
27 - :type="agent.critical_asset ? 'warning' : 'default'"
28 - @click.stop="toggleCritical(agent.agent_id, agent.critical_asset)"
29 - >
30 - <template #icon>
31 - <Icon :name="StarIcon"></Icon>
32 - </template>
33 - </n-button>
34 - </template>
35 - </n-tooltip>
36 - </div>
37 - <div v-show="agent.quarantined" class="quarantined">
38 - <n-tooltip>
39 - Quarantined
40 - <template #trigger>
41 - <Icon :name="QuarantinedIcon" :size="18"></Icon>
42 - </template>
43 - </n-tooltip>
44 - </div>
45 - </div>
46 - <div class="info">#{{ agent.agent_id }} / {{ agent.label }}</div>
47 - </div>
48 - <div class="agent-info">
49 - <div class="os" :title="agent.os">
50 - {{ agent.os }}
51 - </div>
52 - <div class="ip-address" :title="agent.ip_address">
53 - {{ agent.ip_address }}
30 </div>
55 - </div>
56 -
57 - <div v-if="showActions" class="agent-actions">
58 - <div class="box">
31 + <div v-show="agent.quarantined" class="quarantined">
32 <n-tooltip>
60 - Delete
33 + Quarantined
34 <template #trigger>
62 - <n-button quaternary circle type="error" @click.stop="handleDelete">
63 - <template #icon>
64 - <Icon :name="DeleteIcon"></Icon>
65 - </template>
66 - </n-button>
35 + <Icon :name="QuarantinedIcon" :size="18"></Icon>
36 </template>
37 </n-tooltip>
38 </div>
39 </div>
40 + <div class="info">#{{ agent.agent_id }} / {{ agent.label }}</div>
41 + </div>
42 + <div class="agent-info">
43 + <div class="os" :title="agent.os">
44 + {{ agent.os }}
45 + </div>
46 + <div class="ip-address" :title="agent.ip_address">
47 + {{ agent.ip_address }}
48 + </div>
49 + </div>
50 +
51 + <div v-if="showActions" class="agent-actions">
52 + <div class="box">
53 + <n-tooltip>
54 + Delete
55 + <template #trigger>
56 + <n-button quaternary circle type="error" @click.stop="handleDelete">
57 + <template #icon>
58 + <Icon :name="DeleteIcon"></Icon>
59 + </template>
60 + </n-button>
61 + </template>
62 + </n-tooltip>
63 + </div>
64 </div>
72 - </n-spin>
73 - </n-card>
65 + </div>
66 + </CardEntity>
67 </template>
68
69 <script setup lang="ts">
70 +import CardEntity from "@/components/common/cards/CardEntity.vue"
71 import Icon from "@/components/common/Icon.vue"
72 import { useSettingsStore } from "@/stores/settings"
73 import { type Agent, AgentStatus } from "@/types/agents.d"
74 import dayjs from "@/utils/dayjs"
81 -import { NButton, NCard, NSpin, NTooltip, useDialog, useMessage } from "naive-ui"
75 +import { NButton, NTooltip, useDialog, useMessage } from "naive-ui"
76 import { computed, ref, toRefs } from "vue"
77 import { handleDeleteAgent, toggleAgentCritical } from "./utils"
78
79 const props = defineProps<{
80 agent: Agent
81 showActions?: boolean
88 - bgSecondary?: boolean
82 + embedded?: boolean
83 + hoverable?: boolean
84 + clickable?: boolean
85 }>()
86
87 const emit = defineEmits<{
88 (e: "delete"): void
89 }>()
90
95 -const { agent, showActions, bgSecondary } = toRefs(props)
91 +const { agent, showActions, embedded, hoverable, clickable } = toRefs(props)
92
93 const QuarantinedIcon = "ph:seal-warning-light"
94 const StarIcon = "carbon:star"
@@ -149,15 +145,6 @@ function toggleCritical(agentId: string, criticalStatus: boolean) {
145 <style lang="scss" scoped>
146 .agent-card {
147 container-type: inline-size;
152 - overflow: hidden;
153 - max-width: 100%;
154 - box-sizing: border-box;
155 - cursor: pointer;
156 - transition: all 0.3s;
157 -
158 - &.bg-secondary {
159 - background-color: var(--bg-secondary-color);
160 - }
148
149 .wrapper {
150 display: flex;
@@ -242,10 +229,6 @@ function toggleCritical(agentId: string, criticalStatus: boolean) {
229 }
230 }
231
245 - &:hover {
246 - border-color: var(--primary-color);
247 - }
248 -
232 &.critical {
233 border-color: var(--warning-color);
234 }
frontend/src/components/agents/AgentCases.vue
+3 -3
@@ -1,14 +1,14 @@
1 <template>
2 <n-spin :show="loading">
3 <div class="header flex items-center justify-end gap-2">
4 - <div class="info grow flex gap-5">
4 + <div class="info flex grow gap-5">
5 <div class="box">
6 Total:
7 <code>{{ casesList.length }}</code>
8 </div>
9 </div>
10 </div>
11 - <div class="list flex flex-col gap-2 my-3">
11 + <div class="list my-3 flex flex-col gap-2">
12 <template v-if="casesList.length">
13 <SocCaseItem
14 v-for="item of casesList"
@@ -19,7 +19,7 @@
19 />
20 </template>
21 <template v-else>
22 - <n-empty v-if="!loading" description="No items found" class="justify-center h-48" />
22 + <n-empty v-if="!loading" description="No items found" class="h-48 justify-center" />
23 </template>
24 </div>
25 </n-spin>
frontend/src/components/agents/AgentToolbar.vue
+8 -4
@@ -1,6 +1,6 @@
1 <template>
2 <n-card class="agent-toolbar" content-style="padding:0">
3 - <div class="wrapper flex flex-col gap-6 py-3 px-4">
3 + <div class="wrapper flex flex-col gap-6 px-4 py-3">
4 <div class="flex flex-col gap-2">
5 <div class="agent-search flex gap-3">
6 <n-input v-model:value="textFilter" placeholder="Search for an agent" clearable>
@@ -23,7 +23,7 @@
23 <div v-if="agentsCritical?.length" class="agents-critical-list">
24 <div class="title">
25 Critical Assets
26 - <small class="text-secondary-color font-mono">({{ agentsCritical.length }})</small>
26 + <small class="text-secondary font-mono">({{ agentsCritical.length }})</small>
27 </div>
28 <div class="list">
29 <div
@@ -39,7 +39,7 @@
39 <div v-if="agentsOnline?.length" class="agents-online-list">
40 <div class="title">
41 Online Agents
42 - <small class="text-secondary-color font-mono">({{ agentsOnline.length }})</small>
42 + <small class="text-secondary font-mono">({{ agentsOnline.length }})</small>
43 </div>
44 <div class="list">
45 <div
@@ -115,7 +115,7 @@ const textFilter = computed<string>({
115 .list {
116 .item {
117 border: 2px solid transparent;
118 - @apply py-2 px-3;
118 + @apply px-3 py-2;
119 font-size: 14px;
120 font-weight: bold;
121 cursor: pointer;
@@ -124,6 +124,10 @@ const textFilter = computed<string>({
124 &:not(:last-child) {
125 @apply mb-2;
126 }
127 +
128 + &:hover {
129 + background-color: var(--bg-secondary-color);
130 + }
131 }
132 }
133
frontend/src/components/agents/AgentVelociraptorIdForm.vue
+1 -1
@@ -1,6 +1,6 @@
1 <template>
2 <div class="flex items-center gap-2">
3 - <code v-if="!editing" class="cursor-pointer text-primary-color" @click="edit()">
3 + <code v-if="!editing" class="text-primary cursor-pointer" @click="edit()">
4 {{ velociraptorId }}
5 <Icon :name="loading ? LoadingIcon : EditIcon" :size="13" class="relative top-0.5" />
6 </code>
frontend/src/components/agents/OverviewSection.vue
+5 -5
@@ -1,13 +1,13 @@
1 <template>
2 <div class="overview-section">
3 - <div class="property-group gap-2 grid grid-auto-fit-250">
4 - <KVCard v-for="item of propsSanitized" :key="item.key">
3 + <div class="property-group grid-auto-fit-250 grid gap-2">
4 + <CardKV v-for="item of propsSanitized" :key="item.key">
5 <template #key>
6 {{ item.key }}
7 </template>
8 <template #value>
9 <template v-if="item.key === 'customer_code' && item.val !== '-'">
10 - <code class="cursor-pointer text-primary-color" @click="gotoCustomer({ code: item.val })">
10 + <code class="text-primary cursor-pointer" @click="gotoCustomer({ code: item.val })">
11 {{ item.val }}
12 <Icon :name="LinkIcon" :size="13" class="relative top-0.5" />
13 </code>
@@ -19,15 +19,15 @@
19 {{ item.val ?? "-" }}
20 </template>
21 </template>
22 - </KVCard>
22 + </CardKV>
23 </div>
24 </div>
25 </template>
26
27 <script setup lang="ts">
28 import type { Agent } from "@/types/agents.d"
29 +import CardKV from "@/components/common/cards/CardKV.vue"
30 import Icon from "@/components/common/Icon.vue"
30 -import KVCard from "@/components/common/KVCard.vue"
31 import { useGoto } from "@/composables/useGoto"
32 import { useSettingsStore } from "@/stores/settings"
33 import { formatDate } from "@/utils"
frontend/src/components/agents/agentFlow/AgentFlowCollectList.vue
+7 -3
@@ -1,14 +1,14 @@
1 <template>
2 <n-spin :show="loading">
3 <div class="header flex items-center justify-end gap-2">
4 - <div class="info grow flex gap-5">
4 + <div class="info flex grow gap-5">
5 <div class="box">
6 Total:
7 <code>{{ collectList.length }}</code>
8 </div>
9 </div>
10 </div>
11 - <div class="list flex flex-col gap-4 my-3">
11 + <div class="list my-3 flex flex-col gap-4">
12 <template v-if="collectList.length">
13 <CollectItem
14 v-for="item of collectList"
@@ -19,7 +19,7 @@
19 />
20 </template>
21 <template v-else>
22 - <n-empty v-if="!loading" description="No items found" class="justify-center h-48" />
22 + <n-empty v-if="!loading" description="No items found" class="h-48 justify-center" />
23 </template>
24 </div>
25 </n-spin>
@@ -58,6 +58,10 @@ function getData() {
58 })
59 .catch(err => {
60 message.error(err.response?.data?.message || "An error occurred. Please try again later.")
61 + // MOCK
62 + /*
63 + collectList.value = collect_result
64 + */
65 })
66 .finally(() => {
67 loading.value = false
frontend/src/components/agents/agentFlow/AgentFlowItem.vue
+70 -149
@@ -1,72 +1,75 @@
1 <template>
2 - <div class="item flex flex-col gap-2 px-5 py-3" :class="{ embedded }">
3 - <div class="header-box flex justify-between">
4 - <div class="flex items-center gap-2">
5 - <div class="id flex items-center gap-2 cursor-pointer" @click="showDetails = true">
6 - <span>{{ flow.session_id }}</span>
7 - <Icon :name="InfoIcon" :size="16"></Icon>
2 + <div>
3 + <CardEntity :embedded hoverable clickable @click.stop="showDetails = true">
4 + <template #headerMain>
5 + <div class="flex items-center gap-2">
6 + {{ flow.session_id }}
7 </div>
9 - </div>
10 - <div class="time">
8 + </template>
9 + <template #headerExtra>
10 <n-popover overlap placement="top-end" class="max-h-64" scrollable to="body">
11 <template #trigger>
13 - <div class="flex items-center gap-2 cursor-help">
12 + <div class="flex cursor-help items-center gap-2">
13 <span>
14 {{ formatDate(flow.start_time, dFormats.datetimesec) }}
15 </span>
16 <Icon :name="TimeIcon" :size="16"></Icon>
17 </div>
18 </template>
20 - <div class="flex flex-col py-2 px-1">
19 + <div class="flex flex-col px-1 py-2">
20 <AgentFlowTimeline :flow="flow" />
21 </div>
22 </n-popover>
24 - </div>
25 - </div>
26 - <div class="main-box">
27 - <div class="content flex flex-wrap gap-2">
28 - <span v-for="artifact of flow.artifacts_with_results" :key="artifact" class="artifact-label">
29 - {{ artifact }}
30 - </span>
31 - </div>
32 - <div class="badges-box flex flex-wrap items-center gap-3 mt-4">
33 - <Badge type="splitted" color="primary">
34 - <template #label>State</template>
35 - <template #value>
36 - {{ flow.state || "-" }}
37 - </template>
38 - </Badge>
39 - <Badge type="splitted" color="primary">
40 - <template #label>Status</template>
41 - <template #value>
42 - {{ flow.status || "-" }}
43 - </template>
44 - </Badge>
45 - <Badge type="splitted" color="primary">
46 - <template #label>Exec. time</template>
47 - <template #value>
48 - {{ executionDuration }}
49 - </template>
50 - </Badge>
51 - <Badge :type="flow.dirty ? 'active' : 'muted'">
52 - <template #iconRight>
53 - <Icon :name="flow.dirty ? EnabledIcon : DisabledIcon" :size="14"></Icon>
54 - </template>
55 - <template #label>Dirty</template>
56 - </Badge>
57 - <Badge :type="flow.user_notified ? 'active' : 'muted'">
58 - <template #iconRight>
59 - <Icon :name="flow.user_notified ? EnabledIcon : DisabledIcon" :size="14"></Icon>
60 - </template>
61 - <template #label>User notified</template>
62 - </Badge>
63 - </div>
64 - </div>
65 - <div class="footer-box">
66 - <div class="time">
67 - {{ formatDate(flow.start_time, dFormats.datetimesec) }}
68 - </div>
69 - </div>
23 + </template>
24 + <template #default>
25 + <div class="flex flex-wrap gap-2">
26 + <Badge
27 + v-for="artifact of flow.artifacts_with_results"
28 + :key="artifact"
29 + color="primary"
30 + type="splitted"
31 + >
32 + <template #value>
33 + {{ artifact }}
34 + </template>
35 + </Badge>
36 + </div>
37 + </template>
38 + <template #mainExtra>
39 + <div class="flex flex-wrap items-center gap-3">
40 + <Badge type="splitted" color="primary">
41 + <template #label>State</template>
42 + <template #value>
43 + {{ flow.state || "-" }}
44 + </template>
45 + </Badge>
46 + <Badge type="splitted" color="primary">
47 + <template #label>Status</template>
48 + <template #value>
49 + {{ flow.status || "-" }}
50 + </template>
51 + </Badge>
52 + <Badge type="splitted" color="primary">
53 + <template #label>Exec. time</template>
54 + <template #value>
55 + {{ executionDuration }}
56 + </template>
57 + </Badge>
58 + <Badge :type="flow.dirty ? 'active' : 'muted'">
59 + <template #iconRight>
60 + <Icon :name="flow.dirty ? EnabledIcon : DisabledIcon" :size="14"></Icon>
61 + </template>
62 + <template #label>Dirty</template>
63 + </Badge>
64 + <Badge :type="flow.user_notified ? 'active' : 'muted'">
65 + <template #iconRight>
66 + <Icon :name="flow.user_notified ? EnabledIcon : DisabledIcon" :size="14"></Icon>
67 + </template>
68 + <template #label>User notified</template>
69 + </Badge>
70 + </div>
71 + </template>
72 + </CardEntity>
73
74 <n-modal
75 v-model:show="showDetails"
@@ -79,15 +82,15 @@
82 >
83 <n-tabs type="line" animated :tabs-padding="24">
84 <n-tab-pane name="Info" tab="Info" display-directive="show">
82 - <div v-if="properties" class="grid gap-2 grid-auto-fit-200 p-7 pt-4">
83 - <KVCard v-for="(value, key) of properties" :key="key">
85 + <div v-if="properties" class="grid-auto-fit-200 grid gap-2 p-7 pt-4">
86 + <CardKV v-for="(value, key) of properties" :key="key">
87 <template #key>
88 {{ key }}
89 </template>
90 <template #value>
91 {{ value === "" ? "-" : (value ?? "-") }}
92 </template>
90 - </KVCard>
93 + </CardKV>
94 </div>
95 </n-tab-pane>
96 <n-tab-pane name="Backtrace" tab="Backtrace" display-directive="show">
@@ -118,7 +121,7 @@
121 </li>
122 </ul>
123 </div>
121 - <n-empty v-else description="No items found" class="justify-center h-48" />
124 + <n-empty v-else description="No items found" class="h-48 justify-center" />
125 </n-tab-pane>
126 <n-tab-pane name="Uploaded files" tab="Uploaded files" display-directive="show:lazy">
127 <div v-if="flow.uploaded_files.length" class="p-7 pt-4">
@@ -128,7 +131,7 @@
131 </li>
132 </ul>
133 </div>
131 - <n-empty v-else description="No items found" class="justify-center h-48" />
134 + <n-empty v-else description="No items found" class="h-48 justify-center" />
135 </n-tab-pane>
136 <n-tab-pane name="Query stats" tab="Query stats" display-directive="show:lazy">
137 <div class="p-7 pt-4" style="container-type: inline-size">
@@ -138,10 +141,10 @@
141 :key="stat.first_active + stat.last_active"
142 :stat="stat"
143 embedded
141 - class="mb-2 item-appear item-appear-bottom item-appear-005"
144 + class="item-appear item-appear-bottom item-appear-005 mb-2"
145 />
146 </template>
144 - <n-empty v-else description="No items found" class="justify-center h-48" />
147 + <n-empty v-else description="No items found" class="h-48 justify-center" />
148 </div>
149 </n-tab-pane>
150 <n-tab-pane name="Request" tab="Request" display-directive="show:lazy">
@@ -154,8 +157,7 @@
157 </div>
158 </n-tab-pane>
159 <n-tab-pane name="Collect" tab="Collect" display-directive="show:lazy">
157 - <!-- TODO: replace max-height or similar with TailWind classes -->
158 - <n-scrollbar style="max-height: 430px" trigger="none">
160 + <n-scrollbar class="max-h-106" trigger="none">
161 <div class="px-7">
162 <AgentFlowCollectList :flow="flow" />
163 </div>
@@ -169,8 +171,9 @@
171 <script setup lang="ts">
172 import type { FlowResult } from "@/types/flow.d"
173 import Badge from "@/components/common/Badge.vue"
174 +import CardEntity from "@/components/common/cards/CardEntity.vue"
175 +import CardKV from "@/components/common/cards/CardKV.vue"
176 import Icon from "@/components/common/Icon.vue"
173 -import KVCard from "@/components/common/KVCard.vue"
177 import { useSettingsStore } from "@/stores/settings"
178 import { formatDate } from "@/utils"
179 import dayjs from "@/utils/dayjs"
@@ -178,7 +181,7 @@ import _pick from "lodash/pick"
181 import { NEmpty, NInput, NModal, NPopover, NScrollbar, NTabPane, NTabs } from "naive-ui"
182 import { computed, defineAsyncComponent, ref } from "vue"
183 import { SimpleJsonViewer } from "vue-sjv"
181 -import "@/assets/scss/vuesjv-override.scss"
184 +import "@/assets/scss/overrides/vuesjv-override.scss"
185
186 const { flow, embedded } = defineProps<{ flow: FlowResult; embedded?: boolean }>()
187 const AgentFlowTimeline = defineAsyncComponent(() => import("./AgentFlowTimeline.vue"))
@@ -186,7 +189,6 @@ const AgentFlowQueryStat = defineAsyncComponent(() => import("./AgentFlowQuerySt
189 const AgentFlowCollectList = defineAsyncComponent(() => import("./AgentFlowCollectList.vue"))
190
191 const TimeIcon = "carbon:time"
189 -const InfoIcon = "carbon:information"
192 const DisabledIcon = "carbon:subtract"
193 const EnabledIcon = "ri:check-line"
194
@@ -211,84 +213,3 @@ const properties = computed(() => {
213 ])
214 })
215 </script>
214 -
215 -<style lang="scss" scoped>
216 -.item {
217 - border-radius: var(--border-radius);
218 - background-color: var(--bg-color);
219 - transition: all 0.2s var(--bezier-ease);
220 - border: var(--border-small-050);
221 -
222 - .header-box {
223 - font-family: var(--font-family-mono);
224 - font-size: 13px;
225 - .id {
226 - word-break: break-word;
227 - color: var(--fg-secondary-color);
228 - line-height: 1.2;
229 -
230 - &:hover {
231 - color: var(--primary-color);
232 - }
233 - }
234 - .time {
235 - color: var(--fg-secondary-color);
236 -
237 - &:hover {
238 - color: var(--primary-color);
239 - }
240 - }
241 - }
242 -
243 - .main-box {
244 - .content {
245 - word-break: break-word;
246 -
247 - .artifact-label {
248 - background-color: var(--bg-secondary-color);
249 - padding: 3px 8px;
250 - border-radius: var(--border-radius);
251 - }
252 - }
253 - }
254 - .footer-box {
255 - font-family: var(--font-family-mono);
256 - display: none;
257 - text-align: right;
258 - font-size: 13px;
259 - margin-top: 10px;
260 -
261 - .time {
262 - color: var(--fg-secondary-color);
263 - width: 100%;
264 - }
265 - }
266 -
267 - &:hover {
268 - box-shadow: 0px 0px 0px 1px inset var(--primary-color);
269 - }
270 -
271 - &.embedded {
272 - background-color: var(--bg-secondary-color);
273 -
274 - .main-box {
275 - .content {
276 - .artifact-label {
277 - background-color: var(--bg-color);
278 - }
279 - }
280 - }
281 - }
282 -
283 - @container (max-width: 550px) {
284 - .header-box {
285 - .time {
286 - display: none;
287 - }
288 - }
289 - .footer-box {
290 - display: flex;
291 - }
292 - }
293 -}
294 -</style>
frontend/src/components/agents/agentFlow/AgentFlowList.vue
+8 -10
@@ -1,14 +1,14 @@
1 <template>
2 <n-spin :show="loading">
3 <div class="header flex items-center justify-end gap-2">
4 - <div class="info grow flex gap-5">
4 + <div class="info flex grow gap-5">
5 <div class="box">
6 Total:
7 <code>{{ flowList.length }}</code>
8 </div>
9 </div>
10 </div>
11 - <div class="list flex flex-col gap-2 my-3">
11 + <div class="my-3 flex min-h-52 flex-col gap-2">
12 <template v-if="flowList.length">
13 <AgentFlowItem
14 v-for="item of flowList"
@@ -19,7 +19,7 @@
19 />
20 </template>
21 <template v-else>
22 - <n-empty v-if="!loading" description="No items found" class="justify-center h-48" />
22 + <n-empty v-if="!loading" description="No items found" class="h-48 justify-center" />
23 </template>
24 </div>
25 </n-spin>
@@ -64,6 +64,11 @@ function getData() {
64 })
65 .catch(err => {
66 message.error(err.response?.data?.message || "An error occurred. Please try again later.")
67 +
68 + // MOCK
69 + /*
70 + flowList.value = flow_results
71 + */
72 })
73 .finally(() => {
74 loading.value = false
@@ -74,10 +79,3 @@ onBeforeMount(() => {
79 getData()
80 })
81 </script>
77 -
78 -<style lang="scss" scoped>
79 -.list {
80 - container-type: inline-size;
81 - min-height: 200px;
82 -}
83 -</style>
frontend/src/components/agents/agentFlow/AgentFlowQueryStat.vue
+48 -126
@@ -1,58 +1,46 @@
1 <template>
2 - <div class="item flex flex-col gap-2 px-5 py-3" :class="{ embedded }">
3 - <div class="header-box flex justify-between items-center gap-3">
4 - <div class="id grow flex flex-wrap gap-2">
5 - <span>
6 - {{ formatDate(stat.first_active, dFormats.datetimesecmill) }}
7 - </span>
8 - <span>•</span>
9 - <span>
10 - {{ formatDate(stat.last_active, dFormats.datetimesecmill) }}
11 - </span>
12 - </div>
13 - <div class="actions whitespace-nowrap">
14 - <n-button size="small" @click.stop="showDetails = true">
15 - <template #icon>
16 - <Icon :name="InfoIcon"></Icon>
17 - </template>
18 - Details
19 - </n-button>
20 - </div>
21 - </div>
22 - <div class="main-box flex flex-col gap-2 mt-2">
23 - <div class="content flex flex-wrap gap-2">
24 - <span v-for="artifact of stat.names_with_response" :key="artifact" class="artifact-label">
25 - {{ artifact }}
26 - </span>
27 - </div>
28 - <div v-if="stat.error_message" class="error-message">
29 - {{ stat.error_message }}
30 - </div>
31 - <div class="badges-box flex flex-wrap items-center gap-3 mt-1">
32 - <Badge type="splitted" color="primary">
33 - <template #label>Status</template>
34 - <template #value>
35 - {{ stat.status || "-" }}
36 - </template>
37 - </Badge>
38 - <Badge type="splitted" color="primary">
39 - <template #label>Duration</template>
40 - <template #value>
41 - {{ duration }}
42 - </template>
43 - </Badge>
44 - </div>
45 - </div>
46 - <div class="footer-box">
47 - <div class="actions whitespace-nowrap">
48 - <n-button size="small" @click.stop="showDetails = true">
49 - <template #icon>
50 - <Icon :name="InfoIcon"></Icon>
51 - </template>
52 - Details
53 - </n-button>
54 - </div>
55 - </div>
2 + <div>
3 + <CardEntity :embedded hoverable clickable @click.stop="showDetails = true">
4 + <template #headerMain>
5 + <div class="flex grow flex-wrap gap-2">
6 + <span>
7 + {{ formatDate(stat.first_active, dFormats.datetimesecmill) }}
8 + </span>
9 + <span>•</span>
10 + <span>
11 + {{ formatDate(stat.last_active, dFormats.datetimesecmill) }}
12 + </span>
13 + </div>
14 + </template>
15 + <template #default>
16 + <div class="flex flex-wrap gap-2">
17 + <Badge v-for="artifact of stat.names_with_response" :key="artifact" color="primary" type="splitted">
18 + <template #value>
19 + {{ artifact }}
20 + </template>
21 + </Badge>
22 + </div>
23 + <div v-if="stat.error_message" class="text-error mt-3">
24 + {{ stat.error_message }}
25 + </div>
26 + </template>
27 + <template #mainExtra>
28 + <div class="flex flex-wrap items-center gap-3">
29 + <Badge type="splitted" color="primary">
30 + <template #label>Status</template>
31 + <template #value>
32 + {{ stat.status || "-" }}
33 + </template>
34 + </Badge>
35 + <Badge type="splitted" color="primary">
36 + <template #label>Duration</template>
37 + <template #value>
38 + {{ duration }}
39 + </template>
40 + </Badge>
41 + </div>
42 + </template>
43 + </CardEntity>
44
45 <n-modal
46 v-model:show="showDetails"
@@ -65,15 +53,15 @@
53 >
54 <n-tabs type="line" animated :tabs-padding="24">
55 <n-tab-pane name="Info" tab="Info" display-directive="show">
68 - <div v-if="properties" class="grid gap-2 grid-auto-fit-200 p-7 pt-4">
69 - <KVCard v-for="(value, key) of properties" :key="key">
56 + <div v-if="properties" class="grid-auto-fit-200 grid gap-2 p-7 pt-4">
57 + <CardKV v-for="(value, key) of properties" :key="key">
58 <template #key>
59 {{ key }}
60 </template>
61 <template #value>
62 {{ value === "" ? "-" : (value ?? "-") }}
63 </template>
76 - </KVCard>
64 + </CardKV>
65 </div>
66 </n-tab-pane>
67 <n-tab-pane name="Backtrace" tab="Backtrace" display-directive="show">
@@ -99,19 +87,17 @@
87 <script setup lang="ts">
88 import type { FlowQueryStat } from "@/types/flow.d"
89 import Badge from "@/components/common/Badge.vue"
102 -import Icon from "@/components/common/Icon.vue"
103 -import KVCard from "@/components/common/KVCard.vue"
90 +import CardEntity from "@/components/common/cards/CardEntity.vue"
91 +import CardKV from "@/components/common/cards/CardKV.vue"
92 import { useSettingsStore } from "@/stores/settings"
93 import { formatDate } from "@/utils"
94 import dayjs from "@/utils/dayjs"
95 import _pick from "lodash/pick"
108 -import { NButton, NInput, NModal, NTabPane, NTabs } from "naive-ui"
96 +import { NInput, NModal, NTabPane, NTabs } from "naive-ui"
97 import { computed, ref } from "vue"
98
99 const { stat, embedded } = defineProps<{ stat: FlowQueryStat; embedded?: boolean }>()
100
113 -const InfoIcon = "carbon:information"
114 -
101 const showDetails = ref(false)
102 const dFormats = useSettingsStore().dateFormat
103
@@ -130,67 +116,3 @@ const properties = computed(() => {
116 ])
117 })
118 </script>
133 -
134 -<style lang="scss" scoped>
135 -.item {
136 - background-color: var(--bg-color);
137 - border-radius: var(--border-radius);
138 - border: var(--border-small-050);
139 - transition: all 0.2s var(--bezier-ease);
140 -
141 - .header-box {
142 - font-size: 13px;
143 - .id {
144 - font-family: var(--font-family-mono);
145 - word-break: break-word;
146 - color: var(--fg-secondary-color);
147 - line-height: 1.2;
148 - }
149 - }
150 -
151 - .main-box {
152 - .content {
153 - word-break: break-word;
154 -
155 - .artifact-label {
156 - background-color: var(--bg-secondary-color);
157 - padding: 3px 8px;
158 - border-radius: var(--border-radius);
159 - }
160 - }
161 - }
162 - .footer-box {
163 - display: none;
164 - text-align: right;
165 - font-size: 13px;
166 - margin-top: 10px;
167 - }
168 -
169 - &:hover {
170 - box-shadow: 0px 0px 0px 1px inset var(--primary-color);
171 - }
172 -
173 - &.embedded {
174 - background-color: var(--bg-secondary-color);
175 -
176 - .main-box {
177 - .content {
178 - .artifact-label {
179 - background-color: var(--bg-color);
180 - }
181 - }
182 - }
183 - }
184 -
185 - @container (max-width: 550px) {
186 - .header-box {
187 - .actions {
188 - display: none;
189 - }
190 - }
191 - .footer-box {
192 - display: flex;
193 - }
194 - }
195 -}
196 -</style>
frontend/src/components/agents/agentFlow/mock.ts new
+111
@@ -0,0 +1,111 @@
1 +import type { CollectResult } from "@/types/flow.d"
2 +
3 +export const flow_results = [
4 + {
5 + id: "sedrftg",
6 + client_id: "client_12345",
7 + session_id: "session_abc123",
8 + request: {
9 + creator: "user123",
10 + user_data: "some_user_data",
11 + client_id: "client_12345",
12 + flow_id: "flow_xyz789",
13 + urgent: true,
14 + artifacts: ["artifact_1", "artifact_2"],
15 + specs: [
16 + {
17 + artifactstring: "artifact_spec_1",
18 + parameters: [
19 + {
20 + key: "param1",
21 + value: "value1",
22 + comment: "Parameter 1"
23 + },
24 + {
25 + key: "param2",
26 + value: "value2",
27 + comment: "Parameter 2"
28 + }
29 + ]
30 + }
31 + ],
32 + cpu_limit: 4,
33 + iops_limit: 1000,
34 + progress_timeout: 30,
35 + timeout: 600,
36 + max_rows: 1000,
37 + max_upload_bytes: 10485760,
38 + trace_freq_sec: 60,
39 + allow_custom_overrides: true,
40 + log_batch_time: 5,
41 + compiled_collector_args: ["arg1", "arg2"],
42 + ops_per_second: 100
43 + },
44 + backtrace: "no_errors_backtrace",
45 + create_time: 1697884800,
46 + start_time: 1697884900,
47 + active_time: 100,
48 + total_uploaded_files: 5,
49 + total_expected_uploaded_bytes: 5242880,
50 + total_uploaded_bytes: 4194304,
51 + total_collected_rows: 2000,
52 + total_logs: 15,
53 + total_requests: 10,
54 + outstanding_requests: 2,
55 + next_response_id: 11,
56 + execution_duration: 3600,
57 + state: "running",
58 + status: "active",
59 + artifacts_with_results: ["artifact_result_1", "artifact_result_2"],
60 + query_stats: [
61 + {
62 + status: "complete",
63 + error_message: "",
64 + backtrace: "",
65 + duration: 200,
66 + last_active: 1697885000,
67 + first_active: 1697884800,
68 + names_with_response: ["name1", "name2"],
69 + Artifact: "artifact_1",
70 + log_rows: 50,
71 + uploaded_files: 3,
72 + uploaded_bytes: 2097152,
73 + expected_uploaded_bytes: 3145728,
74 + result_rows: 500,
75 + query_id: 1,
76 + total_queries: 3
77 + },
78 + {
79 + status: "in_progress",
80 + error_message: "",
81 + backtrace: "",
82 + duration: 150,
83 + last_active: 1697885100,
84 + first_active: 1697884900,
85 + names_with_response: ["name3", "name4"],
86 + Artifact: "artifact_2",
87 + log_rows: 30,
88 + uploaded_files: 2,
89 + uploaded_bytes: 1048576,
90 + expected_uploaded_bytes: 2097152,
91 + result_rows: 300,
92 + query_id: 2,
93 + total_queries: 5
94 + }
95 + ],
96 + uploaded_files: ["file1.txt", "file2.txt"],
97 + user_notified: true,
98 + logs: ["log1", "log2", "log3"],
99 + dirty: false,
100 + total_loads: 20
101 + }
102 +]
103 +
104 +export const collect_result: CollectResult[] = [
105 + {
106 + ___id: "2345678",
107 + uno: 1,
108 + due: new Date().getTime(),
109 + tre: "tre"
110 + }
111 +]
frontend/src/components/agents/sca/ScaItem.vue
+8 -8
@@ -2,8 +2,8 @@
2 <n-tabs type="line" animated :tabs-padding="24">
3 <n-tab-pane name="Details" tab="Details" display-directive="show" class="flex flex-col gap-4 !py-8">
4 <div class="px-7">
5 - <n-card content-class="bg-secondary-color" class="overflow-hidden">
6 - <div class="flex justify-between gap-8 flex-wrap">
5 + <n-card content-class="bg-secondary" class="overflow-hidden">
6 + <div class="flex flex-wrap justify-between gap-8">
7 <n-statistic label="Checks" :value="sca.total_checks" tabular-nums />
8 <n-statistic label="Pass" :value="sca.pass" tabular-nums />
9 <n-statistic label="Fail" :value="sca.fail" tabular-nums />
@@ -13,8 +13,8 @@
13 </n-card>
14 </div>
15 <div class="px-7">
16 - <n-card content-class="bg-secondary-color" class="overflow-hidden">
17 - <div class="flex justify-between gap-8 xs:!flex-row flex-col">
16 + <n-card content-class="bg-secondary" class="overflow-hidden">
17 + <div class="xs:!flex-row flex flex-col justify-between gap-8">
18 <n-statistic
19 class="grow"
20 label="Start scan"
@@ -28,8 +28,8 @@
28 </div>
29 </n-card>
30 </div>
31 - <div v-if="properties" class="grid gap-2 grid-auto-fit-200 px-7">
32 - <KVCard v-for="(value, key) of properties" :key="key">
31 + <div v-if="properties" class="grid-auto-fit-200 grid gap-2 px-7">
32 + <CardKV v-for="(value, key) of properties" :key="key">
33 <template #key>
34 {{ key }}
35 </template>
@@ -52,7 +52,7 @@
52 {{ value ?? "-" }}
53 </template>
54 </template>
55 - </KVCard>
55 + </CardKV>
56 </div>
57 </n-tab-pane>
58 <n-tab-pane name="Description" tab="Description" display-directive="show">
@@ -80,8 +80,8 @@
80
81 <script setup lang="ts">
82 import type { Agent, AgentSca } from "@/types/agents.d"
83 +import CardKV from "@/components/common/cards/CardKV.vue"
84 import Icon from "@/components/common/Icon.vue"
84 -import KVCard from "@/components/common/KVCard.vue"
85 import { useSettingsStore } from "@/stores/settings"
86 import { formatDate } from "@/utils"
87 import _pick from "lodash/pick"
frontend/src/components/agents/sca/ScaResultItem.vue
+55 -93
@@ -1,63 +1,62 @@
1 <template>
2 - <div class="sca-result-item" :class="{ embedded }">
3 - <div class="px-4 py-3 flex flex-col gap-2">
4 - <div class="header-box flex items-center">
5 - <div class="id">#{{ data.id }}</div>
6 - <div class="grow"></div>
7 - <div class="actions">
8 - <n-button size="small" @click.stop="showDetails = true">
9 - <template #icon>
10 - <Icon :name="DetailsIcon"></Icon>
11 - </template>
12 - Details
13 - </n-button>
14 - </div>
15 - </div>
16 - <div class="main-box flex items-center gap-3">
17 - <div class="content flex flex-col gap-1 grow">
18 - <div class="title">
19 - {{ data.title }}
20 - </div>
21 - <div class="description">$ {{ data.command }}</div>
22 - </div>
23 - </div>
24 -
25 - <div class="badges-box flex flex-wrap items-center gap-3 mt-2">
26 - <Badge
27 - type="splitted"
28 - :color="
29 - data.result === 'failed' ? 'danger' : data.result === 'not applicable' ? 'warning' : 'success'
30 - "
31 - class="uppercase"
32 - >
33 - <template #label>
34 - {{ data.result }}
35 - </template>
36 - </Badge>
37 -
38 - <Badge type="splitted" color="primary">
39 - <template #label>Compliance</template>
40 - <template #value>
41 - {{ data.compliance?.length || "-" }}
2 + <div>
3 + <CardEntity :embedded hoverable>
4 + <template #headerMain>#{{ data.id }}</template>
5 + <template #headerExtra>
6 + <n-button size="small" @click.stop="showDetails = true">
7 + <template #icon>
8 + <Icon :name="DetailsIcon"></Icon>
9 </template>
43 - </Badge>
10 + Details
11 + </n-button>
12 + </template>
13 + <template #default>
14 + <div class="flex flex-col gap-1">
15 + <div>{{ data.title }}</div>
16 + <p class="text-sm">$ {{ data.command }}</p>
17 + </div>
18 + </template>
19 + <template #mainExtra>
20 + <div class="flex flex-wrap items-center gap-3">
21 + <Badge
22 + type="splitted"
23 + :color="
24 + data.result === 'failed'
25 + ? 'danger'
26 + : data.result === 'not applicable'
27 + ? 'warning'
28 + : 'success'
29 + "
30 + class="uppercase"
31 + >
32 + <template #label>
33 + {{ data.result }}
34 + </template>
35 + </Badge>
36
45 - <Badge type="splitted" color="primary">
46 - <template #label>Condition</template>
47 - <template #value>
48 - {{ data.condition || "-" }}
49 - </template>
50 - </Badge>
37 + <Badge type="splitted" color="primary">
38 + <template #label>Compliance</template>
39 + <template #value>
40 + {{ data.compliance?.length || "-" }}
41 + </template>
42 + </Badge>
43
52 - <Badge type="splitted" color="primary">
53 - <template #label>Rules</template>
54 - <template #value>
55 - {{ data.rules?.length || "-" }}
56 - </template>
57 - </Badge>
58 - </div>
59 - </div>
44 + <Badge type="splitted" color="primary">
45 + <template #label>Condition</template>
46 + <template #value>
47 + {{ data.condition || "-" }}
48 + </template>
49 + </Badge>
50
51 + <Badge type="splitted" color="primary">
52 + <template #label>Rules</template>
53 + <template #value>
54 + {{ data.rules?.length || "-" }}
55 + </template>
56 + </Badge>
57 + </div>
58 + </template>
59 + </CardEntity>
60 <n-modal
61 v-model:show="showDetails"
62 preset="card"
@@ -75,6 +74,7 @@
74 <script setup lang="ts">
75 import type { ScaPolicyResult } from "@/types/agents.d"
76 import Badge from "@/components/common/Badge.vue"
77 +import CardEntity from "@/components/common/cards/CardEntity.vue"
78 import Icon from "@/components/common/Icon.vue"
79 import { NButton, NModal } from "naive-ui"
80 import { ref } from "vue"
@@ -88,41 +88,3 @@ const { data, embedded } = defineProps<{
88 const DetailsIcon = "carbon:settings-adjust"
89 const showDetails = ref(false)
90 </script>
91 -
92 -<style lang="scss" scoped>
93 -.sca-result-item {
94 - border-radius: var(--border-radius);
95 - background-color: var(--bg-color);
96 - transition: all 0.2s var(--bezier-ease);
97 - border: var(--border-small-050);
98 -
99 - .header-box {
100 - font-size: 13px;
101 - .id {
102 - font-family: var(--font-family-mono);
103 - word-break: break-word;
104 - color: var(--fg-secondary-color);
105 - line-height: 1.2;
106 - }
107 - }
108 -
109 - .main-box {
110 - .content {
111 - word-break: break-word;
112 -
113 - .description {
114 - color: var(--fg-secondary-color);
115 - font-size: 13px;
116 - }
117 - }
118 - }
119 -
120 - &.embedded {
121 - background-color: var(--bg-secondary-color);
122 - }
123 -
124 - &:hover {
125 - box-shadow: 0px 0px 0px 1px inset var(--primary-color);
126 - }
127 -}
128 -</style>
frontend/src/components/agents/sca/ScaResultItemDetails.vue
+15 -15
@@ -2,17 +2,17 @@
2 <n-tabs type="line" animated :tabs-padding="24">
3 <n-tab-pane name="Overview" tab="Overview" display-directive="show:lazy" class="flex flex-col gap-4 !py-8">
4 <div class="px-7">
5 - <n-card content-class="bg-secondary-color" class="overflow-hidden">
6 - <div class="flex justify-between gap-8 flex-wrap">
5 + <n-card content-class="bg-secondary" class="overflow-hidden">
6 + <div class="flex flex-wrap justify-between gap-8">
7 <n-statistic label="Result" tabular-nums>
8 <span
9 class="uppercase"
10 :class="
11 data.result === 'failed'
12 - ? 'text-error-color'
12 + ? 'text-error'
13 : data.result === 'not applicable'
14 - ? 'text-warning-color'
15 - : 'text-success-color'
14 + ? 'text-warning'
15 + : 'text-success'
16 "
17 >
18 {{ data.result }}
@@ -28,25 +28,25 @@
28 </div>
29
30 <div class="px-7">
31 - <n-card content-class="bg-secondary-color !p-0" class="overflow-hidden">
31 + <n-card content-class="bg-secondary !p-0" class="overflow-hidden">
32 <div
33 v-shiki="{ lang: 'shell', decode: true }"
34 - class="scrollbar-styled overflow-hidden code-bg-transparent"
34 + class="scrollbar-styled code-bg-transparent overflow-hidden"
35 >
36 <pre v-html="data.command"></pre>
37 </div>
38 </n-card>
39 </div>
40
41 - <div v-if="properties" class="grid gap-2 grid-auto-fit-200 px-7">
42 - <KVCard v-for="(value, key) of properties" :key="key">
41 + <div v-if="properties" class="grid-auto-fit-200 grid gap-2 px-7">
42 + <CardKV v-for="(value, key) of properties" :key="key">
43 <template #key>
44 {{ key }}
45 </template>
46 <template #value>
47 {{ value ?? "-" }}
48 </template>
49 - </KVCard>
49 + </CardKV>
50 </div>
51 </n-tab-pane>
52 <n-tab-pane name="Description" tab="Description" display-directive="show:lazy">
@@ -110,11 +110,11 @@
110 </div>
111 </n-tab-pane>
112 <n-tab-pane name="Compliance" tab="Compliance" display-directive="show:lazy">
113 - <div class="p-7 pt-4 flex flex-col gap-1">
113 + <div class="flex flex-col gap-1 p-7 pt-4">
114 <n-card
115 v-for="item of data.compliance"
116 :key="item.key"
117 - content-class="bg-secondary-color flex flex-col gap-2"
117 + content-class="bg-secondary flex flex-col gap-2"
118 class="overflow-hidden"
119 size="small"
120 >
@@ -124,11 +124,11 @@
124 </div>
125 </n-tab-pane>
126 <n-tab-pane name="Rules" tab="Rules" display-directive="show:lazy">
127 - <div class="p-7 pt-4 flex flex-col gap-1">
127 + <div class="flex flex-col gap-1 p-7 pt-4">
128 <n-card
129 v-for="item of data.rules"
130 :key="item.type + item.rule"
131 - content-class="bg-secondary-color flex flex-col gap-2"
131 + content-class="bg-secondary flex flex-col gap-2"
132 class="overflow-hidden"
133 size="small"
134 >
@@ -142,7 +142,7 @@
142
143 <script setup lang="ts">
144 import type { ScaPolicyResult } from "@/types/agents.d"
145 -import KVCard from "@/components/common/KVCard.vue"
145 +import CardKV from "@/components/common/cards/CardKV.vue"
146 import vShiki from "@/directives/v-shiki"
147 import _pick from "lodash/pick"
148 import { NCard, NInput, NStatistic, NTabPane, NTabs } from "naive-ui"
frontend/src/components/agents/sca/ScaResults.vue
+9 -16
@@ -1,10 +1,10 @@
1 <template>
2 <n-spin :show="loading">
3 <div ref="header" class="header flex items-center justify-end gap-2">
4 - <div class="info grow flex gap-5">
4 + <div class="info flex grow gap-5">
5 <n-popover overlap placement="bottom-start">
6 <template #trigger>
7 - <div class="bg-color border-radius">
7 + <div class="bg-default rounded-default">
8 <n-button size="small" class="!cursor-help">
9 <template #icon>
10 <Icon :name="InfoIcon"></Icon>
@@ -19,15 +19,15 @@
19 </div>
20 <div class="box">
21 Passed:
22 - <code class="text-success-color">{{ totalPassed }}</code>
22 + <code class="text-success">{{ totalPassed }}</code>
23 </div>
24 <div class="box">
25 Not applicable:
26 - <code class="text-warning-color">{{ totalNA }}</code>
26 + <code class="text-warning">{{ totalNA }}</code>
27 </div>
28 <div class="box">
29 Failed:
30 - <code class="text-error-color">{{ totalFailed }}</code>
30 + <code class="text-error">{{ totalFailed }}</code>
31 </div>
32 </div>
33 </n-popover>
@@ -43,7 +43,7 @@
43 />
44 <n-popover overlap placement="right" class="!px-0">
45 <template #trigger>
46 - <div class="bg-color border-radius">
46 + <div class="bg-default rounded-default">
47 <n-button size="small">
48 <template #icon>
49 <Icon :name="FilterIcon"></Icon>
@@ -53,7 +53,7 @@
53 </template>
54 <div class="py-1">
55 <div class="px-3">
56 - <div class="text-secondary-color text-sm mb-1">Result:</div>
56 + <div class="text-secondary mb-1 text-sm">Result:</div>
57 <n-select
58 v-model:value="resultFilter"
59 size="small"
@@ -66,12 +66,12 @@
66 </div>
67 </n-popover>
68 </div>
69 - <div class="list flex flex-col gap-2 my-3">
69 + <div class="my-3 flex min-h-52 flex-col gap-2">
70 <template v-if="itemsPaginated.length">
71 <ScaResultItem v-for="item of itemsPaginated" :key="item.id" :data="item" embedded />
72 </template>
73 <template v-else>
74 - <n-empty v-if="!loading" description="No items found" class="justify-center h-48" />
74 + <n-empty v-if="!loading" description="No items found" class="h-48 justify-center" />
75 </template>
76 </div>
77 <div class="footer flex justify-end">
@@ -174,10 +174,3 @@ onBeforeMount(() => {
174 if (agent?.agent_id && sca?.policy_id) getSCAResults(agent.agent_id, sca.policy_id)
175 })
176 </script>
177 -
178 -<style lang="scss" scoped>
179 -.list {
180 - container-type: inline-size;
181 - min-height: 200px;
182 -}
183 -</style>
frontend/src/components/agents/sca/ScaTable.vue
+2 -2
@@ -57,7 +57,7 @@
57 <template #trigger>
58 <span class="cursor-help underline">...</span>
59 </template>
60 - <div class="flex flex-col py-2 px-1">
60 + <div class="flex flex-col px-1 py-2">
61 {{ item.description }}
62 </div>
63 </n-popover>
@@ -81,7 +81,7 @@
81 </tbody>
82 </n-table>
83 </n-scrollbar>
84 - <n-empty v-if="!loading && !scaList.length" description="No items found" class="justify-center h-48" />
84 + <n-empty v-if="!loading && !scaList.length" description="No items found" class="h-48 justify-center" />
85
86 <n-modal
87 v-model:show="showDetails"
frontend/src/components/agents/vulnerabilities/VulnerabilitiesGrid.vue
+3 -3
@@ -1,6 +1,6 @@
1 <template>
2 <div class="vulnerabilities-section">
3 - <div class="toolbar flex items-center gap-3 mb-8">
3 + <div class="toolbar mb-8 flex items-center gap-3">
4 <n-form-item label="Severity" label-placement="left" size="small" :show-feedback="false">
5 <n-select v-model:value="severity" :options="severityOptions" class="!w-28" />
6 </n-form-item>
@@ -15,13 +15,13 @@
15 </n-button>
16 </div>
17 <n-spin content-class="min-h-48" :show="loading">
18 - <div class="group gap-4 grid grid-auto-fill-200">
18 + <div class="grid-auto-fill-200 group grid gap-4">
19 <VulnerabilityCard v-for="item of vulnerabilities" :key="item.id" :vulnerability="item" hide-tooltip />
20 </div>
21 <n-empty
22 v-if="!loading && !vulnerabilities.length"
23 description="No vulnerabilities detected"
24 - class="justify-center h-48"
24 + class="h-48 justify-center"
25 />
26 </n-spin>
27 </div>
frontend/src/components/agents/vulnerabilities/VulnerabilityCard.vue
+10 -10
@@ -64,23 +64,23 @@
64 >
65 <n-tabs type="line" animated :tabs-padding="24">
66 <n-tab-pane name="Details" tab="Details" display-directive="show">
67 - <div class="p-7 pt-4 pb-0">
68 - <KVCard>
67 + <div class="p-7 pb-0 pt-4">
68 + <CardKV>
69 <template #key>title</template>
70 <template #value>
71 {{ vulnerability.title ?? "-" }}
72 </template>
73 - </KVCard>
73 + </CardKV>
74 </div>
75 - <div v-if="vulnerabilitySanitized" class="grid gap-2 grid-auto-fit-200 p-7 pt-2">
76 - <KVCard v-for="item of vulnerabilitySanitized" :key="item.label">
75 + <div v-if="vulnerabilitySanitized" class="grid-auto-fit-200 grid gap-2 p-7 pt-2">
76 + <CardKV v-for="item of vulnerabilitySanitized" :key="item.label">
77 <template #key>
78 {{ item.label }}
79 </template>
80 <template #value>
81 {{ item.value ?? "-" }}
82 </template>
83 - </KVCard>
83 + </CardKV>
84 </div>
85 </n-tab-pane>
86 <n-tab-pane name="External references" tab="External references" display-directive="show">
@@ -104,8 +104,8 @@
104
105 <script setup lang="ts">
106 import type { AgentVulnerabilities } from "@/types/agents.d"
107 +import CardKV from "@/components/common/cards/CardKV.vue"
108 import Icon from "@/components/common/Icon.vue"
108 -import KVCard from "@/components/common/KVCard.vue"
109 import { useSettingsStore } from "@/stores/settings"
110 import dayjs from "@/utils/dayjs"
111 import { cloneDeep } from "lodash"
@@ -186,7 +186,7 @@ const showDialog = ref(false)
186 line-height: 1;
187 text-transform: uppercase;
188 font-family: var(--font-family-mono);
189 - @apply text-xs py-0.5 px-2;
189 + @apply px-2 py-0.5 text-xs;
190 white-space: nowrap;
191 text-overflow: ellipsis;
192 background-color: var(--bg-color);
@@ -209,7 +209,7 @@ const showDialog = ref(false)
209 top: 0;
210 right: 0px;
211 text-align: center;
212 - @apply text-xs py-0.5 px-2;
212 + @apply px-2 py-0.5 text-xs;
213 z-index: 2;
214 width: 100%;
215 height: 100%;
@@ -217,7 +217,7 @@ const showDialog = ref(false)
217 }
218
219 .wrapper {
220 - @apply py-3 px-4;
220 + @apply px-4 py-3;
221
222 .title {
223 font-weight: bold;
frontend/src/components/alerts/Alert.vue
+48 -140
@@ -1,24 +1,20 @@
1 <template>
2 - <div class="alert-details flex flex-col gap-2 px-5 py-4">
3 - <div class="header-box flex justify-between">
4 - <div class="id flex items-center gap-2 cursor-pointer" @click="showDetails = true">
5 - <span>#{{ alert._id || alert._source.id }}</span>
6 - <Icon :name="InfoIcon" :size="16"></Icon>
7 - </div>
8 - <div class="time">
2 + <div>
3 + <CardEntity hoverable clickable :embedded class="@container" @click.stop="showDetails = true">
4 + <template #headerMain>#{{ alert._id || alert._source.id }}</template>
5 + <template #headerExtra>
6 {{ formatDate(alert._source.timestamp_utc, dFormats.datetimesec) }}
10 - </div>
11 - </div>
12 - <div class="main-box flex justify-between gap-4">
13 - <div class="content">
14 - <div class="rule-description">
7 + </template>
8 + <template #default>
9 + <div class="flex flex-col gap-1">
10 {{ alert._source.rule_description || alert._source.type }}
11 + <p>
12 + {{ alert._source.rule_groups }}
13 + </p>
14 </div>
17 - <div class="rule-groups">
18 - {{ alert._source.rule_groups }}
19 - </div>
20 -
21 - <div v-if="alert._id" class="badges-box flex flex-wrap items-center gap-3">
15 + </template>
16 + <template v-if="alert._id" #mainExtra>
17 + <div class="flex flex-wrap items-center gap-3">
18 <Badge type="splitted" color="primary">
19 <template #iconLeft>
20 <Icon :name="TargetIcon" :size="13" class="!opacity-80"></Icon>
@@ -44,7 +40,10 @@
40 </template>
41 <template #label>Agent</template>
42 <template #value>
47 - {{ alert._source.agent_name }} / {{ alert._source.agent_labels_customer }}
43 + <div class="flex flex-wrap items-center gap-2">
44 + {{ alert._source.agent_name }} / {{ alert._source.agent_labels_customer }}
45 + <Icon :name="InfoIcon" :size="13" class="!opacity-80"></Icon>
46 + </div>
47 </template>
48 </Badge>
49 </template>
@@ -52,8 +51,8 @@
51 <div class="box">
52 agent_id:
53 <code
55 - class="cursor-pointer text-primary-color"
56 - @click="gotoAgent(alert._source.agent_id)"
54 + class="text-primary cursor-pointer"
55 + @click.stop="gotoAgent(alert._source.agent_id)"
56 >
57 {{ alert._source.agent_id }}
58 <Icon :name="LinkIcon" :size="13" class="relative top-0.5" />
@@ -70,8 +69,8 @@
69 <div class="box">
70 agent_labels_customer:
71 <code
73 - class="cursor-pointer text-primary-color"
74 - @click="gotoCustomer({ code: alert._source.agent_labels_customer })"
72 + class="text-primary cursor-pointer"
73 + @click.stop="gotoCustomer({ code: alert._source.agent_labels_customer })"
74 >
75 {{ alert._source.agent_labels_customer }}
76 <Icon :name="LinkIcon" :size="13" class="relative top-0.5" />
@@ -83,55 +82,39 @@
82 <template #label>syslog</template>
83 <template #value>{{ alert._source.syslog_type }} / {{ alert._source.syslog_level }}</template>
84 </Badge>
86 - <Badge type="splitted" color="primary" class="hide-on-small">
85 + <Badge type="splitted" color="primary" class="@2xl:!flex !hidden">
86 <template #label>manager</template>
87 <template #value>
88 {{ alert._source.manager_name }}
89 </template>
90 </Badge>
92 - <Badge type="splitted" color="primary" class="hide-on-small">
91 + <Badge type="splitted" color="primary" class="@2xl:!flex !hidden">
92 <template #label>decoder</template>
93 <template #value>
94 {{ alert._source.decoder_name }}
95 </template>
96 </Badge>
98 - <Badge type="splitted" color="primary" class="hide-on-small">
97 + <Badge type="splitted" color="primary" class="@2xl:!flex !hidden">
98 <template #label>source</template>
99 <template #value>
100 {{ alert._source.source }}
101 </template>
102 </Badge>
103 </div>
105 - </div>
106 - <AlertActions
107 - v-if="!hideActions"
108 - class="actions-box"
109 - :alert
110 - :soc-alert-field="socAlertCreationField"
111 - @start-loading="loading = true"
112 - @stop-loading="loading = false"
113 - @updated-url="alert._source.alert_url = $event"
114 - @updated-id="alert._source.alert_id = $event"
115 - @updated-ask-message="alert._source.ask_socfortress_message = $event"
116 - />
117 - </div>
118 - <div class="footer-box flex justify-between items-center gap-4">
119 - <AlertActions
120 - v-if="!hideActions"
121 - class="actions-box"
122 - :alert
123 - :soc-alert-field="socAlertCreationField"
124 - size="small"
125 - @start-loading="loading = true"
126 - @stop-loading="loading = false"
127 - @updated-url="alert._source.alert_url = $event"
128 - @updated-id="alert._source.alert_id = $event"
129 - @updated-ask-message="alert._source.ask_socfortress_message = $event"
130 - />
131 - <div class="time">
132 - {{ formatDate(alert._source.timestamp_utc, dFormats.datetimesec) }}
133 - </div>
134 - </div>
104 + </template>
105 + <template v-if="!hideActions" #footerExtra>
106 + <AlertActions
107 + :alert
108 + :soc-alert-field="socAlertCreationField"
109 + size="small"
110 + @start-loading="loading = true"
111 + @stop-loading="loading = false"
112 + @updated-url="alert._source.alert_url = $event"
113 + @updated-id="alert._source.alert_id = $event"
114 + @updated-ask-message="alert._source.ask_socfortress_message = $event"
115 + />
116 + </template>
117 + </CardEntity>
118
119 <n-modal
120 v-model:show="showDetails"
@@ -144,22 +127,22 @@
127 >
128 <n-tabs type="line" animated :tabs-padding="24">
129 <n-tab-pane v-if="alert._id" name="Agent" tab="Agent" display-directive="show">
147 - <div v-if="agentProperties" class="grid gap-2 grid-auto-fit-200 p-7 pt-4">
148 - <KVCard v-for="(value, key) of agentProperties" :key="key">
130 + <div v-if="agentProperties" class="grid-auto-fit-200 grid gap-2 p-7 pt-4">
131 + <CardKV v-for="(value, key) of agentProperties" :key="key">
132 <template #key>
133 {{ key }}
134 </template>
135 <template #value>
136 <template v-if="key === 'agent_id'">
154 - <code class="cursor-pointer text-primary-color" @click="gotoAgent(`${value}`)">
137 + <code class="text-primary cursor-pointer" @click.stop="gotoAgent(`${value}`)">
138 {{ value }}
139 <Icon :name="LinkIcon" :size="13" class="relative top-0.5" />
140 </code>
141 </template>
142 <template v-else-if="key === 'agent_labels_customer'">
143 <code
161 - class="cursor-pointer text-primary-color"
162 - @click="gotoCustomer(value ? { code: value.toString() } : undefined)"
144 + class="text-primary cursor-pointer"
145 + @click.stop="gotoCustomer(value ? { code: value.toString() } : undefined)"
146 >
147 {{ value }}
148 <Icon :name="LinkIcon" :size="13" class="relative top-0.5" />
@@ -169,7 +152,7 @@
152 {{ value || "-" }}
153 </template>
154 </template>
172 - </KVCard>
155 + </CardKV>
156 </div>
157 </n-tab-pane>
158 <n-tab-pane
@@ -229,8 +212,9 @@
212 import type { Alert } from "@/types/alerts.d"
213 import type { SocAlertField } from "./type.d"
214 import Badge from "@/components/common/Badge.vue"
215 +import CardEntity from "@/components/common/cards/CardEntity.vue"
216 +import CardKV from "@/components/common/cards/CardKV.vue"
217 import Icon from "@/components/common/Icon.vue"
233 -import KVCard from "@/components/common/KVCard.vue"
218 import { useGoto } from "@/composables/useGoto"
219 import { useSettingsStore } from "@/stores/settings"
220 import { formatDate } from "@/utils"
@@ -238,11 +222,11 @@ import _pick from "lodash/pick"
222 import { NInput, NModal, NPopover, NTabPane, NTabs } from "naive-ui"
223 import { computed, defineAsyncComponent, inject, ref, toRefs } from "vue"
224
241 -const props = defineProps<{ alert: Alert; hideActions?: boolean }>()
225 +const props = defineProps<{ alert: Alert; hideActions?: boolean; embedded?: boolean }>()
226 const AlertActions = defineAsyncComponent(() => import("./AlertActions.vue"))
227 const CodeSource = defineAsyncComponent(() => import("@/components/common/CodeSource.vue"))
228
245 -const { alert, hideActions } = toRefs(props)
229 +const { alert, hideActions, embedded } = toRefs(props)
230
231 const InfoIcon = "carbon:information"
232 const TargetIcon = "zondicons:target"
@@ -271,79 +255,3 @@ const agentProperties = computed(() => {
255
256 const socAlertCreationField = ref(inject<SocAlertField>("soc-alert-creation-field", "alert_url"))
257 </script>
274 -
275 -<style lang="scss" scoped>
276 -.alert-details {
277 - transition: all 0.2s var(--bezier-ease);
278 -
279 - .header-box {
280 - font-family: var(--font-family-mono);
281 - font-size: 13px;
282 - .id {
283 - word-break: break-word;
284 - color: var(--fg-secondary-color);
285 - line-height: 1.2;
286 -
287 - &:hover {
288 - color: var(--primary-color);
289 - }
290 - }
291 - .time {
292 - color: var(--fg-secondary-color);
293 - }
294 - }
295 - .main-box {
296 - .content {
297 - word-break: break-word;
298 -
299 - .rule-groups {
300 - color: var(--fg-secondary-color);
301 - font-size: 13px;
302 - }
303 -
304 - .badges-box {
305 - margin-top: 16px;
306 - }
307 - }
308 - }
309 - .footer-box {
310 - display: none;
311 - font-size: 13px;
312 - margin-top: 10px;
313 -
314 - .time {
315 - font-family: var(--font-family-mono);
316 - color: var(--fg-secondary-color);
317 - text-align: right;
318 - }
319 - }
320 -
321 - &:hover {
322 - background-color: var(--primary-005-color);
323 - }
324 -
325 - @container (max-width: 650px) {
326 - .header-box {
327 - .time {
328 - display: none;
329 - }
330 - }
331 - .main-box {
332 - .actions-box {
333 - display: none;
334 - }
335 -
336 - .badges-box {
337 - .badge {
338 - &.hide-on-small {
339 - display: none;
340 - }
341 - }
342 - }
343 - }
344 - .footer-box {
345 - display: flex;
346 - }
347 - }
348 -}
349 -</style>
frontend/src/components/alerts/AlertActions.vue
+6 -6
@@ -1,6 +1,6 @@
1 <template>
2 - <div class="alert-actions flex flex-col gap-2 justify-end">
3 - <n-button v-if="socAlertFieldValue" type="success" secondary :size="size" @click="gotoSocAlertUrl()">
2 + <div class="flex flex-wrap justify-end gap-2">
3 + <n-button v-if="socAlertFieldValue" type="success" secondary :size="size" @click.stop="gotoSocAlertUrl()">
4 <template #icon>
5 <Icon :name="ViewIcon"></Icon>
6 </template>
@@ -12,14 +12,14 @@
12 type="warning"
13 secondary
14 :size="size"
15 - @click="createAlert()"
15 + @click.stop="createAlert()"
16 >
17 <template #icon>
18 <Icon :name="DangerIcon"></Icon>
19 </template>
20 Create SOC Alert
21 </n-button>
22 - <n-button v-if="alertAskMessage" type="success" secondary :size="size" @click="showSocResponse = true">
22 + <n-button v-if="alertAskMessage" type="success" secondary :size="size" @click.stop="showSocResponse = true">
23 <template #icon>
24 <Icon :name="ViewIcon"></Icon>
25 </template>
@@ -31,7 +31,7 @@
31 type="warning"
32 secondary
33 :size="size"
34 - @click="askSOCFortress()"
34 + @click.stop="askSOCFortress()"
35 >
36 <template #icon>
37 <Icon :name="AskIcon"></Icon>
@@ -43,7 +43,7 @@
43 :loading="loadingWazuhRuleExclude"
44 secondary
45 :size="size"
46 - @click="wazuhManagerRuleExclude()"
46 + @click.stop="wazuhManagerRuleExclude()"
47 >
48 <template #icon>
49 <Icon :name="RulesIcon"></Icon>
frontend/src/components/alerts/AlertsFilters.vue
+1 -1
@@ -25,7 +25,7 @@
25 <template #empty>
26 <n-empty
27 description="Empty Field history"
28 - class="text-center justify-center h-48"
28 + class="h-48 justify-center text-center"
29 ></n-empty>
30 </template>
31 </n-select>
frontend/src/components/alerts/AlertsGraylogList.vue
+8 -19
@@ -1,10 +1,10 @@
1 <template>
2 <div class="alerts-list">
3 <div class="header flex items-center justify-end gap-2">
4 - <div class="info grow flex gap-5">
4 + <div class="info flex grow gap-5">
5 <n-popover overlap placement="bottom-start">
6 <template #trigger>
7 - <div class="bg-color border-radius">
7 + <div class="bg-default rounded-default">
8 <n-button size="small" class="!cursor-help">
9 <template #icon>
10 <Icon :name="InfoIcon"></Icon>
@@ -24,7 +24,7 @@
24 </div>
25 </n-popover>
26 </div>
27 - <div class="actions flex gap-2 items-center">
27 + <div class="actions flex items-center gap-2">
28 <n-button size="small" @click="showFiltersDrawer = true">
29 <template #icon>
30 <Icon :name="FilterIcon" :size="15"></Icon>
@@ -37,7 +37,7 @@
37 <n-spin :show="loading">
38 <template #description>Alerts are being fetched, this may take up to 1 minute.</template>
39
40 - <div class="list flex flex-col gap-2 my-3">
40 + <div class="my-3 flex min-h-52 flex-col gap-2">
41 <template v-if="alertsSummaryList.length">
42 <AlertsSummaryItem
43 v-for="alertsSummary of alertsSummaryList"
@@ -47,7 +47,7 @@
47 />
48 </template>
49 <template v-else>
50 - <n-empty v-if="!loading" description="No items found" class="justify-center h-48" />
50 + <n-empty v-if="!loading" description="No items found" class="h-48 justify-center" />
51 </template>
52 </div>
53 </n-spin>
@@ -68,10 +68,6 @@
68 </template>
69
70 <script setup lang="ts">
71 -// MOCK
72 -// import { alerts_summary } from "./mock"
73 -// import type { AlertsSummary } from "@/types/alerts.d"
74 -
71 import type { GraylogAlertsQuery } from "@/api/endpoints/alerts"
72 import type { IndexStats } from "@/types/indices.d"
73 import type { SocAlertField } from "./type.d"
@@ -167,7 +163,9 @@ provide<SocAlertField>("soc-alert-creation-field", "alert_id")
163 onBeforeMount(() => {
164 nextTick(() => {
165 // MOCK
170 - // alertsSummaryList.value = alerts_summary as AlertsSummary[]
166 + /*
167 + alertsSummaryList.value = alerts_summary
168 + */
169 startSearch()
170 })
171 })
@@ -184,12 +182,3 @@ onBeforeUnmount(() => {
182 cancelSearch()
183 })
184 </script>
187 -
188 -<style lang="scss" scoped>
189 -.alerts-list {
190 - .list {
191 - container-type: inline-size;
192 - min-height: 200px;
193 - }
194 -}
195 -</style>
frontend/src/components/alerts/AlertsList.vue
+5 -5
@@ -1,10 +1,10 @@
1 <template>
2 <div class="alerts-list">
3 <div class="header flex items-center justify-end gap-2">
4 - <div class="info grow flex gap-5">
4 + <div class="info flex grow gap-5">
5 <n-popover overlap placement="bottom-start">
6 <template #trigger>
7 - <div class="bg-color border-radius">
7 + <div class="bg-default rounded-default">
8 <n-button size="small" class="!cursor-help">
9 <template #icon>
10 <Icon :name="InfoIcon"></Icon>
@@ -24,7 +24,7 @@
24 </div>
25 </n-popover>
26 </div>
27 - <div class="actions flex gap-2 items-center">
27 + <div class="actions flex items-center gap-2">
28 <n-button v-if="!isFilterPreselected" size="small" @click="showStatsDrawer = true">
29 <template #icon>
30 <Icon :name="StatsIcon" :size="14"></Icon>
@@ -43,7 +43,7 @@
43 <n-spin :show="loading">
44 <template #description>Alerts are being fetched, this may take up to 1 minute.</template>
45
46 - <div class="list flex flex-col gap-2 my-3">
46 + <div class="list my-3 flex flex-col gap-2">
47 <template v-if="alertsSummaryList.length">
48 <AlertsSummaryItem
49 v-for="alertsSummary of alertsSummaryList"
@@ -53,7 +53,7 @@
53 />
54 </template>
55 <template v-else>
56 - <n-empty v-if="!loading" description="No items found" class="justify-center h-48" />
56 + <n-empty v-if="!loading" description="No items found" class="h-48 justify-center" />
57 </template>
58 </div>
59 </n-spin>
frontend/src/components/alerts/AlertsStats.vue
+3 -3
@@ -18,7 +18,7 @@
18 <n-empty
19 v-if="!loadingCountByHost"
20 description="No items found"
21 - class="justify-center h-48"
21 + class="h-48 justify-center"
22 />
23 </template>
24 </div>
@@ -41,7 +41,7 @@
41 <n-empty
42 v-if="!loadingCountByRule"
43 description="No items found"
44 - class="justify-center h-48"
44 + class="h-48 justify-center"
45 />
46 </template>
47 </div>
@@ -64,7 +64,7 @@
64 <n-empty
65 v-if="!loadingCountByRuleHost"
66 description="No items found"
67 - class="justify-center h-48"
67 + class="h-48 justify-center"
68 />
69 </template>
70 </div>
frontend/src/components/alerts/AlertsStatsItem.vue
+3 -3
@@ -1,10 +1,10 @@
1 <template>
2 <div class="alerts-stats-item flex items-stretch">
3 - <div class="info grow flex flex-col gap-1 justify-center">
3 + <div class="info flex grow flex-col justify-center gap-1">
4 <div
5 v-if="summary.agent_name"
6 class="agent"
7 - :class="{ 'text-secondary-color': summary.agent_name && summary.rule }"
7 + :class="{ 'text-secondary': summary.agent_name && summary.rule }"
8 >
9 {{ summary.agent_name }}
10 </div>
@@ -12,7 +12,7 @@
12 {{ summary.rule }}
13 </div>
14 </div>
15 - <div class="count font-mono flex items-center justify-center">
15 + <div class="count flex items-center justify-center font-mono">
16 <span v-if="summary.number_of_alerts">
17 {{ summary.number_of_alerts }}
18 </span>
frontend/src/components/alerts/AlertsSummary.vue
+58 -100
@@ -1,18 +1,21 @@
1 <template>
2 - <div class="alert-summary flex flex-col">
3 - <div class="header-box flex justify-between gap-4">
4 - <div class="id flex items-center gap-2" @click="gotoIndex(alertsSummary.index_name)">
2 + <CardEntity>
3 + <template #headerMain>
4 + <div
5 + class="hover:text-primary flex cursor-pointer items-center gap-2"
6 + @click="gotoIndex(alertsSummary.index_name)"
7 + >
8 <IndexIcon v-if="alertsSummary.indexStats?.health" :health="alertsSummary.indexStats?.health" color />
9 <Icon v-else :name="PlaceholderIcon" :size="18" />
7 -
8 - {{ alertsSummary.index_name }}
9 -
10 + index: {{ alertsSummary.index_name }}
11 <Icon :name="LinkIcon" :size="14" />
12 </div>
12 - <div class="total-alerts flex items-center flex-wrap justify-end">
13 + </template>
14 + <template #headerExtra>
15 + <div class="flex min-h-6 flex-wrap items-center justify-end gap-3">
16 <n-button
17 v-if="alertsSummary.alerts.length > 3 && showAllAlerts"
15 - class="show-less"
18 + class="animate-fade opacity-0"
19 size="tiny"
20 @click="showAllAlerts = false"
21 >
@@ -20,14 +23,16 @@
23 </n-button>
24 <span>
25 Alerts:
23 - <strong class="font-mono ml-2">{{ alertsSummary.total_alerts }}</strong>
26 + <strong class="ml-2 font-mono">{{ alertsSummary.total_alerts }}</strong>
27 </span>
28 </div>
26 - </div>
27 - <div class="main-box">
29 + </template>
30 + <template #mainExtra>
31 <div class="alert-list" :class="{ expand: showAllAlerts }">
32 <n-scrollbar class="list-scroll" trigger="none">
30 - <Alert v-for="alert of alertsSummary.alerts" :key="alert._id" :alert="alert" />
33 + <div class="flex flex-col gap-2">
34 + <Alert v-for="alert of alertsSummary.alerts" :key="alert._id" :alert="alert" embedded />
35 + </div>
36 </n-scrollbar>
37
38 <div v-if="alertsSummary.alerts.length > 3" class="load-more" @click="showAllAlerts = true">
@@ -39,13 +44,14 @@
44 </n-button>
45 </div>
46 </div>
42 - </div>
43 - </div>
47 + </template>
48 + </CardEntity>
49 </template>
50
51 <script setup lang="ts">
52 import type { AlertsSummary } from "@/types/alerts.d"
53 import type { IndexStats } from "@/types/indices.d"
54 +import CardEntity from "@/components/common/cards/CardEntity.vue"
55 import Icon from "@/components/common/Icon.vue"
56 import IndexIcon from "@/components/indices/IndexIcon.vue"
57 import { useGoto } from "@/composables/useGoto"
@@ -68,105 +74,57 @@ const { gotoIndex } = useGoto()
74 </script>
75
76 <style lang="scss" scoped>
71 -.alert-summary {
72 - border-radius: var(--border-radius);
73 - background-color: var(--bg-color);
77 +.alert-list {
78 + position: relative;
79 overflow: hidden;
80 transition: all 0.2s var(--bezier-ease);
76 - border: var(--border-small-050);
81
78 - .header-box {
79 - font-size: 15px;
80 - padding: 14px 16px;
81 - min-height: 52px;
82 + .alert-details {
83 border-bottom: var(--border-small-100);
84
84 - .id {
85 - word-break: break-word;
86 - cursor: pointer;
87 -
88 - &:hover {
89 - color: var(--primary-color);
90 - }
85 + &:last-child {
86 + border-bottom: none;
87 + border-bottom-left-radius: var(--border-radius);
88 + border-bottom-right-radius: var(--border-radius);
89 }
92 - .total-alerts {
93 - text-align: right;
94 - gap: 7px;
90 + }
91
96 - .show-less {
97 - opacity: 0;
98 - animation: show-less-fade 0.3s forwards;
92 + .load-more {
93 + position: absolute;
94 + top: 0;
95 + bottom: 0;
96 + left: 0;
97 + right: 0;
98 + height: 100%;
99 + width: 100%;
100 + background: rgba(var(--bg-color-rgb), 0.6);
101 + background: linear-gradient(transparent 0%, var(--bg-color) 85%);
102 + display: flex;
103 + align-items: center;
104 + text-align: center;
105 + padding: 10px;
106 + flex-direction: column;
107 + justify-content: flex-end;
108 + cursor: pointer;
109 + transition: all 0.6s var(--bezier-ease);
110 + }
111
100 - @keyframes show-less-fade {
101 - from {
102 - opacity: 0;
103 - }
104 - to {
105 - opacity: 1;
106 - }
107 - }
108 - }
112 + :deep() {
113 + .list-scroll {
114 + max-height: 250px;
115 + transition: all 0.4s var(--bezier-ease);
116 }
117 }
111 -
112 - .main-box {
113 - .alert-list {
114 - position: relative;
115 - overflow: hidden;
116 - transition: all 0.2s var(--bezier-ease);
117 -
118 - .alert-details {
119 - border-bottom: var(--border-small-100);
120 -
121 - &:last-child {
122 - border-bottom: none;
123 - border-bottom-left-radius: var(--border-radius);
124 - border-bottom-right-radius: var(--border-radius);
125 - }
126 - }
127 -
128 - .load-more {
129 - position: absolute;
130 - top: 0;
131 - bottom: 0;
132 - left: 0;
133 - right: 0;
134 - height: 100%;
135 - width: 100%;
136 - background: rgba(var(--bg-color-rgb), 0.6);
137 - background: linear-gradient(transparent 0%, var(--bg-color) 85%);
138 - display: flex;
139 - align-items: center;
140 - text-align: center;
141 - padding: 10px;
142 - flex-direction: column;
143 - justify-content: flex-end;
144 - cursor: pointer;
145 - transition: all 0.6s var(--bezier-ease);
146 - }
147 -
148 - :deep() {
149 - .list-scroll {
150 - max-height: 250px;
151 - transition: all 0.4s var(--bezier-ease);
152 - }
153 - }
154 - &.expand {
155 - :deep() {
156 - .list-scroll {
157 - max-height: 600px;
158 - }
159 - }
160 -
161 - .load-more {
162 - transform: translateY(100%);
163 - }
118 + &.expand {
119 + :deep() {
120 + .list-scroll {
121 + max-height: 600px;
122 }
123 }
166 - }
124
168 - &:hover {
169 - border-color: var(--primary-color);
125 + .load-more {
126 + transform: translateY(100%);
127 + }
128 }
129 }
130 </style>
frontend/src/components/alerts/mock.ts
+161 -148
@@ -1,4 +1,19 @@
1 -const alerts_summary = [
1 +import {
2 + AlertSourceDataGroup,
3 + AlertSourceDataKind,
4 + AlertSourceDataLevelEnum,
5 + AlertSourceDataLogsourceCategory,
6 + AlertSourceDataLogsourceProduct,
7 + AlertSourceDataStatus,
8 + AlertSourceDataWinEventdataIntegrityLevel,
9 + AlertSourceDataWinSystemSeverityValue,
10 + AlertSourceDecoderName,
11 + AlertSourceSyslogLevel,
12 + AlertSourceSyslogType,
13 + type AlertsSummary
14 +} from "@/types/alerts.d"
15 +
16 +export const alerts_summary: AlertsSummary[] = [
17 {
18 index_name: "wazuh-wso4vxhq_7",
19 total_alerts: 5,
@@ -16,8 +31,8 @@ const alerts_summary = [
31 rule_id: "92400",
32 rule_mail: true,
33
19 - syslog_type: "wazuh",
20 - syslog_level: "ALERT",
34 + syslog_type: AlertSourceSyslogType.Wazuh,
35 + syslog_level: AlertSourceSyslogLevel.Alert,
36
37 agent_id: "070",
38 agent_ip: "202.43.110.138",
@@ -29,7 +44,7 @@ const alerts_summary = [
44
45 source: "10.255.255.13",
46 streams: ["650d3da25e9a2d550c6d6491"],
32 - decoder_name: "windows_eventchannel",
47 + decoder_name: AlertSourceDecoderName.WindowsEventchannel,
48 manager_name: "ASHWZHMA",
49 location: "EventChannel",
50
@@ -61,7 +76,7 @@ const alerts_summary = [
76 true: 1699187091.846419,
77 data_win_system_keywords: "0x8000000000000000",
78 data_win_system_level: "4",
64 - data_win_system_severityValue: "INFORMATION",
79 + data_win_system_severityValue: AlertSourceDataWinSystemSeverityValue.Information,
80 data_win_eventdata_targetUser: "WEB1\\\\Administrator",
81 agent_ip_geolocation: "16.1667,107.8333",
82 rule_mitre_technique: "Process Injection",
@@ -83,7 +98,7 @@ const alerts_summary = [
98 data_win_eventdata_sourceProcessGuid: "{d9ab9ebb-48da-652f-4900-000000003000}",
99 data_win_eventdata_targetProcessId: "4384",
100 data_win_eventdata_startFunction: "GetCommandLineW",
86 - rule_group3: "windows",
101 + rule_group3: AlertSourceDataLogsourceProduct.Windows,
102 data_win_system_message:
103 '"CreateRemoteThread detected:\r\nRuleName: technique_id=T1055,technique_name=Process Injection\r\nUtcTime: 2023-11-05 12:24:50.567\r\nSourceProcessGuid: {d9ab9ebb-48da-652f-4900-000000003000}\r\nSourceProcessId: 3368\r\nSourceImage: C:\\Program Files\\VMware\\VMware Tools\\vmtoolsd.exe\r\nTargetProcessGuid: {d9ab9ebb-62bb-6547-601c-020000003000}\r\nTargetProcessId: 4384\r\nTargetImage: C:\\Windows\\explorer.exe\r\nNewThreadId: 16400\r\nStartAddress: 0x00007FFDE5CCE720\r\nStartModule: C:\\Windows\\System32\\KERNEL32.DLL\r\nStartFunction: GetCommandLineW\r\nSourceUser: NT AUTHORITY\\SYSTEM\r\nTargetUser: WEB1\\Administrator"',
104 msg_timestamp: "2023-11-05T12:24:51.691Z",
@@ -114,7 +129,7 @@ const alerts_summary = [
129 data_win_eventdata_sourceUser: "NT AUTHORITY\\\\SYSTEM",
130 data_win_system_task: "8",
131 timestamp_utc: "2023-11-05T12:24:32.015Z",
117 - syslog_type: "wazuh",
132 + syslog_type: AlertSourceSyslogType.Wazuh,
133 data_win_system_threadID: "5576",
134 rule_description:
135 "Local Security Authority Subsystem Service (LSASS) process was accessed by C:\\\\Program Files\\\\VMware\\\\VMware Tools\\\\vmtoolsd.exe, possible code injection for credential dumping",
@@ -136,18 +151,18 @@ const alerts_summary = [
151 rule_groups: "sysmon, sysmon_eid8_detections, windows",
152 data_win_system_keywords: "0x8000000000000000",
153 data_win_system_level: "4",
139 - data_win_system_severityValue: "INFORMATION",
154 + data_win_system_severityValue: AlertSourceDataWinSystemSeverityValue.Information,
155 data_win_eventdata_targetUser: "NT AUTHORITY\\\\SYSTEM",
156 agent_ip_geolocation: "16.1667,107.8333",
157 rule_mitre_technique: "Process Injection",
158 rule_firedtimes: 1,
159 data_win_system_systemTime: "2023-11-05T12:24:32.015055900Z",
160 rule_mail: true,
146 - decoder_name: "windows_eventchannel",
161 + decoder_name: AlertSourceDecoderName.WindowsEventchannel,
162 agent_ip_country_code: "VN",
163 data_win_system_processID: "3468",
164 data_win_system_channel: "Microsoft-Windows-Sysmon/Operational",
150 - syslog_level: "ALERT",
165 + syslog_level: AlertSourceSyslogLevel.Alert,
166 data_win_system_providerName: "Microsoft-Windows-Sysmon",
167 data_win_system_version: "2",
168 data_win_system_providerGuid: "{5770385f-c22a-43e0-bf4c-06f5698ffbd9}",
@@ -165,7 +180,7 @@ const alerts_summary = [
180 location: "EventChannel",
181 data_win_eventdata_targetProcessId: "740",
182 data_win_eventdata_startFunction: "GetCommandLineW",
168 - rule_group3: "windows",
183 + rule_group3: AlertSourceDataLogsourceProduct.Windows,
184 data_win_system_message:
185 '"CreateRemoteThread detected:\r\nRuleName: technique_id=T1055,technique_name=Process Injection\r\nUtcTime: 2023-11-05 12:24:32.013\r\nSourceProcessGuid: {d9ab9ebb-48da-652f-4900-000000003000}\r\nSourceProcessId: 3368\r\nSourceImage: C:\\Program Files\\VMware\\VMware Tools\\vmtoolsd.exe\r\nTargetProcessGuid: {d9ab9ebb-48d7-652f-0c00-000000003000}\r\nTargetProcessId: 740\r\nTargetImage: C:\\Windows\\System32\\lsass.exe\r\nNewThreadId: 17292\r\nStartAddress: 0x00007FFDE5CCE720\r\nStartModule: C:\\Windows\\System32\\KERNEL32.DLL\r\nStartFunction: GetCommandLineW\r\nSourceUser: NT AUTHORITY\\SYSTEM\r\nTargetUser: NT AUTHORITY\\SYSTEM"',
186 msg_timestamp: "2023-11-05T12:24:32.489Z",
@@ -196,7 +211,7 @@ const alerts_summary = [
211 data_win_eventdata_sourceUser: "WEB1\\\\Administrator",
212 data_win_system_task: "10",
213 timestamp_utc: "2023-11-05T12:23:11.139Z",
199 - syslog_type: "wazuh",
214 + syslog_type: AlertSourceSyslogType.Wazuh,
215 data_win_system_threadID: "5576",
216 rule_description:
217 "Explorer process was accessed by C:\\\\Users\\\\Administrator\\\\AppData\\\\Roaming\\\\Telegram Desktop\\\\Telegram.exe, possible process injection",
@@ -219,18 +234,18 @@ const alerts_summary = [
234 data_win_system_keywords: "0x8000000000000000",
235 data_win_system_level: "4",
236 data_win_eventdata_targetProcessGUID: "{d9ab9ebb-62bb-6547-601c-020000003000}",
222 - data_win_system_severityValue: "INFORMATION",
237 + data_win_system_severityValue: AlertSourceDataWinSystemSeverityValue.Information,
238 data_win_eventdata_targetUser: "WEB1\\\\Administrator",
239 agent_ip_geolocation: "16.1667,107.8333",
240 rule_mitre_technique: "Process Injection",
241 rule_firedtimes: 33,
242 data_win_system_systemTime: "2023-11-05T12:23:11.139487000Z",
243 rule_mail: true,
229 - decoder_name: "windows_eventchannel",
244 + decoder_name: AlertSourceDecoderName.WindowsEventchannel,
245 agent_ip_country_code: "VN",
246 data_win_system_processID: "3468",
247 data_win_system_channel: "Microsoft-Windows-Sysmon/Operational",
233 - syslog_level: "ALERT",
248 + syslog_level: AlertSourceSyslogLevel.Alert,
249 data_win_system_providerName: "Microsoft-Windows-Sysmon",
250 data_win_system_version: "3",
251 data_win_system_providerGuid: "{5770385f-c22a-43e0-bf4c-06f5698ffbd9}",
@@ -247,7 +262,7 @@ const alerts_summary = [
262 manager_name: "ASHWZHMA",
263 location: "EventChannel",
264 data_win_eventdata_targetProcessId: "4384",
250 - rule_group3: "windows",
265 + rule_group3: AlertSourceDataLogsourceProduct.Windows,
266 data_win_system_message:
267 '"Process accessed:\r\nRuleName: technique_id=T1036,technique_name=Masquerading\r\nUtcTime: 2023-11-05 12:23:11.138\r\nSourceProcessGUID: {d9ab9ebb-7e1a-6544-44e0-010000003000}\r\nSourceProcessId: 1652\r\nSourceThreadId: 1284\r\nSourceImage: C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe\r\nTargetProcessGUID: {d9ab9ebb-62bb-6547-601c-020000003000}\r\nTargetProcessId: 4384\r\nTargetImage: C:\\Windows\\explorer.exe\r\nGrantedAccess: 0x40\r\nCallTrace: C:\\Windows\\SYSTEM32\\ntdll.dll+9ff24|C:\\Windows\\System32\\KERNELBASE.dll+1668e|C:\\Windows\\System32\\shcore.dll+cca8|C:\\Windows\\System32\\shcore.dll+ba77|C:\\Windows\\System32\\shcore.dll+b967|C:\\Windows\\System32\\shcore.dll+b8f1|C:\\Windows\\System32\\shcore.dll+b61a|C:\\Windows\\system32\\explorerframe.dll+12b9d0|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+157bd8c|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+18051ce|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+2e1a17|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+2dfdfe|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+130216a|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+a566ec|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+a5695f|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+3c3e93b|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+3c40433|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+3fbdb8e|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+3d62541|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+3fbdb68|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+3c942dd|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+3c3db94|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+a52491|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+a3e4a9\r\nSourceUser: WEB1\\Administrator\r\nTargetUser: WEB1\\Administrator"',
268 data_win_eventdata_sourceThreadId: "1284",
@@ -279,7 +294,7 @@ const alerts_summary = [
294 data_win_eventdata_sourceUser: "WEB1\\\\Administrator",
295 data_win_system_task: "10",
296 timestamp_utc: "2023-11-05T12:23:11.139Z",
282 - syslog_type: "wazuh",
297 + syslog_type: AlertSourceSyslogType.Wazuh,
298 data_win_system_threadID: "5576",
299 rule_description:
300 "Explorer process was accessed by C:\\\\Users\\\\Administrator\\\\AppData\\\\Roaming\\\\Telegram Desktop\\\\Telegram.exe, possible process injection",
@@ -302,18 +317,18 @@ const alerts_summary = [
317 data_win_system_keywords: "0x8000000000000000",
318 data_win_system_level: "4",
319 data_win_eventdata_targetProcessGUID: "{d9ab9ebb-62bb-6547-601c-020000003000}",
305 - data_win_system_severityValue: "INFORMATION",
320 + data_win_system_severityValue: AlertSourceDataWinSystemSeverityValue.Information,
321 data_win_eventdata_targetUser: "WEB1\\\\Administrator",
322 agent_ip_geolocation: "16.1667,107.8333",
323 rule_mitre_technique: "Process Injection",
324 rule_firedtimes: 32,
325 data_win_system_systemTime: "2023-11-05T12:23:11.139039000Z",
326 rule_mail: true,
312 - decoder_name: "windows_eventchannel",
327 + decoder_name: AlertSourceDecoderName.WindowsEventchannel,
328 agent_ip_country_code: "VN",
329 data_win_system_processID: "3468",
330 data_win_system_channel: "Microsoft-Windows-Sysmon/Operational",
316 - syslog_level: "ALERT",
331 + syslog_level: AlertSourceSyslogLevel.Alert,
332 data_win_system_providerName: "Microsoft-Windows-Sysmon",
333 data_win_system_version: "3",
334 data_win_system_providerGuid: "{5770385f-c22a-43e0-bf4c-06f5698ffbd9}",
@@ -330,7 +345,7 @@ const alerts_summary = [
345 manager_name: "ASHWZHMA",
346 location: "EventChannel",
347 data_win_eventdata_targetProcessId: "4384",
333 - rule_group3: "windows",
348 + rule_group3: AlertSourceDataLogsourceProduct.Windows,
349 data_win_system_message:
350 '"Process accessed:\r\nRuleName: technique_id=T1036,technique_name=Masquerading\r\nUtcTime: 2023-11-05 12:23:11.137\r\nSourceProcessGUID: {d9ab9ebb-7e1a-6544-44e0-010000003000}\r\nSourceProcessId: 1652\r\nSourceThreadId: 1284\r\nSourceImage: C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe\r\nTargetProcessGUID: {d9ab9ebb-62bb-6547-601c-020000003000}\r\nTargetProcessId: 4384\r\nTargetImage: C:\\Windows\\explorer.exe\r\nGrantedAccess: 0x40\r\nCallTrace: C:\\Windows\\SYSTEM32\\ntdll.dll+9ff24|C:\\Windows\\System32\\KERNELBASE.dll+1668e|C:\\Windows\\System32\\shcore.dll+cca8|C:\\Windows\\System32\\shcore.dll+ba62|C:\\Windows\\System32\\shcore.dll+b585|C:\\Windows\\System32\\shcore.dll+b275|C:\\Windows\\System32\\shcore.dll+b209|C:\\Windows\\System32\\shcore.dll+b104|C:\\Windows\\system32\\explorerframe.dll+12b986|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+157bd8c|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+18051ce|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+2e1a17|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+2dfdfe|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+130216a|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+a566ec|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+a5695f|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+3c3e93b|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+3c40433|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+3fbdb8e|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+3d62541|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+3fbdb68|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+3c942dd|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+3c3db94|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+a52491\r\nSourceUser: WEB1\\Administrator\r\nTargetUser: WEB1\\Administrator"',
351 data_win_eventdata_sourceThreadId: "1284",
@@ -362,7 +377,7 @@ const alerts_summary = [
377 data_win_eventdata_sourceUser: "WEB1\\\\Administrator",
378 data_win_system_task: "10",
379 timestamp_utc: "2023-11-05T12:23:11.138Z",
365 - syslog_type: "wazuh",
380 + syslog_type: AlertSourceSyslogType.Wazuh,
381 data_win_system_threadID: "5576",
382 rule_description:
383 "Explorer process was accessed by C:\\\\Users\\\\Administrator\\\\AppData\\\\Roaming\\\\Telegram Desktop\\\\Telegram.exe, possible process injection",
@@ -385,18 +400,18 @@ const alerts_summary = [
400 data_win_system_keywords: "0x8000000000000000",
401 data_win_system_level: "4",
402 data_win_eventdata_targetProcessGUID: "{d9ab9ebb-62bb-6547-601c-020000003000}",
388 - data_win_system_severityValue: "INFORMATION",
403 + data_win_system_severityValue: AlertSourceDataWinSystemSeverityValue.Information,
404 data_win_eventdata_targetUser: "WEB1\\\\Administrator",
405 agent_ip_geolocation: "16.1667,107.8333",
406 rule_mitre_technique: "Process Injection",
407 rule_firedtimes: 31,
408 data_win_system_systemTime: "2023-11-05T12:23:11.138753100Z",
409 rule_mail: true,
395 - decoder_name: "windows_eventchannel",
410 + decoder_name: AlertSourceDecoderName.WindowsEventchannel,
411 agent_ip_country_code: "VN",
412 data_win_system_processID: "3468",
413 data_win_system_channel: "Microsoft-Windows-Sysmon/Operational",
399 - syslog_level: "ALERT",
414 + syslog_level: AlertSourceSyslogLevel.Alert,
415 data_win_system_providerName: "Microsoft-Windows-Sysmon",
416 data_win_system_version: "3",
417 data_win_system_providerGuid: "{5770385f-c22a-43e0-bf4c-06f5698ffbd9}",
@@ -413,7 +428,7 @@ const alerts_summary = [
428 manager_name: "ASHWZHMA",
429 location: "EventChannel",
430 data_win_eventdata_targetProcessId: "4384",
416 - rule_group3: "windows",
431 + rule_group3: AlertSourceDataLogsourceProduct.Windows,
432 data_win_system_message:
433 '"Process accessed:\r\nRuleName: technique_id=T1036,technique_name=Masquerading\r\nUtcTime: 2023-11-05 12:23:11.137\r\nSourceProcessGUID: {d9ab9ebb-7e1a-6544-44e0-010000003000}\r\nSourceProcessId: 1652\r\nSourceThreadId: 1284\r\nSourceImage: C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe\r\nTargetProcessGUID: {d9ab9ebb-62bb-6547-601c-020000003000}\r\nTargetProcessId: 4384\r\nTargetImage: C:\\Windows\\explorer.exe\r\nGrantedAccess: 0x40\r\nCallTrace: C:\\Windows\\SYSTEM32\\ntdll.dll+9ff24|C:\\Windows\\System32\\KERNELBASE.dll+1668e|C:\\Windows\\System32\\shcore.dll+cca8|C:\\Windows\\System32\\shcore.dll+b55c|C:\\Windows\\System32\\shcore.dll+b275|C:\\Windows\\System32\\shcore.dll+b209|C:\\Windows\\System32\\shcore.dll+b104|C:\\Windows\\system32\\explorerframe.dll+12b986|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+157bd8c|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+18051ce|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+2e1a17|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+2dfdfe|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+130216a|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+a566ec|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+a5695f|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+3c3e93b|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+3c40433|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+3fbdb8e|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+3d62541|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+3fbdb68|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+3c942dd|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+3c3db94|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+a52491|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+a3e4a9\r\nSourceUser: WEB1\\Administrator\r\nTargetUser: WEB1\\Administrator"',
434 data_win_eventdata_sourceThreadId: "1284",
@@ -449,7 +464,7 @@ const alerts_summary = [
464 data_counter: "8287",
465 data_columns_duration: "132210",
466 timestamp_utc: "2023-11-05T10:22:52.000Z",
452 - syslog_type: "wazuh",
467 + syslog_type: AlertSourceSyslogType.Wazuh,
468 process_name: "/usr/bin/chmod",
469 process_cmd_line: "chmod +r /var/lib/update-notifier/updates-available",
470 data_hostIdentifier: "ip-178-216-201-141",
@@ -477,10 +492,10 @@ const alerts_summary = [
492 rule_firedtimes: 1,
493 rule_mail: true,
494 data_name: "bpf_process_events",
480 - decoder_name: "json",
495 + decoder_name: AlertSourceDecoderName.JSON,
496 agent_ip_country_code: "PL",
497 data_columns_ntime: "3515969404589692",
483 - syslog_level: "ALERT",
498 + syslog_level: AlertSourceSyslogLevel.Alert,
499 timestamp: "2023-11-05 10:22:56.651",
500 data_columns_cmdline: "chmod +r /var/lib/update-notifier/updates-available",
501 data_columns_tid: "3565780",
@@ -528,15 +543,15 @@ const alerts_summary = [
543 source: "10.255.255.13",
544 gl2_source_input: "6459151dea00fd5d3da2df91",
545 rule_level: 12,
531 - data_level: "high",
546 + data_level: AlertSourceDataLevelEnum.High,
547 timestamp_utc: "2023-11-05T12:16:02.043Z",
548 data_event_ProcessId: "4684",
534 - syslog_type: "wazuh",
549 + syslog_type: AlertSourceSyslogType.Wazuh,
550 data_system_Opcode: "0",
551 rule_description: "Process Explorer Driver Creation By Non-Sysinternals Binary",
552 gl2_source_node: "809d9894-1865-4ac7-8204-3226c347cb38",
553 id: "1699186616.690805701",
539 - data_status: "experimental",
554 + data_status: AlertSourceDataStatus.Experimental,
555 data_system_Computer: "ANSYDWDC01.ANMS.LOCAL",
556 gl2_accounted_message_size: 10712,
557 data_document:
@@ -544,7 +559,7 @@ const alerts_summary = [
559 data_event_UtcTime: "2023-11-05 12:16:02.043",
560 streams: ["645a3a6123e5cc30bbc0e5dc"],
561 gl2_message_id: "01HEFPMAE4N8YW57K4Q6P44CKB",
547 - data_source: "sigma",
562 + data_source: AlertSourceDataLogsourceProduct.Sigma,
563 agent_ip: "139.180.134.102",
564 data_system_Security_attributes_UserID: "S-1-5-18",
565 true: 1699186616.142398,
@@ -557,24 +572,24 @@ const alerts_summary = [
572 process_id: "4684",
573 data_system_TimeCreated_attributes_SystemTime: "2023-11-05T12:16:02.045670Z",
574 data_event_RuleName: "-",
560 - data_logsource_category: "file_event",
575 + data_logsource_category: AlertSourceDataLogsourceCategory.FileEvent,
576 data_system_Keywords: "0x8000000000000000",
577 sigma_name_encoded: "Process%20Explorer%20Driver%20Creation%20By%20Non-Sysinternals%20Binary",
578 agent_ip_geolocation: "1.3078,103.6818",
564 - data_group: "Sigma",
579 + data_group: AlertSourceDataGroup.Sigma,
580 rule_firedtimes: 1,
581 data_event_User: "NT AUTHORITY\\SYSTEM",
582 data_path: "C:\\Windows\\System32\\winevt\\Logs\\Microsoft-Windows-Sysmon%4Operational.evtx",
583 rule_mail: true,
584 data_system_Provider_attributes_Name: "Microsoft-Windows-Sysmon",
585 data_name: "Process Explorer Driver Creation By Non-Sysinternals Binary",
571 - decoder_name: "json",
586 + decoder_name: AlertSourceDecoderName.JSON,
587 data_id: "de46c52b-0bf8-4936-a327-aace94f94ac6",
588 agent_ip_country_code: "SG",
574 - syslog_level: "ALERT",
589 + syslog_level: AlertSourceSyslogLevel.Alert,
590 data_tags: "attack.persistence, attack.privilege_escalation, attack.t1068",
576 - data_kind: "individual",
577 - data_logsource_product: "windows",
591 + data_kind: AlertSourceDataKind.Individual,
592 + data_logsource_product: AlertSourceDataLogsourceProduct.Windows,
593 timestamp: "2023-11-05 12:16:56.772",
594 ask_socfortress_message:
595 "The SIGMA alert \"Process Explorer Driver Creation By Non-Sysinternals Binary\" suggests that a non-Sysinternals binary has attempted to create a Process Explorer driver on a Windows endpoint. Process Explorer is a widely used system monitoring tool developed by Sysinternals (now part of Microsoft). The creation of a Process Explorer driver by a non-Sysinternals binary could indicate suspicious or potentially malicious activity.\n\nTo investigate this alert and determine an appropriate response, you should focus on the following key aspects:\n\n1. Validate the Alert: Verify the accuracy of the alert by checking if it was triggered by legitimate activity or if it is a false positive. Ensure that your detection system is properly configured and up to date.\n\n2. Identify the Binary: Determine which specific binary attempted to create the Process Explorer driver. Look for any unusual or suspicious characteristics such as unfamiliar names, file paths, digital signatures, or hash values.\n\n3. Analyze Process Execution Context: Investigate the context in which the binary executed and attempted to create the driver. Review process execution details, such as parent processes, command-line arguments, process creation time, and associated network connections.\n\n4. Assess System Impact: Evaluate whether any abnormal behavior occurred on the endpoint after this event took place. Look for signs of system instability, crashes, performance degradation, or other anomalous activities that may indicate malicious intent.\n\n5. Conduct File Analysis: Perform an in-depth analysis of the binary itself using appropriate tools like antivirus scanners and sandboxing environments to identify any malware indicators such as malicious code patterns or known signatures associated with malware families.\n\n6. Check Reputation: Research information about the binary's reputation online using threat intelligence platforms, virus total scanners, or security forums to determine if it has been previously identified as malicious.\n\n7. Perform Behavioral Analysis: If feasible, conduct dynamic analysis by executing the binary in an isolated environment while monitoring its behavior for any suspicious activities like network communication, file system changes, or attempts to escalate privileges.\n\n8. Review System Logs: Examine relevant logs such as event logs, process creation logs, driver loading logs, and network logs to identify any additional indicators of compromise or related activities.\n\nWhen assessing this alert, you should also ask yourself the following additional questions:\n\n1. Is the binary a legitimate tool that is commonly used in your organization? If not, why would it be present on the endpoint?\n\n2. Is there a business justification for creating a Process Explorer driver with this specific binary? Are there any documented cases or known legitimate reasons for doing so?\n\n3. Are there any other security events or alerts related to this binary or associated processes that can provide further context?\n\n4. Has the binary been whitelisted or approved by your organization's security policies? If not, why was it allowed to execute on the endpoint?\n\n5. Do you have sufficient visibility into other endpoints within your environment? Have similar events been observed elsewhere? This could indicate a larger-scale attack.\n\nRemember that each investigation may vary based on your organization's specific context and requirements.",
@@ -597,7 +612,7 @@ const alerts_summary = [
612 data_event_TargetFilename: "C:\\Windows\\System32\\drivers\\PROCEXP152.SYS",
613 location: "active-response\\active-responses.log",
614 data_authors: "Florian Roth (Nextron Systems)",
600 - rule_group3: "sigma",
615 + rule_group3: AlertSourceDataLogsourceProduct.Sigma,
616 msg_timestamp: "2023-11-05T12:16:56.030Z",
617 rule_group2: "chainsaw",
618 rule_group1: "windows"
@@ -622,15 +637,15 @@ const alerts_summary = [
637 source: "10.255.255.13",
638 gl2_source_input: "6459151dea00fd5d3da2df91",
639 rule_level: 12,
625 - data_level: "high",
640 + data_level: AlertSourceDataLevelEnum.High,
641 timestamp_utc: "2023-11-05T12:16:02.043Z",
642 data_event_ProcessId: "4684",
628 - syslog_type: "wazuh",
643 + syslog_type: AlertSourceSyslogType.Wazuh,
644 data_system_Opcode: "0",
645 rule_description: "Process Explorer Driver Creation By Non-Sysinternals Binary",
646 gl2_source_node: "809d9894-1865-4ac7-8204-3226c347cb38",
647 id: "1699187457.705230523",
633 - data_status: "experimental",
648 + data_status: AlertSourceDataStatus.Experimental,
649 data_system_Computer: "ANSYDWDC01.ANMS.LOCAL",
650 gl2_accounted_message_size: 10712,
651 data_document:
@@ -638,7 +653,7 @@ const alerts_summary = [
653 data_event_UtcTime: "2023-11-05 12:16:02.043",
654 streams: ["645a3a6123e5cc30bbc0e5dc"],
655 gl2_message_id: "01HEFQE3FX6ARYDEQYMHJPGTE9",
641 - data_source: "sigma",
656 + data_source: AlertSourceDataLogsourceProduct.Sigma,
657 agent_ip: "139.180.134.102",
658 data_system_Security_attributes_UserID: "S-1-5-18",
659 true: 1699187457.773739,
@@ -651,24 +666,24 @@ const alerts_summary = [
666 process_id: "4684",
667 data_system_TimeCreated_attributes_SystemTime: "2023-11-05T12:16:02.045670Z",
668 data_event_RuleName: "-",
654 - data_logsource_category: "file_event",
669 + data_logsource_category: AlertSourceDataLogsourceCategory.FileEvent,
670 data_system_Keywords: "0x8000000000000000",
671 sigma_name_encoded: "Process%20Explorer%20Driver%20Creation%20By%20Non-Sysinternals%20Binary",
672 agent_ip_geolocation: "1.3078,103.6818",
658 - data_group: "Sigma",
673 + data_group: AlertSourceDataGroup.Sigma,
674 rule_firedtimes: 2,
675 data_event_User: "NT AUTHORITY\\SYSTEM",
676 data_path: "C:\\Windows\\System32\\winevt\\Logs\\Microsoft-Windows-Sysmon%4Operational.evtx",
677 rule_mail: true,
678 data_system_Provider_attributes_Name: "Microsoft-Windows-Sysmon",
679 data_name: "Process Explorer Driver Creation By Non-Sysinternals Binary",
665 - decoder_name: "json",
680 + decoder_name: AlertSourceDecoderName.JSON,
681 data_id: "de46c52b-0bf8-4936-a327-aace94f94ac6",
682 agent_ip_country_code: "SG",
668 - syslog_level: "ALERT",
683 + syslog_level: AlertSourceSyslogLevel.Alert,
684 data_tags: "attack.persistence, attack.privilege_escalation, attack.t1068",
670 - data_kind: "individual",
671 - data_logsource_product: "windows",
685 + data_kind: AlertSourceDataKind.Individual,
686 + data_logsource_product: AlertSourceDataLogsourceProduct.Windows,
687 timestamp: "2023-11-05 12:31:01.629",
688 ask_socfortress_message:
689 "The SIGMA alert \"Process Explorer Driver Creation By Non-Sysinternals Binary\" suggests that a non-Sysinternals binary has attempted to create a Process Explorer driver on a Windows endpoint. Process Explorer is a widely used system monitoring tool developed by Sysinternals (now part of Microsoft). The creation of a Process Explorer driver by a non-Sysinternals binary could indicate suspicious or potentially malicious activity.\n\nTo investigate this alert and determine an appropriate response, you should focus on the following key aspects:\n\n1. Validate the Alert: Verify the accuracy of the alert by checking if it was triggered by legitimate activity or if it is a false positive. Ensure that your detection system is properly configured and up to date.\n\n2. Identify the Binary: Determine which specific binary attempted to create the Process Explorer driver. Look for any unusual or suspicious characteristics such as unfamiliar names, file paths, digital signatures, or hash values.\n\n3. Analyze Process Execution Context: Investigate the context in which the binary executed and attempted to create the driver. Review process execution details, such as parent processes, command-line arguments, process creation time, and associated network connections.\n\n4. Assess System Impact: Evaluate whether any abnormal behavior occurred on the endpoint after this event took place. Look for signs of system instability, crashes, performance degradation, or other anomalous activities that may indicate malicious intent.\n\n5. Conduct File Analysis: Perform an in-depth analysis of the binary itself using appropriate tools like antivirus scanners and sandboxing environments to identify any malware indicators such as malicious code patterns or known signatures associated with malware families.\n\n6. Check Reputation: Research information about the binary's reputation online using threat intelligence platforms, virus total scanners, or security forums to determine if it has been previously identified as malicious.\n\n7. Perform Behavioral Analysis: If feasible, conduct dynamic analysis by executing the binary in an isolated environment while monitoring its behavior for any suspicious activities like network communication, file system changes, or attempts to escalate privileges.\n\n8. Review System Logs: Examine relevant logs such as event logs, process creation logs, driver loading logs, and network logs to identify any additional indicators of compromise or related activities.\n\nWhen assessing this alert, you should also ask yourself the following additional questions:\n\n1. Is the binary a legitimate tool that is commonly used in your organization? If not, why would it be present on the endpoint?\n\n2. Is there a business justification for creating a Process Explorer driver with this specific binary? Are there any documented cases or known legitimate reasons for doing so?\n\n3. Are there any other security events or alerts related to this binary or associated processes that can provide further context?\n\n4. Has the binary been whitelisted or approved by your organization's security policies? If not, why was it allowed to execute on the endpoint?\n\n5. Do you have sufficient visibility into other endpoints within your environment? Have similar events been observed elsewhere? This could indicate a larger-scale attack.\n\nRemember that each investigation may vary based on your organization's specific context and requirements.",
@@ -691,7 +706,7 @@ const alerts_summary = [
706 data_event_TargetFilename: "C:\\Windows\\System32\\drivers\\PROCEXP152.SYS",
707 location: "active-response\\active-responses.log",
708 data_authors: "Florian Roth (Nextron Systems)",
694 - rule_group3: "sigma",
709 + rule_group3: AlertSourceDataLogsourceProduct.Sigma,
710 msg_timestamp: "2023-11-05T12:30:57.704Z",
711 rule_group2: "chainsaw",
712 rule_group1: "windows"
@@ -716,15 +731,15 @@ const alerts_summary = [
731 source: "10.255.255.13",
732 gl2_source_input: "6459151dea00fd5d3da2df91",
733 rule_level: 12,
719 - data_level: "high",
734 + data_level: AlertSourceDataLevelEnum.High,
735 timestamp_utc: "2023-11-05T11:16:02.307Z",
736 data_event_ProcessId: "6712",
722 - syslog_type: "wazuh",
737 + syslog_type: AlertSourceSyslogType.Wazuh,
738 data_system_Opcode: "0",
739 rule_description: "Process Explorer Driver Creation By Non-Sysinternals Binary",
740 gl2_source_node: "809d9894-1865-4ac7-8204-3226c347cb38",
741 id: "1699183014.641989382",
727 - data_status: "experimental",
742 + data_status: AlertSourceDataStatus.Experimental,
743 data_system_Computer: "ANSYDWDC01.ANMS.LOCAL",
744 gl2_accounted_message_size: 10712,
745 data_document:
@@ -732,7 +747,7 @@ const alerts_summary = [
747 data_event_UtcTime: "2023-11-05 11:16:02.307",
748 streams: ["645a3a6123e5cc30bbc0e5dc"],
749 gl2_message_id: "01HEFK6ESE3ZHZY3GH5THZQ7VS",
735 - data_source: "sigma",
750 + data_source: AlertSourceDataLogsourceProduct.Sigma,
751 agent_ip: "139.180.134.102",
752 data_system_Security_attributes_UserID: "S-1-5-18",
753 true: 1699183014.546914,
@@ -745,24 +760,24 @@ const alerts_summary = [
760 process_id: "6712",
761 data_system_TimeCreated_attributes_SystemTime: "2023-11-05T11:16:02.321071Z",
762 data_event_RuleName: "-",
748 - data_logsource_category: "file_event",
763 + data_logsource_category: AlertSourceDataLogsourceCategory.FileEvent,
764 data_system_Keywords: "0x8000000000000000",
765 sigma_name_encoded: "Process%20Explorer%20Driver%20Creation%20By%20Non-Sysinternals%20Binary",
766 agent_ip_geolocation: "1.3078,103.6818",
752 - data_group: "Sigma",
767 + data_group: AlertSourceDataGroup.Sigma,
768 rule_firedtimes: 1,
769 data_event_User: "NT AUTHORITY\\SYSTEM",
770 data_path: "C:\\Windows\\System32\\winevt\\Logs\\Microsoft-Windows-Sysmon%4Operational.evtx",
771 rule_mail: true,
772 data_system_Provider_attributes_Name: "Microsoft-Windows-Sysmon",
773 data_name: "Process Explorer Driver Creation By Non-Sysinternals Binary",
759 - decoder_name: "json",
774 + decoder_name: AlertSourceDecoderName.JSON,
775 data_id: "de46c52b-0bf8-4936-a327-aace94f94ac6",
776 agent_ip_country_code: "SG",
762 - syslog_level: "ALERT",
777 + syslog_level: AlertSourceSyslogLevel.Alert,
778 data_tags: "attack.persistence, attack.privilege_escalation, attack.t1068",
764 - data_kind: "individual",
765 - data_logsource_product: "windows",
779 + data_kind: AlertSourceDataKind.Individual,
780 + data_logsource_product: AlertSourceDataLogsourceProduct.Windows,
781 timestamp: "2023-11-05 11:16:56.750",
782 ask_socfortress_message:
783 "The SIGMA alert \"Process Explorer Driver Creation By Non-Sysinternals Binary\" suggests that a non-Sysinternals binary has attempted to create a Process Explorer driver on a Windows endpoint. Process Explorer is a widely used system monitoring tool developed by Sysinternals (now part of Microsoft). The creation of a Process Explorer driver by a non-Sysinternals binary could indicate suspicious or potentially malicious activity.\n\nTo investigate this alert and determine an appropriate response, you should focus on the following key aspects:\n\n1. Validate the Alert: Verify the accuracy of the alert by checking if it was triggered by legitimate activity or if it is a false positive. Ensure that your detection system is properly configured and up to date.\n\n2. Identify the Binary: Determine which specific binary attempted to create the Process Explorer driver. Look for any unusual or suspicious characteristics such as unfamiliar names, file paths, digital signatures, or hash values.\n\n3. Analyze Process Execution Context: Investigate the context in which the binary executed and attempted to create the driver. Review process execution details, such as parent processes, command-line arguments, process creation time, and associated network connections.\n\n4. Assess System Impact: Evaluate whether any abnormal behavior occurred on the endpoint after this event took place. Look for signs of system instability, crashes, performance degradation, or other anomalous activities that may indicate malicious intent.\n\n5. Conduct File Analysis: Perform an in-depth analysis of the binary itself using appropriate tools like antivirus scanners and sandboxing environments to identify any malware indicators such as malicious code patterns or known signatures associated with malware families.\n\n6. Check Reputation: Research information about the binary's reputation online using threat intelligence platforms, virus total scanners, or security forums to determine if it has been previously identified as malicious.\n\n7. Perform Behavioral Analysis: If feasible, conduct dynamic analysis by executing the binary in an isolated environment while monitoring its behavior for any suspicious activities like network communication, file system changes, or attempts to escalate privileges.\n\n8. Review System Logs: Examine relevant logs such as event logs, process creation logs, driver loading logs, and network logs to identify any additional indicators of compromise or related activities.\n\nWhen assessing this alert, you should also ask yourself the following additional questions:\n\n1. Is the binary a legitimate tool that is commonly used in your organization? If not, why would it be present on the endpoint?\n\n2. Is there a business justification for creating a Process Explorer driver with this specific binary? Are there any documented cases or known legitimate reasons for doing so?\n\n3. Are there any other security events or alerts related to this binary or associated processes that can provide further context?\n\n4. Has the binary been whitelisted or approved by your organization's security policies? If not, why was it allowed to execute on the endpoint?\n\n5. Do you have sufficient visibility into other endpoints within your environment? Have similar events been observed elsewhere? This could indicate a larger-scale attack.\n\nRemember that each investigation may vary based on your organization's specific context and requirements.",
@@ -785,7 +800,7 @@ const alerts_summary = [
800 data_event_TargetFilename: "C:\\Windows\\System32\\drivers\\PROCEXP152.SYS",
801 location: "active-response\\active-responses.log",
802 data_authors: "Florian Roth (Nextron Systems)",
788 - rule_group3: "sigma",
803 + rule_group3: AlertSourceDataLogsourceProduct.Sigma,
804 msg_timestamp: "2023-11-05T11:16:54.542Z",
805 rule_group2: "chainsaw",
806 rule_group1: "windows"
@@ -810,15 +825,15 @@ const alerts_summary = [
825 source: "10.255.255.13",
826 gl2_source_input: "6459151dea00fd5d3da2df91",
827 rule_level: 12,
813 - data_level: "high",
828 + data_level: AlertSourceDataLevelEnum.High,
829 timestamp_utc: "2023-11-05T11:16:02.307Z",
830 data_event_ProcessId: "6712",
816 - syslog_type: "wazuh",
831 + syslog_type: AlertSourceSyslogType.Wazuh,
832 data_system_Opcode: "0",
833 rule_description: "Process Explorer Driver Creation By Non-Sysinternals Binary",
834 gl2_source_node: "809d9894-1865-4ac7-8204-3226c347cb38",
835 id: "1699183862.653635812",
821 - data_status: "experimental",
836 + data_status: AlertSourceDataStatus.Experimental,
837 data_system_Computer: "ANSYDWDC01.ANMS.LOCAL",
838 gl2_accounted_message_size: 10712,
839 data_document:
@@ -826,7 +841,7 @@ const alerts_summary = [
841 data_event_UtcTime: "2023-11-05 11:16:02.307",
842 streams: ["645a3a6123e5cc30bbc0e5dc"],
843 gl2_message_id: "01HEFM0CR3M66JCE9GK8X0BSHV",
829 - data_source: "sigma",
844 + data_source: AlertSourceDataLogsourceProduct.Sigma,
845 agent_ip: "139.180.134.102",
846 data_system_Security_attributes_UserID: "S-1-5-18",
847 true: 1699183863.254522,
@@ -839,24 +854,24 @@ const alerts_summary = [
854 process_id: "6712",
855 data_system_TimeCreated_attributes_SystemTime: "2023-11-05T11:16:02.321071Z",
856 data_event_RuleName: "-",
842 - data_logsource_category: "file_event",
857 + data_logsource_category: AlertSourceDataLogsourceCategory.FileEvent,
858 data_system_Keywords: "0x8000000000000000",
859 sigma_name_encoded: "Process%20Explorer%20Driver%20Creation%20By%20Non-Sysinternals%20Binary",
860 agent_ip_geolocation: "1.3078,103.6818",
846 - data_group: "Sigma",
861 + data_group: AlertSourceDataGroup.Sigma,
862 rule_firedtimes: 2,
863 data_event_User: "NT AUTHORITY\\SYSTEM",
864 data_path: "C:\\Windows\\System32\\winevt\\Logs\\Microsoft-Windows-Sysmon%4Operational.evtx",
865 rule_mail: true,
866 data_system_Provider_attributes_Name: "Microsoft-Windows-Sysmon",
867 data_name: "Process Explorer Driver Creation By Non-Sysinternals Binary",
853 - decoder_name: "json",
868 + decoder_name: AlertSourceDecoderName.JSON,
869 data_id: "de46c52b-0bf8-4936-a327-aace94f94ac6",
870 agent_ip_country_code: "SG",
856 - syslog_level: "ALERT",
871 + syslog_level: AlertSourceSyslogLevel.Alert,
872 data_tags: "attack.persistence, attack.privilege_escalation, attack.t1068",
858 - data_kind: "individual",
859 - data_logsource_product: "windows",
873 + data_kind: AlertSourceDataKind.Individual,
874 + data_logsource_product: AlertSourceDataLogsourceProduct.Windows,
875 timestamp: "2023-11-05 11:31:06.627",
876 ask_socfortress_message:
877 "The SIGMA alert \"Process Explorer Driver Creation By Non-Sysinternals Binary\" suggests that a non-Sysinternals binary has attempted to create a Process Explorer driver on a Windows endpoint. Process Explorer is a widely used system monitoring tool developed by Sysinternals (now part of Microsoft). The creation of a Process Explorer driver by a non-Sysinternals binary could indicate suspicious or potentially malicious activity.\n\nTo investigate this alert and determine an appropriate response, you should focus on the following key aspects:\n\n1. Validate the Alert: Verify the accuracy of the alert by checking if it was triggered by legitimate activity or if it is a false positive. Ensure that your detection system is properly configured and up to date.\n\n2. Identify the Binary: Determine which specific binary attempted to create the Process Explorer driver. Look for any unusual or suspicious characteristics such as unfamiliar names, file paths, digital signatures, or hash values.\n\n3. Analyze Process Execution Context: Investigate the context in which the binary executed and attempted to create the driver. Review process execution details, such as parent processes, command-line arguments, process creation time, and associated network connections.\n\n4. Assess System Impact: Evaluate whether any abnormal behavior occurred on the endpoint after this event took place. Look for signs of system instability, crashes, performance degradation, or other anomalous activities that may indicate malicious intent.\n\n5. Conduct File Analysis: Perform an in-depth analysis of the binary itself using appropriate tools like antivirus scanners and sandboxing environments to identify any malware indicators such as malicious code patterns or known signatures associated with malware families.\n\n6. Check Reputation: Research information about the binary's reputation online using threat intelligence platforms, virus total scanners, or security forums to determine if it has been previously identified as malicious.\n\n7. Perform Behavioral Analysis: If feasible, conduct dynamic analysis by executing the binary in an isolated environment while monitoring its behavior for any suspicious activities like network communication, file system changes, or attempts to escalate privileges.\n\n8. Review System Logs: Examine relevant logs such as event logs, process creation logs, driver loading logs, and network logs to identify any additional indicators of compromise or related activities.\n\nWhen assessing this alert, you should also ask yourself the following additional questions:\n\n1. Is the binary a legitimate tool that is commonly used in your organization? If not, why would it be present on the endpoint?\n\n2. Is there a business justification for creating a Process Explorer driver with this specific binary? Are there any documented cases or known legitimate reasons for doing so?\n\n3. Are there any other security events or alerts related to this binary or associated processes that can provide further context?\n\n4. Has the binary been whitelisted or approved by your organization's security policies? If not, why was it allowed to execute on the endpoint?\n\n5. Do you have sufficient visibility into other endpoints within your environment? Have similar events been observed elsewhere? This could indicate a larger-scale attack.\n\nRemember that each investigation may vary based on your organization's specific context and requirements.",
@@ -879,7 +894,7 @@ const alerts_summary = [
894 data_event_TargetFilename: "C:\\Windows\\System32\\drivers\\PROCEXP152.SYS",
895 location: "active-response\\active-responses.log",
896 data_authors: "Florian Roth (Nextron Systems)",
882 - rule_group3: "sigma",
897 + rule_group3: AlertSourceDataLogsourceProduct.Sigma,
898 msg_timestamp: "2023-11-05T11:31:02.897Z",
899 rule_group2: "chainsaw",
900 rule_group1: "windows"
@@ -904,15 +919,15 @@ const alerts_summary = [
919 source: "10.255.255.13",
920 gl2_source_input: "6459151dea00fd5d3da2df91",
921 rule_level: 12,
907 - data_level: "high",
922 + data_level: AlertSourceDataLevelEnum.High,
923 timestamp_utc: "2023-11-05T10:16:05.625Z",
924 data_event_ProcessId: "5020",
910 - syslog_type: "wazuh",
925 + syslog_type: AlertSourceSyslogType.Wazuh,
926 data_system_Opcode: "0",
927 rule_description: "Process Explorer Driver Creation By Non-Sysinternals Binary",
928 gl2_source_node: "809d9894-1865-4ac7-8204-3226c347cb38",
929 id: "1699179418.594692359",
915 - data_status: "experimental",
930 + data_status: AlertSourceDataStatus.Experimental,
931 data_system_Computer: "ANSYDWDC01.ANMS.LOCAL",
932 gl2_accounted_message_size: 11648,
933 data_document:
@@ -920,7 +935,7 @@ const alerts_summary = [
935 data_event_UtcTime: "2023-11-05 10:16:05.625",
936 streams: ["645a3a6123e5cc30bbc0e5dc"],
937 gl2_message_id: "01HEFFRR246C2SFHZZNDKNXRYP",
923 - data_source: "sigma",
938 + data_source: AlertSourceDataLogsourceProduct.Sigma,
939 agent_ip: "139.180.134.102",
940 data_system_Security_attributes_UserID: "S-1-5-18",
941 true: 1699179418.395436,
@@ -933,24 +948,24 @@ const alerts_summary = [
948 process_id: "5020",
949 data_system_TimeCreated_attributes_SystemTime: "2023-11-05T10:16:05.635338Z",
950 data_event_RuleName: "-",
936 - data_logsource_category: "file_event",
951 + data_logsource_category: AlertSourceDataLogsourceCategory.FileEvent,
952 data_system_Keywords: "0x8000000000000000",
953 sigma_name_encoded: "Process%20Explorer%20Driver%20Creation%20By%20Non-Sysinternals%20Binary",
954 agent_ip_geolocation: "1.3078,103.6818",
940 - data_group: "Sigma",
955 + data_group: AlertSourceDataGroup.Sigma,
956 rule_firedtimes: 1,
957 data_event_User: "NT AUTHORITY\\SYSTEM",
958 data_path: "C:\\Windows\\System32\\winevt\\Logs\\Microsoft-Windows-Sysmon%4Operational.evtx",
959 rule_mail: true,
960 data_system_Provider_attributes_Name: "Microsoft-Windows-Sysmon",
961 data_name: "Process Explorer Driver Creation By Non-Sysinternals Binary",
947 - decoder_name: "json",
962 + decoder_name: AlertSourceDecoderName.JSON,
963 data_id: "de46c52b-0bf8-4936-a327-aace94f94ac6",
964 agent_ip_country_code: "SG",
950 - syslog_level: "ALERT",
965 + syslog_level: AlertSourceSyslogLevel.Alert,
966 data_tags: "attack.persistence, attack.privilege_escalation, attack.t1068",
952 - data_kind: "individual",
953 - data_logsource_product: "windows",
967 + data_kind: AlertSourceDataKind.Individual,
968 + data_logsource_product: AlertSourceDataLogsourceProduct.Windows,
969 timestamp: "2023-11-05 10:17:01.764",
970 ask_socfortress_message:
971 "The SIGMA alert \"Process Explorer Driver Creation By Non-Sysinternals Binary\" indicates that a Windows endpoint has detected an instance where a process explorer driver was created by a binary that is not associated with Microsoft Sysinternals, a legitimate software tool widely used for system monitoring and troubleshooting.\n\nThis alert suggests the possibility of malicious activity on the endpoint. Attackers often leverage process explorer drivers or similar techniques to gain unauthorized access, elevate privileges, or hide their presence on a system. As such, it is important to thoroughly investigate this alert to determine the appropriate response.\n\nHere are key aspects you should investigate when responding to this alert:\n\n1. Endpoint Details: Gather information about the affected endpoint such as its hostname, IP address, operating system version, and any other relevant details. This information will help in understanding the context and potential impact of the alert.\n\n2. Timestamp and Correlation: Identify when the event occurred and check for any correlation with other security events or alerts on the same endpoint or across your environment. This can help determine if it's an isolated incident or part of a broader attack pattern.\n\n3. Process Explorer Driver: Determine which specific driver was created and by which binary it was created. Identify its location on disk and inspect its file properties (e.g., name, size, creation date). Compare these details against known legitimate drivers associated with Microsoft Sysinternals tools.\n\n4. Binary Analysis: Conduct further analysis of the non-Sysinternals binary responsible for creating the process explorer driver. Scan it using antivirus/anti-malware tools to identify any potential malicious behavior or indicators of compromise (IOCs). Consider submitting samples to threat intelligence platforms for additional analysis.\n\n5. Process Information: Examine details about the process associated with creating this driver (e.g., process ID (PID), parent PID) to understand how it was initiated and by what means.\n\n6. System Logs: Review relevant logs such as event logs, system logs, and security logs to identify any suspicious activities or additional indicators of compromise. Look for any abnormal system behavior or unauthorized modifications.\n\n7. User Context: Determine the user account associated with the process that initiated the driver creation. Check if it is a privileged account or a standard user account. If it is a privileged account, investigate whether this activity was expected and authorized.\n\n8. Network Activity: Analyze network traffic logs to identify any communication originating from the affected endpoint during or after the event. Look for connections to suspicious IP addresses, domains, or known command-and-control servers.\n\n9. Endpoint Security Posture: Evaluate the security controls deployed on the affected endpoint, such as antivirus/anti-malware software, intrusion prevention systems (IPS), host-based firewalls, and endpoint detection and response (EDR) solutions. Determine if these controls detected or blocked any malicious activity related to this alert.\n\n10. Incident Response Plan: Assess your organization's incident response plan and determine if there are predefined steps for responding to similar alerts like this one. Follow established procedures to contain the incident, mitigate risks, remediate affected systems, and prevent future occurrences.\n\nAdditional questions you should ask yourself when assessing this alert:\n\n1. Is there any legitimate reason for a non-Sysinternals binary to create a process explorer driver on this endpoint?\n2. Have there been any recent changes in software deployment or system configuration that could explain this alert?\n3. Are there other endpoints in your environment running similar binaries that could trigger similar alerts?\n4. Are there any recent reports of malware campaigns targeting process explorer drivers or abusing legitimate tools like Sysinternals?\n5. Are there any indicators suggesting compromise on this endpoint beyond just the creation of the driver?\n\nBy thoroughly investigating these aspects and considering additional relevant questions specific to your environment, you can make an informed decision about how best to respond to this SIGMA alert and mitigate potential risks.",
@@ -973,7 +988,7 @@ const alerts_summary = [
988 data_event_TargetFilename: "C:\\Windows\\System32\\drivers\\PROCEXP152.SYS",
989 location: "active-response\\active-responses.log",
990 data_authors: "Florian Roth (Nextron Systems)",
976 - rule_group3: "sigma",
991 + rule_group3: AlertSourceDataLogsourceProduct.Sigma,
992 msg_timestamp: "2023-11-05T10:16:58.328Z",
993 rule_group2: "chainsaw",
994 rule_group1: "windows"
@@ -1009,7 +1024,7 @@ const alerts_summary = [
1024 data_win_eventdata_company: "Microsoft Corporation",
1025 data_win_system_task: "1",
1026 timestamp_utc: "2023-11-05T12:34:39.363Z",
1012 - syslog_type: "wazuh",
1027 + syslog_type: AlertSourceSyslogType.Wazuh,
1028 data_win_system_threadID: "4928",
1029 rule_description: "Application Compatibility Database launched",
1030 data_win_eventdata_parentUser: "NT AUTHORITY\\\\SYSTEM",
@@ -1017,7 +1032,7 @@ const alerts_summary = [
1032 id: "1699187674.709551442",
1033 rule_mitre_tactic: "Privilege Escalation, Persistence",
1034 gl2_accounted_message_size: 7629,
1020 - data_win_eventdata_integrityLevel: "System",
1035 + data_win_eventdata_integrityLevel: AlertSourceDataWinEventdataIntegrityLevel.System,
1036 data_win_eventdata_utcTime: "2023-11-05 12:34:39.359",
1037 streams: ["650b315d5e9a2d550c6687ae"],
1038 rule_mitre_id: "T1546.011",
@@ -1039,17 +1054,17 @@ const alerts_summary = [
1054 data_win_eventdata_fileVersion: "10.0.22621.2361 (WinBuild.160101.0800)",
1055 data_win_eventdata_parentImage: "C:\\\\Windows\\\\System32\\\\svchost.exe",
1056 process_id: "7076",
1042 - data_win_system_severityValue: "INFORMATION",
1057 + data_win_system_severityValue: AlertSourceDataWinSystemSeverityValue.Information,
1058 data_win_eventdata_processGuid: "{10906cbf-8bdf-6547-fe84-010000000e00}",
1059 rule_mitre_technique: "Application Shimming",
1060 rule_firedtimes: 1,
1061 data_win_system_systemTime: "2023-11-05T12:34:39.3631014Z",
1062 rule_mail: true,
1048 - decoder_name: "windows_eventchannel",
1063 + decoder_name: AlertSourceDecoderName.WindowsEventchannel,
1064 data_win_eventdata_commandLine: "C:\\\\Windows\\\\System32\\\\sdbinst.exe -m -bg",
1065 data_win_system_processID: "3808",
1066 data_win_system_channel: "Microsoft-Windows-Sysmon/Operational",
1052 - syslog_level: "ALERT",
1067 + syslog_level: AlertSourceSyslogLevel.Alert,
1068 data_win_system_providerName: "Microsoft-Windows-Sysmon",
1069 data_win_eventdata_processId: "7076",
1070 data_win_system_version: "5",
@@ -1069,7 +1084,7 @@ const alerts_summary = [
1084 data_win_eventdata_logonGuid: "{10906cbf-9df1-6528-e703-000000000000}",
1085 data_win_eventdata_logonId: "0x3e7",
1086 location: "EventChannel",
1072 - rule_group3: "windows",
1087 + rule_group3: AlertSourceDataLogsourceProduct.Windows,
1088 data_win_system_message:
1089 '"Process Create:\r\nRuleName: technique_id=T1546.011,technique_name=Application Shimming\r\nUtcTime: 2023-11-05 12:34:39.359\r\nProcessGuid: {10906cbf-8bdf-6547-fe84-010000000e00}\r\nProcessId: 7076\r\nImage: C:\\Windows\\System32\\sdbinst.exe\r\nFileVersion: 10.0.22621.2361 (WinBuild.160101.0800)\r\nDescription: Application Compatibility Database Installer\r\nProduct: Microsoft® Windows® Operating System\r\nCompany: Microsoft Corporation\r\nOriginalFileName: sdbinst.exe\r\nCommandLine: C:\\Windows\\System32\\sdbinst.exe -m -bg\r\nCurrentDirectory: C:\\Windows\\system32\\\r\nUser: NT AUTHORITY\\SYSTEM\r\nLogonGuid: {10906cbf-9df1-6528-e703-000000000000}\r\nLogonId: 0x3E7\r\nTerminalSessionId: 0\r\nIntegrityLevel: System\r\nHashes: SHA1=C0C9554DCEBF89ABC7DA5332037BC2C88A3B0F1E,MD5=72A442005F409F233C223E60A7A0D868,SHA256=5913E1A6AC0D582A8710FFD723E16486A0E7C56C6122820175C4745C30816B77,IMPHASH=999B9DCD61DAB941B1E8D50FE6EF72CD\r\nParentProcessGuid: {10906cbf-9e07-6528-8600-000000000e00}\r\nParentProcessId: 5952\r\nParentImage: C:\\Windows\\System32\\svchost.exe\r\nParentCommandLine: C:\\Windows\\system32\\svchost.exe -k LocalSystemNetworkRestricted -p -s PcaSvc\r\nParentUser: NT AUTHORITY\\SYSTEM"',
1090 msg_timestamp: "2023-11-05T12:34:34.734Z",
@@ -1100,7 +1115,7 @@ const alerts_summary = [
1115 rule_level: 12,
1116 data_win_system_task: "0",
1117 timestamp_utc: "2023-11-05T11:42:41.269Z",
1103 - syslog_type: "wazuh",
1118 + syslog_type: AlertSourceSyslogType.Wazuh,
1119 data_win_system_threadID: "1424",
1120 rule_description:
1121 "Windows Defender: Antimalware platform detected potentially unwanted software ()",
@@ -1118,17 +1133,17 @@ const alerts_summary = [
1133 data_win_system_keywords: "0x8000000000000000",
1134 data_win_system_level: "3",
1135 process_id: "3772",
1121 - data_win_system_severityValue: "WARNING",
1136 + data_win_system_severityValue: AlertSourceDataWinSystemSeverityValue.Warning,
1137 rule_gdpr: "IV_35.7.d",
1138 rule_firedtimes: 1,
1139 data_win_system_systemTime: "2023-11-05T11:42:41.2693093Z",
1140 rule_mail: true,
1141 rule_pci_dss: "5.1, 5.2, 10.6.1, 11.4",
1142 rule_nist_800_53: "SI.3, AU.6, SI.4",
1128 - decoder_name: "windows_eventchannel",
1143 + decoder_name: AlertSourceDecoderName.WindowsEventchannel,
1144 data_win_system_processID: "3772",
1145 data_win_system_channel: "Microsoft-Windows-Windows Defender/Operational",
1131 - syslog_level: "ALERT",
1146 + syslog_level: AlertSourceSyslogLevel.Alert,
1147 data_win_system_providerName: "Microsoft-Windows-Windows Defender",
1148 data_win_system_version: "0",
1149 data_win_system_providerGuid: "{11cd958a-c507-4ef3-b3f2-5fd9dfbd2c78}",
@@ -1176,7 +1191,7 @@ const alerts_summary = [
1191 data_win_eventdata_company: "Microsoft Corporation",
1192 data_win_system_task: "1",
1193 timestamp_utc: "2023-11-05T11:34:39.282Z",
1179 - syslog_type: "wazuh",
1194 + syslog_type: AlertSourceSyslogType.Wazuh,
1195 data_win_system_threadID: "4928",
1196 rule_description: "Application Compatibility Database launched",
1197 data_win_eventdata_parentUser: "NT AUTHORITY\\\\SYSTEM",
@@ -1184,7 +1199,7 @@ const alerts_summary = [
1199 id: "1699184073.657048982",
1200 rule_mitre_tactic: "Privilege Escalation, Persistence",
1201 gl2_accounted_message_size: 7629,
1187 - data_win_eventdata_integrityLevel: "System",
1202 + data_win_eventdata_integrityLevel: AlertSourceDataWinEventdataIntegrityLevel.System,
1203 data_win_eventdata_utcTime: "2023-11-05 11:34:39.276",
1204 streams: ["650b315d5e9a2d550c6687ae"],
1205 rule_mitre_id: "T1546.011",
@@ -1206,17 +1221,17 @@ const alerts_summary = [
1221 data_win_eventdata_fileVersion: "10.0.22621.2361 (WinBuild.160101.0800)",
1222 data_win_eventdata_parentImage: "C:\\\\Windows\\\\System32\\\\svchost.exe",
1223 process_id: "1800",
1209 - data_win_system_severityValue: "INFORMATION",
1224 + data_win_system_severityValue: AlertSourceDataWinSystemSeverityValue.Information,
1225 data_win_eventdata_processGuid: "{10906cbf-7dcf-6547-6284-010000000e00}",
1226 rule_mitre_technique: "Application Shimming",
1227 rule_firedtimes: 1,
1228 data_win_system_systemTime: "2023-11-05T11:34:39.2824291Z",
1229 rule_mail: true,
1215 - decoder_name: "windows_eventchannel",
1230 + decoder_name: AlertSourceDecoderName.WindowsEventchannel,
1231 data_win_eventdata_commandLine: "C:\\\\Windows\\\\System32\\\\sdbinst.exe -m -bg",
1232 data_win_system_processID: "3808",
1233 data_win_system_channel: "Microsoft-Windows-Sysmon/Operational",
1219 - syslog_level: "ALERT",
1234 + syslog_level: AlertSourceSyslogLevel.Alert,
1235 data_win_system_providerName: "Microsoft-Windows-Sysmon",
1236 data_win_eventdata_processId: "1800",
1237 data_win_system_version: "5",
@@ -1236,7 +1251,7 @@ const alerts_summary = [
1251 data_win_eventdata_logonGuid: "{10906cbf-9df1-6528-e703-000000000000}",
1252 data_win_eventdata_logonId: "0x3e7",
1253 location: "EventChannel",
1239 - rule_group3: "windows",
1254 + rule_group3: AlertSourceDataLogsourceProduct.Windows,
1255 data_win_system_message:
1256 '"Process Create:\r\nRuleName: technique_id=T1546.011,technique_name=Application Shimming\r\nUtcTime: 2023-11-05 11:34:39.276\r\nProcessGuid: {10906cbf-7dcf-6547-6284-010000000e00}\r\nProcessId: 1800\r\nImage: C:\\Windows\\System32\\sdbinst.exe\r\nFileVersion: 10.0.22621.2361 (WinBuild.160101.0800)\r\nDescription: Application Compatibility Database Installer\r\nProduct: Microsoft® Windows® Operating System\r\nCompany: Microsoft Corporation\r\nOriginalFileName: sdbinst.exe\r\nCommandLine: C:\\Windows\\System32\\sdbinst.exe -m -bg\r\nCurrentDirectory: C:\\Windows\\system32\\\r\nUser: NT AUTHORITY\\SYSTEM\r\nLogonGuid: {10906cbf-9df1-6528-e703-000000000000}\r\nLogonId: 0x3E7\r\nTerminalSessionId: 0\r\nIntegrityLevel: System\r\nHashes: SHA1=C0C9554DCEBF89ABC7DA5332037BC2C88A3B0F1E,MD5=72A442005F409F233C223E60A7A0D868,SHA256=5913E1A6AC0D582A8710FFD723E16486A0E7C56C6122820175C4745C30816B77,IMPHASH=999B9DCD61DAB941B1E8D50FE6EF72CD\r\nParentProcessGuid: {10906cbf-9e07-6528-8600-000000000e00}\r\nParentProcessId: 5952\r\nParentImage: C:\\Windows\\System32\\svchost.exe\r\nParentCommandLine: C:\\Windows\\system32\\svchost.exe -k LocalSystemNetworkRestricted -p -s PcaSvc\r\nParentUser: NT AUTHORITY\\SYSTEM"',
1257 msg_timestamp: "2023-11-05T11:34:33.778Z",
@@ -1269,7 +1284,7 @@ const alerts_summary = [
1284 data_win_eventdata_company: "Microsoft Corporation",
1285 data_win_system_task: "1",
1286 timestamp_utc: "2023-11-05T10:34:39.227Z",
1272 - syslog_type: "wazuh",
1287 + syslog_type: AlertSourceSyslogType.Wazuh,
1288 data_win_system_threadID: "4928",
1289 rule_description: "Application Compatibility Database launched",
1290 data_win_eventdata_parentUser: "NT AUTHORITY\\\\SYSTEM",
@@ -1277,7 +1292,7 @@ const alerts_summary = [
1292 id: "1699180474.607950326",
1293 rule_mitre_tactic: "Privilege Escalation, Persistence",
1294 gl2_accounted_message_size: 7634,
1280 - data_win_eventdata_integrityLevel: "System",
1295 + data_win_eventdata_integrityLevel: AlertSourceDataWinEventdataIntegrityLevel.System,
1296 data_win_eventdata_utcTime: "2023-11-05 10:34:39.223",
1297 streams: ["650b315d5e9a2d550c6687ae"],
1298 rule_mitre_id: "T1546.011",
@@ -1299,17 +1314,17 @@ const alerts_summary = [
1314 data_win_eventdata_fileVersion: "10.0.22621.2361 (WinBuild.160101.0800)",
1315 data_win_eventdata_parentImage: "C:\\\\Windows\\\\System32\\\\svchost.exe",
1316 process_id: "10456",
1302 - data_win_system_severityValue: "INFORMATION",
1317 + data_win_system_severityValue: AlertSourceDataWinSystemSeverityValue.Information,
1318 data_win_eventdata_processGuid: "{10906cbf-6fbf-6547-bc83-010000000e00}",
1319 rule_mitre_technique: "Application Shimming",
1320 rule_firedtimes: 1,
1321 data_win_system_systemTime: "2023-11-05T10:34:39.2278008Z",
1322 rule_mail: true,
1308 - decoder_name: "windows_eventchannel",
1323 + decoder_name: AlertSourceDecoderName.WindowsEventchannel,
1324 data_win_eventdata_commandLine: "C:\\\\Windows\\\\System32\\\\sdbinst.exe -m -bg",
1325 data_win_system_processID: "3808",
1326 data_win_system_channel: "Microsoft-Windows-Sysmon/Operational",
1312 - syslog_level: "ALERT",
1327 + syslog_level: AlertSourceSyslogLevel.Alert,
1328 data_win_system_providerName: "Microsoft-Windows-Sysmon",
1329 data_win_eventdata_processId: "10456",
1330 data_win_system_version: "5",
@@ -1329,7 +1344,7 @@ const alerts_summary = [
1344 data_win_eventdata_logonGuid: "{10906cbf-9df1-6528-e703-000000000000}",
1345 data_win_eventdata_logonId: "0x3e7",
1346 location: "EventChannel",
1332 - rule_group3: "windows",
1347 + rule_group3: AlertSourceDataLogsourceProduct.Windows,
1348 data_win_system_message:
1349 '"Process Create:\r\nRuleName: technique_id=T1546.011,technique_name=Application Shimming\r\nUtcTime: 2023-11-05 10:34:39.223\r\nProcessGuid: {10906cbf-6fbf-6547-bc83-010000000e00}\r\nProcessId: 10456\r\nImage: C:\\Windows\\System32\\sdbinst.exe\r\nFileVersion: 10.0.22621.2361 (WinBuild.160101.0800)\r\nDescription: Application Compatibility Database Installer\r\nProduct: Microsoft® Windows® Operating System\r\nCompany: Microsoft Corporation\r\nOriginalFileName: sdbinst.exe\r\nCommandLine: C:\\Windows\\System32\\sdbinst.exe -m -bg\r\nCurrentDirectory: C:\\Windows\\system32\\\r\nUser: NT AUTHORITY\\SYSTEM\r\nLogonGuid: {10906cbf-9df1-6528-e703-000000000000}\r\nLogonId: 0x3E7\r\nTerminalSessionId: 0\r\nIntegrityLevel: System\r\nHashes: SHA1=C0C9554DCEBF89ABC7DA5332037BC2C88A3B0F1E,MD5=72A442005F409F233C223E60A7A0D868,SHA256=5913E1A6AC0D582A8710FFD723E16486A0E7C56C6122820175C4745C30816B77,IMPHASH=999B9DCD61DAB941B1E8D50FE6EF72CD\r\nParentProcessGuid: {10906cbf-9e07-6528-8600-000000000e00}\r\nParentProcessId: 5952\r\nParentImage: C:\\Windows\\System32\\svchost.exe\r\nParentCommandLine: C:\\Windows\\system32\\svchost.exe -k LocalSystemNetworkRestricted -p -s PcaSvc\r\nParentUser: NT AUTHORITY\\SYSTEM"',
1350 msg_timestamp: "2023-11-05T10:34:34.669Z",
@@ -1362,7 +1377,7 @@ const alerts_summary = [
1377 data_win_eventdata_company: "Microsoft Corporation",
1378 data_win_system_task: "1",
1379 timestamp_utc: "2023-11-05T09:34:39.164Z",
1365 - syslog_type: "wazuh",
1380 + syslog_type: AlertSourceSyslogType.Wazuh,
1381 data_win_system_threadID: "4928",
1382 rule_description: "Application Compatibility Database launched",
1383 data_win_eventdata_parentUser: "NT AUTHORITY\\\\SYSTEM",
@@ -1370,7 +1385,7 @@ const alerts_summary = [
1385 id: "1699176874.562050141",
1386 rule_mitre_tactic: "Privilege Escalation, Persistence",
1387 gl2_accounted_message_size: 7629,
1373 - data_win_eventdata_integrityLevel: "System",
1388 + data_win_eventdata_integrityLevel: AlertSourceDataWinEventdataIntegrityLevel.System,
1389 data_win_eventdata_utcTime: "2023-11-05 09:34:39.158",
1390 streams: ["650b315d5e9a2d550c6687ae"],
1391 rule_mitre_id: "T1546.011",
@@ -1392,17 +1407,17 @@ const alerts_summary = [
1407 data_win_eventdata_fileVersion: "10.0.22621.2361 (WinBuild.160101.0800)",
1408 data_win_eventdata_parentImage: "C:\\\\Windows\\\\System32\\\\svchost.exe",
1409 process_id: "1368",
1395 - data_win_system_severityValue: "INFORMATION",
1410 + data_win_system_severityValue: AlertSourceDataWinSystemSeverityValue.Information,
1411 data_win_eventdata_processGuid: "{10906cbf-61af-6547-4683-010000000e00}",
1412 rule_mitre_technique: "Application Shimming",
1413 rule_firedtimes: 1,
1414 data_win_system_systemTime: "2023-11-05T09:34:39.1640751Z",
1415 rule_mail: true,
1401 - decoder_name: "windows_eventchannel",
1416 + decoder_name: AlertSourceDecoderName.WindowsEventchannel,
1417 data_win_eventdata_commandLine: "C:\\\\Windows\\\\System32\\\\sdbinst.exe -m -bg",
1418 data_win_system_processID: "3808",
1419 data_win_system_channel: "Microsoft-Windows-Sysmon/Operational",
1405 - syslog_level: "ALERT",
1420 + syslog_level: AlertSourceSyslogLevel.Alert,
1421 data_win_system_providerName: "Microsoft-Windows-Sysmon",
1422 data_win_eventdata_processId: "1368",
1423 data_win_system_version: "5",
@@ -1422,7 +1437,7 @@ const alerts_summary = [
1437 data_win_eventdata_logonGuid: "{10906cbf-9df1-6528-e703-000000000000}",
1438 data_win_eventdata_logonId: "0x3e7",
1439 location: "EventChannel",
1425 - rule_group3: "windows",
1440 + rule_group3: AlertSourceDataLogsourceProduct.Windows,
1441 data_win_system_message:
1442 '"Process Create:\r\nRuleName: technique_id=T1546.011,technique_name=Application Shimming\r\nUtcTime: 2023-11-05 09:34:39.158\r\nProcessGuid: {10906cbf-61af-6547-4683-010000000e00}\r\nProcessId: 1368\r\nImage: C:\\Windows\\System32\\sdbinst.exe\r\nFileVersion: 10.0.22621.2361 (WinBuild.160101.0800)\r\nDescription: Application Compatibility Database Installer\r\nProduct: Microsoft® Windows® Operating System\r\nCompany: Microsoft Corporation\r\nOriginalFileName: sdbinst.exe\r\nCommandLine: C:\\Windows\\System32\\sdbinst.exe -m -bg\r\nCurrentDirectory: C:\\Windows\\system32\\\r\nUser: NT AUTHORITY\\SYSTEM\r\nLogonGuid: {10906cbf-9df1-6528-e703-000000000000}\r\nLogonId: 0x3E7\r\nTerminalSessionId: 0\r\nIntegrityLevel: System\r\nHashes: SHA1=C0C9554DCEBF89ABC7DA5332037BC2C88A3B0F1E,MD5=72A442005F409F233C223E60A7A0D868,SHA256=5913E1A6AC0D582A8710FFD723E16486A0E7C56C6122820175C4745C30816B77,IMPHASH=999B9DCD61DAB941B1E8D50FE6EF72CD\r\nParentProcessGuid: {10906cbf-9e07-6528-8600-000000000e00}\r\nParentProcessId: 5952\r\nParentImage: C:\\Windows\\System32\\svchost.exe\r\nParentCommandLine: C:\\Windows\\system32\\svchost.exe -k LocalSystemNetworkRestricted -p -s PcaSvc\r\nParentUser: NT AUTHORITY\\SYSTEM"',
1443 msg_timestamp: "2023-11-05T09:34:34.642Z",
@@ -1459,7 +1474,7 @@ const alerts_summary = [
1474 data_counter: "19295",
1475 data_columns_duration: "2809889",
1476 timestamp_utc: "2023-11-05T06:25:09.000Z",
1462 - syslog_type: "wazuh",
1477 + syslog_type: AlertSourceSyslogType.Wazuh,
1478 process_name: "/bin/dd",
1479 process_cmd_line: "dd if=/dev/urandom bs=2 count=1",
1480 data_hostIdentifier: "ssdnodes-zabbix",
@@ -1488,10 +1503,10 @@ const alerts_summary = [
1503 rule_firedtimes: 1,
1504 rule_mail: true,
1505 data_name: "bpf_process_events",
1491 - decoder_name: "json",
1506 + decoder_name: AlertSourceDecoderName.JSON,
1507 agent_ip_country_code: "AU",
1508 data_columns_ntime: "3024028081495260",
1494 - syslog_level: "ALERT",
1509 + syslog_level: AlertSourceSyslogLevel.Alert,
1510 timestamp: "2023-11-05 06:25:16.633",
1511 data_columns_cmdline: "dd if=/dev/urandom bs=2 count=1",
1512 data_columns_tid: "214456",
@@ -1536,7 +1551,7 @@ const alerts_summary = [
1551 data_counter: "18098",
1552 data_columns_duration: "134246",
1553 timestamp_utc: "2023-11-05T02:35:28.000Z",
1539 - syslog_type: "wazuh",
1554 + syslog_type: AlertSourceSyslogType.Wazuh,
1555 process_name: "/usr/bin/chmod",
1556 process_cmd_line: "chmod +r /var/lib/update-notifier/updates-available",
1557 data_hostIdentifier: "ssdnodes-zabbix",
@@ -1564,10 +1579,10 @@ const alerts_summary = [
1579 rule_firedtimes: 1,
1580 rule_mail: true,
1581 data_name: "bpf_process_events",
1567 - decoder_name: "json",
1582 + decoder_name: AlertSourceDecoderName.JSON,
1583 agent_ip_country_code: "AU",
1584 data_columns_ntime: "3010249590404014",
1570 - syslog_level: "ALERT",
1585 + syslog_level: AlertSourceSyslogLevel.Alert,
1586 timestamp: "2023-11-05 02:35:31.692",
1587 data_columns_cmdline: "chmod +r /var/lib/update-notifier/updates-available",
1588 data_columns_tid: "98594",
@@ -1619,7 +1634,7 @@ const alerts_summary = [
1634 data_win_eventdata_sourceUser: "WEB1\\\\Administrator",
1635 data_win_system_task: "10",
1636 timestamp_utc: "2023-11-05T12:57:26.938Z",
1622 - syslog_type: "wazuh",
1637 + syslog_type: AlertSourceSyslogType.Wazuh,
1638 data_win_system_threadID: "5576",
1639 rule_description:
1640 "Explorer process was accessed by C:\\\\Users\\\\Administrator\\\\AppData\\\\Roaming\\\\Telegram Desktop\\\\Telegram.exe, possible process injection",
@@ -1642,18 +1657,18 @@ const alerts_summary = [
1657 data_win_system_keywords: "0x8000000000000000",
1658 data_win_system_level: "4",
1659 data_win_eventdata_targetProcessGUID: "{d9ab9ebb-62bb-6547-601c-020000003000}",
1645 - data_win_system_severityValue: "INFORMATION",
1660 + data_win_system_severityValue: AlertSourceDataWinSystemSeverityValue.Information,
1661 data_win_eventdata_targetUser: "WEB1\\\\Administrator",
1662 agent_ip_geolocation: "16.1667,107.8333",
1663 rule_mitre_technique: "Process Injection",
1664 rule_firedtimes: 86,
1665 data_win_system_systemTime: "2023-11-05T12:57:26.938209400Z",
1666 rule_mail: true,
1652 - decoder_name: "windows_eventchannel",
1667 + decoder_name: AlertSourceDecoderName.WindowsEventchannel,
1668 agent_ip_country_code: "VN",
1669 data_win_system_processID: "3468",
1670 data_win_system_channel: "Microsoft-Windows-Sysmon/Operational",
1656 - syslog_level: "ALERT",
1671 + syslog_level: AlertSourceSyslogLevel.Alert,
1672 data_win_system_providerName: "Microsoft-Windows-Sysmon",
1673 data_win_system_version: "3",
1674 data_win_system_providerGuid: "{5770385f-c22a-43e0-bf4c-06f5698ffbd9}",
@@ -1670,7 +1685,7 @@ const alerts_summary = [
1685 manager_name: "ASHWZHMA",
1686 location: "EventChannel",
1687 data_win_eventdata_targetProcessId: "4384",
1673 - rule_group3: "windows",
1688 + rule_group3: AlertSourceDataLogsourceProduct.Windows,
1689 data_win_system_message:
1690 '"Process accessed:\r\nRuleName: technique_id=T1036,technique_name=Masquerading\r\nUtcTime: 2023-11-05 12:57:26.937\r\nSourceProcessGUID: {d9ab9ebb-7e1a-6544-44e0-010000003000}\r\nSourceProcessId: 1652\r\nSourceThreadId: 1284\r\nSourceImage: C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe\r\nTargetProcessGUID: {d9ab9ebb-62bb-6547-601c-020000003000}\r\nTargetProcessId: 4384\r\nTargetImage: C:\\Windows\\explorer.exe\r\nGrantedAccess: 0x40\r\nCallTrace: C:\\Windows\\SYSTEM32\\ntdll.dll+9ff24|C:\\Windows\\System32\\KERNELBASE.dll+1668e|C:\\Windows\\System32\\shcore.dll+cca8|C:\\Windows\\System32\\shcore.dll+ba62|C:\\Windows\\System32\\shcore.dll+b585|C:\\Windows\\System32\\shcore.dll+b275|C:\\Windows\\System32\\shcore.dll+b209|C:\\Windows\\System32\\shcore.dll+b104|C:\\Windows\\system32\\explorerframe.dll+12b986|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+157bd8c|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+18051ce|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+2e1a17|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+2dfdfe|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+130216a|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+a566ec|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+a5695f|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+3c3e93b|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+3c40433|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+3fbdb8e|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+3d62541|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+3fbdb68|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+3c942dd|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+3c3db94|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+a52491\r\nSourceUser: WEB1\\Administrator\r\nTargetUser: WEB1\\Administrator"',
1691 data_win_eventdata_sourceThreadId: "1284",
@@ -1702,7 +1717,7 @@ const alerts_summary = [
1717 data_win_eventdata_sourceUser: "WEB1\\\\Administrator",
1718 data_win_system_task: "10",
1719 timestamp_utc: "2023-11-05T12:57:26.938Z",
1705 - syslog_type: "wazuh",
1720 + syslog_type: AlertSourceSyslogType.Wazuh,
1721 data_win_system_threadID: "5576",
1722 rule_description:
1723 "Explorer process was accessed by C:\\\\Users\\\\Administrator\\\\AppData\\\\Roaming\\\\Telegram Desktop\\\\Telegram.exe, possible process injection",
@@ -1725,18 +1740,18 @@ const alerts_summary = [
1740 data_win_system_keywords: "0x8000000000000000",
1741 data_win_system_level: "4",
1742 data_win_eventdata_targetProcessGUID: "{d9ab9ebb-62bb-6547-601c-020000003000}",
1728 - data_win_system_severityValue: "INFORMATION",
1743 + data_win_system_severityValue: AlertSourceDataWinSystemSeverityValue.Information,
1744 data_win_eventdata_targetUser: "WEB1\\\\Administrator",
1745 agent_ip_geolocation: "16.1667,107.8333",
1746 rule_mitre_technique: "Process Injection",
1747 rule_firedtimes: 87,
1748 data_win_system_systemTime: "2023-11-05T12:57:26.938692200Z",
1749 rule_mail: true,
1735 - decoder_name: "windows_eventchannel",
1750 + decoder_name: AlertSourceDecoderName.WindowsEventchannel,
1751 agent_ip_country_code: "VN",
1752 data_win_system_processID: "3468",
1753 data_win_system_channel: "Microsoft-Windows-Sysmon/Operational",
1739 - syslog_level: "ALERT",
1754 + syslog_level: AlertSourceSyslogLevel.Alert,
1755 data_win_system_providerName: "Microsoft-Windows-Sysmon",
1756 data_win_system_version: "3",
1757 data_win_system_providerGuid: "{5770385f-c22a-43e0-bf4c-06f5698ffbd9}",
@@ -1753,7 +1768,7 @@ const alerts_summary = [
1768 manager_name: "ASHWZHMA",
1769 location: "EventChannel",
1770 data_win_eventdata_targetProcessId: "4384",
1756 - rule_group3: "windows",
1771 + rule_group3: AlertSourceDataLogsourceProduct.Windows,
1772 data_win_system_message:
1773 '"Process accessed:\r\nRuleName: technique_id=T1036,technique_name=Masquerading\r\nUtcTime: 2023-11-05 12:57:26.937\r\nSourceProcessGUID: {d9ab9ebb-7e1a-6544-44e0-010000003000}\r\nSourceProcessId: 1652\r\nSourceThreadId: 1284\r\nSourceImage: C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe\r\nTargetProcessGUID: {d9ab9ebb-62bb-6547-601c-020000003000}\r\nTargetProcessId: 4384\r\nTargetImage: C:\\Windows\\explorer.exe\r\nGrantedAccess: 0x40\r\nCallTrace: C:\\Windows\\SYSTEM32\\ntdll.dll+9ff24|C:\\Windows\\System32\\KERNELBASE.dll+1668e|C:\\Windows\\System32\\shcore.dll+cca8|C:\\Windows\\System32\\shcore.dll+ba77|C:\\Windows\\System32\\shcore.dll+b967|C:\\Windows\\System32\\shcore.dll+b8f1|C:\\Windows\\System32\\shcore.dll+b61a|C:\\Windows\\system32\\explorerframe.dll+12b9d0|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+157bd8c|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+18051ce|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+2e1a17|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+2dfdfe|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+130216a|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+a566ec|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+a5695f|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+3c3e93b|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+3c40433|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+3fbdb8e|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+3d62541|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+3fbdb68|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+3c942dd|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+3c3db94|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+a52491|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+a3e4a9\r\nSourceUser: WEB1\\Administrator\r\nTargetUser: WEB1\\Administrator"',
1774 data_win_eventdata_sourceThreadId: "1284",
@@ -1785,7 +1800,7 @@ const alerts_summary = [
1800 data_win_eventdata_sourceUser: "WEB1\\\\Administrator",
1801 data_win_system_task: "10",
1802 timestamp_utc: "2023-11-05T12:57:26.937Z",
1788 - syslog_type: "wazuh",
1803 + syslog_type: AlertSourceSyslogType.Wazuh,
1804 data_win_system_threadID: "5576",
1805 rule_description:
1806 "Explorer process was accessed by C:\\\\Users\\\\Administrator\\\\AppData\\\\Roaming\\\\Telegram Desktop\\\\Telegram.exe, possible process injection",
@@ -1808,18 +1823,18 @@ const alerts_summary = [
1823 data_win_system_keywords: "0x8000000000000000",
1824 data_win_system_level: "4",
1825 data_win_eventdata_targetProcessGUID: "{d9ab9ebb-62bb-6547-601c-020000003000}",
1811 - data_win_system_severityValue: "INFORMATION",
1826 + data_win_system_severityValue: AlertSourceDataWinSystemSeverityValue.Information,
1827 data_win_eventdata_targetUser: "WEB1\\\\Administrator",
1828 agent_ip_geolocation: "16.1667,107.8333",
1829 rule_mitre_technique: "Process Injection",
1830 rule_firedtimes: 85,
1831 data_win_system_systemTime: "2023-11-05T12:57:26.937850100Z",
1832 rule_mail: true,
1818 - decoder_name: "windows_eventchannel",
1833 + decoder_name: AlertSourceDecoderName.WindowsEventchannel,
1834 agent_ip_country_code: "VN",
1835 data_win_system_processID: "3468",
1836 data_win_system_channel: "Microsoft-Windows-Sysmon/Operational",
1822 - syslog_level: "ALERT",
1837 + syslog_level: AlertSourceSyslogLevel.Alert,
1838 data_win_system_providerName: "Microsoft-Windows-Sysmon",
1839 data_win_system_version: "3",
1840 data_win_system_providerGuid: "{5770385f-c22a-43e0-bf4c-06f5698ffbd9}",
@@ -1836,7 +1851,7 @@ const alerts_summary = [
1851 manager_name: "ASHWZHMA",
1852 location: "EventChannel",
1853 data_win_eventdata_targetProcessId: "4384",
1839 - rule_group3: "windows",
1854 + rule_group3: AlertSourceDataLogsourceProduct.Windows,
1855 data_win_system_message:
1856 '"Process accessed:\r\nRuleName: technique_id=T1036,technique_name=Masquerading\r\nUtcTime: 2023-11-05 12:57:26.937\r\nSourceProcessGUID: {d9ab9ebb-7e1a-6544-44e0-010000003000}\r\nSourceProcessId: 1652\r\nSourceThreadId: 1284\r\nSourceImage: C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe\r\nTargetProcessGUID: {d9ab9ebb-62bb-6547-601c-020000003000}\r\nTargetProcessId: 4384\r\nTargetImage: C:\\Windows\\explorer.exe\r\nGrantedAccess: 0x40\r\nCallTrace: C:\\Windows\\SYSTEM32\\ntdll.dll+9ff24|C:\\Windows\\System32\\KERNELBASE.dll+1668e|C:\\Windows\\System32\\shcore.dll+cca8|C:\\Windows\\System32\\shcore.dll+b55c|C:\\Windows\\System32\\shcore.dll+b275|C:\\Windows\\System32\\shcore.dll+b209|C:\\Windows\\System32\\shcore.dll+b104|C:\\Windows\\system32\\explorerframe.dll+12b986|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+157bd8c|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+18051ce|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+2e1a17|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+2dfdfe|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+130216a|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+a566ec|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+a5695f|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+3c3e93b|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+3c40433|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+3fbdb8e|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+3d62541|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+3fbdb68|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+3c942dd|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+3c3db94|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+a52491|C:\\Users\\Administrator\\AppData\\Roaming\\Telegram Desktop\\Telegram.exe+a3e4a9\r\nSourceUser: WEB1\\Administrator\r\nTargetUser: WEB1\\Administrator"',
1857 data_win_eventdata_sourceThreadId: "1284",
@@ -1868,7 +1883,7 @@ const alerts_summary = [
1883 data_win_eventdata_sourceUser: "NT AUTHORITY\\\\SYSTEM",
1884 data_win_system_task: "8",
1885 timestamp_utc: "2023-11-05T12:54:51.363Z",
1871 - syslog_type: "wazuh",
1886 + syslog_type: AlertSourceSyslogType.Wazuh,
1887 data_win_system_threadID: "5576",
1888 rule_description:
1889 "Possible code injection on explorer.exe by C:\\\\Program Files\\\\VMware\\\\VMware Tools\\\\vmtoolsd.exe",
@@ -1890,18 +1905,18 @@ const alerts_summary = [
1905 rule_groups: "sysmon, sysmon_eid8_detections, windows",
1906 data_win_system_keywords: "0x8000000000000000",
1907 data_win_system_level: "4",
1893 - data_win_system_severityValue: "INFORMATION",
1908 + data_win_system_severityValue: AlertSourceDataWinSystemSeverityValue.Information,
1909 data_win_eventdata_targetUser: "WEB1\\\\Administrator",
1910 agent_ip_geolocation: "16.1667,107.8333",
1911 rule_mitre_technique: "Process Injection",
1912 rule_firedtimes: 2,
1913 data_win_system_systemTime: "2023-11-05T12:54:51.363981300Z",
1914 rule_mail: true,
1900 - decoder_name: "windows_eventchannel",
1915 + decoder_name: AlertSourceDecoderName.WindowsEventchannel,
1916 agent_ip_country_code: "VN",
1917 data_win_system_processID: "3468",
1918 data_win_system_channel: "Microsoft-Windows-Sysmon/Operational",
1904 - syslog_level: "ALERT",
1919 + syslog_level: AlertSourceSyslogLevel.Alert,
1920 data_win_system_providerName: "Microsoft-Windows-Sysmon",
1921 data_win_system_version: "2",
1922 data_win_system_providerGuid: "{5770385f-c22a-43e0-bf4c-06f5698ffbd9}",
@@ -1919,7 +1934,7 @@ const alerts_summary = [
1934 location: "EventChannel",
1935 data_win_eventdata_targetProcessId: "4384",
1936 data_win_eventdata_startFunction: "GetCommandLineW",
1922 - rule_group3: "windows",
1937 + rule_group3: AlertSourceDataLogsourceProduct.Windows,
1938 data_win_system_message:
1939 '"CreateRemoteThread detected:\r\nRuleName: technique_id=T1055,technique_name=Process Injection\r\nUtcTime: 2023-11-05 12:54:51.363\r\nSourceProcessGuid: {d9ab9ebb-48da-652f-4900-000000003000}\r\nSourceProcessId: 3368\r\nSourceImage: C:\\Program Files\\VMware\\VMware Tools\\vmtoolsd.exe\r\nTargetProcessGuid: {d9ab9ebb-62bb-6547-601c-020000003000}\r\nTargetProcessId: 4384\r\nTargetImage: C:\\Windows\\explorer.exe\r\nNewThreadId: 10040\r\nStartAddress: 0x00007FFDE5CCE720\r\nStartModule: C:\\Windows\\System32\\KERNEL32.DLL\r\nStartFunction: GetCommandLineW\r\nSourceUser: NT AUTHORITY\\SYSTEM\r\nTargetUser: WEB1\\Administrator"',
1940 msg_timestamp: "2023-11-05T12:54:52.014Z",
@@ -1950,7 +1965,7 @@ const alerts_summary = [
1965 data_win_eventdata_sourceUser: "NT AUTHORITY\\\\SYSTEM",
1966 data_win_system_task: "8",
1967 timestamp_utc: "2023-11-05T12:54:32.314Z",
1953 - syslog_type: "wazuh",
1968 + syslog_type: AlertSourceSyslogType.Wazuh,
1969 data_win_system_threadID: "5576",
1970 rule_description:
1971 "Local Security Authority Subsystem Service (LSASS) process was accessed by C:\\\\Program Files\\\\VMware\\\\VMware Tools\\\\vmtoolsd.exe, possible code injection for credential dumping",
@@ -1972,18 +1987,18 @@ const alerts_summary = [
1987 rule_groups: "sysmon, sysmon_eid8_detections, windows",
1988 data_win_system_keywords: "0x8000000000000000",
1989 data_win_system_level: "4",
1975 - data_win_system_severityValue: "INFORMATION",
1990 + data_win_system_severityValue: AlertSourceDataWinSystemSeverityValue.Information,
1991 data_win_eventdata_targetUser: "NT AUTHORITY\\\\SYSTEM",
1992 agent_ip_geolocation: "16.1667,107.8333",
1993 rule_mitre_technique: "Process Injection",
1994 rule_firedtimes: 2,
1995 data_win_system_systemTime: "2023-11-05T12:54:32.314179900Z",
1996 rule_mail: true,
1982 - decoder_name: "windows_eventchannel",
1997 + decoder_name: AlertSourceDecoderName.WindowsEventchannel,
1998 agent_ip_country_code: "VN",
1999 data_win_system_processID: "3468",
2000 data_win_system_channel: "Microsoft-Windows-Sysmon/Operational",
1986 - syslog_level: "ALERT",
2001 + syslog_level: AlertSourceSyslogLevel.Alert,
2002 data_win_system_providerName: "Microsoft-Windows-Sysmon",
2003 data_win_system_version: "2",
2004 data_win_system_providerGuid: "{5770385f-c22a-43e0-bf4c-06f5698ffbd9}",
@@ -2001,7 +2016,7 @@ const alerts_summary = [
2016 location: "EventChannel",
2017 data_win_eventdata_targetProcessId: "740",
2018 data_win_eventdata_startFunction: "GetCommandLineW",
2004 - rule_group3: "windows",
2019 + rule_group3: AlertSourceDataLogsourceProduct.Windows,
2020 data_win_system_message:
2021 '"CreateRemoteThread detected:\r\nRuleName: technique_id=T1055,technique_name=Process Injection\r\nUtcTime: 2023-11-05 12:54:32.313\r\nSourceProcessGuid: {d9ab9ebb-48da-652f-4900-000000003000}\r\nSourceProcessId: 3368\r\nSourceImage: C:\\Program Files\\VMware\\VMware Tools\\vmtoolsd.exe\r\nTargetProcessGuid: {d9ab9ebb-48d7-652f-0c00-000000003000}\r\nTargetProcessId: 740\r\nTargetImage: C:\\Windows\\System32\\lsass.exe\r\nNewThreadId: 13164\r\nStartAddress: 0x00007FFDE5CCE720\r\nStartModule: C:\\Windows\\System32\\KERNEL32.DLL\r\nStartFunction: GetCommandLineW\r\nSourceUser: NT AUTHORITY\\SYSTEM\r\nTargetUser: NT AUTHORITY\\SYSTEM"',
2022 msg_timestamp: "2023-11-05T12:54:33.443Z",
@@ -2014,7 +2029,7 @@ const alerts_summary = [
2029 }
2030 ]
2031
2017 -const alerts_by_host = [
2032 +export const alerts_by_host = [
2033 {
2034 agent_name: "ip-178-216-201-141",
2035 number_of_alerts: 4
@@ -2037,7 +2052,7 @@ const alerts_by_host = [
2052 }
2053 ]
2054
2040 -const alerts_by_rule = [
2055 +export const alerts_by_rule = [
2056 {
2057 rule: "Explorer process was accessed by C:\\\\Users\\\\Administrator\\\\AppData\\\\Roaming\\\\Telegram Desktop\\\\Telegram.exe, possible process injection",
2058 number_of_alerts: 6
@@ -2064,7 +2079,7 @@ const alerts_by_rule = [
2079 }
2080 ]
2081
2067 -const alerts_by_rule_per_host = [
2082 +export const alerts_by_rule_per_host = [
2083 {
2084 agent_name: "ANSYDWDC01",
2085 number_of_alerts: 20,
@@ -2101,5 +2116,3 @@ const alerts_by_rule_per_host = [
2116 rule: "Detects file and folder permission changes."
2117 }
2118 ]
2104 -
2105 -export { alerts_by_host, alerts_by_rule, alerts_by_rule_per_host, alerts_summary }
frontend/src/components/artifacts/ArtifactItem.vue
+7 -14
@@ -1,24 +1,17 @@
1 <template>
2 - <div class="artifact-item flex flex-col gap-1 px-5 py-3">
3 - <div class="name text-secondary-color">
4 - {{ artifact.name }}
5 - </div>
6 - <div class="description">
2 + <CardEntity>
3 + <div class="flex flex-col gap-1">
4 + <p>
5 + {{ artifact.name }}
6 + </p>
7 {{ artifact.description }}
8 </div>
9 - </div>
9 + </CardEntity>
10 </template>
11
12 <script setup lang="ts">
13 import type { Artifact } from "@/types/artifacts.d"
14 +import CardEntity from "@/components/common/cards/CardEntity.vue"
15
16 const { artifact } = defineProps<{ artifact: Artifact }>()
17 </script>
17 -
18 -<style lang="scss" scoped>
19 -.artifact-item {
20 - border-radius: var(--border-radius);
21 - background-color: var(--bg-color);
22 - border: var(--border-small-050);
23 -}
24 -</style>
frontend/src/components/artifacts/ArtifactRecommendation.vue
+5 -5
@@ -16,7 +16,7 @@
16 display-directive="show"
17 segmented
18 >
19 - <div class="flex gap-3 items-center flex-wrap mb-4">
19 + <div class="mb-4 flex flex-wrap items-center gap-3">
20 <div>Get Recommendations for OS:</div>
21 <n-select
22 v-model:value="selectedOs"
@@ -45,11 +45,11 @@
45 <n-card
46 v-for="recommendation of recommendations"
47 :key="recommendation.name"
48 - content-class="bg-secondary-color flex flex-col gap-2 !p-0"
49 - class="overflow-hidden item-appear item-appear-bottom item-appear-005"
48 + content-class="bg-secondary flex flex-col gap-2 !p-0"
49 + class="item-appear item-appear-bottom item-appear-005 overflow-hidden"
50 size="small"
51 >
52 - <strong class="recommendation-name font-mono px-4 pt-3 pb-1">{{ recommendation.name }}</strong>
52 + <strong class="recommendation-name px-4 pb-1 pt-3 font-mono">{{ recommendation.name }}</strong>
53 <n-divider class="!m-0" />
54 <div class="recommendation-description px-4 pt-1">
55 {{ recommendation.description }}
@@ -62,7 +62,7 @@
62 <n-empty
63 v-if="!loading && !recommendations.length"
64 description="Recommendations not found"
65 - class="justify-center h-48"
65 + class="h-48 justify-center"
66 />
67 </n-spin>
68 </n-modal>
frontend/src/components/artifacts/ArtifactsCollect.vue
+8 -28
@@ -1,10 +1,10 @@
1 <template>
2 <div class="artifacts-collect">
3 - <div class="header flex justify-end items-start gap-2">
3 + <div class="header flex items-start justify-end gap-2">
4 <div v-if="isDirty" class="info flex gap-5">
5 <n-popover overlap placement="bottom-start">
6 <template #trigger>
7 - <div class="bg-color border-radius">
7 + <div class="bg-default rounded-default">
8 <n-button size="small" class="!cursor-help">
9 <template #icon>
10 <Icon :name="InfoIcon"></Icon>
@@ -20,7 +20,7 @@
20 </div>
21 </n-popover>
22 </div>
23 - <div class="grow flex items-center justify-end gap-2 flex-wrap">
23 + <div class="flex grow flex-wrap items-center justify-end gap-2">
24 <div v-if="!hideHostnameField" class="grow basis-56">
25 <n-select
26 v-model:value="filters.hostname"
@@ -69,17 +69,18 @@
69 </div>
70 </div>
71 <n-spin :show="loading">
72 - <div class="list grid gap-3 my-7">
72 + <div class="my-7 flex min-h-52 flex-col gap-3">
73 <template v-if="collectList.length">
74 <CollectItem
75 v-for="collect of collectList"
76 - :key="collect.___id"
76 + :key="`${collect.___id}`"
77 + embedded
78 :collect="collect"
79 class="item-appear item-appear-bottom item-appear-005"
80 />
81 </template>
82 <template v-else>
82 - <n-empty v-if="!loading" description="No items found" class="justify-center h-48" />
83 + <n-empty v-if="!loading" description="No items found" class="h-48 justify-center" />
84 </template>
85 </div>
86 </n-spin>
@@ -107,8 +108,6 @@ const props = defineProps<{
108 hideVelociraptorIdField?: boolean
109 }>()
110
110 -// import { collectResult } from "./mock"
111 -
111 const emit = defineEmits<{
112 (e: "loaded-agents", value: Agent[]): void
113 (e: "loaded-artifacts", value: Artifact[]): void
@@ -259,28 +258,9 @@ onBeforeMount(() => {
258 // MOCK
259 /*
260 collectList.value = collectResult.map(o => {
262 - // @ts-ignore
261 o.___id = nanoid()
262 return o
265 - }) as CollectResultExt[]
263 + })
264 */
265 })
266 </script>
269 -
270 -<style lang="scss" scoped>
271 -.artifacts-collect {
272 - .list {
273 - container-type: inline-size;
274 - min-height: 200px;
275 - grid-template-columns: repeat(auto-fit, minmax(390px, 1fr));
276 - grid-auto-flow: row dense;
277 - }
278 -
279 - @media (max-width: 490px) {
280 - .list {
281 - display: flex;
282 - flex-direction: column;
283 - }
284 - }
285 -}
286 -</style>
frontend/src/components/artifacts/ArtifactsCommand.vue
+10 -19
@@ -1,8 +1,8 @@
1 <template>
2 <div class="artifacts-command">
3 <div class="header flex items-start gap-2">
4 - <div class="flex flex-col gap-2 w-full">
5 - <div class="grow flex items-center gap-2 flex-wrap">
4 + <div class="flex w-full flex-col gap-2">
5 + <div class="flex grow flex-wrap items-center gap-2">
6 <div v-if="!hideHostnameField" class="grow basis-56">
7 <n-select
8 v-model:value="filters.hostname"
@@ -37,7 +37,7 @@
37 />
38 </div>
39 </div>
40 - <div class="grow flex items-center gap-2 flex-wrap">
40 + <div class="flex grow flex-wrap items-center gap-2">
41 <n-input
42 v-model:value="filters.command"
43 placeholder="Command"
@@ -50,8 +50,8 @@
50 }"
51 />
52 </div>
53 - <div class="grow flex items-center justify-end gap-2 flex-wrap-reverse">
54 - <div class="badges-box flex gap-2 flex-wrap grow">
53 + <div class="flex grow flex-wrap-reverse items-center justify-end gap-2">
54 + <div class="flex grow flex-wrap gap-2">
55 <n-tooltip v-if="commandTime" trigger="hover">
56 <template #trigger>
57 <Badge type="splitted" color="primary" hint-cursor>
@@ -95,7 +95,7 @@
95 </div>
96 </div>
97 <n-spin :show="loading">
98 - <div class="list flex flex-col gap-3 my-7">
98 + <div class="my-7 flex min-h-52 flex-col gap-3">
99 <template v-if="commandList.length">
100 <CommandItem
101 v-for="command of commandList"
@@ -105,7 +105,7 @@
105 />
106 </template>
107 <template v-else>
108 - <n-empty v-if="!loading" description="No items found" class="justify-center h-48" />
108 + <n-empty v-if="!loading" description="No items found" class="h-48 justify-center" />
109 </template>
110 </div>
111 </n-spin>
@@ -134,8 +134,6 @@ const props = defineProps<{
134 hideVelociraptorIdField?: boolean
135 }>()
136
137 -// import { commandResult } from "./mock"
138 -
137 const emit = defineEmits<{
138 (e: "loaded-agents", value: Agent[]): void
139 (e: "loaded-artifacts", value: Artifact[]): void
@@ -287,15 +285,8 @@ onBeforeMount(() => {
285 })
286
287 // MOCK
290 - // commandList.value = commandResult as CommandResult[]
288 + /*
289 + commandList.value = commandResult
290 + */
291 })
292 </script>
293 -
294 -<style lang="scss" scoped>
295 -.artifacts-command {
296 - .list {
297 - container-type: inline-size;
298 - min-height: 200px;
299 - }
300 -}
301 -</style>
frontend/src/components/artifacts/ArtifactsList.vue
+12 -16
@@ -1,10 +1,10 @@
1 <template>
2 <div class="artifacts-list">
3 <div ref="header" class="header flex items-center justify-end gap-2">
4 - <div class="info grow flex gap-2">
4 + <div class="info flex grow gap-2">
5 <n-popover overlap placement="bottom-start">
6 <template #trigger>
7 - <div class="bg-color border-radius">
7 + <div class="bg-default rounded-default">
8 <n-button size="small" class="!cursor-help">
9 <template #icon>
10 <Icon :name="InfoIcon"></Icon>
@@ -31,7 +31,7 @@
31 />
32 <n-popover :show="showFilters" trigger="manual" overlap placement="right" class="!px-0">
33 <template #trigger>
34 - <div class="bg-color border-radius">
34 + <div class="bg-default rounded-default">
35 <n-badge
36 :show="!!lastFilters.hostname || !!lastFilters.os"
37 dot
@@ -46,7 +46,7 @@
46 </n-badge>
47 </div>
48 </template>
49 - <div class="py-1 flex flex-col gap-2">
49 + <div class="flex flex-col gap-2 py-1">
50 <div class="px-3">
51 <n-input-group class="artifacts-list-filter-combo" :class="{ 'filters-active': filterType }">
52 <n-select
@@ -90,7 +90,7 @@
90 />
91 </n-input-group>
92 </div>
93 - <div class="px-3 flex justify-end gap-2">
93 + <div class="flex justify-end gap-2 px-3">
94 <n-button size="small" secondary @click="showFilters = false">Close</n-button>
95 <n-button size="small" type="primary" secondary @click="getData()">Submit</n-button>
96 </div>
@@ -98,7 +98,7 @@
98 </n-popover>
99 </div>
100 <n-spin :show="loading">
101 - <div class="list flex flex-col gap-2 my-3">
101 + <div class="my-3 flex min-h-52 flex-col gap-2">
102 <template v-if="artifactsList.length">
103 <ArtifactItem
104 v-for="artifact of itemsPaginated"
@@ -108,7 +108,7 @@
108 />
109 </template>
110 <template v-else>
111 - <n-empty v-if="!loading" description="No items found" class="justify-center h-48" />
111 + <n-empty v-if="!loading" description="No items found" class="h-48 justify-center" />
112 </template>
113 </div>
114 </n-spin>
@@ -224,6 +224,11 @@ function getData(cb?: (artifacts: Artifact[]) => void) {
224 .catch(err => {
225 artifactsList.value = []
226
227 + // MOCK
228 + /*
229 + artifactsList.value = artifact_list
230 + */
231 +
232 message.error(err.response?.data?.message || "An error occurred. Please try again later.")
233 })
234 .finally(() => {
@@ -291,15 +296,6 @@ onBeforeMount(() => {
296 })
297 </script>
298
294 -<style lang="scss" scoped>
295 -.artifacts-list {
296 - .list {
297 - container-type: inline-size;
298 - min-height: 200px;
299 - }
300 -}
301 -</style>
302 -
299 <style lang="scss">
300 .artifacts-list-filter-combo {
301 .artifacts-list-filter-type {
frontend/src/components/artifacts/ArtifactsQuarantine.vue
+7 -16
@@ -1,7 +1,7 @@
1 <template>
2 <div class="artifacts-quarantine">
3 - <div class="header flex justify-end items-start gap-2">
4 - <div class="grow flex items-center justify-end gap-2 flex-wrap">
3 + <div class="header flex items-start justify-end gap-2">
4 + <div class="flex grow flex-wrap items-center justify-end gap-2">
5 <div v-if="!hideHostnameField" class="grow basis-56">
6 <n-select
7 v-model:value="filters.hostname"
@@ -60,7 +60,7 @@
60 </div>
61 </div>
62 <n-spin :show="loading">
63 - <div class="list grid gap-3 my-7">
63 + <div class="my-7 flex min-h-28 flex-col gap-3">
64 <template v-if="quarantineList.length">
65 <QuarantineItem
66 v-for="quarantine of quarantineList"
@@ -70,7 +70,7 @@
70 />
71 </template>
72 <template v-else>
73 - <n-empty v-if="!loading" description="No items found" class="justify-center h-48" />
73 + <n-empty v-if="!loading" description="No items found" class="h-48 justify-center" />
74 </template>
75 </div>
76 </n-spin>
@@ -95,8 +95,6 @@ const props = defineProps<{
95 hideVelociraptorIdField?: boolean
96 }>()
97
98 -// import { quarantineResult } from "./mock"
99 -
98 const emit = defineEmits<{
99 (e: "loaded-agents", value: Agent[]): void
100 (e: "loaded-artifacts", value: Artifact[]): void
@@ -243,15 +241,8 @@ onBeforeMount(() => {
241 })
242
243 // MOCK
246 - // quarantineList.value = quarantineResult as QuarantineResult[]
244 + /*
245 + quarantineList.value = quarantineResult
246 + */
247 })
248 </script>
249 -
250 -<style lang="scss" scoped>
251 -.artifacts-quarantine {
252 - .list {
253 - container-type: inline-size;
254 - min-height: 100px;
255 - }
256 -}
257 -</style>
frontend/src/components/artifacts/CollectItem.vue
+28 -46
@@ -1,24 +1,29 @@
1 <template>
2 - <div class="collect-item flex flex-wrap gap-2 p-2" :class="{ embedded }">
3 - <KVCard v-for="prop of displayData" :key="prop.key" :class="{ 'hide-mobile': prop.hideMobile }">
4 - <template #key>
5 - {{ prop.key }}
6 - </template>
7 - <template #value>
8 - {{ prop.value }}
9 - </template>
10 - </KVCard>
11 - <KVCard class="more" @click="showDetails = true">
12 - <template #value>
13 - <div class="h-full w-full flex items-center text-center justify-center">view more...</div>
14 - </template>
15 - </KVCard>
2 + <div>
3 + <CardEntity :embedded hoverable size="small">
4 + <div class="collect-item grid-auto-fit-200 grid gap-2">
5 + <CardKV v-for="prop of displayData" :key="prop.key" :class="{ 'hide-mobile': prop.hideMobile }">
6 + <template #key>
7 + {{ prop.key }}
8 + </template>
9 + <template #value>
10 + {{ prop.value }}
11 + </template>
12 + </CardKV>
13 + <CardKV class="hover:!border-primary cursor-pointer" @click="showDetails = true">
14 + <template #value>
15 + <div class="flex h-full w-full items-center justify-center text-center">view more...</div>
16 + </template>
17 + </CardKV>
18 + </div>
19 + </CardEntity>
20
21 <n-modal
22 v-model:show="showDetails"
23 preset="card"
24 :style="{ maxWidth: 'min(800px, 90vw)', overflow: 'hidden' }"
25 :bordered="false"
26 + title="Collected Item"
27 >
28 <SimpleJsonViewer class="vuesjv-override" :model-value="jsonData" :initial-expanded-depth="2" />
29 </n-modal>
@@ -27,7 +32,8 @@
32
33 <script setup lang="ts">
34 import type { CollectResult } from "@/types/artifacts.d"
30 -import KVCard from "@/components/common/KVCard.vue"
35 +import CardEntity from "@/components/common/cards/CardEntity.vue"
36 +import CardKV from "@/components/common/cards/CardKV.vue"
37 import { useSettingsStore } from "@/stores/settings"
38 import { formatDate } from "@/utils"
39 import dayjs from "@/utils/dayjs"
@@ -36,7 +42,7 @@ import _isString from "lodash/isString"
42 import { NModal } from "naive-ui"
43 import { onBeforeMount, ref } from "vue"
44 import { SimpleJsonViewer } from "vue-sjv"
39 -import "@/assets/scss/vuesjv-override.scss"
45 +import "@/assets/scss/overrides/vuesjv-override.scss"
46
47 interface Prop {
48 key: string
@@ -68,15 +74,17 @@ onBeforeMount(() => {
74 }
75
76 if (prop.value && typeof prop.value === "string") {
71 - prop.value = dayjs(value).isValid() ? formatDate(value, dFormats.datetimesec).toString() : value.toString()
77 + prop.value = dayjs(prop.value).isValid()
78 + ? formatDate(prop.value, dFormats.datetimesec).toString()
79 + : prop.value
80 }
81
82 if (prop.value && typeof prop.value === "number") {
83 const numText = prop.value.toString()
84
85 if (numText.length === 10 || numText.length === 13) {
78 - if (dayjs(value).isValid()) {
79 - prop.value = formatDate(value, dFormats.datetimesec).toString()
86 + if (dayjs(prop.value).isValid()) {
87 + prop.value = formatDate(prop.value, dFormats.datetimesec).toString()
88 }
89 }
90 }
@@ -97,34 +105,8 @@ onBeforeMount(() => {
105
106 <style lang="scss" scoped>
107 .collect-item {
100 - border-radius: var(--border-radius);
101 - background-color: var(--bg-color);
102 - border: var(--border-small-050);
103 - transition: all 0.2s var(--bezier-ease);
104 - min-height: 160px;
105 - max-width: 100%;
106 - overflow: hidden;
107 -
108 - .kv-card {
109 - &.more {
110 - cursor: pointer;
111 - transition: all 0.2s;
112 -
113 - &:hover {
114 - border-color: var(--primary-color);
115 - }
116 - }
117 - }
118 -
119 - &:hover {
120 - border-color: var(--primary-color);
121 - }
122 -
123 - &.embedded {
124 - background-color: var(--bg-secondary-color);
125 - }
126 -
108 @container (max-width: 500px) {
109 + display: flex;
110 flex-direction: column;
111
112 .hide-mobile {
frontend/src/components/artifacts/CommandItem.vue
+46 -100
@@ -1,53 +1,55 @@
1 <template>
2 - <div class="command-item flex flex-col">
3 - <div class="header-box flex justify-between">
4 - <div class="status">
5 - Complete:
6 - <strong class="font-mono" :class="{ success: `${command.Complete}` === 'true' }">
7 - {{ command.Complete }}
8 - </strong>
2 + <CardEntity>
3 + <template #headerMain>
4 + Complete:
5 + <strong class="font-mono" :class="{ 'text-success': `${command.Complete}` === 'true' }">
6 + {{ command.Complete }}
7 + </strong>
8 + </template>
9 + <template #headerExtra>
10 + Code:
11 + <strong class="font-mono">{{ command.ReturnCode }}</strong>
12 + </template>
13 +
14 + <template #mainExtra>
15 + <div class="flex flex-col gap-4">
16 + <div v-if="command.Stdout" class="flex flex-col gap-2">
17 + <label>Stdout</label>
18 + <n-input
19 + :value="command.Stdout"
20 + type="textarea"
21 + readonly
22 + placeholder="Empty"
23 + size="large"
24 + :autosize="{
25 + minRows: 3
26 + }"
27 + />
28 + </div>
29 + <div v-if="command.Stderr" class="flex flex-col gap-2">
30 + <label class="text-error flex items-center gap-2 leading-none">
31 + <Icon :name="DangerIcon" />
32 + <span>Stderr</span>
33 + </label>
34 + <n-input
35 + :value="command.Stderr"
36 + type="textarea"
37 + readonly
38 + placeholder="Empty"
39 + size="large"
40 + :autosize="{
41 + minRows: 3
42 + }"
43 + />
44 + </div>
45 </div>
10 - <div class="code">
11 - Code:
12 - <strong class="font-mono">{{ command.ReturnCode }}</strong>
13 - </div>
14 - </div>
15 - <div class="main-box">
16 - <div v-if="command.Stdout" class="output stdout">
17 - <label>Stdout</label>
18 - <n-input
19 - :value="command.Stdout"
20 - type="textarea"
21 - readonly
22 - placeholder="Empty"
23 - size="large"
24 - :autosize="{
25 - minRows: 3
26 - }"
27 - />
28 - </div>
29 - <div v-if="command.Stderr" class="output stderr">
30 - <label class="flex items-center">
31 - <Icon :name="DangerIcon" class="mr-1"></Icon>
32 - Stderr
33 - </label>
34 - <n-input
35 - :value="command.Stderr"
36 - type="textarea"
37 - readonly
38 - placeholder="Empty"
39 - size="large"
40 - :autosize="{
41 - minRows: 3
42 - }"
43 - />
44 - </div>
45 - </div>
46 - </div>
46 + </template>
47 + </CardEntity>
48 </template>
49
50 <script setup lang="ts">
51 import type { CommandResult } from "@/types/artifacts.d"
52 +import CardEntity from "@/components/common/cards/CardEntity.vue"
53 import Icon from "@/components/common/Icon.vue"
54 import { NInput } from "naive-ui"
55
@@ -55,59 +57,3 @@ const { command } = defineProps<{ command: CommandResult }>()
57
58 const DangerIcon = "majesticons:exclamation-line"
59 </script>
58 -
59 -<style lang="scss" scoped>
60 -.command-item {
61 - border-radius: var(--border-radius);
62 - background-color: var(--bg-color);
63 - transition: all 0.2s var(--bezier-ease);
64 - border: var(--border-small-050);
65 - max-width: 100%;
66 - overflow: hidden;
67 -
68 - .header-box {
69 - padding: 16px 20px;
70 - font-family: var(--font-family-mono);
71 - font-size: 14px;
72 - border-bottom: var(--border-small-100);
73 - .status {
74 - strong {
75 - color: var(--warning-color);
76 - &.success {
77 - color: var(--primary-color);
78 - }
79 - }
80 - }
81 - }
82 - .main-box {
83 - .output {
84 - margin-top: 20px;
85 -
86 - label {
87 - padding: 0px 20px;
88 - line-height: 1;
89 - }
90 -
91 - .n-input {
92 - margin-top: 8px;
93 - border-radius: 0;
94 -
95 - background-color: var(--n-color) !important;
96 -
97 - :deep() {
98 - .n-input__border,
99 - .n-input__state-border {
100 - display: none;
101 - }
102 - }
103 - }
104 -
105 - &.stderr {
106 - label {
107 - color: var(--warning-color);
108 - }
109 - }
110 - }
111 - }
112 -}
113 -</style>
frontend/src/components/artifacts/QuarantineItem.vue
+7 -14
@@ -1,16 +1,17 @@
1 <template>
2 - <div class="quarantine-item flex flex-col gap-1 px-5 py-3">
3 - <div class="time text-secondary-color">
2 + <CardEntity embedded>
3 + <template #header>
4 {{ formatDate(quarantine.Time, dFormats.datetimesec) }}
5 - </div>
6 - <div class="result">
5 + </template>
6 + <template #default>
7 {{ quarantine.Result }}
8 - </div>
9 - </div>
8 + </template>
9 + </CardEntity>
10 </template>
11
12 <script setup lang="ts">
13 import type { QuarantineResult } from "@/types/artifacts.d"
14 +import CardEntity from "@/components/common/cards/CardEntity.vue"
15 import { useSettingsStore } from "@/stores/settings"
16 import { formatDate } from "@/utils"
17
@@ -18,11 +19,3 @@ const { quarantine } = defineProps<{ quarantine: QuarantineResult }>()
19
20 const dFormats = useSettingsStore().dateFormat
21 </script>
21 -
22 -<style lang="scss" scoped>
23 -.quarantine-item {
24 - border-radius: var(--border-radius);
25 - background-color: var(--bg-color);
26 - border: var(--border-small-050);
27 -}
28 -</style>
frontend/src/components/artifacts/mock.ts
+19 -4
@@ -1,4 +1,6 @@
1 -const collectResult = [
1 +import type { Artifact, CollectResult, CommandResult, QuarantineResult } from "@/types/artifacts.d"
2 +
3 +export const collectResult: CollectResult[] = [
4 {
5 Pid: 928,
6 Name: "svchost.exe",
@@ -872,7 +874,7 @@ const collectResult = [
874 }
875 ]
876
875 -const commandResult = [
877 +export const commandResult: CommandResult[] = [
878 {
879 Stdout: "\r\n\r\nAccountType : 512\r\nCaption : WIN-HFOU106TD7K\\Administrator\r\nDomain : WIN-HFOU106TD7K\r\nSID : S-1-5-21-1287727892-3649796646-2502983199-500\r\nFullName : \r\nName : Administrator\r\n\r\nAccountType : 512\r\nCaption : WIN-HFOU106TD7K\\DefaultAccount\r\nDomain : WIN-HFOU106TD7K\r\nSID : S-1-5-21-1287727892-3649796646-2502983199-503\r\nFullName : \r\nName : DefaultAccount\r\n\r\nAccountType : 512\r\nCaption : WIN-HFOU106TD7K\\Guest\r\nDomain : WIN-HFOU106TD7K\r\nSID : S-1-5-21-1287727892-3649796646-2502983199-501\r\nFullName : \r\nName : Guest\r\n\r\nAccountType : 512\r\nCaption : WIN-HFOU106TD7K\\WDAGUtilityAccount\r\nDomain : WIN-HFOU106TD7K\r\nSID : S-1-5-21-1287727892-3649796646-2502983199-504\r\nFullName : \r\nName : WDAGUtilityAccount\r\n\r\n\r\n\r\n",
880 Stderr: '#< CLIXML\r\n<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>',
@@ -881,7 +883,7 @@ const commandResult = [
883 }
884 ]
885
884 -const quarantineResult = [
886 +export const quarantineResult: QuarantineResult[] = [
887 {
888 Time: "2023-11-14T21:03:03Z",
889 Result: "VelociraptorQuarantine IPSec policy removed."
@@ -936,4 +938,17 @@ const quarantineResult = [
938 }
939 ]
940
939 -export { collectResult, commandResult, quarantineResult }
941 +export const artifact_list: Artifact[] = [
942 + {
943 + description: "This artifact contains the initial data collected from the user session.",
944 + name: "session_data_artifact"
945 + },
946 + {
947 + description: "This artifact stores the processed results after the data flow execution.",
948 + name: "processed_results_artifact"
949 + },
950 + {
951 + description: "This artifact includes the logs generated during the data collection process.",
952 + name: "logs_artifact"
953 + }
954 +]
frontend/src/components/auth/AuthForm.vue
+1 -1
@@ -14,7 +14,7 @@
14 </transition>
15 </div>
16
17 - <div class="sign-text text-center mt-10">
17 + <div class="sign-text mt-10 text-center">
18 <div v-if="typeRef === 'signin'" class="sign-text">
19 Don't you have an account?
20 <n-button text type="primary" size="large" @click="gotoSignUp()">Sign up</n-button>
frontend/src/components/auth/SignUp.vue
+2 -2
@@ -33,7 +33,7 @@
33 @keydown.enter="signUp"
34 />
35 </n-form-item>
36 - <div class="flex items-center justify-end mt-3">
36 + <div class="mt-3 flex items-center justify-end">
37 <n-button
38 type="primary"
39 size="large"
@@ -113,7 +113,7 @@
113 </n-form-item>
114 -->
115
116 - <div class="flex items-center justify-between mt-3 gap-3">
116 + <div class="mt-3 flex items-center justify-between gap-3">
117 <n-button size="large" @click="wizardCurrent = 1">
118 <template #icon>
119 <Icon :name="ArrowLeftIcon"></Icon>
frontend/src/components/cards/CardActions.vue deleted
-167
@@ -1,167 +0,0 @@
1 -<template>
2 - <n-card hoverable size="large" :class="{ actionBoxTransparent }">
3 - <template v-if="showImage" #cover>
4 - <img :src="image || 'https://picsum.photos/seed/IqZMU/900/300'" width="900" height="300" />
5 - </template>
6 - <template #header>
7 - <div v-if="title" class="title">
8 - {{ title }}
9 - </div>
10 - <div v-if="!hideSubtitle && subtitle" class="subtitle">
11 - {{ subtitle }}
12 - </div>
13 - </template>
14 - <template #header-extra>
15 - <n-dropdown v-if="!hideMenu" :options="menuOptions" placement="bottom-end" to="body" @select="menuSelect">
16 - <Icon :size="20" :name="MenuIcon" />
17 - </n-dropdown>
18 - </template>
19 - <template #default>
20 - <div class="overflow-hidden w-full">
21 - <n-scrollbar x-scrollable class="!w-full" trigger="none">
22 - <slot />
23 - </n-scrollbar>
24 - </div>
25 - </template>
26 - <template v-if="$slots.footer" #footer>
27 - <slot name="footer" />
28 - </template>
29 - <template v-if="$slots.action" #action>
30 - <slot name="action" />
31 - </template>
32 - </n-card>
33 -</template>
34 -
35 -<script setup lang="ts">
36 -import Icon from "@/components/common/Icon.vue"
37 -import { renderIcon } from "@/utils"
38 -import { NCard, NDropdown, NScrollbar } from "naive-ui"
39 -import { computed, onMounted, ref, toRefs } from "vue"
40 -
41 -const props = defineProps<{
42 - showImage?: boolean
43 - hideSubtitle?: boolean
44 - actionBoxTransparent?: boolean
45 - hideMenu?: boolean
46 - reload?: (state: boolean) => void
47 - expand?: (state: boolean) => void
48 - isExpand?: () => boolean
49 - title?: string
50 - subtitle?: string
51 - image?: string
52 -}>()
53 -const MenuIcon = "carbon:overflow-menu-vertical"
54 -const ContractIcon = "fluent:contract-down-left-24-regular"
55 -const ExpandIcon = "fluent:expand-up-right-24-regular"
56 -const ReloadIcon = "tabler:refresh"
57 -
58 -const { showImage, hideSubtitle, title, subtitle, image, actionBoxTransparent, hideMenu, reload, expand, isExpand } =
59 - toRefs(props)
60 -
61 -let reloadTimeout: NodeJS.Timeout | null = null
62 -const showExpandButton = ref(true)
63 -
64 -/* eslint no-mixed-spaces-and-tabs: "off" */
65 -const menuOptions = computed(() =>
66 - showExpandButton.value
67 - ? [
68 - {
69 - label: "Expand",
70 - key: "expand",
71 - icon: renderIcon(ExpandIcon)
72 - },
73 - {
74 - label: "Reload",
75 - key: "reload",
76 - icon: renderIcon(ReloadIcon)
77 - }
78 - ]
79 - : [
80 - {
81 - label: "Collapse",
82 - key: "collapse",
83 - icon: renderIcon(ContractIcon)
84 - },
85 - {
86 - label: "Reload",
87 - key: "reload",
88 - icon: renderIcon(ReloadIcon)
89 - }
90 - ]
91 -)
92 -
93 -function menuSelect(key: string) {
94 - if (key === "expand") {
95 - expand?.value?.(true)
96 - }
97 - if (key === "collapse") {
98 - expand?.value?.(false)
99 - }
100 - if (key === "reload") {
101 - reload?.value?.(true)
102 -
103 - if (reloadTimeout) {
104 - clearTimeout(reloadTimeout)
105 - }
106 -
107 - reloadTimeout = setTimeout(() => {
108 - reload?.value?.(false)
109 - }, 1000)
110 - }
111 -}
112 -
113 -onMounted(() => {
114 - if (isExpand?.value) {
115 - showExpandButton.value = !isExpand?.value()
116 - }
117 -})
118 -</script>
119 -
120 -<style lang="scss" scoped>
121 -.n-card {
122 - .title {
123 - line-height: 1.2;
124 - }
125 - .subtitle {
126 - line-height: 1.2;
127 - font-size: 14px;
128 - opacity: 0.6;
129 - margin-top: 6px;
130 - font-weight: 500;
131 - font-family: var(--font-family);
132 - }
133 -
134 - :deep() {
135 - .n-card-header {
136 - align-items: flex-start;
137 - }
138 -
139 - .n-card__footer {
140 - margin: 0 auto;
141 - overflow-x: clip;
142 - width: calc(100% - 2px);
143 - .vue-apexcharts {
144 - margin-left: -18px;
145 - margin-right: -18px;
146 - }
147 - }
148 -
149 - .n-card__action {
150 - padding: 0;
151 - //overflow-x: clip;
152 - .vue-apexcharts {
153 - width: calc(100% - 2px);
154 - margin: 0 auto;
155 - }
156 - }
157 - }
158 -
159 - &.actionBoxTransparent {
160 - :deep() {
161 - .n-card__action {
162 - background-color: transparent;
163 - }
164 - }
165 - }
166 -}
167 -</style>
frontend/src/components/cards/CardWrapper.vue deleted
-82
@@ -1,82 +0,0 @@
1 -<template>
2 - <div class="card-wrapper">
3 - <n-spin :show="showSpin" class="h-full">
4 - <slot :expand="expand" :reload="reload" :is-expand="isExpand" />
5 - </n-spin>
6 - <n-modal v-model:show="showModal" display-directive="show" class="card-modal-wrapper">
7 - <n-spin :show="showSpin">
8 - <slot :expand="expand" :reload="reload" :is-expand="isExpand" />
9 - </n-spin>
10 - </n-modal>
11 - </div>
12 -</template>
13 -
14 -<script setup lang="ts">
15 -import { NModal, NSpin } from "naive-ui"
16 -import { ref } from "vue"
17 -
18 -const showModal = ref(false)
19 -const showSpin = ref(false)
20 -
21 -function expand(state: boolean): void {
22 - showModal.value = state
23 -}
24 -
25 -function reload(state: boolean): void {
26 - showSpin.value = state
27 -}
28 -
29 -function isExpand(): boolean {
30 - return showModal.value
31 -}
32 -</script>
33 -
34 -<style lang="scss" scoped>
35 -.card-wrapper {
36 - :deep() {
37 - .n-spin-content {
38 - height: 100%;
39 - }
40 - }
41 - .n-card {
42 - .title {
43 - line-height: 1.2;
44 - }
45 - .subtitle {
46 - line-height: 1.2;
47 - font-size: 12px;
48 - opacity: 0.6;
49 - margin-top: 10px;
50 - }
51 -
52 - :deep() {
53 - .n-spin-content {
54 - height: 100%;
55 - }
56 - .n-card-header {
57 - align-items: flex-start;
58 - }
59 - .n-card__action {
60 - padding: 0;
61 - }
62 - }
63 - }
64 -}
65 -</style>
66 -
67 -<style lang="scss">
68 -.card-modal-wrapper {
69 - background-color: transparent;
70 - backdrop-filter: none;
71 - box-shadow: none !important;
72 -
73 - .n-spin-content {
74 - margin: 100px 0;
75 - min-width: 60vw;
76 -
77 - .n-card.n-card--hoverable:hover {
78 - box-shadow: none;
79 - }
80 - }
81 -}
82 -</style>
frontend/src/components/cloudSecurityAssessment/AvailableReportsItem.vue
+20 -51
@@ -1,31 +1,30 @@
1 <template>
2 - <n-spin :show="canceling">
3 - <div class="item flex flex-col gap-2 px-5 py-3" @click="openReport()">
4 - <div class="header-box flex justify-between">
5 - {{ report }}
6 - </div>
7 - <div class="footer-box flex justify-end">
8 - <n-popconfirm
9 - v-model:show="showConfirm"
10 - trigger="manual"
11 - @positive-click="deleteScoutSuiteReport()"
12 - @clickoutside="showConfirm = false"
13 - >
14 - <template #trigger>
15 - <div class="delete-btn" @click.stop="showConfirm = true">delete</div>
16 - </template>
17 - Are you sure you want to delete the report?
18 - </n-popconfirm>
19 - </div>
20 - </div>
21 - </n-spin>
2 + <CardEntity :loading="canceling" hoverable clickable @click.stop="openReport()">
3 + <template #default>
4 + {{ report }}
5 + </template>
6 + <template #footerExtra>
7 + <n-popconfirm
8 + v-model:show="showConfirm"
9 + trigger="manual"
10 + @positive-click="deleteScoutSuiteReport()"
11 + @clickoutside="showConfirm = false"
12 + >
13 + <template #trigger>
14 + <n-button quaternary size="tiny" @click.stop="showConfirm = true">delete</n-button>
15 + </template>
16 + Are you sure you want to delete the report?
17 + </n-popconfirm>
18 + </template>
19 + </CardEntity>
20 </template>
21
22 <script setup lang="ts">
23 import type { ScoutSuiteReport } from "@/types/cloudSecurityAssessment.d"
24 import Api from "@/api"
25 +import CardEntity from "@/components/common/cards/CardEntity.vue"
26 import { getBaseUrl } from "@/utils"
28 -import { NPopconfirm, NSpin, useMessage } from "naive-ui"
27 +import { NButton, NPopconfirm, useMessage } from "naive-ui"
28 import { ref } from "vue"
29
30 const { report } = defineProps<{ report: ScoutSuiteReport }>()
@@ -63,33 +62,3 @@ function openReport() {
62 window.open(`${getBaseUrl()}/scoutsuite-report/${report}`, "_blank")
63 }
64 </script>
66 -
67 -<style lang="scss" scoped>
68 -.item {
69 - border-radius: var(--border-radius);
70 - background-color: var(--bg-color);
71 - transition: all 0.2s var(--bezier-ease);
72 - border: var(--border-small-050);
73 - cursor: pointer;
74 -
75 - .header-box {
76 - font-family: var(--font-family-mono);
77 - }
78 - .footer-box {
79 - font-family: var(--font-family-mono);
80 - text-align: right;
81 - font-size: 12px;
82 - color: var(--fg-secondary-color);
83 -
84 - .delete-btn {
85 - &:hover {
86 - color: var(--error-color);
87 - }
88 - }
89 - }
90 -
91 - &:hover {
92 - box-shadow: 0px 0px 0px 1px inset var(--primary-color);
93 - }
94 -}
95 -</style>
frontend/src/components/cloudSecurityAssessment/AvailableReportsList.vue
+6 -6
@@ -1,10 +1,10 @@
1 <template>
2 <div class="available-reports-list">
3 - <div class="header flex items-center justify-end gap-2 mb-3">
4 - <div class="info grow flex gap-5">
3 + <div class="header mb-3 flex items-center justify-end gap-2">
4 + <div class="info flex grow gap-5">
5 <n-popover overlap placement="bottom-start">
6 <template #trigger>
7 - <div class="bg-color border-radius">
7 + <div class="bg-default rounded-default">
8 <n-button size="small" class="!cursor-help">
9 <template #icon>
10 <Icon :name="InfoIcon"></Icon>
@@ -20,7 +20,7 @@
20 </div>
21 </n-popover>
22 </div>
23 - <div class="actions flex gap-2 items-center">
23 + <div class="actions flex items-center gap-2">
24 <n-button size="small" type="primary" @click="showForm = true">
25 <template #icon>
26 <Icon :name="NewReportIcon" :size="15"></Icon>
@@ -31,7 +31,7 @@
31 </div>
32 <n-spin :show="loading" class="min-h-32">
33 <template v-if="reportsList.length">
34 - <div class="list grid gap-4 grid-auto-fill-250">
34 + <div class="list grid-auto-fill-250 grid gap-4">
35 <AvailableReportsItem
36 v-for="report of reportsList"
37 :key="report"
@@ -42,7 +42,7 @@
42 </div>
43 </template>
44 <template v-else>
45 - <n-empty v-if="!loading" description="No items found" class="justify-center h-48" />
45 + <n-empty v-if="!loading" description="No items found" class="h-48 justify-center" />
46 </template>
47 </n-spin>
48
frontend/src/components/cloudSecurityAssessment/CreationReportForm.vue
+2 -2
@@ -2,7 +2,7 @@
2 <n-spin :show="loading" class="creation-report-form">
3 <n-form ref="baseFormRef" :model="baseForm" :rules="rules">
4 <div class="flex flex-col gap-2">
5 - <div class="flex gap-4 items-start">
5 + <div class="flex items-start gap-4">
6 <n-form-item label="Type" path="report_type" class="w-32">
7 <n-select
8 v-model:value="baseForm.report_type"
@@ -42,7 +42,7 @@
42 @mounted="typeFormRef = $event"
43 />
44
45 - <div class="flex justify-between gap-4 mt-8">
45 + <div class="mt-8 flex justify-between gap-4">
46 <n-button :disabled="loading" @click="reset()">Reset</n-button>
47 <n-button
48 type="primary"
frontend/src/components/common/CodeSource.vue
+2 -2
@@ -1,7 +1,7 @@
1 <template>
2 <div class="flex flex-col gap-2">
3 - <n-card v-if="!showSource" content-class="bg-secondary-color !p-0" class="overflow-hidden">
4 - <div v-shiki="{ lang, decode }" class="scrollbar-styled overflow-hidden code-bg-transparent">
3 + <n-card v-if="!showSource" content-class="bg-secondary !p-0" class="overflow-hidden">
4 + <div v-shiki="{ lang, decode }" class="scrollbar-styled code-bg-transparent overflow-hidden">
5 <pre v-html="source"></pre>
6 </div>
7 </n-card>
frontend/src/components/common/Icon.vue
+1 -1
@@ -4,7 +4,7 @@
4 <slot />
5 </template>
6 <template v-else>
7 - <Icon v-if="icon" :icon :width="size" :height="size" />
7 + <Icon v-if="icon" :icon :width="options.size || undefined" :height="options.size || undefined" />
8 </template>
9 </component>
10 </template>
frontend/src/components/common/ImageCropper.vue
+1 -1
@@ -25,7 +25,7 @@
25 />
26 </div>
27 </div>
28 - <div class="flex justify-end gap-4 mt-4">
28 + <div class="mt-4 flex justify-end gap-4">
29 <n-button secondary @click="closeCropper()">Close</n-button>
30 <n-button v-if="img" type="primary" @click="emitCrop()">Save</n-button>
31 </div>
frontend/src/components/common/LayoutSettings.vue
+26 -26
@@ -17,18 +17,18 @@
17 <div class="ls-label">Primary color</div>
18 <div class="color-picker-box">
19 <n-color-picker
20 - v-if="theme === ThemeEnum.Dark"
20 + v-if="theme === ThemeNameEnum.Dark"
21 v-model:value="darkColor"
22 :modes="['hex']"
23 :show-alpha="false"
24 />
25 <n-color-picker v-else v-model:value="lightColor" :modes="['hex']" :show-alpha="false" />
26 </div>
27 - <div class="palette flex justify-around mt-3">
27 + <div class="palette mt-3 flex justify-around">
28 <n-button v-for="color of palette" :key="color.light" text @click="setPrimary(color)">
29 <template #icon>
30 <Icon
31 - :color="theme === ThemeEnum.Dark ? color.dark : color.light"
31 + :color="theme === ThemeNameEnum.Dark ? color.dark : color.light"
32 :size="24"
33 :name="ColorIcon"
34 />
@@ -43,11 +43,11 @@
43 <div class="basis-1/2">
44 <n-button
45 class="!w-full"
46 - :type="theme === ThemeEnum.Light ? 'primary' : 'default'"
47 - @click="theme = ThemeEnum.Light"
46 + :type="theme === ThemeNameEnum.Light ? 'primary' : 'default'"
47 + @click="theme = ThemeNameEnum.Light"
48 >
49 <template #icon>
50 - <Icon v-if="theme === ThemeEnum.Light" :name="LightIcon" />
50 + <Icon v-if="theme === ThemeNameEnum.Light" :name="LightIcon" />
51 <Icon v-else :name="LightOutlineIcon" />
52 </template>
53 Light
@@ -56,11 +56,11 @@
56 <div class="basis-1/2">
57 <n-button
58 class="!w-full"
59 - :type="theme === ThemeEnum.Dark ? 'primary' : 'default'"
60 - @click="theme = ThemeEnum.Dark"
59 + :type="theme === ThemeNameEnum.Dark ? 'primary' : 'default'"
60 + @click="theme = ThemeNameEnum.Dark"
61 >
62 <template #icon>
63 - <Icon v-if="theme === ThemeEnum.Dark" :name="DarkIcon" />
63 + <Icon v-if="theme === ThemeNameEnum.Dark" :name="DarkIcon" />
64 <Icon v-else :name="DarkOutlineIcon" />
65 </template>
66 Dark
@@ -72,7 +72,7 @@
72 <div class="ls-section ls-nav-selection">
73 <div class="ls-label">
74 Navbar
75 - <span v-if="isMobileView" class="opacity-50 px-1">desktop only</span>
75 + <span v-if="isMobileView" class="px-1 opacity-50">desktop only</span>
76 </div>
77 <div class="flex items-center gap-2">
78 <div class="basis-1/2">
@@ -101,17 +101,17 @@
101 </div>
102 <div class="ls-section ls-boxed-selection">
103 <div class="flex flex-col gap-3">
104 - <div class="flex justify-between items-center">
104 + <div class="flex items-center justify-between">
105 <div class="switch-label">
106 View boxed
107 - <span v-if="isMobileView" class="opacity-50 px-1">desktop only</span>
107 + <span v-if="isMobileView" class="px-1 opacity-50">desktop only</span>
108 </div>
109 <n-switch v-model:value="boxed" :disabled="isMobileView" size="small" />
110 </div>
111 - <div class="flex justify-between items-center">
111 + <div class="flex items-center justify-between">
112 <div class="switch-label">
113 Toolbar boxed
114 - <span v-if="isMobileView" class="opacity-50 px-1">desktop only</span>
114 + <span v-if="isMobileView" class="px-1 opacity-50">desktop only</span>
115 </div>
116 <n-switch
117 v-model:value="toolbarBoxed"
@@ -119,14 +119,14 @@
119 size="small"
120 />
121 </div>
122 - <div class="flex justify-between items-center">
122 + <div class="flex items-center justify-between">
123 <div class="switch-label">Footer visible</div>
124 <n-switch v-model:value="footerShown" size="small" />
125 </div>
126 - <div class="flex justify-between items-center">
126 + <div class="flex items-center justify-between">
127 <div class="switch-label">
128 RTL
129 - <span class="opacity-50 px-1">beta</span>
129 + <span class="px-1 opacity-50">beta</span>
130 </div>
131 <n-switch v-model:value="rtl" size="small" />
132 </div>
@@ -140,7 +140,7 @@
140 </div>
141 </div>
142 <div class="ls-section ls-reset-selection items-center">
143 - <n-button class="!w-full !mb-3" strong secondary type="primary" @click="reset()">
143 + <n-button class="!mb-3 !w-full" strong secondary type="primary" @click="reset()">
144 Restore default
145 </n-button>
146 <a
@@ -161,7 +161,7 @@
161 <script setup lang="ts">
162 import Icon from "@/components/common/Icon.vue"
163 import { useThemeStore } from "@/stores/theme"
164 -import { Layout, RouterTransition, ThemeEnum } from "@/types/theme.d"
164 +import { Layout, RouterTransition, ThemeNameEnum } from "@/types/theme.d"
165 import { useWindowSize } from "@vueuse/core"
166 import { NButton, NColorPicker, NScrollbar, NSelect, NSwitch, useOsTheme } from "naive-ui"
167 import { computed, ref } from "vue"
@@ -225,12 +225,12 @@ const theme = computed({
225
226 const darkColor = computed({
227 get: () => themeStore.darkPrimaryColor,
228 - set: val => themeStore.setColor(ThemeEnum.Dark, "primary", val)
228 + set: val => themeStore.setColor(ThemeNameEnum.Dark, "primary", val)
229 })
230
231 const lightColor = computed({
232 get: () => themeStore.lightPrimaryColor,
233 - set: val => themeStore.setColor(ThemeEnum.Light, "primary", val)
233 + set: val => themeStore.setColor(ThemeNameEnum.Light, "primary", val)
234 })
235
236 const rtl = computed({
@@ -262,14 +262,14 @@ const palette = ref<Palette>([
262 ])
263
264 function setPrimary(color: ColorPalette) {
265 - themeStore.setColor(ThemeEnum.Dark, "primary", color.dark)
266 - themeStore.setColor(ThemeEnum.Light, "primary", color.light)
265 + themeStore.setColor(ThemeNameEnum.Dark, "primary", color.dark)
266 + themeStore.setColor(ThemeNameEnum.Light, "primary", color.light)
267 }
268
269 function reset() {
270 - themeStore.setColor(ThemeEnum.Dark, "primary", "#00E19B")
271 - themeStore.setColor(ThemeEnum.Light, "primary", "#00B27B")
272 - themeStore.setTheme(useOsTheme().value || ThemeEnum.Light)
270 + themeStore.setColor(ThemeNameEnum.Dark, "primary", "#00E19B")
271 + themeStore.setColor(ThemeNameEnum.Light, "primary", "#00B27B")
272 + themeStore.setTheme(useOsTheme().value === "dark" ? ThemeNameEnum.Dark : ThemeNameEnum.Light)
273 themeStore.setLayout(Layout.HorizontalNav)
274 themeStore.setRouterTransition(RouterTransition.FadeUp)
275 themeStore.setRTL(false)
frontend/src/components/common/ListPercentage.vue
+4 -4
@@ -1,9 +1,9 @@
1 <template>
2 <div class="flex flex-col gap-2">
3 - <n-empty v-if="!list.length" description="No items found" class="justify-center h-48" />
3 + <n-empty v-if="!list.length" description="No items found" class="h-48 justify-center" />
4
5 - <div class="flex gap-4 justify-between items-center list-header font-mono text-secondary-color text-sm">
6 - <div class="basis-2/3 truncate borde">
5 + <div class="list-header text-secondary flex items-center justify-between gap-4 font-mono text-sm">
6 + <div class="borde basis-2/3 truncate">
7 {{ labelKey }}
8 </div>
9 <div class="grow">
@@ -13,7 +13,7 @@
13 <div
14 v-for="item of list"
15 :key="item[labelKey as keyof typeof item]"
16 - class="flex gap-4 justify-between items-center"
16 + class="flex items-center justify-between gap-4"
17 >
18 <div class="basis-2/3 truncate font-mono">
19 {{ item[labelKey as keyof typeof item] }}
frontend/src/components/common/LocaleSelect.vue
+23 -17
@@ -1,26 +1,28 @@
1 <template>
2 - <div class="select-box">
2 + <div class="max-w-60">
3 <n-select v-model:value="currentLocale" :options="list" :render-label="renderLabel" />
4 </div>
5 </template>
6
7 <script lang="ts" setup>
8 import Icon from "@/components/common/Icon.vue"
9 -import { useStoreI18n } from "@/composables/useStoreI18n"
9 +import { useLocalesStore } from "@/stores/i18n"
10 import { NSelect, type SelectOption } from "naive-ui"
11 import { computed, h, type VNodeChild } from "vue"
12
13 -const { getAvailableLocales, getLocale, setLocale, t } = useStoreI18n()
13 +const localesStore = useLocalesStore()
14 +
15 +const { setLocale, t } = localesStore
16
17 const list = computed(() =>
16 - getAvailableLocales().map(i => ({
18 + localesStore.availableLocales.map(i => ({
19 label: i,
20 value: i
21 }))
22 )
23
24 const currentLocale = computed({
23 - get: () => getLocale(),
25 + get: () => localesStore.locale,
26 set: v => setLocale(v)
27 })
28
@@ -39,21 +41,25 @@ function renderLabel(option: SelectOption): VNodeChild {
41 {},
42 {
43 default: () => {
42 - if (option.label === "it") return t("italian")
43 - if (option.label === "en") return t("english")
44 - if (option.label === "es") return t("spanish")
45 - if (option.label === "fr") return t("french")
46 - if (option.label === "de") return t("german")
47 - if (option.label === "jp") return t("japanese")
44 + switch (option.label) {
45 + case "it":
46 + return t("italian")
47 + case "en":
48 + return t("english")
49 + case "es":
50 + return t("spanish")
51 + case "fr":
52 + return t("french")
53 + case "de":
54 + return t("german")
55 + case "jp":
56 + return t("japanese")
57 + default:
58 + return option.label
59 + }
60 }
61 }
62 )
63 ]
64 }
65 </script>
54 -
55 -<style lang="scss" scoped>
56 -.select-box {
57 - max-width: 230px;
58 -}
59 -</style>
frontend/src/components/common/Markdown.vue
+1 -1
@@ -22,7 +22,7 @@ import { codeThemes, getHighlighter } from "@/utils/highlighter"
22 import { VueMarkdownIt } from "@f3ve/vue-markdown-it"
23 import { fromHighlighter } from "@shikijs/markdown-it/core"
24 import { toRefs } from "vue"
25 -import "@/assets/scss/vue-md-it-override.scss"
25 +import "@/assets/scss/overrides/vue-md-it-override.scss"
26
27 const props = defineProps<{
28 source: string
frontend/src/components/common/Notifications/List.vue
+2 -2
@@ -23,7 +23,7 @@
23 <div class="description">
24 {{ item.description }}
25 </div>
26 - <div class="footer flex justify-between items-center">
26 + <div class="footer flex items-center justify-between">
27 <div class="date">
28 {{ formatDatetime(item.date) }}
29 </div>
@@ -37,7 +37,7 @@
37 </div>
38 </div>
39 <slot name="last" />
40 - <n-empty v-if="!list.length" description="There is no notification" class="justify-center h-48" />
40 + <n-empty v-if="!list.length" description="There is no notification" class="h-48 justify-center" />
41 </n-scrollbar>
42 </template>
43
frontend/src/components/common/Percentage.vue
+1 -1
@@ -20,7 +20,7 @@
20 class="!w-12"
21 />
22 </span>
23 - <span v-if="icon && icon === 'arrow'" class="flex items-center percentage-icon">
23 + <span v-if="icon && icon === 'arrow'" class="percentage-icon flex items-center">
24 <Icon v-if="direction === 'up'" :name="ChevronUp" />
25 <Icon v-if="direction === 'down'" :name="ChevronDown" />
26 </span>
frontend/src/components/common/SegmentedPage.vue
+1 -1
@@ -38,7 +38,7 @@
38 </template>
39
40 <template #[tplNameMain]>
41 - <div class="main flex-grow flex flex-col">
41 + <div class="main flex flex-grow flex-col">
42 <div v-if="$slots['main-toolbar']" class="main-toolbar flex items-center">
43 <div v-if="sidebarAvailable && !hideMenuBtn" class="menu-btn flex justify-center opacity-50">
44 <n-button text @click="sidebarOpen = true">
frontend/src/components/common/cards/CardEntity.vue new
+207
@@ -0,0 +1,207 @@
1 +<template>
2 + <n-card
3 + class="card-entity"
4 + content-class="!p-0"
5 + :class="[
6 + `card-size-${size}`,
7 + `card-status-${status}`,
8 + { embedded, highlighted, clickable, hoverable, disabled }
9 + ]"
10 + >
11 + <n-spin :show="loading" :description="loadingDescription">
12 + <div class="card-entity-wrapper flex flex-col">
13 + <div class="main-box flex flex-col">
14 + <div v-if="$slots.header" class="header-box">
15 + <slot name="header" />
16 + </div>
17 +
18 + <div
19 + v-if="!$slots.header && ($slots.headerMain || $slots.headerExtra)"
20 + class="header-box flex flex-wrap items-center justify-between"
21 + >
22 + <div>
23 + <slot name="headerMain" />
24 + </div>
25 + <div>
26 + <slot name="headerExtra" />
27 + </div>
28 + </div>
29 +
30 + <div v-if="$slots.default" class="content-box">
31 + <slot name="default" />
32 + </div>
33 + </div>
34 +
35 + <div v-if="$slots.mainExtra" class="extra-box">
36 + <slot name="mainExtra" />
37 + </div>
38 +
39 + <div v-if="$slots.footer" class="footer-box">
40 + <slot name="footer" />
41 + </div>
42 +
43 + <div
44 + v-if="!$slots.footer && ($slots.footerMain || $slots.footerExtra)"
45 + class="footer-box flex flex-wrap items-start justify-between"
46 + >
47 + <div>
48 + <slot name="footerMain" />
49 + </div>
50 + <div>
51 + <slot name="footerExtra" />
52 + </div>
53 + </div>
54 + </div>
55 + </n-spin>
56 + </n-card>
57 +</template>
58 +
59 +<script setup lang="ts">
60 +import { NCard, NSpin } from "naive-ui"
61 +
62 +const { size, status, embedded, highlighted, clickable, hoverable, disabled, loading, loadingDescription } =
63 + defineProps<{
64 + size?: "medium" | "small" | "large"
65 + status?: "success" | "warning" | "error"
66 + embedded?: boolean
67 + highlighted?: boolean
68 + clickable?: boolean
69 + hoverable?: boolean
70 + disabled?: boolean
71 + loading?: boolean
72 + loadingDescription?: string
73 + }>()
74 +</script>
75 +
76 +<style lang="scss" scoped>
77 +.card-entity {
78 + transition: all 0.2s var(--bezier-ease);
79 + overflow: hidden;
80 +
81 + .card-entity-wrapper {
82 + .main-box {
83 + .header-box {
84 + font-family: var(--font-family-mono);
85 + font-size: 13px;
86 + color: var(--fg-secondary-color);
87 +
88 + :deep(.n-button) {
89 + font-family: var(--font-family);
90 + }
91 + }
92 + .content-box {
93 + word-break: break-word;
94 + }
95 + }
96 +
97 + .extra-box {
98 + border-top: var(--border-small-050);
99 + }
100 +
101 + .footer-box {
102 + border-top: var(--border-small-050);
103 + font-size: 13px;
104 + background-color: var(--bg-secondary-color);
105 + }
106 +
107 + .main-box,
108 + .extra-box,
109 + .footer-box {
110 + @apply gap-3 px-5 py-3;
111 + }
112 +
113 + .main-box {
114 + .header-box {
115 + @apply gap-3;
116 + }
117 + }
118 + }
119 +
120 + &.card-size-small {
121 + .card-entity-wrapper {
122 + .main-box,
123 + .extra-box,
124 + .footer-box {
125 + @apply gap-2 px-3 py-2;
126 + }
127 +
128 + .main-box {
129 + .header-box {
130 + @apply gap-2;
131 + }
132 + }
133 + }
134 + }
135 +
136 + &.card-size-large {
137 + .card-entity-wrapper {
138 + .main-box,
139 + .extra-box,
140 + .footer-box {
141 + @apply gap-6 px-8 py-6;
142 + }
143 +
144 + .main-box {
145 + .header-box {
146 + @apply gap-6;
147 + }
148 + }
149 + }
150 + }
151 +
152 + &.clickable {
153 + @apply cursor-pointer;
154 + }
155 +
156 + &.embedded {
157 + background-color: var(--bg-secondary-color);
158 + border: var(--border-small-100);
159 +
160 + .footer-box {
161 + background-color: var(--bg-body);
162 + }
163 + }
164 +
165 + &.card-status-success {
166 + background-color: var(--success-005-color);
167 + border-color: var(--success-030-color);
168 + }
169 +
170 + &.card-status-warning {
171 + background-color: var(--warning-005-color);
172 + border-color: var(--warning-030-color);
173 + }
174 +
175 + &.card-status-error {
176 + background-color: var(--error-005-color);
177 + border-color: var(--error-030-color);
178 + }
179 +
180 + &.hoverable {
181 + &:not(.disabled) {
182 + &:hover {
183 + border-color: var(--primary-040-color);
184 + }
185 + }
186 + }
187 +
188 + &.highlighted {
189 + background-color: var(--primary-005-color);
190 + border-color: var(--primary-030-color);
191 +
192 + &:not(.disabled) {
193 + &:hover {
194 + box-shadow: 0px 0px 0px 1px var(--primary-color);
195 + }
196 + }
197 + }
198 +
199 + &.disabled {
200 + @apply cursor-not-allowed;
201 +
202 + .card-entity-wrapper {
203 + @apply opacity-70;
204 + }
205 + }
206 +}
207 +</style>
frontend/src/components/common/cards/CardKV.vue renamed
frontend/src/components/common/cards/CardStats.vue renamed
+2 -2
@@ -1,11 +1,11 @@
1 <template>
2 <n-card :class="{ hovered }">
3 - <div class="flex items-center h-full overflow-hidden">
3 + <div class="flex h-full items-center overflow-hidden">
4 <div class="card-wrap flex gap-4" :class="{ 'flex-col items-center text-center': vertical }">
5 <div class="icon flex flex-col justify-center">
6 <slot name="icon"></slot>
7 </div>
8 - <div class="info flex flex-col grow overflow-hidden">
8 + <div class="info flex grow flex-col overflow-hidden">
9 <div class="title flex items-center gap-2">
10 {{ title }}
11 <Icon v-if="hovered" :name="ArrowRightIcon" :size="12"></Icon>
frontend/src/components/common/cards/CardStatsBars.vue renamed
+7 -7
@@ -1,8 +1,8 @@
1 <template>
2 <n-card content-style="padding:0" :class="{ hovered }">
3 <div class="flex flex-col overflow-hidden">
4 - <div class="card-header flex gap-4 items-center justify-between">
5 - <div class="title flex items-center gap-2 grow">
4 + <div class="card-header flex items-center justify-between gap-4">
5 + <div class="title flex grow items-center gap-2">
6 <span class="truncate">{{ title }}</span>
7 <Icon v-if="hovered" :name="ArrowRightIcon" :size="12"></Icon>
8 </div>
@@ -10,7 +10,7 @@
10 <slot name="icon"></slot>
11 </div>
12 </div>
13 - <div class="flex flex-col gap-3 card-content">
13 + <div class="card-content flex flex-col gap-3">
14 <div class="bars flex">
15 <div
16 v-for="item of barValues"
@@ -26,15 +26,15 @@
26 <div
27 v-for="item of sanitizedValues"
28 :key="JSON.stringify(item)"
29 - class="flex items-center item gap-3"
29 + class="item flex items-center gap-3"
30 :class="item.status"
31 >
32 - <div class="label flex gap-2 items-center truncate">
32 + <div class="label flex items-center gap-2 truncate">
33 <span class="badge"></span>
34 - <span class="font-mono truncate">{{ item.label }}</span>
34 + <span class="truncate font-mono">{{ item.label }}</span>
35 </div>
36 <div class="divider grow"></div>
37 - <div class="value flex gap-3 font-mono whitespace-nowrap">
37 + <div class="value flex gap-3 whitespace-nowrap font-mono">
38 <span v-if="!item.isTotal" class="opacity-50">{{ item.percentage }}%</span>
39 <strong>{{ item.value }}</strong>
40 </div>
frontend/src/components/common/cards/CardStatsIcon.vue renamed
frontend/src/components/common/cards/CardStatsMulti.vue renamed
+6 -6
@@ -1,8 +1,8 @@
1 <template>
2 <n-card content-style="padding:0" :class="{ hovered }">
3 - <div class="flex flex-col overflow-hidden h-full">
4 - <div class="card-header flex gap-4 items-center justify-between">
5 - <div class="title flex items-center gap-2 grow">
3 + <div class="flex h-full flex-col overflow-hidden">
4 + <div class="card-header flex items-center justify-between gap-4">
5 + <div class="title flex grow items-center gap-2">
6 <span class="truncate">{{ title }}</span>
7 <Icon v-if="hovered" :name="ArrowRightIcon" :size="12"></Icon>
8 </div>
@@ -10,14 +10,14 @@
10 <slot name="icon"></slot>
11 </div>
12 </div>
13 - <div class="flex card-content grow">
13 + <div class="card-content flex grow">
14 <div
15 v-for="item of values"
16 :key="JSON.stringify(item)"
17 - class="flex flex-col value-box"
17 + class="value-box flex flex-col"
18 :class="[item.status, values.length !== 1 ? `basis-1/${values.length}` : 'grow']"
19 >
20 - <div class="value grow flex justify-center items-center">
20 + <div class="value flex grow items-center justify-center">
21 {{ item.value }}
22 </div>
23 <div v-if="item.label" class="label">
frontend/src/components/connectors/ConfigForm/ConfigForm.vue
+2 -2
@@ -55,7 +55,7 @@
55
56 <div class="connector-footer mt-4">
57 <n-form-item>
58 - <div class="flex gap-2 justify-end w-full">
58 + <div class="flex w-full justify-end gap-2">
59 <n-button type="primary" @click="saveConnector()">Save</n-button>
60 <n-button @click="closeForm(false)">Cancel</n-button>
61 </div>
@@ -305,7 +305,7 @@ onMounted(() => {
305 .connector-header {
306 display: flex;
307 align-items: center;
308 - @apply gap-5 mb-7;
308 + @apply mb-7 gap-5;
309
310 .connector-image {
311 border: 2px solid var(--bg-body);
frontend/src/components/connectors/ConnectorItem.vue
+49 -90
@@ -1,60 +1,53 @@
1 <template>
2 - <n-spin :show="loading" class="connector-item">
3 - <div class="px-4 py-3 flex flex-col gap-2">
4 - <div class="main-box flex gap-6">
5 - <div class="content flex flex-col gap-2 grow">
6 - <div class="flex gap-4">
7 - <div class="avatar">
8 - <n-avatar
9 - class="connector-image"
10 - object-fit="contain"
11 - round
12 - :size="40"
13 - :src="`/images/connectors/${
14 - connector ? `${connector.connector_name.toLowerCase()}.svg` : 'default-logo.svg'
15 - }`"
16 - :alt="`${connector.connector_name} Logo`"
17 - fallback-src="/images/img-not-found.svg"
18 - />
2 + <div>
3 + <CardEntity :loading>
4 + <template #default>
5 + <div class="flex items-start gap-4">
6 + <n-avatar
7 + class="mt-0.5"
8 + object-fit="contain"
9 + round
10 + :size="40"
11 + :src="`/images/connectors/${
12 + connector ? `${connector.connector_name.toLowerCase()}.svg` : 'default-logo.svg'
13 + }`"
14 + :alt="`${connector.connector_name} Logo`"
15 + fallback-src="/images/img-not-found.svg"
16 + />
17 +
18 + <div class="flex flex-col gap-1">
19 + <div>
20 + {{ connector.connector_name }}
21 </div>
20 -
21 - <div class="info flex flex-col gap-2">
22 - <div class="name">
23 - {{ connector.connector_name }}
24 - </div>
25 - <div v-if="connector.connector_description" class="description">
26 - {{ connector.connector_description }}
27 - </div>
28 - <div v-if="connector.connector_extra_data" class="extra-data">
29 - {{ connector.connector_extra_data }}
30 - </div>
22 + <div v-if="connector.connector_description">
23 + {{ connector.connector_description }}
24 </div>
32 - </div>
33 -
34 - <div class="badges-box flex flex-wrap items-center gap-3 mt-2">
35 - <Badge :type="connector.connector_configured ? 'active' : 'muted'">
36 - <template #iconRight>
37 - <Icon
38 - :name="connector.connector_configured ? EnabledIcon : DisabledIcon"
39 - :size="14"
40 - ></Icon>
41 - </template>
42 - <template #label>Configured</template>
43 - </Badge>
44 -
45 - <Badge :type="connector.connector_verified ? 'active' : 'muted'">
46 - <template #iconRight>
47 - <Icon
48 - :name="connector.connector_verified ? EnabledIcon : DisabledIcon"
49 - :size="14"
50 - ></Icon>
51 - </template>
52 - <template #label>Verified</template>
53 - </Badge>
25 + <p v-if="connector.connector_extra_data">
26 + {{ connector.connector_extra_data }}
27 + </p>
28 </div>
29 </div>
30 + </template>
31
57 - <div class="actions-box flex flex-col gap-2 justify-center">
32 + <template #footerMain>
33 + <div class="flex flex-wrap items-center gap-3">
34 + <Badge :type="connector.connector_configured ? 'active' : 'muted'">
35 + <template #iconRight>
36 + <Icon :name="connector.connector_configured ? EnabledIcon : DisabledIcon" :size="14" />
37 + </template>
38 + <template #label>Configured</template>
39 + </Badge>
40 +
41 + <Badge :type="connector.connector_verified ? 'active' : 'muted'">
42 + <template #iconRight>
43 + <Icon :name="connector.connector_verified ? EnabledIcon : DisabledIcon" :size="14" />
44 + </template>
45 + <template #label>Verified</template>
46 + </Badge>
47 + </div>
48 + </template>
49 + <template #footerExtra>
50 + <div class="flex flex-wrap justify-end gap-2">
51 <n-button
52 v-if="!connector.connector_verified"
53 type="primary"
@@ -81,8 +74,8 @@
74 {{ !connector.connector_configured ? "Configure" : "Update" }}
75 </n-button>
76 </div>
84 - </div>
85 - </div>
77 + </template>
78 + </CardEntity>
79
80 <n-modal
81 v-model:show="showConfigDialog"
@@ -100,15 +93,16 @@
93 />
94 </n-card>
95 </n-modal>
103 - </n-spin>
96 + </div>
97 </template>
98
99 <script setup lang="ts">
100 import type { Connector } from "@/types/connectors.d"
101 import Api from "@/api"
102 import Badge from "@/components/common/Badge.vue"
103 +import CardEntity from "@/components/common/cards/CardEntity.vue"
104 import Icon from "@/components/common/Icon.vue"
111 -import { NAvatar, NButton, NCard, NModal, NSpin, useMessage } from "naive-ui"
105 +import { NAvatar, NButton, NCard, NModal, useMessage } from "naive-ui"
106 import { computed, ref, toRefs } from "vue"
107 import ConfigForm from "./ConfigForm"
108
@@ -164,38 +158,3 @@ function verify(connector: Connector) {
158 })
159 }
160 </script>
167 -
168 -<style lang="scss" scoped>
169 -.connector-item {
170 - border-radius: var(--border-radius);
171 - background-color: var(--bg-color);
172 - transition: all 0.2s var(--bezier-ease);
173 - border: var(--border-small-050);
174 -
175 - .main-box {
176 - .connector-image {
177 - border: 2px solid var(--bg-body);
178 - min-width: 40px;
179 - min-height: 40px;
180 - }
181 - .content {
182 - word-break: break-word;
183 -
184 - .name {
185 - font-weight: bold;
186 - }
187 - .description {
188 - font-size: 13px;
189 - }
190 - .extra-data {
191 - color: var(--fg-secondary-color);
192 - font-size: 13px;
193 - }
194 - }
195 - }
196 -
197 - &:hover {
198 - box-shadow: 0px 0px 0px 1px inset var(--primary-color);
199 - }
200 -}
201 -</style>
frontend/src/components/connectors/ConnectorsList.vue
+4 -13
@@ -1,14 +1,14 @@
1 <template>
2 <div class="connectors-list">
3 - <div class="header mb-4 flex gap-5 justify-between items-center">
3 + <div class="header mb-4 flex items-center justify-between gap-5">
4 <div>
5 Total:
6 <strong class="font-mono">{{ totalCustomers }}</strong>
7 </div>
8 - <div class="text-secondary-color text-right">Configure connections to your toolset</div>
8 + <div class="text-secondary text-right">Configure connections to your toolset</div>
9 </div>
10 <n-spin :show="loadingConnectors">
11 - <div class="list">
11 + <div class="min-h-52">
12 <template v-if="connectorsList.length">
13 <ConnectorItem
14 v-for="connector of connectorsList"
@@ -20,7 +20,7 @@
20 />
21 </template>
22 <template v-else>
23 - <n-empty v-if="!loadingConnectors" description="No items found" class="justify-center h-48" />
23 + <n-empty v-if="!loadingConnectors" description="No items found" class="h-48 justify-center" />
24 </template>
25 </div>
26 </n-spin>
@@ -66,12 +66,3 @@ onBeforeMount(() => {
66 getConnectors()
67 })
68 </script>
69 -
70 -<style lang="scss" scoped>
71 -.connectors-list {
72 - .list {
73 - container-type: inline-size;
74 - min-height: 200px;
75 - }
76 -}
77 -</style>
frontend/src/components/customers/CustomerAgents.vue
+2 -2
@@ -5,13 +5,13 @@
5 v-for="agent in list"
6 :key="agent.agent_id"
7 :agent="agent"
8 - bg-secondary
8 + embedded
9 show-actions
10 class="item-appear item-appear-bottom item-appear-005"
11 @delete="getAgents()"
12 @click="gotoAgent(agent.agent_id)"
13 />
14 - <n-empty v-if="!list.length" description="No Agents found" class="justify-center h-48" />
14 + <n-empty v-if="!list.length" description="No Agents found" class="h-48 justify-center" />
15 </div>
16 </n-spin>
17 </template>
frontend/src/components/customers/CustomerInfo.vue
+4 -4
@@ -23,15 +23,15 @@
23 </n-button>
24 </div>
25
26 - <div class="grid gap-2 grid-auto-fit-200 p-7 pt-4">
27 - <KVCard v-for="(value, key) of customer" :key="key">
26 + <div class="grid-auto-fit-200 grid gap-2 p-7 pt-4">
27 + <CardKV v-for="(value, key) of customer" :key="key">
28 <template #key>
29 {{ key }}
30 </template>
31 <template #value>
32 {{ value || "-" }}
33 </template>
34 - </KVCard>
34 + </CardKV>
35 </div>
36 </template>
37 </div>
@@ -40,8 +40,8 @@
40 <script setup lang="ts">
41 import type { Customer } from "@/types/customers.d"
42 import Api from "@/api"
43 +import CardKV from "@/components/common/cards/CardKV.vue"
44 import Icon from "@/components/common/Icon.vue"
44 -import KVCard from "@/components/common/KVCard.vue"
45 import { NButton, useDialog, useMessage } from "naive-ui"
46 import { h, ref, toRefs, watch } from "vue"
47 import CustomerForm from "./CustomerForm.vue"
frontend/src/components/customers/CustomerItem.vue
+110 -132
@@ -1,106 +1,117 @@
1 <template>
2 - <n-spin :id="`customer-${customer.customer_code}`" :show="loading" :class="{ highlight }" class="customer-item">
3 - <div class="px-4 py-3 flex flex-col gap-2">
4 - <div class="header-box flex justify-between items-center">
5 - <div class="id">#{{ customer.customer_code }}</div>
6 - <div v-if="!hideCardActions" class="actions">
7 - <n-button size="small" @click.stop="showDetails = true">
8 - <template #icon>
9 - <Icon :name="DetailsIcon"></Icon>
10 - </template>
11 - Details
12 - </n-button>
13 - </div>
14 - </div>
15 - <div class="main-box flex items-center gap-3">
16 - <n-avatar
17 - :src="customerInfo?.logo_file || fallbackAvatar"
18 - :fallback-src="fallbackAvatar"
19 - round
20 - :size="40"
21 - />
2 + <div :id="`customer-${customer.customer_code}`">
3 + <CardEntity :loading :highlighted="!!highlight">
4 + <template #default>
5 + <div class="flex items-start gap-4">
6 + <n-avatar
7 + :src="customerInfo?.logo_file || fallbackAvatar"
8 + :fallback-src="fallbackAvatar"
9 + round
10 + :size="40"
11 + />
12
23 - <div class="content flex flex-col gap-1 grow">
24 - <div class="title">
25 - {{ customerInfo?.customer_name }}
26 - </div>
27 - <div class="description">
28 - {{ customerInfo?.contact_first_name }} {{ customerInfo?.contact_last_name }}
13 + <div class="flex flex-col gap-1">
14 + <div class="flex flex-wrap gap-2">
15 + {{ customerInfo?.customer_name }}
16 + <span class="text-secondary">#{{ customer.customer_code }}</span>
17 + </div>
18 + <p class="text-sm">
19 + {{ customerInfo?.contact_first_name }} {{ customerInfo?.contact_last_name }}
20 + </p>
21 </div>
22 </div>
31 - </div>
32 -
33 - <div class="badges-box flex flex-wrap items-center gap-3 mt-2">
34 - <Badge type="splitted" color="primary">
35 - <template #iconLeft>
36 - <Icon :name="UserTypeIcon" :size="14"></Icon>
37 - </template>
38 - <template #label>Type</template>
39 - <template #value>
40 - {{ customerInfo?.customer_type || "-" }}
41 - </template>
42 - </Badge>
23 + </template>
24
44 - <n-popover trigger="hover" :disabled="addressLabel === '-'">
45 - <template #trigger>
46 - <Badge type="splitted" color="primary" :class="{ 'cursor-help': addressLabel !== '-' }">
47 - <template #iconLeft>
48 - <Icon :name="LocationIcon" :size="13"></Icon>
49 - </template>
50 - <template #value>
51 - {{ addressLabel }}
52 - </template>
53 - </Badge>
54 - </template>
25 + <template #footerMain>
26 + <div class="flex flex-wrap items-center gap-3">
27 + <Badge type="splitted" color="primary">
28 + <template #iconLeft>
29 + <Icon :name="UserTypeIcon" :size="14"></Icon>
30 + </template>
31 + <template #label>Type</template>
32 + <template #value>
33 + {{ customerInfo?.customer_type || "-" }}
34 + </template>
35 + </Badge>
36 +
37 + <n-popover trigger="hover" :disabled="addressLabel === '-'">
38 + <template #trigger>
39 + <Badge type="splitted" color="primary" :class="{ 'cursor-help': addressLabel !== '-' }">
40 + <template #iconLeft>
41 + <Icon :name="LocationIcon" :size="13"></Icon>
42 + </template>
43 + <template #value>
44 + <div class="flex flex-wrap items-center gap-2">
45 + {{ addressLabel }}
46 + <Icon
47 + v-if="addressLabel !== '-'"
48 + :name="InfoIcon"
49 + :size="13"
50 + class="!opacity-80"
51 + ></Icon>
52 + </div>
53 + </template>
54 + </Badge>
55 + </template>
56
56 - <div class="flex flex-col gap-1">
57 - <div v-if="customerInfo?.address_line1" class="box">
58 - address_line1:
59 - <code>{{ customerInfo.address_line1 }}</code>
60 - </div>
61 - <div v-if="customerInfo?.address_line2" class="box">
62 - address_line2:
63 - <code>{{ customerInfo.address_line2 }}</code>
64 - </div>
65 - <div v-if="customerInfo?.postal_code" class="box">
66 - postal_code:
67 - <code>{{ customerInfo.postal_code }}</code>
68 - </div>
69 - <div v-if="customerInfo?.city" class="box">
70 - city:
71 - <code>{{ customerInfo.city }}</code>
72 - </div>
73 - <div v-if="customerInfo?.state" class="box">
74 - state:
75 - <code>{{ customerInfo.state }}</code>
76 - </div>
77 - <div v-if="customerInfo?.country" class="box">
78 - country:
79 - <code>{{ customerInfo.country }}</code>
57 + <div class="flex flex-col gap-1">
58 + <div v-if="customerInfo?.address_line1" class="box">
59 + address_line1:
60 + <code>{{ customerInfo.address_line1 }}</code>
61 + </div>
62 + <div v-if="customerInfo?.address_line2" class="box">
63 + address_line2:
64 + <code>{{ customerInfo.address_line2 }}</code>
65 + </div>
66 + <div v-if="customerInfo?.postal_code" class="box">
67 + postal_code:
68 + <code>{{ customerInfo.postal_code }}</code>
69 + </div>
70 + <div v-if="customerInfo?.city" class="box">
71 + city:
72 + <code>{{ customerInfo.city }}</code>
73 + </div>
74 + <div v-if="customerInfo?.state" class="box">
75 + state:
76 + <code>{{ customerInfo.state }}</code>
77 + </div>
78 + <div v-if="customerInfo?.country" class="box">
79 + country:
80 + <code>{{ customerInfo.country }}</code>
81 + </div>
82 </div>
81 - </div>
82 - </n-popover>
83 + </n-popover>
84
84 - <Badge type="splitted" color="primary">
85 - <template #iconLeft>
86 - <Icon :name="PhoneIcon" :size="13"></Icon>
87 - </template>
88 - <template #value>
89 - {{ customerInfo?.phone || "-" }}
90 - </template>
91 - </Badge>
85 + <Badge type="splitted" color="primary">
86 + <template #iconLeft>
87 + <Icon :name="PhoneIcon" :size="13"></Icon>
88 + </template>
89 + <template #value>
90 + {{ customerInfo?.phone || "-" }}
91 + </template>
92 + </Badge>
93
93 - <Badge v-if="customerInfo?.parent_customer_code" type="splitted" color="primary">
94 - <template #iconLeft>
95 - <Icon :name="ParentIcon" :size="13"></Icon>
96 - </template>
97 - <template #label>Parent</template>
98 - <template #value>
99 - {{ customerInfo?.parent_customer_code }}
94 + <Badge v-if="customerInfo?.parent_customer_code" type="splitted" color="primary">
95 + <template #iconLeft>
96 + <Icon :name="ParentIcon" :size="13"></Icon>
97 + </template>
98 + <template #label>Parent</template>
99 + <template #value>
100 + {{ customerInfo?.parent_customer_code }}
101 + </template>
102 + </Badge>
103 + </div>
104 + </template>
105 +
106 + <template v-if="!hideCardActions" #footerExtra>
107 + <n-button size="small" @click.stop="showDetails = true">
108 + <template #icon>
109 + <Icon :name="DetailsIcon"></Icon>
110 </template>
101 - </Badge>
102 - </div>
103 - </div>
111 + Details
112 + </n-button>
113 + </template>
114 + </CardEntity>
115
116 <n-modal
117 v-model:show="showDetails"
@@ -155,7 +166,7 @@
166 <CustomerNotificationsWorkflows :customer-code="customer.customer_code" />
167 </n-tab-pane>
168 <template #suffix>
158 - <div class="pr-8 hover:text-primary-color cursor-pointer" @click="selectedTabsGroup = 'agents'">
169 + <div class="hover:text-primary cursor-pointer pr-8" @click="selectedTabsGroup = 'agents'">
170 Agents
171 </div>
172 </template>
@@ -163,7 +174,7 @@
174 <n-tabs v-else-if="selectedTabsGroup === 'agents'" type="line" animated :tabs-padding="24">
175 <template #prefix>
176 <div
166 - class="pl-6 relative top-1 hover:text-primary-color cursor-pointer"
177 + class="hover:text-primary relative top-1 cursor-pointer pl-6"
178 @click="selectedTabsGroup = 'customer'"
179 >
180 <Icon :name="ArrowIcon" :size="20"></Icon>
@@ -200,17 +211,18 @@
211 </n-tabs>
212 </Transition>
213 </n-modal>
203 - </n-spin>
214 + </div>
215 </template>
216
217 <script setup lang="ts">
218 import type { Customer, CustomerMeta } from "@/types/customers.d"
219 import Api from "@/api"
220 import Badge from "@/components/common/Badge.vue"
221 +import CardEntity from "@/components/common/cards/CardEntity.vue"
222 import Icon from "@/components/common/Icon.vue"
223 import { hashMD5 } from "@/utils"
224 import _toSafeInteger from "lodash/toSafeInteger"
213 -import { NAvatar, NButton, NModal, NPopover, NScrollbar, NSpin, NTabPane, NTabs, useMessage } from "naive-ui"
225 +import { NAvatar, NButton, NModal, NPopover, NScrollbar, NTabPane, NTabs, useMessage } from "naive-ui"
226 import { computed, defineAsyncComponent, onBeforeMount, ref, toRefs, watch } from "vue"
227
228 const props = defineProps<{
@@ -238,6 +250,7 @@ const { customer, highlight, hideCardActions } = toRefs(props)
250 const DetailsIcon = "carbon:settings-adjust"
251 const UserTypeIcon = "solar:shield-user-linear"
252 const ParentIcon = "material-symbols-light:supervisor-account-outline-rounded"
253 +const InfoIcon = "carbon:information"
254 const ArrowIcon = "carbon:arrow-left"
255 const LocationIcon = "carbon:location"
256 const PhoneIcon = "carbon:phone"
@@ -317,41 +330,6 @@ onBeforeMount(() => {
330 })
331 </script>
332
320 -<style lang="scss" scoped>
321 -.customer-item {
322 - border-radius: var(--border-radius);
323 - background-color: var(--bg-color);
324 - transition: all 0.2s var(--bezier-ease);
325 - border: var(--border-small-050);
326 -
327 - .header-box {
328 - font-size: 13px;
329 - .id {
330 - font-family: var(--font-family-mono);
331 - word-break: break-word;
332 - color: var(--fg-secondary-color);
333 - line-height: 1.2;
334 - }
335 - }
336 -
337 - .main-box {
338 - .content {
339 - word-break: break-word;
340 -
341 - .description {
342 - color: var(--fg-secondary-color);
343 - font-size: 13px;
344 - }
345 - }
346 - }
347 -
348 - &.highlight,
349 - &:hover {
350 - box-shadow: 0px 0px 0px 1px inset var(--primary-color);
351 - }
352 -}
353 -</style>
354 -
333 <style>
334 .slide-tabs-right-enter-active,
335 .slide-tabs-right-leave-active,
frontend/src/components/customers/CustomersList.vue
+3 -12
@@ -1,6 +1,6 @@
1 <template>
2 <div class="customers-list">
3 - <div class="header mb-4 flex gap-2 justify-between items-center">
3 + <div class="header mb-4 flex items-center justify-between gap-2">
4 <div>
5 Total:
6 <strong class="font-mono">{{ totalCustomers }}</strong>
@@ -10,7 +10,7 @@
10 </div>
11 </div>
12 <n-spin :show="loadingCustomers">
13 - <div class="list">
13 + <div class="min-h-52">
14 <template v-if="customersList.length">
15 <CustomerItem
16 v-for="customer of customersList"
@@ -23,7 +23,7 @@
23 />
24 </template>
25 <template v-else>
26 - <n-empty v-if="!loadingCustomers" description="No items found" class="justify-center h-48" />
26 + <n-empty v-if="!loadingCustomers" description="No items found" class="h-48 justify-center" />
27 </template>
28 </div>
29 </n-spin>
@@ -116,12 +116,3 @@ onBeforeMount(() => {
116 getCustomers()
117 })
118 </script>
119 -
120 -<style lang="scss" scoped>
121 -.customers-list {
122 - .list {
123 - container-type: inline-size;
124 - min-height: 200px;
125 - }
126 -}
127 -</style>
frontend/src/components/customers/healthcheck/CustomerHealthcheckItem.vue
+71 -139
@@ -1,71 +1,73 @@
1 <template>
2 - <div class="customer-healthcheck-item" :class="[{ 'bg-secondary': bgSecondary }, type]">
3 - <div class="px-4 py-3 flex flex-col gap-2">
4 - <div class="header-box flex justify-between items-center">
5 - <div class="id flex items-center gap-2 cursor-pointer" @click="showDetails = true">
6 - <span>#{{ healthData.id }} - {{ healthData.label }}</span>
7 - <Icon :name="InfoIcon" :size="16"></Icon>
8 - </div>
9 - <div v-if="cardDate" class="time">
10 - {{ cardDate }}
11 - </div>
12 - </div>
13 -
14 - <div class="main-box">
15 - <div class="content flex flex-col gap-1 grow">
16 - <div class="title">
17 - <Icon :name="iconFromOs(healthData.os)" :size="16" class="mr-1 relative top-0.5"></Icon>
2 + <div>
3 + <CardEntity
4 + :embedded
5 + hoverable
6 + clickable
7 + :status="type === 'healthy' ? 'success' : type === 'unhealthy' ? 'warning' : undefined"
8 + @click="showDetails = true"
9 + >
10 + <template #headerMain>#{{ healthData.id }} - {{ healthData.label }}</template>
11 + <template v-if="cardDate" #headerExtra>{{ cardDate }}</template>
12 + <template #default>
13 + <div class="flex grow flex-col gap-1">
14 + <div class="flex flex-wrap items-center gap-2">
15 + <Icon :name="iconFromOs(healthData.os)" :size="16"></Icon>
16 {{ healthData.os }}
17 </div>
20 - <div class="description">
18 + <p>
19 {{ healthData.ip_address }}
22 - </div>
20 + </p>
21 </div>
24 - </div>
25 -
26 - <div class="badges-box flex flex-wrap items-center gap-3 mt-2">
27 - <Badge v-if="agentVersion" type="splitted" color="primary">
28 - <template #label>Agent version</template>
29 - <template #value>
30 - {{ agentVersion }}
31 - </template>
32 - </Badge>
33 -
34 - <Badge v-if="source === 'velociraptor'" type="splitted" color="primary">
35 - <template #label>Velociraptor Id</template>
36 - <template #value>
37 - {{ healthData.velociraptor_id }}
38 - </template>
39 - </Badge>
40 -
41 - <n-popover overlap placement="bottom-start">
42 - <template #trigger>
43 - <Badge type="splitted" color="primary" hint-cursor>
44 - <template #iconLeft>
45 - <Icon :name="AgentIcon" :size="13" class="!opacity-80"></Icon>
46 - </template>
47 - <template #label>Agent</template>
48 - <template #value>
49 - {{ healthData.hostname }}
50 - </template>
51 - </Badge>
52 - </template>
53 - <div class="flex flex-col gap-1">
54 - <div class="box">
55 - agent_id:
56 - <code class="cursor-pointer text-primary-color" @click="gotoAgent(healthData.agent_id)">
57 - {{ healthData.agent_id }}
58 - <Icon :name="LinkIcon" :size="13" class="relative top-0.5" />
59 - </code>
22 + </template>
23 + <template #mainExtra>
24 + <div class="flex flex-wrap items-center gap-3">
25 + <Badge v-if="agentVersion" type="splitted">
26 + <template #label>Agent version</template>
27 + <template #value>
28 + {{ agentVersion }}
29 + </template>
30 + </Badge>
31 +
32 + <Badge v-if="source === 'velociraptor'" type="splitted">
33 + <template #label>Velociraptor Id</template>
34 + <template #value>
35 + {{ healthData.velociraptor_id }}
36 + </template>
37 + </Badge>
38 +
39 + <n-popover overlap placement="bottom-start">
40 + <template #trigger>
41 + <Badge type="splitted" hint-cursor>
42 + <template #iconLeft>
43 + <Icon :name="AgentIcon" :size="13" class="!opacity-80"></Icon>
44 + </template>
45 + <template #label>Agent</template>
46 + <template #value>
47 + <div class="flex items-center gap-2">
48 + {{ healthData.hostname }}
49 + <Icon :name="InfoIcon" :size="14"></Icon>
50 + </div>
51 + </template>
52 + </Badge>
53 + </template>
54 + <div class="flex flex-col gap-1">
55 + <div class="box">
56 + agent_id:
57 + <code class="text-primary cursor-pointer" @click="gotoAgent(healthData.agent_id)">
58 + {{ healthData.agent_id }}
59 + <Icon :name="LinkIcon" :size="13" class="relative top-0.5" />
60 + </code>
61 + </div>
62 + <div class="box">
63 + hostname:
64 + <code>{{ healthData.hostname }}</code>
65 + </div>
66 </div>
61 - <div class="box">
62 - hostname:
63 - <code>{{ healthData.hostname }}</code>
64 - </div>
65 - </div>
66 - </n-popover>
67 - </div>
68 - </div>
67 + </n-popover>
68 + </div>
69 + </template>
70 + </CardEntity>
71
72 <n-modal
73 v-model:show="showDetails"
@@ -76,15 +78,15 @@
78 :bordered="false"
79 segmented
80 >
79 - <div class="grid gap-2 grid-auto-fit-200 px-7 py-6">
80 - <KVCard v-for="(value, key) of healthData" :key="key">
81 + <div class="grid-auto-fit-200 grid gap-2 px-7 py-6">
82 + <CardKV v-for="(value, key) of healthData" :key="key">
83 <template #key>
84 {{ key }}
85 </template>
86 <template #value>
87 {{ value || "-" }}
88 </template>
87 - </KVCard>
89 + </CardKV>
90 </div>
91 </n-modal>
92 </div>
@@ -93,8 +95,9 @@
95 <script setup lang="ts">
96 import type { CustomerAgentHealth, CustomerHealthcheckSource } from "@/types/customers.d"
97 import Badge from "@/components/common/Badge.vue"
98 +import CardEntity from "@/components/common/cards/CardEntity.vue"
99 +import CardKV from "@/components/common/cards/CardKV.vue"
100 import Icon from "@/components/common/Icon.vue"
97 -import KVCard from "@/components/common/KVCard.vue"
101 import { useGoto } from "@/composables/useGoto"
102 import { useSettingsStore } from "@/stores/settings"
103 import { iconFromOs } from "@/utils"
@@ -102,11 +105,11 @@ import dayjs from "@/utils/dayjs"
105 import { NModal, NPopover } from "naive-ui"
106 import { computed, ref } from "vue"
107
105 -const { healthData, source, bgSecondary, type } = defineProps<{
108 +const { healthData, source, embedded, type } = defineProps<{
109 healthData: CustomerAgentHealth
110 source: CustomerHealthcheckSource
111 type?: "healthy" | "unhealthy"
109 - bgSecondary?: boolean
112 + embedded?: boolean
113 }>()
114
115 const InfoIcon = "carbon:information"
@@ -151,74 +154,3 @@ function formatDate(timestamp: string | number, utc: boolean = true): string {
154 return dayjs(timestamp).utc(utc).format(dFormats.datetimesec)
155 }
156 </script>
154 -
155 -<style lang="scss" scoped>
156 -.customer-healthcheck-item {
157 - border-radius: var(--border-radius);
158 - background-color: var(--bg-color);
159 - transition: all 0.2s var(--bezier-ease);
160 - border: var(--border-small-050);
161 -
162 - &.bg-secondary {
163 - background-color: var(--bg-secondary-color);
164 - }
165 -
166 - .header-box {
167 - font-family: var(--font-family-mono);
168 - font-size: 13px;
169 -
170 - .id {
171 - word-break: break-word;
172 - color: var(--fg-secondary-color);
173 - line-height: 1.2;
174 -
175 - &:hover {
176 - color: var(--primary-color);
177 - }
178 - }
179 -
180 - .time {
181 - color: var(--fg-secondary-color);
182 - }
183 - }
184 -
185 - .main-box {
186 - .content {
187 - word-break: break-word;
188 -
189 - .description {
190 - color: var(--fg-secondary-color);
191 - font-size: 13px;
192 - }
193 - }
194 - }
195 -
196 - &.healthy {
197 - border-color: var(--success-color);
198 - }
199 - &.unhealthy {
200 - border-color: var(--warning-color);
201 -
202 - .header-box {
203 - .id {
204 - &:hover {
205 - color: var(--warning-color);
206 - }
207 - }
208 - }
209 - }
210 -
211 - &:hover {
212 - box-shadow: 0px 0px 0px 1px inset var(--primary-color);
213 -
214 - &.healthy {
215 - background-color: var(--success-005-color);
216 - box-shadow: none;
217 - }
218 - &.unhealthy {
219 - background-color: var(--secondary3-opacity-005-color);
220 - box-shadow: none;
221 - }
222 - }
223 -}
224 -</style>
frontend/src/components/customers/healthcheck/CustomerHealthcheckList.vue
+9 -32
@@ -1,5 +1,5 @@
1 <template>
2 - <div class="flex mb-6 justify-end">
2 + <div class="mb-6 flex justify-end">
3 <div>
4 <n-input-group>
5 <n-select
@@ -14,9 +14,9 @@
14 </div>
15 </div>
16 <n-spin :show="loading">
17 - <div class="customer-healthcheck-list flex flex-col gap-6">
18 - <div v-if="healthyList.length" class="list flex flex-col gap-2">
19 - <div class="title healthy flex items-center gap-2">
17 + <div class="flex min-h-52 flex-col gap-6">
18 + <div v-if="healthyList.length" class="flex flex-col gap-2 [&:not(:last-child)]:mb-5">
19 + <div class="text-primary mb-2 flex items-center gap-2">
20 <Icon :name="CheckIcon" :size="16"></Icon>
21 Healthy
22 <code>{{ healthyList.length }}</code>
@@ -27,12 +27,12 @@
27 :health-data="item"
28 :source="source"
29 type="healthy"
30 - bg-secondary
30 + embedded
31 class="item-appear item-appear-bottom item-appear-005"
32 />
33 </div>
34 - <div v-if="unhealthyList.length" class="list flex flex-col gap-2">
35 - <div class="title unhealthy flex items-center gap-2">
34 + <div v-if="unhealthyList.length" class="flex flex-col gap-2 [&:not(:last-child)]:mb-5">
35 + <div class="text-warning mb-2 flex items-center gap-2">
36 <Icon :name="AlertIcon" :size="16"></Icon>
37 Unhealthy
38 <code>{{ unhealthyList.length }}</code>
@@ -43,11 +43,11 @@
43 :health-data="item"
44 :source="source"
45 type="unhealthy"
46 - bg-secondary
46 + embedded
47 class="item-appear item-appear-bottom item-appear-005"
48 />
49 </div>
50 - <n-empty v-if="!healthyList.length && !unhealthyList.length && !loading" class="justify-center h-48" />
50 + <n-empty v-if="!healthyList.length && !unhealthyList.length && !loading" class="h-48 justify-center" />
51 </div>
52 </n-spin>
53 </template>
@@ -155,26 +155,3 @@ onBeforeMount(() => {
155 getList()
156 })
157 </script>
158 -
159 -<style lang="scss" scoped>
160 -.customer-healthcheck-list {
161 - min-height: 200px;
162 -
163 - .list {
164 - .title {
165 - margin-bottom: 10px;
166 -
167 - &.healthy {
168 - color: var(--primary-color);
169 - }
170 - &.unhealthy {
171 - color: var(--warning-color);
172 - }
173 - }
174 -
175 - &:not(:last-child) {
176 - margin-bottom: 20px;
177 - }
178 - }
179 -}
180 -</style>
frontend/src/components/customers/integrations/CustomerIntegrationActions.vue
+3 -10
@@ -1,20 +1,13 @@
1 <template>
2 - <div class="alert-actions flex gap-4 justify-end">
3 - <n-button v-if="isDeployEnabled" :loading="loading" type="success" :size="size" secondary @click="provision()">
2 + <div class="contents">
3 + <n-button v-if="isDeployEnabled" :loading="loading" type="success" :size secondary @click.stop="provision()">
4 <template #icon>
5 <Icon :name="DeployIcon"></Icon>
6 </template>
7 Deploy
8 </n-button>
9
10 - <n-button
11 - v-if="!hideDeleteButton"
12 - :size="size"
13 - type="error"
14 - ghost
15 - :loading="loadingDelete"
16 - @click="handleDelete"
17 - >
10 + <n-button v-if="!hideDeleteButton" :size type="error" ghost :loading="loadingDelete" @click.stop="handleDelete">
11 <template #icon>
12 <Icon :name="DeleteIcon" :size="15"></Icon>
13 </template>
frontend/src/components/customers/integrations/CustomerIntegrationForm.vue
+3 -3
@@ -2,7 +2,7 @@
2 <div class="customer-integration-form flex flex-col gap-4">
3 <div>
4 <n-scrollbar x-scrollable trigger="none">
5 - <div class="px-7 pt-4 pb-2">
5 + <div class="px-7 pb-2 pt-4">
6 <n-steps :current="current" size="small" :status="currentStatus">
7 <n-step title="Choose Integration" />
8 <n-step title="Set Auth Keys">
@@ -15,7 +15,7 @@
15 </n-scrollbar>
16 </div>
17
18 - <div class="flex flex-col grow overflow-hidden">
18 + <div class="flex grow flex-col overflow-hidden">
19 <Transition :name="`slide-form-${slideFormDirection}`">
20 <div v-if="current === 1" class="available-list grow overflow-hidden">
21 <n-scrollbar style="max-height: 355px" trigger="none">
@@ -29,7 +29,7 @@
29 />
30 </n-scrollbar>
31 </div>
32 - <div v-else class="auth-key-form px-7 flex flex-wrap gap-3">
32 + <div v-else class="auth-key-form flex flex-wrap gap-3 px-7">
33 <template v-for="ak of authKeysForm" :key="ak.key">
34 <n-form-item v-if="ak.type === 'string'" :label="ak.key" required class="grow">
35 <n-input v-model:value="ak.value" :placeholder="`Input ${ak.key}...`" clearable />
frontend/src/components/customers/integrations/CustomerIntegrationItem.vue
+33 -91
@@ -1,47 +1,38 @@
1 <template>
2 - <div class="integration-item" :class="{ embedded }">
3 - <div class="px-4 py-3 flex flex-col gap-3">
4 - <div class="header-box flex justify-between items-center">
5 - <div class="id">#{{ integration.id }}</div>
6 - <div class="actions flex gap-3">
7 - <Badge v-if="integration.deployed" type="active">
8 - <template #iconLeft>
9 - <Icon :name="DeployIcon" :size="13"></Icon>
10 - </template>
11 - <template #value>Deployed</template>
12 - </Badge>
2 + <div>
3 + <CardEntity hoverable :embedded>
4 + <template #default>
5 + {{ serviceName }}
6 + </template>
7 +
8 + <template v-if="integration.deployed" #footerMain>
9 + <Badge type="active">
10 + <template #iconLeft>
11 + <Icon :name="DeployIcon" :size="13"></Icon>
12 + </template>
13 + <template #value>Deployed</template>
14 + </Badge>
15 + </template>
16 + <template #footerExtra>
17 + <div class="flex flex-wrap gap-3">
18 <n-button size="small" @click.stop="showDetails = true">
19 <template #icon>
20 <Icon :name="InfoIcon"></Icon>
21 </template>
22 + Details
23 </n-button>
24 +
25 + <CustomerIntegrationActions
26 + class="flex flex-wrap gap-3"
27 + :integration
28 + hide-delete-button
29 + size="small"
30 + @deployed="emit('deployed')"
31 + @deleted="emit('deleted')"
32 + />
33 </div>
19 - </div>
20 - <div class="main-box flex items-center gap-3">
21 - <div class="content flex flex-col gap-1 grow">
22 - <div class="title">
23 - {{ serviceName }}
24 - </div>
25 - </div>
26 - <CustomerIntegrationActions
27 - class="actions-box"
28 - :integration="integration"
29 - hide-delete-button
30 - @deployed="emit('deployed')"
31 - @deleted="emit('deleted')"
32 - />
33 - </div>
34 - <div class="footer-box flex justify-between items-center gap-4">
35 - <CustomerIntegrationActions
36 - class="actions-box"
37 - :integration="integration"
38 - hide-delete-button
39 - size="small"
40 - @deployed="emit('deployed')"
41 - @deleted="emit('deleted')"
42 - />
43 - </div>
44 - </div>
34 + </template>
35 + </CardEntity>
36
37 <n-modal
38 v-model:show="showDetails"
@@ -51,15 +42,15 @@
42 :bordered="false"
43 segmented
44 >
54 - <div class="grid gap-2 grid-auto-fit-200">
55 - <KVCard v-for="ak of authKeys" :key="ak.key">
45 + <div class="grid-auto-fit-200 grid gap-2">
46 + <CardKV v-for="ak of authKeys" :key="ak.key">
47 <template #key>
48 {{ ak.key }}
49 </template>
50 <template #value>
51 {{ ak.value || "-" }}
52 </template>
62 - </KVCard>
53 + </CardKV>
54 </div>
55 </n-modal>
56 </div>
@@ -68,8 +59,9 @@
59 <script setup lang="ts">
60 import type { CustomerIntegration } from "@/types/integrations.d"
61 import Badge from "@/components/common/Badge.vue"
62 +import CardEntity from "@/components/common/cards/CardEntity.vue"
63 +import CardKV from "@/components/common/cards/CardKV.vue"
64 import Icon from "@/components/common/Icon.vue"
72 -import KVCard from "@/components/common/KVCard.vue"
65 import _uniqBy from "lodash/uniqBy"
66 import { NButton, NModal } from "naive-ui"
67 import { computed, ref, toRefs } from "vue"
@@ -106,53 +98,3 @@ const authKeys = computed(() => {
98 return _uniqBy(keys, "key")
99 })
100 </script>
109 -
110 -<style lang="scss" scoped>
111 -.integration-item {
112 - border-radius: var(--border-radius);
113 - background-color: var(--bg-color);
114 - border: var(--border-small-050);
115 - transition: all 0.2s var(--bezier-ease);
116 -
117 - .header-box {
118 - font-size: 13px;
119 - .id {
120 - font-family: var(--font-family-mono);
121 - word-break: break-word;
122 - color: var(--fg-secondary-color);
123 - line-height: 1.2;
124 - }
125 - }
126 -
127 - .main-box {
128 - .content {
129 - word-break: break-word;
130 - }
131 - }
132 -
133 - .footer-box {
134 - display: none;
135 - font-size: 13px;
136 - margin-top: 10px;
137 - }
138 -
139 - &.embedded {
140 - background-color: var(--bg-secondary-color);
141 - }
142 -
143 - &:hover {
144 - box-shadow: 0px 0px 0px 1px inset var(--primary-color);
145 - }
146 -
147 - @container (max-width: 450px) {
148 - .main-box {
149 - .actions-box {
150 - display: none;
151 - }
152 - }
153 - .footer-box {
154 - display: flex;
155 - }
156 - }
157 -}
158 -</style>
frontend/src/components/customers/integrations/CustomerIntegrations.vue
+2 -7
@@ -21,7 +21,7 @@
21 </div>
22
23 <n-spin :show="loading">
24 - <div class="list p-7 pt-4">
24 + <div class="min-h-52 p-7 pt-4">
25 <template v-if="list.length">
26 <CustomerIntegrationItem
27 v-for="integration of list"
@@ -34,7 +34,7 @@
34 />
35 </template>
36 <template v-else>
37 - <n-empty v-if="!loading" description="No integrations found" class="justify-center h-48" />
37 + <n-empty v-if="!loading" description="No integrations found" class="h-48 justify-center" />
38 </template>
39 </div>
40 </n-spin>
@@ -105,11 +105,6 @@ onBeforeMount(() => {
105
106 <style lang="scss" scoped>
107 .customer-integrations {
108 - .list {
109 - container-type: inline-size;
110 - min-height: 200px;
111 - }
112 -
108 .form-fade-enter-active,
109 .form-fade-leave-active {
110 transition:
frontend/src/components/customers/networkConnectors/CustomerNetworkConnectorActions.vue
+5 -5
@@ -1,12 +1,12 @@
1 <template>
2 - <div class="alert-actions flex gap-4 justify-end">
2 + <div class="contents">
3 <n-button
4 v-if="networkConnector.deployed"
5 :loading="loadingDecommission"
6 type="error"
7 :size="size"
8 secondary
9 - @click="decommissionNetworkConnector()"
9 + @click.stop="decommissionNetworkConnector()"
10 >
11 <template #icon>
12 <Icon :name="DecommissionIcon"></Icon>
@@ -20,7 +20,7 @@
20 type="success"
21 :size="size"
22 secondary
23 - @click="showFortinetForm = true"
23 + @click.stop="showFortinetForm = true"
24 >
25 <template #icon>
26 <Icon :name="DeployIcon"></Icon>
@@ -34,7 +34,7 @@
34 type="error"
35 ghost
36 :loading="loadingDelete"
37 - @click="handleDelete"
37 + @click.stop="handleDelete"
38 >
39 <template #icon>
40 <Icon :name="DeleteIcon" :size="15"></Icon>
@@ -62,7 +62,7 @@
62 type="success"
63 secondary
64 :disabled="!isFortinetFormValid"
65 - @click="fortinetProvision()"
65 + @click.stop="fortinetProvision()"
66 >
67 <template #icon>
68 <Icon :name="DeployIcon"></Icon>
frontend/src/components/customers/networkConnectors/CustomerNetworkConnectorForm.vue
+3 -3
@@ -2,7 +2,7 @@
2 <div class="customer-network-connector-form flex flex-col gap-4">
3 <div>
4 <n-scrollbar x-scrollable trigger="none">
5 - <div class="px-7 pt-4 pb-2">
5 + <div class="px-7 pb-2 pt-4">
6 <n-steps :current="current" size="small" :status="currentStatus">
7 <n-step title="Choose Network Connector" />
8 <n-step title="Set Auth Keys">
@@ -15,7 +15,7 @@
15 </n-scrollbar>
16 </div>
17
18 - <div class="flex flex-col grow overflow-hidden">
18 + <div class="flex grow flex-col overflow-hidden">
19 <Transition :name="`slide-form-${slideFormDirection}`">
20 <div v-if="current === 1" class="available-list grow overflow-hidden">
21 <n-scrollbar style="max-height: 355px" trigger="none">
@@ -29,7 +29,7 @@
29 />
30 </n-scrollbar>
31 </div>
32 - <div v-else class="auth-key-form px-7 flex flex-wrap gap-3">
32 + <div v-else class="auth-key-form flex flex-wrap gap-3 px-7">
33 <template v-for="ak of authKeysForm" :key="ak.key">
34 <n-form-item v-if="ak.type === 'string'" :label="ak.key" required class="grow">
35 <n-input v-model:value="ak.value" :placeholder="`Input ${ak.key}...`" clearable />
frontend/src/components/customers/networkConnectors/CustomerNetworkConnectorItem.vue
+34 -93
@@ -1,49 +1,39 @@
1 <template>
2 - <div class="network-connector-item" :class="{ embedded }">
3 - <div class="px-4 py-3 flex flex-col gap-3">
4 - <div class="header-box flex justify-between items-center">
5 - <div class="id">#{{ networkConnector.id }}</div>
6 - <div class="actions flex gap-3">
7 - <Badge v-if="networkConnector.deployed" type="active">
8 - <template #iconLeft>
9 - <Icon :name="DeployIcon" :size="13"></Icon>
10 - </template>
11 - <template #value>Deployed</template>
12 - </Badge>
2 + <div>
3 + <CardEntity hoverable :embedded>
4 + <template #default>
5 + {{ serviceName }}
6 + </template>
7 +
8 + <template v-if="networkConnector.deployed" #footerMain>
9 + <Badge type="active">
10 + <template #iconLeft>
11 + <Icon :name="DeployIcon" :size="13"></Icon>
12 + </template>
13 + <template #value>Deployed</template>
14 + </Badge>
15 + </template>
16 + <template #footerExtra>
17 + <div class="flex flex-wrap gap-3">
18 <n-button size="small" @click.stop="showDetails = true">
19 <template #icon>
20 <Icon :name="InfoIcon"></Icon>
21 </template>
22 + Details
23 </n-button>
24 +
25 + <CustomerNetworkConnectorActions
26 + class="flex flex-wrap gap-3"
27 + :network-connector
28 + hide-delete-button
29 + size="small"
30 + @deployed="emit('deployed')"
31 + @deleted="emit('deleted')"
32 + @decommissioned="emit('decommissioned')"
33 + />
34 </div>
19 - </div>
20 - <div class="main-box flex items-center gap-3">
21 - <div class="content flex flex-col gap-1 grow">
22 - <div class="title">
23 - {{ serviceName }}
24 - </div>
25 - </div>
26 - <CustomerNetworkConnectorActions
27 - class="actions-box"
28 - :network-connector="networkConnector"
29 - hide-delete-button
30 - @deployed="emit('deployed')"
31 - @deleted="emit('deleted')"
32 - @decommissioned="emit('decommissioned')"
33 - />
34 - </div>
35 - <div class="footer-box flex justify-between items-center gap-4">
36 - <CustomerNetworkConnectorActions
37 - class="actions-box"
38 - :network-connector="networkConnector"
39 - hide-delete-button
40 - size="small"
41 - @deployed="emit('deployed')"
42 - @deleted="emit('deleted')"
43 - @decommissioned="emit('decommissioned')"
44 - />
45 - </div>
46 - </div>
35 + </template>
36 + </CardEntity>
37
38 <n-modal
39 v-model:show="showDetails"
@@ -53,15 +43,15 @@
43 :bordered="false"
44 segmented
45 >
56 - <div class="grid gap-2 grid-auto-fit-200">
57 - <KVCard v-for="ak of authKeys" :key="ak.key">
46 + <div class="grid-auto-fit-200 grid gap-2">
47 + <CardKV v-for="ak of authKeys" :key="ak.key">
48 <template #key>
49 {{ ak.key }}
50 </template>
51 <template #value>
52 {{ ak.value || "-" }}
53 </template>
64 - </KVCard>
54 + </CardKV>
55 </div>
56 </n-modal>
57 </div>
@@ -70,8 +60,9 @@
60 <script setup lang="ts">
61 import type { CustomerNetworkConnector } from "@/types/networkConnectors.d"
62 import Badge from "@/components/common/Badge.vue"
63 +import CardEntity from "@/components/common/cards/CardEntity.vue"
64 +import CardKV from "@/components/common/cards/CardKV.vue"
65 import Icon from "@/components/common/Icon.vue"
74 -import KVCard from "@/components/common/KVCard.vue"
66 import _uniqBy from "lodash/uniqBy"
67 import { NButton, NModal } from "naive-ui"
68 import { computed, ref, toRefs } from "vue"
@@ -109,53 +100,3 @@ const authKeys = computed(() => {
100 return _uniqBy(keys, "key")
101 })
102 </script>
112 -
113 -<style lang="scss" scoped>
114 -.network-connector-item {
115 - border-radius: var(--border-radius);
116 - background-color: var(--bg-color);
117 - border: var(--border-small-050);
118 - transition: all 0.2s var(--bezier-ease);
119 -
120 - .header-box {
121 - font-size: 13px;
122 - .id {
123 - font-family: var(--font-family-mono);
124 - word-break: break-word;
125 - color: var(--fg-secondary-color);
126 - line-height: 1.2;
127 - }
128 - }
129 -
130 - .main-box {
131 - .content {
132 - word-break: break-word;
133 - }
134 - }
135 -
136 - .footer-box {
137 - display: none;
138 - font-size: 13px;
139 - margin-top: 10px;
140 - }
141 -
142 - &.embedded {
143 - background-color: var(--bg-secondary-color);
144 - }
145 -
146 - &:hover {
147 - box-shadow: 0px 0px 0px 1px inset var(--primary-color);
148 - }
149 -
150 - @container (max-width: 450px) {
151 - .main-box {
152 - .actions-box {
153 - display: none;
154 - }
155 - }
156 - .footer-box {
157 - display: flex;
158 - }
159 - }
160 -}
161 -</style>
frontend/src/components/customers/networkConnectors/CustomerNetworkConnectors.vue
+2 -7
@@ -21,7 +21,7 @@
21 </div>
22
23 <n-spin :show="loading">
24 - <div class="list p-7 pt-4">
24 + <div class="min-h-52 p-7 pt-4">
25 <template v-if="list.length">
26 <CustomerNetworkConnectorItem
27 v-for="networkConnector of list"
@@ -38,7 +38,7 @@
38 <n-empty
39 v-if="!loading"
40 description="No network connectors found"
41 - class="justify-center h-48"
41 + class="h-48 justify-center"
42 />
43 </template>
44 </div>
@@ -110,11 +110,6 @@ onBeforeMount(() => {
110
111 <style lang="scss" scoped>
112 .customer-network-connectors {
113 - .list {
114 - container-type: inline-size;
115 - min-height: 200px;
116 - }
117 -
113 .form-fade-enter-active,
114 .form-fade-leave-active {
115 transition:
frontend/src/components/customers/notifications/CustomerNotificationsWorkflows.vue
+2 -7
@@ -15,7 +15,7 @@
15 <div v-else>
16 <n-spin :show="loading" class="min-h-48">
17 <template v-if="list.length">
18 - <div class="list p-7 pt-4">
18 + <div class="min-h-52 p-7 pt-4">
19 <CustomerNotificationsWorkflowsItem
20 v-for="item of list"
21 :key="item.id"
@@ -27,7 +27,7 @@
27 </div>
28 </template>
29 <template v-else>
30 - <n-empty v-if="!loading" class="justify-center h-48">
30 + <n-empty v-if="!loading" class="h-48 justify-center">
31 <div class="flex flex-col items-center gap-4">
32 <p>No Notification found</p>
33
@@ -111,11 +111,6 @@ onBeforeMount(() => {
111
112 <style lang="scss" scoped>
113 .customer-notifications-workflows {
114 - .list {
115 - container-type: inline-size;
116 - min-height: 200px;
117 - }
118 -
114 .form-fade-enter-active,
115 .form-fade-leave-active {
116 transition:
frontend/src/components/customers/notifications/CustomerNotificationsWorkflowsForm.vue
+1 -1
@@ -1,5 +1,5 @@
1 <template>
2 - <div class="customer-notifications-workflows-form flex flex-col justify-between grow">
2 + <div class="customer-notifications-workflows-form flex grow flex-col justify-between">
3 <div class="form-box">
4 <n-spin v-model:show="loading">
5 <n-form ref="formRef" :label-width="80" :model="form" :rules="rules">
frontend/src/components/customers/notifications/CustomerNotificationsWorkflowsItem.vue
+16 -58
@@ -1,27 +1,25 @@
1 <template>
2 - <div class="customer-notifications-workflows-item" :class="{ embedded }" @click="openForm()">
3 - <div class="px-4 py-3 flex flex-col gap-1">
4 - <div class="header-box flex justify-between items-center">
5 - <div class="label">shuffle_workflow_id</div>
6 - <div class="status flex gap-2 items-center">
7 - <span>{{ incidentNotification.enabled ? "Enabled" : "Disabled" }}</span>
2 + <div>
3 + <CardEntity :embedded clickable hoverable @click.stop="openForm()">
4 + <template #headerMain>shuffle_workflow_id</template>
5 + <template #headerExtra>
6 + <div class="flex items-center gap-2">
7 + <span :class="{ 'text-default': incidentNotification.enabled }">
8 + {{ incidentNotification.enabled ? "Enabled" : "Disabled" }}
9 + </span>
10 <Icon
11 v-if="incidentNotification.enabled"
12 :name="EnabledIcon"
13 :size="14"
12 - class="text-success-color"
14 + class="text-success"
15 ></Icon>
14 - <Icon v-else :name="DisabledIcon" :size="14" class="text-secondary-color"></Icon>
16 + <Icon v-else :name="DisabledIcon" :size="14" class="text-secondary"></Icon>
17 </div>
16 - </div>
17 - <div class="main-box flex items-center gap-3">
18 - <div class="content flex flex-col grow">
19 - <div class="title">
20 - {{ incidentNotification.shuffle_workflow_id }}
21 - </div>
22 - </div>
23 - </div>
24 - </div>
18 + </template>
19 + <template #default>
20 + {{ incidentNotification.shuffle_workflow_id }}
21 + </template>
22 + </CardEntity>
23
24 <n-modal
25 v-model:show="showForm"
@@ -44,6 +42,7 @@
42
43 <script setup lang="ts">
44 import type { IncidentNotification } from "@/types/incidentManagement/notifications.d"
45 +import CardEntity from "@/components/common/cards/CardEntity.vue"
46 import Icon from "@/components/common/Icon.vue"
47 import { NModal } from "naive-ui"
48 import { defineAsyncComponent, ref, toRefs, watch } from "vue"
@@ -83,44 +82,3 @@ function emitUpdate(incidentNotification: IncidentNotification) {
82 emit("updated", incidentNotification)
83 }
84 </script>
86 -
87 -<style lang="scss" scoped>
88 -.customer-notifications-workflows-item {
89 - border-radius: var(--border-radius);
90 - background-color: var(--bg-color);
91 - border: var(--border-small-050);
92 - transition: all 0.2s var(--bezier-ease);
93 - cursor: pointer;
94 -
95 - .header-box {
96 - font-size: 13px;
97 -
98 - .label {
99 - font-size: 11px;
100 - font-family: var(--font-family-mono);
101 - word-break: break-word;
102 - color: var(--fg-secondary-color);
103 - line-height: 1.2;
104 - }
105 - }
106 -
107 - .main-box {
108 - .content {
109 - word-break: break-word;
110 -
111 - .label {
112 - color: var(--fg-secondary-color);
113 - font-size: 11px;
114 - }
115 - }
116 - }
117 -
118 - &.embedded {
119 - background-color: var(--bg-secondary-color);
120 - }
121 -
122 - &:hover {
123 - box-shadow: 0px 0px 0px 1px inset var(--primary-color);
124 - }
125 -}
126 -</style>
frontend/src/components/customers/provision/CustomerProvision.vue
+4 -4
@@ -30,15 +30,15 @@
30 </n-button>
31 </div>
32
33 - <div class="grid gap-2 grid-auto-fit-200 p-7 pt-4">
34 - <KVCard v-for="(value, key) of customerMeta" :key="key">
33 + <div class="grid-auto-fit-200 grid gap-2 p-7 pt-4">
34 + <CardKV v-for="(value, key) of customerMeta" :key="key">
35 <template #key>
36 {{ key }}
37 </template>
38 <template #value>
39 {{ value || "-" }}
40 </template>
41 - </KVCard>
41 + </CardKV>
42 </div>
43 </div>
44 </transition>
@@ -48,8 +48,8 @@
48 <script setup lang="ts">
49 import type { CustomerMeta } from "@/types/customers.d"
50 import Api from "@/api"
51 +import CardKV from "@/components/common/cards/CardKV.vue"
52 import Icon from "@/components/common/Icon.vue"
52 -import KVCard from "@/components/common/KVCard.vue"
53 import { NButton, useDialog, useMessage } from "naive-ui"
54 import { computed, h, ref, toRefs } from "vue"
55 import CustomerProvisionWizard from "./CustomerProvisionWizard.vue"
frontend/src/components/customers/provision/CustomerProvisionWizard.vue
+7 -7
@@ -24,7 +24,7 @@
24
25 <n-form ref="formRef" :label-width="80" :model="form" :rules="rules" class="form-container mt-4">
26 <Transition :name="`slide-form-${slideFormDirection}`">
27 - <div v-if="current === 1" class="px-7 flex flex-col gap-3">
27 + <div v-if="current === 1" class="flex flex-col gap-3 px-7">
28 <div class="flex flex-wrap gap-3">
29 <n-form-item label="Customer Code" path="customer_code" class="grow">
30 <n-input
@@ -68,8 +68,8 @@
68 </n-form-item>
69 </div>
70
71 - <div v-else-if="current === 2" class="px-7 flex flex-col gap-3">
72 - <div class="flex flex-col sm:flex-row gap-3">
71 + <div v-else-if="current === 2" class="flex flex-col gap-3 px-7">
72 + <div class="flex flex-col gap-3 sm:flex-row">
73 <n-form-item
74 label="Customer Index name"
75 path="customer_index_name"
@@ -97,7 +97,7 @@
97 </div>
98 </div>
99
100 - <div v-else-if="current === 3" class="px-7 flex flex-col gap-3">
100 + <div v-else-if="current === 3" class="flex flex-col gap-3 px-7">
101 <n-form-item label="Subscriptions" path="customer_subscription" class="grow">
102 <n-select
103 v-model:value="form.customer_subscription"
@@ -119,7 +119,7 @@
119 :show-require-mark="false"
120 >
121 <template #label>
122 - <div class="flex items-center justify-between gap-4 w-full">
122 + <div class="flex w-full items-center justify-between gap-4">
123 <div>
124 Dashboards
125 <span class="n-form-item-label__asterisk">*</span>
@@ -148,7 +148,7 @@
148 </n-form-item>
149 </div>
150
151 - <div v-else-if="current === 4" class="px-7 flex gap-3">
151 + <div v-else-if="current === 4" class="flex gap-3 px-7">
152 <n-card class="grow">
153 <n-form-item label="Deploy HA Proxy" path="provision_ha_proxy">
154 <n-switch v-model:value="form.provision_ha_proxy" clearable />
@@ -161,7 +161,7 @@
161 </n-card>
162 </div>
163
164 - <div v-else-if="current === 5" class="px-7 flex flex-wrap gap-3">
164 + <div v-else-if="current === 5" class="flex flex-wrap gap-3 px-7">
165 <n-form-item label="Auth Password" path="wazuh_auth_password" class="grow">
166 <n-input
167 v-model:value="form.wazuh_auth_password"
frontend/src/components/graylog/Alerts/Item.vue
+75 -147
@@ -1,97 +1,85 @@
1 <template>
2 - <div class="item flex flex-col gap-2 px-5 py-3">
3 - <div class="header-box flex justify-between">
4 - <div class="id">
5 - <n-popover overlap placement="bottom-start">
6 - <template #trigger>
7 - <div class="flex items-center gap-2 cursor-help">
8 - <span>#{{ alertsEvent.event.id }}</span>
9 - <Icon :name="InfoIcon" :size="16"></Icon>
10 - </div>
11 - </template>
12 - <div class="flex flex-col gap-1">
13 - <div class="box">
14 - event_definition_id:
15 - <code
16 - class="cursor-pointer text-primary-color"
17 - @click="gotoEventsPage(alertsEvent.event.event_definition_id)"
18 - >
19 - {{ alertsEvent.event.event_definition_id }}
20 - <Icon :name="LinkIcon" :size="13" class="relative top-0.5" />
21 - </code>
22 - </div>
23 - <div class="box">
24 - event_definition_type:
25 - <code>{{ alertsEvent.event.event_definition_type }}</code>
26 - </div>
27 - <div class="box">
28 - source:
29 - <code>{{ alertsEvent.event.source }}</code>
30 - </div>
31 - <div class="box">
32 - index_name:
33 - <code class="cursor-pointer text-primary-color" @click="gotoIndex(alertsEvent.index_name)">
34 - {{ alertsEvent.index_name }}
35 - <Icon :name="LinkIcon" :size="13" class="relative top-0.5" />
36 - </code>
37 - </div>
38 - <div class="box">
39 - index_type:
40 - <code>{{ alertsEvent.index_type }}</code>
41 - </div>
42 - <div class="box">
43 - timestamp:
44 - <code>{{ formatDateTime(alertsEvent.event.timestamp) }}</code>
45 - </div>
46 - <div class="box">
47 - timestamp processing:
48 - <code>{{ formatDateTime(alertsEvent.event.timestamp_processing) }}</code>
49 - </div>
2 + <CardEntity>
3 + <template #headerMain>
4 + <n-popover overlap placement="bottom-start">
5 + <template #trigger>
6 + <div class="hover:text-primary flex cursor-help items-center gap-2">
7 + <span>#{{ alertsEvent.event.id }}</span>
8 + <Icon :name="InfoIcon" :size="16"></Icon>
9 </div>
51 - </n-popover>
52 - </div>
53 - <div class="time">
54 - <n-popover overlap placement="top-end">
55 - <template #trigger>
56 - <div class="flex items-center gap-2 cursor-help">
57 - <span>
58 - {{ formatDateTime(alertsEvent.event.timestamp) }}
59 - </span>
60 - <Icon :name="TimeIcon" :size="16"></Icon>
61 - </div>
62 - </template>
63 - <div class="flex flex-col py-2 px-1">
64 - <n-timeline>
65 - <n-timeline-item
66 - type="success"
67 - title="Timestamp"
68 - :time="formatDateTime(alertsEvent.event.timestamp)"
69 - />
70 - <n-timeline-item
71 - v-if="alertsEvent.event.timestamp_processing"
72 - title="Processing"
73 - :time="formatDateTime(alertsEvent.event.timestamp_processing)"
74 - />
75 - </n-timeline>
10 + </template>
11 + <div class="flex flex-col gap-1">
12 + <div class="box">
13 + event_definition_id:
14 + <code
15 + class="text-primary cursor-pointer"
16 + @click="gotoEventsPage(alertsEvent.event.event_definition_id)"
17 + >
18 + {{ alertsEvent.event.event_definition_id }}
19 + <Icon :name="LinkIcon" :size="13" class="relative top-0.5" />
20 + </code>
21 </div>
77 - </n-popover>
78 - </div>
79 - </div>
80 - <div class="main-box">
81 - <div class="content">
82 - {{ alertsEvent.event.message }}
83 - </div>
84 - </div>
85 - <div class="footer-box flex justify-end items-center gap-3">
86 - <div class="time">
87 - {{ formatDateTime(alertsEvent.event.timestamp) }}
88 - </div>
89 - </div>
90 - </div>
22 + <div class="box">
23 + event_definition_type:
24 + <code>{{ alertsEvent.event.event_definition_type }}</code>
25 + </div>
26 + <div class="box">
27 + source:
28 + <code>{{ alertsEvent.event.source }}</code>
29 + </div>
30 + <div class="box">
31 + index_name:
32 + <code class="text-primary cursor-pointer" @click="gotoIndex(alertsEvent.index_name)">
33 + {{ alertsEvent.index_name }}
34 + <Icon :name="LinkIcon" :size="13" class="relative top-0.5" />
35 + </code>
36 + </div>
37 + <div class="box">
38 + index_type:
39 + <code>{{ alertsEvent.index_type }}</code>
40 + </div>
41 + <div class="box">
42 + timestamp:
43 + <code>{{ formatDateTime(alertsEvent.event.timestamp) }}</code>
44 + </div>
45 + <div class="box">
46 + timestamp processing:
47 + <code>{{ formatDateTime(alertsEvent.event.timestamp_processing) }}</code>
48 + </div>
49 + </div>
50 + </n-popover>
51 + </template>
52 + <template #headerExtra>
53 + <n-popover overlap placement="top-end">
54 + <template #trigger>
55 + <div class="hover:text-primary flex cursor-help items-center gap-2">
56 + <span>{{ formatDateTime(alertsEvent.event.timestamp) }}</span>
57 + <Icon :name="TimeIcon" :size="16"></Icon>
58 + </div>
59 + </template>
60 + <div class="flex flex-col px-1 py-2">
61 + <n-timeline>
62 + <n-timeline-item
63 + type="success"
64 + title="Timestamp"
65 + :time="formatDateTime(alertsEvent.event.timestamp)"
66 + />
67 + <n-timeline-item
68 + v-if="alertsEvent.event.timestamp_processing"
69 + title="Processing"
70 + :time="formatDateTime(alertsEvent.event.timestamp_processing)"
71 + />
72 + </n-timeline>
73 + </div>
74 + </n-popover>
75 + </template>
76 + <template #default>{{ alertsEvent.event.message }}</template>
77 + </CardEntity>
78 </template>
79
80 <script setup lang="ts">
81 import type { AlertsEventElement } from "@/types/graylog/alerts.d"
82 +import CardEntity from "@/components/common/cards/CardEntity.vue"
83 import Icon from "@/components/common/Icon.vue"
84 import { useGoto } from "@/composables/useGoto"
85 import { useSettingsStore } from "@/stores/settings"
@@ -119,63 +107,3 @@ function gotoEventsPage(event_definition_id: string) {
107 emit("clickEvent", event_definition_id)
108 }
109 </script>
122 -
123 -<style lang="scss" scoped>
124 -.item {
125 - border-radius: var(--border-radius);
126 - background-color: var(--bg-color);
127 - transition: all 0.2s var(--bezier-ease);
128 - border: var(--border-small-050);
129 -
130 - .header-box {
131 - font-family: var(--font-family-mono);
132 - font-size: 13px;
133 - .id {
134 - word-break: break-word;
135 - color: var(--fg-secondary-color);
136 -
137 - &:hover {
138 - color: var(--primary-color);
139 - }
140 - }
141 - .time {
142 - color: var(--fg-secondary-color);
143 -
144 - &:hover {
145 - color: var(--primary-color);
146 - }
147 - }
148 - }
149 - .main-box {
150 - .content {
151 - word-break: break-word;
152 - }
153 - }
154 - .footer-box {
155 - font-family: var(--font-family-mono);
156 - font-size: 13px;
157 - margin-top: 10px;
158 - display: none;
159 -
160 - .time {
161 - text-align: right;
162 - color: var(--fg-secondary-color);
163 - }
164 - }
165 -
166 - &:hover {
167 - box-shadow: 0px 0px 0px 1px inset var(--primary-color);
168 - }
169 -
170 - @container (max-width: 650px) {
171 - .header-box {
172 - .time {
173 - display: none;
174 - }
175 - }
176 - .footer-box {
177 - display: flex;
178 - }
179 - }
180 -}
181 -</style>
frontend/src/components/graylog/Alerts/List.vue
+11 -14
@@ -1,10 +1,10 @@
1 <template>
2 <n-spin :show="loading">
3 <div ref="header" class="header flex items-center justify-end gap-2">
4 - <div class="info grow flex gap-5">
4 + <div class="info flex grow gap-5">
5 <n-popover overlap placement="bottom-start">
6 <template #trigger>
7 - <div class="bg-color border-radius">
7 + <div class="bg-default rounded-default">
8 <n-button size="small" class="!cursor-help">
9 <template #icon>
10 <Icon :name="InfoIcon"></Icon>
@@ -36,7 +36,7 @@
36 <n-select v-if="!compactMode" v-model:value="timerange" size="small" :options="timeOptions" class="!w-32" />
37 <n-popover v-if="compactMode" overlap placement="right">
38 <template #trigger>
39 - <div class="bg-color border-radius">
39 + <div class="bg-default rounded-default">
40 <n-button size="small">
41 <template #icon>
42 <Icon :name="FilterIcon"></Icon>
@@ -45,12 +45,12 @@
45 </div>
46 </template>
47 <div class="mb-2">
48 - <div class="text-secondary-color text-sm my-1">Time range:</div>
49 - <n-select v-model:value="timerange" size="small" :options="timeOptions" class="!w-32 mb-1" />
48 + <div class="text-secondary my-1 text-sm">Time range:</div>
49 + <n-select v-model:value="timerange" size="small" :options="timeOptions" class="mb-1 !w-32" />
50 </div>
51 </n-popover>
52 </div>
53 - <div class="list flex flex-col gap-2 my-3">
53 + <div class="my-3 flex min-h-28 flex-col gap-2">
54 <template v-if="alertsEvents.length">
55 <AlertsEventItem
56 v-for="alertsEvent of alertsEvents"
@@ -60,7 +60,7 @@
60 />
61 </template>
62 <template v-else>
63 - <n-empty v-if="!loading" description="No items found" class="justify-center h-48" />
63 + <n-empty v-if="!loading" description="No items found" class="h-48 justify-center" />
64 </template>
65 </div>
66 <div class="footer flex justify-end">
@@ -207,12 +207,9 @@ watch([currentPage, pageSize, timerange], ([page, pageSize, timerange]) => {
207
208 onBeforeMount(() => {
209 getData(currentPage.value, pageSize.value, timerange.value)
210 + // MOCK
211 + /*
212 + alertsEvents.value = alerts_event_element
213 + */
214 })
215 </script>
212 -
213 -<style lang="scss" scoped>
214 -.list {
215 - container-type: inline-size;
216 - min-height: 200px;
217 -}
218 -</style>
frontend/src/components/graylog/Alerts/mock.ts new
+59
@@ -0,0 +1,59 @@
1 +import type { AlertsEventElement } from "@/types/graylog/alerts.d"
2 +
3 +export const alerts_event_element: AlertsEventElement[] = [
4 + {
5 + event: {
6 + alert: true,
7 + event_definition_id: "event_def_001",
8 + event_definition_type: "threshold",
9 + fields: {
10 + field1: "value1",
11 + field2: "value2",
12 + field3: "value3"
13 + },
14 + group_by_fields: {},
15 + id: "event_12345",
16 + key: null,
17 + key_tuple: [],
18 + message: "Alert triggered due to threshold breach",
19 + origin_context: "system_monitor",
20 + priority: 1,
21 + source: "source_system",
22 + source_streams: ["stream_1", "stream_2"],
23 + streams: ["stream_1", "stream_2", "stream_3"],
24 + timerange_end: null,
25 + timerange_start: null,
26 + timestamp: "2024-10-22T10:15:30Z",
27 + timestamp_processing: "2024-10-22T10:16:00Z"
28 + },
29 + index_name: "alert_index_001",
30 + index_type: "logs"
31 + },
32 + {
33 + event: {
34 + alert: false,
35 + event_definition_id: "event_def_002",
36 + event_definition_type: "aggregation",
37 + fields: {
38 + fieldA: "valueA",
39 + fieldB: "valueB"
40 + },
41 + group_by_fields: {},
42 + id: "event_67890",
43 + key: null,
44 + key_tuple: [],
45 + message: "No issues detected, monitoring continues",
46 + origin_context: "network_monitor",
47 + priority: 3,
48 + source: "network_system",
49 + source_streams: ["stream_3"],
50 + streams: ["stream_3", "stream_4"],
51 + timerange_end: null,
52 + timerange_start: null,
53 + timestamp: "2024-10-22T10:17:45Z",
54 + timestamp_processing: "2024-10-22T10:18:00Z"
55 + },
56 + index_name: "alert_index_002",
57 + index_type: "metrics"
58 + }
59 +]
frontend/src/components/graylog/Events/Item.vue
+38 -109
@@ -1,41 +1,34 @@
1 <template>
2 - <div :id="`event-${event.id}`" class="item flex flex-col gap-2 px-5 py-3" :class="{ highlight }">
3 - <div class="header-box flex justify-between">
4 - <div class="flex items-center gap-3">
5 - <n-tooltip trigger="hover">
6 - <template #trigger>
7 - <div class="priority cursor-help">
8 - {{ event.priority }}
9 - </div>
10 - </template>
11 - Priority
12 - </n-tooltip>
13 - <div class="id">
14 - <div class="flex items-center gap-2 cursor-pointer" @click="showDetails = true">
15 - <span>#{{ event.id }}</span>
16 - <Icon :name="InfoIcon" :size="16"></Icon>
17 - </div>
2 + <div :id="`event-${event.id}`">
3 + <CardEntity :highlighted="!!highlight" hoverable clickable @click.stop="showDetails = true">
4 + <template #headerMain>
5 + <div class="flex items-center gap-3">
6 + <n-tooltip trigger="hover">
7 + <template #trigger>
8 + <div class="priority cursor-help">
9 + {{ event.priority }}
10 + </div>
11 + </template>
12 + Priority
13 + </n-tooltip>
14 + <span>#{{ event.id }}</span>
15 </div>
19 - </div>
20 - <div class="notification">
21 - Notifications:
22 - <strong>{{ event.notifications.length }}</strong>
23 - </div>
24 - </div>
25 - <div class="main-box">
26 - <div class="title">
27 - {{ event.title }}
28 - </div>
29 - <div class="description">
30 - {{ event.description }}
31 - </div>
32 - </div>
33 - <div class="footer-box flex justify-end items-center gap-3">
34 - <div class="notification">
16 + </template>
17 + <template #headerExtra>
18 Notifications:
19 <strong>{{ event.notifications.length }}</strong>
37 - </div>
38 - </div>
20 + </template>
21 + <template #default>
22 + <div class="flex flex-col gap-1">
23 + <div>
24 + {{ event.title }}
25 + </div>
26 + <p>
27 + {{ event.description }}
28 + </p>
29 + </div>
30 + </template>
31 + </CardEntity>
32
33 <n-modal
34 v-model:show="showDetails"
@@ -78,91 +71,27 @@
71
72 <script setup lang="ts">
73 import type { EventDefinition } from "@/types/graylog/event-definition.d"
81 -import Icon from "@/components/common/Icon.vue"
74 +import CardEntity from "@/components/common/cards/CardEntity.vue"
75 import { NInput, NModal, NTabPane, NTabs, NTooltip } from "naive-ui"
76 import { ref, toRefs } from "vue"
77 import { SimpleJsonViewer } from "vue-sjv"
85 -import "@/assets/scss/vuesjv-override.scss"
78 +import "@/assets/scss/overrides/vuesjv-override.scss"
79
80 const props = defineProps<{ event: EventDefinition; highlight: boolean | null | undefined }>()
81 const { event, highlight } = toRefs(props)
82
90 -const InfoIcon = "carbon:information"
91 -
83 const showDetails = ref(false)
84 </script>
85
86 <style lang="scss" scoped>
96 -.item {
97 - border-radius: var(--border-radius);
98 - background-color: var(--bg-color);
99 - transition: all 0.2s var(--bezier-ease);
100 - border: var(--border-small-050);
101 -
102 - .header-box {
103 - font-family: var(--font-family-mono);
104 - font-size: 13px;
105 -
106 - .priority {
107 - background-color: var(--hover-005-color);
108 - border: var(--border-small-100);
109 - width: 20px;
110 - height: 20px;
111 - border-radius: 99999px;
112 - text-align: center;
113 - line-height: 19px;
114 - font-size: 11px;
115 - }
116 - .id {
117 - word-break: break-word;
118 - color: var(--fg-secondary-color);
119 -
120 - &:hover {
121 - color: var(--primary-color);
122 - }
123 - }
124 - .notification {
125 - color: var(--fg-secondary-color);
126 - }
127 - }
128 - .main-box {
129 - word-break: break-word;
130 -
131 - .description {
132 - color: var(--fg-secondary-color);
133 - font-size: 13px;
134 - }
135 - }
136 - .footer-box {
137 - font-family: var(--font-family-mono);
138 - font-size: 13px;
139 - margin-top: 10px;
140 - display: none;
141 -
142 - .notification {
143 - text-align: right;
144 - color: var(--fg-secondary-color);
145 - }
146 - }
147 -
148 - &.highlight {
149 - background-color: var(--primary-005-color);
150 - box-shadow: 0px 0px 0px 1px inset var(--primary-030-color);
151 - }
152 -
153 - &:hover {
154 - box-shadow: 0px 0px 0px 1px inset var(--primary-color);
155 - }
156 -
157 - @container (max-width: 650px) {
158 - .header-box {
159 - .notification {
160 - display: none;
161 - }
162 - }
163 - .footer-box {
164 - display: flex;
165 - }
166 - }
87 +.priority {
88 + background-color: var(--hover-005-color);
89 + border: var(--border-small-100);
90 + width: 20px;
91 + height: 20px;
92 + border-radius: 99999px;
93 + text-align: center;
94 + line-height: 19px;
95 + font-size: 11px;
96 }
97 </style>
frontend/src/components/graylog/Events/List.vue
+4 -11
@@ -1,10 +1,10 @@
1 <template>
2 <n-spin :show="loading">
3 <div class="header flex items-center justify-end gap-2">
4 - <div class="info grow flex gap-5">
4 + <div class="info flex grow gap-5">
5 <n-popover overlap placement="bottom-start">
6 <template #trigger>
7 - <div class="bg-color border-radius">
7 + <div class="bg-default rounded-default">
8 <n-button size="small" class="!cursor-help">
9 <template #icon>
10 <Icon :name="InfoIcon"></Icon>
@@ -29,7 +29,7 @@
29 style="width: 110px"
30 />
31 </div>
32 - <div class="list flex flex-col gap-2 my-3">
32 + <div class="my-3 flex min-h-52 flex-col gap-2">
33 <template v-if="itemsPaginated.length">
34 <EventItem
35 v-for="event of itemsPaginated"
@@ -39,7 +39,7 @@
39 />
40 </template>
41 <template v-else>
42 - <n-empty v-if="!loading" description="No items found" class="justify-center h-48" />
42 + <n-empty v-if="!loading" description="No items found" class="h-48 justify-center" />
43 </template>
44 </div>
45 </n-spin>
@@ -141,10 +141,3 @@ onBeforeMount(() => {
141 getData()
142 })
143 </script>
144 -
145 -<style lang="scss" scoped>
146 -.list {
147 - container-type: inline-size;
148 - min-height: 200px;
149 -}
150 -</style>
frontend/src/components/graylog/Inputs/Item.vue
+41 -126
@@ -1,30 +1,23 @@
1 <template>
2 - <div class="item flex flex-col gap-2 px-5 py-3">
3 - <div class="header-box flex items-center gap-3">
4 - <div class="info flex items-center gap-2 grow">
5 - <div class="user flex items-center gap-2">
2 + <div>
3 + <CardEntity hoverable :embedded>
4 + <template #headerMain>
5 + <div class="flex items-center gap-2">
6 <Icon :name="UserIcon" :size="14"></Icon>
7 {{ input.creator_user_id }}
8 </div>
9 - </div>
10 - <div class="time">
11 - {{ formatDateTime(input.created_at) }}
12 - </div>
13 - <n-button size="small" @click.stop="showDetails = true">
14 - <template #icon>
15 - <Icon :name="InfoIcon"></Icon>
16 - </template>
17 - </n-button>
18 - </div>
19 - <div class="main-box flex justify-between">
20 - <div class="content">
21 - <div class="title">
9 + </template>
10 + <template #headerExtra>{{ formatDateTime(input.created_at) }}</template>
11 + <template #default>
12 + <div class="flex flex-col gap-1">
13 {{ input.title }}
14 + <p>
15 + {{ input.name }}
16 + </p>
17 </div>
24 - <div class="name mb-2">
25 - {{ input.name }}
26 - </div>
27 - <div class="badges-box flex flex-wrap items-center gap-3">
18 + </template>
19 + <template #footerMain>
20 + <div class="flex flex-wrap items-center gap-3">
21 <Badge :type="input.global ? 'active' : 'muted'">
22 <template #iconRight>
23 <Icon :name="input.global ? GlobalIcon : DisabledIcon" :size="14"></Icon>
@@ -43,43 +36,30 @@
36 {{ formatDateTime(input.started_at) }}
37 </n-tooltip>
38 </div>
46 - </div>
47 -
48 - <div class="actions-box flex flex-col justify-end">
49 - <n-button v-if="isRunning" :loading="loading" @click="stop()">
50 - <template #icon>
51 - <Icon :name="StopIcon"></Icon>
52 - </template>
53 - Stop input
54 - </n-button>
55 - <n-button v-else :loading="loading" type="primary" @click="start()">
56 - <template #icon>
57 - <Icon :name="StartIcon"></Icon>
58 - </template>
59 - Start input
60 - </n-button>
61 - </div>
62 - </div>
63 - <div class="footer-box flex justify-between items-center">
64 - <div class="actions-box flex flex-col justify-end">
65 - <n-button v-if="isRunning" :loading="loading" size="small" @click="stop()">
66 - <template #icon>
67 - <Icon :name="StopIcon"></Icon>
68 - </template>
69 - Stop
70 - </n-button>
71 - <n-button v-else :loading="loading" type="primary" size="small" @click="start()">
72 - <template #icon>
73 - <Icon :name="StartIcon"></Icon>
74 - </template>
75 - Start
76 - </n-button>
77 - </div>
78 -
79 - <div class="time">
80 - {{ formatDateTime(input.created_at) }}
81 - </div>
82 - </div>
39 + </template>
40 + <template #footerExtra>
41 + <div class="flex flex-wrap items-center justify-end gap-3">
42 + <n-button size="small" @click.stop="showDetails = true">
43 + <template #icon>
44 + <Icon :name="InfoIcon"></Icon>
45 + </template>
46 + Details
47 + </n-button>
48 + <n-button v-if="isRunning" :loading="loading" type="warning" size="small" secondary @click="stop()">
49 + <template #icon>
50 + <Icon :name="StopIcon"></Icon>
51 + </template>
52 + Stop input
53 + </n-button>
54 + <n-button v-else :loading="loading" type="success" secondary size="small" @click="start()">
55 + <template #icon>
56 + <Icon :name="StartIcon"></Icon>
57 + </template>
58 + Start input
59 + </n-button>
60 + </div>
61 + </template>
62 + </CardEntity>
63
64 <n-modal
65 v-model:show="showDetails"
@@ -135,15 +115,16 @@
115 import type { InputExtended } from "@/types/graylog/inputs.d"
116 import Api from "@/api"
117 import Badge from "@/components/common/Badge.vue"
118 +import CardEntity from "@/components/common/cards/CardEntity.vue"
119 import Icon from "@/components/common/Icon.vue"
120 import { useSettingsStore } from "@/stores/settings"
121 import { formatDate } from "@/utils"
122 import { NButton, NModal, NTabPane, NTabs, NTooltip, useMessage } from "naive-ui"
123 import { computed, ref } from "vue"
124 import { SimpleJsonViewer } from "vue-sjv"
144 -import "@/assets/scss/vuesjv-override.scss"
125 +import "@/assets/scss/overrides/vuesjv-override.scss"
126
146 -const { input } = defineProps<{ input: InputExtended }>()
127 +const { input, embedded } = defineProps<{ input: InputExtended; embedded?: boolean }>()
128
129 const emit = defineEmits<{
130 (e: "updated"): void
@@ -209,69 +190,3 @@ function start() {
190 })
191 }
192 </script>
212 -
213 -<style lang="scss" scoped>
214 -.item {
215 - border-radius: var(--border-radius);
216 - background-color: var(--bg-secondary-color);
217 - transition: all 0.2s var(--bezier-ease);
218 - border: var(--border-small-100);
219 -
220 - .header-box {
221 - font-family: var(--font-family-mono);
222 - font-size: 13px;
223 - .user {
224 - word-break: break-word;
225 - color: var(--fg-secondary-color);
226 - }
227 - .time {
228 - color: var(--fg-secondary-color);
229 - }
230 - }
231 - .main-box {
232 - word-break: break-word;
233 -
234 - .name {
235 - color: var(--fg-secondary-color);
236 - font-size: 13px;
237 - }
238 - }
239 -
240 - .footer-box {
241 - display: none;
242 - text-align: right;
243 - font-size: 13px;
244 - margin-top: 10px;
245 -
246 - .time {
247 - font-family: var(--font-family-mono);
248 - color: var(--fg-secondary-color);
249 - width: 100%;
250 - }
251 - }
252 -
253 - &.default {
254 - background-color: var(--primary-005-color);
255 - box-shadow: 0px 0px 0px 1px inset var(--primary-030-color);
256 - }
257 - &:hover {
258 - box-shadow: 0px 0px 0px 1px inset var(--primary-color);
259 - }
260 -
261 - @container (max-width: 650px) {
262 - .header-box {
263 - .time {
264 - display: none;
265 - }
266 - }
267 - .main-box {
268 - .actions-box {
269 - display: none;
270 - }
271 - }
272 - .footer-box {
273 - display: flex;
274 - }
275 - }
276 -}
277 -</style>
frontend/src/components/graylog/Inputs/List.vue
+5 -7
@@ -1,10 +1,10 @@
1 <template>
2 <n-spin :show="loading" class="flex flex-col">
3 <div class="header flex items-center justify-end gap-2">
4 - <div class="info grow flex gap-5">
4 + <div class="info flex grow gap-5">
5 <n-popover overlap placement="bottom-start">
6 <template #trigger>
7 - <div class="bg-color border-radius">
7 + <div class="bg-default rounded-default">
8 <n-button size="small" class="!cursor-help">
9 <template #icon>
10 <Icon :name="InfoIcon"></Icon>
@@ -34,17 +34,18 @@
34 />
35 </div>
36 <n-scrollbar class="my-3">
37 - <div class="list flex flex-col gap-2">
37 + <div class="list flex min-h-52 flex-col gap-2">
38 <template v-if="itemsFiltered.length">
39 <InputItem
40 v-for="input of itemsFiltered"
41 :key="input.id"
42 + embedded
43 :input="input"
44 @updated="getData('running')"
45 />
46 </template>
47 <template v-else>
47 - <n-empty v-if="!loading" description="No items found" class="justify-center h-48" />
48 + <n-empty v-if="!loading" description="No items found" class="h-48 justify-center" />
49 </template>
50 </div>
51 </n-scrollbar>
@@ -164,8 +165,5 @@ onBeforeMount(() => {
165 padding: var(--n-body-padding);
166 padding-top: 0;
167 padding-bottom: 0;
167 - container-type: inline-size;
168 - box-sizing: border-box;
169 - min-height: 200px;
168 }
169 </style>
frontend/src/components/graylog/Messages/Item.vue
+6 -73
@@ -1,28 +1,14 @@
1 <template>
2 - <div class="item flex flex-col gap-2 px-5 py-3">
3 - <div class="header-box flex justify-between">
4 - <div class="caller">
5 - {{ message.caller }}
6 - </div>
7 - <div class="time">
8 - {{ formatDate(message.timestamp, dFormats.datetimesec) }}
9 - </div>
10 - </div>
11 - <div class="main-box">
12 - <div class="content">
13 - {{ message.content }}
14 - </div>
15 - </div>
16 - <div class="footer-box">
17 - <div class="time">
18 - {{ formatDate(message.timestamp, dFormats.datetimesec) }}
19 - </div>
20 - </div>
21 - </div>
2 + <CardEntity>
3 + <template #headerMain>{{ message.caller }}</template>
4 + <template #headerExtra>{{ formatDate(message.timestamp, dFormats.datetimesec) }}</template>
5 + <template #default>{{ message.content }}</template>
6 + </CardEntity>
7 </template>
8
9 <script setup lang="ts">
10 import type { Message } from "@/types/graylog/messages.d"
11 +import CardEntity from "@/components/common/cards/CardEntity.vue"
12 import { useSettingsStore } from "@/stores/settings"
13 import { formatDate } from "@/utils"
14
@@ -30,56 +16,3 @@ const { message } = defineProps<{ message: Message }>()
16
17 const dFormats = useSettingsStore().dateFormat
18 </script>
33 -
34 -<style lang="scss" scoped>
35 -.item {
36 - border-radius: var(--border-radius);
37 - background-color: var(--bg-color);
38 - transition: all 0.2s var(--bezier-ease);
39 - border: var(--border-small-050);
40 -
41 - .header-box {
42 - font-family: var(--font-family-mono);
43 - font-size: 13px;
44 - .caller {
45 - word-break: break-word;
46 - color: var(--fg-secondary-color);
47 - }
48 - .time {
49 - color: var(--fg-secondary-color);
50 - }
51 - }
52 - .main-box {
53 - .content {
54 - word-break: break-word;
55 - }
56 - }
57 - .footer-box {
58 - font-family: var(--font-family-mono);
59 - display: none;
60 - text-align: right;
61 - font-size: 13px;
62 - margin-top: 10px;
63 -
64 - .time {
65 - color: var(--fg-secondary-color);
66 - width: 100%;
67 - }
68 - }
69 -
70 - &:hover {
71 - box-shadow: 0px 0px 0px 1px inset var(--primary-color);
72 - }
73 -
74 - @container (max-width: 650px) {
75 - .header-box {
76 - .time {
77 - display: none;
78 - }
79 - }
80 - .footer-box {
81 - display: flex;
82 - }
83 - }
84 -}
85 -</style>
frontend/src/components/graylog/Messages/List.vue
+4 -11
@@ -1,10 +1,10 @@
1 <template>
2 <n-spin :show="loading">
3 <div class="header flex items-center justify-end gap-2">
4 - <div class="info grow flex gap-5">
4 + <div class="info flex grow gap-5">
5 <n-popover overlap placement="bottom-start">
6 <template #trigger>
7 - <div class="bg-color border-radius">
7 + <div class="bg-default rounded-default">
8 <n-button size="small" class="!cursor-help">
9 <template #icon>
10 <Icon :name="InfoIcon"></Icon>
@@ -22,12 +22,12 @@
22 </div>
23 <n-pagination v-model:page="currentPage" :page-size="pageSize" :item-count="total" :page-slot="5" />
24 </div>
25 - <div class="list flex flex-col gap-2 my-3">
25 + <div class="my-3 flex min-h-52 flex-col gap-2">
26 <template v-if="messages.length">
27 <MessageItem v-for="msg of messages" :key="msg.id" :message="msg" />
28 </template>
29 <template v-else>
30 - <n-empty v-if="!loading" description="No items found" class="justify-center h-48" />
30 + <n-empty v-if="!loading" description="No items found" class="h-48 justify-center" />
31 </template>
32 </div>
33 <div class="footer flex justify-end">
@@ -94,10 +94,3 @@ onBeforeMount(() => {
94 getData(currentPage.value)
95 })
96 </script>
97 -
98 -<style lang="scss" scoped>
99 -.list {
100 - container-type: inline-size;
101 - min-height: 200px;
102 -}
103 -</style>
frontend/src/components/graylog/Metrics/List.vue
+3 -2
@@ -13,7 +13,7 @@
13 <div
14 v-for="metric of group.throughputMetrics"
15 :key="metric.metric"
16 - class="flex items-center gap-4 metric-wrap"
16 + class="metric-wrap flex items-center gap-4"
17 >
18 <div class="metric basis-2/3">
19 {{ metric.metric }}
@@ -92,7 +92,8 @@ function sanitizeMetrics(metrics: ThroughputMetric[]): Metrics[] {
92 .list {
93 background-color: var(--bg-secondary-color);
94 .metric-wrap {
95 - @apply py-3 px-4;
95 + @apply px-4 py-3;
96 +
97 .metric {
98 line-height: 1.1;
99 }
frontend/src/components/graylog/Metrics/UncommittedEntries.vue
+1 -1
@@ -32,7 +32,7 @@ import dayjs from "@/utils/dayjs"
32 import { NButton } from "naive-ui"
33 import { computed, ref, toRefs, watch } from "vue"
34 import apexchart from "vue3-apexcharts"
35 -import "@/assets/scss/apexchart-override.scss"
35 +import "@/assets/scss/overrides/apexchart-override.scss"
36
37 const props = defineProps<{
38 value: number
frontend/src/components/graylog/MonitoringAlerts/CustomAlertButton.vue
+1 -1
@@ -2,7 +2,7 @@
2 <n-button size="small" type="primary" secondary :loading="loading" @click="showForm = true">
3 <div class="flex items-center gap-2">
4 <Icon :name="DangerIcon" :size="18"></Icon>
5 - <span class="hidden xs:block">Custom Alert</span>
5 + <span class="xs:block hidden">Custom Alert</span>
6 </div>
7 </n-button>
8
frontend/src/components/graylog/MonitoringAlerts/Item.vue
+11 -77
@@ -1,10 +1,9 @@
1 <template>
2 - <div class="item flex flex-col gap-2 px-5 py-3">
3 - <div class="header-box flex justify-between gap-4">
4 - <div class="name">
5 - {{ alert.name }}
6 - </div>
7 - <div class="badge flex mb-2">
2 + <div>
3 + <CardEntity hoverable>
4 + <template #header>{{ alert.name }}</template>
5 + <template #default>{{ alert.value }}</template>
6 + <template #footerMain>
7 <Badge :type="isEnabled ? 'active' : 'muted'">
8 <template #iconRight>
9 <Icon :name="isEnabled ? EnabledIcon : DisabledIcon" :size="13"></Icon>
@@ -15,35 +14,14 @@
14 </span>
15 </template>
16 </Badge>
18 - </div>
19 - </div>
20 - <div class="main-box flex justify-between gap-4">
21 - <div class="content">
22 - {{ alert.value }}
23 - </div>
24 - <div class="actions-box">
25 - <n-button
26 - v-if="!isEnabled"
27 - :loading="loadingProvision"
28 - type="success"
29 - secondary
30 - @click="openFormDialog()"
31 - >
32 - <template #icon>
33 - <Icon :name="EnableIcon"></Icon>
34 - </template>
35 - Enable
36 - </n-button>
37 - </div>
38 - </div>
39 - <div class="footer-box flex justify-between items-center gap-4">
40 - <div class="actions-box">
17 + </template>
18 + <template #footerExtra>
19 <n-button
20 v-if="!isEnabled"
21 :loading="loadingProvision"
22 type="success"
45 - secondary
23 size="small"
24 + secondary
25 @click="openFormDialog()"
26 >
27 <template #icon>
@@ -51,8 +29,8 @@
29 </template>
30 Enable
31 </n-button>
54 - </div>
55 - </div>
32 + </template>
33 + </CardEntity>
34
35 <n-modal
36 v-model:show="showFormDialog"
@@ -102,6 +80,7 @@ import type { ProvisionsMonitoringAlertParams } from "@/api/endpoints/monitoring
80 import type { AvailableMonitoringAlert } from "@/types/monitoringAlerts.d"
81 import Api from "@/api"
82 import Badge from "@/components/common/Badge.vue"
83 +import CardEntity from "@/components/common/cards/CardEntity.vue"
84 import Icon from "@/components/common/Icon.vue"
85 import {
86 type FormRules,
@@ -207,48 +186,3 @@ function provisionsMonitoringAlert() {
186 }
187 }
188 </script>
210 -
211 -<style lang="scss" scoped>
212 -.item {
213 - border-radius: var(--border-radius);
214 - background-color: var(--bg-color);
215 - transition: all 0.2s var(--bezier-ease);
216 - border: var(--border-small-050);
217 -
218 - .header-box {
219 - font-size: 13px;
220 -
221 - .name {
222 - font-family: var(--font-family-mono);
223 - word-break: break-word;
224 - color: var(--fg-secondary-color);
225 - }
226 - }
227 - .main-box {
228 - .content {
229 - word-break: break-word;
230 - }
231 - }
232 -
233 - .footer-box {
234 - display: none;
235 - font-size: 13px;
236 - margin-top: 10px;
237 - }
238 -
239 - &:hover {
240 - box-shadow: 0px 0px 0px 1px inset var(--primary-color);
241 - }
242 -
243 - @container (max-width: 450px) {
244 - .main-box {
245 - .actions-box {
246 - display: none;
247 - }
248 - }
249 - .footer-box {
250 - display: flex;
251 - }
252 - }
253 -}
254 -</style>
frontend/src/components/graylog/MonitoringAlerts/List.vue
+5 -12
@@ -1,10 +1,10 @@
1 <template>
2 <div class="monitoring-alert-list">
3 <div ref="header" class="header flex items-center justify-end gap-2">
4 - <div class="info grow flex gap-2">
4 + <div class="info flex grow gap-2">
5 <n-popover overlap placement="bottom-start">
6 <template #trigger>
7 - <div class="bg-color border-radius">
7 + <div class="bg-default rounded-default">
8 <n-button size="small" class="!cursor-help">
9 <template #icon>
10 <Icon :name="InfoIcon"></Icon>
@@ -17,7 +17,7 @@
17 Total :
18 <code>{{ total }}</code>
19 </div>
20 - <div class="box text-success-color">
20 + <div class="box text-success">
21 Enabled :
22 <code>{{ enabledTotal }}</code>
23 </div>
@@ -36,7 +36,7 @@
36 />
37 </div>
38 <n-spin :show="loading">
39 - <div class="list flex flex-col gap-2 my-3">
39 + <div class="my-3 flex min-h-52 flex-col gap-2">
40 <template v-if="alerts.length">
41 <MonitoringAlert
42 v-for="alert of itemsPaginated"
@@ -47,7 +47,7 @@
47 />
48 </template>
49 <template v-else>
50 - <n-empty v-if="!loading" description="No items found" class="justify-center h-48" />
50 + <n-empty v-if="!loading" description="No items found" class="h-48 justify-center" />
51 </template>
52 </div>
53 </n-spin>
@@ -169,10 +169,3 @@ onBeforeMount(() => {
169 }
170 })
171 </script>
172 -
173 -<style lang="scss" scoped>
174 -.list {
175 - container-type: inline-size;
176 - min-height: 200px;
177 -}
178 -</style>
frontend/src/components/graylog/Pipelines/PipeDetails.vue
+5 -15
@@ -1,13 +1,13 @@
1 <template>
2 <div class="pipe-details flex flex-wrap justify-between gap-1">
3 - <div class="description">
3 + <div class="flex w-full flex-wrap items-center justify-between gap-2">
4 <p v-if="pipeline.description">
5 {{ pipeline.description }}
6 </p>
7 - </div>
7
9 - <div class="time">
10 - {{ formatDate(pipeline.modified_at, dFormats.datetimesec) }}
8 + <div class="text-secondary text-right font-mono text-sm">
9 + {{ formatDate(pipeline.modified_at, dFormats.datetimesec) }}
10 + </div>
11 </div>
12 </div>
13
@@ -29,7 +29,7 @@
29 <Icon :name="RulesIcon" :size="18"></Icon>
30 </template>
31 Rules
32 - <span class="font-mono ml-2 text-secondary-color">{{ stage.rules.length }}</span>
32 + <span class="text-secondary ml-2 font-mono">{{ stage.rules.length }}</span>
33 </n-button>
34 </template>
35
@@ -94,13 +94,3 @@ const stages = computed<PipelineFullStageExt[]>(() => {
94 return stages
95 })
96 </script>
97 -
98 -<style lang="scss" scoped>
99 -.time {
100 - font-family: var(--font-family-mono);
101 - font-size: 13px;
102 - text-align: right;
103 - color: var(--fg-secondary-color);
104 - line-height: 1.6;
105 -}
106 -</style>
frontend/src/components/graylog/Pipelines/PipeList.vue
+16 -16
@@ -1,14 +1,15 @@
1 <template>
2 <div class="pipe-list">
3 - <n-card>
4 - <n-spin :show="loading">
5 - <n-collapse
6 - v-if="pipelines.length"
7 - v-model:expanded-names="selectedPipeline"
8 - accordion
9 - :style="minHeight ? `min-height: ${minHeight}` : ''"
10 - >
11 - <n-collapse-item v-for="pipe of pipelines" :key="pipe.id" :title="pipe.title" :name="pipe.id">
3 + <n-card content-class="!px-0">
4 + <n-spin :show="loading" content-class="min-h-7">
5 + <n-collapse v-if="pipelines.length" v-model:expanded-names="selectedPipeline" accordion>
6 + <n-collapse-item
7 + v-for="pipe of pipelines"
8 + :key="pipe.id"
9 + :title="pipe.title"
10 + :name="pipe.id"
11 + class="px-5"
12 + >
13 <template #header>
14 <PipeTitle :pipeline="pipe" />
15 </template>
@@ -25,7 +26,7 @@
26 </n-collapse-item>
27 </n-collapse>
28 <template v-else>
28 - <n-empty v-if="!loading" description="No pipelines found" class="justify-center h-32" />
29 + <n-empty v-if="!loading" description="No pipelines found" class="h-32 justify-center" />
30 </template>
31 </n-spin>
32 </n-card>
@@ -52,17 +53,12 @@ import PipeDetails from "@/components/graylog/Pipelines/PipeDetails.vue"
53 import PipeInfo from "@/components/graylog/Pipelines/PipeInfo.vue"
54 import PipeTitle from "@/components/graylog/Pipelines/PipeTitle.vue"
55 import { NButton, NCard, NCollapse, NCollapseItem, NEmpty, NModal, NSpin, useMessage } from "naive-ui"
55 -import { onBeforeMount, ref, toRefs, watch } from "vue"
56 +import { onBeforeMount, ref, watch } from "vue"
57
57 -const props = defineProps<{
58 - minHeight?: string
59 -}>()
58 const emit = defineEmits<{
59 (e: "openRule", value: string): void
60 }>()
61
64 -const { minHeight } = toRefs(props)
65 -
62 const InfoIcon = "carbon:information"
63
64 const message = useMessage()
@@ -114,5 +110,9 @@ watch(showRulesDrawer, val => {
110
111 onBeforeMount(() => {
112 getPipelines()
113 + // MOCK
114 + /*
115 + pipelines.value = pipeline_full
116 + */
117 })
118 </script>
frontend/src/components/graylog/Pipelines/PipeTitle.vue
+1 -11
@@ -1,5 +1,5 @@
1 <template>
2 - <div class="pipe-title flex items-center gap-1" :class="{ warning: isWarning }">
2 + <div class="flex items-center gap-1 leading-[1.1]" :class="{ 'text-warning': isWarning }">
3 <n-tooltip v-if="isWarning" placement="top-start" trigger="hover">
4 <template #trigger>
5 <Icon :name="DangerIcon" :size="18"></Icon>
@@ -25,13 +25,3 @@ const isWarning = computed<boolean>(() => {
25 return !!pipeline.value.errors
26 })
27 </script>
28 -
29 -<style lang="scss" scoped>
30 -.pipe-title {
31 - line-height: 1.1;
32 -
33 - &.warning {
34 - color: var(--secondary3-color);
35 - }
36 -}
37 -</style>
frontend/src/components/graylog/Pipelines/Rule.vue
+22 -102
@@ -1,25 +1,17 @@
1 <template>
2 - <div :id="`rule-${rule.id}`" class="item flex flex-col mb-2 gap-2 px-5 py-3" :class="{ highlight }">
3 - <div class="header-box flex justify-between">
4 - <div class="flex items-center gap-3">
5 - <div class="id">
6 - <div class="flex items-center gap-2 cursor-pointer" @click="showDetails = true">
7 - <span>#{{ rule.id }}</span>
8 - <Icon :name="InfoIcon" :size="16"></Icon>
9 - </div>
10 - </div>
11 - </div>
12 - <div class="time">
2 + <div :id="`rule-${rule.id}`">
3 + <CardEntity :highlighted="!!highlight" :embedded hoverable clickable @click.stop="showDetails = true">
4 + <template #headerMain>#{{ rule.id }}</template>
5 + <template #headerExtra>
6 <n-popover overlap placement="top-end">
7 <template #trigger>
15 - <div class="flex items-center gap-2 cursor-help">
16 - <span>
17 - {{ formatDateTime(rule.modified_at) }}
18 - </span>
8 + <div class="hover:text-primary flex cursor-help items-center gap-2">
9 + {{ formatDateTime(rule.modified_at) }}
10 +
11 <Icon :name="TimeIcon" :size="16"></Icon>
12 </div>
13 </template>
22 - <div class="flex flex-col py-2 px-1">
14 + <div class="flex flex-col px-1 py-2">
15 <n-timeline>
16 <n-timeline-item type="success" title="Created" :time="formatDateTime(rule.created_at)" />
17 <n-timeline-item
@@ -30,21 +22,17 @@
22 </n-timeline>
23 </div>
24 </n-popover>
33 - </div>
34 - </div>
35 - <div class="main-box">
36 - <div class="title">
37 - {{ rule.title }}
38 - </div>
39 - <div class="description">
40 - {{ rule.description }}
41 - </div>
42 - </div>
43 - <div class="footer-box flex justify-end items-center gap-3">
44 - <div class="time">
45 - {{ formatDateTime(rule.modified_at) }}
46 - </div>
47 - </div>
25 + </template>
26 + <template #default>
27 + <div class="flex flex-col gap-1">
28 + {{ rule.title }}
29 +
30 + <p v-if="rule.description && rule.description !== rule.title">
31 + {{ rule.description }}
32 + </p>
33 + </div>
34 + </template>
35 + </CardEntity>
36
37 <n-modal
38 v-model:show="showDetails"
@@ -87,17 +75,17 @@
75
76 <script setup lang="ts">
77 import type { PipelineRule } from "@/types/graylog/pipelines.d"
78 +import CardEntity from "@/components/common/cards/CardEntity.vue"
79 import Icon from "@/components/common/Icon.vue"
80 import { useSettingsStore } from "@/stores/settings"
81 import { formatDate } from "@/utils"
82 import { NInput, NModal, NPopover, NTimeline, NTimelineItem } from "naive-ui"
83 import { ref, toRefs } from "vue"
84
96 -const props = defineProps<{ rule: PipelineRule; highlight: boolean | null | undefined }>()
97 -const { rule, highlight } = toRefs(props)
85 +const props = defineProps<{ rule: PipelineRule; embedded?: boolean; highlight: boolean | null | undefined }>()
86 +const { rule, highlight, embedded } = toRefs(props)
87
88 const TimeIcon = "carbon:time"
100 -const InfoIcon = "carbon:information"
89
90 const showDetails = ref(false)
91 const dFormats = useSettingsStore().dateFormat
@@ -106,71 +94,3 @@ function formatDateTime(timestamp: string): string {
94 return formatDate(timestamp, dFormats.datetimesec).toString()
95 }
96 </script>
109 -
110 -<style lang="scss" scoped>
111 -.item {
112 - border-radius: var(--border-radius);
113 - background-color: var(--bg-secondary-color);
114 - transition: all 0.2s var(--bezier-ease);
115 - border: var(--border-small-100);
116 - color: var(--fg-color);
117 -
118 - .header-box {
119 - font-family: var(--font-family-mono);
120 - font-size: 13px;
121 - .id {
122 - word-break: break-word;
123 - color: var(--fg-secondary-color);
124 -
125 - &:hover {
126 - color: var(--primary-color);
127 - }
128 - }
129 - .time {
130 - color: var(--fg-secondary-color);
131 -
132 - &:hover {
133 - color: var(--primary-color);
134 - }
135 - }
136 - }
137 - .main-box {
138 - word-break: break-word;
139 -
140 - .description {
141 - color: var(--fg-secondary-color);
142 - font-size: 13px;
143 - }
144 - }
145 - .footer-box {
146 - font-family: var(--font-family-mono);
147 - font-size: 13px;
148 - margin-top: 10px;
149 - display: none;
150 -
151 - .time {
152 - text-align: right;
153 - color: var(--fg-secondary-color);
154 - }
155 - }
156 -
157 - &.highlight {
158 - background-color: var(--primary-005-color);
159 - box-shadow: 0px 0px 0px 1px inset var(--primary-030-color);
160 - }
161 - &:hover {
162 - box-shadow: 0px 0px 0px 1px inset var(--primary-color);
163 - }
164 -
165 - @container (max-width: 650px) {
166 - .header-box {
167 - .time {
168 - display: none;
169 - }
170 - }
171 - .footer-box {
172 - display: flex;
173 - }
174 - }
175 -}
176 -</style>
frontend/src/components/graylog/Pipelines/RulesList.vue
+2 -5
@@ -1,8 +1,8 @@
1 <template>
2 <n-spin :show="loading" class="rules-list">
3 <n-scrollbar ref="scrollContent">
4 - <div class="list">
5 - <Rule v-for="rule of rules" :key="rule.id" :rule="rule" :highlight="highlight === rule.id" />
4 + <div class="list flex min-h-52 flex-col gap-2">
5 + <Rule v-for="rule of rules" :key="rule.id" :rule="rule" :highlight="highlight === rule.id" embedded />
6 </div>
7 </n-scrollbar>
8 </n-spin>
@@ -98,9 +98,6 @@ onBeforeMount(() => {
98
99 .list {
100 padding: var(--n-body-padding);
101 - container-type: inline-size;
102 - box-sizing: border-box;
103 - min-height: 200px;
101 padding-bottom: 50vh;
102 }
103 }
frontend/src/components/graylog/Pipelines/RulesSmallList.vue
+1 -1
@@ -5,7 +5,7 @@
5 <span class="spacer">
6 <Icon :name="ViewIcon" :size="16"></Icon>
7 </span>
8 - <span class="grow title">
8 + <span class="title grow">
9 {{ rule.title }}
10 </span>
11 <span class="spacer small"></span>
frontend/src/components/graylog/Pipelines/mock.ts new
+56
@@ -0,0 +1,56 @@
1 +import type { PipelineFull } from "@/types/graylog/pipelines.d"
2 +
3 +export const pipeline_full: PipelineFull[] = [
4 + {
5 + created_at: "2023-10-01T12:00:00Z",
6 + description: "Pipeline for processing customer data",
7 + errors: null,
8 + id: "pipeline_001",
9 + modified_at: "2023-10-10T15:30:00Z",
10 + source: "internal_system",
11 + stages: [
12 + {
13 + match: "PASS",
14 + rules: ["rule_001", "rule_002"],
15 + rule_ids: ["rule_id_001", "rule_id_002"],
16 + stage: 1
17 + },
18 + {
19 + match: "EITHER",
20 + rules: ["rule_003", "rule_004"],
21 + rule_ids: ["rule_id_003", "rule_id_004"],
22 + stage: 2
23 + }
24 + ],
25 + title: "Customer Data Pipeline"
26 + },
27 + {
28 + created_at: "2023-09-15T08:45:00Z",
29 + description: "Pipeline for processing transaction data",
30 + errors: "Error in stage 3",
31 + id: "pipeline_002",
32 + modified_at: "2023-09-20T11:00:00Z",
33 + source: "external_system",
34 + stages: [
35 + {
36 + match: "PASS",
37 + rules: ["rule_005"],
38 + rule_ids: ["rule_id_005"],
39 + stage: 1
40 + },
41 + {
42 + match: "PASS",
43 + rules: ["rule_006", "rule_007"],
44 + rule_ids: ["rule_id_006", "rule_id_007"],
45 + stage: 2
46 + },
47 + {
48 + match: "EITHER",
49 + rules: ["rule_008"],
50 + rule_ids: ["rule_id_008"],
51 + stage: 3
52 + }
53 + ],
54 + title: "Transaction Data Pipeline"
55 + }
56 +]
frontend/src/components/graylog/Streams/Item.vue
+55 -123
@@ -1,30 +1,24 @@
1 <template>
2 - <div class="item flex flex-col gap-2 px-5 py-3" :class="{ default: stream.is_default }">
3 - <div class="header-box flex items-center gap-3">
4 - <div class="info flex items-center gap-2 grow">
5 - <div class="user flex items-center gap-2">
2 + <div>
3 + <CardEntity hoverable :highlighted="stream.is_default">
4 + <template #headerMain>
5 + <div class="flex items-center gap-2">
6 <Icon :name="UserIcon" :size="14"></Icon>
7 {{ stream.creator_user_id }}
8 </div>
9 - </div>
10 - <div class="time">
11 - {{ formatDate(stream.created_at, dFormats.datetimesec) }}
12 - </div>
13 - <n-button size="small" @click.stop="showDetails = true">
14 - <template #icon>
15 - <Icon :name="InfoIcon"></Icon>
16 - </template>
17 - </n-button>
18 - </div>
19 - <div class="main-box flex justify-between">
20 - <div class="content">
21 - <div class="title">
9 + </template>
10 + <template #headerExtra>{{ formatDate(stream.created_at, dFormats.datetimesec) }}</template>
11 + <template #default>
12 + <div class="flex flex-col gap-1">
13 {{ stream.title }}
14 +
15 + <p v-if="stream.description && stream.description !== stream.title">
16 + {{ stream.description }}
17 + </p>
18 </div>
24 - <div class="description mb-2">
25 - {{ stream.description }}
26 - </div>
27 - <div class="badges-box flex flex-wrap items-center gap-3">
19 + </template>
20 + <template #footerMain>
21 + <div class="flex flex-wrap items-center gap-3">
22 <Badge :type="stream.disabled ? 'muted' : 'active'">
23 <template #iconRight>
24 <Icon :name="stream.disabled ? DisabledIcon : EnabledIcon" :size="14"></Icon>
@@ -44,41 +38,44 @@
38 <template #label>Editable</template>
39 </Badge>
40 </div>
47 - </div>
48 - <div v-if="stream.is_editable" class="actions-box flex flex-col justify-end">
49 - <n-button v-if="!stream.disabled" :loading="loading" @click="stop()">
50 - <template #icon>
51 - <Icon :name="StopIcon"></Icon>
52 - </template>
53 - Stop stream
54 - </n-button>
55 - <n-button v-else :loading="loading" type="primary" @click="start()">
56 - <template #icon>
57 - <Icon :name="StartIcon"></Icon>
58 - </template>
59 - Start stream
60 - </n-button>
61 - </div>
62 - </div>
63 - <div class="footer-box flex justify-between items-center">
64 - <div v-if="stream.is_editable" class="actions-box flex flex-col justify-end">
65 - <n-button v-if="!stream.disabled" :loading="loading" size="small" @click="stop()">
66 - <template #icon>
67 - <Icon :name="StopIcon"></Icon>
68 - </template>
69 - Stop
70 - </n-button>
71 - <n-button v-else :loading="loading" type="primary" size="small" @click="start()">
72 - <template #icon>
73 - <Icon :name="StartIcon"></Icon>
74 - </template>
75 - Start
76 - </n-button>
77 - </div>
78 - <div class="time">
79 - {{ formatDate(stream.created_at, dFormats.datetimesec) }}
80 - </div>
81 - </div>
41 + </template>
42 + <template #footerExtra>
43 + <div class="flex flex-wrap items-center justify-end gap-3">
44 + <n-button size="small" @click.stop="showDetails = true">
45 + <template #icon>
46 + <Icon :name="InfoIcon"></Icon>
47 + </template>
48 + Details
49 + </n-button>
50 + <n-button
51 + v-if="stream.is_editable && !stream.disabled"
52 + :loading="loading"
53 + type="warning"
54 + secondary
55 + size="small"
56 + @click="stop()"
57 + >
58 + <template #icon>
59 + <Icon :name="StopIcon"></Icon>
60 + </template>
61 + Stop stream
62 + </n-button>
63 + <n-button
64 + v-if="stream.is_editable && stream.disabled"
65 + :loading="loading"
66 + type="success"
67 + secondary
68 + size="small"
69 + @click="start()"
70 + >
71 + <template #icon>
72 + <Icon :name="StartIcon"></Icon>
73 + </template>
74 + Start stream
75 + </n-button>
76 + </div>
77 + </template>
78 + </CardEntity>
79
80 <n-modal
81 v-model:show="showDetails"
@@ -106,13 +103,14 @@
103 import type { Stream } from "@/types/graylog/stream.d"
104 import Api from "@/api"
105 import Badge from "@/components/common/Badge.vue"
106 +import CardEntity from "@/components/common/cards/CardEntity.vue"
107 import Icon from "@/components/common/Icon.vue"
108 import { useSettingsStore } from "@/stores/settings"
109 import { formatDate } from "@/utils"
110 import { NButton, NModal, useMessage } from "naive-ui"
111 import { ref, toRefs } from "vue"
112 import { SimpleJsonViewer } from "vue-sjv"
115 -import "@/assets/scss/vuesjv-override.scss"
113 +import "@/assets/scss/overrides/vuesjv-override.scss"
114
115 const props = defineProps<{ stream: Stream }>()
116 const { stream } = toRefs(props)
@@ -171,69 +169,3 @@ function start() {
169 })
170 }
171 </script>
174 -
175 -<style lang="scss" scoped>
176 -.item {
177 - border-radius: var(--border-radius);
178 - background-color: var(--bg-color);
179 - transition: all 0.2s var(--bezier-ease);
180 - border: var(--border-small-050);
181 -
182 - .header-box {
183 - font-family: var(--font-family-mono);
184 - font-size: 13px;
185 - .user {
186 - word-break: break-word;
187 - color: var(--fg-secondary-color);
188 - }
189 - .time {
190 - color: var(--fg-secondary-color);
191 - }
192 - }
193 - .main-box {
194 - word-break: break-word;
195 -
196 - .description {
197 - color: var(--fg-secondary-color);
198 - font-size: 13px;
199 - }
200 - }
201 -
202 - .footer-box {
203 - display: none;
204 - text-align: right;
205 - font-size: 13px;
206 - margin-top: 10px;
207 -
208 - .time {
209 - font-family: var(--font-family-mono);
210 - color: var(--fg-secondary-color);
211 - width: 100%;
212 - }
213 - }
214 -
215 - &.default {
216 - background-color: var(--primary-005-color);
217 - box-shadow: 0px 0px 0px 1px inset var(--primary-030-color);
218 - }
219 - &:hover {
220 - box-shadow: 0px 0px 0px 1px inset var(--primary-color);
221 - }
222 -
223 - @container (max-width: 650px) {
224 - .header-box {
225 - .time {
226 - display: none;
227 - }
228 - }
229 - .main-box {
230 - .actions-box {
231 - display: none;
232 - }
233 - }
234 - .footer-box {
235 - display: flex;
236 - }
237 - }
238 -}
239 -</style>
frontend/src/components/graylog/Streams/List.vue
+7 -14
@@ -1,10 +1,10 @@
1 <template>
2 <n-spin :show="loading">
3 <div ref="header" class="header flex items-center justify-end gap-2">
4 - <div class="info grow flex gap-5">
4 + <div class="info flex grow gap-5">
5 <n-popover overlap placement="bottom-start">
6 <template #trigger>
7 - <div class="bg-color border-radius">
7 + <div class="bg-default rounded-default">
8 <n-button size="small" class="!cursor-help">
9 <template #icon>
10 <Icon :name="InfoIcon"></Icon>
@@ -35,7 +35,7 @@
35 />
36 <n-popover overlap placement="right" class="!px-0">
37 <template #trigger>
38 - <div class="bg-color border-radius">
38 + <div class="bg-default rounded-default">
39 <n-button size="small">
40 <template #icon>
41 <Icon :name="FilterIcon"></Icon>
@@ -45,7 +45,7 @@
45 </template>
46 <div class="py-1">
47 <div class="px-3">
48 - <div class="text-secondary-color text-sm mb-1">Enabled:</div>
48 + <div class="text-secondary mb-1 text-sm">Enabled:</div>
49 <n-select
50 v-model:value="enabledFilter"
51 size="small"
@@ -57,7 +57,7 @@
57 </div>
58 <n-divider class="!my-3" />
59 <div class="px-3">
60 - <div class="text-secondary-color text-sm mb-1">Editable:</div>
60 + <div class="text-secondary mb-1 text-sm">Editable:</div>
61 <n-select
62 v-model:value="editableFilter"
63 size="small"
@@ -70,12 +70,12 @@
70 </div>
71 </n-popover>
72 </div>
73 - <div class="list flex flex-col gap-2 my-3">
73 + <div class="my-3 flex min-h-52 flex-col gap-2">
74 <template v-if="itemsPaginated.length">
75 <StreamItem v-for="stream of itemsPaginated" :key="stream.id" :stream="stream" />
76 </template>
77 <template v-else>
78 - <n-empty v-if="!loading" description="No items found" class="justify-center h-48" />
78 + <n-empty v-if="!loading" description="No items found" class="h-48 justify-center" />
79 </template>
80 </div>
81 <div class="footer flex justify-end">
@@ -186,10 +186,3 @@ onBeforeMount(() => {
186 getData()
187 })
188 </script>
189 -
190 -<style lang="scss" scoped>
191 -.list {
192 - container-type: inline-size;
193 - min-height: 200px;
194 -}
195 -</style>
frontend/src/components/healthcheck/HealthcheckItem.vue
+19 -87
@@ -1,33 +1,28 @@
1 <template>
2 - <div class="healthcheck-item flex flex-col gap-2 px-5 py-3" :class="`status-${alert.level}`">
3 - <div class="header-box flex justify-between">
4 - <div class="id">
5 - <span>#{{ alert.checkID }}</span>
6 - </div>
7 - <div class="time">
8 - {{ formatDate(alert.time) }}
9 - </div>
10 - </div>
11 - <div class="main-box flex justify-between gap-4">
12 - <div class="content flex gap-3 items-center">
13 - <div class="level mt-1">
14 - <Icon v-if="alert.level === InfluxDBAlertLevel.Crit" :name="WarningIcon" :size="20" />
15 - <Icon v-else :name="OKIcon" :size="20" />
2 + <div>
3 + <CardEntity :status="alert.level === InfluxDBAlertLevel.Crit ? 'warning' : undefined">
4 + <template #headerMain>#{{ alert.checkID }}</template>
5 + <template #headerExtra>{{ formatDate(alert.time) }}</template>
6 + <template #default>
7 + <div class="flex items-center gap-3">
8 + <div class="mt-1">
9 + <Icon
10 + v-if="alert.level === InfluxDBAlertLevel.Crit"
11 + :name="WarningIcon"
12 + :size="20"
13 + class="text-warning"
14 + />
15 + <Icon v-else :name="OKIcon" :size="20" class="text-success" />
16 + </div>
17 + <div class="grow" v-html="message"></div>
18 </div>
17 - <div class="info grow">
18 - <div class="message" v-html="message"></div>
19 - </div>
20 - </div>
21 - </div>
22 - <div class="footer-box flex justify-end items-center gap-3">
23 - <div class="time">
24 - {{ formatDate(alert.time) }}
25 - </div>
26 - </div>
19 + </template>
20 + </CardEntity>
21 </div>
22 </template>
23
24 <script setup lang="ts">
25 +import CardEntity from "@/components/common/cards/CardEntity.vue"
26 import Icon from "@/components/common/Icon.vue"
27 import { useSettingsStore } from "@/stores/settings"
28 import { type InfluxDBAlert, InfluxDBAlertLevel } from "@/types/healthchecks.d"
@@ -49,66 +44,3 @@ function formatDate(timestamp: string | number | Date, utc: boolean = true): str
44 return dayjs(timestamp).utc(utc).format(dFormats.datetime)
45 }
46 </script>
52 -
53 -<style lang="scss" scoped>
54 -.healthcheck-item {
55 - border-radius: var(--border-radius);
56 - background-color: var(--bg-color);
57 - border: var(--border-small-050);
58 -
59 - .header-box {
60 - font-family: var(--font-family-mono);
61 - font-size: 13px;
62 - .id {
63 - word-break: break-word;
64 - color: var(--fg-secondary-color);
65 - line-height: 1.2;
66 - }
67 -
68 - .time {
69 - color: var(--fg-secondary-color);
70 - }
71 - }
72 -
73 - .main-box {
74 - word-break: break-word;
75 -
76 - .level {
77 - color: var(--success-color);
78 - }
79 - }
80 -
81 - .footer-box {
82 - font-family: var(--font-family-mono);
83 - font-size: 13px;
84 - margin-top: 10px;
85 - display: none;
86 -
87 - .time {
88 - text-align: right;
89 - color: var(--fg-secondary-color);
90 - }
91 - }
92 -
93 - &.status- {
94 - &crit {
95 - border-color: var(--warning-color);
96 -
97 - .level {
98 - color: var(--warning-color);
99 - }
100 - }
101 - }
102 -
103 - @container (max-width: 450px) {
104 - .header-box {
105 - .time {
106 - display: none;
107 - }
108 - }
109 - .footer-box {
110 - display: flex;
111 - }
112 - }
113 -}
114 -</style>
frontend/src/components/healthcheck/HealthcheckList.vue
+5 -14
@@ -1,10 +1,10 @@
1 <template>
2 <div class="healthcheck-list">
3 <div ref="header" class="header flex items-center justify-end gap-2">
4 - <div class="info grow flex gap-2">
4 + <div class="info flex grow gap-2">
5 <n-popover overlap placement="bottom-start">
6 <template #trigger>
7 - <div class="bg-color border-radius">
7 + <div class="bg-default rounded-default">
8 <n-button size="small" class="!cursor-help">
9 <template #icon>
10 <Icon :name="InfoIcon"></Icon>
@@ -17,7 +17,7 @@
17 Total :
18 <code>{{ total }}</code>
19 </div>
20 - <div class="box text-warning-color">
20 + <div class="box text-warning">
21 Critical :
22 <code>{{ criticalTotal }}</code>
23 </div>
@@ -35,7 +35,7 @@
35 />
36 </div>
37 <n-spin :show="loading">
38 - <div class="list flex flex-col gap-2 my-3">
38 + <div class="my-3 flex min-h-52 flex-col gap-2">
39 <template v-if="healthcheckList.length">
40 <HealthcheckItem
41 v-for="alert of itemsPaginated"
@@ -45,7 +45,7 @@
45 />
46 </template>
47 <template v-else>
48 - <n-empty v-if="!loading" description="No items found" class="justify-center h-48" />
48 + <n-empty v-if="!loading" description="No items found" class="h-48 justify-center" />
49 </template>
50 </div>
51 </n-spin>
@@ -136,12 +136,3 @@ onBeforeMount(() => {
136 getData()
137 })
138 </script>
139 -
140 -<style lang="scss" scoped>
141 -.healthcheck-list {
142 - .list {
143 - container-type: inline-size;
144 - min-height: 200px;
145 - }
146 -}
147 -</style>
frontend/src/components/incidentManagement/alerts/AlertAsset.vue
+33 -60
@@ -1,29 +1,25 @@
1 <template>
2 - <div class="alert-asset-item" :class="{ embedded, badge }">
3 - <code v-if="badge" @click="showDetails = true">
4 - <span>{{ asset.asset_name }}</span>
5 - <Icon :name="ViewIcon" :size="14" />
6 - </code>
7 -
8 - <div v-else class="flex flex-col cursor-pointer" @click="showDetails = true">
9 - <div class="main-box flex flex-col gap-3 px-5 py-3">
10 - <div class="content flex flex-col gap-1 grow">
11 - <div class="title">
12 - {{ asset.asset_name }}
13 - </div>
14 - </div>
15 -
16 - <div class="badges-box flex flex-wrap items-center gap-3">
2 + <div>
3 + <div v-if="badge" class="alert-assets-badge" @click="showDetails = true">
4 + <code>
5 + <span>{{ asset.asset_name }}</span>
6 + <Icon :name="ViewIcon" :size="14" />
7 + </code>
8 + </div>
9 + <CardEntity v-else :embedded hoverable clickable @click="showDetails = true">
10 + <template #default>{{ asset.asset_name }}</template>
11 + <template #mainExtra>
12 + <div class="flex flex-wrap items-center gap-3">
13 <Badge type="splitted">
14 <template #label>Index</template>
15 <template #value>
20 - <div class="flex items-center h-full">
16 + <div class="flex h-full items-center">
17 <code
22 - class="cursor-pointer text-primary-color leading-none"
18 + class="text-primary cursor-pointer leading-none"
19 @click.stop="gotoIndex(asset.index_name)"
20 >
21 {{ asset.index_name }}
26 - <Icon :name="LinkIcon" :size="14" class="top-0.5 relative" />
22 + <Icon :name="LinkIcon" :size="14" class="relative top-0.5" />
23 </code>
24 </div>
25 </template>
@@ -32,20 +28,20 @@
28 <Badge type="splitted">
29 <template #label>Agent</template>
30 <template #value>
35 - <div class="flex items-center h-full">
31 + <div class="flex h-full items-center">
32 <code
37 - class="cursor-pointer text-primary-color leading-none"
33 + class="text-primary cursor-pointer leading-none"
34 @click.stop="gotoAgent(asset.agent_id)"
35 >
36 {{ asset.agent_id }}
41 - <Icon :name="LinkIcon" :size="14" class="top-0.5 relative" />
37 + <Icon :name="LinkIcon" :size="14" class="relative top-0.5" />
38 </code>
39 </div>
40 </template>
41 </Badge>
42 </div>
47 - </div>
48 - </div>
43 + </template>
44 + </CardEntity>
45
46 <n-modal
47 v-model:show="showDetails"
@@ -72,7 +68,7 @@
68 <n-tab-pane name="Context" tab="Context" display-directive="show">
69 <n-spin :show="loading" class="min-h-40">
70 <div v-if="alertContext" class="p-7 pt-4">
75 - <div class="flex flex-wrap gap-3 mb-4">
71 + <div class="mb-4 flex flex-wrap gap-3">
72 <Badge type="splitted">
73 <template #label>id</template>
74 <template #value>#{{ alertContext.id }}</template>
@@ -105,8 +101,8 @@
101 >
102 <n-card
103 size="small"
108 - content-class="bg-secondary-color"
109 - class="overflow-hidden hover:border-primary-color cursor-pointer"
104 + content-class="bg-secondary"
105 + class="hover:border-primary cursor-pointer overflow-hidden"
106 @click="openEvaluation()"
107 >
108 {{ pn }}
@@ -140,6 +136,7 @@
136 import type { AlertAsset, AlertContext } from "@/types/incidentManagement/alerts.d"
137 import Api from "@/api"
138 import Badge from "@/components/common/Badge.vue"
139 +import CardEntity from "@/components/common/cards/CardEntity.vue"
140 import Icon from "@/components/common/Icon.vue"
141 import { useGoto } from "@/composables/useGoto"
142 import _truncate from "lodash/truncate"
@@ -196,40 +193,16 @@ function getAlertContext(alertContextId: number) {
193 </script>
194
195 <style lang="scss" scoped>
199 -.alert-asset-item {
200 - &:not(.badge) {
201 - border-radius: var(--border-radius);
202 - background-color: var(--bg-color);
203 - transition: all 0.2s var(--bezier-ease);
204 - border: var(--border-small-050);
205 - overflow: hidden;
206 -
207 - &:hover {
208 - box-shadow: 0px 0px 0px 1px var(--primary-color);
209 - }
210 -
211 - .main-box {
212 - .content {
213 - word-break: break-word;
214 - }
215 - }
216 - }
217 -
218 - &.embedded {
219 - background-color: var(--bg-secondary-color);
220 - }
221 -
222 - &.badge {
223 - color: var(--primary-color);
224 - line-height: 1;
225 - cursor: pointer;
226 -
227 - code {
228 - display: flex;
229 - align-items: center;
230 - gap: 7px;
231 - padding: 2px 5px;
232 - }
196 +.alert-assets-badge {
197 + color: var(--primary-color);
198 + line-height: 1;
199 + cursor: pointer;
200 +
201 + code {
202 + display: flex;
203 + align-items: center;
204 + gap: 7px;
205 + padding: 2px 5px;
206 }
207 }
208 </style>
frontend/src/components/incidentManagement/alerts/AlertAssetInfo.vue
+17 -20
@@ -1,43 +1,40 @@
1 <template>
2 - <div class="grid gap-2 grid-auto-fit-200 p-7 pt-4">
3 - <KVCard v-for="(value, key) of asset" :key="key">
2 + <div class="grid-auto-fit-200 grid gap-2 p-7 pt-4">
3 + <CardKV v-for="(value, key) of asset" :key="key">
4 <template #key>
5 {{ key }}
6 </template>
7 <template #value>
8 <div v-if="key === 'id'">#{{ value }}</div>
9 <div v-else-if="key === 'customer_code'">
10 - <code
11 - class="cursor-pointer text-primary-color"
12 - @click.stop="gotoCustomer({ code: asset.customer_code })"
13 - >
10 + <code class="text-primary cursor-pointer" @click.stop="gotoCustomer({ code: asset.customer_code })">
11 #{{ asset.customer_code }}
15 - <Icon :name="LinkIcon" :size="14" class="top-0.5 relative" />
12 + <Icon :name="LinkIcon" :size="14" class="relative top-0.5" />
13 </code>
14 </div>
15 <div v-else-if="key === 'agent_id'">
19 - <code class="cursor-pointer text-primary-color" @click.stop="gotoAgent(asset.agent_id)">
16 + <code class="text-primary cursor-pointer" @click.stop="gotoAgent(asset.agent_id)">
17 {{ asset.agent_id }}
21 - <Icon :name="LinkIcon" :size="14" class="top-0.5 relative" />
18 + <Icon :name="LinkIcon" :size="14" class="relative top-0.5" />
19 </code>
20 </div>
21 <div v-else-if="key === 'index_name'">
25 - <code class="cursor-pointer text-primary-color" @click.stop="gotoIndex(asset.index_name)">
22 + <code class="text-primary cursor-pointer" @click.stop="gotoIndex(asset.index_name)">
23 {{ asset.index_name }}
27 - <Icon :name="LinkIcon" :size="14" class="top-0.5 relative" />
24 + <Icon :name="LinkIcon" :size="14" class="relative top-0.5" />
25 </code>
26 </div>
27 <div v-else-if="key === 'index_id'">
31 - <code class="cursor-pointer text-primary-color" @click.stop="openAlertDetails()">
28 + <code class="text-primary cursor-pointer" @click.stop="openAlertDetails()">
29 {{ asset.index_id }}
33 - <Icon :name="ViewIcon" :size="14" class="top-0.5 relative" />
30 + <Icon :name="ViewIcon" :size="14" class="relative top-0.5" />
31 </code>
32 </div>
33 <div v-else>
34 {{ value === "" ? "-" : (value ?? "-") }}
35 </div>
36 </template>
40 - </KVCard>
37 + </CardKV>
38 </div>
39
40 <n-modal
@@ -52,26 +49,26 @@
49 <n-spin :show="loading" class="min-h-40">
50 <n-tabs type="line" animated :tabs-padding="24">
51 <n-tab-pane name="Info" tab="Info" display-directive="show">
55 - <div class="grid gap-2 grid-auto-fit-200 p-7 pt-4">
56 - <KVCard v-for="(value, key) of alertDetailsInfo" :key="key">
52 + <div class="grid-auto-fit-200 grid gap-2 p-7 pt-4">
53 + <CardKV v-for="(value, key) of alertDetailsInfo" :key="key">
54 <template #key>
55 {{ key }}
56 </template>
57 <template #value>
58 <div v-if="key === '_index'">
59 <code
63 - class="cursor-pointer text-primary-color"
60 + class="text-primary cursor-pointer"
61 @click.stop="gotoIndex(alertDetailsInfo._index)"
62 >
63 {{ alertDetailsInfo._index }}
67 - <Icon :name="LinkIcon" :size="14" class="top-0.5 relative" />
64 + <Icon :name="LinkIcon" :size="14" class="relative top-0.5" />
65 </code>
66 </div>
67 <div v-else>
68 {{ value === "" ? "-" : (value ?? "-") }}
69 </div>
70 </template>
74 - </KVCard>
71 + </CardKV>
72 </div>
73 </n-tab-pane>
74 <n-tab-pane name="Source" tab="Source" display-directive="show">
@@ -87,8 +84,8 @@
84 <script setup lang="ts">
85 import type { AlertAsset, AlertDetails } from "@/types/incidentManagement/alerts.d"
86 import Api from "@/api"
87 +import CardKV from "@/components/common/cards/CardKV.vue"
88 import Icon from "@/components/common/Icon.vue"
91 -import KVCard from "@/components/common/KVCard.vue"
89 import { useGoto } from "@/composables/useGoto"
90 import _omit from "lodash/omit"
91 import { NModal, NSpin, NTabPane, NTabs, useMessage } from "naive-ui"
frontend/src/components/incidentManagement/alerts/AlertAssetsList.vue
+1 -1
@@ -4,7 +4,7 @@
4 <AlertAssetItem v-for="asset of assets" :key="asset.id" :asset embedded />
5 </template>
6 <template v-else>
7 - <n-empty description="No assets found" class="justify-center h-48" />
7 + <n-empty description="No assets found" class="h-48 justify-center" />
8 </template>
9 </div>
10 </template>
frontend/src/components/incidentManagement/alerts/AlertComment.vue
+2 -2
@@ -3,8 +3,8 @@
3 <div v-if="userPic" class="user-pic">
4 <n-avatar round :size="32" :src="userPic" />
5 </div>
6 - <div class="comment grow flex flex-col gap-1">
7 - <div class="user flex gap-3 items-center">
6 + <div class="comment flex grow flex-col gap-1">
7 + <div class="user flex items-center gap-3">
8 <div class="user-name">
9 {{ comment.user_name }}
10 </div>
frontend/src/components/incidentManagement/alerts/AlertCommentsList.vue
+2 -2
@@ -4,7 +4,7 @@
4 <AlertCommentItem v-for="comment of commentsList" :key="comment.id" :comment embedded />
5 </template>
6 <template v-else>
7 - <n-empty description="No comments found" class="justify-center h-48" />
7 + <n-empty description="No comments found" class="h-48 justify-center" />
8 </template>
9 <n-spin :show="submitting">
10 <div class="comment-form mt-6 flex flex-col gap-3">
@@ -19,7 +19,7 @@
19 }"
20 />
21 </div>
22 - <div class="tool-box flex gap-2 justify-end">
22 + <div class="tool-box flex justify-end gap-2">
23 <n-button secondary :disabled="submitting" @click="reset()">Reset</n-button>
24 <n-button
25 type="primary"
frontend/src/components/incidentManagement/alerts/AlertDetailTimelineItem.vue
+11 -39
@@ -1,14 +1,8 @@
1 <template>
2 - <div class="alert-timeline-item" :class="{ embedded }">
3 - <div class="flex flex-col cursor-pointer" @click="showDetails = true">
4 - <div class="main-box flex flex-col gap-3 px-5 py-3">
5 - <div class="content flex flex-col gap-1 grow">
6 - <div class="title">
7 - {{ timelineData._source.rule_description }}
8 - </div>
9 - </div>
10 - </div>
11 - </div>
2 + <div>
3 + <CardEntity :embedded hoverable clickable @click="showDetails = true">
4 + {{ timelineData._source.rule_description }}
5 + </CardEntity>
6
7 <n-modal
8 v-model:show="showDetails"
@@ -21,26 +15,26 @@
15 >
16 <n-tabs type="line" animated :tabs-padding="24">
17 <n-tab-pane name="Info" tab="Info" display-directive="show">
24 - <div class="grid gap-2 grid-auto-fit-200 p-7 pt-4">
25 - <KVCard v-for="(value, key) of timelineDetailsInfo" :key="key">
18 + <div class="grid-auto-fit-200 grid gap-2 p-7 pt-4">
19 + <CardKV v-for="(value, key) of timelineDetailsInfo" :key="key">
20 <template #key>
21 {{ key }}
22 </template>
23 <template #value>
24 <div v-if="key === '_index'">
25 <code
32 - class="cursor-pointer text-primary-color"
26 + class="text-primary cursor-pointer"
27 @click.stop="gotoIndex(timelineDetailsInfo._index)"
28 >
29 {{ timelineDetailsInfo._index }}
36 - <Icon :name="LinkIcon" :size="14" class="top-0.5 relative" />
30 + <Icon :name="LinkIcon" :size="14" class="relative top-0.5" />
31 </code>
32 </div>
33 <div v-else>
34 {{ value === "" ? "-" : (value ?? "-") }}
35 </div>
36 </template>
43 - </KVCard>
37 + </CardKV>
38 </div>
39 </n-tab-pane>
40 <n-tab-pane name="Source" tab="Source" display-directive="show">
@@ -55,8 +49,9 @@
49
50 <script setup lang="ts">
51 import type { AlertTimeline } from "@/types/incidentManagement/alerts.d"
52 +import CardEntity from "@/components/common/cards/CardEntity.vue"
53 +import CardKV from "@/components/common/cards/CardKV.vue"
54 import Icon from "@/components/common/Icon.vue"
59 -import KVCard from "@/components/common/KVCard.vue"
55 import { useGoto } from "@/composables/useGoto"
56 import _omit from "lodash/omit"
57 import { NModal, NTabPane, NTabs } from "naive-ui"
@@ -74,26 +69,3 @@ const showDetails = ref(false)
69 const timelineDetailsInfo = computed(() => _omit(timelineData.value, ["_source"]))
70 const timelineDetailsSource = computed(() => timelineData.value?._source)
71 </script>
77 -
78 -<style lang="scss" scoped>
79 -.alert-timeline-item {
80 - border-radius: var(--border-radius);
81 - background-color: var(--bg-color);
82 - transition: all 0.2s var(--bezier-ease);
83 - border: var(--border-small-050);
84 - overflow: hidden;
85 -
86 - .main-box {
87 - .content {
88 - word-break: break-word;
89 - }
90 - }
91 -
92 - &.embedded {
93 - background-color: var(--bg-secondary-color);
94 - }
95 - &:hover {
96 - box-shadow: 0px 0px 0px 1px var(--primary-color);
97 - }
98 -}
99 -</style>
frontend/src/components/incidentManagement/alerts/AlertDetails.vue
+2 -2
@@ -1,5 +1,5 @@
1 <template>
2 - <n-spin :show="loading" class="flex flex-col grow" content-class="flex flex-col grow">
2 + <n-spin :show="loading" class="flex grow flex-col" content-class="flex flex-col grow">
3 <n-tabs
4 v-if="alert"
5 type="line"
@@ -8,7 +8,7 @@
8 class="grow"
9 pane-wrapper-class="flex flex-col grow"
10 >
11 - <n-tab-pane name="Overview" tab="Overview" display-directive="show:lazy" class="flex flex-col grow">
11 + <n-tab-pane name="Overview" tab="Overview" display-directive="show:lazy" class="flex grow flex-col">
12 <div class="pt-1">
13 <AlertOverview :alert @updated="updateAlert($event)" @deleted="emit('deleted')" />
14 </div>
frontend/src/components/incidentManagement/alerts/AlertItem.vue
+172 -248
@@ -1,51 +1,96 @@
1 <template>
2 - <div
3 - class="alert-item"
4 - :class="[`status-${alert?.status}`, { compact, embedded, 'cursor-pointer': compact, highlight }]"
5 - @click="compact ? openDetails() : undefined"
6 - >
7 - <n-spin :show="loading">
8 - <div v-if="alert" class="flex flex-col">
9 - <div class="header-box px-5 py-3 pb-0 flex justify-between items-center">
10 - <div class="id flex items-center gap-2 cursor-pointer" @click="openDetails()">
11 - <span>#{{ alert.id }} - {{ alert.source }}</span>
12 - <Icon v-if="!compact" :name="InfoIcon" :size="16"></Icon>
13 - </div>
14 - <div class="time">
15 - <n-popover
16 - v-if="!compact"
17 - overlap
18 - placement="top-end"
19 - style="max-height: 240px"
20 - scrollable
21 - to="body"
22 - >
23 - <template #trigger>
24 - <div class="flex items-center gap-2 cursor-help">
25 - <span v-if="alert.alert_creation_time">
26 - {{ formatDate(alert.alert_creation_time, dFormats.datetime) }}
27 - </span>
28 - <Icon :name="TimeIcon" :size="16"></Icon>
29 - </div>
30 - </template>
31 - <div class="flex flex-col py-2 px-1">
32 - <AlertTimeline v-if="alert" :alert />
33 - </div>
34 - </n-popover>
35 - <span v-if="compact && alert.alert_creation_time">
36 - {{ formatDate(alert.alert_creation_time, dFormats.datetime) }}
37 - </span>
38 - </div>
2 + <div>
3 + <CardEntity
4 + :loading
5 + :embedded
6 + hoverable
7 + :size="compact ? 'small' : 'medium'"
8 + :clickable="compact"
9 + :highlighted="highlight"
10 + @click="compact ? openDetails() : undefined"
11 + >
12 + <template v-if="alert" #headerMain>
13 + <div
14 + class="flex cursor-pointer items-center gap-2"
15 + :class="{ 'hover:text-primary cursor-pointer': !compact }"
16 + @click="compact ? undefined : openDetails()"
17 + >
18 + <span>#{{ alert.id }} - {{ alert.source }}</span>
19 + <Icon v-if="!compact" :name="InfoIcon" :size="16"></Icon>
20 </div>
40 -
41 - <div class="main-box flex flex-col gap-3 px-5 py-3">
42 - <div class="content flex flex-col gap-1 grow">
43 - <div class="title">
44 - {{ alert.alert_name }}
21 + </template>
22 + <template v-if="alert?.alert_creation_time" #headerExtra>
23 + <div :class="{ 'hidden sm:block': !compact }">
24 + <n-popover
25 + v-if="!compact"
26 + overlap
27 + placement="top-end"
28 + style="max-height: 240px"
29 + scrollable
30 + to="body"
31 + >
32 + <template #trigger>
33 + <div class="flex cursor-help items-center gap-2">
34 + <span v-if="alert.alert_creation_time">
35 + {{ formatDate(alert.alert_creation_time, dFormats.datetime) }}
36 + </span>
37 + <Icon :name="TimeIcon" :size="16"></Icon>
38 + </div>
39 + </template>
40 + <div class="flex flex-col px-1 py-2">
41 + <AlertTimeline v-if="alert" :alert />
42 </div>
46 - </div>
47 -
48 - <div v-if="compact" class="badges-box flex flex-wrap items-center gap-3">
43 + </n-popover>
44 + <span v-if="compact && alert.alert_creation_time">
45 + {{ formatDate(alert.alert_creation_time, dFormats.datetime) }}
46 + </span>
47 + </div>
48 + </template>
49 +
50 + <template v-if="alert" #default>
51 + {{ alert.alert_name }}
52 + </template>
53 +
54 + <template v-if="alert" #mainExtra>
55 + <div v-if="compact" class="flex flex-wrap items-center gap-3">
56 + <Badge
57 + type="splitted"
58 + class="cursor-pointer"
59 + bright
60 + :color="
61 + alert.status === 'OPEN' ? 'danger' : alert.status === 'IN_PROGRESS' ? 'warning' : 'success'
62 + "
63 + >
64 + <template #iconLeft>
65 + <StatusIcon :status="alert.status" />
66 + </template>
67 + <template #label>Status</template>
68 + <template #value>
69 + <div class="flex items-center gap-2">
70 + {{ alert.status || "n/d" }}
71 + </div>
72 + </template>
73 + </Badge>
74 +
75 + <Badge
76 + type="splitted"
77 + class="cursor-pointer"
78 + bright
79 + :color="alert.assigned_to ? 'success' : undefined"
80 + >
81 + <template #iconLeft>
82 + <AssigneeIcon :assignee="alert.assigned_to" />
83 + </template>
84 + <template #label>Assignee</template>
85 + <template #value>
86 + <div class="flex items-center gap-2">
87 + {{ alert.assigned_to || "n/d" }}
88 + </div>
89 + </template>
90 + </Badge>
91 + </div>
92 + <div v-else class="flex flex-wrap items-center gap-3">
93 + <AlertStatusSwitch v-slot="{ loading: loadingStatus }" :alert @updated="updateAlert($event)">
94 <Badge
95 type="splitted"
96 class="cursor-pointer"
@@ -59,16 +104,21 @@
104 "
105 >
106 <template #iconLeft>
62 - <StatusIcon :status="alert.status" />
107 + <n-spin :size="12" :show="loadingStatus" content-class="flex flex-col justify-center">
108 + <StatusIcon :status="alert.status" />
109 + </n-spin>
110 </template>
111 <template #label>Status</template>
112 <template #value>
66 - <div class="flex gap-2 items-center">
113 + <div class="flex items-center gap-2">
114 {{ alert.status || "n/d" }}
115 + <Icon :name="EditIcon" :size="13" />
116 </div>
117 </template>
118 </Badge>
119 + </AlertStatusSwitch>
120
121 + <AlertAssignUser v-slot="{ loading: loadingAssignee }" :alert @updated="updateAlert($event)">
122 <Badge
123 type="splitted"
124 class="cursor-pointer"
@@ -76,150 +126,99 @@
126 :color="alert.assigned_to ? 'success' : undefined"
127 >
128 <template #iconLeft>
79 - <AssigneeIcon :assignee="alert.assigned_to" />
129 + <n-spin :size="12" :show="loadingAssignee" content-class="flex flex-col justify-center">
130 + <AssigneeIcon :assignee="alert.assigned_to" />
131 + </n-spin>
132 </template>
133 <template #label>Assignee</template>
134 <template #value>
83 - <div class="flex gap-2 items-center">
135 + <div class="flex items-center gap-2">
136 {{ alert.assigned_to || "n/d" }}
137 + <Icon :name="EditIcon" :size="13" />
138 </div>
139 </template>
140 </Badge>
88 - </div>
89 - <div v-else class="badges-box flex flex-wrap items-center gap-3">
90 - <AlertStatusSwitch v-slot="{ loading: loadingStatus }" :alert @updated="updateAlert($event)">
91 - <Badge
92 - type="splitted"
93 - class="cursor-pointer"
94 - bright
95 - :color="
96 - alert.status === 'OPEN'
97 - ? 'danger'
98 - : alert.status === 'IN_PROGRESS'
99 - ? 'warning'
100 - : 'success'
101 - "
102 - >
141 + </AlertAssignUser>
142 +
143 + <Badge v-if="alert.customer_code" type="splitted" class="!hidden sm:!flex">
144 + <template #label>Customer</template>
145 + <template #value>
146 + <div class="flex h-full items-center">
147 + <code
148 + class="text-primary cursor-pointer leading-none"
149 + @click.stop="gotoCustomer({ code: alert.customer_code })"
150 + >
151 + #{{ alert.customer_code }}
152 + <Icon :name="LinkIcon" :size="14" class="relative top-0.5" />
153 + </code>
154 + </div>
155 + </template>
156 + </Badge>
157 +
158 + <Badge v-if="alert.assets?.length" type="splitted" fluid class="!hidden sm:!flex">
159 + <template #label>Assets</template>
160 + <template #value>
161 + <div class="flex flex-wrap gap-1">
162 + <AlertAssetItem v-for="asset of alert.assets" :key="asset.id" :asset badge />
163 + </div>
164 + </template>
165 + </Badge>
166 + </div>
167 + </template>
168 +
169 + <template v-if="alert && !compact" #footerMain>
170 + <div class="flex items-center gap-3">
171 + <Badge v-if="alert.alert_creation_time" type="splitted" :class="{ 'flex sm:!hidden': !compact }">
172 + <template #iconLeft>
173 + <Icon :name="TimeIcon" :size="16" />
174 + </template>
175 + <template #value>
176 + {{ formatDate(alert.alert_creation_time, dFormats.datetime) }}
177 + </template>
178 + </Badge>
179 +
180 + <n-tooltip trigger="hover">
181 + <template #trigger>
182 + <Badge type="splitted" class="xs:!flex !hidden">
183 <template #iconLeft>
104 - <n-spin
105 - :size="12"
106 - :show="loadingStatus"
107 - content-class="flex flex-col justify-center"
108 - >
109 - <StatusIcon :status="alert.status" />
110 - </n-spin>
184 + <Icon :name="AssetsIcon" :size="16" />
185 </template>
112 - <template #label>Status</template>
186 <template #value>
114 - <div class="flex gap-2 items-center">
115 - {{ alert.status || "n/d" }}
116 - <Icon :name="EditIcon" :size="13" />
117 - </div>
187 + {{ alert.assets?.length || 0 }}
188 </template>
189 </Badge>
120 - </AlertStatusSwitch>
190 + </template>
191 + Assets
192 + </n-tooltip>
193
122 - <AlertAssignUser v-slot="{ loading: loadingAssignee }" :alert @updated="updateAlert($event)">
123 - <Badge
124 - type="splitted"
125 - class="cursor-pointer"
126 - bright
127 - :color="alert.assigned_to ? 'success' : undefined"
128 - >
194 + <n-tooltip trigger="hover">
195 + <template #trigger>
196 + <Badge type="splitted" class="xs:!flex !hidden">
197 <template #iconLeft>
130 - <n-spin
131 - :size="12"
132 - :show="loadingAssignee"
133 - content-class="flex flex-col justify-center"
134 - >
135 - <AssigneeIcon :assignee="alert.assigned_to" />
136 - </n-spin>
198 + <Icon :name="CommentsIcon" :size="16" />
199 </template>
138 - <template #label>Assignee</template>
200 <template #value>
140 - <div class="flex gap-2 items-center">
141 - {{ alert.assigned_to || "n/d" }}
142 - <Icon :name="EditIcon" :size="13" />
143 - </div>
201 + {{ alert.comments?.length || 0 }}
202 </template>
203 </Badge>
146 - </AlertAssignUser>
147 -
148 - <Badge v-if="alert.customer_code" type="splitted" class="!hidden sm:!flex">
149 - <template #label>Customer</template>
150 - <template #value>
151 - <div class="flex items-center h-full">
152 - <code
153 - class="cursor-pointer text-primary-color leading-none"
154 - @click.stop="gotoCustomer({ code: alert.customer_code })"
155 - >
156 - #{{ alert.customer_code }}
157 - <Icon :name="LinkIcon" :size="14" class="top-0.5 relative" />
158 - </code>
159 - </div>
160 - </template>
161 - </Badge>
162 -
163 - <Badge v-if="alert.assets?.length" type="splitted" fluid class="!hidden sm:!flex">
164 - <template #label>Assets</template>
165 - <template #value>
166 - <div class="flex flex-wrap gap-1">
167 - <AlertAssetItem v-for="asset of alert.assets" :key="asset.id" :asset badge />
168 - </div>
169 - </template>
170 - </Badge>
171 - </div>
172 - </div>
173 -
174 - <div v-if="!compact" class="footer-box px-5 py-3 flex justify-between items-center">
175 - <div class="details flex gap-3 items-center">
176 - <Badge v-if="alert.alert_creation_time" type="splitted" class="time">
177 - <template #iconLeft>
178 - <Icon :name="TimeIcon" :size="16" />
179 - </template>
180 - <template #value>
181 - {{ formatDate(alert.alert_creation_time, dFormats.datetime) }}
182 - </template>
183 - </Badge>
184 -
185 - <n-tooltip trigger="hover">
186 - <template #trigger>
187 - <Badge type="splitted" class="!hidden xs:!flex">
188 - <template #iconLeft>
189 - <Icon :name="AssetsIcon" :size="16" />
190 - </template>
191 - <template #value>
192 - {{ alert.assets?.length || 0 }}
193 - </template>
194 - </Badge>
195 - </template>
196 - Assets
197 - </n-tooltip>
198 -
199 - <n-tooltip trigger="hover">
200 - <template #trigger>
201 - <Badge type="splitted" class="!hidden xs:!flex">
202 - <template #iconLeft>
203 - <Icon :name="CommentsIcon" :size="16" />
204 - </template>
205 - <template #value>
206 - {{ alert.comments?.length || 0 }}
207 - </template>
208 - </Badge>
209 - </template>
210 - Comments
211 - </n-tooltip>
212 -
213 - <span v-for="tag of alert.tags" :key="tag.tag" class="text-secondary-color">
214 - #{{ tag.tag }}
215 - </span>
216 - </div>
217 - <div class="actions-box">
218 - <n-button quaternary size="tiny" @click.stop="handleDelete()">Delete</n-button>
219 - </div>
204 + </template>
205 + Comments
206 + </n-tooltip>
207 +
208 + <span
209 + v-for="tag of alert.tags"
210 + :key="tag.tag"
211 + class="text-secondary"
212 + :class="{ 'hidden sm:inline-block': !compact }"
213 + >
214 + #{{ tag.tag }}
215 + </span>
216 </div>
221 - </div>
222 - </n-spin>
217 + </template>
218 + <template v-if="alert && !compact" #footerExtra>
219 + <n-button quaternary size="tiny" @click.stop="handleDelete()">Delete</n-button>
220 + </template>
221 + </CardEntity>
222
223 <n-modal
224 v-model:show="showDetails"
@@ -245,6 +244,7 @@
244 import type { Alert } from "@/types/incidentManagement/alerts.d"
245 import Api from "@/api"
246 import Badge from "@/components/common/Badge.vue"
247 +import CardEntity from "@/components/common/cards/CardEntity.vue"
248 import Icon from "@/components/common/Icon.vue"
249 import { useGoto } from "@/composables/useGoto"
250 import { useSettingsStore } from "@/stores/settings"
@@ -370,79 +370,3 @@ onMounted(() => {
370 }
371 })
372 </script>
373 -
374 -<style lang="scss" scoped>
375 -.alert-item {
376 - border-radius: var(--border-radius);
377 - background-color: var(--bg-color);
378 - transition: all 0.2s var(--bezier-ease);
379 - border: var(--border-small-050);
380 - overflow: hidden;
381 -
382 - .header-box {
383 - font-family: var(--font-family-mono);
384 - font-size: 13px;
385 - color: var(--fg-secondary-color);
386 -
387 - .id {
388 - word-break: break-word;
389 - line-height: 1.2;
390 - }
391 - }
392 - .main-box {
393 - .content {
394 - word-break: break-word;
395 - }
396 - }
397 -
398 - .footer-box {
399 - border-top: var(--border-small-100);
400 - font-size: 13px;
401 - background-color: var(--bg-secondary-color);
402 -
403 - .time {
404 - display: none;
405 - }
406 - }
407 -
408 - &.embedded {
409 - background-color: var(--bg-secondary-color);
410 - border: var(--border-small-100);
411 -
412 - .footer-box {
413 - background-color: var(--bg-body);
414 - }
415 - }
416 -
417 - &:hover {
418 - box-shadow: 0px 0px 0px 1px var(--primary-color);
419 - }
420 -
421 - &.highlight {
422 - box-shadow: 0px 0px 0px 1px var(--primary-color);
423 - }
424 -
425 - &:not(.compact) {
426 - .header-box {
427 - .id {
428 - &:hover {
429 - color: var(--primary-color);
430 - }
431 - }
432 - }
433 -
434 - @container (max-width: 600px) {
435 - .header-box {
436 - .time {
437 - display: none;
438 - }
439 - }
440 - .footer-box {
441 - .time {
442 - display: flex;
443 - }
444 - }
445 - }
446 - }
447 -}
448 -</style>
frontend/src/components/incidentManagement/alerts/AlertLinkedCases.vue
+2 -2
@@ -2,11 +2,11 @@
2 <code
3 v-for="linkedCase of linkedCases"
4 :key="linkedCase.id"
5 - class="cursor-pointer text-primary-color"
5 + class="text-primary cursor-pointer"
6 @click="gotoIncidentManagementCases(linkedCase.id)"
7 >
8 #{{ linkedCase.id }}
9 - <Icon :name="LinkIcon" :size="14" class="top-0.5 relative" />
9 + <Icon :name="LinkIcon" :size="14" class="relative top-0.5" />
10 </code>
11 </template>
12
frontend/src/components/incidentManagement/alerts/AlertMergeCaseButton.vue
+4 -4
@@ -17,10 +17,10 @@
17 >
18 <n-spin
19 :show="loadingCases"
20 - class="grow overflow-hidden flex flex-col"
20 + class="flex grow flex-col overflow-hidden"
21 content-class="grow overflow-hidden flex flex-col"
22 >
23 - <n-scrollbar class="grow flex flex-col" content-class="grow" trigger="none">
23 + <n-scrollbar class="flex grow flex-col" content-class="grow" trigger="none">
24 <div class="flex flex-col gap-2 px-5 py-2">
25 <template v-if="linkableCases.length">
26 <CaseItem
@@ -29,12 +29,12 @@
29 :case-data="item"
30 compact
31 embedded
32 - :class="{ active: selectedCase?.id === item.id }"
32 + :highlight="selectedCase?.id === item.id"
33 @click="toggleSelectedCase(item)"
34 />
35 </template>
36 <template v-else>
37 - <n-empty v-if="!loadingCases" description="No items found" class="justify-center h-48" />
37 + <n-empty v-if="!loadingCases" description="No items found" class="h-48 justify-center" />
38 </template>
39 </div>
40 </n-scrollbar>
frontend/src/components/incidentManagement/alerts/AlertOverview.vue
+31 -31
@@ -1,17 +1,17 @@
1 <template>
2 - <n-spin :show="loading" class="flex flex-col grow" content-class="flex flex-col grow">
3 - <div class="flex flex-col gap-4 grow justify-between">
2 + <n-spin :show="loading" class="flex grow flex-col" content-class="flex flex-col grow">
3 + <div class="flex grow flex-col justify-between gap-4">
4 <div class="content-box flex flex-col gap-4 py-3">
5 - <div class="px-7 flex sm:!flex-row flex-col gap-4">
6 - <KVCard
5 + <div class="flex flex-col gap-4 px-7 sm:!flex-row">
6 + <CardKV
7 :color="
8 alert.status === 'OPEN' ? 'danger' : alert.status === 'IN_PROGRESS' ? 'warning' : 'success'
9 "
10 size="lg"
11 - class="grow w-full"
11 + class="w-full grow"
12 >
13 <template #key>
14 - <div class="flex gap-2 items-center">
14 + <div class="flex items-center gap-2">
15 <StatusIcon :status="alert.status" />
16 <span>Status</span>
17 </div>
@@ -24,7 +24,7 @@
24 @updated="updateAlert($event)"
25 >
26 <div
27 - class="flex gap-3 items-center"
27 + class="flex items-center gap-3"
28 :class="{
29 'cursor-not-allowed': loadingStatus,
30 'cursor-pointer': !loadingStatus
@@ -42,11 +42,11 @@
42 </AlertStatusSwitch>
43 </div>
44 </template>
45 - </KVCard>
45 + </CardKV>
46
47 - <KVCard :color="alert.assigned_to ? 'success' : undefined" size="lg" class="grow w-full">
47 + <CardKV :color="alert.assigned_to ? 'success' : undefined" size="lg" class="w-full grow">
48 <template #key>
49 - <div class="flex gap-2 items-center">
49 + <div class="flex items-center gap-2">
50 <AssigneeIcon :assignee="alert.assigned_to" />
51 <span>Assigned to</span>
52 </div>
@@ -59,7 +59,7 @@
59 @updated="updateAlert($event)"
60 >
61 <div
62 - class="flex gap-3 items-center"
62 + class="flex items-center gap-3"
63 :class="{
64 'cursor-not-allowed': loadingAssignee,
65 'cursor-pointer': !loadingAssignee
@@ -77,73 +77,73 @@
77 </AlertAssignUser>
78 </div>
79 </template>
80 - </KVCard>
80 + </CardKV>
81 </div>
82
83 <div class="px-7">
84 - <KVCard>
84 + <CardKV>
85 <template #key>description</template>
86 <template #value>
87 {{ alert.alert_description ?? "-" }}
88 </template>
89 - </KVCard>
89 + </CardKV>
90 </div>
91
92 - <div class="px-7 grid gap-2 grid-auto-fit-250">
93 - <KVCard>
92 + <div class="grid-auto-fit-250 grid gap-2 px-7">
93 + <CardKV>
94 <template #key>id</template>
95 <template #value>#{{ alert.id }}</template>
96 - </KVCard>
96 + </CardKV>
97
98 - <KVCard>
98 + <CardKV>
99 <template #key>source</template>
100 <template #value>
101 {{ alert.source ?? "-" }}
102 </template>
103 - </KVCard>
103 + </CardKV>
104
105 - <KVCard>
105 + <CardKV>
106 <template #key>customer code</template>
107 <template #value>
108 <code
109 - class="cursor-pointer text-primary-color"
109 + class="text-primary cursor-pointer"
110 @click="gotoCustomer({ code: alert.customer_code })"
111 >
112 {{ alert.customer_code }}
113 <Icon :name="LinkIcon" :size="13" class="relative top-0.5" />
114 </code>
115 </template>
116 - </KVCard>
116 + </CardKV>
117
118 - <KVCard>
118 + <CardKV>
119 <template #key>assets</template>
120 <template #value>
121 {{ alert.assets.length }}
122 </template>
123 - </KVCard>
123 + </CardKV>
124
125 - <KVCard>
125 + <CardKV>
126 <template #key>comments</template>
127 <template #value>
128 {{ alert.comments.length }}
129 </template>
130 - </KVCard>
130 + </CardKV>
131
132 - <KVCard>
132 + <CardKV>
133 <template #key>tags</template>
134 <template #value>
135 <AlertTags :alert @updated="updateAlert" />
136 </template>
137 - </KVCard>
137 + </CardKV>
138 </div>
139 </div>
140
141 - <div class="footer-box px-7 py-4 flex items-center gap-2">
141 + <div class="footer-box flex items-center gap-2 px-7 py-4">
142 <AlertCreateCaseButton v-if="!linkedCases.length" :alert @updated="updateAlert" />
143
144 <AlertMergeCaseButton v-if="!linkedCases.length" :alert @updated="updateAlert" />
145
146 - <div v-if="linkedCases.length" class="flex flex-wrap gap-3 items-center">
146 + <div v-if="linkedCases.length" class="flex flex-wrap items-center gap-3">
147 <span>Linked Cases:</span>
148 <AlertLinkedCases :alert />
149 </div>
@@ -163,8 +163,8 @@
163
164 <script setup lang="ts">
165 import type { Alert } from "@/types/incidentManagement/alerts.d"
166 +import CardKV from "@/components/common/cards/CardKV.vue"
167 import Icon from "@/components/common/Icon.vue"
167 -import KVCard from "@/components/common/KVCard.vue"
168 import { useGoto } from "@/composables/useGoto"
169 import { NButton, NSpin, useDialog, useMessage } from "naive-ui"
170 import { computed, defineAsyncComponent, ref, toRefs } from "vue"
frontend/src/components/incidentManagement/alerts/AlertsList.vue
+11 -16
@@ -1,10 +1,10 @@
1 <template>
2 <div class="alerts-list">
3 <div ref="header" class="header flex items-center justify-end gap-2">
4 - <div class="info grow flex gap-2 lg:!hidden">
4 + <div class="info flex grow gap-2 lg:!hidden">
5 <n-popover overlap placement="left">
6 <template #trigger>
7 - <div class="bg-color border-radius">
7 + <div class="bg-default rounded-default">
8 <n-button size="small" class="!cursor-help">
9 <template #icon>
10 <Icon :name="InfoIcon"></Icon>
@@ -17,22 +17,22 @@
17 Total :
18 <code>{{ total }}</code>
19 </div>
20 - <div class="box text-error-color">
20 + <div class="box text-error">
21 Open :
22 <code>{{ statusOpenTotal }}</code>
23 </div>
24 - <div class="box text-warning-color">
24 + <div class="box text-warning">
25 In Progress :
26 <code>{{ statusInProgressTotal }}</code>
27 </div>
28 - <div class="box text-success-color">
28 + <div class="box text-success">
29 Close :
30 <code>{{ statusCloseTotal }}</code>
31 </div>
32 </div>
33 </n-popover>
34 </div>
35 - <div class="info grow lg:flex gap-1 hidden text-sm items-center">
35 + <div class="info hidden grow items-center gap-1 text-sm lg:flex">
36 <n-button quaternary size="small" @click="filtersCTX?.setFilter([{ type: 'status', value: null }])">
37 <div class="flex items-center gap-2">
38 <span>Total</span>
@@ -43,7 +43,7 @@
43 <n-button quaternary size="small" @click="filtersCTX?.setFilter([{ type: 'status', value: 'OPEN' }])">
44 <div class="flex items-center gap-2">
45 <span>Open</span>
46 - <code class="py-1 text-error-color">{{ statusOpenTotal }}</code>
46 + <code class="text-error py-1">{{ statusOpenTotal }}</code>
47 </div>
48 </n-button>
49 <span>/</span>
@@ -54,14 +54,14 @@
54 >
55 <div class="flex items-center gap-2">
56 <span>In Progress</span>
57 - <code class="py-1 text-warning-color">{{ statusInProgressTotal }}</code>
57 + <code class="text-warning py-1">{{ statusInProgressTotal }}</code>
58 </div>
59 </n-button>
60 <span>/</span>
61 <n-button quaternary size="small" @click="filtersCTX?.setFilter([{ type: 'status', value: 'CLOSED' }])">
62 <div class="flex items-center gap-2">
63 <span>Close</span>
64 - <code class="py-1 text-success-color">{{ statusCloseTotal }}</code>
64 + <code class="text-success py-1">{{ statusCloseTotal }}</code>
65 </div>
66 </n-button>
67 </div>
@@ -104,7 +104,7 @@
104 </div>
105
106 <n-spin :show="loading">
107 - <div class="list flex flex-col gap-2 my-3">
107 + <div class="my-3 flex min-h-52 flex-col gap-2">
108 <template v-if="alertsList.length">
109 <AlertItem
110 v-for="alert of alertsList"
@@ -119,7 +119,7 @@
119 />
120 </template>
121 <template v-else>
122 - <n-empty v-if="!loading" description="No items found" class="justify-center h-48" />
122 + <n-empty v-if="!loading" description="No items found" class="h-48 justify-center" />
123 </template>
124 </div>
125 </n-spin>
@@ -339,11 +339,6 @@ onBeforeMount(() => {
339
340 <style lang="scss" scoped>
341 .alerts-list {
342 - .list {
343 - container-type: inline-size;
344 - min-height: 200px;
345 - }
346 -
342 .filters-box {
343 overflow: hidden;
344 display: grid;
frontend/src/components/incidentManagement/cases/CaseDataStore.vue
+1 -1
@@ -1,5 +1,5 @@
1 <template>
2 - <n-spin :show="loading" class="flex flex-col grow min-h-48" content-class="flex flex-col grow gap-4">
2 + <n-spin :show="loading" class="flex min-h-48 grow flex-col" content-class="flex flex-col grow gap-4">
3 <div>
4 <n-collapse-transition :show="!showUploadForm">
5 <n-button v-if="dataStore.length" :loading="uploading" type="primary" @click="openUploadForm()">
frontend/src/components/incidentManagement/cases/CaseDataStoreItem.vue
+64 -125
@@ -1,94 +1,82 @@
1 <template>
2 - <div class="data-store-file" :class="{ embedded }">
3 - <n-spin :show="canceling">
4 - <div class="flex flex-col">
5 - <div class="header-box px-5 py-3 pb-0 flex justify-between items-center gap-3">
6 - <div class="id flex items-center">
7 - <span>
8 - #{{ dataStoreFile.id }}
9 - <span class="hidden xs:inline">- {{ dataStoreFile.bucket_name }}</span>
10 - </span>
11 - </div>
12 - <div class="time">
13 - <span v-if="dataStoreFile.upload_time">
14 - {{ formatDate(dataStoreFile.upload_time, dFormats.datetime) }}
15 - </span>
16 - </div>
17 - </div>
18 -
19 - <div class="main-box flex flex-col gap-3 px-5 py-3">
20 - <div class="content flex flex-col gap-1">
21 - <span>
22 - {{ dataStoreFile.file_name }}
23 - </span>
24 -
25 - <small v-if="dataStoreFile.file_hash" class="text-secondary-color font-mono hidden sm:inline">
26 - hash:
27 - {{ dataStoreFile.file_hash }}
28 - </small>
29 - </div>
30 - </div>
31 -
32 - <div class="footer-box px-5 py-3 flex justify-between items-center">
33 - <div class="details gap-3 items-center hidden sm:flex">
34 - <Badge v-if="dataStoreFile.content_type" type="splitted">
35 - <template #label>type</template>
36 - <template #value>
37 - {{ dataStoreFile.content_type }}
38 - </template>
39 - </Badge>
40 - <Badge v-if="dataStoreFile.file_size" type="splitted">
41 - <template #label>size</template>
42 - <template #value>
43 - {{ prettyBytes }}
44 - </template>
45 - </Badge>
46 - </div>
47 - <div class="actions-box flex flex-wrap gap-3 justify-end w-full sm:w-auto">
48 - <n-popconfirm
49 - v-model:show="showDeleteConfirm"
50 - trigger="manual"
51 - to="body"
52 - @positive-click="deleteDataStoreFile()"
53 - @clickoutside="showDeleteConfirm = false"
54 - >
55 - <template #trigger>
56 - <n-button
57 - quaternary
58 - size="tiny"
59 - :loading="canceling"
60 - @click.stop="showDeleteConfirm = true"
61 - >
62 - Delete
63 - </n-button>
64 - </template>
65 - Are you sure you want to delete this file?
66 - </n-popconfirm>
2 + <CardEntity :loading="canceling" :embedded hoverable>
3 + <template #headerMain>
4 + <div class="flex items-center">
5 + <span>
6 + #{{ dataStoreFile.id }}
7 + <span class="xs:inline hidden">- {{ dataStoreFile.bucket_name }}</span>
8 + </span>
9 + </div>
10 + </template>
11 + <template v-if="dataStoreFile.upload_time" #headerExtra>
12 + {{ formatDate(dataStoreFile.upload_time, dFormats.datetime) }}
13 + </template>
14 + <template #default>
15 + <div class="flex flex-col gap-1">
16 + {{ dataStoreFile.file_name }}
17 +
18 + <p v-if="dataStoreFile.file_hash" class="hidden font-mono text-sm sm:inline">
19 + hash:
20 + {{ dataStoreFile.file_hash }}
21 + </p>
22 + </div>
23 + </template>
24 + <template #footerMain>
25 + <div class="hidden flex-wrap items-center gap-3 sm:flex">
26 + <Badge v-if="dataStoreFile.content_type" type="splitted">
27 + <template #label>type</template>
28 + <template #value>
29 + {{ dataStoreFile.content_type }}
30 + </template>
31 + </Badge>
32 + <Badge v-if="dataStoreFile.file_size" type="splitted">
33 + <template #label>size</template>
34 + <template #value>
35 + {{ prettyBytes }}
36 + </template>
37 + </Badge>
38 + </div>
39 + </template>
40 + <template #footerExtra>
41 + <div class="flex flex-wrap gap-3">
42 + <n-popconfirm
43 + v-model:show="showDeleteConfirm"
44 + trigger="manual"
45 + to="body"
46 + @positive-click="deleteDataStoreFile()"
47 + @clickoutside="showDeleteConfirm = false"
48 + >
49 + <template #trigger>
50 + <n-button quaternary size="tiny" :loading="canceling" @click.stop="showDeleteConfirm = true">
51 + Delete
52 + </n-button>
53 + </template>
54 + Are you sure you want to delete this file?
55 + </n-popconfirm>
56
68 - <n-button size="tiny" type="primary" :loading="downloading" @click.stop="downloadFile()">
69 - <template #icon>
70 - <Icon :name="DownloadIcon" />
71 - </template>
57 + <n-button size="tiny" type="primary" :loading="downloading" @click.stop="downloadFile()">
58 + <template #icon>
59 + <Icon :name="DownloadIcon" />
60 + </template>
61
73 - Download
74 - </n-button>
75 - </div>
76 - </div>
62 + Download
63 + </n-button>
64 </div>
78 - </n-spin>
79 - </div>
65 + </template>
66 + </CardEntity>
67 </template>
68
69 <script setup lang="ts">
70 import type { CaseDataStore } from "@/types/incidentManagement/cases"
71 import Api from "@/api"
72 import Badge from "@/components/common/Badge.vue"
73 +import CardEntity from "@/components/common/cards/CardEntity.vue"
74 import Icon from "@/components/common/Icon.vue"
75 import { useSettingsStore } from "@/stores/settings"
76 import { formatDate } from "@/utils"
77 import bytes from "bytes"
78 import { saveAs } from "file-saver"
91 -import { NButton, NPopconfirm, NSpin, useMessage } from "naive-ui"
79 +import { NButton, NPopconfirm, useMessage } from "naive-ui"
80 import { computed, ref } from "vue"
81
82 const { dataStoreFile, embedded } = defineProps<{
@@ -150,52 +138,3 @@ function deleteDataStoreFile() {
138 })
139 }
140 </script>
153 -
154 -<style lang="scss" scoped>
155 -.data-store-file {
156 - border-radius: var(--border-radius);
157 - background-color: var(--bg-color);
158 - transition: all 0.2s var(--bezier-ease);
159 - border: var(--border-small-050);
160 - overflow: hidden;
161 -
162 - .header-box {
163 - font-family: var(--font-family-mono);
164 - font-size: 13px;
165 - color: var(--fg-secondary-color);
166 -
167 - .id {
168 - word-break: break-word;
169 - line-height: 1.2;
170 - }
171 -
172 - .time {
173 - text-align: right;
174 - }
175 - }
176 - .main-box {
177 - .content {
178 - word-break: break-word;
179 - }
180 - }
181 -
182 - .footer-box {
183 - border-top: var(--border-small-100);
184 - font-size: 13px;
185 - background-color: var(--bg-secondary-color);
186 - }
187 -
188 - &.embedded {
189 - background-color: var(--bg-secondary-color);
190 - border: var(--border-small-100);
191 -
192 - .footer-box {
193 - background-color: var(--bg-body);
194 - }
195 - }
196 -
197 - &:hover {
198 - box-shadow: 0px 0px 0px 1px var(--primary-color);
199 - }
200 -}
201 -</style>
frontend/src/components/incidentManagement/cases/CaseDetails.vue
+4 -4
@@ -1,5 +1,5 @@
1 <template>
2 - <n-spin :show="loading" class="flex flex-col grow" content-class="flex flex-col grow">
2 + <n-spin :show="loading" class="flex grow flex-col" content-class="flex flex-col grow">
3 <n-tabs
4 v-if="caseEntity"
5 type="line"
@@ -8,13 +8,13 @@
8 class="grow"
9 pane-wrapper-class="flex flex-col grow"
10 >
11 - <n-tab-pane name="Overview" tab="Overview" display-directive="show:lazy" class="flex flex-col grow">
11 + <n-tab-pane name="Overview" tab="Overview" display-directive="show:lazy" class="flex grow flex-col">
12 <div class="pt-1">
13 <CaseOverview :case-data="caseEntity" @updated="updateCase($event)" @deleted="emit('deleted')" />
14 </div>
15 </n-tab-pane>
16 <n-tab-pane name="Alerts" tab="Alerts" display-directive="show:lazy">
17 - <div class="p-7 pt-4 flex flex-col gap-2">
17 + <div class="flex flex-col gap-2 p-7 pt-4">
18 <template v-if="caseEntity.alerts.length">
19 <AlertItem
20 v-for="alert of caseEntity.alerts"
@@ -26,7 +26,7 @@
26 />
27 </template>
28 <template v-else>
29 - <n-empty v-if="!loading" description="No items found" class="justify-center h-48" />
29 + <n-empty v-if="!loading" description="No items found" class="h-48 justify-center" />
30 </template>
31 </div>
32 </n-tab-pane>
frontend/src/components/incidentManagement/cases/CaseItem.vue
+117 -174
@@ -1,28 +1,82 @@
1 <template>
2 - <div
3 - class="case-item"
4 - :class="[`status-${caseEntity?.case_status}`, { compact, embedded, 'cursor-pointer': compact, highlight }]"
5 - >
6 - <n-spin :show="loading">
7 - <div v-if="caseEntity" class="flex flex-col">
8 - <div class="header-box px-5 py-3 pb-0 flex justify-between items-center">
9 - <div class="id flex items-center gap-2 cursor-pointer" @click="compact ? undefined : openDetails()">
10 - <span>#{{ caseEntity.id }}</span>
11 - <Icon v-if="!compact" :name="InfoIcon" :size="16"></Icon>
12 - </div>
13 - <div v-if="caseEntity.case_creation_time" class="time">
14 - {{ formatDate(caseEntity.case_creation_time, dFormats.datetime) }}
15 - </div>
2 + <div>
3 + <CardEntity
4 + :loading
5 + :embedded
6 + hoverable
7 + :size="compact ? 'small' : 'medium'"
8 + :clickable="compact"
9 + :highlighted="highlight"
10 + >
11 + <template v-if="caseEntity" #headerMain>
12 + <div
13 + class="flex items-center gap-2 break-words"
14 + :class="{ 'hover:text-primary cursor-pointer': !compact }"
15 + @click="compact ? undefined : openDetails()"
16 + >
17 + <span>#{{ caseEntity.id }}</span>
18 + <Icon v-if="!compact" :name="InfoIcon" :size="16"></Icon>
19 + </div>
20 + </template>
21 + <template v-if="caseEntity?.case_creation_time" #headerExtra>
22 + {{ formatDate(caseEntity.case_creation_time, dFormats.datetime) }}
23 + </template>
24 +
25 + <template v-if="caseEntity" #default>
26 + {{ caseEntity.case_name }}
27 + </template>
28 +
29 + <template v-if="caseEntity" #mainExtra>
30 + <div v-if="compact" class="flex flex-wrap items-center gap-3">
31 + <Badge
32 + type="splitted"
33 + class="cursor-pointer"
34 + bright
35 + :color="
36 + caseEntity.case_status === 'OPEN'
37 + ? 'danger'
38 + : caseEntity.case_status === 'IN_PROGRESS'
39 + ? 'warning'
40 + : caseEntity.case_status === 'CLOSED'
41 + ? 'success'
42 + : undefined
43 + "
44 + >
45 + <template #iconLeft>
46 + <StatusIcon :status="caseEntity.case_status" />
47 + </template>
48 + <template #label>Status</template>
49 + <template #value>
50 + <div class="flex items-center gap-2">
51 + {{ caseEntity.case_status || "n/d" }}
52 + </div>
53 + </template>
54 + </Badge>
55 +
56 + <Badge
57 + type="splitted"
58 + class="cursor-pointer"
59 + bright
60 + :color="caseEntity.assigned_to ? 'success' : undefined"
61 + >
62 + <template #iconLeft>
63 + <AssigneeIcon :assignee="caseEntity.assigned_to" />
64 + </template>
65 + <template #label>Assignee</template>
66 + <template #value>
67 + <div class="flex items-center gap-2">
68 + {{ caseEntity.assigned_to || "n/d" }}
69 + </div>
70 + </template>
71 + </Badge>
72 </div>
73
18 - <div class="main-box flex flex-col gap-3 px-5 py-3">
19 - <div class="content flex flex-col gap-1 grow">
20 - <div class="title">
21 - {{ caseEntity.case_name }}
22 - </div>
23 - </div>
24 -
25 - <div v-if="compact" class="badges-box flex flex-wrap items-center gap-3">
74 + <div v-else class="flex flex-wrap items-center gap-3">
75 + <CaseStatusSwitch
76 + v-slot="{ loading: loadingStatus }"
77 + :case-data="caseEntity"
78 + @updated="updateCase($event)"
79 + >
80 <Badge
81 type="splitted"
82 class="cursor-pointer"
@@ -38,16 +92,25 @@
92 "
93 >
94 <template #iconLeft>
41 - <StatusIcon :status="caseEntity.case_status" />
95 + <n-spin :size="12" :show="loadingStatus" content-class="flex flex-col justify-center">
96 + <StatusIcon :status="caseEntity.case_status" />
97 + </n-spin>
98 </template>
99 <template #label>Status</template>
100 <template #value>
45 - <div class="flex gap-2 items-center">
101 + <div class="flex items-center gap-2">
102 {{ caseEntity.case_status || "n/d" }}
103 + <Icon :name="EditIcon" :size="13" />
104 </div>
105 </template>
106 </Badge>
107 + </CaseStatusSwitch>
108
109 + <CaseAssignUser
110 + v-slot="{ loading: loadingAssignee }"
111 + :case-data="caseEntity"
112 + @updated="updateCase($event)"
113 + >
114 <Badge
115 type="splitted"
116 class="cursor-pointer"
@@ -55,104 +118,39 @@
118 :color="caseEntity.assigned_to ? 'success' : undefined"
119 >
120 <template #iconLeft>
58 - <AssigneeIcon :assignee="caseEntity.assigned_to" />
121 + <n-spin :size="12" :show="loadingAssignee" content-class="flex flex-col justify-center">
122 + <AssigneeIcon :assignee="caseEntity.assigned_to" />
123 + </n-spin>
124 </template>
125 <template #label>Assignee</template>
126 <template #value>
62 - <div class="flex gap-2 items-center">
127 + <div class="flex items-center gap-2">
128 {{ caseEntity.assigned_to || "n/d" }}
129 + <Icon :name="EditIcon" :size="13" />
130 </div>
131 </template>
132 </Badge>
67 - </div>
68 -
69 - <div v-else class="badges-box flex flex-wrap items-center gap-3">
70 - <CaseStatusSwitch
71 - v-slot="{ loading: loadingStatus }"
72 - :case-data="caseEntity"
73 - @updated="updateCase($event)"
74 - >
75 - <Badge
76 - type="splitted"
77 - class="cursor-pointer"
78 - bright
79 - :color="
80 - caseEntity.case_status === 'OPEN'
81 - ? 'danger'
82 - : caseEntity.case_status === 'IN_PROGRESS'
83 - ? 'warning'
84 - : caseEntity.case_status === 'CLOSED'
85 - ? 'success'
86 - : undefined
87 - "
88 - >
89 - <template #iconLeft>
90 - <n-spin
91 - :size="12"
92 - :show="loadingStatus"
93 - content-class="flex flex-col justify-center"
94 - >
95 - <StatusIcon :status="caseEntity.case_status" />
96 - </n-spin>
97 - </template>
98 - <template #label>Status</template>
99 - <template #value>
100 - <div class="flex gap-2 items-center">
101 - {{ caseEntity.case_status || "n/d" }}
102 - <Icon :name="EditIcon" :size="13" />
103 - </div>
104 - </template>
105 - </Badge>
106 - </CaseStatusSwitch>
107 -
108 - <CaseAssignUser
109 - v-slot="{ loading: loadingAssignee }"
110 - :case-data="caseEntity"
111 - @updated="updateCase($event)"
112 - >
113 - <Badge
114 - type="splitted"
115 - class="cursor-pointer"
116 - bright
117 - :color="caseEntity.assigned_to ? 'success' : undefined"
118 - >
119 - <template #iconLeft>
120 - <n-spin
121 - :size="12"
122 - :show="loadingAssignee"
123 - content-class="flex flex-col justify-center"
124 - >
125 - <AssigneeIcon :assignee="caseEntity.assigned_to" />
126 - </n-spin>
127 - </template>
128 - <template #label>Assignee</template>
129 - <template #value>
130 - <div class="flex gap-2 items-center">
131 - {{ caseEntity.assigned_to || "n/d" }}
132 - <Icon :name="EditIcon" :size="13" />
133 - </div>
134 - </template>
135 - </Badge>
136 - </CaseAssignUser>
137 -
138 - <Badge v-if="caseEntity.customer_code" type="splitted" class="!hidden sm:!flex">
139 - <template #label>Customer</template>
140 - <template #value>
141 - <div class="flex items-center h-full">
142 - <code
143 - class="cursor-pointer text-primary-color leading-none"
144 - @click.stop="gotoCustomer({ code: caseEntity.customer_code })"
145 - >
146 - #{{ caseEntity.customer_code }}
147 - <Icon :name="LinkIcon" :size="14" class="top-0.5 relative" />
148 - </code>
149 - </div>
150 - </template>
151 - </Badge>
152 - </div>
133 + </CaseAssignUser>
134 +
135 + <Badge v-if="caseEntity.customer_code" type="splitted" class="!hidden sm:!flex">
136 + <template #label>Customer</template>
137 + <template #value>
138 + <div class="flex h-full items-center">
139 + <code
140 + class="text-primary cursor-pointer leading-none"
141 + @click.stop="gotoCustomer({ code: caseEntity.customer_code })"
142 + >
143 + #{{ caseEntity.customer_code }}
144 + <Icon :name="LinkIcon" :size="14" class="relative top-0.5" />
145 + </code>
146 + </div>
147 + </template>
148 + </Badge>
149 </div>
150 + </template>
151
155 - <div v-if="!compact" class="footer-box px-5 py-3 flex justify-between items-center">
152 + <template v-if="caseEntity && !compact" #footer>
153 + <div class="flex items-center justify-between">
154 <n-collapse :trigger-areas="['main', 'arrow']">
155 <n-collapse-item name="alerts-list">
156 <template #header>
@@ -160,8 +158,8 @@
158 <code class="ml-2">{{ caseEntity.alerts.length }}</code>
159 </template>
160 <template #header-extra>
163 - <div class="actions-box flex gap-2 items-center ml-2">
164 - <n-button quaternary size="tiny" class="!hidden xs:!flex" @click="handleDelete()">
161 + <div class="actions-box ml-2 flex items-center gap-2">
162 + <n-button quaternary size="tiny" class="xs:!flex !hidden" @click="handleDelete()">
163 Delete Case
164 </n-button>
165 <CaseReportButton :case-id="caseEntity.id" size="tiny" />
@@ -182,15 +180,15 @@
180 <n-empty
181 v-if="!loading"
182 description="No alerts attached"
185 - class="justify-center h-24"
183 + class="h-24 justify-center"
184 />
185 </template>
186 </div>
187 </n-collapse-item>
188 </n-collapse>
189 </div>
192 - </div>
193 - </n-spin>
190 + </template>
191 + </CardEntity>
192
193 <n-modal
194 v-model:show="showDetails"
@@ -220,6 +218,7 @@
218 import type { Case } from "@/types/incidentManagement/cases.d"
219 import Api from "@/api"
220 import Badge from "@/components/common/Badge.vue"
221 +import CardEntity from "@/components/common/cards/CardEntity.vue"
222 import Icon from "@/components/common/Icon.vue"
223 import { useGoto } from "@/composables/useGoto"
224 import { useSettingsStore } from "@/stores/settings"
@@ -338,59 +337,3 @@ onMounted(() => {
337 }
338 })
339 </script>
341 -
342 -<style lang="scss" scoped>
343 -.case-item {
344 - border-radius: var(--border-radius);
345 - background-color: var(--bg-color);
346 - transition: all 0.2s var(--bezier-ease);
347 - border: var(--border-small-050);
348 - overflow: hidden;
349 -
350 - .header-box {
351 - font-family: var(--font-family-mono);
352 - font-size: 13px;
353 - color: var(--fg-secondary-color);
354 -
355 - .id {
356 - word-break: break-word;
357 - line-height: 1.2;
358 -
359 - &:hover {
360 - color: var(--primary-color);
361 - }
362 - }
363 - }
364 - .main-box {
365 - .content {
366 - word-break: break-word;
367 - }
368 - }
369 -
370 - .footer-box {
371 - border-top: var(--border-small-100);
372 - font-size: 13px;
373 - background-color: var(--bg-secondary-color);
374 -
375 - .time {
376 - display: none;
377 - }
378 - }
379 -
380 - &.embedded {
381 - background-color: var(--bg-secondary-color);
382 - }
383 -
384 - &:hover {
385 - box-shadow: 0px 0px 0px 1px var(--primary-040-color);
386 - }
387 -
388 - &:hover {
389 - box-shadow: 0px 0px 0px 1px var(--primary-040-color);
390 - }
391 -
392 - &.highlight {
393 - box-shadow: 0px 0px 0px 1px var(--primary-color);
394 - }
395 -}
396 -</style>
frontend/src/components/incidentManagement/cases/CaseOverview.vue
+24 -24
@@ -1,9 +1,9 @@
1 <template>
2 - <n-spin :show="loading" class="flex flex-col grow" content-class="flex flex-col grow">
3 - <div class="flex flex-col gap-4 grow justify-between">
2 + <n-spin :show="loading" class="flex grow flex-col" content-class="flex flex-col grow">
3 + <div class="flex grow flex-col justify-between gap-4">
4 <div class="content-box flex flex-col gap-4 py-3">
5 - <div class="px-7 flex sm:!flex-row flex-col gap-4">
6 - <KVCard
5 + <div class="flex flex-col gap-4 px-7 sm:!flex-row">
6 + <CardKV
7 :color="
8 caseData.case_status === 'OPEN'
9 ? 'danger'
@@ -14,10 +14,10 @@
14 : undefined
15 "
16 size="lg"
17 - class="grow w-full"
17 + class="w-full grow"
18 >
19 <template #key>
20 - <div class="flex gap-2 items-center">
20 + <div class="flex items-center gap-2">
21 <StatusIcon :status="caseData.case_status" />
22 <span>Status</span>
23 </div>
@@ -30,7 +30,7 @@
30 @updated="updateCase($event)"
31 >
32 <div
33 - class="flex gap-3 items-center"
33 + class="flex items-center gap-3"
34 :class="{
35 'cursor-not-allowed': loadingStatus,
36 'cursor-pointer': !loadingStatus
@@ -48,11 +48,11 @@
48 </CaseStatusSwitch>
49 </div>
50 </template>
51 - </KVCard>
51 + </CardKV>
52
53 - <KVCard :color="caseData.assigned_to ? 'success' : undefined" size="lg" class="grow w-full">
53 + <CardKV :color="caseData.assigned_to ? 'success' : undefined" size="lg" class="w-full grow">
54 <template #key>
55 - <div class="flex gap-2 items-center">
55 + <div class="flex items-center gap-2">
56 <AssigneeIcon :assignee="caseData.assigned_to" />
57 <span>Assigned to</span>
58 </div>
@@ -65,7 +65,7 @@
65 @updated="updateCase($event)"
66 >
67 <div
68 - class="flex gap-3 items-center"
68 + class="flex items-center gap-3"
69 :class="{
70 'cursor-not-allowed': loadingAssignee,
71 'cursor-pointer': !loadingAssignee
@@ -83,27 +83,27 @@
83 </CaseAssignUser>
84 </div>
85 </template>
86 - </KVCard>
86 + </CardKV>
87 </div>
88
89 <div class="px-7">
90 - <KVCard>
90 + <CardKV>
91 <template #key>description</template>
92 <template #value>
93 <span class="whitespace-pre-wrap">
94 {{ caseData.case_description ?? "-" }}
95 </span>
96 </template>
97 - </KVCard>
97 + </CardKV>
98 </div>
99
100 - <div class="px-7 grid gap-2 grid-auto-fit-250">
101 - <KVCard>
100 + <div class="grid-auto-fit-250 grid gap-2 px-7">
101 + <CardKV>
102 <template #key>id</template>
103 <template #value>#{{ caseData.id }}</template>
104 - </KVCard>
104 + </CardKV>
105
106 - <KVCard>
106 + <CardKV>
107 <template #key>creation time</template>
108 <template #value>
109 {{
@@ -112,14 +112,14 @@
112 : "-"
113 }}
114 </template>
115 - </KVCard>
115 + </CardKV>
116
117 - <KVCard>
117 + <CardKV>
118 <template #key>customer code</template>
119 <template #value>
120 <code
121 v-if="caseData.customer_code"
122 - class="cursor-pointer text-primary-color"
122 + class="text-primary cursor-pointer"
123 @click="gotoCustomer({ code: caseData.customer_code })"
124 >
125 {{ caseData.customer_code }}
@@ -127,11 +127,11 @@
127 </code>
128 <span v-else>-</span>
129 </template>
130 - </KVCard>
130 + </CardKV>
131 </div>
132 </div>
133
134 - <div class="footer-box px-7 py-4 gap-3 flex justify-end">
134 + <div class="footer-box flex justify-end gap-3 px-7 py-4">
135 <n-button type="error" secondary @click="handleDelete()">
136 <template #icon>
137 <Icon :name="TrashIcon" />
@@ -146,8 +146,8 @@
146
147 <script setup lang="ts">
148 import type { Case } from "@/types/incidentManagement/cases.d"
149 +import CardKV from "@/components/common/cards/CardKV.vue"
150 import Icon from "@/components/common/Icon.vue"
150 -import KVCard from "@/components/common/KVCard.vue"
151 import { useGoto } from "@/composables/useGoto"
152 import { useSettingsStore } from "@/stores/settings"
153 import { formatDate } from "@/utils"
frontend/src/components/incidentManagement/cases/CaseReportButton.vue
+1 -1
@@ -32,7 +32,7 @@
32 </n-input-group>
33 </n-form-item>
34
35 - <div class="flex justify-between gap-4 mt-8">
35 + <div class="mt-8 flex justify-between gap-4">
36 <n-button :disabled="exporting" @click="reset()">Reset</n-button>
37 <n-button
38 type="primary"
frontend/src/components/incidentManagement/cases/CaseReportTemplateManager.vue
+4 -4
@@ -1,8 +1,8 @@
1 <template>
2 - <n-spin :show="loading" class="flex flex-col grow min-h-48" content-class="flex flex-col grow gap-4">
2 + <n-spin :show="loading" class="flex min-h-48 grow flex-col" content-class="flex flex-col grow gap-4">
3 <div>
4 <n-collapse-transition :show="!showUploadForm">
5 - <div class="flex items-center gap-3 flex-wrap">
5 + <div class="flex flex-wrap items-center gap-3">
6 <n-button v-if="templateNameList.length" type="primary" @click="openUploadForm()">
7 <template #icon>
8 <Icon :name="UploadIcon" />
@@ -67,7 +67,7 @@
67 :key="templateName"
68 size="small"
69 class="overflow-hidden"
70 - content-class="flex justify-between items-center bg-secondary-color flex-wrap gap-4"
70 + content-class="flex justify-between items-center bg-secondary flex-wrap gap-4"
71 >
72 <div class="flex gap-3">
73 <n-tooltip to="body">
@@ -104,7 +104,7 @@
104 <n-empty v-if="!loading" class="min-h-48">
105 <div class="flex flex-col items-center gap-4">
106 <p>No templates found</p>
107 - <div class="flex items-center gap-3 flex-wrap">
107 + <div class="flex flex-wrap items-center gap-3">
108 <n-button type="primary" :loading="uploading" @click="openUploadForm()">
109 <template #icon>
110 <Icon :name="UploadIcon" />
frontend/src/components/incidentManagement/cases/CasesList.vue
+12 -21
@@ -1,10 +1,10 @@
1 <template>
2 <div class="cases-list">
3 <div ref="header" class="header flex items-center justify-end gap-2">
4 - <div class="info grow flex gap-2">
4 + <div class="info flex grow gap-2">
5 <n-popover overlap placement="left">
6 <template #trigger>
7 - <div class="bg-color border-radius">
7 + <div class="bg-default rounded-default">
8 <n-button size="small" class="!cursor-help">
9 <template #icon>
10 <Icon :name="InfoIcon"></Icon>
@@ -17,19 +17,19 @@
17 Total :
18 <code>{{ total }}</code>
19 </div>
20 - <div class="box text-error-color">
20 + <div class="box text-error">
21 Open :
22 <code>{{ statusOpenTotal }}</code>
23 </div>
24 - <div class="box text-warning-color">
24 + <div class="box text-warning">
25 In Progress :
26 <code>{{ statusInProgressTotal }}</code>
27 </div>
28 - <div class="box text-success-color">
28 + <div class="box text-success">
29 Close :
30 <code>{{ statusCloseTotal }}</code>
31 </div>
32 - <div class="box text-secondary-color">
32 + <div class="box text-secondary">
33 N/D :
34 <code>{{ statusUndefinedTotal }}</code>
35 </div>
@@ -38,7 +38,7 @@
38
39 <n-popover v-if="showMobileMenu" overlap placement="left" display-directive="show">
40 <template #trigger>
41 - <div class="bg-color border-radius">
41 + <div class="bg-default rounded-default">
42 <n-button size="small" class="!cursor-pointer">
43 <template #icon>
44 <Icon :name="MenuIcon"></Icon>
@@ -72,7 +72,7 @@
72 />
73 <n-popover v-if="!hideFilters" :show="showFilters" trigger="manual" overlap placement="right" class="!px-0">
74 <template #trigger>
75 - <div class="bg-color border-radius">
75 + <div class="bg-default rounded-default">
76 <n-badge :show="filtered" dot type="success" :offset="[-4, 0]">
77 <n-button size="small" @click="showFilters = true">
78 <template #icon>
@@ -82,7 +82,7 @@
82 </n-badge>
83 </div>
84 </template>
85 - <div class="py-1 flex flex-col gap-2">
85 + <div class="flex flex-col gap-2 py-1">
86 <div class="px-3">
87 <n-input-group>
88 <n-select
@@ -132,7 +132,7 @@
132 />
133 </n-input-group>
134 </div>
135 - <div class="px-3 flex justify-between gap-2">
135 + <div class="flex justify-between gap-2 px-3">
136 <div class="flex justify-start gap-2">
137 <n-button size="small" quaternary @click="showFilters = false">Close</n-button>
138 </div>
@@ -147,7 +147,7 @@
147 </n-popover>
148 </div>
149 <n-spin :show="loading">
150 - <div class="list flex flex-col gap-2 my-3">
150 + <div class="my-3 flex min-h-52 flex-col gap-2">
151 <template v-if="casesList.length">
152 <CaseItem
153 v-for="item of itemsPaginated"
@@ -162,7 +162,7 @@
162 />
163 </template>
164 <template v-else>
165 - <n-empty v-if="!loading" description="No items found" class="justify-center h-48" />
165 + <n-empty v-if="!loading" description="No items found" class="h-48 justify-center" />
166 </template>
167 </div>
168 </n-spin>
@@ -430,12 +430,3 @@ onBeforeMount(() => {
430 getCustomers()
431 })
432 </script>
433 -
434 -<style lang="scss" scoped>
435 -.cases-list {
436 - .list {
437 - container-type: inline-size;
438 - min-height: 200px;
439 - }
440 -}
441 -</style>
frontend/src/components/incidentManagement/sources/ConfiguredSourceItem.vue
+11 -40
@@ -1,10 +1,10 @@
1 <template>
2 - <n-spin :show="canceling">
3 - <div class="item flex flex-col gap-2 px-5 py-3" @click="openConfiguredSource()">
4 - <div class="header-box flex justify-between">
2 + <div>
3 + <CardEntity :loading="canceling" hoverable clickable @click.stop="openConfiguredSource()">
4 + <template #default>
5 {{ source }}
6 - </div>
7 - <div class="footer-box flex justify-end">
6 + </template>
7 + <template #footerExtra>
8 <n-popconfirm
9 v-model:show="showConfirm"
10 trigger="manual"
@@ -12,12 +12,12 @@
12 @clickoutside="showConfirm = false"
13 >
14 <template #trigger>
15 - <div class="delete-btn" @click.stop="showConfirm = true">delete</div>
15 + <n-button quaternary size="tiny" @click.stop="showConfirm = true">delete</n-button>
16 </template>
17 Are you sure you want to delete the source configuration?
18 </n-popconfirm>
19 - </div>
20 - </div>
19 + </template>
20 + </CardEntity>
21
22 <n-modal
23 v-model:show="showDetails"
@@ -30,13 +30,14 @@
30 >
31 <SourceConfigurationDetails :source />
32 </n-modal>
33 - </n-spin>
33 + </div>
34 </template>
35
36 <script setup lang="ts">
37 import type { SourceName } from "@/types/incidentManagement/sources.d"
38 import Api from "@/api"
39 -import { NModal, NPopconfirm, NSpin, useMessage } from "naive-ui"
39 +import CardEntity from "@/components/common/cards/CardEntity.vue"
40 +import { NButton, NModal, NPopconfirm, useMessage } from "naive-ui"
41 import { ref } from "vue"
42 import SourceConfigurationDetails from "./SourceConfigurationDetails.vue"
43
@@ -76,33 +77,3 @@ function openConfiguredSource() {
77 showDetails.value = true
78 }
79 </script>
79 -
80 -<style lang="scss" scoped>
81 -.item {
82 - border-radius: var(--border-radius);
83 - background-color: var(--bg-color);
84 - transition: all 0.2s var(--bezier-ease);
85 - border: var(--border-small-050);
86 - cursor: pointer;
87 -
88 - .header-box {
89 - font-family: var(--font-family-mono);
90 - }
91 - .footer-box {
92 - font-family: var(--font-family-mono);
93 - text-align: right;
94 - font-size: 12px;
95 - color: var(--fg-secondary-color);
96 -
97 - .delete-btn {
98 - &:hover {
99 - color: var(--error-color);
100 - }
101 - }
102 - }
103 -
104 - &:hover {
105 - box-shadow: 0px 0px 0px 1px inset var(--primary-color);
106 - }
107 -}
108 -</style>
frontend/src/components/incidentManagement/sources/ConfiguredSourcesList.vue
+6 -6
@@ -1,10 +1,10 @@
1 <template>
2 <div class="configured-sources-list">
3 - <div class="header flex items-center justify-end gap-2 mb-3">
4 - <div class="info grow flex gap-5">
3 + <div class="header mb-3 flex items-center justify-end gap-2">
4 + <div class="info flex grow gap-5">
5 <n-popover overlap placement="bottom-start">
6 <template #trigger>
7 - <div class="bg-color border-radius">
7 + <div class="bg-default rounded-default">
8 <n-button size="small" class="!cursor-help">
9 <template #icon>
10 <Icon :name="InfoIcon"></Icon>
@@ -20,7 +20,7 @@
20 </div>
21 </n-popover>
22 </div>
23 - <div class="actions flex gap-2 items-center">
23 + <div class="actions flex items-center gap-2">
24 <n-button size="small" type="primary" @click="showWizard = true">
25 <template #icon>
26 <Icon :name="NewSourceConfigurationIcon" :size="15"></Icon>
@@ -30,7 +30,7 @@
30 </div>
31 </div>
32 <n-spin :show="loading" class="min-h-32">
33 - <div v-if="configuredSourcesList.length" class="list gap-4 grid grid-auto-fill-250">
33 + <div v-if="configuredSourcesList.length" class="list grid-auto-fill-250 grid gap-4">
34 <ConfiguredSourceItem
35 v-for="source of configuredSourcesList"
36 :key="source"
@@ -40,7 +40,7 @@
40 />
41 </div>
42 <template v-else>
43 - <n-empty v-if="!loading" description="No items found" class="justify-center h-48" />
43 + <n-empty v-if="!loading" description="No items found" class="h-48 justify-center" />
44 </template>
45 </n-spin>
46
frontend/src/components/incidentManagement/sources/SourceConfigurationDetails.vue
+1 -1
@@ -2,7 +2,7 @@
2 <n-spin :show="loading || submitting" class="min-h-20">
3 <SourceConfigurationViewer v-if="sourceConfiguration" v-show="!editing" :source-configuration />
4
5 - <div v-if="!editing && !loading" class="flex gap-2 justify-end items-center mt-4">
5 + <div v-if="!editing && !loading" class="mt-4 flex items-center justify-end gap-2">
6 <n-button @click="setEditMode()">
7 <template #icon>
8 <Icon :name="EditIcon" :size="16"></Icon>
frontend/src/components/incidentManagement/sources/SourceConfigurationForm.vue
+2 -2
@@ -17,7 +17,7 @@
17 </n-form-item>
18 <n-form-item v-if="showSourceField" path="source" :show-require-mark="false" class="source-field">
19 <template #label>
20 - <div class="flex justify-between items-end gap-2">
20 + <div class="flex items-end justify-between gap-2">
21 <span>
22 Source
23 <span class="n-form-item-label__asterisk">*</span>
@@ -108,7 +108,7 @@
108 <div>
109 <slot name="additionalActions"></slot>
110 </div>
111 - <div class="flex gap-3 items-center">
111 + <div class="flex items-center gap-3">
112 <n-button :disabled="loading" @click="reset()">Reset</n-button>
113 <n-button
114 type="primary"
frontend/src/components/incidentManagement/sources/SourceConfigurationViewer.vue
+11 -11
@@ -1,12 +1,12 @@
1 <template>
2 <div v-if="sourceConfiguration" class="flex flex-col gap-3">
3 - <KVCard v-if="showSource">
3 + <CardKV v-if="showSource">
4 <template #key>Source</template>
5 <template #value>
6 {{ sourceConfiguration.source }}
7 </template>
8 - </KVCard>
9 - <KVCard>
8 + </CardKV>
9 + <CardKV>
10 <template #key>Field names</template>
11 <template #value>
12 <div class="flex flex-wrap gap-2">
@@ -17,32 +17,32 @@
17 </Badge>
18 </div>
19 </template>
20 - </KVCard>
21 - <KVCard>
20 + </CardKV>
21 + <CardKV>
22 <template #key>Asset name</template>
23 <template #value>
24 {{ sourceConfiguration.asset_name }}
25 </template>
26 - </KVCard>
27 - <KVCard>
26 + </CardKV>
27 + <CardKV>
28 <template #key>Timefield name</template>
29 <template #value>
30 {{ sourceConfiguration.timefield_name }}
31 </template>
32 - </KVCard>
33 - <KVCard>
32 + </CardKV>
33 + <CardKV>
34 <template #key>Alert title name</template>
35 <template #value>
36 {{ sourceConfiguration.alert_title_name }}
37 </template>
38 - </KVCard>
38 + </CardKV>
39 </div>
40 </template>
41
42 <script setup lang="ts">
43 import type { SourceConfiguration } from "@/types/incidentManagement/sources.d"
44 import Badge from "@/components/common/Badge.vue"
45 -import KVCard from "@/components/common/KVCard.vue"
45 +import CardKV from "@/components/common/cards/CardKV.vue"
46
47 const { sourceConfiguration, showSource } = defineProps<{
48 sourceConfiguration: SourceConfiguration
frontend/src/components/incidentManagement/sources/SourceConfigurationWizard.vue
+5 -5
@@ -1,7 +1,7 @@
1 <template>
2 <n-spin :show="loading" class="source-configuration-wizard">
3 <div class="wrapper flex flex-col">
4 - <div class="grow flex flex-col">
4 + <div class="flex grow flex-col">
5 <n-scrollbar x-scrollable trigger="none">
6 <div class="p-7 pt-4">
7 <n-steps :current="current" size="small" :status="currentStatus">
@@ -11,9 +11,9 @@
11 </div>
12 </n-scrollbar>
13
14 - <div class="mt-4 grow flex flex-col">
14 + <div class="mt-4 flex grow flex-col">
15 <Transition :name="`slide-form-${slideFormDirection}`">
16 - <div v-if="current === 1" class="px-7 flex flex-col gap-4">
16 + <div v-if="current === 1" class="flex flex-col gap-4 px-7">
17 <n-select
18 v-model:value="selectedIndex"
19 placeholder="Indices list"
@@ -25,7 +25,7 @@
25 @update:value="setSourceConfiguration(selectedIndex)"
26 ></n-select>
27
28 - <div class="flex gap-4 justify-end">
28 + <div class="flex justify-end gap-4">
29 <n-button
30 v-if="isNextStepEnabled"
31 icon-placement="right"
@@ -40,7 +40,7 @@
40 </div>
41 </div>
42
43 - <div v-else-if="current === 2" class="px-7 grow flex flex-col pb-7" style="min-height: 401px">
43 + <div v-else-if="current === 2" class="flex grow flex-col px-7 pb-7" style="min-height: 401px">
44 <SourceConfigurationForm
45 v-if="sourceConfigurationModel"
46 :source-configuration-model
frontend/src/components/indices/ClusterHealth.vue
+4 -4
@@ -1,7 +1,7 @@
1 <template>
2 <n-card class="cluster-health" segmented>
3 <template #header>
4 - <div class="flex align-center justify-between">
4 + <div class="align-center flex justify-between">
5 <span>Overall Health</span>
6 <IndexIcon v-if="cluster" :health="cluster.status" color />
7 </div>
@@ -12,7 +12,7 @@
12 <div class="card-wrap">
13 <div v-for="prop of propsOrder" :key="prop" class="box">
14 <template v-if="prop === 'status'">
15 - <div class="value uppercase flex align-center gap-2">
15 + <div class="value align-center flex gap-2 uppercase">
16 <IndexIcon :health="cluster.status" color />
17 {{ cluster.status }}
18 </div>
@@ -30,7 +30,7 @@
30 </n-scrollbar>
31 </div>
32 <template v-else>
33 - <n-empty v-if="!loading" description="No cluster found" class="justify-center h-48" />
33 + <n-empty v-if="!loading" description="No cluster found" class="h-48 justify-center" />
34 </template>
35 </n-spin>
36 </n-card>
@@ -110,7 +110,7 @@ onBeforeMount(() => {
110 min-height: 50px;
111
112 .card-wrap {
113 - @apply py-3 px-4 gap-6 gap-x-6;
113 + @apply gap-6 gap-x-6 px-4 py-3;
114 column-width: 12rem;
115 column-count: auto;
116
frontend/src/components/indices/IndexCard.vue
+48 -52
@@ -1,72 +1,71 @@
1 <template>
2 - <div class="index-card" :class="[`health-${index.health}`]">
3 - <n-spin :show="loading">
4 - <div class="wrapper">
5 - <div class="group">
6 - <div class="box">
7 - <div class="value">
8 - {{ index.index }}
9 - </div>
10 - <div class="label">name</div>
2 + <CardEntity class="index-card" :loading :class="[`health-${index.health}`]">
3 + <div class="wrapper">
4 + <div class="group">
5 + <div class="box">
6 + <div class="value">
7 + {{ index.index }}
8 </div>
12 - <div class="box">
13 - <div class="value uppercase flex align-center gap-2">
14 - <IndexIcon :health="index.health" color />
15 - {{ index.health }}
16 - </div>
17 - <div class="label">health</div>
9 + <div class="label">name</div>
10 + </div>
11 + <div class="box">
12 + <div class="value align-center flex gap-2 uppercase">
13 + <IndexIcon :health="index.health" color />
14 + {{ index.health }}
15 </div>
16 + <div class="label">health</div>
17 </div>
20 - <div class="group">
21 - <div class="box">
22 - <div class="value">
23 - {{ index.store_size }}
24 - </div>
25 - <div class="label">store_size</div>
18 + </div>
19 + <div class="group">
20 + <div class="box">
21 + <div class="value">
22 + {{ index.store_size }}
23 </div>
27 - <div class="box">
28 - <div class="value">
29 - {{ index.docs_count }}
30 - </div>
31 - <div class="label">docs_count</div>
24 + <div class="label">store_size</div>
25 + </div>
26 + <div class="box">
27 + <div class="value">
28 + {{ index.docs_count }}
29 </div>
33 - <div class="box">
34 - <div class="value">
35 - {{ index.replica_count }}
36 - </div>
37 - <div class="label">replica_count</div>
30 + <div class="label">docs_count</div>
31 + </div>
32 + <div class="box">
33 + <div class="value">
34 + {{ index.replica_count }}
35 </div>
36 + <div class="label">replica_count</div>
37 </div>
40 - <div v-if="showActions" class="group actions">
41 - <div class="box">
42 - <!--
38 + </div>
39 + <div v-if="showActions" class="actions group">
40 + <div class="box">
41 + <!--
42 <el-tooltip content="Rotate" placement="top" :show-arrow="false">
43 <el-button type="primary" :icon="RefreshIcon" circle />
44 </el-tooltip>
45 -->
47 - <n-tooltip content="Delete">
48 - Delete
49 - <template #trigger>
50 - <n-button quaternary circle type="error" @click.stop="handleDelete">
51 - <template #icon>
52 - <Icon :name="DeleteIcon"></Icon>
53 - </template>
54 - </n-button>
55 - </template>
56 - </n-tooltip>
57 - </div>
46 + <n-tooltip content="Delete">
47 + Delete
48 + <template #trigger>
49 + <n-button quaternary circle type="error" @click.stop="handleDelete">
50 + <template #icon>
51 + <Icon :name="DeleteIcon"></Icon>
52 + </template>
53 + </n-button>
54 + </template>
55 + </n-tooltip>
56 </div>
57 </div>
60 - </n-spin>
61 - </div>
58 + </div>
59 + </CardEntity>
60 </template>
61
62 <script setup lang="ts">
63 import type { IndexStats } from "@/types/indices.d"
64 import Api from "@/api"
65 +import CardEntity from "@/components/common/cards/CardEntity.vue"
66 import Icon from "@/components/common/Icon.vue"
67 import IndexIcon from "@/components/indices/IndexIcon.vue"
69 -import { NButton, NSpin, NTooltip, useDialog, useMessage } from "naive-ui"
68 +import { NButton, NTooltip, useDialog, useMessage } from "naive-ui"
69 import { h, ref, toRefs } from "vue"
70
71 const props = defineProps<{
@@ -138,10 +137,6 @@ function deleteIndex() {
137
138 <style lang="scss" scoped>
139 .index-card {
141 - @apply py-3 px-4 gap-6;
142 - border: 2px solid transparent;
143 - border-radius: var(--border-radius);
144 -
140 .wrapper {
141 display: flex;
142 justify-content: space-between;
@@ -174,6 +169,7 @@ function deleteIndex() {
169 }
170 }
171 }
172 +
173 &.health-green {
174 border-color: var(--success-color);
175 }
frontend/src/components/indices/NodeAllocation.vue
+5 -5
@@ -1,9 +1,9 @@
1 <template>
2 <n-card class="cluster-health" segmented>
3 <template #header>
4 - <div class="flex align-center justify-between">
4 + <div class="align-center flex justify-between">
5 <span>Nodes Allocation</span>
6 - <span v-if="indicesAllocation.length" class="text-secondary-color font-mono">
6 + <span v-if="indicesAllocation.length" class="text-secondary font-mono">
7 {{ indicesAllocation.length }}
8 </span>
9 </div>
@@ -46,7 +46,7 @@
46 <div class="label">disk_available</div>
47 </div>
48 </div>
49 - <div v-if="node.disk_percent" class="group disk-percent">
49 + <div v-if="node.disk_percent" class="disk-percent group">
50 <div class="box w-full">
51 <n-progress
52 type="line"
@@ -62,7 +62,7 @@
62 </n-scrollbar>
63 </template>
64 <template v-else>
65 - <n-empty v-if="!loading" description="No allocations found" class="justify-center h-48" />
65 + <n-empty v-if="!loading" description="No allocations found" class="h-48 justify-center" />
66 </template>
67 </div>
68 </n-spin>
@@ -138,7 +138,7 @@ onBeforeMount(() => {
138 overflow: hidden;
139
140 .group {
141 - @apply py-3 px-4;
141 + @apply px-4 py-3;
142 @apply gap-6;
143 display: flex;
144 justify-content: space-between;
frontend/src/components/indices/UnhealthyIndices.vue
+2 -2
@@ -1,9 +1,9 @@
1 <template>
2 <n-card class="unhealthy-indices" segmented>
3 <template #header>
4 - <div class="flex align-center justify-between">
4 + <div class="align-center flex justify-between">
5 <span>Unhealthy Indices</span>
6 - <span class="text-secondary-color font-mono">{{ unhealthyIndices.length }}</span>
6 + <span class="text-secondary font-mono">{{ unhealthyIndices.length }}</span>
7 </div>
8 </template>
9 <n-spin :show="loading">
frontend/src/components/license/LicenseCheckoutResponse.vue
+2 -2
@@ -6,7 +6,7 @@
6 content-class="flex flex-col items-center gap-5"
7 >
8 <template v-if="type === 'success'">
9 - <Icon :name="CheckIcon" class="text-success-color" :size="100" />
9 + <Icon :name="CheckIcon" class="text-success" :size="100" />
10 <h1 class="text-center">Congratulations!</h1>
11 <p class="text-center">Your checkout was successful, and your license will be updated soon.</p>
12 <n-spin v-if="loadingLicense" :size="24" />
@@ -15,7 +15,7 @@
15 </h4>
16 </template>
17 <template v-if="type === 'error'">
18 - <Icon :name="ErrorIcon" class="text-error-color" :size="100"></Icon>
18 + <Icon :name="ErrorIcon" class="text-error" :size="100"></Icon>
19 <h1 class="text-center">Checkout canceled</h1>
20 </template>
21 <div>
frontend/src/components/license/LicenseCheckoutWizard.vue
+3 -3
@@ -1,6 +1,6 @@
1 <template>
2 <n-spin :show="loading" class="min-h-48">
3 - <n-empty v-if="errorMessage" :description="errorMessage" class="justify-center h-48">
3 + <n-empty v-if="errorMessage" :description="errorMessage" class="h-48 justify-center">
4 <template #icon>
5 <Icon :name="WarningIcon"></Icon>
6 </template>
@@ -14,7 +14,7 @@
14 :subscription="subscription"
15 selectable
16 embedded
17 - class="item-appear item-appear-bottom item-appear-005"
17 + class="item-appear item-appear-bottom item-appear-005 cursor-pointer"
18 @click="selectedSubscription = subscription"
19 />
20 </div>
@@ -22,7 +22,7 @@
22 <n-empty
23 v-if="!loading"
24 description="Congratulations, you have already unlocked all available features"
25 - class="justify-center h-48"
25 + class="h-48 justify-center"
26 >
27 <template #icon>
28 <Icon :name="CheckIcon"></Icon>
frontend/src/components/license/LicenseDetails.vue
+22 -22
@@ -1,9 +1,9 @@
1 <template>
2 <n-spin :show="loading" content-class=" grow flex flex-col" class="flex flex-col overflow-hidden">
3 <div v-if="license" class="flex flex-col gap-4">
4 - <KVCard v-if="!hideKey">
4 + <CardKV v-if="!hideKey">
5 <template #key>
6 - <span class="flex gap-3 items-center">
6 + <span class="flex items-center gap-3">
7 <Icon :name="KeyIcon" :size="14"></Icon>
8 <span>Key</span>
9 </span>
@@ -11,43 +11,43 @@
11 <template #value>
12 {{ license.key }}
13 </template>
14 - </KVCard>
15 - <KVCard v-if="!hideFeatures">
14 + </CardKV>
15 + <CardKV v-if="!hideFeatures">
16 <template #key>
17 - <span class="flex gap-3 items-center">
17 + <span class="flex items-center gap-3">
18 <Icon :name="FeaturesIcon" :size="14"></Icon>
19 <span>Features</span>
20 </span>
21 </template>
22 <template #value>
23 - <div v-if="features.length" class="grid gap-2 grid-auto-fit-200">
24 - <KVCard v-for="feature of features" :key="feature">
23 + <div v-if="features.length" class="grid-auto-fit-200 grid gap-2">
24 + <CardKV v-for="feature of features" :key="feature">
25 <template #value>
26 - <span class="flex gap-3 items-center">
27 - <Icon :name="CheckIcon" :size="14" class="text-primary-color"></Icon>
26 + <span class="flex items-center gap-3">
27 + <Icon :name="CheckIcon" :size="14" class="text-primary"></Icon>
28 <span>{{ feature }}</span>
29 </span>
30 </template>
31 - </KVCard>
31 + </CardKV>
32 </div>
33 <template v-else>No feature enabled</template>
34 </template>
35 - </KVCard>
36 - <KVCard>
35 + </CardKV>
36 + <CardKV>
37 <template #key>
38 - <span class="flex gap-3 items-center">
38 + <span class="flex items-center gap-3">
39 <Icon :name="ExpiresIcon" :size="14"></Icon>
40 <span>Expires</span>
41 </span>
42 </template>
43 <template #value>
44 {{ expiresText }}
45 - <span class="text-secondary-color">({{ periodText }})</span>
45 + <span class="text-secondary">({{ periodText }})</span>
46 </template>
47 - </KVCard>
48 - <KVCard>
47 + </CardKV>
48 + <CardKV>
49 <template #key>
50 - <span class="flex gap-3 items-center">
50 + <span class="flex items-center gap-3">
51 <Icon :name="CustomerIcon" :size="14"></Icon>
52 <span>Customer</span>
53 </span>
@@ -75,10 +75,10 @@
75 </Badge>
76 </div>
77 </template>
78 - </KVCard>
79 - <KVCard v-if="dockerCompose">
78 + </CardKV>
79 + <CardKV v-if="dockerCompose">
80 <template #key>
81 - <span class="flex gap-3 items-center">
81 + <span class="flex items-center gap-3">
82 <Icon :name="ConfigIcon" :size="14"></Icon>
83 <span>Docker Configuration</span>
84 </span>
@@ -88,7 +88,7 @@
88 <Markdown :source="dockerCompose" code-bg-transparent />
89 </Suspense>
90 </template>
91 - </KVCard>
91 + </CardKV>
92 </div>
93 </n-spin>
94 </template>
@@ -97,8 +97,8 @@
97 import type { License, LicenseFeatures } from "@/types/license.d"
98 import Api from "@/api"
99 import Badge from "@/components/common/Badge.vue"
100 +import CardKV from "@/components/common/cards/CardKV.vue"
101 import Icon from "@/components/common/Icon.vue"
101 -import KVCard from "@/components/common/KVCard.vue"
102 import { useSettingsStore } from "@/stores/settings"
103 import { formatDate } from "@/utils"
104 import _startCase from "lodash/startCase"
frontend/src/components/license/LicenseFeatures.vue
+3 -3
@@ -2,8 +2,8 @@
2 <div class="license-features" :class="{ loading }">
3 <div class="license-features-box flex items-center justify-center">
4 <n-spin :show="loading" class="h-full w-full" content-class="h-full">
5 - <div v-if="!loading" class="wrapper h-full flex flex-col gap-4">
6 - <div class="flex justify-between items-center gap-4">
5 + <div v-if="!loading" class="wrapper flex h-full flex-col gap-4">
6 + <div class="flex items-center justify-between gap-4">
7 <h3>
8 {{ features.length ? "Your features" : "Unlock features" }}
9 </h3>
@@ -29,7 +29,7 @@
29 @deleted="load()"
30 />
31 </template>
32 - <n-empty v-else description="No features unlocked" class="justify-center h-48">
32 + <n-empty v-else description="No features unlocked" class="h-48 justify-center">
33 <template #icon>
34 <Icon :name="NoFeaturesIcon"></Icon>
35 </template>
frontend/src/components/license/LicenseViewer.vue
+1 -1
@@ -1,5 +1,5 @@
1 <template>
2 - <div class="license-viewer flex justify-center items-center gap-4" :class="{ 'has-side': !!key }">
2 + <div class="license-viewer flex items-center justify-center gap-4" :class="{ 'has-side': !!key }">
3 <div class="main-box">
4 <LicenseFeatures
5 :hide-key="!!key"
frontend/src/components/license/SubscriptionCard.vue
+45 -95
@@ -1,45 +1,49 @@
1 <template>
2 - <div
3 - class="license-subscription-feature-box"
4 - :class="{ embedded, disabled }"
5 - @click="selectable ? () => {} : (showDetails = true)"
6 - >
7 - <n-spin :show="canceling" content-class="px-4 py-3 flex flex-col gap-2">
8 - <div class="header-box flex justify-between items-center">
9 - <div class="flex items-center gap-2 cursor-pointer">
10 - <span>{{ subscription.name }}</span>
11 - <span v-if="selectable" class="info-btn pt-0.5" @click.stop="showDetails = true">
12 - <Icon :name="InfoIcon" :size="14"></Icon>
13 - </span>
14 - </div>
15 - <div class="price">
2 + <div>
3 + <CardEntity
4 + hoverable
5 + :embedded
6 + :disabled
7 + :clickable="!selectable"
8 + :loading="canceling"
9 + @click="selectable ? () => {} : (showDetails = true)"
10 + >
11 + <template #headerMain>{{ subscription.name }}</template>
12 + <template #headerExtra>
13 + <div class="text-primary">
14 {{ price(subscription.price) }}
15 </div>
18 - </div>
19 - <div v-if="!hideDetails" class="main-box flex items-center gap-3">
20 - <div class="content flex flex-col gap-2 grow">
21 - <div class="title">
22 - {{ subscription.info }}
23 - </div>
24 - <div class="description">
16 + </template>
17 + <template v-if="!hideDetails" #default>
18 + <div class="flex flex-col gap-1">
19 + {{ subscription.info }}
20 + <p class="text-sm">
21 {{ subscription.short_description }}
26 - </div>
27 - <div v-if="showDeleteOnCard && licenseData" class="flex items-center justify-end">
28 - <n-popconfirm @positive-click="cancelSubscription()">
29 - <template #trigger>
30 - <n-button text size="small" class="opacity-50">
31 - <template #icon>
32 - <Icon :name="DeleteIcon" :size="16"></Icon>
33 - </template>
34 - Unsubscribe
35 - </n-button>
36 - </template>
37 - {{ deleteMessage }}
38 - </n-popconfirm>
39 - </div>
22 + </p>
23 </div>
41 - </div>
42 - </n-spin>
24 + </template>
25 + <template v-if="showDeleteOnCard && licenseData" #footerMain>
26 + <n-popconfirm @positive-click="cancelSubscription()">
27 + <template #trigger>
28 + <n-button text size="small">
29 + <template #icon>
30 + <Icon :name="DeleteIcon" :size="16" />
31 + </template>
32 + Unsubscribe
33 + </n-button>
34 + </template>
35 + {{ deleteMessage }}
36 + </n-popconfirm>
37 + </template>
38 + <template v-if="selectable" #footerExtra>
39 + <n-button size="small" @click.stop="showDetails = true">
40 + <template #icon>
41 + <Icon :name="InfoIcon"></Icon>
42 + </template>
43 + Details
44 + </n-button>
45 + </template>
46 + </CardEntity>
47
48 <n-modal
49 v-model:show="showDetails"
@@ -50,10 +54,10 @@
54 content-class="flex flex-col"
55 segmented
56 >
53 - <n-spin :show="canceling" content-class="flex flex-col gap-4 grow" class="flex flex-col grow">
54 - <div class="flex gap-4 justify-between">
57 + <n-spin :show="canceling" content-class="flex flex-col gap-4 grow" class="flex grow flex-col">
58 + <div class="flex justify-between gap-4">
59 <div>{{ subscription.info }}</div>
56 - <div class="font-mono whitespace-nowrap text-primary-color">
60 + <div class="text-primary whitespace-nowrap font-mono">
61 {{ price(subscription.price) }}
62 </div>
63 </div>
@@ -82,6 +86,7 @@
86 import type { CancelSubscriptionPayload } from "@/api/endpoints/license"
87 import type { License, SubscriptionFeature } from "@/types/license.d"
88 import Api from "@/api"
89 +import CardEntity from "@/components/common/cards/CardEntity.vue"
90 import Icon from "@/components/common/Icon.vue"
91 import { price } from "@/utils"
92 import { NButton, NModal, NPopconfirm, NSpin, useMessage } from "naive-ui"
@@ -138,58 +143,3 @@ function cancelSubscription() {
143 })
144 }
145 </script>
141 -
142 -<style lang="scss" scoped>
143 -.license-subscription-feature-box {
144 - border-radius: var(--border-radius);
145 - background-color: var(--bg-color);
146 - border: var(--border-small-050);
147 - transition: all 0.2s var(--bezier-ease);
148 - cursor: pointer;
149 -
150 - .header-box {
151 - font-size: 13px;
152 - line-height: 1.25;
153 - .price {
154 - font-size: 15px;
155 - font-family: var(--font-family-mono);
156 - color: var(--primary-color);
157 - }
158 -
159 - .info-btn {
160 - &:hover {
161 - color: var(--primary-color);
162 - }
163 - }
164 - }
165 -
166 - .main-box {
167 - .content {
168 - word-break: break-word;
169 -
170 - .description {
171 - color: var(--fg-secondary-color);
172 - font-size: 13px;
173 - }
174 - }
175 - }
176 -
177 - &.embedded {
178 - background-color: var(--bg-secondary-color);
179 - }
180 -
181 - &.disabled {
182 - cursor: not-allowed;
183 -
184 - & > div {
185 - opacity: 0.5;
186 - }
187 - }
188 -
189 - &:not(.disabled) {
190 - &:hover {
191 - box-shadow: 0px 0px 0px 1px inset var(--primary-color);
192 - }
193 - }
194 -}
195 -</style>
frontend/src/components/license/bkp/LicenseCheckout.vue
+3 -3
@@ -1,7 +1,7 @@
1 <template>
2 - <div class="license-box flex gap-1 items-center justify-between">
2 + <div class="license-box flex items-center justify-between gap-1">
3 <div class="flex flex-col gap-1">
4 - <p class="flex gap-4 items-center">
4 + <p class="flex items-center gap-4">
5 <span>license</span>
6 <Icon v-if="loadingLicense" :name="LoadingIcon"></Icon>
7 </p>
@@ -11,7 +11,7 @@
11 </h3>
12 </div>
13
14 - <div v-if="!loadingLicense" class="actions-box flex gap-2 mr-2">
14 + <div v-if="!loadingLicense" class="actions-box mr-2 flex gap-2">
15 <n-button type="primary" @click="openCheckout()">
16 <template #icon>
17 <Icon :name="licenseKey ? ExtendIcon : LicenseIcon"></Icon>
frontend/src/components/license/bkp/LicenseEditor.vue
+8 -8
@@ -1,13 +1,13 @@
1 <template>
2 <n-spin :show="loading">
3 <div class="license-box" :class="{ loading: loadingLicense && !licenseKey }">
4 - <p v-if="loadingLicense || licenseKey" class="flex gap-4 items-center">
4 + <p v-if="loadingLicense || licenseKey" class="flex items-center gap-4">
5 <span>your license:</span>
6 <Icon v-if="loadingLicense" :name="LoadingIcon"></Icon>
7 </p>
8 <div v-if="!loadingLicense && !licenseKey">
9 - <p v-if="!creationEnabled" class="flex gap-4 items-center">no license found</p>
10 - <div class="flex items-center gap-4 mt-2">
9 + <p v-if="!creationEnabled" class="flex items-center gap-4">no license found</p>
10 + <div class="mt-2 flex items-center gap-4">
11 <div class="actions-box flex gap-2">
12 <n-button
13 v-if="!creationEnabled"
@@ -24,7 +24,7 @@
24 </div>
25 </div>
26 </div>
27 - <div v-if="!replaceEnabled && licenseKey" class="flex items-center gap-4 mt-1">
27 + <div v-if="!replaceEnabled && licenseKey" class="mt-1 flex items-center gap-4">
28 <h3>{{ licenseKey }}</h3>
29 <div class="actions-box flex gap-2">
30 <n-button secondary :disabled="replaceEnabled" size="small" @click="enableReplace()">
@@ -50,7 +50,7 @@
50 </div>
51
52 <div v-if="replaceEnabled" class="replace-box mt-2 flex gap-2">
53 - <n-input v-model:value="licenseKeyModel" class="grow !max-w-72" clearable />
53 + <n-input v-model:value="licenseKeyModel" class="!max-w-72 grow" clearable />
54 <n-button secondary :disabled="loadingReplace" @click="resetLicense()">Reset</n-button>
55 <n-button type="success" :loading="loadingReplace" :disabled="!licenseKeyModel" @click="replaceLicense()">
56 <template #icon>
@@ -61,7 +61,7 @@
61 </div>
62
63 <div v-if="extendEnabled" class="extend-box mt-5 flex gap-2">
64 - <n-input-number v-model:value="period" class="grow !max-w-44" :min="1">
64 + <n-input-number v-model:value="period" class="!max-w-44 grow" :min="1">
65 <template #prefix>
66 <div class="min-w-12">Day{{ period === 1 ? "" : "s" }}</div>
67 </template>
@@ -77,7 +77,7 @@
77
78 <div v-if="creationEnabled" class="create-box flex flex-col gap-2">
79 <n-form ref="formRef" :label-width="80" :model="creationForm" :rules="rules">
80 - <div class="grid gap-2 grid-auto-fit-200">
80 + <div class="grid-auto-fit-200 grid gap-2">
81 <n-form-item label="Name" path="name">
82 <n-input v-model:value.trim="creationForm.name" placeholder="Input name..." clearable />
83 </n-form-item>
@@ -93,7 +93,7 @@
93 </n-form-item>
94 </div>
95 </n-form>
96 - <div class="flex gap-2 justify-end">
96 + <div class="flex justify-end gap-2">
97 <n-button secondary :disabled="loadingCreation" @click="resetCreation()">Reset</n-button>
98 <n-button
99 type="success"
frontend/src/components/logs/LogItem.vue
+83 -125
@@ -1,68 +1,70 @@
1 <template>
2 - <div class="log-item flex flex-col gap-2 px-5 py-3" :class="`type-${eventTypeLower}`">
3 - <div class="header-box flex justify-end">
4 - <div class="time">
5 - {{ formatDate(log.timestamp) }}
6 - </div>
7 - </div>
8 - <div class="main-box flex justify-between gap-4">
9 - <div class="content flex flex-col gap-2">
10 - <div class="resource flex flex-wrap gap-3">
11 - <div class="status" :class="`cat-${statusCategory}`">
12 - <code>{{ log.status_code }}</code>
13 - </div>
14 - <div class="method" :class="methodLower">
15 - <strong>{{ log.method }}</strong>
2 + <CardEntity>
3 + <template #headerExtra>{{ formatDate(log.timestamp) }}</template>
4 + <template #default>
5 + <div class="flex flex-col gap-2">
6 + <CardEntity
7 + :embedded="eventTypeLower !== 'error'"
8 + :status="eventTypeLower === 'error' ? 'error' : undefined"
9 + >
10 + <div class="flex flex-wrap gap-3 font-mono">
11 + <div :class="`status-cat-${statusCategory}`">
12 + <code>{{ log.status_code }}</code>
13 + </div>
14 + <div :class="`method-${methodLower}`">
15 + <strong>{{ log.method }}</strong>
16 + </div>
17 + <div class="text-sm">
18 + {{ log.route }}
19 + </div>
20 </div>
17 - <div class="route">
18 - {{ log.route }}
19 - </div>
20 - </div>
21 - <div class="title px-1">
21 + </CardEntity>
22 + <div class="flex flex-col gap-1 px-1">
23 {{ log.message }}
23 - </div>
24 - <div v-if="log.additional_info" class="description px-1">
25 - {{ log.additional_info }}
26 - </div>
24
28 - <div class="badges-box flex flex-wrap items-center gap-3 mt-2">
29 - <Badge type="splitted" :color="log.event_type === LogEventType.ERROR ? 'danger' : 'primary'">
30 - <template #iconLeft>
31 - <Icon
32 - :name="log.event_type === LogEventType.ERROR ? ErrorIcon : InfoIcon"
33 - :size="14"
34 - ></Icon>
35 - </template>
36 - <template #label>Type</template>
37 - <template #value>
38 - {{ log.event_type }}
39 - </template>
40 - </Badge>
41 - <Badge v-if="log.user_id" type="splitted" color="primary">
42 - <template #iconLeft>
43 - <Icon :name="UserIcon" :size="14"></Icon>
44 - </template>
45 - <template #value>
46 - <span class="flex items-center gap-2">
47 - <span>#{{ log.user_id }}</span>
48 - <span v-if="username" class="flex gap-2">
49 - <span>/</span>
50 - <span>
51 - {{ username }}
52 - </span>
25 + <p v-if="log.additional_info">
26 + {{ log.additional_info }}
27 + </p>
28 + </div>
29 + </div>
30 + </template>
31 +
32 + <template #mainExtra>
33 + <div class="flex flex-wrap items-center gap-3">
34 + <Badge type="splitted" :color="eventTypeLower === LogEventType.ERROR ? 'danger' : 'primary'">
35 + <template #iconLeft>
36 + <Icon :name="eventTypeLower === LogEventType.ERROR ? ErrorIcon : InfoIcon" :size="14"></Icon>
37 + </template>
38 + <template #label>Type</template>
39 + <template #value>
40 + {{ log.event_type }}
41 + </template>
42 + </Badge>
43 + <Badge v-if="log.user_id" type="splitted" color="primary">
44 + <template #iconLeft>
45 + <Icon :name="UserIcon" :size="14"></Icon>
46 + </template>
47 + <template #value>
48 + <span class="flex items-center gap-2">
49 + <span>#{{ log.user_id }}</span>
50 + <span v-if="username" class="flex gap-2">
51 + <span>/</span>
52 + <span>
53 + {{ username }}
54 </span>
55 </span>
55 - </template>
56 - </Badge>
57 - </div>
56 + </span>
57 + </template>
58 + </Badge>
59 </div>
59 - </div>
60 - </div>
60 + </template>
61 + </CardEntity>
62 </template>
63
64 <script setup lang="ts">
65 import type { AuthUser } from "@/types/auth.d"
66 import Badge from "@/components/common/Badge.vue"
67 +import CardEntity from "@/components/common/cards/CardEntity.vue"
68 import Icon from "@/components/common/Icon.vue"
69 import { useSettingsStore } from "@/stores/settings"
70 import { type Log, LogEventType } from "@/types/logs.d"
@@ -77,7 +79,7 @@ const ErrorIcon = "majesticons:exclamation-line"
79
80 const dFormats = useSettingsStore().dateFormat
81
80 -const statusCategory = computed(() => log.status_code.toString()[0])
82 +const statusCategory = computed(() => log.status_code.toString()[0]?.toLowerCase())
83 const methodLower = computed(() => log.method.toLowerCase())
84 const eventTypeLower = computed(() => log.event_type.toLowerCase())
85 const username = computed(() => {
@@ -94,80 +96,36 @@ function formatDate(timestamp: string | number | Date, utc: boolean = true): str
96 </script>
97
98 <style lang="scss" scoped>
97 -.log-item {
98 - border-radius: var(--border-radius);
99 - background-color: var(--bg-color);
100 - border: var(--border-small-050);
101 -
102 - .header-box {
103 - font-family: var(--font-family-mono);
104 - font-size: 13px;
105 -
106 - .time {
107 - color: var(--fg-secondary-color);
108 - }
99 +.status {
100 + &-cat-2 {
101 + color: var(--success-color);
102 }
110 -
111 - .main-box {
112 - word-break: break-word;
113 -
114 - .resource {
115 - background-color: var(--bg-secondary-color);
116 - font-family: var(--font-family-mono);
117 - padding: 10px 12px;
118 - border-radius: var(--border-radius);
119 -
120 - .status {
121 - &.cat-2 {
122 - color: var(--success-color);
123 - }
124 - &.cat-3 {
125 - color: var(--success-color);
126 - }
127 - &.cat-4 {
128 - color: var(--warning-color);
129 - }
130 - &.cat-5 {
131 - color: var(--error-color);
132 - }
133 - }
134 -
135 - .method {
136 - color: var(--secondary1-color);
137 - &.option {
138 - color: var(--secondary3-color);
139 - }
140 - &.put {
141 - color: var(--secondary2-color);
142 - }
143 - &.post {
144 - color: var(--primary-color);
145 - }
146 - &.delete {
147 - color: var(--secondary4-color);
148 - }
149 - }
150 -
151 - .route {
152 - font-size: 14px;
153 - }
154 - }
155 -
156 - .description {
157 - color: var(--fg-secondary-color);
158 - font-size: 13px;
159 - }
103 + &-cat-3 {
104 + color: var(--success-color);
105 }
106 + &-cat-4 {
107 + color: var(--warning-color);
108 + }
109 + &-cat-5 {
110 + color: var(--error-color);
111 + }
112 +}
113
162 - &.type- {
163 - &error {
164 - border-color: var(--secondary4-opacity-010-color);
165 -
166 - .resource {
167 - background-color: var(--secondary4-opacity-005-color);
168 - border: 1px solid var(--secondary4-opacity-030-color);
169 - }
170 - }
114 +.method {
115 + &-get {
116 + color: var(--secondary1-color);
117 + }
118 + &-option {
119 + color: var(--secondary3-color);
120 + }
121 + &-put {
122 + color: var(--secondary2-color);
123 + }
124 + &-post {
125 + color: var(--primary-color);
126 + }
127 + &-delete {
128 + color: var(--secondary4-color);
129 }
130 }
131 </style>
frontend/src/components/logs/LogsFilters.vue
+4 -4
@@ -1,6 +1,6 @@
1 <template>
2 - <div class="py-1 flex flex-col gap-2">
3 - <div class="px-3 flex items-center justify-between gap-4">
2 + <div class="flex flex-col gap-2 py-1">
3 + <div class="flex items-center justify-between gap-4 px-3">
4 <small>Filter by:</small>
5 <n-select
6 v-model:value="filterType"
@@ -11,7 +11,7 @@
11 class="!w-24"
12 />
13 </div>
14 - <div class="px-3 !w-72">
14 + <div class="!w-72 px-3">
15 <div v-if="filterType === 'userId'" class="flex grow">
16 <n-select
17 v-if="userIdOptions.length"
@@ -48,7 +48,7 @@
48 <n-input-number v-model:value="filterTimeRange.time" :min="1" placeholder="Time" class="grow" />
49 </n-input-group>
50 </div>
51 - <div class="px-3 flex justify-end gap-2">
51 + <div class="flex justify-end gap-2 px-3">
52 <n-button size="small" secondary @click="close()">Close</n-button>
53 <n-button size="small" type="primary" secondary @click="submit()">Submit</n-button>
54 </div>
frontend/src/components/logs/LogsList.vue
+7 -16
@@ -1,10 +1,10 @@
1 <template>
2 <div class="logs-list">
3 <div ref="header" class="header flex items-center justify-end gap-2">
4 - <div class="info grow flex gap-2">
4 + <div class="info flex grow gap-2">
5 <n-popover overlap placement="bottom-start">
6 <template #trigger>
7 - <div class="bg-color border-radius">
7 + <div class="bg-default rounded-default">
8 <n-button size="small" class="!cursor-help">
9 <template #icon>
10 <Icon :name="InfoIcon"></Icon>
@@ -21,7 +21,7 @@
21 Event Info :
22 <code>{{ eventInfoTotal }}</code>
23 </div>
24 - <div class="box text-error-color">
24 + <div class="box text-error">
25 Event Error :
26 <code>{{ eventErrorTotal }}</code>
27 </div>
@@ -31,7 +31,7 @@
31 <n-button size="small" type="error" ghost :loading="loadingPurge" @click="showPurgeConfirm = true">
32 <div class="flex items-center gap-2">
33 <Icon :name="TrashIcon" :size="16"></Icon>
34 - <span class="hidden xs:block">Purge</span>
34 + <span class="xs:block hidden">Purge</span>
35 </div>
36 </n-button>
37 </div>
@@ -46,7 +46,7 @@
46 />
47 <n-popover :show="showFilters" trigger="manual" overlap placement="right" class="!px-0">
48 <template #trigger>
49 - <div class="bg-color border-radius">
49 + <div class="bg-default rounded-default">
50 <n-badge :show="filtered" dot type="success" :offset="[-4, 0]">
51 <n-button size="small" @click="showFilters = true">
52 <template #icon>
@@ -68,7 +68,7 @@
68 </n-popover>
69 </div>
70 <n-spin :show="loading">
71 - <div class="list flex flex-col gap-2 my-3">
71 + <div class="my-3 flex min-h-52 flex-col gap-2">
72 <template v-if="logsList.length">
73 <LogItem
74 v-for="log of itemsPaginated"
@@ -79,7 +79,7 @@
79 />
80 </template>
81 <template v-else>
82 - <n-empty v-if="!loading" description="No Logs found" class="justify-center h-48" />
82 + <n-empty v-if="!loading" description="No Logs found" class="h-48 justify-center" />
83 </template>
84 </div>
85 </n-spin>
@@ -283,12 +283,3 @@ onBeforeMount(() => {
283 getData()
284 })
285 </script>
286 -
287 -<style lang="scss" scoped>
288 -.logs-list {
289 - .list {
290 - container-type: inline-size;
291 - min-height: 200px;
292 - }
293 -}
294 -</style>
frontend/src/components/monitoringAlerts/Item.vue
+43 -116
@@ -1,78 +1,55 @@
1 <template>
2 - <n-spin :show="loading" :description="loadingDelete ? 'Deleting' : 'Invoking'">
3 - <div class="monitoring-alerts-item flex flex-col gap-2 px-5 py-3" :class="{ embedded }">
4 - <div class="header-box flex justify-between">
5 - <div class="id flex items-center">#{{ alert.id }}</div>
2 + <CardEntity :loading :loading-description="loadingDelete ? 'Deleting' : 'Invoking'" :embedded class="min-h-24">
3 + <template #header>#{{ alert.id }}</template>
4 + <template #default>
5 + {{ alert.alert_id }}
6 + </template>
7 + <template #mainExtra>
8 + <div class="flex flex-wrap items-center gap-3">
9 + <Badge type="active" class="cursor-pointer" @click.stop="gotoIndex(alert.alert_index)">
10 + <template #iconRight>
11 + <Icon :name="LinkIcon" :size="14"></Icon>
12 + </template>
13 + <template #label>Index / {{ alert.alert_index }}</template>
14 + </Badge>
15 +
16 + <Badge type="active" class="cursor-pointer" @click.stop="gotoCustomer({ code: alert.customer_code })">
17 + <template #iconRight>
18 + <Icon :name="LinkIcon" :size="14"></Icon>
19 + </template>
20 + <template #label>Customer #{{ alert.customer_code }}</template>
21 + </Badge>
22 +
23 + <Badge type="splitted" color="primary">
24 + <template #label>Source</template>
25 + <template #value>
26 + {{ alert.alert_source }}
27 + </template>
28 + </Badge>
29 </div>
7 - <div class="main-box flex items-center justify-between gap-4">
8 - <div class="content">
9 - <div class="title">
10 - {{ alert.alert_id }}
11 - </div>
12 -
13 - <div class="badges-box flex flex-wrap items-center gap-3 mt-4">
14 - <Badge type="active" class="cursor-pointer" @click="gotoIndex(alert.alert_index)">
15 - <template #iconRight>
16 - <Icon :name="LinkIcon" :size="14"></Icon>
17 - </template>
18 - <template #label>Index / {{ alert.alert_index }}</template>
19 - </Badge>
20 -
21 - <Badge
22 - type="active"
23 - class="cursor-pointer"
24 - @click="gotoCustomer({ code: alert.customer_code })"
25 - >
26 - <template #iconRight>
27 - <Icon :name="LinkIcon" :size="14"></Icon>
28 - </template>
29 - <template #label>Customer #{{ alert.customer_code }}</template>
30 - </Badge>
31 -
32 - <Badge type="splitted" color="primary">
33 - <template #label>Source</template>
34 - <template #value>
35 - {{ alert.alert_source }}
36 - </template>
37 - </Badge>
38 - </div>
39 - </div>
40 -
41 - <AlertActions
42 - class="actions-box"
43 - :alert="alert"
44 - @deleted="emit('deleted')"
45 - @invoked="emit('invoked')"
46 - @start-deleting="loadingDelete = true"
47 - @stop-deleting="loadingDelete = false"
48 - @start-invoking="loadingInvoke = true"
49 - @stop-invoking="loadingInvoke = false"
50 - />
51 - </div>
52 - <div class="footer-box flex justify-between items-center gap-3">
53 - <AlertActions
54 - class="actions-box !flex-row"
55 - :alert="alert"
56 - size="small"
57 - inline
58 - @deleted="emit('deleted')"
59 - @invoked="emit('invoked')"
60 - @start-deleting="loadingDelete = true"
61 - @stop-deleting="loadingDelete = false"
62 - @start-invoking="loadingInvoke = true"
63 - @stop-invoking="loadingInvoke = false"
64 - />
65 - </div>
66 - </div>
67 - </n-spin>
30 + </template>
31 + <template #footerExtra>
32 + <AlertActions
33 + class="flex flex-wrap gap-3"
34 + :alert="alert"
35 + size="small"
36 + @deleted="emit('deleted')"
37 + @invoked="emit('invoked')"
38 + @start-deleting="loadingDelete = true"
39 + @stop-deleting="loadingDelete = false"
40 + @start-invoking="loadingInvoke = true"
41 + @stop-invoking="loadingInvoke = false"
42 + />
43 + </template>
44 + </CardEntity>
45 </template>
46
47 <script setup lang="ts">
48 import type { MonitoringAlert } from "@/types/monitoringAlerts.d"
49 import Badge from "@/components/common/Badge.vue"
50 +import CardEntity from "@/components/common/cards/CardEntity.vue"
51 import Icon from "@/components/common/Icon.vue"
52 import { useGoto } from "@/composables/useGoto"
75 -import { NSpin } from "naive-ui"
53 import { computed, ref } from "vue"
54 import AlertActions from "./ItemActions.vue"
55
@@ -93,53 +70,3 @@ const loadingDelete = ref(false)
70 const loadingInvoke = ref(false)
71 const loading = computed(() => loadingDelete.value || loadingInvoke.value)
72 </script>
96 -
97 -<style lang="scss" scoped>
98 -.monitoring-alerts-item {
99 - border-top: var(--border-small-050);
100 - transition: all 0.2s var(--bezier-ease);
101 - min-height: 100px;
102 -
103 - .header-box {
104 - font-family: var(--font-family-mono);
105 - font-size: 13px;
106 - .id {
107 - word-break: break-word;
108 - color: var(--fg-secondary-color);
109 - line-height: 1.2;
110 - }
111 - }
112 -
113 - .main-box {
114 - word-break: break-word;
115 - }
116 -
117 - .footer-box {
118 - font-size: 13px;
119 - margin-top: 10px;
120 - display: none;
121 - }
122 -
123 - &:not(.embedded) {
124 - border-radius: var(--border-radius);
125 - background-color: var(--bg-color);
126 - border: var(--border-small-050);
127 -
128 - &:hover {
129 - border-color: var(--primary-color);
130 - }
131 - }
132 -
133 - @container (max-width: 550px) {
134 - .main-box {
135 - .actions-box {
136 - display: none;
137 - }
138 - }
139 -
140 - .footer-box {
141 - display: flex;
142 - }
143 - }
144 -}
145 -</style>
frontend/src/components/monitoringAlerts/ItemActions.vue
+4 -5
@@ -1,12 +1,12 @@
1 <template>
2 - <div class="alert-actions flex flex-col gap-3 justify-center" :class="{ '!flex-row': inline }">
3 - <n-button :loading="loadingInvoke" type="success" secondary :size="size" @click="invoke()">
2 + <div class="contents">
3 + <n-button :loading="loadingInvoke" type="success" secondary :size="size" @click.stop="invoke()">
4 <template #icon>
5 <Icon :name="InvokeIcon"></Icon>
6 </template>
7 Invoke
8 </n-button>
9 - <n-button :loading="loadingDelete" :size="size" type="error" secondary @click="handleDelete()">
9 + <n-button :loading="loadingDelete" :size="size" type="error" secondary @click.stop="handleDelete()">
10 <template #icon>
11 <Icon :name="DeleteIcon"></Icon>
12 </template>
@@ -23,10 +23,9 @@ import Icon from "@/components/common/Icon.vue"
23 import { NButton, useDialog, useMessage } from "naive-ui"
24 import { computed, ref, watch } from "vue"
25
26 -const { alert, size, inline } = defineProps<{
26 +const { alert, size } = defineProps<{
27 alert: MonitoringAlert
28 size?: Size
29 - inline?: boolean
29 }>()
30
31 const emit = defineEmits<{
frontend/src/components/monitoringAlerts/List.vue
+5 -14
@@ -1,10 +1,10 @@
1 <template>
2 <div class="monitoring-alerts-list">
3 <div ref="header" class="header flex items-center justify-end gap-2">
4 - <div class="info grow flex gap-2">
4 + <div class="info flex grow gap-2">
5 <n-popover overlap placement="bottom-start">
6 <template #trigger>
7 - <div class="bg-color border-radius">
7 + <div class="bg-default rounded-default">
8 <n-button size="small" class="!cursor-help">
9 <template #icon>
10 <Icon :name="InfoIcon"></Icon>
@@ -30,7 +30,7 @@
30 >
31 <div class="flex items-center gap-2">
32 <Icon :name="TrashIcon" :size="16"></Icon>
33 - <span class="hidden xs:block">Purge</span>
33 + <span class="xs:block hidden">Purge</span>
34 </div>
35 </n-button>
36 </div>
@@ -45,7 +45,7 @@
45 />
46 </div>
47 <n-spin :show="loading">
48 - <div class="list flex flex-col gap-2 my-3">
48 + <div class="my-3 flex min-h-52 flex-col gap-2">
49 <template v-if="monitoringAlerts.length">
50 <Alert
51 v-for="alert of itemsPaginated"
@@ -57,7 +57,7 @@
57 />
58 </template>
59 <template v-else>
60 - <n-empty v-if="!loading" description="No items found" class="justify-center h-48" />
60 + <n-empty v-if="!loading" description="No items found" class="h-48 justify-center" />
61 </template>
62 </div>
63 </n-spin>
@@ -180,12 +180,3 @@ onBeforeMount(() => {
180 getData()
181 })
182 </script>
183 -
184 -<style lang="scss" scoped>
185 -.monitoring-alerts-list {
186 - .list {
187 - container-type: inline-size;
188 - min-height: 200px;
189 - }
190 -}
191 -</style>
frontend/src/components/overview/AgentsCard.vue
+3 -3
@@ -1,6 +1,6 @@
1 <template>
2 <n-spin :show="loading">
3 - <CardStatsMulti title="Agents" hovered class="cursor-pointer h-full" :values @click="gotoAgent()">
3 + <CardStatsMulti title="Agents" hovered class="h-full cursor-pointer" :values @click="gotoAgent()">
4 <template #icon>
5 <CardStatsIcon :icon-name="AgentsIcon" boxed :box-size="30"></CardStatsIcon>
6 </template>
@@ -10,8 +10,8 @@
10
11 <script setup lang="ts">
12 import Api from "@/api"
13 -import CardStatsIcon from "@/components/common/CardStatsIcon.vue"
14 -import CardStatsMulti, { type ItemProps } from "@/components/common/CardStatsMulti.vue"
13 +import CardStatsIcon from "@/components/common/cards/CardStatsIcon.vue"
14 +import CardStatsMulti, { type ItemProps } from "@/components/common/cards/CardStatsMulti.vue"
15 import { useGoto } from "@/composables/useGoto"
16 import { type Agent, AgentStatus } from "@/types/agents.d"
17 import { NSpin, useMessage } from "naive-ui"
frontend/src/components/overview/CustomersCard.vue
+3 -3
@@ -3,7 +3,7 @@
3 <CardStatsMulti
4 title="Customers"
5 hovered
6 - class="cursor-pointer h-full"
6 + class="h-full cursor-pointer"
7 :values="[{ value: total, label: 'Total' }]"
8 @click="gotoCustomer()"
9 >
@@ -17,8 +17,8 @@
17 <script setup lang="ts">
18 import type { Customer } from "@/types/customers.d"
19 import Api from "@/api"
20 -import CardStatsIcon from "@/components/common/CardStatsIcon.vue"
21 -import CardStatsMulti from "@/components/common/CardStatsMulti.vue"
20 +import CardStatsIcon from "@/components/common/cards/CardStatsIcon.vue"
21 +import CardStatsMulti from "@/components/common/cards/CardStatsMulti.vue"
22 import { useGoto } from "@/composables/useGoto"
23 import { NSpin, useMessage } from "naive-ui"
24 import { computed, onBeforeMount, ref } from "vue"
frontend/src/components/overview/HealthcheckCard.vue
+3 -3
@@ -1,6 +1,6 @@
1 <template>
2 <n-spin :show="loading">
3 - <CardStatsMulti title="Healthcheck" hovered class="cursor-pointer h-full" :values @click="gotoHealthcheck()">
3 + <CardStatsMulti title="Healthcheck" hovered class="h-full cursor-pointer" :values @click="gotoHealthcheck()">
4 <template #icon>
5 <CardStatsIcon
6 :icon-name="HealthcheckIcon"
@@ -15,8 +15,8 @@
15
16 <script setup lang="ts">
17 import Api from "@/api"
18 -import CardStatsIcon from "@/components/common/CardStatsIcon.vue"
19 -import CardStatsMulti, { type ItemProps } from "@/components/common/CardStatsMulti.vue"
18 +import CardStatsIcon from "@/components/common/cards/CardStatsIcon.vue"
19 +import CardStatsMulti, { type ItemProps } from "@/components/common/cards/CardStatsMulti.vue"
20 import { useGoto } from "@/composables/useGoto"
21 import { useThemeStore } from "@/stores/theme"
22 import { type InfluxDBAlert, InfluxDBAlertLevel } from "@/types/healthchecks.d"
frontend/src/components/overview/IncidentAlerts.vue
+3 -3
@@ -3,7 +3,7 @@
3 <CardStatsBars
4 title="Alerts"
5 hovered
6 - class="cursor-pointer h-full"
6 + class="h-full cursor-pointer"
7 :values
8 @click="gotoIncidentManagementAlerts()"
9 >
@@ -16,8 +16,8 @@
16
17 <script setup lang="ts">
18 import Api from "@/api"
19 -import CardStatsBars, { type ItemProps } from "@/components/common/CardStatsBars.vue"
20 -import CardStatsIcon from "@/components/common/CardStatsIcon.vue"
19 +import CardStatsBars, { type ItemProps } from "@/components/common/cards/CardStatsBars.vue"
20 +import CardStatsIcon from "@/components/common/cards/CardStatsIcon.vue"
21 import { useGoto } from "@/composables/useGoto"
22 import { NSpin, useMessage } from "naive-ui"
23 import { computed, onBeforeMount, ref } from "vue"
frontend/src/components/overview/IncidentCases.vue
+3 -3
@@ -3,7 +3,7 @@
3 <CardStatsBars
4 title="Cases"
5 hovered
6 - class="cursor-pointer h-full"
6 + class="h-full cursor-pointer"
7 :values
8 @click="gotoIncidentManagementCases()"
9 >
@@ -17,8 +17,8 @@
17 <script setup lang="ts">
18 import type { Case } from "@/types/incidentManagement/cases"
19 import Api from "@/api"
20 -import CardStatsBars, { type ItemProps } from "@/components/common/CardStatsBars.vue"
21 -import CardStatsIcon from "@/components/common/CardStatsIcon.vue"
20 +import CardStatsBars, { type ItemProps } from "@/components/common/cards/CardStatsBars.vue"
21 +import CardStatsIcon from "@/components/common/cards/CardStatsIcon.vue"
22 import { useGoto } from "@/composables/useGoto"
23 import { NSpin, useMessage } from "naive-ui"
24 import { computed, onBeforeMount, ref } from "vue"
frontend/src/components/overview/SocAlertsCard.vue
+3 -3
@@ -5,7 +5,7 @@
5 :value="total"
6 :vertical="vertical"
7 hovered
8 - class="cursor-pointer h-full"
8 + class="h-full cursor-pointer"
9 @click="gotoSocAlerts()"
10 >
11 <template #icon>
@@ -18,8 +18,8 @@
18 <script setup lang="ts">
19 import type { SocAlert } from "@/types/soc/alert.d"
20 import Api from "@/api"
21 -import CardStats from "@/components/common/CardStats.vue"
22 -import CardStatsIcon from "@/components/common/CardStatsIcon.vue"
21 +import CardStats from "@/components/common/cards/CardStats.vue"
22 +import CardStatsIcon from "@/components/common/cards/CardStatsIcon.vue"
23 import { useGoto } from "@/composables/useGoto"
24 import { NSpin, useMessage } from "naive-ui"
25 import { computed, onBeforeMount, ref, toRefs } from "vue"
frontend/src/components/reportCreation/Panels.vue
+11 -13
@@ -1,7 +1,7 @@
1 <template>
2 - <n-spin v-model:show="loading" class="overflow-hidden h-full w-full" content-class="overflow-hidden h-full w-full">
3 - <div v-if="org" class="report-panels h-full w-full flex gap-2">
4 - <div class="panels-container grow h-full flex flex-col gap-4">
2 + <n-spin v-model:show="loading" class="h-full w-full overflow-hidden" content-class="overflow-hidden h-full w-full">
3 + <div v-if="org" class="report-panels flex h-full w-full gap-2">
4 + <div class="panels-container flex h-full grow flex-col gap-4">
5 <div class="rows-container">
6 <n-scrollbar style="max-height: 100%" trigger="none">
7 <div class="drag-wrapper">
@@ -29,7 +29,7 @@
29 },
30 pull: ['panels']
31 }"
32 - class="drop-panels-area flex gap-3 w-full h-full"
32 + class="drop-panels-area flex h-full w-full gap-3"
33 >
34 <template #header>
35 <div class="left-box flex justify-end">
@@ -58,10 +58,8 @@
58 </n-button>
59 </template>
60
61 - <div class="py-1 flex gap-3 items-center">
62 - <div class="text-secondary-color text-sm">
63 - Row height:
64 - </div>
61 + <div class="flex items-center gap-3 py-1">
62 + <div class="text-secondary text-sm">Row height:</div>
63 <n-switch
64 v-model:value="row.height"
65 size="small"
@@ -113,10 +111,10 @@
111 </div>
112 </n-scrollbar>
113 </div>
116 - <div class="toolbar pr-4 flex items-center justify-between gap-2">
114 + <div class="toolbar flex items-center justify-between gap-2 pr-4">
115 <n-button
116 v-if="dashboard || panelsReady"
119 - class="add-task-btn flex items-center justify-center !mt-0"
117 + class="add-task-btn !mt-0 flex items-center justify-center"
118 @click="addRow()"
119 >
120 <template #icon>
@@ -161,7 +159,7 @@
159 </draggable>
160 </div>
161 </n-scrollbar>
164 - <div v-else class="p-3 h-full">
162 + <div v-else class="h-full p-3">
163 <div class="empty-message p-3">
164 <div v-if="!dashboard">
165 Select a
@@ -503,14 +501,14 @@ onMounted(() => {
501 z-index: 0;
502 width: unset;
503 height: unset;
506 - @apply top-3 bottom-3 left-3 right-3;
504 + @apply bottom-3 left-3 right-3 top-3;
505 }
506
507 .drop-panels-area {
508 position: absolute;
509 width: unset;
510 height: unset;
513 - @apply top-3 bottom-3 left-3 right-3;
511 + @apply bottom-3 left-3 right-3 top-3;
512 }
513
514 .left-box {
frontend/src/components/reportCreation/PrintSettings.vue
+2 -2
@@ -1,9 +1,9 @@
1 <template>
2 <div class="flex flex-col gap-8">
3 - <div class="flex gap-6 mb-2">
3 + <div class="mb-2 flex gap-6">
4 <n-avatar :size="110" :src="logo" />
5
6 - <div class="flex flex-col justify-between grow">
6 + <div class="flex grow flex-col justify-between">
7 <ImageCropper v-slot="{ openCropper }" placeholder="Select a Logo" @crop="setCroppedImage">
8 <n-button @click="openCropper()">
9 <template #icon>
frontend/src/components/reportCreation/Wizard.vue
+1 -1
@@ -2,7 +2,7 @@
2 <div class="report-wizard">
3 <n-spin v-model:show="loading">
4 <n-form :label-width="80" class="flex flex-col gap-5" :show-feedback="false">
5 - <div class="flex gap-5 flex-col sm:flex-row">
5 + <div class="flex flex-col gap-5 sm:flex-row">
6 <n-form-item label="Time Range" class="sm:max-w-56">
7 <n-input-group>
8 <n-select
frontend/src/components/scheduler/Item.vue
+34 -92
@@ -1,10 +1,8 @@
1 <template>
2 - <div class="item flex flex-col gap-4 px-5 py-3">
3 - <div class="header-box flex justify-between gap-4">
4 - <div class="name">
5 - {{ job.id }}
6 - </div>
7 - <div class="time flex items-center gap-2">
2 + <CardEntity>
3 + <template #headerMain>{{ job.id }}</template>
4 + <template #headerExtra>
5 + <div class="flex items-center gap-2">
6 {{ formatDate(job.last_success, dFormats.datetimesec) }}
7
8 <n-tooltip>
@@ -14,46 +12,48 @@
12 Last success time
13 </n-tooltip>
14 </div>
17 - </div>
18 - <div class="main-box flex justify-between gap-4 items-center">
19 - <div class="content">
20 - <div class="title">
21 - {{ job.name }}
22 - </div>
23 - <div class="description mt-1">
24 - {{ job.description }}
25 - </div>
26 - <div class="badges-box flex flex-wrap items-center gap-3 mt-4">
27 - <Badge type="splitted" color="primary">
28 - <template #label>Interval</template>
29 - <template #value>
30 - {{ job.time_interval }} {{ job.time_interval === 1 ? "minute" : "minutes" }}
31 - </template>
32 - </Badge>
33 - </div>
34 - </div>
35 -
36 - <div class="actions-box">
37 - <JobActions :job="job" />
15 + </template>
16 +
17 + <template #default>
18 + {{ job.description }}
19 + </template>
20 +
21 + <template #footerMain>
22 + <div class="flex flex-wrap items-center gap-3">
23 + <Badge type="splitted" color="primary">
24 + <template #label>Interval</template>
25 + <template #value>
26 + {{ job.time_interval }} {{ job.time_interval === 1 ? "minute" : "minutes" }}
27 + </template>
28 + </Badge>
29 + <Badge v-if="job.enabled" type="splitted" color="primary">
30 + <template #label>Next run time</template>
31 + <template #value>
32 + <div class="hover:text-primary flex h-full cursor-help items-center">
33 + <NextJobTimeTooltip :job-id="job.id" />
34 + </div>
35 + </template>
36 + </Badge>
37 </div>
39 - </div>
40 - <div class="footer-box flex flex-col gap-4">
41 - <JobActions :job="job" size="small" inline />
42 - <div class="time w-full text-right">
43 - {{ formatDate(job.last_success, dFormats.datetimesec) }}
38 + </template>
39 + <template #footerExtra>
40 + <div class="flex flex-row flex-wrap gap-3">
41 + <JobActions :job="job" size="small" />
42 </div>
45 - </div>
46 - </div>
43 + </template>
44 + </CardEntity>
45 </template>
46
47 <script setup lang="ts">
48 import type { Job } from "@/types/scheduler.d"
49 import Badge from "@/components/common/Badge.vue"
50 +import CardEntity from "@/components/common/cards/CardEntity.vue"
51 import Icon from "@/components/common/Icon.vue"
52 import { useSettingsStore } from "@/stores/settings"
53 import { formatDate } from "@/utils"
54 import { NTooltip } from "naive-ui"
55 import JobActions from "./JobActions.vue"
56 +import NextJobTimeTooltip from "./NextJobTimeTooltip.vue"
57
58 const { job } = defineProps<{ job: Job }>()
59
@@ -61,61 +61,3 @@ const TimeIcon = "carbon:time"
61
62 const dFormats = useSettingsStore().dateFormat
63 </script>
64 -
65 -<style lang="scss" scoped>
66 -.item {
67 - border-radius: var(--border-radius);
68 - background-color: var(--bg-color);
69 - transition: all 0.2s var(--bezier-ease);
70 - border: var(--border-small-050);
71 -
72 - .header-box {
73 - font-size: 13px;
74 - font-family: var(--font-family-mono);
75 - word-break: break-word;
76 - color: var(--fg-secondary-color);
77 - }
78 - .main-box {
79 - .content {
80 - word-break: break-word;
81 -
82 - .description {
83 - color: var(--fg-secondary-color);
84 - font-size: 13px;
85 - }
86 - }
87 - }
88 -
89 - .footer-box {
90 - display: none;
91 - margin-top: 4px;
92 -
93 - .time {
94 - font-size: 13px;
95 - font-family: var(--font-family-mono);
96 - word-break: break-word;
97 - color: var(--fg-secondary-color);
98 - }
99 - }
100 -
101 - &:hover {
102 - box-shadow: 0px 0px 0px 1px inset var(--primary-color);
103 - }
104 -
105 - @container (max-width: 450px) {
106 - .header-box {
107 - .time {
108 - display: none;
109 - }
110 - }
111 - .main-box {
112 - .actions-box {
113 - display: none;
114 - }
115 - }
116 - .footer-box {
117 - display: flex;
118 - }
119 - }
120 -}
121 -</style>
frontend/src/components/scheduler/JobActions.vue
+7 -12
@@ -1,8 +1,8 @@
1 <template>
2 - <div class="job-actions flex flex-col gap-3" :class="{ '!flex-row': inline }">
3 - <div class="flex gap-3 items-center">
2 + <div class="contents gap-3">
3 + <div class="flex items-center gap-3">
4 <n-button
5 - :size="size"
5 + :size
6 :type="job.enabled ? 'warning' : 'success'"
7 secondary
8 :loading="loadingAction"
@@ -14,23 +14,19 @@
14 </template>
15 {{ job.enabled ? "Pause" : "Start" }}
16 </n-button>
17 -
18 - <NextTooltip v-if="job.enabled && !inline" :job-id="job.id" />
17 </div>
20 - <div class="flex gap-3 items-center">
21 - <n-button :size="size" type="success" secondary :loading="loadingRun" @click="run()">
18 + <div class="flex items-center gap-3">
19 + <n-button :size type="success" secondary :loading="loadingRun" @click="run()">
20 <template #icon>
21 <Icon :name="RunIcon"></Icon>
22 </template>
23 Run once
24 </n-button>
27 - <n-button :size="size" secondary :loading="loadingUpdate" @click="showForm = true">
25 + <n-button :size secondary :loading="loadingUpdate" @click="showForm = true">
26 <template #icon>
27 <Icon :name="UpdatedIcon"></Icon>
28 </template>
29 </n-button>
32 -
33 - <NextTooltip v-if="job.enabled && inline" :job-id="job.id" />
30 </div>
31 </div>
32
@@ -56,10 +52,9 @@ import Icon from "@/components/common/Icon.vue"
52 import { NButton, NModal, useMessage } from "naive-ui"
53 import { ref, toRefs } from "vue"
54 import JobForm from "./JobForm.vue"
59 -import NextTooltip from "./NextTooltip.vue"
55
56 const props = defineProps<{ job: Job; size?: Size; inline?: boolean }>()
62 -const { job, size, inline } = toRefs(props)
57 +const { job, size } = toRefs(props)
58
59 const StartIcon = "material-symbols:autoplay"
60 const PauseIcon = "carbon:pause-filled"
frontend/src/components/scheduler/JobForm.vue
+1 -1
@@ -12,7 +12,7 @@
12 />
13 </n-form-item>
14
15 - <div class="flex gap-3 justify-end items-center">
15 + <div class="flex items-center justify-end gap-3">
16 <n-button :disabled="loading" @click="reset()">Reset</n-button>
17 <n-button
18 type="primary"
frontend/src/components/scheduler/List.vue
+2 -9
@@ -1,12 +1,12 @@
1 <template>
2 <div class="scheduler-list">
3 <n-spin :show="loading" class="min-h-48">
4 - <div class="list">
4 + <div class="min-h-52">
5 <template v-if="jobs.length">
6 <JobCard v-for="job of jobs" :key="job.id" :job="job" class="mb-2" />
7 </template>
8 <template v-else>
9 - <n-empty v-if="!loading" description="No items found" class="justify-center h-48" />
9 + <n-empty v-if="!loading" description="No items found" class="h-48 justify-center" />
10 </template>
11 </div>
12 </n-spin>
@@ -49,10 +49,3 @@ onBeforeMount(() => {
49 getData()
50 })
51 </script>
52 -
53 -<style lang="scss" scoped>
54 -.list {
55 - container-type: inline-size;
56 - min-height: 200px;
57 -}
58 -</style>
frontend/src/components/scheduler/NextJobTimeTooltip.vue renamed
frontend/src/components/services/Item.vue
+29 -82
@@ -1,41 +1,39 @@
1 <template>
2 - <div class="service-item" :class="{ embedded, selectable, disabled }">
3 - <div class="px-4 py-3 flex flex-col gap-2">
4 - <div class="header-box flex justify-between items-center">
5 - <div class="flex items-center gap-2 cursor-pointer">
2 + <div>
3 + <CardEntity :embedded :clickable="selectable" :disabled hoverable>
4 + <template #default>
5 + <div class="flex items-center gap-3">
6 <div v-if="selectable" class="check-box mr-2">
7 <n-radio v-model:checked="checked" size="large" />
8 </div>
9 - <div class="id">#{{ data.id }}</div>
10 - </div>
11 - <div class="actions">
12 - <n-button size="small" @click.stop="showDetails = true">
13 - <template #icon>
14 - <Icon :name="InfoIcon"></Icon>
15 - </template>
16 - </n-button>
17 - </div>
18 - </div>
19 - <div class="main-box flex items-center gap-3">
20 - <div class="content flex flex-col gap-1 grow">
21 - <div class="title">
9 + <div class="flex flex-col gap-1">
10 {{ data.name }}
23 - </div>
24 - <div class="description">
25 - {{ data.description }}
11 + <p>
12 + {{ data.description }}
13 + </p>
14 </div>
15 </div>
28 - </div>
29 -
30 - <div class="badges-box flex flex-wrap items-center gap-3 mt-2">
31 - <code class="py-1">Auth Keys:</code>
32 - <Badge v-for="authKey of data.keys" :key="authKey.auth_key_name">
33 - <template #value>
34 - {{ authKey.auth_key_name }}
16 + </template>
17 +
18 + <template #footerMain>
19 + <div class="flex flex-wrap items-center gap-3">
20 + <code class="py-1">Auth Keys:</code>
21 + <Badge v-for="authKey of data.keys" :key="authKey.auth_key_name">
22 + <template #value>
23 + {{ authKey.auth_key_name }}
24 + </template>
25 + </Badge>
26 + </div>
27 + </template>
28 + <template #footerExtra>
29 + <n-button size="small" @click.stop="showDetails = true">
30 + <template #icon>
31 + <Icon :name="InfoIcon"></Icon>
32 </template>
36 - </Badge>
37 - </div>
38 - </div>
33 + Details
34 + </n-button>
35 + </template>
36 + </CardEntity>
37
38 <n-modal
39 v-model:show="showDetails"
@@ -55,6 +53,7 @@
53 <script setup lang="ts">
54 import type { ServiceItemData, ServiceItemType } from "./types"
55 import Badge from "@/components/common/Badge.vue"
56 +import CardEntity from "@/components/common/cards/CardEntity.vue"
57 import Icon from "@/components/common/Icon.vue"
58 import { NButton, NModal, NRadio } from "naive-ui"
59 import { defineAsyncComponent, ref, toRefs } from "vue"
@@ -76,55 +75,3 @@ const InfoIcon = "carbon:information"
75
76 const showDetails = ref(false)
77 </script>
79 -
80 -<style lang="scss" scoped>
81 -.service-item {
82 - border-radius: var(--border-radius);
83 - background-color: var(--bg-color);
84 - border: var(--border-small-050);
85 - transition: all 0.2s var(--bezier-ease);
86 -
87 - .header-box {
88 - font-size: 13px;
89 - .id {
90 - font-family: var(--font-family-mono);
91 - word-break: break-word;
92 - color: var(--fg-secondary-color);
93 - line-height: 1.2;
94 - }
95 - }
96 -
97 - .main-box {
98 - .content {
99 - word-break: break-word;
100 -
101 - .description {
102 - color: var(--fg-secondary-color);
103 - font-size: 13px;
104 - }
105 - }
106 - }
107 -
108 - &.embedded {
109 - background-color: var(--bg-secondary-color);
110 - }
111 -
112 - &.selectable {
113 - cursor: pointer;
114 - }
115 -
116 - &.disabled {
117 - cursor: not-allowed;
118 -
119 - & > div {
120 - opacity: 0.5;
121 - }
122 - }
123 -
124 - &:not(.disabled) {
125 - &:hover {
126 - box-shadow: 0px 0px 0px 1px inset var(--primary-color);
127 - }
128 - }
129 -}
130 -</style>
frontend/src/components/services/List.vue
+3 -12
@@ -1,13 +1,13 @@
1 <template>
2 <div class="services-list">
3 - <div v-if="!hideTotals" class="header mb-4 flex gap-2 justify-between items-center">
3 + <div v-if="!hideTotals" class="header mb-4 flex items-center justify-between gap-2">
4 <div>
5 Total:
6 <strong class="font-mono">{{ total }}</strong>
7 </div>
8 </div>
9 <n-spin :show="loading">
10 - <div class="list">
10 + <div class="min-h-52">
11 <template v-if="list.length">
12 <ServiceItem
13 v-for="item of list"
@@ -23,7 +23,7 @@
23 />
24 </template>
25 <template v-else>
26 - <n-empty v-if="!loading" description="No items found" class="justify-center h-48" />
26 + <n-empty v-if="!loading" description="No items found" class="h-48 justify-center" />
27 </template>
28 </div>
29 </n-spin>
@@ -67,12 +67,3 @@ function setItem(item: ServiceItemData) {
67 }
68 }
69 </script>
70 -
71 -<style lang="scss" scoped>
72 -.services-list {
73 - .list {
74 - container-type: inline-size;
75 - min-height: 200px;
76 - }
77 -}
78 -</style>
frontend/src/components/services/types/index.d.ts
+1
@@ -1,4 +1,5 @@
1 export type ServiceItemType = "integration" | "network-connector"
2 +
3 export interface ServiceItemData {
4 id: number
5 name: string
frontend/src/components/sigma/QueriesList.vue
+12 -12
@@ -1,10 +1,10 @@
1 <template>
2 <div class="sigma-queries-list">
3 <div ref="header" class="header flex items-center justify-end gap-2">
4 - <div class="info grow flex gap-2">
4 + <div class="info flex grow gap-2">
5 <n-popover overlap placement="bottom-start">
6 <template #trigger>
7 - <div class="bg-color border-radius">
7 + <div class="bg-default rounded-default">
8 <n-button size="small" class="!cursor-help">
9 <template #icon>
10 <Icon :name="InfoIcon"></Icon>
@@ -18,12 +18,12 @@
18 <code>{{ total }}</code>
19 </div>
20 <div class="box">
21 - <span class="text-success-color">Active</span>
21 + <span class="text-success">Active</span>
22 :
23 <code>{{ activeTotal }}</code>
24 </div>
25 <div class="box">
26 - <span class="text-secondary-color">Inactive</span>
26 + <span class="text-secondary">Inactive</span>
27 :
28 <code>{{ inactiveTotal }}</code>
29 </div>
@@ -33,9 +33,9 @@
33 <n-button size="small" type="primary" secondary strong @click="showActionsView = !showActionsView">
34 <div class="flex items-center gap-2">
35 <Icon :name="ToolsIcon" :size="16"></Icon>
36 - <span class="hidden xs:block">Actions</span>
36 + <span class="xs:block hidden">Actions</span>
37 <Icon
38 - class="!hidden xs:!block transition-transform"
38 + class="xs:!block !hidden transition-transform"
39 :class="{ '!rotate-90': showActionsView }"
40 :name="ChevronIcon"
41 :size="16"
@@ -54,7 +54,7 @@
54 />
55 <n-popover :show="showFilters" trigger="manual" overlap placement="right" class="!px-0">
56 <template #trigger>
57 - <div class="bg-color border-radius">
57 + <div class="bg-default rounded-default">
58 <n-badge :show="filtered" dot type="success" :offset="[-4, 0]">
59 <n-button size="small" @click="showFilters = true">
60 <template #icon>
@@ -64,7 +64,7 @@
64 </n-badge>
65 </div>
66 </template>
67 - <div class="py-1 flex flex-col gap-2">
67 + <div class="flex flex-col gap-2 py-1">
68 <div class="px-3">
69 <small>Status:</small>
70 </div>
@@ -77,7 +77,7 @@
77 class="!w-56"
78 />
79 </div>
80 - <div class="px-3 flex justify-between gap-2">
80 + <div class="flex justify-between gap-2 px-3">
81 <div class="flex justify-start gap-2">
82 <n-button size="small" quaternary @click="showFilters = false">Close</n-button>
83 </div>
@@ -93,13 +93,13 @@
93 </div>
94
95 <div class="actions-box" :class="{ open: showActionsView }">
96 - <n-card size="small" content-class="bg-secondary-color" class="overflow-hidden" :bordered="false">
96 + <n-card size="small" content-class="bg-secondary" class="overflow-hidden" :bordered="false">
97 <QueriesActions @updated="getData()" />
98 </n-card>
99 </div>
100
101 <n-spin :show="loading">
102 - <div class="list flex flex-col gap-2 my-3">
102 + <div class="list my-3 flex flex-col gap-2">
103 <template v-if="queriesList.length">
104 <QueryItem
105 v-for="query of itemsPaginated"
@@ -111,7 +111,7 @@
111 />
112 </template>
113 <template v-else>
114 - <n-empty v-if="!loading" description="No items found" class="justify-center h-48" />
114 + <n-empty v-if="!loading" description="No items found" class="h-48 justify-center" />
115 </template>
116 </div>
117 </n-spin>
frontend/src/components/sigma/QueryDetails.vue
+1 -1
@@ -1,6 +1,6 @@
1 <template>
2 <n-tabs type="line" animated :tabs-padding="24" class="grow" pane-wrapper-class="flex flex-col grow">
3 - <n-tab-pane name="Overview" tab="Overview" display-directive="show:lazy" class="flex flex-col grow">
3 + <n-tab-pane name="Overview" tab="Overview" display-directive="show:lazy" class="flex grow flex-col">
4 <div class="pt-1">
5 <QueryOverview :query @updated="updateQuery($event)" @deleted="emit('deleted', query)" />
6 </div>
frontend/src/components/sigma/QueryItem.vue
+63 -112
@@ -1,83 +1,74 @@
1 <template>
2 - <div class="sigma-query-item" :class="{ embedded }" @click="openDetails()">
3 - <n-spin :show="loading">
4 - <div class="flex flex-col">
5 - <div class="header-box px-5 py-3 pb-0 flex justify-between items-center">
6 - <div class="id flex items-center gap-2 cursor-pointer" @click="openDetails()">
7 - <span>#{{ query.id }}</span>
8 - </div>
9 - <div class="status flex gap-2 items-center">
10 - <span>{{ query.active ? "Active" : "Inactive" }}</span>
11 - <Icon v-if="query.active" :name="EnabledIcon" :size="14" class="text-success-color"></Icon>
12 - <Icon v-else :name="DisabledIcon" :size="14" class="text-secondary-color"></Icon>
13 - </div>
2 + <div>
3 + <CardEntity :loading :embedded hoverable clickable @click.stop="openDetails()">
4 + <template #headerMain>#{{ query.id }}</template>
5 + <template #headerExtra>
6 + <div class="flex items-center gap-2">
7 + <span>{{ query.active ? "Active" : "Inactive" }}</span>
8 + <Icon v-if="query.active" :name="EnabledIcon" :size="14" class="text-success"></Icon>
9 + <Icon v-else :name="DisabledIcon" :size="14" class="text-secondary"></Icon>
10 </div>
15 -
16 - <div class="main-box flex flex-col gap-3 px-5 py-3">
17 - <div class="content flex flex-col gap-1 grow">
18 - <div class="title">
19 - {{ query.rule_name }}
20 - </div>
21 - </div>
22 - </div>
23 -
24 - <div class="footer-box px-5 py-3 flex justify-between items-center gap-4">
25 - <div class="badges-box flex flex-wrap items-center gap-3">
26 - <QueryTimeIntervalForm
27 - v-slot="{ loading: loadingTimeInterval, togglePopup: toggleTimeIntervalPopup }"
28 - :query
29 - @updated="updateQuery($event)"
30 - >
31 - <Badge type="splitted" bright point-cursor @click.stop="toggleTimeIntervalPopup()">
32 - <template #iconLeft>
33 - <n-spin
34 - :size="12"
35 - :show="loadingTimeInterval"
36 - content-class="flex flex-col justify-center"
37 - >
38 - <Icon :name="TimeIntervalIcon" />
39 - </n-spin>
40 - </template>
41 - <template #label>Time Interval</template>
42 - <template #value>
43 - <div class="flex gap-2 items-center">
44 - {{ query.time_interval || "n/d" }}
45 - <Icon :name="EditIcon" :size="13" />
46 - </div>
47 - </template>
48 - </Badge>
49 - </QueryTimeIntervalForm>
50 -
51 - <Badge type="splitted" bright fluid class="!hidden sm:!flex">
11 + </template>
12 + <template #default>
13 + {{ query.rule_name }}
14 + </template>
15 + <template #footerMain>
16 + <div class="flex flex-wrap items-center gap-3">
17 + <QueryTimeIntervalForm
18 + v-slot="{ loading: loadingTimeInterval, togglePopup: toggleTimeIntervalPopup }"
19 + :query
20 + @updated="updateQuery($event)"
21 + >
22 + <Badge type="splitted" bright point-cursor @click.stop="toggleTimeIntervalPopup()">
23 <template #iconLeft>
53 - <Icon :name="TimeIcon" />
24 + <n-spin
25 + :size="12"
26 + :show="loadingTimeInterval"
27 + content-class="flex flex-col justify-center"
28 + >
29 + <Icon :name="TimeIntervalIcon" />
30 + </n-spin>
31 </template>
55 - <template #label>Last execution time</template>
32 + <template #label>Time Interval</template>
33 <template #value>
57 - <div class="flex gap-2 items-center">
58 - {{
59 - query.last_execution_time
60 - ? formatDate(query.last_execution_time, dFormats.datetimesec)
61 - : "n/d"
62 - }}
34 + <div class="flex items-center gap-2">
35 + {{ query.time_interval || "n/d" }}
36 + <Icon :name="EditIcon" :size="13" />
37 </div>
38 </template>
39 </Badge>
66 - </div>
67 - <div class="actions-box">
68 - <QueryDeleteOne
69 - v-slot="{ loading: loadingDelete, togglePopup: toggleDeletePopup }"
70 - :query
71 - @deleted="emit('deleted', query)"
72 - >
73 - <n-button quaternary size="tiny" :loading="loadingDelete" @click.stop="toggleDeletePopup()">
74 - Delete
75 - </n-button>
76 - </QueryDeleteOne>
77 - </div>
40 + </QueryTimeIntervalForm>
41 +
42 + <Badge type="splitted" bright fluid class="!hidden sm:!flex">
43 + <template #iconLeft>
44 + <Icon :name="TimeIcon" />
45 + </template>
46 + <template #label>Last execution time</template>
47 + <template #value>
48 + <div class="flex items-center gap-2">
49 + {{
50 + query.last_execution_time
51 + ? formatDate(query.last_execution_time, dFormats.datetimesec)
52 + : "n/d"
53 + }}
54 + </div>
55 + </template>
56 + </Badge>
57 </div>
79 - </div>
80 - </n-spin>
58 + </template>
59 +
60 + <template #footerExtra>
61 + <QueryDeleteOne
62 + v-slot="{ loading: loadingDelete, togglePopup: toggleDeletePopup }"
63 + :query
64 + @deleted="emit('deleted', query)"
65 + >
66 + <n-button quaternary size="tiny" :loading="loadingDelete" @click.stop="toggleDeletePopup()">
67 + Delete
68 + </n-button>
69 + </QueryDeleteOne>
70 + </template>
71 + </CardEntity>
72
73 <n-modal
74 v-model:show="showDetails"
@@ -102,6 +93,7 @@
93 <script setup lang="ts">
94 import type { SigmaQuery } from "@/types/sigma.d"
95 import Badge from "@/components/common/Badge.vue"
96 +import CardEntity from "@/components/common/cards/CardEntity.vue"
97 import Icon from "@/components/common/Icon.vue"
98 import { useSettingsStore } from "@/stores/settings"
99 import { formatDate } from "@/utils"
@@ -150,44 +142,3 @@ function closeDetails() {
142 showDetails.value = false
143 }
144 </script>
153 -
154 -<style lang="scss" scoped>
155 -.sigma-query-item {
156 - border-radius: var(--border-radius);
157 - background-color: var(--bg-color);
158 - transition: all 0.2s var(--bezier-ease);
159 - border: var(--border-small-050);
160 - overflow: hidden;
161 - cursor: pointer;
162 -
163 - .header-box {
164 - font-size: 13px;
165 -
166 - .id {
167 - color: var(--fg-secondary-color);
168 - font-family: var(--font-family-mono);
169 - word-break: break-word;
170 - line-height: 1.2;
171 - }
172 - }
173 - .main-box {
174 - .content {
175 - word-break: break-word;
176 - }
177 - }
178 -
179 - .footer-box {
180 - border-top: var(--border-small-100);
181 - font-size: 13px;
182 - background-color: var(--bg-secondary-color);
183 - }
184 -
185 - &.embedded {
186 - background-color: var(--bg-secondary-color);
187 - }
188 -
189 - &:hover {
190 - box-shadow: 0px 0px 0px 1px var(--primary-color);
191 - }
192 -}
193 -</style>
frontend/src/components/sigma/QueryOverview.vue
+20 -20
@@ -1,11 +1,11 @@
1 <template>
2 - <n-spin :show="loading" class="flex flex-col grow" content-class="flex flex-col grow">
3 - <div class="flex flex-col gap-4 grow justify-between">
2 + <n-spin :show="loading" class="flex grow flex-col" content-class="flex flex-col grow">
3 + <div class="flex grow flex-col justify-between gap-4">
4 <div class="content-box flex flex-col gap-4 py-3">
5 - <div class="px-7 flex sm:!flex-row flex-col gap-4">
6 - <KVCard :color="query.active ? 'success' : undefined" size="lg" class="grow w-full">
5 + <div class="flex flex-col gap-4 px-7 sm:!flex-row">
6 + <CardKV :color="query.active ? 'success' : undefined" size="lg" class="w-full grow">
7 <template #key>
8 - <div class="flex gap-2 items-center">
8 + <div class="flex items-center gap-2">
9 <Icon :name="query.active ? EnabledIcon : DisabledIcon" />
10 <span>Status</span>
11 </div>
@@ -18,7 +18,7 @@
18 @updated="updateQuery($event)"
19 >
20 <div
21 - class="flex gap-3 items-center"
21 + class="flex items-center gap-3"
22 :class="{
23 'cursor-not-allowed': loadingActive,
24 'cursor-pointer': !loadingActive
@@ -37,11 +37,11 @@
37 </QueryActiveForm>
38 </div>
39 </template>
40 - </KVCard>
40 + </CardKV>
41
42 - <KVCard size="lg" class="grow w-full">
42 + <CardKV size="lg" class="w-full grow">
43 <template #key>
44 - <div class="flex gap-2 items-center">
44 + <div class="flex items-center gap-2">
45 <Icon :name="TimeIntervalIcon" />
46 <span>Time Interval</span>
47 </div>
@@ -54,7 +54,7 @@
54 @updated="updateQuery($event)"
55 >
56 <div
57 - class="flex gap-3 items-center"
57 + class="flex items-center gap-3"
58 :class="{
59 'cursor-not-allowed': loadingTimeInterval,
60 'cursor-pointer': !loadingTimeInterval
@@ -73,20 +73,20 @@
73 </QueryTimeIntervalForm>
74 </div>
75 </template>
76 - </KVCard>
76 + </CardKV>
77 </div>
78
79 <div class="px-7">
80 - <KVCard>
80 + <CardKV>
81 <template #key>name</template>
82 <template #value>
83 {{ query.rule_name ?? "-" }}
84 </template>
85 - </KVCard>
85 + </CardKV>
86 </div>
87
88 - <div class="px-7 grid gap-2 grid-auto-fit-250">
89 - <KVCard>
88 + <div class="grid-auto-fit-250 grid gap-2 px-7">
89 + <CardKV>
90 <template #key>last execution time</template>
91 <template #value>
92 {{
@@ -95,18 +95,18 @@
95 : "n/d"
96 }}
97 </template>
98 - </KVCard>
98 + </CardKV>
99
100 - <KVCard>
100 + <CardKV>
101 <template #key>last updated</template>
102 <template #value>
103 {{ query.last_updated ? formatDate(query.last_updated, dFormats.datetimesec) : "n/d" }}
104 </template>
105 - </KVCard>
105 + </CardKV>
106 </div>
107 </div>
108
109 - <div class="footer-box px-7 py-4 flex items-center gap-2">
109 + <div class="footer-box flex items-center gap-2 px-7 py-4">
110 <div class="grow"></div>
111
112 <QueryDeleteOne
@@ -128,8 +128,8 @@
128
129 <script setup lang="ts">
130 import type { SigmaQuery } from "@/types/sigma.d"
131 +import CardKV from "@/components/common/cards/CardKV.vue"
132 import Icon from "@/components/common/Icon.vue"
132 -import KVCard from "@/components/common/KVCard.vue"
133 import { useSettingsStore } from "@/stores/settings"
134 import { formatDate } from "@/utils"
135 import { NButton, NSpin } from "naive-ui"
frontend/src/components/sigma/actionsProviders/QueryActiveAllForm.vue
+3 -3
@@ -4,15 +4,15 @@
4 <slot :loading :toggle-popup />
5 </template>
6
7 - <div class="py-1 flex flex-col gap-2 justify-center min-w-52">
8 - <div class="flex gap-2 items-center">
7 + <div class="flex min-w-52 flex-col justify-center gap-2 py-1">
8 + <div class="flex items-center gap-2">
9 <n-button :loading type="success" @click="updateActive(true)">Activates all Sigma queries</n-button>
10 <n-button :loading @click="updateActive(false)">Deactivates all Sigma queries</n-button>
11 </div>
12
13 <p class="text-right">* It may take several minutes</p>
14
15 - <div class="flex gap-2 justify-between">
15 + <div class="flex justify-between gap-2">
16 <n-button quaternary size="small" @click="closePopup()">Close</n-button>
17 </div>
18 </div>
frontend/src/components/sigma/actionsProviders/QueryActiveForm.vue
+3 -3
@@ -4,13 +4,13 @@
4 <slot :loading :toggle-popup />
5 </template>
6
7 - <div class="py-1 flex flex-col gap-4 justify-center min-w-52">
8 - <div class="flex gap-2 items-center justify-center py-3">
7 + <div class="flex min-w-52 flex-col justify-center gap-4 py-1">
8 + <div class="flex items-center justify-center gap-2 py-3">
9 <span>Active</span>
10 <n-switch v-model:value="model.active" :disabled="loading" />
11 </div>
12
13 - <div class="flex gap-2 justify-between">
13 + <div class="flex justify-between gap-2">
14 <n-button quaternary size="small" @click="closePopup()">Close</n-button>
15 <n-button :disabled="!dirty" :loading type="primary" size="small" @click="updateActive()">
16 Save
frontend/src/components/sigma/actionsProviders/QueryDeleteAll.vue
+2 -2
@@ -4,12 +4,12 @@
4 <slot :loading :toggle-popup />
5 </template>
6
7 - <div class="py-1 flex flex-col gap-2 max-w-80">
7 + <div class="flex max-w-80 flex-col gap-2 py-1">
8 <div>This will remove ALL Sigma queries, are you sure you want to proceed?</div>
9
10 <p class="text-right">* It may take several minutes</p>
11
12 - <div class="flex gap-2 justify-between">
12 + <div class="flex justify-between gap-2">
13 <n-button quaternary size="small" @click="closePopup()">Close</n-button>
14 <n-button :loading type="primary" size="small" @click="deleteQueries()">Yes I'm sure</n-button>
15 </div>
frontend/src/components/sigma/actionsProviders/QueryDeleteOne.vue
+2 -2
@@ -4,14 +4,14 @@
4 <slot :loading :toggle-popup />
5 </template>
6
7 - <div class="py-1 flex flex-col gap-4">
7 + <div class="flex flex-col gap-4 py-1">
8 <div>
9 Are you sure you want to delete the Query
10 <strong>#{{ query.id }}</strong>
11 ?
12 </div>
13
14 - <div class="flex gap-2 justify-between">
14 + <div class="flex justify-between gap-2">
15 <n-button quaternary size="small" @click="closePopup()">Close</n-button>
16 <n-button :loading type="error" size="small" @click="deleteQuery()">
17 <template #icon>
frontend/src/components/sigma/actionsProviders/QueryDownloadAll.vue
+2 -2
@@ -4,10 +4,10 @@
4 <slot :loading :toggle-popup />
5 </template>
6
7 - <div class="py-1 flex flex-col gap-4 max-w-80">
7 + <div class="flex max-w-80 flex-col gap-4 py-1">
8 <div>This will download ALL Sigma queries, are you sure you want to proceed?</div>
9
10 - <div class="flex gap-2 justify-between">
10 + <div class="flex justify-between gap-2">
11 <n-button quaternary size="small" @click="closePopup()">Close</n-button>
12 <n-button :loading type="primary" size="small" @click="downloadQueries()">Yes I'm sure</n-button>
13 </div>
frontend/src/components/sigma/actionsProviders/QueryTimeIntervalForm.vue
+3 -3
@@ -4,8 +4,8 @@
4 <slot :loading :toggle-popup />
5 </template>
6
7 - <div class="py-1 flex flex-col gap-4">
8 - <div class="flex gap-2 items-center">
7 + <div class="flex flex-col gap-4 py-1">
8 + <div class="flex items-center gap-2">
9 <n-input-group>
10 <n-select
11 v-model:value="model.unit"
@@ -25,7 +25,7 @@
25 </n-input-group>
26 </div>
27
28 - <div class="flex gap-2 justify-between">
28 + <div class="flex justify-between gap-2">
29 <n-button quaternary size="small" @click="closePopup()">Close</n-button>
30 <n-button
31 :disabled="!dirty || !isValid"
frontend/src/components/sigma/actionsProviders/QueryUploadDB.vue
+2 -2
@@ -4,7 +4,7 @@
4 <slot :loading :toggle-popup />
5 </template>
6
7 - <div class="py-1 flex flex-col gap-2 max-w-80 min-w-72">
7 + <div class="flex min-w-72 max-w-80 flex-col gap-2 py-1">
8 <div>Choose the level to load:</div>
9
10 <n-checkbox-group v-model:value="ruleLevels" class="flex gap-4" :disabled="loading">
@@ -14,7 +14,7 @@
14
15 <p class="text-right">* It may take several minutes</p>
16
17 - <div class="flex gap-2 justify-between">
17 + <div class="flex justify-between gap-2">
18 <n-button quaternary size="small" @click="closePopup()">Close</n-button>
19 <n-button :disabled="!isValid" :loading type="primary" size="small" @click="uploadQueries()">
20 Upload
frontend/src/components/sigma/actionsProviders/QueryUploadFile.vue
+2 -2
@@ -4,7 +4,7 @@
4 <slot :loading :toggle-popup />
5 </template>
6
7 - <div class="py-1 flex flex-col gap-2 max-w-80">
7 + <div class="flex max-w-80 flex-col gap-2 py-1">
8 <n-upload
9 v-model:file-list="fileList"
10 :max="1"
@@ -20,7 +20,7 @@
20 </n-upload-dragger>
21 </n-upload>
22
23 - <div class="flex gap-2 justify-between">
23 + <div class="flex justify-between gap-2">
24 <n-button quaternary size="small" @click="closePopup()">Close</n-button>
25 <n-button :disabled="!isValid" :loading type="primary" size="small" @click="uploadQueries()">
26 Upload
frontend/src/components/soc/SocAlerts/SocAlertAssets/SocAlertAssetsItem.vue
+63 -124
@@ -1,20 +1,12 @@
1 <template>
2 - <div class="soc-asset-item">
3 - <div class="flex flex-col gap-2 px-5 py-4">
4 - <div class="header-box flex justify-between">
5 - <div class="flex items-center gap-2">
6 - <div class="id flex items-center gap-2 cursor-pointer" @click="showDetails = true">
7 - <span>#{{ asset.asset_id }} - {{ asset.asset_uuid }}</span>
8 - <Icon :name="InfoIcon" :size="16"></Icon>
9 - </div>
10 - </div>
11 - </div>
12 - <div class="main-box flex justify-between gap-4">
13 - <div class="content">
14 - <div class="title">
15 - {{ asset.asset_name }}
16 - </div>
17 - <div v-if="asset.asset_description" class="description mt-2">
2 + <div>
3 + <CardEntity hoverable clickable @click.stop="showDetails = true">
4 + <template #headerMain>#{{ asset.asset_id }} - {{ asset.asset_uuid }}</template>
5 + <template #default>
6 + <div class="flex flex-col gap-1">
7 + {{ asset.asset_name }}
8 +
9 + <p v-if="asset.asset_description" class="text-sm">
10 <template v-if="isUrlLike(asset.asset_description)">
11 <a
12 :href="asset.asset_description"
@@ -23,7 +15,7 @@
15 alt="asset url"
16 rel="nofollow noopener noreferrer"
17 >
26 - <code class="text-primary-color">
18 + <code class="text-primary">
19 <span>
20 {{ asset.asset_description }}
21 </span>
@@ -34,37 +26,38 @@
26 <template v-else>
27 {{ excerpt }}
28 </template>
37 - </div>
38 -
39 - <div class="badges-box flex flex-wrap items-center gap-3 mt-4">
40 - <Badge v-if="asset.date_added" type="splitted" color="primary">
41 - <template #iconLeft>
42 - <Icon :name="ClockIcon" :size="14"></Icon>
43 - </template>
44 - <template #label>Added</template>
45 - <template #value>
46 - {{ formatDate(asset.date_added) }}
47 - </template>
48 - </Badge>
49 - <Badge v-if="asset.date_update" type="splitted" color="primary">
50 - <template #iconLeft>
51 - <Icon :name="ClockIcon" :size="14"></Icon>
52 - </template>
53 - <template #label>Updated</template>
54 - <template #value>
55 - {{ formatDate(asset.date_update) }}
56 - </template>
57 - </Badge>
58 - <Badge type="active" class="cursor-pointer" @click="gotoAgent(asset.asset_tags)">
59 - <template #iconRight>
60 - <Icon :name="LinkIcon" :size="14"></Icon>
61 - </template>
62 - <template #label>Agent: {{ asset.asset_tags }}</template>
63 - </Badge>
64 - </div>
29 + </p>
30 </div>
66 - </div>
67 - </div>
31 + </template>
32 + <template #mainExtra>
33 + <div class="flex flex-wrap items-center gap-3">
34 + <Badge v-if="asset.date_added" type="splitted" color="primary">
35 + <template #iconLeft>
36 + <Icon :name="ClockIcon" :size="14"></Icon>
37 + </template>
38 + <template #label>Added</template>
39 + <template #value>
40 + {{ formatDate(asset.date_added) }}
41 + </template>
42 + </Badge>
43 + <Badge v-if="asset.date_update" type="splitted" color="primary">
44 + <template #iconLeft>
45 + <Icon :name="ClockIcon" :size="14"></Icon>
46 + </template>
47 + <template #label>Updated</template>
48 + <template #value>
49 + {{ formatDate(asset.date_update) }}
50 + </template>
51 + </Badge>
52 + <Badge type="active" class="cursor-pointer" @click.stop="gotoAgent(asset.asset_tags)">
53 + <template #iconRight>
54 + <Icon :name="LinkIcon" :size="14"></Icon>
55 + </template>
56 + <template #label>Agent: {{ asset.asset_tags }}</template>
57 + </Badge>
58 + </div>
59 + </template>
60 + </CardEntity>
61
62 <n-modal
63 v-model:show="showDetails"
@@ -77,8 +70,8 @@
70 >
71 <n-tabs type="line" animated :tabs-padding="24">
72 <n-tab-pane name="Info" tab="Info" display-directive="show">
80 - <div v-if="properties" class="grid gap-2 grid-auto-fit-200 p-7 pt-4">
81 - <KVCard v-for="(value, key) of properties" :key="key">
73 + <div v-if="properties" class="grid-auto-fit-200 grid gap-2 p-7 pt-4">
74 + <CardKV v-for="(value, key) of properties" :key="key">
75 <template #key>
76 {{ key }}
77 </template>
@@ -86,8 +79,8 @@
79 <template v-if="key === 'asset_tags'">
80 <code
81 v-if="value && value !== '-'"
89 - class="cursor-pointer text-primary-color"
90 - @click="gotoAgent(value)"
82 + class="text-primary cursor-pointer"
83 + @click.stop="gotoAgent(value)"
84 >
85 {{ value }}
86 <Icon :name="LinkIcon" :size="13" class="relative top-0.5" />
@@ -98,19 +91,19 @@
91 {{ value ?? "-" }}
92 </template>
93 </template>
101 - </KVCard>
94 + </CardKV>
95 </div>
96 </n-tab-pane>
97 <n-tab-pane name="Type" tab="Type" display-directive="show">
105 - <div v-if="assetType" class="grid gap-2 grid-auto-fit-250 p-7 pt-4">
106 - <KVCard v-for="(value, key) of assetType" :key="key">
98 + <div v-if="assetType" class="grid-auto-fit-250 grid gap-2 p-7 pt-4">
99 + <CardKV v-for="(value, key) of assetType" :key="key">
100 <template #key>
101 {{ key }}
102 </template>
103 <template #value>
104 {{ value || "-" }}
105 </template>
113 - </KVCard>
106 + </CardKV>
107 </div>
108 </n-tab-pane>
109 <n-tab-pane name="Description" tab="Description" display-directive="show">
@@ -150,8 +143,9 @@
143 <script setup lang="ts">
144 import type { SocAlertAsset } from "@/types/soc/asset.d"
145 import Badge from "@/components/common/Badge.vue"
146 +import CardEntity from "@/components/common/cards/CardEntity.vue"
147 +import CardKV from "@/components/common/cards/CardKV.vue"
148 import Icon from "@/components/common/Icon.vue"
154 -import KVCard from "@/components/common/KVCard.vue"
149 import { useGoto } from "@/composables/useGoto"
150 import { useSettingsStore } from "@/stores/settings"
151 import { isUrlLike } from "@/utils"
@@ -164,7 +158,6 @@ const { asset } = defineProps<{ asset: SocAlertAsset }>()
158
159 const ArtifactsCollect = defineAsyncComponent(() => import("@/components/artifacts/ArtifactsCollect.vue"))
160
167 -const InfoIcon = "carbon:information"
161 const ClockIcon = "carbon:time"
162 const LinkIcon = "carbon:launch"
163 const { gotoAgent } = useGoto()
@@ -209,74 +202,20 @@ function formatDate(date: string, useSec = false) {
202 </script>
203
204 <style lang="scss" scoped>
212 -.soc-asset-item {
213 - border-radius: var(--border-radius);
214 - background-color: var(--bg-secondary-color);
215 - transition: all 0.2s var(--bezier-ease);
216 - border: var(--border-small-050);
217 -
218 - .header-box {
219 - font-family: var(--font-family-mono);
220 - font-size: 13px;
221 - .id {
222 - word-break: break-word;
223 - color: var(--fg-secondary-color);
224 - line-height: 1.2;
225 -
226 - &:hover {
227 - color: var(--primary-color);
228 - }
229 - }
230 -
231 - .toggler-bookmark {
232 - &.active {
233 - color: var(--primary-color);
234 - }
235 - &:hover {
236 - color: var(--primary-color);
237 - }
205 +.asset-url {
206 + display: block;
207 +
208 + code {
209 + padding: 8px 12px;
210 + display: flex;
211 + gap: 10px;
212 +
213 + span {
214 + white-space: nowrap;
215 + flex-grow: 1;
216 + overflow: hidden;
217 + text-overflow: ellipsis;
218 }
239 - .time {
240 - color: var(--fg-secondary-color);
241 -
242 - &:hover {
243 - color: var(--primary-color);
244 - }
245 - }
246 - }
247 -
248 - .main-box {
249 - word-break: break-word;
250 -
251 - .content {
252 - max-width: 100%;
253 -
254 - .description {
255 - color: var(--fg-secondary-color);
256 - font-size: 13px;
257 -
258 - .asset-url {
259 - display: block;
260 -
261 - code {
262 - padding: 8px 12px;
263 - display: flex;
264 - gap: 10px;
265 -
266 - span {
267 - white-space: nowrap;
268 - flex-grow: 1;
269 - overflow: hidden;
270 - text-overflow: ellipsis;
271 - }
272 - }
273 - }
274 - }
275 - }
276 - }
277 -
278 - &:hover {
279 - box-shadow: 0px 0px 0px 1px inset var(--primary-color);
219 }
220 }
221 </style>
frontend/src/components/soc/SocAlerts/SocAlertAssets/SocAlertAssetsList.vue
+2 -2
@@ -1,11 +1,11 @@
1 <template>
2 <div class="soc-assets-list">
3 <n-spin :show="loadingAssets" style="min-height: 50px">
4 - <div v-if="assetsList?.length" class="p-7 flex flex-col gap-2">
4 + <div v-if="assetsList?.length" class="flex flex-col gap-2 p-7">
5 <SocAlertAssetsItem v-for="asset of assetsList" :key="asset.asset_id" :asset="asset" />
6 </div>
7 <template v-else>
8 - <n-empty v-if="!loadingAssets" description="No items found" class="justify-center h-48" />
8 + <n-empty v-if="!loadingAssets" description="No items found" class="h-48 justify-center" />
9 </template>
10 </n-spin>
11 </div>
frontend/src/components/soc/SocAlerts/SocAlertItem/SocAlertItem.vue
+79 -173
@@ -1,21 +1,22 @@
1 <template>
2 - <n-spin
3 - :id="`alert-${alert?.alert_id}`"
4 - :show="loading"
5 - :description="loadingDelete ? 'Deleting Soc Alert' : 'Loading Soc Alert'"
6 - class="soc-alert-item flex flex-col gap-0 min-h-36 pb-2"
7 - :class="{ bookmarked: isBookmark, highlight, embedded }"
8 - >
9 - <div v-if="alert" class="soc-alert-info px-5 py-3 flex flex-col gap-3">
10 - <div class="header-box flex justify-between">
11 - <div class="flex items-center gap-2 cursor-pointer">
2 + <div :id="`alert-${alert?.alert_id}`">
3 + <CardEntity
4 + :loading
5 + :loading-description="loadingDelete ? 'Deleting Soc Alert' : 'Loading Soc Alert'"
6 + class="min-h-36"
7 + clickable
8 + hoverable
9 + :status="isBookmark ? 'success' : undefined"
10 + :embedded
11 + :highlighted="!!highlight"
12 + @click.stop="showDetails = true"
13 + >
14 + <template #headerMain>
15 + <div class="flex items-center gap-2">
16 <div v-if="showCheckbox" class="check-box mr-2">
17 <n-checkbox v-model:checked="checked" size="large" />
18 </div>
15 - <div class="id flex items-center gap-2 cursor-pointer" @click="showDetails = true">
16 - <span>#{{ alert.alert_id }} - {{ alert.alert_uuid }}</span>
17 - <Icon :name="InfoIcon" :size="16"></Icon>
18 - </div>
19 + <span v-if="alert">#{{ alert.alert_id }} - {{ alert.alert_uuid }}</span>
20 <SocAlertItemBookmarkToggler
21 v-if="!hideBookmarkAction && alert"
22 :alert
@@ -23,79 +24,67 @@
24 @bookmark="emit('bookmark', $event)"
25 />
26 </div>
26 - <div class="time">
27 - <SocAlertItemTime :alert />
28 - </div>
29 - </div>
30 - <div class="main-box flex justify-between gap-4">
31 - <div class="content">
32 - <div class="title">
33 - {{ alert.alert_title }}
34 - </div>
35 - <div
36 - v-if="alert.alert_description && alert.alert_title !== alert.alert_description"
37 - class="description mb-2"
38 - >
27 + </template>
28 + <template v-if="alert" #headerExtra>
29 + <SocAlertItemTime :alert />
30 + </template>
31 +
32 + <template v-if="alert" #default>
33 + <div class="flex flex-col gap-1">
34 + {{ alert.alert_title }}
35 +
36 + <p v-if="alert.alert_description && alert.alert_title !== alert.alert_description" class=" ">
37 {{ alert.alert_description }}
40 - </div>
38 + </p>
39 </div>
42 - <SocAlertItemActions
43 - v-if="!hideSocCaseAction"
44 - class="actions-box"
45 - :case-id
46 - :alert-id="alert.alert_id"
47 - @case-created="caseCreated($event)"
48 - @deleted="deleted()"
49 - @start-deleting="loadingDelete = true"
50 - />
51 - </div>
40 + </template>
41
53 - <div>
54 - <div
55 - v-if="showBadgesToggle"
56 - class="show-badges-toggle flex items-center gap-2"
57 - @click="showBadges = !showBadges"
58 - >
59 - {{ showBadges ? "Less info" : "More info" }}
60 - <span class="transition-transform flex items-center" :class="{ 'rotate-90': showBadges }">
61 - <Icon :name="ChevronIcon" :size="14"></Icon>
62 - </span>
63 - </div>
64 - <n-collapse-transition :show="!showBadgesToggle || showBadges">
65 - <SocAlertItemBadges v-if="alert" class="badges-box" :alert :users @updated="updateAlert" />
66 - </n-collapse-transition>
67 - </div>
42 + <template #mainExtra>
43 + <div class="flex justify-between gap-3">
44 + <div>
45 + <div
46 + v-if="showBadgesToggle"
47 + class="show-badges-toggle flex items-center gap-2"
48 + @click.stop="showBadges = !showBadges"
49 + >
50 + {{ showBadges ? "Less info" : "More info" }}
51 + <span class="flex items-center transition-transform" :class="{ 'rotate-90': showBadges }">
52 + <Icon :name="ChevronIcon" :size="14"></Icon>
53 + </span>
54 + </div>
55 + <n-collapse-transition :show="!showBadgesToggle || showBadges">
56 + <SocAlertItemBadges v-if="alert" :alert :users @updated="updateAlert" />
57 + </n-collapse-transition>
58 + </div>
59
69 - <div class="footer-box flex justify-between items-center gap-4">
70 - <SocAlertItemActions
71 - v-if="!hideSocCaseAction"
72 - class="actions-box grow !flex-wrap !justify-start"
73 - style="flex-direction: initial"
74 - size="small"
75 - :case-id
76 - :alert-id="alert.alert_id"
77 - @case-created="caseCreated($event)"
78 - @deleted="deleted()"
79 - @start-deleting="loadingDelete = true"
80 - />
81 - <div class="time">
82 - <SocAlertItemTime :alert hide-timeline />
83 - </div>
84 - </div>
85 - </div>
86 - <n-collapse>
87 - <template #arrow>
88 - <div class="mx-5 flex">
89 - <Icon :name="ChevronIcon"></Icon>
60 + <SocAlertItemActions
61 + v-if="!hideSocCaseAction && alert"
62 + class="flex flex-row flex-wrap gap-2"
63 + size="small"
64 + :case-id
65 + :alert-id="alert.alert_id"
66 + @case-created="caseCreated($event)"
67 + @deleted="deleted()"
68 + @start-deleting="loadingDelete = true"
69 + />
70 </div>
71 </template>
92 - <n-collapse-item>
93 - <template #header>
94 - <div class="py-3 -ml-2">Alert details</div>
95 - </template>
96 - <AlertItem :alert="alertObject" hide-actions class="-mt-4" />
97 - </n-collapse-item>
98 - </n-collapse>
72 + <template #footer>
73 + <n-collapse>
74 + <template #arrow>
75 + <div class="mx-5 flex">
76 + <Icon :name="ChevronIcon"></Icon>
77 + </div>
78 + </template>
79 + <n-collapse-item>
80 + <template #header>
81 + <div class="-ml-2 py-3">Alert details</div>
82 + </template>
83 + <AlertItem :alert="alertObject" hide-actions class="-mt-4" />
84 + </n-collapse-item>
85 + </n-collapse>
86 + </template>
87 + </CardEntity>
88
89 <n-modal
90 v-model:show="showDetails"
@@ -114,7 +103,7 @@
103 </template>
104 <SocAlertItemDetails v-if="alert" :alert :users @updated="updateAlert" />
105 </n-modal>
117 - </n-spin>
106 + </div>
107 </template>
108
109 <script setup lang="ts">
@@ -122,8 +111,9 @@ import type { Alert } from "@/types/alerts.d"
111 import type { SocAlert } from "@/types/soc/alert.d"
112 import type { SocUser } from "@/types/soc/user.d"
113 import Api from "@/api"
114 +import CardEntity from "@/components/common/cards/CardEntity.vue"
115 import Icon from "@/components/common/Icon.vue"
126 -import { NCheckbox, NCollapse, NCollapseItem, NCollapseTransition, NModal, NSpin, useMessage } from "naive-ui"
116 +import { NCheckbox, NCollapse, NCollapseItem, NCollapseTransition, NModal, useMessage } from "naive-ui"
117 import { computed, defineAsyncComponent, onBeforeMount, ref, toRefs, watch } from "vue"
118 import SocAlertItemActions from "./SocAlertItemActions.vue"
119 import SocAlertItemBookmarkToggler from "./SocAlertItemBookmarkToggler.vue"
@@ -169,7 +159,6 @@ const {
159 } = toRefs(props)
160
161 const ChevronIcon = "carbon:chevron-right"
172 -const InfoIcon = "carbon:information"
162
163 const showDetails = ref(false)
164 const showBadges = ref(false)
@@ -254,96 +243,13 @@ onBeforeMount(() => {
243 </script>
244
245 <style lang="scss" scoped>
257 -.soc-alert-item {
258 - transition: all 0.2s var(--bezier-ease);
259 -
260 - .soc-alert-info {
261 - border-bottom: var(--border-small-050);
262 -
263 - .header-box {
264 - font-family: var(--font-family-mono);
265 - font-size: 13px;
266 - .id {
267 - word-break: break-word;
268 - color: var(--fg-secondary-color);
269 - line-height: 1.2;
270 -
271 - &:hover {
272 - color: var(--primary-color);
273 - }
274 - }
275 - }
276 -
277 - .main-box {
278 - .content {
279 - word-break: break-word;
280 -
281 - .description {
282 - color: var(--fg-secondary-color);
283 - font-size: 13px;
284 - }
285 - }
286 - }
287 -
288 - .show-badges-toggle {
289 - font-size: 14px;
290 - cursor: pointer;
291 - transition: color 0.2s var(--bezier-ease);
292 -
293 - &:hover {
294 - color: var(--primary-color);
295 - }
296 - }
297 -
298 - .footer-box {
299 - font-size: 13px;
300 - margin-top: 10px;
301 - display: none;
302 - }
303 - }
246 +.show-badges-toggle {
247 + font-size: 14px;
248 + cursor: pointer;
249 + transition: color 0.2s var(--bezier-ease);
250
305 - &.bookmarked {
306 - background-color: var(--primary-005-color);
307 - border-color: var(--primary-030-color);
308 - }
309 -
310 - &:not(.embedded) {
311 - border-radius: var(--border-radius);
312 - background-color: var(--bg-color);
313 - border: var(--border-small-050);
314 -
315 - &:hover,
316 - &.highlight {
317 - border-color: var(--primary-color);
318 - }
319 - }
320 -
321 - @container (max-width: 650px) {
322 - .soc-alert-info {
323 - .header-box {
324 - .time {
325 - display: none;
326 - }
327 - }
328 -
329 - .main-box {
330 - .actions-box {
331 - display: none;
332 - }
333 - .badges-box {
334 - :deep() {
335 - .badge {
336 - &.hide-on-small {
337 - display: none;
338 - }
339 - }
340 - }
341 - }
342 - }
343 - .footer-box {
344 - display: flex;
345 - }
346 - }
251 + &:hover {
252 + color: var(--primary-color);
253 }
254 }
255 </style>
frontend/src/components/soc/SocAlerts/SocAlertItem/SocAlertItemActions.vue
+5 -5
@@ -1,6 +1,6 @@
1 <template>
2 - <div class="soc-alert-actions flex flex-col gap-2 justify-center">
3 - <n-button v-if="existCase" type="success" secondary :size="size" @click="openSocCase()">
2 + <div class="contents">
3 + <n-button v-if="existCase" type="success" secondary :size="size" @click.stop="openSocCase()">
4 <template #icon>
5 <Icon :name="ViewIcon"></Icon>
6 </template>
@@ -12,7 +12,7 @@
12 type="warning"
13 secondary
14 :size="size"
15 - @click="createCase()"
15 + @click.stop="createCase()"
16 >
17 <template #icon>
18 <Icon :name="DangerIcon"></Icon>
@@ -25,7 +25,7 @@
25 :size="size"
26 type="error"
27 secondary
28 - @click="handleDelete()"
28 + @click.stop="handleDelete()"
29 >
30 <template #icon>
31 <Icon :name="DeleteIcon"></Icon>
@@ -42,7 +42,7 @@
42 :bordered="false"
43 segmented
44 >
45 - <div class="h-full w-full flex items-center justify-center">
45 + <div class="flex h-full w-full items-center justify-center">
46 <SocCaseItem
47 v-if="caseId"
48 :case-id="caseId"
frontend/src/components/soc/SocAlerts/SocAlertItem/SocAlertItemBadges.vue
+4 -4
@@ -1,5 +1,5 @@
1 <template>
2 - <div class="flex flex-wrap items-center gap-3 mt-3">
2 + <div class="@container flex flex-wrap items-center gap-3">
3 <n-tooltip placement="top-start" trigger="hover">
4 <template #trigger>
5 <Badge type="splitted" color="primary" hint-cursor>
@@ -23,7 +23,7 @@
23 {{ alert.severity?.severity_name || "-" }}
24 </template>
25 </Badge>
26 - <Badge type="splitted" color="primary" class="hide-on-small">
26 + <Badge type="splitted" color="primary" class="@2xl:!flex !hidden">
27 <template #iconLeft>
28 <Icon :name="SourceIcon" :size="13"></Icon>
29 </template>
@@ -32,7 +32,7 @@
32 {{ alert.alert_source || "-" }}
33 </template>
34 </Badge>
35 - <Badge type="splitted" color="primary" class="hide-on-small">
35 + <Badge type="splitted" color="primary" class="@2xl:!flex !hidden">
36 <template #iconLeft>
37 <Icon :name="CustomerIcon" :size="13"></Icon>
38 </template>
@@ -40,7 +40,7 @@
40 <template #value>
41 <template v-if="alert.customer?.customer_code && alert.customer.customer_code !== 'Customer Not Found'">
42 <code
43 - class="cursor-pointer text-primary-color"
43 + class="text-primary cursor-pointer"
44 @click="gotoCustomer({ code: alert.customer.customer_code })"
45 >
46 {{ alert.customer?.customer_name || alert.customer.customer_code || "-" }}
frontend/src/components/soc/SocAlerts/SocAlertItem/SocAlertItemBookmarkToggler.vue
+1 -1
@@ -4,7 +4,7 @@
4 :size="16"
5 class="toggler-bookmark"
6 :class="{ active: isBookmark }"
7 - @click="toggleBookmark()"
7 + @click.stop="toggleBookmark()"
8 ></Icon>
9 </template>
10
frontend/src/components/soc/SocAlerts/SocAlertItem/SocAlertItemContext.vue
+4 -4
@@ -6,8 +6,8 @@
6 </template>
7 </n-input>
8
9 - <div class="grid gap-2 grid-auto-fit-200">
10 - <KVCard v-for="{ value, key } of contextFiltered" :key="key">
9 + <div class="grid-auto-fit-200 grid gap-2">
10 + <CardKV v-for="{ value, key } of contextFiltered" :key="key">
11 <template #key>
12 {{ key }}
13 </template>
@@ -28,15 +28,15 @@
28 <ExpandableText :text="value.toString() ?? '-'" :max-length="100" />
29 </template>
30 </template>
31 - </KVCard>
31 + </CardKV>
32 </div>
33 </div>
34 </template>
35
36 <script setup lang="ts">
37 import type { SocAlert } from "@/types/soc/alert.d"
38 +import CardKV from "@/components/common/cards/CardKV.vue"
39 import Icon from "@/components/common/Icon.vue"
39 -import KVCard from "@/components/common/KVCard.vue"
40 import _compact from "lodash/compact"
41 import _split from "lodash/split"
42 import _uniq from "lodash/uniq"
frontend/src/components/soc/SocAlerts/SocAlertItem/SocAlertItemDetails.vue
+14 -17
@@ -9,17 +9,14 @@
9 </div>
10 </n-tab-pane>
11 <n-tab-pane name="Customer" tab="Customer" display-directive="show:lazy">
12 - <div class="grid gap-2 grid-auto-fit-200 p-7 pt-4">
13 - <KVCard v-for="(value, key) of alert.customer" :key="key">
12 + <div class="grid-auto-fit-200 grid gap-2 p-7 pt-4">
13 + <CardKV v-for="(value, key) of alert.customer" :key="key">
14 <template #key>
15 {{ key }}
16 </template>
17 <template #value>
18 <template v-if="key === 'customer_code' && value && value !== 'Customer Not Found'">
19 - <code
20 - class="cursor-pointer text-primary-color"
21 - @click="gotoCustomer({ code: value.toString() })"
22 - >
19 + <code class="text-primary cursor-pointer" @click="gotoCustomer({ code: value.toString() })">
20 #{{ value }}
21 <Icon :name="LinkIcon" :size="13" class="relative top-0.5" />
22 </code>
@@ -28,7 +25,7 @@
25 {{ value || "-" }}
26 </template>
27 </template>
31 - </KVCard>
28 + </CardKV>
29 </div>
30 </n-tab-pane>
31 <n-tab-pane name="Owner" tab="Owner" display-directive="show:lazy">
@@ -40,8 +37,8 @@
37 <template #label>Go to users page</template>
38 </Badge>
39 </div>
43 - <div class="grid gap-2 grid-auto-fit-200 p-7 pt-4">
44 - <KVCard>
40 + <div class="grid-auto-fit-200 grid gap-2 p-7 pt-4">
41 + <CardKV>
42 <template #key>user_login</template>
43 <template #value>
44 <SocAssignUser
@@ -50,7 +47,7 @@
47 :users="users"
48 @updated="emit('updated', $event)"
49 >
53 - <div class="flex items-center gap-2 cursor-pointer text-primary-color">
50 + <div class="text-primary flex cursor-pointer items-center gap-2">
51 <n-spin :size="16" :show="loading">
52 <Icon :name="EditIcon" :size="16"></Icon>
53 </n-spin>
@@ -58,20 +55,20 @@
55 </div>
56 </SocAssignUser>
57 </template>
61 - </KVCard>
62 - <KVCard v-if="alert.owner">
58 + </CardKV>
59 + <CardKV v-if="alert.owner">
60 <template #key>user_name</template>
61 <template #value>
62 <span>#{{ alert.owner.id }}</span>
63 {{ alert.owner.user_name }}
64 </template>
68 - </KVCard>
69 - <KVCard v-if="alert.owner">
65 + </CardKV>
66 + <CardKV v-if="alert.owner">
67 <template #key>user_email</template>
68 <template #value>
69 {{ alert.owner.user_email }}
70 </template>
74 - </KVCard>
71 + </CardKV>
72 </div>
73 </n-tab-pane>
74 <n-tab-pane name="History" tab="History" display-directive="show:lazy">
@@ -94,13 +91,13 @@
91 import type { SocAlert } from "@/types/soc/alert.d"
92 import type { SocUser } from "@/types/soc/user.d"
93 import Badge from "@/components/common/Badge.vue"
94 +import CardKV from "@/components/common/cards/CardKV.vue"
95 import Icon from "@/components/common/Icon.vue"
98 -import KVCard from "@/components/common/KVCard.vue"
96 import { useGoto } from "@/composables/useGoto"
97 import { NSpin, NTabPane, NTabs } from "naive-ui"
98 import { computed, defineAsyncComponent } from "vue"
99 import { SimpleJsonViewer } from "vue-sjv"
103 -import "@/assets/scss/vuesjv-override.scss"
100 +import "@/assets/scss/overrides/vuesjv-override.scss"
101
102 const { alert } = defineProps<{
103 alert: SocAlert
frontend/src/components/soc/SocAlerts/SocAlertItem/SocAlertItemTime.vue
+1 -1
@@ -8,7 +8,7 @@
8 <Icon v-if="!hideTimeline" :name="TimeIcon" :size="16"></Icon>
9 </div>
10 </template>
11 - <div class="flex flex-col py-2 px-1">
11 + <div class="flex flex-col px-1 py-2">
12 <SocAlertItemTimeline :alert="alert" />
13 </div>
14 </n-popover>
frontend/src/components/soc/SocAlerts/SocAlertsBookmarks.vue
+1 -1
@@ -24,7 +24,7 @@
24 />
25 </template>
26 <template v-else>
27 - <n-empty v-if="!loadingBookmarks" description="No items found" class="justify-center h-48" />
27 + <n-empty v-if="!loadingBookmarks" description="No items found" class="h-48 justify-center" />
28 </template>
29 </div>
30 </n-spin>
frontend/src/components/soc/SocAlerts/SocAlertsList.vue
+4 -16
@@ -1,6 +1,6 @@
1 <template>
2 <div class="soc-alerts-list">
3 - <div ref="header" class="header flex items-center justify-end gap-2">
3 + <div ref="header" class="flex h-14 items-center justify-end gap-2">
4 <slot name="header"></slot>
5 <div class="grow">
6 <n-input v-model:value="alertTitle" size="small" placeholder="Search by title..." clearable />
@@ -47,7 +47,7 @@
47 <n-button v-else size="small" type="error" ghost :loading="loadingPurge" @click="handlePurge()">
48 <div class="flex items-center gap-2">
49 <Icon :name="TrashIcon" :size="16"></Icon>
50 - <span class="hidden xs:block">Purge</span>
50 + <span class="xs:block hidden">Purge</span>
51 </div>
52 </n-button>
53 </div>
@@ -62,7 +62,7 @@
62 </div>
63
64 <n-spin :show="loadingAlerts || loadingPurge">
65 - <div class="list">
65 + <div class="min-h-52">
66 <template v-if="alertsList.length">
67 <SocAlertItem
68 v-for="alert of alertsList"
@@ -81,7 +81,7 @@
81 />
82 </template>
83 <template v-else>
84 - <n-empty v-if="!loadingAlerts" description="No items found" class="justify-center h-48" />
84 + <n-empty v-if="!loadingAlerts" description="No items found" class="h-48 justify-center" />
85 </template>
86 </div>
87 </n-spin>
@@ -393,15 +393,3 @@ onBeforeUnmount(() => {
393 abortController?.abort()
394 })
395 </script>
396 -
397 -<style lang="scss" scoped>
398 -.soc-alerts-list {
399 - .header {
400 - height: 50px;
401 - }
402 - .list {
403 - container-type: inline-size;
404 - min-height: 200px;
405 - }
406 -}
407 -</style>
frontend/src/components/soc/SocCases/SocCaseAssetLink.vue
+59 -100
@@ -1,73 +1,67 @@
1 <template>
2 - <div class="soc-asset-link">
3 - <div class="flex flex-col gap-2 px-5 py-4 pb-2">
4 - <div class="header-box flex justify-between">
5 - <div class="flex items-center gap-2 cursor-helper">
6 - <div class="id flex items-center gap-2">
7 - <span>{{ link.case_name }}</span>
8 - </div>
9 - </div>
2 + <CardEntity>
3 + <template #header>{{ link.case_name }}</template>
4 + <template v-if="link.asset_description" #default>
5 + <p>
6 + {{ link.asset_description }}
7 + </p>
8 + </template>
9 + <template #mainExtra>
10 + <div class="flex flex-wrap items-center gap-3">
11 + <Badge type="splitted" color="primary">
12 + <template #label>Case open date</template>
13 + <template #value>
14 + {{ formatDate(link.case_open_date) }}
15 + </template>
16 + </Badge>
17 + <Badge type="splitted" color="primary">
18 + <template #label>Asset id</template>
19 + <template #value>
20 + {{ link.asset_id }}
21 + </template>
22 + </Badge>
23 + <Badge type="splitted" color="primary">
24 + <template #label>Compromise status</template>
25 + <template #value>
26 + {{ link.asset_compromise_status_id || "-" }}
27 + </template>
28 + </Badge>
29 </div>
11 - <div class="main-box flex justify-between gap-4">
12 - <div class="content">
13 - <div v-if="link.asset_description" class="description mt-2">
14 - {{ link.asset_description }}
15 - </div>
30 + </template>
31
17 - <div class="badges-box flex flex-wrap items-center gap-3 mt-4">
18 - <Badge type="splitted" color="primary">
19 - <template #label>Case open date</template>
20 - <template #value>
21 - {{ formatDate(link.case_open_date) }}
22 - </template>
23 - </Badge>
24 - <Badge type="splitted" color="primary">
25 - <template #label>Asset id</template>
26 - <template #value>
27 - {{ link.asset_id }}
28 - </template>
29 - </Badge>
30 - <Badge type="splitted" color="primary">
31 - <template #label>Compromise status</template>
32 - <template #value>
33 - {{ link.asset_compromise_status_id || "-" }}
34 - </template>
35 - </Badge>
32 + <template #footer>
33 + <n-collapse @item-header-click="showSocCase($event.expanded)">
34 + <template #arrow>
35 + <div class="mx-5 flex">
36 + <Icon :name="ChevronIcon"></Icon>
37 </div>
37 - </div>
38 - </div>
39 - </div>
40 - <n-collapse @item-header-click="showSocCase($event.expanded)">
41 - <template #arrow>
42 - <div class="mx-5 flex">
43 - <Icon :name="ChevronIcon"></Icon>
44 - </div>
45 - </template>
46 - <n-collapse-item>
47 - <template #header>
48 - <div class="py-3 -ml-2">SOC Case details</div>
38 </template>
50 - <div style="min-height: 50px">
51 - <n-spin :show="loadingCase">
52 - <SocCaseItem
53 - v-if="socCase"
54 - :case-data="socCase"
55 - :embedded="true"
56 - class="py-2 -mt-4"
57 - @deleted="getSocCase(link.case_id)"
58 - />
59 - <template v-else>
60 - <n-empty
61 - v-if="!loadingCase"
62 - description="No Case found"
63 - class="justify-center h-28 -mt-4"
39 + <n-collapse-item>
40 + <template #header>
41 + <div class="-ml-2 py-3">SOC Case details</div>
42 + </template>
43 + <div style="min-height: 50px">
44 + <n-spin :show="loadingCase">
45 + <SocCaseItem
46 + v-if="socCase"
47 + :case-data="socCase"
48 + :embedded="true"
49 + class="-mt-4 py-2"
50 + @deleted="getSocCase(link.case_id)"
51 />
65 - </template>
66 - </n-spin>
67 - </div>
68 - </n-collapse-item>
69 - </n-collapse>
70 - </div>
52 + <template v-else>
53 + <n-empty
54 + v-if="!loadingCase"
55 + description="No Case found"
56 + class="-mt-4 h-28 justify-center"
57 + />
58 + </template>
59 + </n-spin>
60 + </div>
61 + </n-collapse-item>
62 + </n-collapse>
63 + </template>
64 + </CardEntity>
65 </template>
66
67 <script setup lang="ts">
@@ -75,6 +69,7 @@ import type { SocCaseAssetLink } from "@/types/soc/asset.d"
69 import type { SocCase } from "@/types/soc/case.d"
70 import Api from "@/api"
71 import Badge from "@/components/common/Badge.vue"
72 +import CardEntity from "@/components/common/cards/CardEntity.vue"
73 import Icon from "@/components/common/Icon.vue"
74 import { useSettingsStore } from "@/stores/settings"
75 import dayjs from "@/utils/dayjs"
@@ -122,39 +117,3 @@ function getSocCase(caseId: string | number) {
117 })
118 }
119 </script>
125 -
126 -<style lang="scss" scoped>
127 -.soc-asset-link {
128 - border-radius: var(--border-radius);
129 - background-color: var(--bg-secondary-color);
130 - transition: all 0.2s var(--bezier-ease);
131 - border: var(--border-small-050);
132 - container-type: inline-size;
133 -
134 - .header-box {
135 - font-family: var(--font-family-mono);
136 - font-size: 13px;
137 - .id {
138 - word-break: break-word;
139 - color: var(--fg-secondary-color);
140 - line-height: 1.2;
141 -
142 - &:hover {
143 - color: var(--primary-color);
144 - }
145 - }
146 - }
147 -
148 - .main-box {
149 - word-break: break-word;
150 -
151 - .description {
152 - font-size: 13px;
153 - }
154 - }
155 -
156 - &:hover {
157 - box-shadow: 0px 0px 0px 1px inset var(--primary-color);
158 - }
159 -}
160 -</style>
frontend/src/components/soc/SocCases/SocCaseAssetsItem.vue
+55 -114
@@ -1,18 +1,11 @@
1 <template>
2 - <div class="soc-asset-item">
3 - <div class="flex flex-col gap-2 px-5 py-4">
4 - <div class="header-box flex justify-between">
5 - <div class="flex items-center gap-2">
6 - <div class="id flex items-center gap-2 cursor-pointer" @click="showDetails = true">
7 - <span>#{{ asset.asset_id }} - {{ asset.asset_uuid }}</span>
8 - <Icon :name="InfoIcon" :size="16"></Icon>
9 - </div>
10 - </div>
11 - </div>
12 - <div class="main-box flex justify-between gap-4">
13 - <div class="content">
14 - <div class="title" v-html="asset.asset_name"></div>
15 - <div v-if="asset.asset_description" class="description mt-2">
2 + <div>
3 + <CardEntity clickable hoverable @click.stop="showDetails = true">
4 + <template #headerMain>#{{ asset.asset_id }} - {{ asset.asset_uuid }}</template>
5 + <template #default>
6 + <div class="flex flex-col gap-1">
7 + <div v-html="asset.asset_name"></div>
8 + <p v-if="asset.asset_description">
9 <template v-if="isUrlLike(asset.asset_description)">
10 <a
11 :href="asset.asset_description"
@@ -21,7 +14,7 @@
14 alt="asset url"
15 rel="nofollow noopener noreferrer"
16 >
24 - <code class="text-primary-color">
17 + <code class="text-primary">
18 <span>
19 {{ asset.asset_description }}
20 </span>
@@ -32,33 +25,34 @@
25 <template v-else>
26 {{ excerpt }}
27 </template>
35 - </div>
36 -
37 - <div class="badges-box flex flex-wrap items-center gap-3 mt-4">
38 - <Badge type="splitted" color="primary">
39 - <template #label>Status</template>
40 - <template #value>
41 - {{ asset.analysis_status }}
42 - </template>
43 - </Badge>
44 - <Badge type="splitted" color="primary">
45 - <template #label>Type</template>
46 - <template #value>
47 - {{ asset.asset_type }}
48 - </template>
49 - </Badge>
50 - <Badge v-for="tag of tags" :key="tag.key" type="splitted" color="primary">
51 - <template #label>
52 - {{ tag.key }}
53 - </template>
54 - <template v-if="tag.value !== undefined" #value>
55 - {{ tag.value || "-" }}
56 - </template>
57 - </Badge>
58 - </div>
28 + </p>
29 + </div>
30 + </template>
31 + <template #mainExtra>
32 + <div class="flex flex-wrap items-center gap-3">
33 + <Badge type="splitted" color="primary">
34 + <template #label>Status</template>
35 + <template #value>
36 + {{ asset.analysis_status }}
37 + </template>
38 + </Badge>
39 + <Badge type="splitted" color="primary">
40 + <template #label>Type</template>
41 + <template #value>
42 + {{ asset.asset_type }}
43 + </template>
44 + </Badge>
45 + <Badge v-for="tag of tags" :key="tag.key" type="splitted" color="primary">
46 + <template #label>
47 + {{ tag.key }}
48 + </template>
49 + <template v-if="tag.value !== undefined" #value>
50 + {{ tag.value || "-" }}
51 + </template>
52 + </Badge>
53 </div>
60 - </div>
61 - </div>
54 + </template>
55 + </CardEntity>
56
57 <n-modal
58 v-model:show="showDetails"
@@ -71,15 +65,15 @@
65 >
66 <n-tabs type="line" animated :tabs-padding="24">
67 <n-tab-pane name="Info" tab="Info" display-directive="show">
74 - <div v-if="properties" class="grid gap-2 grid-auto-fit-200 p-7 pt-4">
75 - <KVCard v-for="(value, key) of properties" :key="key">
68 + <div v-if="properties" class="grid-auto-fit-200 grid gap-2 p-7 pt-4">
69 + <CardKV v-for="(value, key) of properties" :key="key">
70 <template #key>
71 {{ key }}
72 </template>
73 <template #value>
74 {{ value || "-" }}
75 </template>
82 - </KVCard>
76 + </CardKV>
77 </div>
78 </n-tab-pane>
79 <n-tab-pane name="Description" tab="Description" display-directive="show">
@@ -101,7 +95,7 @@
95 </div>
96 </n-tab-pane>
97 <n-tab-pane name="Link" tab="Link" display-directive="show:lazy">
104 - <div v-if="asset.link?.length" class="px-4 flex flex-col gap-2">
98 + <div v-if="asset.link?.length" class="flex flex-col gap-2 px-4">
99 <SocCaseAssetLink
100 v-for="link of asset.link"
101 :key="`${link.case_id}-${link.asset_id}`"
@@ -109,7 +103,7 @@
103 />
104 </div>
105 <template v-else>
112 - <n-empty description="No items found" class="justify-center h-48" />
106 + <n-empty description="No items found" class="h-48 justify-center" />
107 </template>
108 </n-tab-pane>
109 </n-tabs>
@@ -120,8 +114,9 @@
114 <script setup lang="ts">
115 import type { SocCaseAsset } from "@/types/soc/asset.d"
116 import Badge from "@/components/common/Badge.vue"
117 +import CardEntity from "@/components/common/cards/CardEntity.vue"
118 +import CardKV from "@/components/common/cards/CardKV.vue"
119 import Icon from "@/components/common/Icon.vue"
124 -import KVCard from "@/components/common/KVCard.vue"
120 import { isUrlLike } from "@/utils"
121 import _omit from "lodash/omit"
122 import _split from "lodash/split"
@@ -133,7 +128,6 @@ const { asset } = defineProps<{ asset: SocCaseAsset }>()
128
129 const SocCaseAssetLink = defineAsyncComponent(() => import("./SocCaseAssetLink.vue"))
130
136 -const InfoIcon = "carbon:information"
131 const LinkIcon = "carbon:launch"
132
133 const showDetails = ref(false)
@@ -174,73 +168,20 @@ const properties = computed(() => {
168 </script>
169
170 <style lang="scss" scoped>
177 -.soc-asset-item {
178 - border-radius: var(--border-radius);
179 - background-color: var(--bg-secondary-color);
180 - transition: all 0.2s var(--bezier-ease);
181 - border: var(--border-small-050);
182 -
183 - .header-box {
184 - font-family: var(--font-family-mono);
185 - font-size: 13px;
186 - .id {
187 - word-break: break-word;
188 - color: var(--fg-secondary-color);
189 - line-height: 1.2;
190 -
191 - &:hover {
192 - color: var(--primary-color);
193 - }
194 - }
195 -
196 - .toggler-bookmark {
197 - &.active {
198 - color: var(--primary-color);
199 - }
200 - &:hover {
201 - color: var(--primary-color);
202 - }
171 +.asset-url {
172 + display: block;
173 +
174 + code {
175 + padding: 8px 12px;
176 + display: flex;
177 + gap: 10px;
178 +
179 + span {
180 + white-space: nowrap;
181 + flex-grow: 1;
182 + overflow: hidden;
183 + text-overflow: ellipsis;
184 }
204 - .time {
205 - color: var(--fg-secondary-color);
206 -
207 - &:hover {
208 - color: var(--primary-color);
209 - }
210 - }
211 - }
212 -
213 - .main-box {
214 - word-break: break-word;
215 - .content {
216 - max-width: 100%;
217 -
218 - .description {
219 - color: var(--fg-secondary-color);
220 - font-size: 13px;
221 -
222 - .asset-url {
223 - display: block;
224 -
225 - code {
226 - padding: 8px 12px;
227 - display: flex;
228 - gap: 10px;
229 -
230 - span {
231 - white-space: nowrap;
232 - flex-grow: 1;
233 - overflow: hidden;
234 - text-overflow: ellipsis;
235 - }
236 - }
237 - }
238 - }
239 - }
240 - }
241 -
242 - &:hover {
243 - box-shadow: 0px 0px 0px 1px inset var(--primary-color);
185 }
186 }
187 </style>
frontend/src/components/soc/SocCases/SocCaseAssetsList.vue
+2 -2
@@ -11,11 +11,11 @@
11 <code>{{ formatDateTime(assetsState.object_last_update) }}</code>
12 </div>
13 </div>
14 - <div v-if="assetsList?.length" class="p-7 flex flex-col gap-2">
14 + <div v-if="assetsList?.length" class="flex flex-col gap-2 p-7">
15 <SocCaseAssetsItem v-for="asset of assetsList" :key="asset.asset_id" :asset="asset" />
16 </div>
17 <template v-else>
18 - <n-empty v-if="!loadingAssets" description="No items found" class="justify-center h-48" />
18 + <n-empty v-if="!loadingAssets" description="No items found" class="h-48 justify-center" />
19 </template>
20 </n-spin>
21 </div>
frontend/src/components/soc/SocCases/SocCaseItem.vue
+220 -332
@@ -1,266 +1,242 @@
1 <template>
2 - <n-spin
3 - :show="loadingDetails || loadingDelete"
4 - :description="loadingDelete ? 'Deleting Soc Case' : 'Loading Soc Case'"
5 - >
6 - <div class="soc-case-item" :class="{ embedded }">
7 - <div v-if="baseInfo" class="flex flex-col gap-2 px-5 py-3">
8 - <div class="header-box flex justify-between">
9 - <div class="flex items-center gap-2">
10 - <div class="id flex items-center gap-2 cursor-pointer" @click="showDetails = true">
11 - <span>{{ baseInfo.case_uuid }}</span>
12 - <Icon :name="InfoIcon" :size="16"></Icon>
13 - </div>
14 - </div>
15 - <div v-if="caseOpenDate" class="time">
16 - <n-popover overlap placement="top-end">
17 - <template #trigger>
18 - <div class="flex items-center gap-2 cursor-help">
19 - <span>
20 - {{ formatDate(caseOpenDate) }}
21 - </span>
22 - <Icon :name="TimeIcon" :size="16"></Icon>
23 - </div>
24 - </template>
25 - <div class="flex flex-col py-2 px-1">
26 - <n-timeline>
27 - <n-timeline-item
28 - type="success"
29 - :title="`Open ${openedBy ? `[${openedBy}]` : ''}`"
30 - :time="formatDate(caseOpenDate)"
31 - />
32 - <n-timeline-item
33 - v-if="caseCloseDate"
34 - title="Close date"
35 - :time="formatDate(caseCloseDate)"
36 - />
37 - </n-timeline>
38 - </div>
39 - </n-popover>
40 - </div>
41 - </div>
42 - <div class="main-box flex items-center justify-between gap-4">
43 - <div class="content">
44 - <div class="title" v-html="baseInfo.case_name"></div>
45 - <div v-if="baseInfo.case_description" class="description mt-2">
46 - {{ excerpt }}
47 - </div>
48 -
49 - <div class="badges-box flex flex-wrap items-center gap-3 mt-4">
50 - <Badge
51 - type="splitted"
52 - :color="baseInfo.state_name === StateName.Open ? 'warning' : 'primary'"
53 - >
54 - <template #iconLeft>
55 - <Icon :name="StatusIcon" :size="14"></Icon>
56 - </template>
57 - <template #label>State</template>
58 - <template #value>
59 - {{ baseInfo.state_name }}
60 - </template>
61 - </Badge>
62 - <Badge type="splitted" color="primary">
63 - <template #iconLeft>
64 - <Icon :name="OwnerIcon" :size="16"></Icon>
65 - </template>
66 - <template #label>Owner</template>
67 - <template #value>
68 - {{ baseInfo.owner }}
69 - </template>
70 - </Badge>
71 - <Badge type="splitted" color="primary">
72 - <template #iconLeft>
73 - <Icon :name="CustomerIcon" :size="13"></Icon>
74 - </template>
75 - <template #label>Client</template>
76 - <template #value>
77 - {{ clientName || "-" }}
78 - </template>
79 - </Badge>
80 - <Badge
81 - v-if="baseInfo.case_soc_id && !hideSocAlertLink"
82 - type="active"
83 - class="cursor-pointer"
84 - @click="openSocAlert()"
85 - >
86 - <template #iconRight>
87 - <Icon :name="LinkIcon" :size="14"></Icon>
88 - </template>
89 - <template #label>Alert #{{ baseInfo.case_soc_id }}</template>
90 - </Badge>
2 + <div>
3 + <CardEntity
4 + :loading="loadingDetails || loadingDelete"
5 + :loading-description="loadingDelete ? 'Deleting Soc Case' : 'Loading Soc Case'"
6 + :embedded
7 + hoverable
8 + clickable
9 + @click.stop="showDetails = true"
10 + >
11 + <template #headerMain>{{ baseInfo?.case_uuid }}</template>
12 + <template v-if="caseOpenDate" #headerExtra>
13 + <n-popover overlap placement="top-end">
14 + <template #trigger>
15 + <div class="hover:text-primary flex cursor-help items-center gap-2">
16 + <span>
17 + {{ formatDate(caseOpenDate) }}
18 + </span>
19 + <Icon :name="TimeIcon" :size="16"></Icon>
20 </div>
21 + </template>
22 + <div class="flex flex-col px-1 py-2">
23 + <n-timeline>
24 + <n-timeline-item
25 + type="success"
26 + :title="`Open ${openedBy ? `[${openedBy}]` : ''}`"
27 + :time="formatDate(caseOpenDate)"
28 + />
29 + <n-timeline-item
30 + v-if="caseCloseDate"
31 + title="Close date"
32 + :time="formatDate(caseCloseDate)"
33 + />
34 + </n-timeline>
35 </div>
93 - <SocCaseItemActions
94 - v-if="!hideSocCaseAction"
95 - class="actions-box"
96 - :case-data="baseInfo"
97 - @closed="setClosed()"
98 - @reopened="setReopened()"
99 - @deleted="deleteCase()"
100 - @start-deleting="loadingDelete = true"
101 - />
36 + </n-popover>
37 + </template>
38 + <template #default>
39 + <div class="flex flex-col gap-1">
40 + <div v-html="baseInfo?.case_name"></div>
41 + <p v-if="baseInfo?.case_description">
42 + {{ excerpt }}
43 + </p>
44 </div>
103 - <div class="footer-box flex justify-between items-center gap-3">
104 - <SocCaseItemActions
105 - v-if="!hideSocCaseAction"
106 - class="actions-box !flex-row"
107 - :case-data="baseInfo"
108 - size="small"
109 - @closed="setClosed()"
110 - @reopened="setReopened()"
111 - @deleted="deleteCase()"
112 - @start-deleting="loadingDelete = true"
113 - />
114 - <div v-if="caseOpenDate" class="time">
115 - {{ formatDate(caseOpenDate) }}
116 - </div>
45 + </template>
46 + <template v-if="baseInfo" #mainExtra>
47 + <div class="flex flex-wrap items-center gap-3">
48 + <Badge type="splitted" :color="baseInfo.state_name === StateName.Open ? 'warning' : 'primary'">
49 + <template #iconLeft>
50 + <Icon :name="StatusIcon" :size="14"></Icon>
51 + </template>
52 + <template #label>State</template>
53 + <template #value>
54 + {{ baseInfo.state_name }}
55 + </template>
56 + </Badge>
57 + <Badge type="splitted" color="primary">
58 + <template #iconLeft>
59 + <Icon :name="OwnerIcon" :size="16"></Icon>
60 + </template>
61 + <template #label>Owner</template>
62 + <template #value>
63 + {{ baseInfo.owner }}
64 + </template>
65 + </Badge>
66 + <Badge type="splitted" color="primary">
67 + <template #iconLeft>
68 + <Icon :name="CustomerIcon" :size="13"></Icon>
69 + </template>
70 + <template #label>Client</template>
71 + <template #value>
72 + {{ clientName || "-" }}
73 + </template>
74 + </Badge>
75 + <Badge
76 + v-if="baseInfo.case_soc_id && !hideSocAlertLink"
77 + type="active"
78 + class="cursor-pointer"
79 + @click.stop="openSocAlert()"
80 + >
81 + <template #iconRight>
82 + <Icon :name="LinkIcon" :size="14"></Icon>
83 + </template>
84 + <template #label>Alert #{{ baseInfo.case_soc_id }}</template>
85 + </Badge>
86 </div>
87 + </template>
88 + <template #footerExtra>
89 + <SocCaseItemActions
90 + v-if="!hideSocCaseAction"
91 + class="flex flex-col justify-center gap-2"
92 + :case-data="baseInfo"
93 + size="small"
94 + @closed="setClosed()"
95 + @reopened="setReopened()"
96 + @deleted="deleteCase()"
97 + @start-deleting="loadingDelete = true"
98 + />
99 + </template>
100 + </CardEntity>
101 +
102 + <n-modal
103 + v-model:show="showSocAlertDetails"
104 + preset="card"
105 + content-class="!p-0"
106 + :style="{ maxWidth: 'min(800px, 90vw)', minHeight: 'min(250px, 90vh)', overflow: 'hidden' }"
107 + :title="`SOC Alert: #${baseInfo?.case_soc_id}`"
108 + :bordered="false"
109 + segmented
110 + >
111 + <div class="flex h-full w-full items-center justify-center">
112 + <SocAlertItem
113 + v-if="baseInfo?.case_soc_id"
114 + :alert-id="baseInfo.case_soc_id"
115 + embedded
116 + hide-bookmark-action
117 + hide-soc-case-action
118 + class="w-full"
119 + />
120 </div>
119 -
120 - <n-modal
121 - v-model:show="showSocAlertDetails"
122 - preset="card"
123 - content-class="!p-0"
124 - :style="{ maxWidth: 'min(800px, 90vw)', minHeight: 'min(250px, 90vh)', overflow: 'hidden' }"
125 - :title="`SOC Alert: #${baseInfo?.case_soc_id}`"
126 - :bordered="false"
127 - segmented
128 - >
129 - <div class="h-full w-full flex items-center justify-center">
130 - <SocAlertItem
131 - v-if="baseInfo?.case_soc_id"
132 - :alert-id="baseInfo.case_soc_id"
133 - embedded
134 - hide-bookmark-action
135 - hide-soc-case-action
136 - class="w-full"
137 - />
138 - </div>
139 - </n-modal>
140 -
141 - <n-modal
142 - v-model:show="showDetails"
143 - preset="card"
144 - content-class="!p-0"
145 - :style="{ maxWidth: 'min(800px, 90vw)', minHeight: 'min(550px, 90vh)', overflow: 'hidden' }"
146 - :title="`SOC Case: ${baseInfo?.case_uuid}`"
147 - :bordered="false"
148 - segmented
149 - >
150 - <n-tabs type="line" animated :tabs-padding="24">
151 - <n-tab-pane name="Info" tab="Info" display-directive="show">
152 - <n-spin :show="loadingDetails">
153 - <div v-if="extendedInfo" class="px-7 py-4">
154 - <div v-if="tags.length" class="flex gap-2 mb-2">
155 - <code v-for="tag of tags" :key="tag">{{ tag }}</code>
156 - </div>
157 - <div>{{ extendedInfo.case_name }}</div>
121 + </n-modal>
122 +
123 + <n-modal
124 + v-model:show="showDetails"
125 + preset="card"
126 + content-class="!p-0"
127 + :style="{ maxWidth: 'min(800px, 90vw)', minHeight: 'min(550px, 90vh)', overflow: 'hidden' }"
128 + :title="`SOC Case: ${baseInfo?.case_uuid}`"
129 + :bordered="false"
130 + segmented
131 + >
132 + <n-tabs type="line" animated :tabs-padding="24">
133 + <n-tab-pane name="Info" tab="Info" display-directive="show">
134 + <n-spin :show="loadingDetails">
135 + <div v-if="extendedInfo" class="px-7 py-4">
136 + <div v-if="tags.length" class="mb-2 flex gap-2">
137 + <code v-for="tag of tags" :key="tag">{{ tag }}</code>
138 </div>
159 - <div v-if="extendedInfo" class="flex flex-col gap-2 px-7 py-4">
160 - <div v-if="baseInfo && !hideSocAlertLink" class="box">
161 - soc id:
162 - <code class="cursor-pointer text-primary-color" @click="openSocAlert()">
163 - #{{ baseInfo.case_soc_id }}
164 - <Icon :name="LinkIcon" :size="13" class="relative top-0.5" />
165 - </code>
166 - </div>
167 - <div v-if="extendedInfo?.protagonists && extendedInfo?.protagonists.length" class="box">
168 - protagonists:
169 - <code
170 - v-for="protagonist of extendedInfo.protagonists"
171 - :key="protagonist"
172 - class="mr-2"
173 - >
174 - {{ protagonist }}
175 - </code>
176 - </div>
139 + <div>{{ extendedInfo.case_name }}</div>
140 + </div>
141 + <div v-if="extendedInfo" class="flex flex-col gap-2 px-7 py-4">
142 + <div v-if="baseInfo && !hideSocAlertLink" class="box">
143 + soc id:
144 + <code class="text-primary cursor-pointer" @click.stop="openSocAlert()">
145 + #{{ baseInfo.case_soc_id }}
146 + <Icon :name="LinkIcon" :size="13" class="relative top-0.5" />
147 + </code>
148 </div>
178 - <div v-if="properties" class="grid gap-2 grid-auto-fit-200 p-7 pt-4">
179 - <KVCard v-for="(value, key) of properties" :key="key">
180 - <template #key>
181 - {{ key }}
182 - </template>
183 - <template #value>
184 - <template
185 - v-if="key === 'customer_code' && value && value !== 'Customer Not Found'"
186 - >
187 - <code
188 - class="cursor-pointer text-primary-color"
189 - @click="gotoCustomer({ code: value })"
190 - >
191 - #{{ value }}
192 - <Icon :name="LinkIcon" :size="13" class="relative top-0.5" />
193 - </code>
194 - </template>
195 - <template v-else>
196 - {{ value || "-" }}
197 - </template>
198 - </template>
199 - </KVCard>
149 + <div v-if="extendedInfo?.protagonists && extendedInfo?.protagonists.length" class="box">
150 + protagonists:
151 + <code v-for="protagonist of extendedInfo.protagonists" :key="protagonist" class="mr-2">
152 + {{ protagonist }}
153 + </code>
154 </div>
201 - </n-spin>
202 - </n-tab-pane>
203 - <n-tab-pane name="Description" tab="Description" display-directive="show">
204 - <div v-if="baseInfo" class="p-7 pt-4">
205 - <n-input
206 - :value="baseInfo.case_description"
207 - type="textarea"
208 - readonly
209 - placeholder="Empty"
210 - size="large"
211 - :autosize="{
212 - minRows: 3
213 - }"
214 - />
155 </div>
216 - </n-tab-pane>
217 - <n-tab-pane name="History" tab="History" display-directive="show:lazy">
218 - <n-spin :show="loadingDetails">
219 - <div class="p-7 pt-4">
220 - <SocCaseTimeline v-if="extendedInfo" :case-data="extendedInfo" />
221 - </div>
222 - </n-spin>
223 - </n-tab-pane>
224 - <n-tab-pane name="Assets" tab="Assets" display-directive="show:lazy">
225 - <SocCaseAssetsList v-if="baseInfo" :case-id="baseInfo.case_id" />
226 - </n-tab-pane>
227 - <n-tab-pane name="Notes" tab="Notes" display-directive="show:lazy">
228 - <div class="px-4">
229 - <n-collapse v-model:expanded-names="noteFormVisible" display-directive="show">
230 - <template #arrow>
231 - <div class="mx-4 flex">
232 - <Icon :name="AddIcon"></Icon>
233 - </div>
156 + <div v-if="properties" class="grid-auto-fit-200 grid gap-2 p-7 pt-4">
157 + <CardKV v-for="(value, key) of properties" :key="key">
158 + <template #key>
159 + {{ key }}
160 </template>
235 - <n-collapse-item name="1">
236 - <template #header>
237 - <div class="py-3 -ml-2">New note</div>
161 + <template #value>
162 + <template v-if="key === 'customer_code' && value && value !== 'Customer Not Found'">
163 + <code
164 + class="text-primary cursor-pointer"
165 + @click.stop="gotoCustomer({ code: value })"
166 + >
167 + #{{ value }}
168 + <Icon :name="LinkIcon" :size="13" class="relative top-0.5" />
169 + </code>
170 + </template>
171 + <template v-else>
172 + {{ value || "-" }}
173 </template>
239 - <div class="p-3 pt-0 -mt-2">
240 - <SocCaseNoteForm
241 - v-if="baseInfo"
242 - :case-id="baseInfo.case_id"
243 - @close="noteFormVisible = []"
244 - @added="updateNotes = true"
245 - />
246 - </div>
247 - </n-collapse-item>
248 - </n-collapse>
174 + </template>
175 + </CardKV>
176 + </div>
177 + </n-spin>
178 + </n-tab-pane>
179 + <n-tab-pane name="Description" tab="Description" display-directive="show">
180 + <div v-if="baseInfo" class="p-7 pt-4">
181 + <n-input
182 + :value="baseInfo.case_description"
183 + type="textarea"
184 + readonly
185 + placeholder="Empty"
186 + size="large"
187 + :autosize="{
188 + minRows: 3
189 + }"
190 + />
191 + </div>
192 + </n-tab-pane>
193 + <n-tab-pane name="History" tab="History" display-directive="show:lazy">
194 + <n-spin :show="loadingDetails">
195 + <div class="p-7 pt-4">
196 + <SocCaseTimeline v-if="extendedInfo" :case-data="extendedInfo" />
197 </div>
250 - <n-divider class="!my-2" />
251 - <SocCaseNotesList v-if="baseInfo" v-model:requested="updateNotes" :case-id="baseInfo.case_id" />
252 - </n-tab-pane>
253 - </n-tabs>
254 - </n-modal>
255 - </div>
256 - </n-spin>
198 + </n-spin>
199 + </n-tab-pane>
200 + <n-tab-pane name="Assets" tab="Assets" display-directive="show:lazy">
201 + <SocCaseAssetsList v-if="baseInfo" :case-id="baseInfo.case_id" />
202 + </n-tab-pane>
203 + <n-tab-pane name="Notes" tab="Notes" display-directive="show:lazy">
204 + <div class="px-4">
205 + <n-collapse v-model:expanded-names="noteFormVisible" display-directive="show">
206 + <template #arrow>
207 + <div class="mx-4 flex">
208 + <Icon :name="AddIcon"></Icon>
209 + </div>
210 + </template>
211 + <n-collapse-item name="1">
212 + <template #header>
213 + <div class="-ml-2 py-3">New note</div>
214 + </template>
215 + <div class="-mt-2 p-3 pt-0">
216 + <SocCaseNoteForm
217 + v-if="baseInfo"
218 + :case-id="baseInfo.case_id"
219 + @close="noteFormVisible = []"
220 + @added="updateNotes = true"
221 + />
222 + </div>
223 + </n-collapse-item>
224 + </n-collapse>
225 + </div>
226 + <n-divider class="!my-2" />
227 + <SocCaseNotesList v-if="baseInfo" v-model:requested="updateNotes" :case-id="baseInfo.case_id" />
228 + </n-tab-pane>
229 + </n-tabs>
230 + </n-modal>
231 + </div>
232 </template>
233
234 <script setup lang="ts">
235 import Api from "@/api"
236 import Badge from "@/components/common/Badge.vue"
237 +import CardEntity from "@/components/common/cards/CardEntity.vue"
238 +import CardKV from "@/components/common/cards/CardKV.vue"
239 import Icon from "@/components/common/Icon.vue"
263 -import KVCard from "@/components/common/KVCard.vue"
240 import { useGoto } from "@/composables/useGoto"
241 import { useSettingsStore } from "@/stores/settings"
242 import { type SocCase, type SocCaseExt, StateName } from "@/types/soc/case.d"
@@ -301,7 +277,6 @@ const SocCaseItemActions = defineAsyncComponent(() => import("./SocCaseItemActio
277 const SocAlertItem = defineAsyncComponent(() => import("../SocAlerts/SocAlertItem/SocAlertItem.vue"))
278
279 const TimeIcon = "carbon:time"
304 -const InfoIcon = "carbon:information"
280 const CustomerIcon = "carbon:user"
281 const LinkIcon = "carbon:launch"
282 const OwnerIcon = "carbon:user-military"
@@ -458,90 +433,3 @@ onBeforeMount(() => {
433 }
434 })
435 </script>
461 -
462 -<style lang="scss" scoped>
463 -.soc-case-item {
464 - border-top: var(--border-small-050);
465 - transition: all 0.2s var(--bezier-ease);
466 - min-height: 100px;
467 -
468 - .header-box {
469 - font-family: var(--font-family-mono);
470 - font-size: 13px;
471 - .id {
472 - word-break: break-word;
473 - color: var(--fg-secondary-color);
474 - line-height: 1.2;
475 -
476 - &:hover {
477 - color: var(--primary-color);
478 - }
479 - }
480 -
481 - .toggler-bookmark {
482 - &.active {
483 - color: var(--primary-color);
484 - }
485 - &:hover {
486 - color: var(--primary-color);
487 - }
488 - }
489 - .time {
490 - color: var(--fg-secondary-color);
491 -
492 - &:hover {
493 - color: var(--primary-color);
494 - }
495 - }
496 - }
497 -
498 - .main-box {
499 - word-break: break-word;
500 -
501 - .description {
502 - color: var(--fg-secondary-color);
503 - font-size: 13px;
504 - }
505 - }
506 -
507 - .footer-box {
508 - font-size: 13px;
509 - margin-top: 10px;
510 - display: none;
511 -
512 - .time {
513 - text-align: right;
514 - font-family: var(--font-family-mono);
515 - color: var(--fg-secondary-color);
516 - }
517 - }
518 -
519 - &:not(.embedded) {
520 - border-radius: var(--border-radius);
521 - background-color: var(--bg-color);
522 - border: var(--border-small-050);
523 -
524 - &:hover {
525 - border-color: var(--primary-color);
526 - }
527 - }
528 -
529 - @container (max-width: 650px) {
530 - .header-box {
531 - .time {
532 - display: none;
533 - }
534 - }
535 -
536 - .main-box {
537 - .actions-box {
538 - display: none;
539 - }
540 - }
541 -
542 - .footer-box {
543 - display: flex;
544 - }
545 - }
546 -}
547 -</style>
frontend/src/components/soc/SocCases/SocCaseItemActions.vue
+4 -4
@@ -1,25 +1,25 @@
1 <template>
2 - <div class="soc-case-actions flex flex-col gap-2 justify-center">
2 + <div class="contents">
3 <n-button
4 v-if="isCaseClosed"
5 :loading="loadingCaseReopen"
6 :size="size"
7 type="warning"
8 secondary
9 - @click="reopenCase()"
9 + @click.stop="reopenCase()"
10 >
11 <template #icon>
12 <Icon :name="OpenIcon"></Icon>
13 </template>
14 Reopen
15 </n-button>
16 - <n-button v-else :loading="loadingCaseClose" type="success" secondary :size="size" @click="closeCase()">
16 + <n-button v-else :loading="loadingCaseClose" type="success" secondary :size="size" @click.stop="closeCase()">
17 <template #icon>
18 <Icon :name="CloseIcon"></Icon>
19 </template>
20 Close
21 </n-button>
22 - <n-button :loading="loadingCaseDelete" :size="size" type="error" secondary @click="handleDelete()">
22 + <n-button :loading="loadingCaseDelete" :size="size" type="error" secondary @click.stop="handleDelete()">
23 <template #icon>
24 <Icon :name="DeleteIcon"></Icon>
25 </template>
frontend/src/components/soc/SocCases/SocCaseNote.vue
+47 -123
@@ -1,60 +1,51 @@
1 <template>
2 - <div class="soc-case-note">
3 - <div class="flex flex-col gap-2 px-5 py-4">
4 - <div class="header-box flex justify-between">
5 - <div class="flex items-center gap-2">
6 - <div class="id flex items-center gap-2 cursor-pointer" @click="showDetails = true">
7 - <span>#{{ note.note_id }} - {{ note.note_details.note_uuid }}</span>
8 - <Icon :name="InfoIcon" :size="16"></Icon>
9 - </div>
10 - </div>
11 - <div class="time">
12 - <n-popover overlap placement="top-end">
13 - <template #trigger>
14 - <div class="flex items-center gap-2 cursor-help">
15 - <span>
16 - {{ formatDateTime(note.note_details.note_creationdate) }}
17 - </span>
18 - <Icon :name="TimeIcon" :size="16"></Icon>
19 - </div>
20 - </template>
21 - <div class="flex flex-col py-2 px-1">
22 - <SocCaseNoteTimeline :note="note" />
2 + <div>
3 + <CardEntity hoverable clickable @click.stop="showDetails = true">
4 + <template #headerMain>#{{ note.note_id }} - {{ note.note_details.note_uuid }}</template>
5 + <template #headerExtra>
6 + <n-popover overlap placement="top-end">
7 + <template #trigger>
8 + <div class="hover:text-primary flex cursor-help items-center gap-2">
9 + <span>
10 + {{ formatDateTime(note.note_details.note_creationdate) }}
11 + </span>
12 + <Icon :name="TimeIcon" :size="16"></Icon>
13 </div>
24 - </n-popover>
25 - </div>
26 - </div>
27 - <div class="main-box flex justify-between gap-4">
28 - <div class="content">
29 - <div class="title" v-html="note.note_title"></div>
30 - <div v-if="note.note_details.note_content" class="description mt-2">
31 - {{ excerpt }}
14 + </template>
15 + <div class="flex flex-col px-1 py-2">
16 + <SocCaseNoteTimeline :note="note" />
17 </div>
18 + </n-popover>
19 + </template>
20
34 - <!--
35 - <div class="badges-box flex flex-wrap items-center gap-3 mt-4">
36 - <Badge type="splitted" color="primary">
37 - <template #label>Status</template>
38 - <template #value>{{ asset.analysis_status }}</template>
39 - </Badge>
40 - <Badge type="splitted" color="primary">
41 - <template #label>Type</template>
42 - <template #value>{{ asset.asset_type }}</template>
43 - </Badge>
44 - <Badge type="splitted" color="primary" v-for="tag of tags" :key="tag.key">
45 - <template #label>{{ tag.key }}</template>
46 - <template #value v-if="tag.value !== undefined">{{ tag.value || "-" }}</template>
47 - </Badge>
48 - </div>
49 - -->
21 + <template #default>
22 + <div class="flex flex-col gap-1">
23 + <div v-html="note.note_title"></div>
24 + <p v-if="note.note_details.note_content">
25 + {{ excerpt }}
26 + </p>
27 </div>
51 - </div>
52 - <div class="footer-box flex justify-end items-center gap-3">
53 - <div class="time">
54 - {{ formatDateTime(note.note_details.note_creationdate) }}
28 + </template>
29 +
30 + <!--
31 + <template #mainExtra>
32 + <div class="flex flex-wrap items-center gap-3">
33 + <Badge type="splitted" color="primary">
34 + <template #label>Status</template>
35 + <template #value>{{ asset.analysis_status }}</template>
36 + </Badge>
37 + <Badge type="splitted" color="primary">
38 + <template #label>Type</template>
39 + <template #value>{{ asset.asset_type }}</template>
40 + </Badge>
41 + <Badge v-for="tag of tags" :key="tag.key" type="splitted" color="primary">
42 + <template #label>{{ tag.key }}</template>
43 + <template v-if="tag.value !== undefined" #value>{{ tag.value || "-" }}</template>
44 + </Badge>
45 </div>
56 - </div>
57 - </div>
46 + </template>
47 + -->
48 + </CardEntity>
49
50 <n-modal
51 v-model:show="showDetails"
@@ -67,15 +58,15 @@
58 >
59 <n-tabs type="line" animated :tabs-padding="24">
60 <n-tab-pane name="Info" tab="Info" display-directive="show">
70 - <div v-if="properties" class="grid gap-2 grid-auto-fit-200 p-7 pt-4">
71 - <KVCard v-for="(value, key) of properties" :key="key">
61 + <div v-if="properties" class="grid-auto-fit-200 grid gap-2 p-7 pt-4">
62 + <CardKV v-for="(value, key) of properties" :key="key">
63 <template #key>
64 {{ key }}
65 </template>
66 <template #value>
67 {{ value || "-" }}
68 </template>
78 - </KVCard>
69 + </CardKV>
70 </div>
71 </n-tab-pane>
72 <n-tab-pane name="Content" tab="Content" display-directive="show">
@@ -105,8 +96,9 @@
96
97 <script setup lang="ts">
98 import type { SocNote } from "@/types/soc/note.d"
99 +import CardEntity from "@/components/common/cards/CardEntity.vue"
100 +import CardKV from "@/components/common/cards/CardKV.vue"
101 import Icon from "@/components/common/Icon.vue"
109 -import KVCard from "@/components/common/KVCard.vue"
102 import { useSettingsStore } from "@/stores/settings"
103 import dayjs from "@/utils/dayjs"
104 import _omit from "lodash/omit"
@@ -117,7 +109,6 @@ const { note } = defineProps<{ note: SocNote }>()
109
110 const SocCaseNoteTimeline = defineAsyncComponent(() => import("./SocCaseNoteTimeline.vue"))
111
120 -const InfoIcon = "carbon:information"
112 const TimeIcon = "carbon:time"
113
114 const showDetails = ref(false)
@@ -138,70 +129,3 @@ const properties = computed(() => {
129 return _omit(note.note_details, ["note_content", "custom_attributes", "note_creationdate", "note_lastupdate"])
130 })
131 </script>
141 -
142 -<style lang="scss" scoped>
143 -.soc-case-note {
144 - border-radius: var(--border-radius);
145 - background-color: var(--bg-secondary-color);
146 - transition: all 0.2s var(--bezier-ease);
147 - border: var(--border-small-050);
148 -
149 - .header-box {
150 - font-family: var(--font-family-mono);
151 - font-size: 13px;
152 - .id {
153 - word-break: break-word;
154 - color: var(--fg-secondary-color);
155 - line-height: 1.2;
156 -
157 - &:hover {
158 - color: var(--primary-color);
159 - }
160 - }
161 -
162 - .time {
163 - color: var(--fg-secondary-color);
164 -
165 - &:hover {
166 - color: var(--primary-color);
167 - }
168 - }
169 - }
170 -
171 - .main-box {
172 - word-break: break-word;
173 -
174 - .description {
175 - color: var(--fg-secondary-color);
176 - font-size: 13px;
177 - }
178 - }
179 -
180 - .footer-box {
181 - font-family: var(--font-family-mono);
182 - font-size: 13px;
183 - margin-top: 10px;
184 - display: none;
185 -
186 - .time {
187 - text-align: right;
188 - color: var(--fg-secondary-color);
189 - }
190 - }
191 -
192 - &:hover {
193 - box-shadow: 0px 0px 0px 1px inset var(--primary-color);
194 - }
195 -
196 - @container (max-width: 650px) {
197 - .header-box {
198 - .time {
199 - display: none;
200 - }
201 - }
202 - .footer-box {
203 - display: flex;
204 - }
205 - }
206 -}
207 -</style>
frontend/src/components/soc/SocCases/SocCaseNoteForm.vue
+1 -1
@@ -12,7 +12,7 @@
12 maxRows: 10
13 }"
14 />
15 - <div class="flex gap-2 justify-end">
15 + <div class="flex justify-end gap-2">
16 <n-button :disabled="loading" secondary class="!w-32" @click="clear(true)">Close</n-button>
17 <n-button :disabled="loading || !title" secondary type="primary" class="!w-32" @click="addNote()">
18 Submit
frontend/src/components/soc/SocCases/SocCaseNotesList.vue
+3 -3
@@ -3,12 +3,12 @@
3 <div class="px-7 pt-4">
4 <n-input v-model:value="notesFilter" placeholder="Search notes..." clearable />
5 </div>
6 - <n-spin :show="loadingNotes" style="min-height: 100px">
7 - <div v-if="notesList?.length" class="p-7 pt-3 flex flex-col gap-2" style="container-type: inline-size">
6 + <n-spin :show="loadingNotes" class="min-h-28">
7 + <div v-if="notesList?.length" class="flex flex-col gap-2 p-7 pt-3" style="container-type: inline-size">
8 <SocCaseNote v-for="note of notesList" :key="note.note_id" :note="note" />
9 </div>
10 <template v-else>
11 - <n-empty v-if="!loadingNotes" description="No items found" class="justify-center h-48" />
11 + <n-empty v-if="!loadingNotes" description="No items found" class="h-48 justify-center" />
12 </template>
13 </n-spin>
14 </div>
frontend/src/components/soc/SocCases/SocCasesList.vue
+8 -17
@@ -1,10 +1,10 @@
1 <template>
2 <div class="soc-cases-list">
3 <div ref="header" class="header flex items-center justify-end gap-2">
4 - <div class="info grow flex gap-2">
4 + <div class="info flex grow gap-2">
5 <n-popover overlap placement="bottom-start">
6 <template #trigger>
7 - <div class="bg-color border-radius">
7 + <div class="bg-default rounded-default">
8 <n-button size="small" class="!cursor-help">
9 <template #icon>
10 <Icon :name="InfoIcon"></Icon>
@@ -30,7 +30,7 @@
30 >
31 <div class="flex items-center gap-2">
32 <Icon :name="TrashIcon" :size="16"></Icon>
33 - <span class="hidden xs:block">Purge</span>
33 + <span class="xs:block hidden">Purge</span>
34 </div>
35 </n-button>
36 </div>
@@ -45,7 +45,7 @@
45 />
46 <n-popover :show="showFilters" trigger="manual" overlap placement="right" class="!px-0">
47 <template #trigger>
48 - <div class="bg-color border-radius">
48 + <div class="bg-default rounded-default">
49 <n-badge :show="filtered" dot type="success" :offset="[-4, 0]">
50 <n-button size="small" @click="showFilters = true">
51 <template #icon>
@@ -55,7 +55,7 @@
55 </n-badge>
56 </div>
57 </template>
58 - <div class="py-1 flex flex-col gap-2">
58 + <div class="flex flex-col gap-2 py-1">
59 <div class="px-3">
60 <small>Cases older then:</small>
61 </div>
@@ -76,7 +76,7 @@
76 />
77 </n-input-group>
78 </div>
79 - <div class="px-3 flex justify-end gap-2">
79 + <div class="flex justify-end gap-2 px-3">
80 <n-button size="small" secondary @click="showFilters = false">Close</n-button>
81 <n-button size="small" type="primary" secondary @click="getData()">Submit</n-button>
82 </div>
@@ -84,7 +84,7 @@
84 </n-popover>
85 </div>
86 <n-spin :show="loading">
87 - <div class="list flex flex-col gap-2 my-3">
87 + <div class="my-3 flex min-h-52 flex-col gap-2">
88 <template v-if="casesList.length">
89 <SocCaseItem
90 v-for="caseData of itemsPaginated"
@@ -95,7 +95,7 @@
95 />
96 </template>
97 <template v-else>
98 - <n-empty v-if="!loading" description="No items found" class="justify-center h-48" />
98 + <n-empty v-if="!loading" description="No items found" class="h-48 justify-center" />
99 </template>
100 </div>
101 </n-spin>
@@ -267,12 +267,3 @@ onBeforeMount(() => {
267 getData()
268 })
269 </script>
270 -
271 -<style lang="scss" scoped>
272 -.soc-cases-list {
273 - .list {
274 - container-type: inline-size;
275 - min-height: 200px;
276 - }
277 -}
278 -</style>
frontend/src/components/soc/SocUsers/SocUserAlerts.vue
+3 -3
@@ -1,7 +1,7 @@
1 <template>
2 <n-spin :show="loadingAlerts" :size="14">
3 - <div v-if="!loadingAlerts" class="flex alert-list items-center gap-3">
4 - <span :class="{ 'text-secondary-color': !alertsList.length, 'font-bold': alertsList.length }">
3 + <div v-if="!loadingAlerts" class="alert-list flex items-center gap-3">
4 + <span :class="{ 'text-secondary': !alertsList.length, 'font-bold': alertsList.length }">
5 {{ alertsList.length || "No Alters" }}
6 </span>
7 <div class="flex flex-wrap gap-2">
@@ -24,7 +24,7 @@
24 :bordered="false"
25 segmented
26 >
27 - <div class="h-full w-full flex items-center justify-center">
27 + <div class="flex h-full w-full items-center justify-center">
28 <SocAlertItem
29 v-if="selectedAlertId"
30 :alert-id="selectedAlertId"
frontend/src/components/soc/SocUsers/SocUsersList.vue
+1 -1
@@ -19,7 +19,7 @@
19 :class="{ highlight: highlight === user.user_id.toString() }"
20 >
21 <td>
22 - <div class="flex gap-3 items-center">
22 + <div class="flex items-center gap-3">
23 <span>#{{ user.user_id }}</span>
24 <n-tooltip trigger="hover">
25 <template #trigger>
frontend/src/components/stackProvisioning/StackProvisioningItem.vue
+23 -81
@@ -1,45 +1,32 @@
1 <template>
2 - <div class="item flex flex-col gap-2 px-5 py-3">
3 - <div class="header-box flex justify-between gap-4">
4 - <div class="name">
5 - {{ contentPack.name }}
6 - </div>
7 - </div>
8 - <div class="main-box flex justify-between gap-4">
9 - <div class="description">
10 - {{ contentPack.description }}
11 - </div>
12 - <div class="actions-box">
13 - <n-button :loading="loadingProvision" type="success" secondary @click="provision(contentPack.name)">
14 - <template #icon>
15 - <Icon :name="DeployIcon"></Icon>
16 - </template>
17 - Deploy
18 - </n-button>
19 - </div>
20 - </div>
21 - <div class="footer-box flex justify-between items-center gap-4">
22 - <div class="actions-box">
23 - <n-button
24 - :loading="loadingProvision"
25 - type="success"
26 - secondary
27 - size="small"
28 - @click="provision(contentPack.name)"
29 - >
30 - <template #icon>
31 - <Icon :name="DeployIcon"></Icon>
32 - </template>
33 - Deploy
34 - </n-button>
35 - </div>
36 - </div>
37 - </div>
2 + <CardEntity embedded hoverable>
3 + <template #headerMain>
4 + {{ contentPack.name }}
5 + </template>
6 + <template #default>
7 + {{ contentPack.description }}
8 + </template>
9 + <template #headerExtra>
10 + <n-button
11 + :loading="loadingProvision"
12 + type="success"
13 + size="small"
14 + secondary
15 + @click="provision(contentPack.name)"
16 + >
17 + <template #icon>
18 + <Icon :name="DeployIcon"></Icon>
19 + </template>
20 + Deploy
21 + </n-button>
22 + </template>
23 + </CardEntity>
24 </template>
25
26 <script setup lang="ts">
27 import type { AvailableContentPack } from "@/types/stackProvisioning.d"
28 import Api from "@/api"
29 +import CardEntity from "@/components/common/cards/CardEntity.vue"
30 import Icon from "@/components/common/Icon.vue"
31 import { NButton, useMessage } from "naive-ui"
32 import { ref } from "vue"
@@ -75,48 +62,3 @@ function provision(contentPackName: string) {
62 })
63 }
64 </script>
78 -
79 -<style lang="scss" scoped>
80 -.item {
81 - border-radius: var(--border-radius);
82 - background-color: var(--bg-secondary-color);
83 - transition: all 0.2s var(--bezier-ease);
84 - border: var(--border-small-050);
85 -
86 - .header-box {
87 - font-size: 13px;
88 -
89 - .name {
90 - font-family: var(--font-family-mono);
91 - word-break: break-word;
92 - color: var(--fg-secondary-color);
93 - }
94 - }
95 - .main-box {
96 - .description {
97 - word-break: break-word;
98 - }
99 - }
100 -
101 - .footer-box {
102 - display: none;
103 - font-size: 13px;
104 - margin-top: 10px;
105 - }
106 -
107 - &:hover {
108 - box-shadow: 0px 0px 0px 1px inset var(--primary-color);
109 - }
110 -
111 - @container (max-width: 450px) {
112 - .main-box {
113 - .actions-box {
114 - display: none;
115 - }
116 - }
117 - .footer-box {
118 - display: flex;
119 - }
120 - }
121 -}
122 -</style>
frontend/src/components/stackProvisioning/StackProvisioningList.vue
+2 -2
@@ -1,12 +1,12 @@
1 <template>
2 <div class="stack-provisioning-list">
3 <n-spin :show="loading">
4 - <div class="list flex flex-col gap-2 my-3">
4 + <div class="list my-3 flex flex-col gap-2">
5 <template v-if="list.length">
6 <StackProvisioningItem v-for="item of list" :key="item.name" :content-pack="item" />
7 </template>
8 <template v-else>
9 - <n-empty v-if="!loading" description="No items found" class="justify-center h-48" />
9 + <n-empty v-if="!loading" description="No items found" class="h-48 justify-center" />
10 </template>
11 </div>
12 </n-spin>
frontend/src/components/threatIntel/ThreatIntelEpssScore.vue
+7 -7
@@ -1,21 +1,21 @@
1 <template>
2 <n-spin :show="loading" content-class="min-h-32">
3 <div class="mb-4">
4 - <KVCard>
4 + <CardKV>
5 <template #key>cve</template>
6 <template #value>
7 {{ cve }}
8 </template>
9 - </KVCard>
9 + </CardKV>
10 </div>
11 <div v-if="epssList.length" class="flex flex-col gap-3">
12 <n-card
13 v-for="item of epssList"
14 :key="item.___id"
15 - content-class="bg-secondary-color"
16 - class="overflow-hidden item-appear item-appear-bottom item-appear-005"
15 + content-class="bg-secondary"
16 + class="item-appear item-appear-bottom item-appear-005 overflow-hidden"
17 >
18 - <div class="flex justify-between gap-8 xs:!flex-row flex-col">
18 + <div class="xs:!flex-row flex flex-col justify-between gap-8">
19 <n-statistic class="grow" label="Date">
20 <span class="stats-value whitespace-nowrap">
21 {{ formatDate(item.date, dFormats.date) }}
@@ -39,7 +39,7 @@
39 </p>
40 </div>
41 <template v-else>
42 - <n-empty v-if="!loading" description="No items found" class="justify-center h-48" />
42 + <n-empty v-if="!loading" description="No items found" class="h-48 justify-center" />
43 </template>
44 </n-spin>
45 </template>
@@ -47,7 +47,7 @@
47 <script setup lang="ts">
48 import type { EpssScore } from "@/types/threatIntel.d"
49 import Api from "@/api"
50 -import KVCard from "@/components/common/KVCard.vue"
50 +import CardKV from "@/components/common/cards/CardKV.vue"
51 import { useSettingsStore } from "@/stores/settings"
52 import { formatDate } from "@/utils"
53 import { NCard, NEmpty, NSpin, NStatistic, useMessage } from "naive-ui"
frontend/src/components/threatIntel/ThreatIntelProcessEvaluationBadge.vue
+1 -1
@@ -1,6 +1,6 @@
1 <template>
2 <ThreatIntelProcessEvaluationProvider v-slot="{ openEvaluation }" :process-name>
3 - <code class="cursor-pointer text-primary-color" @click="openEvaluation()">
3 + <code class="text-primary cursor-pointer" @click="openEvaluation()">
4 {{ processName }}
5 <Icon :name="LinkIcon" :size="13" class="relative top-0.5" />
6 </code>
frontend/src/components/threatIntel/ThreatIntelProcessEvaluationProvider.vue
+3 -3
@@ -19,8 +19,8 @@
19 class="flex flex-col gap-4 !py-8"
20 >
21 <div class="px-7">
22 - <n-card content-class="bg-secondary-color" class="overflow-hidden">
23 - <div class="flex justify-between gap-8 flex-wrap">
22 + <n-card content-class="bg-secondary" class="overflow-hidden">
23 + <div class="flex flex-wrap justify-between gap-8">
24 <n-statistic label="Rank" :value="evaluation.rank" tabular-nums />
25 <n-statistic label="EPS" :value="eps" tabular-nums />
26 <n-statistic label="Host Prevalence" :value="`${evaluation.host_prev}%`" tabular-nums />
@@ -80,7 +80,7 @@
80 />
81 </n-tab-pane>
82 </n-tabs>
83 - <n-empty v-if="!loading && !evaluation" description="Evaluation not found" class="justify-center h-48" />
83 + <n-empty v-if="!loading && !evaluation" description="Evaluation not found" class="h-48 justify-center" />
84 </n-spin>
85 </n-modal>
86 </template>
frontend/src/components/webVulnerabilityAssessment/ReportsItem.vue
+28 -61
@@ -1,10 +1,10 @@
1 <template>
2 - <n-spin :show="canceling">
3 - <div class="item flex flex-col gap-2 px-5 py-3" @click="openReport()">
4 - <div class="header-box flex justify-between">
2 + <div>
3 + <CardEntity :loading="canceling" hoverable clickable @click.stop="openReport()">
4 + <template #default>
5 {{ report }}
6 - </div>
7 - <div class="footer-box flex justify-end">
6 + </template>
7 + <template #footerExtra>
8 <n-popconfirm
9 v-model:show="showConfirm"
10 trigger="manual"
@@ -12,40 +12,37 @@
12 @clickoutside="showConfirm = false"
13 >
14 <template #trigger>
15 - <div class="delete-btn" @click.stop="showConfirm = true">delete</div>
15 + <n-button quaternary size="tiny" @click.stop="showConfirm = true">delete</n-button>
16 </template>
17 Are you sure you want to delete the report?
18 </n-popconfirm>
19 - </div>
20 -
21 - <n-modal
22 - v-model:show="showDetails"
23 - preset="card"
24 - :style="{ maxWidth: 'min(800px, 90vw)', minHeight: 'min(400px, 90vh)', overflow: 'hidden' }"
25 - :title="report"
26 - :bordered="false"
27 - segmented
28 - >
29 - <n-spin :show="loading" class="min-h-48">
30 - <n-page-header v-if="reportNavigation.length > 1" title="index" class="mb-3" @back="pageBack" />
31 - <Suspense>
32 - <Markdown :source="reportMarkdown || ''" @click="checkEvent($event)" />
33 - </Suspense>
34 - <n-empty
35 - v-if="!loading && !reportMarkdown"
36 - description="Page not found"
37 - class="justify-center h-48"
38 - />
39 - </n-spin>
40 - </n-modal>
41 - </div>
42 - </n-spin>
19 + </template>
20 + </CardEntity>
21 +
22 + <n-modal
23 + v-model:show="showDetails"
24 + preset="card"
25 + :style="{ maxWidth: 'min(800px, 90vw)', minHeight: 'min(400px, 90vh)', overflow: 'hidden' }"
26 + :title="report"
27 + :bordered="false"
28 + segmented
29 + >
30 + <n-spin :show="loading" class="min-h-48">
31 + <n-page-header v-if="reportNavigation.length > 1" title="index" class="mb-3" @back="pageBack" />
32 + <Suspense>
33 + <Markdown :source="reportMarkdown || ''" @click.stop="checkEvent($event)" />
34 + </Suspense>
35 + <n-empty v-if="!loading && !reportMarkdown" description="Page not found" class="h-48 justify-center" />
36 + </n-spin>
37 + </n-modal>
38 + </div>
39 </template>
40
41 <script setup lang="ts">
42 import type { NucleiReport } from "@/types/webVulnerabilityAssessment.d"
43 import Api from "@/api"
48 -import { NEmpty, NModal, NPageHeader, NPopconfirm, NSpin, useMessage } from "naive-ui"
44 +import CardEntity from "@/components/common/cards/CardEntity.vue"
45 +import { NButton, NEmpty, NModal, NPageHeader, NPopconfirm, NSpin, useMessage } from "naive-ui"
46 import { computed, defineAsyncComponent, ref, watch } from "vue"
47
48 const { report } = defineProps<{ report: NucleiReport }>()
@@ -145,33 +142,3 @@ function deleteReport() {
142 })
143 }
144 </script>
148 -
149 -<style lang="scss" scoped>
150 -.item {
151 - border-radius: var(--border-radius);
152 - background-color: var(--bg-color);
153 - transition: all 0.2s var(--bezier-ease);
154 - border: var(--border-small-050);
155 - cursor: pointer;
156 -
157 - .header-box {
158 - font-family: var(--font-family-mono);
159 - }
160 - .footer-box {
161 - font-family: var(--font-family-mono);
162 - text-align: right;
163 - font-size: 12px;
164 - color: var(--fg-secondary-color);
165 -
166 - .delete-btn {
167 - &:hover {
168 - color: var(--error-color);
169 - }
170 - }
171 - }
172 -
173 - &:hover {
174 - box-shadow: 0px 0px 0px 1px inset var(--primary-color);
175 - }
176 -}
177 -</style>
frontend/src/components/webVulnerabilityAssessment/ReportsList.vue
+6 -6
@@ -1,10 +1,10 @@
1 <template>
2 <div class="available-reports-list">
3 - <div class="header flex items-center justify-end gap-2 mb-3">
4 - <div class="info grow flex gap-5">
3 + <div class="header mb-3 flex items-center justify-end gap-2">
4 + <div class="info flex grow gap-5">
5 <n-popover overlap placement="bottom-start">
6 <template #trigger>
7 - <div class="bg-color border-radius">
7 + <div class="bg-default rounded-default">
8 <n-button size="small" class="!cursor-help">
9 <template #icon>
10 <Icon :name="InfoIcon"></Icon>
@@ -20,7 +20,7 @@
20 </div>
21 </n-popover>
22 </div>
23 - <div class="actions flex gap-2 items-center">
23 + <div class="actions flex items-center gap-2">
24 <n-button size="small" type="primary" @click="showForm = true">
25 <template #icon>
26 <Icon :name="NewReportIcon" :size="15"></Icon>
@@ -31,7 +31,7 @@
31 </div>
32 <n-spin :show="loading" class="min-h-32">
33 <template v-if="reportsList.length">
34 - <div class="list grid gap-4 grid-auto-fill-250">
34 + <div class="list grid-auto-fill-250 grid gap-4">
35 <ReportsItem
36 v-for="report of reportsList"
37 :key="report"
@@ -42,7 +42,7 @@
42 </div>
43 </template>
44 <template v-else>
45 - <n-empty v-if="!loading" description="No items found" class="justify-center h-48" />
45 + <n-empty v-if="!loading" description="No items found" class="h-48 justify-center" />
46 </template>
47 </n-spin>
48
frontend/src/components/webVulnerabilityAssessment/ScanHostForm.vue
+1 -1
@@ -2,7 +2,7 @@
2 <n-spin :show="loading" class="creation-report-form">
3 <n-form ref="formRef" :label-width="80" :model="form" :rules="rules">
4 <div class="flex flex-col gap-2">
5 - <div class="flex gap-4 items-start">
5 + <div class="flex items-start gap-4">
6 <n-form-item label="Host" path="host" class="grow">
7 <n-input v-model:value.trim="form.host" placeholder="Please insert the Host" clearable />
8 </n-form-item>
frontend/src/composables/useStoreI18n.ts deleted
-24
@@ -1,24 +0,0 @@
1 -import { useLocalesStore } from "@/stores/i18n"
2 -import { useI18n } from "vue-i18n"
3 -
4 -export function useStoreI18n() {
5 - const { t } = useI18n()
6 - const localesStore = useLocalesStore()
7 -
8 - return {
9 - initLocale: (): string => {
10 - return localesStore.locale
11 - },
12 - getAvailableLocales: (): string[] => {
13 - return localesStore.available
14 - },
15 - getLocale: (): string => {
16 - return localesStore.locale
17 - },
18 - setLocale: (newLocale: string): string => {
19 - localesStore.setLocale(newLocale)
20 - return newLocale
21 - },
22 - t
23 - }
24 -}
frontend/src/design-tokens.json
+78
@@ -75,14 +75,53 @@
75 "primary040": "rgba(255, 182, 0, 0.4)",
76 "primary050": "rgba(255, 182, 0, 0.5)",
77 "primary060": "rgba(255, 182, 0, 0.6)",
78 + "primary070": "rgba(255, 182, 0, 0.7)",
79 + "primary080": "rgba(255, 182, 0, 0.8)",
80 + "primary090": "rgba(255, 182, 0, 0.9)",
81 "info": "#6267FF",
82 "success": "#00B27B",
83 "warning": "#E3C22F",
84 "error": "#FF0156",
85 "info005": "rgba(98, 103, 255, 0.05)",
86 + "info010": "rgba(98, 103, 255, 0.1)",
87 + "info020": "rgba(98, 103, 255, 0.2)",
88 + "info030": "rgba(98, 103, 255, 0.3)",
89 + "info040": "rgba(98, 103, 255, 0.4)",
90 + "info050": "rgba(98, 103, 255, 0.5)",
91 + "info060": "rgba(98, 103, 255, 0.6)",
92 + "info070": "rgba(98, 103, 255, 0.7)",
93 + "info080": "rgba(98, 103, 255, 0.8)",
94 + "info090": "rgba(98, 103, 255, 0.9)",
95 "success005": "rgba(0, 178, 123, 0.05)",
96 + "success010": "rgba(0, 178, 123, 0.1)",
97 + "success020": "rgba(0, 178, 123, 0.2)",
98 + "success030": "rgba(0, 178, 123, 0.3)",
99 + "success040": "rgba(0, 178, 123, 0.4)",
100 + "success050": "rgba(0, 178, 123, 0.5)",
101 + "success060": "rgba(0, 178, 123, 0.6)",
102 + "success070": "rgba(0, 178, 123, 0.7)",
103 + "success080": "rgba(0, 178, 123, 0.8)",
104 + "success090": "rgba(0, 178, 123, 0.9)",
105 "warning005": "rgba(227, 194, 47, 0.05)",
106 + "warning010": "rgba(227, 194, 47, 0.1)",
107 + "warning020": "rgba(227, 194, 47, 0.2)",
108 + "warning030": "rgba(227, 194, 47, 0.3)",
109 + "warning040": "rgba(227, 194, 47, 0.4)",
110 + "warning050": "rgba(227, 194, 47, 0.5)",
111 + "warning060": "rgba(227, 194, 47, 0.6)",
112 + "warning070": "rgba(227, 194, 47, 0.7)",
113 + "warning080": "rgba(227, 194, 47, 0.8)",
114 + "warning090": "rgba(227, 194, 47, 0.9)",
115 "error005": "rgba(255, 1, 86, 0.05)",
116 + "error010": "rgba(255, 1, 86, 0.1)",
117 + "error020": "rgba(255, 1, 86, 0.2)",
118 + "error030": "rgba(255, 1, 86, 0.3)",
119 + "error040": "rgba(255, 1, 86, 0.4)",
120 + "error050": "rgba(255, 1, 86, 0.5)",
121 + "error060": "rgba(255, 1, 86, 0.6)",
122 + "error070": "rgba(255, 1, 86, 0.7)",
123 + "error080": "rgba(255, 1, 86, 0.8)",
124 + "error090": "rgba(255, 1, 86, 0.9)",
125 "secondary1": "rgb(98, 103, 255)",
126 "secondary1Opacity005": "rgba(98, 103, 255, 0.05)",
127 "secondary1Opacity010": "rgba(98, 103, 255, 0.1)",
@@ -127,14 +166,53 @@
166 "primary040": "rgba(255, 182, 0, 0.4)",
167 "primary050": "rgba(255, 182, 0, 0.5)",
168 "primary060": "rgba(255, 182, 0, 0.6)",
169 + "primary070": "rgba(255, 182, 0, 0.7)",
170 + "primary080": "rgba(255, 182, 0, 0.8)",
171 + "primary090": "rgba(255, 182, 0, 0.9)",
172 "info": "#6267FF",
173 "success": "#00E19B",
174 "warning": "#E3C22F",
175 "error": "#FF0156",
176 "info005": "rgba(98, 103, 255, 0.05)",
177 + "info010": "rgba(98, 103, 255, 0.1)",
178 + "info020": "rgba(98, 103, 255, 0.2)",
179 + "info030": "rgba(98, 103, 255, 0.3)",
180 + "info040": "rgba(98, 103, 255, 0.4)",
181 + "info050": "rgba(98, 103, 255, 0.5)",
182 + "info060": "rgba(98, 103, 255, 0.6)",
183 + "info070": "rgba(98, 103, 255, 0.7)",
184 + "info080": "rgba(98, 103, 255, 0.8)",
185 + "info090": "rgba(98, 103, 255, 0.9)",
186 "success005": "rgba(0, 178, 123, 0.05)",
187 + "success010": "rgba(0, 178, 123, 0.1)",
188 + "success020": "rgba(0, 178, 123, 0.2)",
189 + "success030": "rgba(0, 178, 123, 0.3)",
190 + "success040": "rgba(0, 178, 123, 0.4)",
191 + "success050": "rgba(0, 178, 123, 0.5)",
192 + "success060": "rgba(0, 178, 123, 0.6)",
193 + "success070": "rgba(0, 178, 123, 0.7)",
194 + "success080": "rgba(0, 178, 123, 0.8)",
195 + "success090": "rgba(0, 178, 123, 0.9)",
196 "warning005": "rgba(227, 194, 47, 0.05)",
197 + "warning010": "rgba(227, 194, 47, 0.1)",
198 + "warning020": "rgba(227, 194, 47, 0.2)",
199 + "warning030": "rgba(227, 194, 47, 0.3)",
200 + "warning040": "rgba(227, 194, 47, 0.4)",
201 + "warning050": "rgba(227, 194, 47, 0.5)",
202 + "warning060": "rgba(227, 194, 47, 0.6)",
203 + "warning070": "rgba(227, 194, 47, 0.7)",
204 + "warning080": "rgba(227, 194, 47, 0.8)",
205 + "warning090": "rgba(227, 194, 47, 0.9)",
206 "error005": "rgba(255, 1, 86, 0.05)",
207 + "error010": "rgba(255, 1, 86, 0.1)",
208 + "error020": "rgba(255, 1, 86, 0.2)",
209 + "error030": "rgba(255, 1, 86, 0.3)",
210 + "error040": "rgba(255, 1, 86, 0.4)",
211 + "error050": "rgba(255, 1, 86, 0.5)",
212 + "error060": "rgba(255, 1, 86, 0.6)",
213 + "error070": "rgba(255, 1, 86, 0.7)",
214 + "error080": "rgba(255, 1, 86, 0.8)",
215 + "error090": "rgba(255, 1, 86, 0.9)",
216 "secondary1": "rgb(98, 103, 255)",
217 "secondary1Opacity005": "rgba(98, 103, 255, 0.05)",
218 "secondary1Opacity010": "rgba(98, 103, 255, 0.1)",
frontend/src/lang/config.ts
+3 -3
@@ -1,7 +1,7 @@
1 import * as locales from "."
2
3 -export type Locales = keyof typeof locales
4 -export type MessageSchema = (typeof locales)[Locales]
3 +export type Locale = keyof typeof locales
4 +export type MessageSchema = (typeof locales)[Locale]
5
6 export function getI18NConf() {
7 // @ts-expect-error "locales" don't match with [key: string]: { default: MessageSchema } }
@@ -13,7 +13,7 @@ export function getI18NConf() {
13 return acc
14 },
15 {}
16 - ) as { [key in Locales]: MessageSchema }
16 + ) as { [key in Locale]: MessageSchema }
17
18 return {
19 legacy: false,
frontend/src/main.ts
+2 -2
@@ -1,5 +1,5 @@
1 import App from "@/App.vue"
2 -import { getI18NConf, type Locales, type MessageSchema } from "@/lang/config"
2 +import { getI18NConf, type Locale, type MessageSchema } from "@/lang/config"
3 import router from "@/router"
4 import { createPinia } from "pinia"
5 import { createPersistedState } from "pinia-plugin-persistedstate"
@@ -17,7 +17,7 @@ pinia.use(
17 })
18 )
19
20 -const i18n = createI18n<MessageSchema, Locales>(getI18NConf())
20 +const i18n = createI18n<MessageSchema, Locale>(getI18NConf())
21
22 const app = createApp(App)
23 app.use(pinia)
frontend/src/stores/i18n.ts
+46 -4
@@ -1,14 +1,56 @@
1 +import type { Locale } from "@/lang/config"
2 +import type { WritableComputedRef } from "vue"
3 +import {
4 + dateDeDE,
5 + dateEnUS,
6 + dateEsAR,
7 + dateFrFR,
8 + dateItIT,
9 + dateJaJP,
10 + deDE,
11 + enUS,
12 + esAR,
13 + frFR,
14 + itIT,
15 + jaJP,
16 + type NDateLocale,
17 + type NLocale
18 +} from "naive-ui"
19 import { acceptHMRUpdate, defineStore } from "pinia"
2 -import { useI18n } from "vue-i18n"
20 +import { type ComposerTranslation, useI18n } from "vue-i18n"
21 +
22 +export type I18nLangCode = Locale
23
24 export const useLocalesStore = defineStore("i18n", {
25 state: () => ({
6 - locale: useI18n().locale,
7 - available: useI18n().availableLocales
26 + locale: useI18n().locale as WritableComputedRef<I18nLangCode, string>,
27 + availableLocales: useI18n().availableLocales as I18nLangCode[]
28 }),
29 actions: {
10 - setLocale(locale: string) {
30 + setLocale(locale: I18nLangCode): I18nLangCode {
31 this.locale = locale
32 + return locale
33 + }
34 + },
35 + getters: {
36 + t(): ComposerTranslation {
37 + return useI18n().t
38 + },
39 + naiveuiLocales(): { code: I18nLangCode; ui: NLocale; date: NDateLocale }[] {
40 + return [
41 + { code: "de", ui: deDE, date: dateDeDE },
42 + { code: "en", ui: enUS, date: dateEnUS },
43 + { code: "es", ui: esAR, date: dateEsAR },
44 + { code: "fr", ui: frFR, date: dateFrFR },
45 + { code: "it", ui: itIT, date: dateItIT },
46 + { code: "jp", ui: jaJP, date: dateJaJP }
47 + ]
48 + },
49 + naiveuiLocale(state): NLocale | undefined {
50 + return this.naiveuiLocales.find(locale => locale.code === state.locale)?.ui
51 + },
52 + naiveuiDateLocale(state): NDateLocale | undefined {
53 + return this.naiveuiLocales.find(locale => locale.code === state.locale)?.date
54 }
55 },
56 persist: {
frontend/src/stores/theme.ts
+68 -11
@@ -1,13 +1,15 @@
1 -import type { ColorType, Layout, RouterTransition, ThemeName } from "@/types/theme.d"
1 +import type { ColorType, Layout, RouterTransition } from "@/types/theme.d"
2 import type { BuiltInGlobalTheme } from "naive-ui/es/themes/interface"
3 import { getCssVars, getDefaultState } from "@/theme"
4 -import { ThemeEnum } from "@/types/theme.d"
4 +import { ThemeNameEnum } from "@/types/theme.d"
5 import { exportPrimaryShades, getThemeColors, getTypeValue, type PrimaryShade } from "@/utils/theme"
6 +import { useWindowSize } from "@vueuse/core"
7 import _get from "lodash/get"
8 import _pick from "lodash/pick"
9 import _set from "lodash/set"
10 import { darkTheme, type GlobalThemeOverrides, lightTheme, type ThemeCommonVars } from "naive-ui"
11 import { acceptHMRUpdate, defineStore } from "pinia"
12 +import { watch } from "vue"
13
14 export const useThemeStore = defineStore("theme", {
15 state: () => getDefaultState(),
@@ -30,16 +32,16 @@ export const useThemeStore = defineStore("theme", {
32 setRouterTransition(routerTransition: RouterTransition): void {
33 this.routerTransition = routerTransition
34 },
33 - setTheme(themeName: ThemeName): void {
35 + setTheme(themeName: ThemeNameEnum): void {
36 this.themeName = themeName
37 },
38 setThemeLight(): void {
37 - this.themeName = ThemeEnum.Light
39 + this.themeName = ThemeNameEnum.Light
40 },
41 setThemeDark(): void {
40 - this.themeName = ThemeEnum.Dark
42 + this.themeName = ThemeNameEnum.Dark
43 },
42 - setColor(theme: ThemeName, colorType: ColorType, color: string): void {
44 + setColor(theme: ThemeNameEnum, colorType: ColorType, color: string): void {
45 this.colors[theme][colorType] = color
46
47 if (colorType === "primary") {
@@ -77,7 +79,7 @@ export const useThemeStore = defineStore("theme", {
79 closeSidebar(): void {
80 this.sidebar.collapsed = true
81 },
80 - updateVars() {
82 + updateResponsiveVars() {
83 for (const key in this.responsive.override) {
84 if (_get(this, key) && key in this.responsive.override) {
85 _set(
@@ -89,18 +91,73 @@ export const useThemeStore = defineStore("theme", {
91 )
92 }
93 }
92 -
94 + },
95 + ensureSidebarState() {
96 // auto close sidebar on resize
97 if (this.sidebar.autoClose) {
98 if (!this.sidebar.collapsed && window.innerWidth <= this.sidebar.autoCloseBreakpoint) {
99 this.sidebar.collapsed = true
100 }
101 }
102 + },
103 + setDocumentThemeName(val: ThemeNameEnum, old?: ThemeNameEnum) {
104 + if (document) {
105 + const html = document.children[0] as HTMLElement
106 + if (old) {
107 + html.classList.remove(`theme-${old}`)
108 + }
109 + html.classList.add(`theme-${val}`)
110 + }
111 + },
112 + // This function allows you to utilize the values in the style object as variables within your CSS/SCSS code like: var(-–bg-color)
113 + setCssGlobalVars() {
114 + if (document) {
115 + const html = document.children[0] as HTMLElement
116 + const body = document.getElementsByTagName("body")?.[0]
117 + if (this.isRTL && body) {
118 + body.classList.add("direction-rtl")
119 + body.classList.remove("direction-ltr")
120 + } else {
121 + body.classList.remove("direction-rtl")
122 + body.classList.add("direction-ltr")
123 + }
124 + // html.dir = this.isRTL ? "rtl" : "ltr"
125 + const { style: htmlStyle } = html
126 + for (const key in this.style) {
127 + htmlStyle.setProperty(`--${key}`, this.style[key])
128 + }
129 + }
130 + },
131 + startWatchers() {
132 + const { width } = useWindowSize()
133 +
134 + watch([() => this.isRTL, () => this.style], () => {
135 + this.setCssGlobalVars()
136 + })
137 +
138 + watch(
139 + () => this.themeName,
140 + (val, old) => {
141 + this.setDocumentThemeName(val, old)
142 + }
143 + )
144 +
145 + watch(width, () => {
146 + this.updateResponsiveVars()
147 + this.ensureSidebarState()
148 + })
149 + },
150 + initTheme() {
151 + this.updateResponsiveVars()
152 + this.ensureSidebarState()
153 + this.setCssGlobalVars()
154 + this.setDocumentThemeName(this.themeName)
155 + this.startWatchers()
156 }
157 },
158 getters: {
159 naiveTheme(state): BuiltInGlobalTheme {
103 - return state.themeName === ThemeEnum.Dark ? darkTheme : lightTheme
160 + return state.themeName === ThemeNameEnum.Dark ? darkTheme : lightTheme
161 },
162 themeOverrides(state): GlobalThemeOverrides {
163 const {
@@ -235,10 +292,10 @@ export const useThemeStore = defineStore("theme", {
292 return getCssVars(state, this)
293 },
294 isThemeDark(state): boolean {
238 - return state.themeName === ThemeEnum.Dark
295 + return state.themeName === ThemeNameEnum.Dark
296 },
297 isThemeLight(state): boolean {
241 - return state.themeName === ThemeEnum.Light
298 + return state.themeName === ThemeNameEnum.Light
299 },
300 isBoxed(state): boolean {
301 return state.boxed.enabled
frontend/src/theme/index.ts
+96 -4
@@ -1,5 +1,5 @@
1 import tokens from "@/design-tokens.json"
2 -import { Layout, RouterTransition, ThemeEnum } from "@/types/theme.d"
2 +import { Layout, RouterTransition, ThemeNameEnum } from "@/types/theme.d"
3 import { hex2rgb } from "@/utils/theme"
4 import { type ThemeCommonVars, useOsTheme } from "naive-ui"
5
@@ -22,7 +22,7 @@ const osTheme = useOsTheme()
22 export function getDefaultState() {
23 return {
24 layout: Layout.HorizontalNav, // Type of layout, with vertical or horizontal navigation
25 - themeName: osTheme.value || ThemeEnum.Light, // Theme name (Dark, Light), with fallback to the light theme
25 + themeName: osTheme.value === "dark" ? ThemeNameEnum.Dark : ThemeNameEnum.Light, // Theme name (Dark, Light), with fallback to the light theme
26 routerTransition: RouterTransition.FadeUp, // Type of transition for the router
27 routerTransitionDuration: 0.3, // Duration of the router transition in seconds
28 rtl: false, // RTL (right to left) mode toggle
@@ -91,7 +91,48 @@ export function getCssVars(state: ThemeState, getters: ThemeGetters): { [key: st
91 const warningColorRGB = hex2rgb(warningColor).join(", ")
92 const infoColorRGB = hex2rgb(infoColor).join(", ")
93
94 - const { success005, warning005, error005, info005 } = state.colors[state.themeName]
94 + const {
95 + success005,
96 + warning005,
97 + error005,
98 + info005,
99 + success010,
100 + warning010,
101 + error010,
102 + info010,
103 + success020,
104 + warning020,
105 + error020,
106 + info020,
107 + success030,
108 + warning030,
109 + error030,
110 + info030,
111 + success040,
112 + warning040,
113 + error040,
114 + info040,
115 + success050,
116 + warning050,
117 + error050,
118 + info050,
119 + success060,
120 + warning060,
121 + error060,
122 + info060,
123 + success070,
124 + warning070,
125 + error070,
126 + info070,
127 + success080,
128 + warning080,
129 + error080,
130 + info080,
131 + success090,
132 + warning090,
133 + error090,
134 + info090
135 + } = state.colors[state.themeName]
136
137 const modalColor = naive.modalColor
138 const modalColorRGB = hex2rgb(modalColor).join(", ")
@@ -180,9 +221,11 @@ export function getCssVars(state: ThemeState, getters: ThemeGetters): { [key: st
221 "view-padding": `${viewPadding}px`,
222 "border-radius": `${borderRadius}`,
223 "border-radius-small": `${borderRadiusSmall}`,
224 +
225 "font-family": `${fontFamily}`,
226 "font-family-display": `${fontFamilyDisplay}`,
227 "font-family-mono": `${fontFamilyMono}`,
228 +
229 "code-color": `${codeColor}`,
230 "primary-color": `${primaryColor}`,
231 "tab-color": `${tabColor}`,
@@ -221,6 +264,52 @@ export function getCssVars(state: ThemeState, getters: ThemeGetters): { [key: st
264 "error-005-color": `${error005}`,
265 "warning-005-color": `${warning005}`,
266 "info-005-color": `${info005}`,
267 +
268 + "success-010-color": `${success010}`,
269 + "error-010-color": `${error010}`,
270 + "warning-010-color": `${warning010}`,
271 + "info-010-color": `${info010}`,
272 +
273 + "success-020-color": `${success020}`,
274 + "error-020-color": `${error020}`,
275 + "warning-020-color": `${warning020}`,
276 + "info-020-color": `${info020}`,
277 +
278 + "success-030-color": `${success030}`,
279 + "error-030-color": `${error030}`,
280 + "warning-030-color": `${warning030}`,
281 + "info-030-color": `${info030}`,
282 +
283 + "success-040-color": `${success040}`,
284 + "error-040-color": `${error040}`,
285 + "warning-040-color": `${warning040}`,
286 + "info-040-color": `${info040}`,
287 +
288 + "success-050-color": `${success050}`,
289 + "error-050-color": `${error050}`,
290 + "warning-050-color": `${warning050}`,
291 + "info-050-color": `${info050}`,
292 +
293 + "success-060-color": `${success060}`,
294 + "error-060-color": `${error060}`,
295 + "warning-060-color": `${warning060}`,
296 + "info-060-color": `${info060}`,
297 +
298 + "success-070-color": `${success070}`,
299 + "error-070-color": `${error070}`,
300 + "warning-070-color": `${warning070}`,
301 + "info-070-color": `${info070}`,
302 +
303 + "success-080-color": `${success080}`,
304 + "error-080-color": `${error080}`,
305 + "warning-080-color": `${warning080}`,
306 + "info-080-color": `${info080}`,
307 +
308 + "success-090-color": `${success090}`,
309 + "error-090-color": `${error090}`,
310 + "warning-090-color": `${warning090}`,
311 + "info-090-color": `${info090}`,
312 +
313 "success-color-rgb": `${successColorRGB}`,
314 "error-color-rgb": `${errorColorRGB}`,
315 "warning-color-rgb": `${warningColorRGB}`,
@@ -250,6 +339,9 @@ export function getCssVars(state: ThemeState, getters: ThemeGetters): { [key: st
339 "secondary4-opacity-005-color": `${secondary4Opacity005}`,
340 "secondary4-opacity-010-color": `${secondary4Opacity010}`,
341 "secondary4-opacity-020-color": `${secondary4Opacity020}`,
253 - "secondary4-opacity-030-color": `${secondary4Opacity030}`
342 + "secondary4-opacity-030-color": `${secondary4Opacity030}`,
343 +
344 + "border-small-050": `1px solid ${borderColor}`,
345 + "border-small-100": `1px solid ${divider010}`
346 }
347 }
frontend/src/types/alerts.d.ts
+14 -1
@@ -138,28 +138,37 @@ export interface AlertSourceContent {
138 data_win_eventdata_currentDirectory?: string
139 data_win_eventdata_description?: string
140 data_win_eventdata_fileVersion?: string
141 + data_win_eventdata_fWLink?: string
142 data_win_eventdata_grantedAccess?: string
143 data_win_eventdata_hashes?: string
144 data_win_eventdata_image?: string
145 data_win_eventdata_integrityLevel?: AlertSourceDataWinEventdataIntegrityLevel
146 data_win_eventdata_logonGuid?: string
147 data_win_eventdata_logonId?: string
148 + data_win_eventdata_newThreadId?: string
149 data_win_eventdata_originalFileName?: string
150 data_win_eventdata_parentCommandLine?: string
151 data_win_eventdata_parentImage?: string
152 data_win_eventdata_parentProcessGuid?: string
153 data_win_eventdata_parentProcessId?: string
154 data_win_eventdata_parentUser?: string
155 + data_win_eventdata_path?: string
156 data_win_eventdata_processGuid?: string
157 data_win_eventdata_processId?: string
158 data_win_eventdata_product?: string
159 data_win_eventdata_ruleName?: string
160 data_win_eventdata_sourceImage?: string
161 + data_win_eventdata_sourceProcessGuid?: string
162 data_win_eventdata_sourceProcessGUID?: string
163 data_win_eventdata_sourceProcessId?: string
164 data_win_eventdata_sourceThreadId?: string
165 data_win_eventdata_sourceUser?: string
166 + data_win_eventdata_startAddress?: string
167 + data_win_eventdata_startFunction?: string
168 + data_win_eventdata_startModule?: string
169 + data_win_eventdata_state?: string
170 data_win_eventdata_targetImage?: string
171 + data_win_eventdata_targetProcessGuid?: string
172 data_win_eventdata_targetProcessGUID?: string
173 data_win_eventdata_targetProcessId?: string
174 data_win_eventdata_targetUser?: string
@@ -208,16 +217,19 @@ export interface AlertSourceContent {
217 rule_description: string
218 rule_firedtimes: number
219 rule_gdpr?: string
220 + rule_gpg13?: string
221 rule_group1: string
222 rule_group2?: string
223 rule_group3?: AlertSourceDataLogsourceProduct
224 rule_groups: string
225 + rule_hipaa?: string
226 rule_id: string
227 rule_level: number
228 rule_mail: boolean
229 rule_mitre_id?: string
230 rule_mitre_tactic?: string
231 rule_mitre_technique?: string
232 + rule_nist_800_53?: string
233 rule_pci_dss?: string
234 rule_tsc?: string
235 sha256?: string
@@ -269,7 +281,8 @@ export enum AlertSourceDataWinEventdataIntegrityLevel {
281 }
282
283 export enum AlertSourceDataWinSystemSeverityValue {
272 - Information = "INFORMATION"
284 + Information = "INFORMATION",
285 + Warning = "WARNING"
286 }
287
288 export enum AlertSourceDecoderName {
frontend/src/types/artifacts.d.ts
+1 -1
@@ -4,7 +4,7 @@ export interface Artifact {
4 }
5
6 export interface CollectResult {
7 - [key: string]: string | number
7 + [key: string]: string | number | null | object
8 }
9
10 export interface CommandResult {
frontend/src/types/theme.d.ts
+1 -5
@@ -11,15 +11,11 @@ export enum RouterTransition {
11 FadeRight = "fade-right"
12 }
13
14 -export enum ThemeEnum {
14 +export enum ThemeNameEnum {
15 Dark = "dark",
16 Light = "light"
17 }
18
19 -export type Theme = "light" | "dark"
20 -
21 -export type ThemeName = ThemeEnum | Theme
22 -
19 export type ColorType = "primary" | "info" | "success" | "warning" | "error"
20 export type ColorScene = "" | "Suppl" | "Hover" | "Pressed"
21 export type ColorKey = `${ColorType}Color${ColorScene}`
frontend/src/utils/highlighter.ts
+2 -1
@@ -20,7 +20,8 @@ export async function getHighlighter() {
20 import("shiki/langs/css.mjs"),
21 import("shiki/langs/csharp.mjs"),
22 import("shiki/langs/http.mjs"),
23 - import("shiki/langs/sql.mjs")
23 + import("shiki/langs/sql.mjs"),
24 + import("shiki/langs/lua.mjs")
25 ],
26 loadWasm: getWasm
27 })
frontend/src/views/Indices.vue
+1 -1
@@ -20,7 +20,7 @@
20 </div>
21
22 <n-card class="section overflow-hidden" content-style="padding:0">
23 - <div class="columns flex column-1200 !gap-0">
23 + <div class="columns column-1200 flex !gap-0">
24 <div class="col basis-2/5">
25 <NodeAllocation class="stretchy" style="border-radius: 0" :bordered="false" />
26 </div>
frontend/src/views/Overview.vue
+7 -7
@@ -1,12 +1,12 @@
1 <template>
2 <div ref="page" class="page">
3 - <div class="section justify-end lg:justify-between flex gap-3">
4 - <div class="left-box hidden lg:flex gap-3">
3 + <div class="section flex justify-end gap-3 lg:justify-between">
4 + <div class="left-box hidden gap-3 lg:flex">
5 <StackProvisioningButton size="small" type="primary" />
6 <CloudSecurityAssessmentButton size="small" type="primary" />
7 <WebVulnerabilityAssessmentButton size="small" type="primary" />
8 </div>
9 - <div class="right-box hidden lg:flex gap-3">
9 + <div class="right-box hidden gap-3 lg:flex">
10 <ActiveResponseWizardButton size="small" type="primary" />
11 <ThreatIntelButton size="small" type="primary" />
12 </div>
@@ -21,13 +21,13 @@
21 </div>
22 <div class="section">
23 <div class="grid grid-flow-row-dense grid-cols-12 gap-6">
24 - <div class="col-span-12 xs:col-span-12 sm:col-span-4 lg:col-span-2">
24 + <div class="xs:col-span-12 col-span-12 sm:col-span-4 lg:col-span-2">
25 <AgentsCard class="h-full" />
26 </div>
27 - <div class="col-span-12 xs:col-span-6 sm:col-span-4 lg:col-span-2">
27 + <div class="xs:col-span-6 col-span-12 sm:col-span-4 lg:col-span-2">
28 <HealthcheckCard class="h-full" />
29 </div>
30 - <div class="col-span-12 xs:col-span-6 sm:col-span-4 lg:col-span-2">
30 + <div class="xs:col-span-6 col-span-12 sm:col-span-4 lg:col-span-2">
31 <CustomersCard class="h-full" />
32 </div>
33 <div class="col-span-12 lg:col-span-3">
@@ -52,7 +52,7 @@
52 </div>
53 </div>
54 <div class="section">
55 - <PipeList min-height="28px" @open-rule="gotoGraylogPipelines($event)" />
55 + <PipeList @open-rule="gotoGraylogPipelines($event)" />
56 </div>
57
58 <n-drawer
frontend/src/views/Profile.vue
+1 -4
@@ -14,7 +14,7 @@
14 <Icon :name="EditIcon" :size="16" class="edit" @click="openCropper()" />
15 </ImageCropper>
16 </div>
17 - <div class="info grow flex flex-col justify-center">
17 + <div class="info flex grow flex-col justify-center">
18 <div class="name">
19 <h1>{{ userName }}</h1>
20 </div>
@@ -158,9 +158,6 @@ function setCroppedImage(result: ImageCropperResult) {
158 display: flex;
159 }
160 }
161 - .actions {
162 - // display: none;
163 - }
161 }
162 }
163 .section-selector {
frontend/src/views/agents/Agents.vue
+8 -6
@@ -1,5 +1,5 @@
1 <template>
2 - <div class="page page-wrapped flex flex-col page-without-footer">
2 + <div class="page page-wrapped page-without-footer flex flex-col">
3 <div class="wrapper flex grow gap-4">
4 <div class="sidebar">
5 <AgentToolbar
@@ -10,11 +10,11 @@
10 :agents-critical="agentsCritical"
11 :agents-online="agentsOnline"
12 @sync="syncAgents()"
13 - @click="gotoAgent($event.agent_id)"
13 + @click.stop="gotoAgent($event.agent_id)"
14 />
15 </div>
16 - <div class="main grow flex flex-col overflow-hidden">
17 - <n-spin class="w-full h-full overflow-hidden flex flex-col" :show="loadingAgents">
16 + <div class="main flex grow flex-col overflow-hidden">
17 + <n-spin class="flex h-full w-full flex-col overflow-hidden" :show="loadingAgents">
18 <n-scrollbar class="grow">
19 <div class="agents-list flex flex-grow flex-col gap-3">
20 <template v-if="agentsFiltered.length">
@@ -23,16 +23,18 @@
23 :key="agent.agent_id"
24 :agent="agent"
25 show-actions
26 + hoverable
27 + clickable
28 class="item-appear item-appear-bottom item-appear-005"
29 @delete="syncAgents()"
28 - @click="gotoAgent(agent.agent_id)"
30 + @click.stop="gotoAgent(agent.agent_id)"
31 />
32 </template>
33 <template v-else>
34 <n-empty
35 v-if="!loadingAgents"
36 description="No items found"
35 - class="justify-center h-48"
37 + class="h-48 justify-center"
38 />
39 </template>
40 </div>
frontend/src/views/agents/Overview.vue
+42 -44
@@ -7,52 +7,53 @@
7 </div>
8 <div v-if="agent" class="delete-btn" @click.stop="handleDelete">Delete Agent</div>
9 </div>
10 - <n-spin
11 - class="agent-header py-5 px-7 my-4"
12 - content-class="flex justify-between gap-y-1 gap-x-6 flex-wrap items-start"
10 + <CardEntity
11 + class="agent-header my-4"
12 :class="{ critical: agent?.critical_asset, online: isOnline }"
14 - :show="loadingAgent"
13 + :loading="loadingAgent"
14 >
16 - <div class="info grow">
17 - <div class="title">
18 - <div v-if="agent" class="critical" :class="{ active: agent?.critical_asset }">
19 - <n-tooltip>
20 - Toggle Critical Assets
21 - <template #trigger>
22 - <n-button
23 - text
24 - :type="agent?.critical_asset ? 'warning' : 'default'"
25 - circle
26 - @click.stop="toggleCritical(agent.agent_id, agent.critical_asset)"
27 - >
28 - <template #icon>
29 - <Icon :name="StarIcon"></Icon>
30 - </template>
31 - </n-button>
32 - </template>
33 - </n-tooltip>
34 - </div>
15 + <div class="flex flex-wrap items-start justify-between gap-x-6 gap-y-1">
16 + <div class="info grow">
17 + <div class="title">
18 + <div v-if="agent" class="critical" :class="{ active: agent?.critical_asset }">
19 + <n-tooltip>
20 + Toggle Critical Assets
21 + <template #trigger>
22 + <n-button
23 + text
24 + :type="agent?.critical_asset ? 'warning' : 'default'"
25 + circle
26 + @click.stop="toggleCritical(agent.agent_id, agent.critical_asset)"
27 + >
28 + <template #icon>
29 + <Icon :name="StarIcon"></Icon>
30 + </template>
31 + </n-button>
32 + </template>
33 + </n-tooltip>
34 + </div>
35
36 - <h1 v-if="agent?.hostname">
37 - {{ agent?.hostname }}
38 - </h1>
36 + <h1 v-if="agent?.hostname">
37 + {{ agent?.hostname }}
38 + </h1>
39
40 - <span v-if="isOnline" class="online-badge">ONLINE</span>
40 + <span v-if="isOnline" class="online-badge">ONLINE</span>
41
42 - <span v-if="isQuarantined" class="quarantined-badge flex items-center gap-1">
43 - <Icon :name="QuarantinedIcon" :size="15"></Icon>
44 - <span>QUARANTINED</span>
45 - </span>
42 + <span v-if="isQuarantined" class="quarantined-badge flex items-center gap-1">
43 + <Icon :name="QuarantinedIcon" :size="15"></Icon>
44 + <span>QUARANTINED</span>
45 + </span>
46 + </div>
47 + <div class="label text-secondary mt-2">Agent #{{ agent?.agent_id }}</div>
48 + </div>
49 + <div class="actions flex grow items-center justify-end">
50 + <n-button size="small" ghost type="primary" :loading="upgradingAgent" @click="upgradeWazuhAgent()">
51 + Upgrade Wazuh Agent
52 + </n-button>
53 </div>
47 - <div class="label text-secondary-color mt-2">Agent #{{ agent?.agent_id }}</div>
48 - </div>
49 - <div class="actions flex items-center justify-end grow">
50 - <n-button size="small" ghost type="primary" :loading="upgradingAgent" @click="upgradeWazuhAgent()">
51 - Upgrade Wazuh Agent
52 - </n-button>
54 </div>
54 - </n-spin>
55 - <n-card class="py-1 px-4 pb-4" content-style="padding:0">
55 + </CardEntity>
56 + <n-card class="px-4 py-1 pb-4" content-style="padding:0">
57 <n-spin :show="loadingAgent">
58 <n-tabs type="line" animated default-value="Overview">
59 <n-tab-pane name="Overview" tab="Overview" display-directive="show">
@@ -142,6 +143,7 @@
143 import type { Artifact } from "@/types/artifacts.d"
144 import Api from "@/api"
145 import { handleDeleteAgent, toggleAgentCritical } from "@/components/agents/utils"
146 +import CardEntity from "@/components/common/cards/CardEntity.vue"
147 import Icon from "@/components/common/Icon.vue"
148 import { useGoto } from "@/composables/useGoto"
149 import { type Agent, AgentStatus } from "@/types/agents.d"
@@ -316,10 +318,6 @@ onBeforeMount(() => {
318 }
319
320 .agent-header {
319 - border-radius: var(--border-radius);
320 - background-color: var(--bg-color);
321 - border: var(--border-small-050);
322 -
321 .title {
322 display: flex;
323 align-items: center;
@@ -342,7 +340,7 @@ onBeforeMount(() => {
340 color: var(--success-color);
341 font-weight: bold;
342 border-radius: var(--border-radius);
345 - @apply text-xs py-1 px-2;
343 + @apply px-2 py-1 text-xs;
344 }
345
346 .quarantined-badge {
frontend/src/views/auth/Login.vue
+2 -2
@@ -1,8 +1,8 @@
1 <template>
2 <div class="page-auth">
3 - <div v-if="!isLogged" class="flex wrapper justify-center">
3 + <div v-if="!isLogged" class="wrapper flex justify-center">
4 <div v-if="align === 'right'" class="image-box basis-2/3" />
5 - <div class="form-box basis-1/3 flex items-center justify-center" :class="{ centered: align === 'center' }">
5 + <div class="form-box flex basis-1/3 items-center justify-center" :class="{ centered: align === 'center' }">
6 <AuthForm :type="type" />
7 </div>
8 <div v-if="align === 'left'" class="image-box basis-2/3">
frontend/src/views/graylog/Metrics.vue
+1 -1
@@ -1,6 +1,6 @@
1 <template>
2 <div class="page">
3 - <div class="header flex flex-wrap justify-between items-center gap-4">
3 + <div class="header flex flex-wrap items-center justify-between gap-4">
4 <div class="info flex items-center gap-3">
5 <n-button size="small" type="primary" secondary :loading="loading" @click="getData()">
6 <template #icon>
frontend/src/views/graylog/Pipelines.vue
+1 -1
@@ -33,7 +33,7 @@
33 <n-drawer-content closable body-content-style="padding:0">
34 <template #header>
35 <span>Rules list</span>
36 - <span v-if="rulesTotal !== null" class="font-mono ml-2 text-secondary-color">{{ rulesTotal }}</span>
36 + <span v-if="rulesTotal !== null" class="text-secondary ml-2 font-mono">{{ rulesTotal }}</span>
37 </template>
38 <RulesList :highlight="highlightRule" @loaded="rulesTotal = $event.total" />
39 </n-drawer-content>
frontend/src/views/license/Cancel.vue
+1 -1
@@ -1,5 +1,5 @@
1 <template>
2 - <div class="page grow flex flex-col justify-center items-center">
2 + <div class="page flex grow flex-col items-center justify-center">
3 <LicenseCheckoutResponse class="max-w-96" type="error" />
4 </div>
5 </template>
frontend/src/views/license/License.vue
+2 -2
@@ -1,5 +1,5 @@
1 <template>
2 - <div class="page grow flex flex-col" :class="{ 'limit-height': licenseKey }">
2 + <div class="page flex grow flex-col" :class="{ 'limit-height': licenseKey }">
3 <LicenseViewer
4 class="grow"
5 :class="{ 'overflow-hidden': licenseKey }"
@@ -20,7 +20,7 @@ const licenseKey = ref<LicenseKey | undefined>(undefined)
20 .page {
21 &.limit-height {
22 @media (min-width: 801px) {
23 - max-height: calc(100svh - var(--toolbar-height) - var(--view-padding) - var(--header-bar-height) - 66px);
23 + max-height: calc(100dvh - var(--toolbar-height) - var(--view-padding) - var(--header-bar-height) - 66px);
24 overflow: hidden;
25 }
26 }
frontend/src/views/license/Success.vue
+1 -1
@@ -1,5 +1,5 @@
1 <template>
2 - <div class="page grow flex flex-col justify-center items-center">
2 + <div class="page flex grow flex-col items-center justify-center">
3 <LicenseCheckoutResponse class="max-w-96" type="success" :data="{ email: route.query.email?.toString() }" />
4 </div>
5 </template>
frontend/tailwind.config.js
+35
@@ -18,7 +18,40 @@ export default {
18 content: ["./index.html", "./src/**/*.{vue,js,ts,jsx,tsx}"],
19 darkMode: ["class"],
20 theme: {
21 + fontFamily: {
22 + sans: ["var(--font-family)", "sans-serif"],
23 + serif: ["var(--font-family-display)", "serif"],
24 + display: ["var(--font-family-display)", "serif"],
25 + mono: ["var(--font-family-mono)", "monospace"]
26 + },
27 extend: {
28 + colors: {
29 + primary: "var(--primary-color)"
30 + },
31 + animation: {
32 + fade: "fade 0.3s forwards"
33 + },
34 + keyframes: {
35 + fade: {
36 + from: { opacity: 0 },
37 + to: { opacity: 1 }
38 + }
39 + },
40 + backgroundColor: {
41 + default: "var(--bg-color)",
42 + secondary: "var(--bg-secondary-color)"
43 + },
44 + textColor: {
45 + default: "var(--fg-color)",
46 + secondary: "var(--fg-secondary-color)",
47 + warning: "var(--warning-color)",
48 + error: "var(--error-color)",
49 + success: "var(--success-color)"
50 + },
51 + borderRadius: {
52 + default: "var(--border-radius)",
53 + small: "var(--border-radius-small)"
54 + },
55 screens: {
56 xs: "460px"
57 },
@@ -37,6 +70,7 @@ export default {
70 },
71 maxHeight: {
72 "50vh": "50vh",
73 + 106: "26.5rem",
74 150: "37.5rem"
75 },
76 maxWidth: {
@@ -63,6 +97,7 @@ export default {
97 "basis-1/5"
98 ],
99 plugins: [
100 + require("@tailwindcss/container-queries"),
101 plugin(({ addBase, theme }) => {
102 addBase({
103 h1: {
frontend/vite.config.ts
+2 -1
@@ -59,7 +59,8 @@ export default defineConfig(({ mode }) => {
59 css: {
60 preprocessorOptions: {
61 scss: {
62 - silenceDeprecations: ["legacy-js-api"]
62 + silenceDeprecations: ["legacy-js-api", "import"],
63 + api: "modern-compiler"
64 }
65 }
66 }