main
vue 81 lines 2.65 KB
Raw
1 <template>
2 <div v-if="event" class="flex flex-col gap-3">
3 <div class="flex items-center justify-between gap-3">
4 <p class="text-secondary text-[10px] font-medium tracking-widest uppercase">Event fields</p>
5 <span class="text-default font-mono text-xs tabular-nums">{{ sortedFields.length }}</span>
6 </div>
7
8 <dl class="border-border divide-border divide-y rounded-lg border">
9 <div
10 v-for="[key, value] in sortedFields"
11 :key
12 class="group hover:bg-hover-005 flex items-start gap-3 px-3 py-2.5 transition-colors"
13 >
14 <dt class="text-secondary max-w-44 min-w-36 shrink-0 truncate font-mono text-xs" :title="key">
15 {{ key }}
16 </dt>
17 <dd class="flex min-w-0 flex-1 items-start justify-end gap-3">
18 <span class="text-default min-w-0 flex-1 text-right font-mono text-xs break-all">
19 {{ formatValue(value) }}
20 </span>
21 <div class="flex shrink-0 gap-0.5 opacity-0 transition-opacity group-hover:opacity-100">
22 <n-tooltip placement="top" class="px-2! py-1! text-xs!">
23 <template #trigger>
24 <n-button size="tiny" quaternary @click="emit('filter-add', key, String(value))">
25 <template #icon>
26 <Icon :name="FilterAddIcon" :size="14" />
27 </template>
28 </n-button>
29 </template>
30 Include in query
31 </n-tooltip>
32 <n-tooltip placement="top" class="px-2! py-1! text-xs!">
33 <template #trigger>
34 <n-button size="tiny" quaternary @click="emit('filter-exclude', key, String(value))">
35 <template #icon>
36 <Icon :name="FilterRemoveIcon" :size="14" />
37 </template>
38 </n-button>
39 </template>
40 Exclude from query
41 </n-tooltip>
42 </div>
43 </dd>
44 </div>
45 </dl>
46 </div>
47
48 <n-empty v-else description="No event selected" class="h-48 justify-center" />
49 </template>
50
51 <script setup lang="ts">
52 import type { EventSearchResult } from "@/types/events.d"
53 import { NButton, NEmpty, NTooltip } from "naive-ui"
54 import { computed } from "vue"
55 import Icon from "@/components/common/Icon.vue"
56
57 const props = defineProps<{
58 event: EventSearchResult | null
59 }>()
60
61 const emit = defineEmits<{
62 "filter-add": [field: string, value: string]
63 "filter-exclude": [field: string, value: string]
64 }>()
65
66 const FilterAddIcon = "carbon:filter"
67 const FilterRemoveIcon = "carbon:filter-remove"
68
69 const sortedFields = computed(() => {
70 if (!props.event) return []
71 return Object.entries(props.event)
72 .filter(([key]) => !key.startsWith("_"))
73 .sort(([a], [b]) => a.localeCompare(b))
74 })
75
76 function formatValue(value: unknown): string {
77 if (value === null || value === undefined) return ""
78 if (typeof value === "object") return JSON.stringify(value)
79 return String(value)
80 }
81 </script>