mirror of
https://github.com/Litlyx/litlyx
synced 2025-12-09 23:48:36 +01:00
implement domain filter
This commit is contained in:
@@ -80,7 +80,7 @@ function reloadPage() {
|
||||
|
||||
|
||||
<div class="flex items-center justify-center mt-10">
|
||||
<div class="flex flex-col-reverse gap-6">
|
||||
<div class="flex flex-col gap-6">
|
||||
|
||||
<div class="flex gap-6 xl:flex-row flex-col">
|
||||
|
||||
@@ -135,8 +135,8 @@ function reloadPage() {
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<CardTitled class="w-full h-full" title="Documentation"
|
||||
sub="Learn how to use Litlyx in every tech stack">
|
||||
<CardTitled class="w-full h-full" title="Modules"
|
||||
sub="Get started with your favorite framework.">
|
||||
<template #header>
|
||||
<LyxUiButton @click="Lit.event('no_visit_goto_docs')" type="secondary"
|
||||
to="https://docs.litlyx.com">
|
||||
|
||||
@@ -253,8 +253,6 @@ watch(readyToDisplay, () => {
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
function onDataReady() {
|
||||
if (!visitsData.data.value) return;
|
||||
if (!eventsData.data.value) return;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts" setup>
|
||||
|
||||
const { domainList, domain, setActiveDomain } = useDomain();
|
||||
const { domainList, domain, setActiveDomain, refreshDomains, refreshingDomains } = useDomain();
|
||||
|
||||
function onChange(e: string) {
|
||||
setActiveDomain(e);
|
||||
@@ -8,35 +8,41 @@ function onChange(e: string) {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex gap-2">
|
||||
<USelectMenu :uiMenu="{
|
||||
select: 'bg-lyx-lightmode-widget-light !ring-lyx-lightmode-widget dark:!bg-lyx-widget-light !shadow-none focus:!ring-lyx-widget-lighter dark:!ring-lyx-widget-lighter',
|
||||
base: '!bg-lyx-lightmode-widget dark:!bg-lyx-widget w-max',
|
||||
option: {
|
||||
base: 'z-[990] hover:!bg-lyx-lightmode-widget-light dark:hover:!bg-lyx-widget-lighter cursor-pointer',
|
||||
active: '!bg-lyx-lightmode-widget-light dark:!bg-lyx-widget-lighter'
|
||||
},
|
||||
input: 'z-[999] !bg-lyx-lightmode-widget dark:!bg-lyx-widget-light'
|
||||
}" class="w-full" searchable searchable-placeholder="Search domain..." v-if="domainList" @change="onChange"
|
||||
:value="domain" value-attribute="_id" :options="domainList">
|
||||
|
||||
<USelectMenu :uiMenu="{
|
||||
select: 'bg-lyx-lightmode-widget-light !ring-lyx-lightmode-widget dark:!bg-lyx-widget-light !shadow-none focus:!ring-lyx-widget-lighter dark:!ring-lyx-widget-lighter',
|
||||
base: '!bg-lyx-lightmode-widget dark:!bg-lyx-widget w-max',
|
||||
option: {
|
||||
base: 'z-[999] hover:!bg-lyx-lightmode-widget-light dark:hover:!bg-lyx-widget-lighter cursor-pointer',
|
||||
active: '!bg-lyx-lightmode-widget-light dark:!bg-lyx-widget-lighter'
|
||||
}
|
||||
}" class="w-full" searchable v-if="domainList" @change="onChange" :value="domain" :options="domainList">
|
||||
|
||||
<template #option="{ option, active, selected }">
|
||||
<div class="flex items-center gap-2">
|
||||
<div>
|
||||
<img class="h-5 bg-black rounded-full" :src="'/logo_32.png'" alt="Litlyx logo">
|
||||
<template #option="{ option, active, selected }">
|
||||
<div class="flex items-center gap-2">
|
||||
<div>
|
||||
<img class="h-5 bg-black rounded-full" :src="'/logo_32.png'" alt="Litlyx logo">
|
||||
</div>
|
||||
<div> {{ option._id }} </div>
|
||||
</div>
|
||||
<div> {{ option }} </div>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<template #label>
|
||||
<div class="flex items-center gap-2">
|
||||
<div>
|
||||
<img class="h-5 bg-black rounded-full" :src="'/logo_32.png'" alt="Litlyx logo">
|
||||
<template #label="e">
|
||||
<div class="flex items-center gap-2">
|
||||
<div>
|
||||
<img class="h-5 bg-black rounded-full" :src="'/logo_32.png'" alt="Litlyx logo">
|
||||
</div>
|
||||
<div>
|
||||
{{ domain || '-' }}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
{{ domain || '-' }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</USelectMenu>
|
||||
|
||||
</template>
|
||||
</USelectMenu>
|
||||
<div @click="refreshDomains" v-if="!refreshingDomains"
|
||||
class="flex items-center hover:rotate-[60deg] transition-all duration-200 ease-in-out cursor-pointer">
|
||||
<i class="far fa-refresh"></i>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -3,7 +3,7 @@
|
||||
const { token } = useAccessToken();
|
||||
const { projectId } = useProject();
|
||||
|
||||
const domainsRequest = useFetch<{ _id: string }[]>('/api/domains/list', {
|
||||
const domainsRequest = useFetch<{ _id: string, visits: number }[]>('/api/domains/list', {
|
||||
headers: computed(() => {
|
||||
return {
|
||||
'Authorization': `Bearer ${token.value}`,
|
||||
@@ -12,18 +12,30 @@ const domainsRequest = useFetch<{ _id: string }[]>('/api/domains/list', {
|
||||
})
|
||||
});
|
||||
|
||||
function refreshDomains() {
|
||||
domainsRequest.refresh();
|
||||
}
|
||||
|
||||
const refreshingDomains = computed(() => domainsRequest.pending.value);
|
||||
|
||||
const domainList = computed(() => {
|
||||
return domainsRequest.data.value?.map(e => e._id);
|
||||
return [
|
||||
{
|
||||
_id: 'ALL DOMAINS', visits: domainsRequest.data.value?.reduce((a, e) => a + e.visits, 0)
|
||||
},
|
||||
...(domainsRequest.data.value?.sort((a, b) => b.visits - a.visits) || [])
|
||||
]
|
||||
})
|
||||
|
||||
|
||||
const activeDomain = ref<string>();
|
||||
|
||||
const domain = computed(() => {
|
||||
if (activeDomain.value) return activeDomain.value;
|
||||
if (!domainList.value) return;
|
||||
if (domainList.value.length == 0) return;
|
||||
activeDomain.value = domainList.value[0];
|
||||
return domainList.value[0];
|
||||
setActiveDomain(domainList.value[0]._id);
|
||||
return domainList.value[0]._id;
|
||||
})
|
||||
|
||||
function setActiveDomain(domain: string) {
|
||||
@@ -31,6 +43,5 @@ function setActiveDomain(domain: string) {
|
||||
}
|
||||
|
||||
export function useDomain() {
|
||||
|
||||
return { domainList, domain, setActiveDomain }
|
||||
return { domainList, domain, setActiveDomain, refreshDomains, refreshingDomains }
|
||||
}
|
||||
@@ -7,7 +7,7 @@ definePageMeta({ layout: 'dashboard' });
|
||||
|
||||
const { snapshotDuration } = useSnapshot();
|
||||
|
||||
const selectedLabelIndex = ref<number>(0);
|
||||
const selectedLabelIndex = ref<number>(1);
|
||||
|
||||
const selectLabels: { label: string, value: Slice }[] = [
|
||||
{ label: 'Hour', value: 'hour' },
|
||||
@@ -21,7 +21,10 @@ const selectLabelsAvailable = computed<{ label: string, value: Slice, disabled:
|
||||
});
|
||||
})
|
||||
|
||||
const eventsData = await useFetch(`/api/data/count`, { headers: useComputedHeaders({ custom: { 'x-schema': 'events' } }), lazy: true });
|
||||
const eventsData = await useFetch(`/api/data/count`, {
|
||||
headers: useComputedHeaders({ custom: { 'x-schema': 'events' } }),
|
||||
lazy: true
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
@@ -54,9 +57,9 @@ const eventsData = await useFetch(`/api/data/count`, { headers: useComputedHeade
|
||||
sub="Events stacked bar chart.">
|
||||
<template #header>
|
||||
|
||||
<SelectButton class="w-fit" @changeIndex="selectedLabelIndex = $event" :currentIndex="selectedLabelIndex"
|
||||
:options="selectLabelsAvailable">
|
||||
</SelectButton>
|
||||
<SelectButton class="w-fit" @changeIndex="selectedLabelIndex = $event"
|
||||
:currentIndex="selectedLabelIndex" :options="selectLabelsAvailable">
|
||||
</SelectButton>
|
||||
|
||||
</template>
|
||||
<div class="h-full">
|
||||
|
||||
@@ -10,9 +10,9 @@ export default defineEventHandler(async event => {
|
||||
|
||||
const result = await VisitModel.aggregate([
|
||||
{ $match: { project_id, } },
|
||||
{ $group: { _id: "$website" } },
|
||||
{ $group: { _id: "$website", visits: { $sum: 1 } } },
|
||||
]);
|
||||
|
||||
return result as { _id: string }[];
|
||||
return result as { _id: string, visits: number }[];
|
||||
|
||||
});
|
||||
@@ -16,8 +16,7 @@ export default defineEventHandler(async event => {
|
||||
const timelineData = await executeAdvancedTimelineAggregation({
|
||||
projectId: project_id,
|
||||
model: VisitModel,
|
||||
from, to, slice, timeOffset, domain,
|
||||
debug: true
|
||||
from, to, slice, timeOffset, domain
|
||||
});
|
||||
return timelineData;
|
||||
});
|
||||
|
||||
@@ -56,10 +56,13 @@ export async function getRequestData(event: H3Event<EventHandlerRequest>, requir
|
||||
const pid = getHeader(event, 'x-pid');
|
||||
if (!pid) return setResponseStatus(event, 400, 'x-pid is required');
|
||||
|
||||
const domain = getHeader(event, 'x-domain');
|
||||
let domain: any = getHeader(event, 'x-domain');
|
||||
if (requireDomain) {
|
||||
if (domain == null || domain == undefined || domain.length == 0) return setResponseStatus(event, 400, 'x-domain is required');
|
||||
}
|
||||
if (domain === 'ALL DOMAINS') {
|
||||
domain = { $ne: '_NODOMAIN_' }
|
||||
}
|
||||
|
||||
const slice = getHeader(event, 'x-slice') as Slice;
|
||||
if (!slice && requireSlice) return setResponseStatus(event, 400, 'x-slice is required');
|
||||
|
||||
Reference in New Issue
Block a user