rewrite litlyx

This commit is contained in:
Emily
2024-10-08 15:12:04 +02:00
parent b27cacf4e6
commit 79e956e930
33 changed files with 231 additions and 214 deletions

11
TODO
View File

@@ -1,7 +1,14 @@
- Slice change on Actionable Chart
- Show more on Dashboard cards
- Fix devices Dashboard card, replace empty with "unkwnwn"
- Component first interaction must make the request inside
- Reactivity on project delete (update dropdown)
- Fix CSV Endpoint
- Devices remove empty
- docs vertical navigation not wfull
- project creation
- Event funnel / metadata analyzer / user flow
- Test guest actions
- Refactor UI Data analyst
- Remove Top Events from web analytics and move to custom events (with raw data access)
- Fix email on plan upgrade and resub

View File

@@ -1,19 +1,24 @@
<script lang="ts" setup>
const isShowMore = ref<boolean>(false);
const browsersData = useFetch('/api/data/browsers', {
headers: useComputedHeaders({
limit: computed(() => isShowMore.value ? '200' : '10'),
}), lazy: true
headers: useComputedHeaders({ limit: 10, }), lazy: true
});
const { showDialog, dialogBarData, isDataLoading } = useBarCardDialog();
function showMore() {
isShowMore.value = true;
async function showMore() {
dialogBarData.value=[];
showDialog.value = true;
dialogBarData.value = browsersData.data.value || [];
isDataLoading.value = true;
const res = await $fetch('/api/data/browsers', {
headers: useComputedHeaders({ limit: 1000 }).value
});
dialogBarData.value = res || [];
isDataLoading.value = false;
}
@@ -22,9 +27,9 @@ function showMore() {
<template>
<div class="flex flex-col gap-2">
<BarCardBase @showMore="showMore()" @dataReload="browsersData.refresh()"
:data="browsersData.data.value || []" desc="The browsers most used to search your website."
:dataIcons="false" :loading="browsersData.pending.value" label="Top Browsers" sub-label="Browsers">
<BarCardBase @showMore="showMore()" @dataReload="browsersData.refresh()" :data="browsersData.data.value || []"
desc="The browsers most used to search your website." :dataIcons="false"
:loading="browsersData.pending.value" label="Top Browsers" sub-label="Browsers">
</BarCardBase>
</div>
</template>

View File

@@ -1,21 +1,25 @@
<script lang="ts" setup>
const isShowMore = ref<boolean>(false);
const devicesData = useFetch('/api/data/devices', {
headers: useComputedHeaders({
limit: computed(() => isShowMore.value ? '200' : '10'),
}), lazy: true
headers: useComputedHeaders({ limit: 10, }), lazy: true
});
const { showDialog, dialogBarData, isDataLoading } = useBarCardDialog();
function showMore() {
isShowMore.value = true;
async function showMore() {
dialogBarData.value=[];
showDialog.value = true;
dialogBarData.value = devicesData.data.value || [];
isDataLoading.value = true;
const res = await $fetch('/api/data/devices', {
headers: useComputedHeaders({ limit: 1000 }).value
});
dialogBarData.value = res || [];
isDataLoading.value = false;
}

View File

@@ -6,20 +6,27 @@ function goToView() {
router.push('/dashboard/events');
}
const isShowMore = ref<boolean>(false);
const eventsData = useFetch('/api/data/events', {
headers: useComputedHeaders({
limit: computed(() => isShowMore.value ? '200' : '10'),
limit: 10,
}), lazy: true
});
const { showDialog, dialogBarData, isDataLoading } = useBarCardDialog();
function showMore() {
isShowMore.value = true;
async function showMore() {
dialogBarData.value=[];
showDialog.value = true;
dialogBarData.value = eventsData.data.value || [];
isDataLoading.value = true;
const res = await $fetch('/api/data/events', {
headers: useComputedHeaders({ limit: 1000 }).value
});
dialogBarData.value = res || [];
isDataLoading.value = false;
}
</script>

View File

@@ -12,25 +12,26 @@ function iconProvider(id: string): ReturnType<IconProvider> {
const customIconStyle = `width: 2rem; padding: 1px;`
const isShowMore = ref<boolean>(false);
const geolocationData = useFetch('/api/data/countries', {
headers: useComputedHeaders({
limit: computed(() => isShowMore.value ? '200' : '10'),
}), lazy: true
headers: useComputedHeaders({ limit: 10, }), lazy: true
});
const { showDialog, dialogBarData, isDataLoading } = useBarCardDialog();
function showMore() {
isShowMore.value = true;
async function showMore() {
dialogBarData.value=[];
showDialog.value = true;
isDataLoading.value = true;
dialogBarData.value = geolocationData.data.value?.map(e => {
const res = await $fetch('/api/data/countries', {
headers: useComputedHeaders({limit: 1000}).value
});
dialogBarData.value = res?.map(e => {
return { ...e, icon: iconProvider(e._id) }
}) || [];
isDataLoading.value = false;
}
@@ -40,9 +41,10 @@ function showMore() {
<template>
<div class="flex flex-col gap-2">
<BarCardBase @showMore="showMore()" @dataReload="geolocationData.refresh()" :data="geolocationData.data.value || []" :dataIcons="false"
:loading="geolocationData.pending.value" label="Top Countries" sub-label="Countries" :iconProvider="iconProvider"
:customIconStyle="customIconStyle" desc=" Lists the countries where users access your website.">
<BarCardBase @showMore="showMore()" @dataReload="geolocationData.refresh()"
:data="geolocationData.data.value || []" :dataIcons="false" :loading="geolocationData.pending.value"
label="Top Countries" sub-label="Countries" :iconProvider="iconProvider" :customIconStyle="customIconStyle"
desc=" Lists the countries where users access your website.">
</BarCardBase>
</div>
</template>

View File

@@ -1,23 +1,29 @@
<script lang="ts" setup>
const isShowMore = ref<boolean>(false);
const ossData = useFetch('/api/data/oss', {
headers: useComputedHeaders({
limit: computed(() => isShowMore.value ? '200' : '10'),
limit: 10,
}), lazy: true
});
const { showDialog, dialogBarData, isDataLoading } = useBarCardDialog();
function showMore() {
isShowMore.value = true;
async function showMore() {
dialogBarData.value=[];
showDialog.value = true;
dialogBarData.value = ossData.data.value || [];
isDataLoading.value = true;
const res = await $fetch('/api/data/oss', {
headers: useComputedHeaders({ limit: 1000 }).value
});
dialogBarData.value = res || [];
isDataLoading.value = false;
}
</script>

View File

@@ -12,22 +12,31 @@ function elementTextTransformer(element: string) {
return element;
}
const isShowMore = ref<boolean>(false);
const referrersData = useFetch('/api/data/referrers', {
headers: useComputedHeaders({
limit: computed(() => isShowMore.value ? '200' : '10'),
limit: 10,
}), lazy: true
});
const { showDialog, dialogBarData, isDataLoading } = useBarCardDialog();
function showMore() {
isShowMore.value = true;
async function showMore() {
dialogBarData.value=[];
showDialog.value = true;
dialogBarData.value = referrersData.data.value?.map(e => {
isDataLoading.value = true;
const res = await $fetch('/api/data/referrers', {
headers: useComputedHeaders({limit: 1000}).value
});
dialogBarData.value = res?.map(e => {
return { ...e, icon: iconProvider(e._id) }
}) || [];
isDataLoading.value = false;
}
</script>

View File

@@ -1,18 +1,16 @@
<script lang="ts" setup>
const isShowMore = ref<boolean>(false);
const currentWebsite = ref<string>("");
const websitesData = useFetch('/api/data/websites', {
headers: useComputedHeaders({
limit: computed(() => isShowMore.value ? '200' : '10'),
limit: 10,
}), lazy: true
});
const pagesData = useFetch('/api/data/websites_pages', {
headers: useComputedHeaders({
limit: computed(() => isShowMore.value ? '200' : '10'),
limit: 10,
custom: {
'x-website-name': currentWebsite
}

View File

@@ -114,7 +114,7 @@ const pricingDrawer = usePricingDrawer();
</script>
<template>
<div class="CVerticalNavigation h-full w-[20rem] bg-lyx-background flex shadow-[1px_0_10px_#000000] rounded-r-lg"
<div class="CVerticalNavigation border-solid border-[#202020] border-r-[1px] h-full w-[20rem] bg-lyx-background flex shadow-[1px_0_10px_#000000] rounded-r-lg"
:class="{
'absolute top-0 w-full md:w-[20rem] z-[45] open': isOpen,
'hidden lg:flex': !isOpen
@@ -141,11 +141,13 @@ const pricingDrawer = usePricingDrawer();
</div>
<NuxtLink to="/project_creation" v-if="projectList && (projectList.length < (maxProjects || 1))"
class="flex items-center text-[.8rem] gap-1 justify-end pt-2 pr-2 text-lyx-text-dark hover:text-lyx-text cursor-pointer">
<LyxUiButton to="/project_creation" v-if="projectList && (projectList.length < (maxProjects || 1))"
type="outlined" class="w-full py-1 mt-2 text-[.8rem]">
<div class="flex items-center gap-2 justify-center">
<div><i class="fas fa-plus"></i></div>
<div> Create new project </div>
</NuxtLink>
</div>
</LyxUiButton>
</div>
@@ -156,13 +158,23 @@ const pricingDrawer = usePricingDrawer();
<div class="poppins text-[.8rem]">
Snapshots
</div>
<div @click="openSnapshotDialog()"
class="poppins text-[.8rem] px-2 rounded-lg outline outline-[2px] outline-lyx-widget-lighter cursor-pointer hover:bg-lyx-widget-lighter">
<i class="far fa-plus"></i>
Add
</div>
<div class="flex gap-2">
<UTooltip text="Download report">
<LyxUiButton @click="generatePDF()" type="outlined" class="!px-3 !py-1">
<div><i class="far fa-download text-[.8rem]"></i></div>
</LyxUiButton>
</UTooltip>
<UTooltip text="Create new snapshot">
<LyxUiButton @click="openSnapshotDialog()" type="outlined" class="!px-3 !py-1">
<div><i class="fas fa-plus text-[.9rem]"></i></div>
</LyxUiButton>
</UTooltip>
</div>
</div>
<div class="flex items-center gap-2">
<USelectMenu :uiMenu="{
select: '!bg-lyx-widget-light !shadow-none focus:!ring-lyx-widget-lighter !ring-lyx-widget-lighter',
base: '!bg-lyx-widget',
@@ -186,22 +198,19 @@ const pricingDrawer = usePricingDrawer();
</div>
</template>
</USelectMenu>
<div v-if="snapshot" class="flex flex-col text-[.8rem] mt-2">
<div class="flex">
<div class="grow poppins"> From:</div>
<div class="poppins"> {{ new Date(snapshot.from).toLocaleString('it-IT').split(',')[0].trim() }}
</div>
</div>
<div class="flex">
<div class="grow poppins"> To:</div>
<div class="poppins"> {{ new Date(snapshot.to).toLocaleString('it-IT').split(',')[0].trim() }}
</div>
</div>
<LyxUiButton @click="generatePDF()" type="secondary" class="w-full text-center mt-4">
Download report
</LyxUiButton>
<div v-if="snapshot" class="flex flex-col text-[.7rem] mt-2">
<div class="flex gap-1 items-center justify-center text-lyx-text-dark">
<div class="poppins">
{{ new Date(snapshot.from).toLocaleString('it-IT').split(',')[0].trim().replace(/\//g, '-')
}}
</div>
<div class="poppins"> to </div>
<div class="poppins">
{{ new Date(snapshot.to).toLocaleString('it-IT').split(',')[0].trim().replace(/\//g, '-') }}
</div>
</div>
<div class="mt-2" v-if="snapshot._id.toString().startsWith('default') === false">
<UPopover placement="bottom">
@@ -226,7 +235,7 @@ const pricingDrawer = usePricingDrawer();
</div>
</div>
<div class="bg-lyx-widget-lighter h-[2px] w-full"></div>
<div class="bg-[#202020] h-[1px] w-full"></div>
<div class="flex flex-col h-full">
@@ -262,26 +271,28 @@ const pricingDrawer = usePricingDrawer();
</div>
<div class="grow"></div>
<div class="bg-lyx-widget-lighter h-[2px] px-4 w-full mb-3"></div>
<div class="bg-[#202020] h-[1px] w-full px-4 mb-3"></div>
<div class="flex justify-end px-2">
<div class="grow flex gap-3">
<NuxtLink to="https://github.com/litlyx/litlyx" target="_blank"
<!-- <NuxtLink to="https://github.com/litlyx/litlyx" target="_blank"
class="cursor-pointer hover:text-lyx-text text-lyx-text-dark">
<i class="fab fa-github"></i>
</NuxtLink>
<NuxtLink to="https://discord.gg/9cQykjsmWX" target="_blank"
</NuxtLink> -->
<!-- <NuxtLink to="https://discord.gg/9cQykjsmWX" target="_blank"
class="cursor-pointer hover:text-lyx-text text-lyx-text-dark">
<i class="fab fa-discord"></i>
</NuxtLink>
</NuxtLink> -->
<NuxtLink to="https://x.com/litlyx" target="_blank"
class="cursor-pointer hover:text-lyx-text text-lyx-text-dark">
<i class="fab fa-x-twitter"></i>
</NuxtLink>
<NuxtLink to="https://dev.to/litlyx-org" target="_blank"
<!-- <NuxtLink to="https://dev.to/litlyx-org" target="_blank"
class="cursor-pointer hover:text-lyx-text text-lyx-text-dark">
<i class="fab fa-dev"></i>
</NuxtLink>
</NuxtLink> -->
<NuxtLink to="/admin" v-if="userRoles.isAdmin"
class="cursor-pointer hover:text-lyx-text text-lyx-text-dark">
<i class="fas fa-cat"></i>

View File

@@ -136,6 +136,8 @@ const selectLabels: { label: string, value: Slice }[] = [
{ label: 'Month', value: 'month' },
];
const selectedSlice = computed(()=>selectLabels[selectedLabelIndex.value].value);
const selectedLabelIndex = ref<number>(1);
const allDatesFull = ref<string[]>([]);
@@ -157,17 +159,17 @@ function onResponse(e: any) {
const visitsData = useFetch('/api/timeline/visits', {
headers: useComputedHeaders({ slice: selectLabels[selectedLabelIndex.value].value }), lazy: true,
headers: useComputedHeaders({ slice: selectedSlice }), lazy: true,
transform: transformResponse, onResponseError, onResponse
});
const sessionsData = useFetch('/api/timeline/sessions', {
headers: useComputedHeaders({ slice: selectLabels[selectedLabelIndex.value].value }), lazy: true,
headers: useComputedHeaders({ slice: selectedSlice }), lazy: true,
transform: transformResponse, onResponseError, onResponse
});
const eventsData = useFetch('/api/timeline/events', {
headers: useComputedHeaders({ slice: selectLabels[selectedLabelIndex.value].value }), lazy: true,
headers: useComputedHeaders({ slice: selectedSlice }), lazy: true,
transform: transformResponse, onResponseError, onResponse
});

View File

@@ -98,19 +98,8 @@ function transformResponse(input: CustomEventsAggregated[]) {
}
}
const headers = computed(() => {
return {
'x-from': safeSnapshotDates.value.from,
'x-to': safeSnapshotDates.value.to,
'Authorization': authorizationHeaderComputed.value,
'x-schema': 'events',
'x-limit': "6",
'x-pid': projectId.value || ''
}
});
const eventsData = useFetch(`/api/data/query`, {
method: 'POST', headers, lazy: true, immediate: false, transform: transformResponse
const eventsData = useFetch(`/api/data/events`, {
method: 'POST', headers: useComputedHeaders({ limit: 6 }), lazy: true, immediate: false, transform: transformResponse
});
onMounted(() => {

View File

@@ -34,37 +34,37 @@ function showAnomalyInfoAlert() {
<template>
<div
class="w-full px-6 py-2 lg:py-6 font-bold text-text-sub/40 flex flex-col xl:flex-row text-lg gap-2 xl:gap-12 lg:text-2xl">
class="w-full px-6 pb-2 lg:pb-6 font-bold text-text-sub/40 flex flex-col xl:flex-row text-lg gap-2 xl:gap-12 lg:text-2xl">
<div class="flex gap-2 items-center text-text/90 justify-center md:justify-start">
<div class="animate-pulse w-[1rem] h-[1rem] bg-green-400 rounded-full"> </div>
<div class="poppins font-medium text-[1.2rem]"> {{ onlineUsers.data }} Online users</div>
<div class="poppins font-medium text-[.9rem]"> {{ onlineUsers.data }} Online users</div>
</div>
<div class="grow"></div>
<div class="flex md:gap-2 items-center md:justify-start flex-col md:flex-row">
<div class="poppins font-medium text-lyx-text-darker text-[1.2rem]">Project:</div>
<div class="text-lyx-text poppins font-medium text-[1.2rem]"> {{ project?.name || 'Loading...' }}
<!-- <div class="flex md:gap-2 items-center md:justify-start flex-col md:flex-row">
<div class="poppins font-medium text-lyx-text-darker text-[.9rem]">Project:</div>
<div class="text-lyx-text poppins font-medium text-[.9rem]"> {{ project?.name || 'Loading...' }}
</div>
</div>
<div class="flex flex-col md:flex-row md:gap-2 items-center md:justify-start">
<div class="poppins font-medium text-lyx-text-darker text-[1.2rem]">Project id:</div>
<div class="poppins font-medium text-lyx-text-darker text-[.9rem]">Project id:</div>
<div class="flex gap-2">
<div class="text-lyx-text poppins font-medium text-[1.2rem]">
<div class="text-lyx-text poppins font-medium text-[.9rem]">
{{ project?._id || 'Loading...' }}
</div>
<div class="flex items-center ml-3">
<i @click="copyProjectId()"
class="far fa-copy text-lyx-text hover:text-lyx-primary cursor-pointer text-[1.2rem]"></i>
</div>
class="far fa-copy text-lyx-text hover:text-lyx-primary cursor-pointer text-[.9rem]"></i>
</div>
</div>
</div> -->
<div class="flex gap-2 items-center text-text/90 justify-center md:justify-start">
<div class="animate-pulse w-[1rem] h-[1rem] bg-green-400 rounded-full"> </div>
<div class="poppins font-regular text-[1rem]"> AI Anomaly Detector </div>
<div class="poppins font-regular text-[.9rem]"> AI Anomaly Detector </div>
<div class="flex items-center">
<i class="far fa-info-circle text-[.9rem] hover:text-lyx-primary cursor-pointer"
@click="showAnomalyInfoAlert"></i>

View File

@@ -8,15 +8,6 @@ const slice = computed(() => props.slice);
const { safeSnapshotDates } = useSnapshot()
const body = computed(() => {
return {
from: safeSnapshotDates.value.from,
to: safeSnapshotDates.value.to,
slice: slice.value,
}
});
function transformResponse(input: { _id: string, name: string, count: number }[]) {
const fixed = fixMetrics({
@@ -90,9 +81,9 @@ function onResponse(e: any) {
}
const eventsStackedData = useFetch(`/api/timeline/events_stacked`, {
method: 'POST', body, lazy: true, immediate: false,
lazy: true, immediate: false,
transform: transformResponse,
headers: useComputedHeaders(),
headers: useComputedHeaders({slice}),
onResponseError,
onResponse
});

View File

@@ -2,7 +2,7 @@
import type { TApiSettings } from '@schema/ApiSettingsSchema';
import type { SettingsTemplateEntry } from './Template.vue';
const { project, actions, projectList } = useProject();
const { project, actions, projectList, isGuest, projectId } = useProject();
const entries: SettingsTemplateEntry[] = [
{ id: 'pname', title: 'Name', text: 'Project name' },
@@ -107,7 +107,7 @@ async function deleteProject() {
const firstProjectId = projectList.value?.[0]?._id.toString();
if (firstProjectId) {
await setActiveProject(firstProjectId);
await actions.setActiveProject(firstProjectId);
}
@@ -120,8 +120,6 @@ async function deleteProject() {
const { createAlert } = useAlert()
const activeProjectId = useActiveProjectId()
function copyScript() {
if (!navigator.clipboard) alert('You can\'t copy in HTTP');
@@ -129,7 +127,7 @@ function copyScript() {
const createScriptText = () => {
return [
'<script defer ',
`data-project="${activeProjectId.data.value}" `,
`data-project="${projectId.value}" `,
'src="https://cdn.jsdelivr.net/gh/litlyx/litlyx-js/browser/litlyx.js"></',
'script>'
].join('')
@@ -142,7 +140,7 @@ function copyScript() {
function copyProjectId() {
if (!navigator.clipboard) alert('You can\'t copy in HTTP');
navigator.clipboard.writeText(activeProjectId.data.value || '');
navigator.clipboard.writeText(projectId.value || '');
createAlert('Success', 'Project id copied successfully.', 'far fa-circle-check', 5000);
}

View File

@@ -1,7 +1,7 @@
<script setup lang="ts">
import type { SettingsTemplateEntry } from './Template.vue';
const { projectId } = useProject();
const { projectId, isGuest } = useProject();
definePageMeta({ layout: 'dashboard' });

View File

@@ -63,7 +63,7 @@ const project = computed(() => {
const isGuest = computed(() => {
return (projectList.value || []).find(e => e._id.toString() === activeProjectId.value);
return (projectList.value || []).find(e => e._id.toString() === activeProjectId.value) == undefined;
})
export function useProject() {

View File

@@ -1,7 +1,6 @@
import type { TProjectSnapshot } from "@schema/ProjectSnapshot";
const { projectId, project } = useProject();
const headers = computed(() => {

View File

@@ -13,8 +13,8 @@ const sections: Section[] = [
{
title: '',
entries: [
{ label: 'Dashboard', to: '/', icon: 'fal fa-table-layout' },
{ label: 'Events', to: '/events', icon: 'fal fa-square-bolt' },
{ label: 'Web Analytics', to: '/', icon: 'fal fa-table-layout' },
{ label: 'Custom Events', to: '/events', icon: 'fal fa-square-bolt' },
{ label: 'AI Analyst', to: '/analyst', icon: 'fal fa-sparkles' },
{ label: 'Security', to: '/security', icon: 'fal fa-shield' },
// { label: 'Insights (soon)', to: '#', icon: 'fal fa-lightbulb', disabled: true },
@@ -23,22 +23,27 @@ const sections: Section[] = [
{ label: 'Settings', to: '/settings', icon: 'fal fa-gear' },
{
grow: true,
label: 'Documentation', to: 'https://docs.litlyx.com', icon: 'fal fa-book', external: true,
label: 'Docs', to: 'https://docs.litlyx.com', icon: 'fal fa-book', external: true,
action() { Lit.event('docs_clicked') },
},
{
label: 'Slack support', icon: 'fab fa-slack',
to: '#',
premiumOnly: true,
action() {
if (isLogged.value === true) return;
if (userRoles.isPremium.value === true) {
window.open('https://join.slack.com/t/litlyx/shared_invite/zt-2q3oawn29-hZlu_fBUBlc4052Ooe3FZg', '_blank');
} else {
pricingDrawer.visible.value = true;
}
},
label: 'Discord support', icon: 'fab fa-discord',
to: 'https://discord.gg/9cQykjsmWX',
external: true,
},
// {
// label: 'Slack support', icon: 'fab fa-slack',
// to: '#',
// premiumOnly: true,
// action() {
// if (isLogged.value === true) return;
// if (userRoles.isPremium.value === true) {
// window.open('https://join.slack.com/t/litlyx/shared_invite/zt-2q3oawn29-hZlu_fBUBlc4052Ooe3FZg', '_blank');
// } else {
// pricingDrawer.visible.value = true;
// }
// },
// },
]
}
];
@@ -76,7 +81,7 @@ const { isOpen, close, open } = useMenu();
</CVerticalNavigation>
<div class="overflow-hidden w-full bg-lyx-background-light relative h-full">
<div class="overflow-hidden w-full bg-lyx-background relative h-full">
<div v-if="showDialog" class="barrier w-full h-full z-[34] absolute bg-black/50 backdrop-blur-[2px]">
<i

View File

@@ -4,9 +4,9 @@ import type { MetricsCounts } from '~/server/api/metrics/[project_id]/counts';
definePageMeta({ layout: 'dashboard' });
const activeProject = useActiveProject();
const {project} = useProject();
const isPremium = computed(() => (activeProject.value?.premium_type || 0) > 0);
const isPremium = computed(() => (project.value?.premium_type || 0) > 0);
const metricsInfo = ref<number>(0);
@@ -29,12 +29,12 @@ const totalItems = computed(() => metricsInfo.value);
const { data: tableData, pending: loadingData } = await useLazyFetch<any[]>(() =>
`/api/metrics/${activeProject.value?._id}/query?type=1&orderBy=${sort.value.column}&order=${sort.value.direction}&page=${page.value}&limit=${itemsPerPage}`, {
`/api/metrics/${project.value?._id}/query?type=1&orderBy=${sort.value.column}&order=${sort.value.direction}&page=${page.value}&limit=${itemsPerPage}`, {
...signHeaders(),
})
onMounted(async () => {
const counts = await $fetch<MetricsCounts>(`/api/metrics/${activeProject.value?._id}/counts`, signHeaders());
const counts = await $fetch<MetricsCounts>(`/api/metrics/${project.value?._id}/counts`, signHeaders());
metricsInfo.value = counts.eventsCount;
});

View File

@@ -4,9 +4,9 @@ import type { MetricsCounts } from '~/server/api/metrics/[project_id]/counts';
definePageMeta({ layout: 'dashboard' });
const activeProject = useActiveProject();
const {project} = useProject();
const isPremium = computed(() => (activeProject.value?.premium_type || 0) > 0);
const isPremium = computed(() => (project.value?.premium_type || 0) > 0);
const metricsInfo = ref<number>(0);
@@ -35,12 +35,12 @@ const totalItems = computed(() => metricsInfo.value);
const { data: tableData, pending: loadingData } = await useLazyFetch<any[]>(() =>
`/api/metrics/${activeProject.value?._id}/query?type=0&orderBy=${sort.value.column}&order=${sort.value.direction}&page=${page.value}&limit=${itemsPerPage}`, {
`/api/metrics/${project.value?._id}/query?type=0&orderBy=${sort.value.column}&order=${sort.value.direction}&page=${page.value}&limit=${itemsPerPage}`, {
...signHeaders(),
})
onMounted(async () => {
const counts = await $fetch<MetricsCounts>(`/api/metrics/${activeProject.value?._id}/counts`, signHeaders());
const counts = await $fetch<MetricsCounts>(`/api/metrics/${project.value?._id}/counts`, signHeaders());
metricsInfo.value = counts.visitsCount;
});

View File

@@ -10,21 +10,7 @@ const selectLabelsEvents = [
];
const eventsStackedSelectIndex = ref<number>(0);
const { projectId } = useProject();
const { snapshot, safeSnapshotDates } = useSnapshot();
const headers = computed(() => {
return {
'x-from': safeSnapshotDates.value.from,
'x-to': safeSnapshotDates.value.to,
'Authorization': authorizationHeaderComputed.value,
'x-schema': 'events',
'x-pid': projectId.value ?? ''
}
});
const eventsData = await useFetch(`/api/data/count`, { method: 'POST', headers, lazy: true });
const eventsData = await useFetch(`/api/data/count`, { headers: useComputedHeaders({ custom: { 'x-schema': 'events' } }), lazy: true });
</script>
@@ -36,9 +22,9 @@ const eventsData = await useFetch(`/api/data/count`, { method: 'POST', headers,
<LyxUiCard class="w-full flex justify-between items-center">
<div class="flex flex-col gap-1">
<div>
Total events: {{ eventsData.data.value?.[0]?.total || '0' }}
Total events: {{ eventsData.data.value?.[0]?.count || '0' }}
</div>
<div v-if="(eventsData.data.value?.[0]?.total || 0) === 0">
<div v-if="(eventsData.data.value?.[0]?.count || 0) === 0">
Waiting for your first event...
</div>
</div>
@@ -71,7 +57,7 @@ const eventsData = await useFetch(`/api/data/count`, { method: 'POST', headers,
</div>
<div class="flex">
<!-- <div class="flex">
<EventsFunnelChart :key="refreshKey" class="w-full"></EventsFunnelChart>
</div>
@@ -81,7 +67,7 @@ const eventsData = await useFetch(`/api/data/count`, { method: 'POST', headers,
<div class="flex">
<EventsMetadataAnalyzer :key="refreshKey"></EventsMetadataAnalyzer>
</div>
</div> -->

View File

@@ -3,8 +3,6 @@
definePageMeta({ layout: 'dashboard' });
const activeProject = useActiveProject();
const items = [
{ label: 'General', slot: 'general' },
{ label: 'Members', slot: 'members' },
@@ -20,16 +18,16 @@ const items = [
<CustomTab :items="items" class="mt-8">
<template #general>
<SettingsGeneral :key="activeProject?._id.toString()"></SettingsGeneral>
<SettingsGeneral :key="refreshKey"></SettingsGeneral>
</template>
<template #members>
<SettingsMembers :key="activeProject?._id.toString()"></SettingsMembers>
<SettingsMembers :key="refreshKey"></SettingsMembers>
</template>
<template #billing>
<SettingsBilling :key="activeProject?._id.toString()"></SettingsBilling>
<SettingsBilling :key="refreshKey"></SettingsBilling>
</template>
<template #account>
<SettingsAccount :key="activeProject?._id.toString()"></SettingsAccount>
<SettingsAccount :key="refreshKey"></SettingsAccount>
</template>
</CustomTab>

View File

@@ -10,7 +10,7 @@ export default defineEventHandler(async event => {
const { pid, from, to, project_id, limit } = data;
const cacheKey = `browsers:${pid}:${from}:${to}`;
const cacheKey = `browsers:${pid}:${limit}:${from}:${to}`;
const cacheExp = 60;
return await Redis.useCacheV2(cacheKey, cacheExp, async () => {

View File

@@ -5,7 +5,7 @@ import { getRequestData } from "~/server/utils/getRequestData";
export default defineEventHandler(async event => {
const data = await getRequestData(event);
const data = await getRequestData(event, { requireSchema: true });
if (!data) return;
const { schemaName, pid, from, to, model, project_id } = data;

View File

@@ -10,7 +10,7 @@ export default defineEventHandler(async event => {
const { pid, from, to, project_id, limit } = data;
const cacheKey = `countries:${pid}:${from}:${to}`;
const cacheKey = `countries:${pid}:${limit}:${from}:${to}`;
const cacheExp = 60;
return await Redis.useCacheV2(cacheKey, cacheExp, async () => {

View File

@@ -10,7 +10,7 @@ export default defineEventHandler(async event => {
const { pid, from, to, project_id, limit } = data;
const cacheKey = `devices:${pid}:${from}:${to}`;
const cacheKey = `devices:${pid}:${limit}:${from}:${to}`;
const cacheExp = 60;
return await Redis.useCacheV2(cacheKey, cacheExp, async () => {

View File

@@ -10,7 +10,7 @@ export default defineEventHandler(async event => {
const { pid, from, to, project_id, limit } = data;
const cacheKey = `events:${pid}:${from}:${to}`;
const cacheKey = `events:${pid}:${limit}:${from}:${to}`;
const cacheExp = 60;
return await Redis.useCacheV2(cacheKey, cacheExp, async () => {

View File

@@ -10,7 +10,7 @@ export default defineEventHandler(async event => {
const { pid, from, to, project_id, limit } = data;
const cacheKey = `oss:${pid}:${from}:${to}`;
const cacheKey = `oss:${pid}:${limit}:${from}:${to}`;
const cacheExp = 60;
return await Redis.useCacheV2(cacheKey, cacheExp, async () => {

View File

@@ -10,7 +10,7 @@ export default defineEventHandler(async event => {
const { pid, from, to, project_id, limit } = data;
const cacheKey = `referrers:${pid}:${from}:${to}`;
const cacheKey = `referrers:${pid}:${limit}:${from}:${to}`;
const cacheExp = 60;
return await Redis.useCacheV2(cacheKey, cacheExp, async () => {

View File

@@ -10,7 +10,7 @@ export default defineEventHandler(async event => {
const { pid, from, to, project_id, limit } = data;
const cacheKey = `websites:${pid}:${from}:${to}`;
const cacheKey = `websites:${pid}:${limit}:${from}:${to}`;
const cacheExp = 60;
return await Redis.useCacheV2(cacheKey, cacheExp, async () => {

View File

@@ -12,7 +12,7 @@ export default defineEventHandler(async event => {
const websiteName = getHeader(event, 'x-website-name');
const cacheKey = `websites_pages:${websiteName}:${pid}:${from}:${to}`;
const cacheKey = `websites_pages:${websiteName}:${pid}:${limit}:${from}:${to}`;
const cacheExp = 60;
return await Redis.useCacheV2(cacheKey, cacheExp, async () => {

View File

@@ -40,7 +40,7 @@ module.exports = {
darker: '#6A6A6A'
},
"lyx-widget": {
DEFAULT: '#151515',
DEFAULT: '#0E0E0E',
light: '#1E1E1E',
lighter: '#262626'
},