main
vue 231 lines 6.12 KB
Raw
1 <template>
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 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
9 v-model:value="timeUnit"
10 :options="timeUnitOptions"
11 placeholder="Time unit"
12 class="min-w-28! basis-1"
13 />
14 <n-input-number v-model:value="timeValue" :min="1" placeholder="Time" class="grow" />
15 </n-input-group>
16 </n-form-item>
17
18 <n-form-item label="Organization" class="flex grow">
19 <n-select
20 v-model:value="selectedOrgId"
21 :options="orgsOptions"
22 :loading="loadingOrgs"
23 clearable
24 />
25 </n-form-item>
26
27 <n-form-item v-if="canSelectDashboard" label="Dashboard" class="flex grow">
28 <n-select
29 v-model:value="selectedDashboardUID"
30 :options="dashboardsOptions"
31 :loading="loadingDashboards"
32 clearable
33 />
34 </n-form-item>
35 </div>
36 <div v-if="!hidePanelsSelect" class="flex">
37 <n-form-item v-if="canSelectPanels" label="Panels" class="grow">
38 <n-select
39 v-model:value="selectedPanelsIds"
40 :options="panelsOptions"
41 :loading="loadingPanels"
42 multiple
43 clearable
44 />
45 </n-form-item>
46 </div>
47 </n-form>
48 </n-spin>
49 </div>
50 </template>
51
52 <script setup lang="ts">
53 import type { ReportTimeRange, RowPanelTimeUnit } from "@/api/endpoints/reporting"
54 import type { Dashboard, Org, Panel } from "@/types/reporting.d"
55 import { useStorage } from "@vueuse/core"
56 import { NForm, NFormItem, NInputGroup, NInputNumber, NSelect, NSpin, useMessage } from "naive-ui"
57 import { computed, onBeforeMount, ref, toRefs, watch } from "vue"
58 import Api from "@/api"
59
60 const props = defineProps<{
61 hidePanelsSelect?: boolean
62 }>()
63
64 const emit = defineEmits<{
65 (e: "selected", value: Panel[]): void
66 (e: "panels", value: Panel[]): void
67 (e: "dashboard", value: Dashboard | null): void
68 (e: "organization", value: Org | null): void
69 (e: "timerange", value: ReportTimeRange): void
70 }>()
71
72 const { hidePanelsSelect } = toRefs(props)
73
74 const message = useMessage()
75 const orgsList = ref<Org[]>([])
76 const dashboardsList = ref<Dashboard[]>([])
77 const panelsList = ref<Panel[]>([])
78
79 const loadingOrgs = ref(false)
80 const loadingDashboards = ref(false)
81 const loadingPanels = ref(false)
82
83 const selectedOrgId = ref<number | string | null>(null)
84 const selectedOrg = computed(() =>
85 selectedOrgId.value ? orgsList.value.find(o => o.id === selectedOrgId.value) || null : null
86 )
87 const selectedDashboardUID = ref<string | null>(null)
88 const selectedDashboard = computed(() =>
89 selectedDashboardUID.value ? dashboardsList.value.find(o => o.uid === selectedDashboardUID.value) || null : null
90 )
91 const selectedPanelsIds = ref<number[]>([])
92 const selectedPanels = computed(() =>
93 selectedPanelsIds.value ? panelsList.value.filter(o => selectedPanelsIds.value.includes(o.id)) : []
94 )
95 const timeUnit = useStorage<RowPanelTimeUnit>("report-wizard-time-unit", "h", localStorage)
96 const timeValue = useStorage<number>("report-wizard-time-value", 1, localStorage)
97
98 const orgsOptions = computed(() => orgsList.value.map(o => ({ value: o.id, label: o.name })))
99 const dashboardsOptions = computed(() => dashboardsList.value.map(o => ({ value: o.uid, label: o.title })))
100 const panelsOptions = computed(() => panelsList.value.map(o => ({ value: o.id, label: o.title })))
101 const timeUnitOptions: { label: string; value: RowPanelTimeUnit }[] = [
102 { label: "Minutes", value: "m" },
103 { label: "Hours", value: "h" },
104 { label: "Days", value: "d" }
105 ]
106
107 const canSelectDashboard = computed(() => !!selectedOrgId.value)
108 const canSelectPanels = computed(() => canSelectDashboard.value && !!selectedDashboardUID.value)
109
110 const loading = computed(() => loadingOrgs.value || loadingDashboards.value || loadingPanels.value)
111
112 watch(
113 selectedOrgId,
114 val => {
115 dashboardsList.value = []
116 panelsList.value = []
117 selectedDashboardUID.value = null
118 selectedPanelsIds.value = []
119
120 emit("organization", selectedOrg.value)
121
122 if (val) {
123 getDashboards()
124 }
125 },
126 { immediate: true }
127 )
128
129 watch(
130 selectedDashboardUID,
131 val => {
132 panelsList.value = []
133 selectedPanelsIds.value = []
134
135 emit("dashboard", selectedDashboard.value)
136
137 if (val) {
138 getPanels()
139 }
140 },
141 { immediate: true }
142 )
143
144 watch(
145 panelsList,
146 val => {
147 emit("panels", val)
148 },
149 { immediate: true }
150 )
151
152 watch(selectedPanelsIds, () => {
153 emit("selected", selectedPanels.value)
154 })
155
156 watch(
157 [timeValue, timeUnit],
158 ([value, unit]) => {
159 emit("timerange", `${value}${unit}`)
160 },
161 { immediate: true }
162 )
163
164 function getOrgs() {
165 loadingOrgs.value = true
166
167 Api.reporting
168 .getOrgs()
169 .then(res => {
170 if (res.data.success) {
171 orgsList.value = res.data?.orgs || []
172 } else {
173 message.warning(res.data?.message || "An error occurred. Please try again later.")
174 }
175 })
176 .catch(err => {
177 message.error(err.response?.data?.message || "An error occurred. Please try again later.")
178 })
179 .finally(() => {
180 loadingOrgs.value = false
181 })
182 }
183
184 function getDashboards() {
185 if (selectedOrgId.value) {
186 loadingDashboards.value = true
187
188 Api.reporting
189 .getDashboards(selectedOrgId.value.toString())
190 .then(res => {
191 if (res.data.success) {
192 dashboardsList.value = res.data?.dashboards || []
193 } else {
194 message.warning(res.data?.message || "An error occurred. Please try again later.")
195 }
196 })
197 .catch(err => {
198 message.error(err.response?.data?.message || "An error occurred. Please try again later.")
199 })
200 .finally(() => {
201 loadingDashboards.value = false
202 })
203 }
204 }
205
206 function getPanels() {
207 if (selectedDashboardUID.value) {
208 loadingPanels.value = true
209
210 Api.reporting
211 .getPanels(selectedDashboardUID.value.toString())
212 .then(res => {
213 if (res.data.success) {
214 panelsList.value = res.data?.panels || []
215 } else {
216 message.warning(res.data?.message || "An error occurred. Please try again later.")
217 }
218 })
219 .catch(err => {
220 message.error(err.response?.data?.message || "An error occurred. Please try again later.")
221 })
222 .finally(() => {
223 loadingPanels.value = false
224 })
225 }
226 }
227
228 onBeforeMount(() => {
229 getOrgs()
230 })
231 </script>