main
vue 169 lines 4.03 KB
Raw
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 flex grow gap-5">
5 <n-popover overlap placement="bottom-start">
6 <template #trigger>
7 <div class="bg-default rounded-lg">
8 <n-button size="small" class="cursor-help!">
9 <template #icon>
10 <Icon :name="InfoIcon" />
11 </template>
12 </n-button>
13 </div>
14 </template>
15 <div class="flex flex-col gap-2">
16 <div class="box">
17 Total:
18 <code>{{ total }}</code>
19 </div>
20 <div class="box">
21 Running:
22 <code>{{ totalRunning }}</code>
23 </div>
24 </div>
25 </n-popover>
26 </div>
27 <n-select
28 v-model:value="stateFilter"
29 :options="stateOptions"
30 clearable
31 placeholder="State..."
32 size="small"
33 style="width: 125px"
34 />
35 </div>
36 <n-scrollbar class="my-3">
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
44 @updated="getData('running')"
45 />
46 </template>
47 <template v-else>
48 <n-empty v-if="!loading" description="No items found" class="h-48 justify-center" />
49 </template>
50 </div>
51 </n-scrollbar>
52 </n-spin>
53 </template>
54
55 <script setup lang="ts">
56 import type { ConfiguredInput, InputExtended, RunningInput } from "@/types/graylog/inputs.d"
57 import { NButton, NEmpty, NPopover, NScrollbar, NSelect, NSpin, useMessage } from "naive-ui"
58 import { computed, onBeforeMount, ref } from "vue"
59 import Api from "@/api"
60 import Icon from "@/components/common/Icon.vue"
61 import InputItem from "./Item.vue"
62
63 const InfoIcon = "carbon:information"
64
65 const message = useMessage()
66 const loading = ref(false)
67 const configuredInputs = ref<ConfiguredInput[]>([])
68 const runningInputs = ref<RunningInput[]>([])
69
70 const total = computed(() => configuredInputs.value.length)
71 const totalRunning = computed(() => runningInputs.value.length)
72
73 const stateFilter = ref<null | number>(null)
74 const stateOptions = [
75 { label: "Not Running", value: 0 },
76 { label: "Running", value: 1 }
77 ]
78
79 const itemsSanitized = computed<InputExtended[]>(() => {
80 return configuredInputs.value.map(c => {
81 const runItem = runningInputs.value.find(r => r.id === c.id)
82 const res = c as InputExtended
83
84 res.state = runItem?.state || ""
85 res.started_at = runItem?.started_at || ""
86 res.detailed_message = runItem?.detailed_message || null
87
88 return res
89 })
90 })
91
92 const itemsFiltered = computed(() => {
93 return itemsSanitized.value.filter(o => {
94 switch (stateFilter.value) {
95 case 1:
96 return o.state === "RUNNING"
97 case 0:
98 return o.state === ""
99 default:
100 return true
101 }
102 })
103 })
104
105 function getData(type: "configured" | "running") {
106 loading.value = true
107
108 const endpoint = type === "configured" ? "getInputsConfigured" : "getInputsRunning"
109
110 Api.graylog[endpoint]()
111 .then(res => {
112 if (res.data.success) {
113 const data = res.data as {
114 configured_inputs?: ConfiguredInput[]
115 running_inputs?: RunningInput[]
116 }
117
118 if (data.configured_inputs !== undefined) {
119 configuredInputs.value = data?.configured_inputs || []
120 }
121 if (data.running_inputs !== undefined) {
122 runningInputs.value = data?.running_inputs || []
123 }
124 } else {
125 message.warning(res.data?.message || "An error occurred. Please try again later.")
126 }
127 })
128 .catch(err => {
129 message.error(err.response?.data?.message || "An error occurred. Please try again later.")
130 })
131 .finally(() => {
132 loading.value = false
133 })
134 }
135
136 onBeforeMount(() => {
137 getData("configured")
138 getData("running")
139 })
140 </script>
141
142 <style lang="scss" scoped>
143 .n-spin-container {
144 height: 100%;
145 max-height: 100%;
146 overflow: hidden;
147 box-sizing: border-box;
148
149 :deep() {
150 .n-spin-content {
151 height: 100%;
152 box-sizing: border-box;
153 display: flex;
154 flex-direction: column;
155 }
156 }
157 }
158
159 .header {
160 padding: var(--n-header-padding);
161 box-sizing: border-box;
162 padding-bottom: 0;
163 }
164 .list {
165 padding: var(--n-body-padding);
166 padding-top: 0;
167 padding-bottom: 0;
168 }
169 </style>