main
vue 152 lines 3.26 KB
Raw
1 <template>
2 <div class="indices-marquee">
3 <n-card content-class="p-0!" class="overflow-hidden">
4 <n-spin :show="loading" content-class="h-12">
5 <Vue3Marquee
6 v-if="list?.length"
7 class="marquee-wrap"
8 :duration="(list?.length || 0) * 1"
9 pause-on-hover
10 :clone="false"
11 gradient
12 :gradient-color
13 gradient-length="10%"
14 >
15 <span
16 v-for="item of list"
17 :key="item.index"
18 class="item flex items-center gap-2"
19 :class="item.health"
20 title="Click to select"
21 @click="emit('click', item)"
22 >
23 <IndexIcon :health="item.health" color />
24 {{ item.index }}
25 </span>
26 </Vue3Marquee>
27 <template v-else>
28 <n-empty
29 v-if="!loading"
30 class="h-full justify-center"
31 description="No indices found"
32 :show-icon="false"
33 />
34 </template>
35 </n-spin>
36 </n-card>
37 <div v-if="list?.length" class="info">
38 <i class="mdi mdi-information-outline"></i>
39 Click on an index to select
40 </div>
41 </div>
42 </template>
43
44 <script setup lang="ts">
45 // TODO-FE: refactor
46 import type { IndexStats } from "@/types/indices.d"
47 import { NCard, NEmpty, NSpin, useMessage } from "naive-ui"
48 import { computed, onBeforeMount, ref, toRefs, watch } from "vue"
49 import { Vue3Marquee } from "vue3-marquee"
50 import Api from "@/api"
51 import IndexIcon from "@/components/indices/IndexIcon.vue"
52 import { useThemeStore } from "@/stores/theme"
53
54 const props = defineProps<{
55 indices?: IndexStats[] | null
56 }>()
57
58 const emit = defineEmits<{
59 (e: "click", value: IndexStats): void
60 }>()
61
62 const { indices } = toRefs(props)
63 const list = ref(indices.value)
64 const message = useMessage()
65 const themeStore = useThemeStore()
66 const gradientColor = computed(() => themeStore.style["bg-default-color-rgb"]?.split(" ") ?? [])
67 const loading = ref(false)
68
69 function getIndices() {
70 loading.value = true
71
72 Api.wazuh.indices
73 .getIndices()
74 .then(res => {
75 if (res.data.success) {
76 list.value = res.data.indices_stats
77 } else {
78 message.error(res.data?.message || "An error occurred. Please try again later.")
79 }
80 })
81 .catch(err => {
82 if (err.response?.status === 401) {
83 message.error(
84 err.response?.data?.message ||
85 "Wazuh-Indexer returned Unauthorized. Please check your connector credentials."
86 )
87 } else if (err.response?.status === 404) {
88 message.error(err.response?.data?.message || "No indices were found.")
89 } else {
90 message.error(err.response?.data?.message || "An error occurred. Please try again later.")
91 }
92 })
93 .finally(() => {
94 loading.value = false
95 })
96 }
97
98 watch(indices, val => {
99 list.value = val
100 })
101
102 onBeforeMount(() => {
103 if (indices.value === undefined) {
104 getIndices()
105 }
106 })
107 </script>
108
109 <style lang="scss" scoped>
110 .indices-marquee {
111 .info {
112 opacity: 0.5;
113 font-size: var(--text-xs);
114 margin-top: 5px;
115 }
116 .marquee-wrap {
117 height: 100%;
118 transform: translate3d(0, 0, 0);
119
120 :deep() {
121 .marquee {
122 transform: translate3d(0, 0, 0);
123 }
124 .overlay {
125 &:after {
126 right: -1px;
127 }
128 }
129 }
130
131 .item {
132 padding: 10px 20px;
133 cursor: pointer;
134 line-height: 1;
135
136 &.green {
137 i {
138 color: var(--success-color);
139 }
140 }
141 &.yellow {
142 color: var(--warning-color);
143 font-weight: bold;
144 }
145 &.red {
146 color: var(--error-color);
147 font-weight: bold;
148 }
149 }
150 }
151 }
152 </style>