mirror of
https://github.com/Litlyx/litlyx
synced 2025-12-10 15:58:38 +01:00
add event page + fix menu
This commit is contained in:
@@ -27,6 +27,23 @@ const props = defineProps<Props>();
|
||||
|
||||
const { isAdmin } = useUserRoles();
|
||||
|
||||
|
||||
let resizeHandler: any;
|
||||
|
||||
onMounted(() => {
|
||||
resizeHandler = () => {
|
||||
isMenuTooLarge.value = innerHeight < 720;
|
||||
}
|
||||
addEventListener('resize', resizeHandler);
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
if (resizeHandler) removeEventListener('resize', resizeHandler);
|
||||
})
|
||||
|
||||
const isMenuTooLarge = ref<boolean>(false);
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -35,16 +52,16 @@ const { isAdmin } = useUserRoles();
|
||||
class="CVerticalNavigation absolute z-[80] bg-menu h-full overflow-hidden w-0 md:w-[5rem]"
|
||||
:class="{ '!w-[18rem] shadow-[0_0_20px_#000000] rounded-r-2xl': isOpen }">
|
||||
<div :class="{ 'w-[18rem]': isOpen }">
|
||||
<div class="flex gap-4 items-center py-6 px-[.9rem] pb-8">
|
||||
<div class="flex gap-4 items-center py-6 px-[.9rem] pb-8" :class="{ '!pb-4': isMenuTooLarge }">
|
||||
<div class="bg-black h-[2.8rem] aspect-[1/1] flex items-center justify-center rounded-lg">
|
||||
<img class="h-[2.4rem]" :src="'/logo.png'">
|
||||
</div>
|
||||
<div v-if="isOpen" class="font-bold text-[1.4rem] text-gray-300"> Litlyx </div>
|
||||
</div>
|
||||
|
||||
<div class="pb-8" v-for="section of sections">
|
||||
<div class="pb-8" :class="{ '!pb-3': isMenuTooLarge }" v-for="section of sections">
|
||||
|
||||
<div class="flex flex-col px-3 gap-2">
|
||||
<div class="flex flex-col px-3 gap-2" :class="{ '!gap-[.3rem]': isMenuTooLarge }">
|
||||
|
||||
<template v-for="entry of section.entries">
|
||||
|
||||
|
||||
103
dashboard/components/events/EventsMetadataAnalyzer.vue
Normal file
103
dashboard/components/events/EventsMetadataAnalyzer.vue
Normal file
@@ -0,0 +1,103 @@
|
||||
<script lang="ts" setup>
|
||||
|
||||
const activeProject = useActiveProject();
|
||||
|
||||
|
||||
const eventNames = ref<string[]>([]);
|
||||
const selectedEventName = ref<string>();
|
||||
const metadataFields = ref<string[]>([]);
|
||||
const selectedMetadataField = ref<string>();
|
||||
const metadataFieldGrouped = ref<any[]>([]);
|
||||
|
||||
onMounted(async () => {
|
||||
eventNames.value = await $fetch<string[]>(`/api/metrics/${activeProject.value?._id.toString()}/events/names`, signHeaders());
|
||||
});
|
||||
|
||||
watch(selectedEventName, () => {
|
||||
getMetadataFields();
|
||||
});
|
||||
|
||||
watch(selectedMetadataField, () => {
|
||||
getMetadataFieldGrouped();
|
||||
});
|
||||
|
||||
async function getMetadataFields() {
|
||||
metadataFields.value = await $fetch<string[]>(`/api/metrics/${activeProject.value?._id.toString()}/events/metadata_fields?name=${selectedEventName.value}`, signHeaders());
|
||||
selectedMetadataField.value = undefined;
|
||||
currentSearchText.value = "";
|
||||
}
|
||||
|
||||
async function getMetadataFieldGrouped() {
|
||||
if (!selectedMetadataField.value) return;
|
||||
metadataFieldGrouped.value = await $fetch<string[]>(`/api/metrics/${activeProject.value?._id.toString()}/events/metadata_field_group?name=${selectedEventName.value}&field=${selectedMetadataField.value}`, signHeaders());
|
||||
}
|
||||
|
||||
|
||||
const metadataFieldGroupedFiltered = computed(() => {
|
||||
if (currentSearchText.value.length == 0) return metadataFieldGrouped.value;
|
||||
return metadataFieldGrouped.value.filter(e => {
|
||||
const currentId: string = e._id || '';
|
||||
const idToMatch = currentId.toLowerCase();
|
||||
return idToMatch.includes(currentSearchText.value.toLowerCase());
|
||||
});
|
||||
});
|
||||
|
||||
const currentSearchText = ref<string>("");
|
||||
|
||||
const canSearch = computed(() => {
|
||||
return selectedMetadataField.value != undefined;
|
||||
});
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
|
||||
<CardTitled title="Event metadata analyzer" sub="Filter events metadata fields to analyze them" class="w-full p-4">
|
||||
|
||||
<div class="p-2 flex flex-col">
|
||||
|
||||
<div class="flex flex-col gap-2">
|
||||
<USelectMenu searchable searchable-placeholder="Search an event..." class="w-full"
|
||||
placeholder="Select an event" :options="eventNames" v-model="selectedEventName">
|
||||
</USelectMenu>
|
||||
|
||||
<USelectMenu v-if="metadataFields.length > 0" searchable searchable-placeholder="Search a field..."
|
||||
class="w-full" placeholder="Select a field" :options="metadataFields"
|
||||
v-model="selectedMetadataField">
|
||||
</USelectMenu>
|
||||
</div>
|
||||
|
||||
<div v-if="canSearch" class="flex gap-4 mt-4 items-center">
|
||||
<div> Filter by name: </div>
|
||||
<div class="h-full flex items-center text-[1.2rem]">
|
||||
<input v-model="currentSearchText"
|
||||
class="bg-black/70 hover:bg-black/40 rounded-lg px-4 py-1 focus:outline-none" type="text">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mt-8 overflow-y-auto px-4 flex flex-col gap-3">
|
||||
|
||||
<div class="text-accent poppins font-semibold">
|
||||
Search results: {{ metadataFieldGroupedFiltered.length }}
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col">
|
||||
<div v-for="item of metadataFieldGroupedFiltered">
|
||||
<div class="flex gap-2">
|
||||
<div> {{ item._id || 'OLD_EVENTS' }} </div>
|
||||
<div> {{ item.count }} </div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</CardTitled>
|
||||
|
||||
|
||||
</template>
|
||||
Reference in New Issue
Block a user