Files
service-finder/frontend_admin/components/RawDataViewer.vue
2026-07-02 11:52:22 +00:00

124 lines
4.9 KiB
Vue

<template>
<div>
<!-- Empty state -->
<div v-if="!data || isEmpty(data)" class="text-center py-8">
<svg class="w-10 h-10 mx-auto mb-3 text-slate-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4" />
</svg>
<p class="text-sm text-slate-500">Nincs nyers adat</p>
</div>
<!-- JSON tree view -->
<div v-else class="space-y-1 font-mono text-xs">
<div
v-for="(value, key) in data"
:key="key"
class="border-b border-slate-700/50 last:border-0"
>
<div class="flex items-start gap-3 py-2">
<!-- Key -->
<span class="text-indigo-400 font-semibold whitespace-nowrap min-w-[140px] flex-shrink-0">
{{ key }}
</span>
<!-- Value -->
<div class="flex-1 min-w-0">
<!-- Null -->
<span v-if="value === null || value === undefined" class="text-slate-500 italic">null</span>
<!-- String -->
<span v-else-if="typeof value === 'string'" class="text-emerald-300 break-words">
"{{ value }}"
</span>
<!-- Number / Boolean -->
<span v-else-if="typeof value === 'number' || typeof value === 'boolean'" class="text-amber-300">
{{ value }}
</span>
<!-- Array -->
<div v-else-if="Array.isArray(value)">
<template v-if="value.length === 0">
<span class="text-slate-500 italic">[]</span>
</template>
<template v-else>
<details class="group">
<summary class="cursor-pointer text-slate-400 hover:text-slate-300 list-none flex items-center gap-1.5">
<svg class="w-3 h-3 transition-transform group-open:rotate-90" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
</svg>
<span class="text-slate-400">Array [{{ value.length }}]</span>
</summary>
<div class="ml-4 mt-1 space-y-1 border-l border-slate-700 pl-3">
<div v-for="(item, idx) in value" :key="idx" class="py-1">
<span class="text-slate-500 mr-2">[{{ idx }}]</span>
<span v-if="typeof item === 'object' && item !== null" class="text-slate-400">
<RawDataViewer :data="item" />
</span>
<span v-else-if="typeof item === 'string'" class="text-emerald-300">"{{ item }}"</span>
<span v-else class="text-amber-300">{{ item }}</span>
</div>
</div>
</details>
</template>
</div>
<!-- Object (nested JSON) -->
<div v-else-if="typeof value === 'object'">
<details class="group">
<summary class="cursor-pointer text-slate-400 hover:text-slate-300 list-none flex items-center gap-1.5">
<svg class="w-3 h-3 transition-transform group-open:rotate-90" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
</svg>
<span class="text-slate-400">Object {{ objectKeys(value) }}</span>
</summary>
<div class="ml-4 mt-1 border-l border-slate-700 pl-3">
<RawDataViewer :data="value" />
</div>
</details>
</div>
<!-- Fallback -->
<span v-else class="text-slate-400">{{ String(value) }}</span>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
/**
* RawDataViewer.vue
*
* Egy Vue 3 komponens, amely egy JSON/objektum adatot jelenít meg
* strukturált, fa-szerű nézetben. Támogatja a beágyazott objektumokat
* és tömböket összecsukható (details/summary) elemekkel.
*
* Props:
* data - Object | null - A megjelenítendő nyers adat (JSON)
*/
defineProps<{
data: Record<string, any> | null
}>()
/**
* Ellenőrzi, hogy egy objektum üres-e (nincs saját enumerable tulajdonsága).
*/
function isEmpty(obj: Record<string, any>): boolean {
if (!obj || typeof obj !== 'object') return true
return Object.keys(obj).length === 0
}
/**
* Visszaadja az objektum kulcsainak számát szöveges formában,
* pl. "{ 3 kulcs }" vagy "{ üres }"
*/
function objectKeys(obj: Record<string, any>): string {
if (!obj || typeof obj !== 'object') return '{ }'
const keys = Object.keys(obj)
if (keys.length === 0) return '{ üres }'
return `{ ${keys.length} kulcs }`
}
</script>