mirror of
https://github.com/Litlyx/litlyx
synced 2025-12-09 23:48:36 +01:00
update menu + add event page
This commit is contained in:
BIN
dashboard/assets/fonts/GeistVF.ttf
Normal file
BIN
dashboard/assets/fonts/GeistVF.ttf
Normal file
Binary file not shown.
@@ -10,7 +10,16 @@
|
|||||||
@import url('https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,100;0,300;0,400;0,700;0,900;1,100;1,300;1,400;1,700;1,900&display=swap');
|
@import url('https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,100;0,300;0,400;0,700;0,900;1,100;1,300;1,400;1,700;1,900&display=swap');
|
||||||
@import url('https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap');
|
@import url('https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap');
|
||||||
|
|
||||||
// @import url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css");
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Geist";
|
||||||
|
src: url("../fonts/GeistVF.ttf");
|
||||||
|
}
|
||||||
|
|
||||||
|
.geist {
|
||||||
|
font-family: "Geist";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.fas,
|
.fas,
|
||||||
.far,
|
.far,
|
||||||
|
|||||||
@@ -20,74 +20,57 @@ type Props = {
|
|||||||
sections: Section[]
|
sections: Section[]
|
||||||
}
|
}
|
||||||
|
|
||||||
const { isOpen, open, close, toggle } = useMenu()
|
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const props = defineProps<Props>();
|
const props = defineProps<Props>();
|
||||||
|
|
||||||
const { isAdmin } = useUserRoles();
|
const { isAdmin } = useUserRoles();
|
||||||
|
|
||||||
|
const { isOpen, close } = useMenu();
|
||||||
let resizeHandler: any;
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
resizeHandler = () => {
|
|
||||||
isMenuTooLarge.value = innerHeight < 720;
|
|
||||||
}
|
|
||||||
addEventListener('resize', resizeHandler);
|
|
||||||
})
|
|
||||||
|
|
||||||
onUnmounted(() => {
|
|
||||||
if (resizeHandler) removeEventListener('resize', resizeHandler);
|
|
||||||
})
|
|
||||||
|
|
||||||
const isMenuTooLarge = ref<boolean>(false);
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="w-0 md:w-[5rem] absolute top-0 md:relative h-full">
|
<div class="CVerticalNavigation h-full w-[20rem] bg-[#111111] flex shadow-[1px_0_10px_#000000] rounded-r-lg" :class="{
|
||||||
<div @mouseover="open()" @mouseleave="close()"
|
'absolute top-0 w-full md:w-[20rem] z-[45] open': isOpen,
|
||||||
class="CVerticalNavigation absolute z-[80] bg-menu h-full overflow-hidden w-0 md:w-[5rem]"
|
'hidden lg:flex': !isOpen
|
||||||
: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" :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" :class="{ '!pb-3': isMenuTooLarge }" v-for="section of sections">
|
|
||||||
|
|
||||||
<div class="flex flex-col px-3 gap-2" :class="{ '!gap-[.3rem]': isMenuTooLarge }">
|
|
||||||
|
|
||||||
<template v-for="entry of section.entries">
|
|
||||||
|
|
||||||
<NuxtLink @click="entry.action?.()" :target="entry.external ? '_blank' : ''"
|
|
||||||
v-if="entry.to && (!entry.adminOnly || (isAdmin && !isAdminHidden))" tag="div"
|
|
||||||
:to="entry.to || '/'"
|
|
||||||
class="text-[#a3a9b6] flex w-full items-center gap-3 p-3 rounded-lg cursor-pointer hover:bg-[#363638] hover:text-[#ffffff]"
|
|
||||||
:class="{
|
|
||||||
'brightness-[.4] pointer-events-none': entry.disabled,
|
|
||||||
'bg-[#363638] shadow-[0px_0px_2px_#ffffff20_inset] border-[#ffffff20] border-[1px] !text-[#ffffff]': route.path == (entry.to || '#')
|
|
||||||
}">
|
}">
|
||||||
<div class="flex items-center text-[1.4rem] w-[1.8rem] justify-center">
|
<div class="p-4 gap-6 flex flex-col w-full">
|
||||||
|
|
||||||
|
<div class="flex items-center gap-2 ml-2">
|
||||||
|
<div class="bg-black h-[2.4rem] aspect-[1/1] flex items-center justify-center rounded-lg">
|
||||||
|
<img class="h-[2rem]" :src="'/logo.png'">
|
||||||
|
</div>
|
||||||
|
<div class="font-bold text-[1.4rem] text-gray-300"> Litlyx </div>
|
||||||
|
|
||||||
|
<div class="grow flex justify-end text-[1.4rem] mr-2 lg:hidden">
|
||||||
|
<i @click="close()" class="fas fa-close"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col gap-4">
|
||||||
|
|
||||||
|
<div v-for="section of sections" class="flex flex-col gap-1">
|
||||||
|
|
||||||
|
<div v-for="entry of section.entries">
|
||||||
|
|
||||||
|
<div class="bg-[#111111] text-gray-300 hover:bg-[#1b1b1b] py-2 px-4 rounded-lg" :class="{
|
||||||
|
'text-gray-700 pointer-events-none': entry.disabled,
|
||||||
|
'bg-[#1b1b1b]': route.path == (entry.to || '#')
|
||||||
|
}">
|
||||||
|
|
||||||
|
<NuxtLink @click="close() && entry.action?.()" :target="entry.external ? '_blank' : ''"
|
||||||
|
v-if="(!entry.adminOnly || (isAdmin && !isAdminHidden))" tag="div" class="flex"
|
||||||
|
:to="entry.to || '/'">
|
||||||
|
<div class="flex items-center w-[1.8rem] justify-start">
|
||||||
<i :class="entry.icon"></i>
|
<i :class="entry.icon"></i>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="isOpen" class="text-[.9rem] font-bold manrope"> {{ entry.label }} </div>
|
<div class="manrope">
|
||||||
|
{{ entry.label }}
|
||||||
|
</div>
|
||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
|
|
||||||
<div v-if="!entry.to" @click="entry.action?.()"
|
|
||||||
class="text-[#a3a9b6] flex w-full items-center gap-3 p-3 rounded-lg cursor-pointer hover:bg-[#363638] hover:text-[#ffffff]">
|
|
||||||
<div class="flex items-center text-[1.4rem] w-[1.8rem] justify-center">
|
|
||||||
<i :class="entry.icon"></i>
|
|
||||||
</div>
|
</div>
|
||||||
<div v-if="isOpen" class="text-[.9rem] font-bold manrope"> {{ entry.label }} </div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</template>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -100,12 +83,9 @@ const isMenuTooLarge = ref<boolean>(false);
|
|||||||
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.CVerticalNavigation {
|
|
||||||
transition: all .25s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.CVerticalNavigation * {
|
.CVerticalNavigation * {
|
||||||
font-family: 'Inter';
|
font-family: 'Geist';
|
||||||
}
|
}
|
||||||
|
|
||||||
input:focus {
|
input:focus {
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ type Props = {
|
|||||||
interactive?: boolean,
|
interactive?: boolean,
|
||||||
isDetailView?: boolean,
|
isDetailView?: boolean,
|
||||||
rawButton?: boolean,
|
rawButton?: boolean,
|
||||||
hideShowMore?: boolean
|
hideShowMore?: boolean,
|
||||||
|
customIconStyle?: string
|
||||||
}
|
}
|
||||||
const props = defineProps<Props>();
|
const props = defineProps<Props>();
|
||||||
const emits = defineEmits<{
|
const emits = defineEmits<{
|
||||||
@@ -97,8 +98,12 @@ function showDetails(id: string) {
|
|||||||
<div class="flex px-2 py-1 relative items-center gap-4">
|
<div class="flex px-2 py-1 relative items-center gap-4">
|
||||||
<div v-if="iconProvider && iconProvider(element._id) != undefined"
|
<div v-if="iconProvider && iconProvider(element._id) != undefined"
|
||||||
class="flex items-center h-[1.3rem]">
|
class="flex items-center h-[1.3rem]">
|
||||||
<img v-if="iconProvider(element._id)?.[0] == 'img'" class="h-full"
|
|
||||||
|
<img v-if="iconProvider(element._id)?.[0] == 'img'"
|
||||||
|
class="h-full"
|
||||||
|
:style="customIconStyle"
|
||||||
:src="iconProvider(element._id)?.[1]">
|
:src="iconProvider(element._id)?.[1]">
|
||||||
|
|
||||||
<i v-else :class="iconProvider(element._id)?.[1]"></i>
|
<i v-else :class="iconProvider(element._id)?.[1]"></i>
|
||||||
</div>
|
</div>
|
||||||
<span class="text-ellipsis line-clamp-1 ui-font z-[20] text-[.95rem] text-text/70">
|
<span class="text-ellipsis line-clamp-1 ui-font z-[20] text-[.95rem] text-text/70">
|
||||||
|
|||||||
@@ -1,10 +1,20 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
|
||||||
import type { CountriesAggregated } from '~/server/api/metrics/[project_id]/data/countries';
|
import type { CountriesAggregated } from '~/server/api/metrics/[project_id]/data/countries';
|
||||||
|
import type { IconProvider } from './BarsCard.vue';
|
||||||
|
|
||||||
const activeProject = await useActiveProject();
|
const activeProject = await useActiveProject();
|
||||||
const { data: countries, pending, refresh } = await useFetch<CountriesAggregated[]>(`/api/metrics/${activeProject.value?._id}/data/countries`, signHeaders());
|
const { data: countries, pending, refresh } = await useFetch<CountriesAggregated[]>(`/api/metrics/${activeProject.value?._id}/data/countries`, signHeaders());
|
||||||
|
|
||||||
|
function iconProvider(id: string): ReturnType<IconProvider> {
|
||||||
|
if (id === 'self') return ['icon', 'fas fa-link'];
|
||||||
|
return [
|
||||||
|
'img',
|
||||||
|
`https://raw.githubusercontent.com/hampusborgos/country-flags/main/png250px/${id.toLowerCase()}.png`
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
const customIconStyle = `width: 2rem; padding: 1px;`
|
||||||
|
|
||||||
const { showDialog, dialogBarData, isDataLoading } = useBarCardDialog();
|
const { showDialog, dialogBarData, isDataLoading } = useBarCardDialog();
|
||||||
|
|
||||||
@@ -29,7 +39,9 @@ function showMore() {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col gap-2">
|
<div class="flex flex-col gap-2">
|
||||||
<DashboardBarsCard @showMore="showMore()" @dataReload="refresh" :data="countries || []" :dataIcons="false" :loading="pending"
|
<DashboardBarsCard @showMore="showMore()" @dataReload="refresh" :data="countries || []" :dataIcons="false"
|
||||||
label="Top Countries" sub-label="Countries" desc=" Lists the countries where users access your website."></DashboardBarsCard>
|
:loading="pending" label="Top Countries" sub-label="Countries" :iconProvider="iconProvider"
|
||||||
|
:customIconStyle="customIconStyle" desc=" Lists the countries where users access your website.">
|
||||||
|
</DashboardBarsCard>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ onMounted(async () => {
|
|||||||
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="gap-6 px-6 grid grid-cols-1 md:grid-cols-2 xl:grid-cols-2 2xl:grid-cols-4" v-if="metricsInfo">
|
<div class="gap-6 px-6 grid grid-cols-1 md:grid-cols-2 xl:grid-cols-2 m-cards-wrap:grid-cols-4" v-if="metricsInfo">
|
||||||
|
|
||||||
<DashboardCountCard :ready="visitsData.ready" icon="far fa-earth" text="Total page visits"
|
<DashboardCountCard :ready="visitsData.ready" icon="far fa-earth" text="Total page visits"
|
||||||
:value="formatNumberK(metricsInfo.visitsCount)" :avg="formatNumberK(avgVisitDay) + '/day'"
|
:value="formatNumberK(metricsInfo.visitsCount)" :avg="formatNumberK(avgVisitDay) + '/day'"
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
const activeProject = useActiveProject();
|
const activeProject = useActiveProject();
|
||||||
|
|
||||||
|
|
||||||
const eventNames = ref<string[]>([]);
|
const eventNames = ref<string[]>([]);
|
||||||
const selectedEventName = ref<string>();
|
const selectedEventName = ref<string>();
|
||||||
const metadataFields = ref<string[]>([]);
|
const metadataFields = ref<string[]>([]);
|
||||||
|
|||||||
57
dashboard/components/events/EventsUserFlow.vue
Normal file
57
dashboard/components/events/EventsUserFlow.vue
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
|
||||||
|
const activeProject = useActiveProject();
|
||||||
|
|
||||||
|
const eventNames = ref<string[]>([]);
|
||||||
|
const selectedEventName = ref<string>();
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
eventNames.value = await $fetch<string[]>(`/api/metrics/${activeProject.value?._id.toString()}/events/names`, signHeaders());
|
||||||
|
});
|
||||||
|
|
||||||
|
const userFlowData = ref<any>();
|
||||||
|
const analyzing = ref<boolean>(false);
|
||||||
|
|
||||||
|
async function analyzeEvent() {
|
||||||
|
userFlowData.value = undefined;
|
||||||
|
analyzing.value = true;
|
||||||
|
userFlowData.value = await $fetch(`/api/metrics/${activeProject.value?._id.toString()}/events/flow_from_name?name=${selectedEventName.value}`, signHeaders());
|
||||||
|
analyzing.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<CardTitled title="Event User Flow"
|
||||||
|
sub="Track your user's journey from external links to custom events within your platform." class="w-full p-4">
|
||||||
|
|
||||||
|
<div class="p-2 flex flex-col gap-3">
|
||||||
|
<USelectMenu searchable searchable-placeholder="Search an event..." class="w-full"
|
||||||
|
placeholder="Select an event" :options="eventNames" v-model="selectedEventName">
|
||||||
|
</USelectMenu>
|
||||||
|
<div v-if="selectedEventName && !analyzing" class="flex justify-center">
|
||||||
|
<div @click="analyzeEvent()"
|
||||||
|
class="bg-bg w-fit px-8 py-2 poppins rounded-lg hover:bg-bg/80 cursor-pointer">
|
||||||
|
Analyze
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="analyzing">
|
||||||
|
Analyzing...
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col gap-2" v-if="userFlowData">
|
||||||
|
<div class="flex gap-4 items-center bg-bg py-1 px-2 rounded-lg" v-for="(count, referrer) in userFlowData">
|
||||||
|
<div class="w-5 h-5 flex items-center justify-center">
|
||||||
|
<img :src="`https://s2.googleusercontent.com/s2/favicons?domain=${referrer}&sz=64`" :alt="'referrer'">
|
||||||
|
</div>
|
||||||
|
<div> {{ referrer }} </div>
|
||||||
|
<div class="grow"></div>
|
||||||
|
<div> {{ count }} </div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</CardTitled>
|
||||||
|
</template>
|
||||||
@@ -61,8 +61,7 @@ const sections: Section[] = [
|
|||||||
|
|
||||||
const { showDialog, closeDialog } = useBarCardDialog();
|
const { showDialog, closeDialog } = useBarCardDialog();
|
||||||
|
|
||||||
|
const { isOpen, close, open } = useMenu();
|
||||||
const { open, isOpen, close } = useMenu();
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -73,7 +72,7 @@ const { open, isOpen, close } = useMenu();
|
|||||||
|
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="px-6 py-3 flex items-center justify-center shadow-[0_0_10px_#000000CC] z-[20] rounded-xl mx-2 my-2 md:hidden">
|
class="px-6 py-3 flex items-center justify-center shadow-[0_0_10px_#000000CC] z-[20] rounded-xl mx-2 my-2 lg:hidden">
|
||||||
<i @click="open()" class="fas fa-bars text-[1.2rem] absolute left-6"></i>
|
<i @click="open()" class="fas fa-bars text-[1.2rem] absolute left-6"></i>
|
||||||
<div class="nunito font-semibold text-[1.2rem]">
|
<div class="nunito font-semibold text-[1.2rem]">
|
||||||
Litlyx
|
Litlyx
|
||||||
@@ -82,13 +81,16 @@ const { open, isOpen, close } = useMenu();
|
|||||||
|
|
||||||
<div class="flex h-full">
|
<div class="flex h-full">
|
||||||
|
|
||||||
|
|
||||||
<div v-if="isOpen" @click="close()"
|
<div v-if="isOpen" @click="close()"
|
||||||
class="lg:hidden barrier bg-black/40 backdrop-blur-[2px] w-full h-full absolute left-0 top-0 z-[40]">
|
class="lg:hidden barrier bg-black/40 backdrop-blur-[2px] w-full h-full absolute left-0 top-0 z-[40]">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<CVerticalNavigation :sections="sections">
|
<CVerticalNavigation :sections="sections">
|
||||||
</CVerticalNavigation>
|
</CVerticalNavigation>
|
||||||
|
|
||||||
|
|
||||||
<div class="overflow-hidden w-full bg-bg relative h-full">
|
<div class="overflow-hidden w-full bg-bg relative h-full">
|
||||||
|
|
||||||
<div v-if="showDialog" class="barrier w-full h-full z-[34] absolute bg-black/50 backdrop-blur-[2px]">
|
<div v-if="showDialog" class="barrier w-full h-full z-[34] absolute bg-black/50 backdrop-blur-[2px]">
|
||||||
|
|||||||
@@ -13,11 +13,10 @@ const eventsStackedSelectIndex = ref<number>(0);
|
|||||||
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="w-full h-full overflow-y-auto pb-20 md:pt-4 lg:pt-0">
|
<div class="w-full h-full overflow-y-auto pb-20 p-6 gap-6 flex flex-col">
|
||||||
|
|
||||||
|
|
||||||
|
<div class="flex gap-6 flex-col xl:flex-row">
|
||||||
<div class="flex p-6 gap-6 flex-col xl:flex-row">
|
|
||||||
<CardTitled class="p-4 flex-[4]" title="Events" sub="Events stacked bar chart.">
|
<CardTitled class="p-4 flex-[4]" title="Events" sub="Events stacked bar chart.">
|
||||||
<template #header>
|
<template #header>
|
||||||
<SelectButton @changeIndex="eventsStackedSelectIndex = $event"
|
<SelectButton @changeIndex="eventsStackedSelectIndex = $event"
|
||||||
@@ -45,7 +44,11 @@ const eventsStackedSelectIndex = ref<number>(0);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex p-6">
|
<div class="flex">
|
||||||
|
<EventsUserFlow></EventsUserFlow>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex">
|
||||||
<EventsMetadataAnalyzer></EventsMetadataAnalyzer>
|
<EventsMetadataAnalyzer></EventsMetadataAnalyzer>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ const limitsInfo = ref<{
|
|||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
if (route.query.just_logged) return location.href = '/';
|
if (route.query.just_logged) return location.href = '/';
|
||||||
limitsInfo.value = await $fetch("/api/project/limits_info", signHeaders());
|
limitsInfo.value = await $fetch<any>("/api/project/limits_info", signHeaders());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -116,9 +116,9 @@ const selectLabelsEvents = [
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="p-6">
|
|
||||||
|
|
||||||
<CardTitled class="p-4 flex-1" title="Events" sub="Events stacked bar chart.">
|
<div class="flex gap-6 flex-col xl:flex-row p-6">
|
||||||
|
<CardTitled class="p-4 flex-[4]" title="Events" sub="Events stacked bar chart.">
|
||||||
<template #header>
|
<template #header>
|
||||||
<SelectButton @changeIndex="eventsStackedSelectIndex = $event"
|
<SelectButton @changeIndex="eventsStackedSelectIndex = $event"
|
||||||
:currentIndex="eventsStackedSelectIndex" :options="selectLabelsEvents">
|
:currentIndex="eventsStackedSelectIndex" :options="selectLabelsEvents">
|
||||||
@@ -129,7 +129,22 @@ const selectLabelsEvents = [
|
|||||||
</EventsStackedBarChart>
|
</EventsStackedBarChart>
|
||||||
</div>
|
</div>
|
||||||
</CardTitled>
|
</CardTitled>
|
||||||
|
|
||||||
|
<div class="bg-menu p-4 rounded-xl flex-[2] flex flex-col gap-10 h-full">
|
||||||
|
<div class="flex flex-col gap-1">
|
||||||
|
<div class="poppins font-semibold text-[1.4rem] text-text">
|
||||||
|
Top events
|
||||||
</div>
|
</div>
|
||||||
|
<div class="poppins text-[1rem] text-text-sub/90">
|
||||||
|
Displays key events.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<DashboardEventsChart class="w-full"> </DashboardEventsChart>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="flex w-full justify-center mt-6 px-6">
|
<div class="flex w-full justify-center mt-6 px-6">
|
||||||
<div class="flex w-full gap-6 flex-col lg:flex-row">
|
<div class="flex w-full gap-6 flex-col lg:flex-row">
|
||||||
|
|||||||
@@ -1,43 +0,0 @@
|
|||||||
<script lang="ts" setup>
|
|
||||||
|
|
||||||
definePageMeta({ layout: 'dashboard' });
|
|
||||||
|
|
||||||
const activeProject = useActiveProject();
|
|
||||||
|
|
||||||
|
|
||||||
const eventNames = ref<string[]>([]);
|
|
||||||
|
|
||||||
onMounted(async () => {
|
|
||||||
eventNames.value = await $fetch<string[]>(`/api/metrics/${activeProject.value?._id.toString()}/events/names`, signHeaders());
|
|
||||||
});
|
|
||||||
|
|
||||||
function test() {
|
|
||||||
const res = $fetch(`/api/metrics/${activeProject.value?._id.toString()}/events/flow_from_name?name=ToggleFavorite`, signHeaders());
|
|
||||||
console.log(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="w-full h-full p-8 flex flex-col">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<CardTitled title="FLOW" sub="owo" class="w-full p-4">
|
|
||||||
<div class="p-2 flex flex-col">
|
|
||||||
|
|
||||||
<button @click="test">
|
|
||||||
TEST
|
|
||||||
</button>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</CardTitled>
|
|
||||||
|
|
||||||
<div class="mt-8 overflow-y-auto px-4 flex flex-col gap-3">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
36
dashboard/pnpm-lock.yaml
generated
36
dashboard/pnpm-lock.yaml
generated
@@ -1373,12 +1373,21 @@ packages:
|
|||||||
'@vue/reactivity@3.4.27':
|
'@vue/reactivity@3.4.27':
|
||||||
resolution: {integrity: sha512-kK0g4NknW6JX2yySLpsm2jlunZJl2/RJGZ0H9ddHdfBVHcNzxmQ0sS0b09ipmBoQpY8JM2KmUw+a6sO8Zo+zIA==}
|
resolution: {integrity: sha512-kK0g4NknW6JX2yySLpsm2jlunZJl2/RJGZ0H9ddHdfBVHcNzxmQ0sS0b09ipmBoQpY8JM2KmUw+a6sO8Zo+zIA==}
|
||||||
|
|
||||||
|
'@vue/reactivity@3.4.28':
|
||||||
|
resolution: {integrity: sha512-B5uvZK0ArgBMkjK8RA9l5XP+PuQ/x99oqrcHRc78wa0pWyDje5X/isGihuiuSr0nFZTA5guoy78sJ6J8XxZv1A==}
|
||||||
|
|
||||||
'@vue/runtime-core@3.4.27':
|
'@vue/runtime-core@3.4.27':
|
||||||
resolution: {integrity: sha512-7aYA9GEbOOdviqVvcuweTLe5Za4qBZkUY7SvET6vE8kyypxVgaT1ixHLg4urtOlrApdgcdgHoTZCUuTGap/5WA==}
|
resolution: {integrity: sha512-7aYA9GEbOOdviqVvcuweTLe5Za4qBZkUY7SvET6vE8kyypxVgaT1ixHLg4urtOlrApdgcdgHoTZCUuTGap/5WA==}
|
||||||
|
|
||||||
|
'@vue/runtime-core@3.4.28':
|
||||||
|
resolution: {integrity: sha512-Corp5aAn5cm9h2cse6w5vRlnlfpy8hBRrsgCzHSoUohStlbqBXvI/uopPVkCivPCgY4fJZhXOufYYJ3DXzpN/w==}
|
||||||
|
|
||||||
'@vue/runtime-dom@3.4.27':
|
'@vue/runtime-dom@3.4.27':
|
||||||
resolution: {integrity: sha512-ScOmP70/3NPM+TW9hvVAz6VWWtZJqkbdf7w6ySsws+EsqtHvkhxaWLecrTorFxsawelM5Ys9FnDEMt6BPBDS0Q==}
|
resolution: {integrity: sha512-ScOmP70/3NPM+TW9hvVAz6VWWtZJqkbdf7w6ySsws+EsqtHvkhxaWLecrTorFxsawelM5Ys9FnDEMt6BPBDS0Q==}
|
||||||
|
|
||||||
|
'@vue/runtime-dom@3.4.28':
|
||||||
|
resolution: {integrity: sha512-y9lDMMFf2Y5GpYdE8+IuavVl95D1GY1Zp8jU1vZhQ3Z4ga3f0Ym+XxRhcFtqaQAm9u82GwB7zDpBxafWDRq4pw==}
|
||||||
|
|
||||||
'@vue/server-renderer@3.4.27':
|
'@vue/server-renderer@3.4.27':
|
||||||
resolution: {integrity: sha512-dlAMEuvmeA3rJsOMJ2J1kXU7o7pOxgsNHVr9K8hB3ImIkSuBrIdy0vF66h8gf8Tuinf1TK3mPAz2+2sqyf3KzA==}
|
resolution: {integrity: sha512-dlAMEuvmeA3rJsOMJ2J1kXU7o7pOxgsNHVr9K8hB3ImIkSuBrIdy0vF66h8gf8Tuinf1TK3mPAz2+2sqyf3KzA==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -1387,6 +1396,9 @@ packages:
|
|||||||
'@vue/shared@3.4.27':
|
'@vue/shared@3.4.27':
|
||||||
resolution: {integrity: sha512-DL3NmY2OFlqmYYrzp39yi3LDkKxa5vZVwxWdQ3rG0ekuWscHraeIbnI8t+aZK7qhYqEqWKTUdijadunb9pnrgA==}
|
resolution: {integrity: sha512-DL3NmY2OFlqmYYrzp39yi3LDkKxa5vZVwxWdQ3rG0ekuWscHraeIbnI8t+aZK7qhYqEqWKTUdijadunb9pnrgA==}
|
||||||
|
|
||||||
|
'@vue/shared@3.4.28':
|
||||||
|
resolution: {integrity: sha512-2b+Vuv5ichZQZPmRJfniHQkBSNigmRsRkr17bkYqBFy3J88T4lB7dRbAX/rx8qr9v0cr8Adg6yP872xhxGmh0w==}
|
||||||
|
|
||||||
'@vueuse/components@10.10.0':
|
'@vueuse/components@10.10.0':
|
||||||
resolution: {integrity: sha512-HiA10NQ9HJAGnju+8ZK4TyA8LIc0a6BnJmVWDa/k+TRhaYCVacSDU04k0BQ2otV+gghUDdwu98upf6TDRXpoeg==}
|
resolution: {integrity: sha512-HiA10NQ9HJAGnju+8ZK4TyA8LIc0a6BnJmVWDa/k+TRhaYCVacSDU04k0BQ2otV+gghUDdwu98upf6TDRXpoeg==}
|
||||||
|
|
||||||
@@ -6602,7 +6614,7 @@ snapshots:
|
|||||||
'@volar/language-core': 1.11.1
|
'@volar/language-core': 1.11.1
|
||||||
'@volar/source-map': 1.11.1
|
'@volar/source-map': 1.11.1
|
||||||
'@vue/compiler-dom': 3.4.27
|
'@vue/compiler-dom': 3.4.27
|
||||||
'@vue/shared': 3.4.27
|
'@vue/shared': 3.4.28
|
||||||
computeds: 0.0.1
|
computeds: 0.0.1
|
||||||
minimatch: 9.0.4
|
minimatch: 9.0.4
|
||||||
muggle-string: 0.3.1
|
muggle-string: 0.3.1
|
||||||
@@ -6615,17 +6627,33 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@vue/shared': 3.4.27
|
'@vue/shared': 3.4.27
|
||||||
|
|
||||||
|
'@vue/reactivity@3.4.28':
|
||||||
|
dependencies:
|
||||||
|
'@vue/shared': 3.4.28
|
||||||
|
|
||||||
'@vue/runtime-core@3.4.27':
|
'@vue/runtime-core@3.4.27':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vue/reactivity': 3.4.27
|
'@vue/reactivity': 3.4.27
|
||||||
'@vue/shared': 3.4.27
|
'@vue/shared': 3.4.27
|
||||||
|
|
||||||
|
'@vue/runtime-core@3.4.28':
|
||||||
|
dependencies:
|
||||||
|
'@vue/reactivity': 3.4.28
|
||||||
|
'@vue/shared': 3.4.28
|
||||||
|
|
||||||
'@vue/runtime-dom@3.4.27':
|
'@vue/runtime-dom@3.4.27':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vue/runtime-core': 3.4.27
|
'@vue/runtime-core': 3.4.27
|
||||||
'@vue/shared': 3.4.27
|
'@vue/shared': 3.4.27
|
||||||
csstype: 3.1.3
|
csstype: 3.1.3
|
||||||
|
|
||||||
|
'@vue/runtime-dom@3.4.28':
|
||||||
|
dependencies:
|
||||||
|
'@vue/reactivity': 3.4.28
|
||||||
|
'@vue/runtime-core': 3.4.28
|
||||||
|
'@vue/shared': 3.4.28
|
||||||
|
csstype: 3.1.3
|
||||||
|
|
||||||
'@vue/server-renderer@3.4.27(vue@3.4.27(typescript@5.4.2))':
|
'@vue/server-renderer@3.4.27(vue@3.4.27(typescript@5.4.2))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vue/compiler-ssr': 3.4.27
|
'@vue/compiler-ssr': 3.4.27
|
||||||
@@ -6634,6 +6662,8 @@ snapshots:
|
|||||||
|
|
||||||
'@vue/shared@3.4.27': {}
|
'@vue/shared@3.4.27': {}
|
||||||
|
|
||||||
|
'@vue/shared@3.4.28': {}
|
||||||
|
|
||||||
'@vueuse/components@10.10.0(vue@3.4.27(typescript@5.4.2))':
|
'@vueuse/components@10.10.0(vue@3.4.27(typescript@5.4.2))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vueuse/core': 10.10.0(vue@3.4.27(typescript@5.4.2))
|
'@vueuse/core': 10.10.0(vue@3.4.27(typescript@5.4.2))
|
||||||
@@ -10310,8 +10340,8 @@ snapshots:
|
|||||||
|
|
||||||
vue-chart-3@3.1.8(chart.js@3.9.1)(vue@3.4.27(typescript@5.4.2)):
|
vue-chart-3@3.1.8(chart.js@3.9.1)(vue@3.4.27(typescript@5.4.2)):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vue/runtime-core': 3.4.27
|
'@vue/runtime-core': 3.4.28
|
||||||
'@vue/runtime-dom': 3.4.27
|
'@vue/runtime-dom': 3.4.28
|
||||||
chart.js: 3.9.1
|
chart.js: 3.9.1
|
||||||
csstype: 3.1.3
|
csstype: 3.1.3
|
||||||
lodash-es: 4.17.21
|
lodash-es: 4.17.21
|
||||||
|
|||||||
@@ -3,6 +3,9 @@ module.exports = {
|
|||||||
content: [],
|
content: [],
|
||||||
theme: {
|
theme: {
|
||||||
extend: {
|
extend: {
|
||||||
|
screens: {
|
||||||
|
"m-cards-wrap": '1830px'
|
||||||
|
},
|
||||||
fontSize: {
|
fontSize: {
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user