mirror of
https://github.com/Litlyx/litlyx
synced 2025-12-10 07:48:37 +01:00
adding event tracker
This commit is contained in:
68
dashboard/pages/test.vue
Normal file
68
dashboard/pages/test.vue
Normal file
@@ -0,0 +1,68 @@
|
||||
<script lang="ts" setup>
|
||||
|
||||
definePageMeta({ layout: 'dashboard' });
|
||||
|
||||
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();
|
||||
});
|
||||
|
||||
async function getMetadataFields() {
|
||||
metadataFields.value = await $fetch<string[]>(`/api/metrics/${activeProject.value?._id.toString()}/events/metadata_fields?name=${selectedEventName.value}`, signHeaders());
|
||||
selectedMetadataField.value = undefined;
|
||||
}
|
||||
|
||||
async function getMetadataFieldGrouped() {
|
||||
metadataFieldGrouped.value = await $fetch<string[]>(`/api/metrics/${activeProject.value?._id.toString()}/events/metadata_field_group?name=${selectedEventName.value}&field=${selectedMetadataField.value}`, signHeaders());
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<template>
|
||||
<div class="w-full h-full p-8 flex">
|
||||
|
||||
|
||||
|
||||
<CardTitled title="Event tracker" sub="Track users from you marketing links to inner events" class="w-full">
|
||||
|
||||
<div class="p-8">
|
||||
|
||||
<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 @click="getMetadataFieldGrouped()"
|
||||
class="bg-black/70 p-2 px-8 w-fit rounded-lg mt-4 hover:bg-black/40 cursor-pointer">
|
||||
Find
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{{ metadataFieldGrouped }}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</CardTitled>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,31 @@
|
||||
|
||||
import { getUserProjectFromId } from "~/server/LIVE_DEMO_DATA";
|
||||
import { EventModel } from "@schema/metrics/EventSchema";
|
||||
import { EVENT_METADATA_FIELDS_EXPIRE_TIME, Redis } from "~/server/services/CacheService";
|
||||
|
||||
|
||||
export default defineEventHandler(async event => {
|
||||
|
||||
const project_id = getRequestProjectId(event);
|
||||
if (!project_id) return;
|
||||
|
||||
const user = getRequestUser(event);
|
||||
|
||||
const project = await getUserProjectFromId(project_id, user);
|
||||
if (!project) return;
|
||||
|
||||
const { name: eventName, field } = getQuery(event);
|
||||
if (!eventName || !field) return [];
|
||||
|
||||
const aggregation = [
|
||||
{ $match: { project_id: project._id, name: eventName } },
|
||||
{ $group: { _id: `$metadata.${field}`, count: { $sum: 1 } } }
|
||||
]
|
||||
|
||||
const metadataGrouped = await EventModel.aggregate(aggregation);
|
||||
|
||||
console.log(metadataGrouped);
|
||||
return metadataGrouped;
|
||||
|
||||
|
||||
});
|
||||
@@ -0,0 +1,33 @@
|
||||
|
||||
import { getUserProjectFromId } from "~/server/LIVE_DEMO_DATA";
|
||||
import { EventModel } from "@schema/metrics/EventSchema";
|
||||
import { EVENT_METADATA_FIELDS_EXPIRE_TIME, Redis } from "~/server/services/CacheService";
|
||||
|
||||
|
||||
export default defineEventHandler(async event => {
|
||||
|
||||
const project_id = getRequestProjectId(event);
|
||||
if (!project_id) return;
|
||||
|
||||
const user = getRequestUser(event);
|
||||
|
||||
const project = await getUserProjectFromId(project_id, user);
|
||||
if (!project) return;
|
||||
|
||||
const { name: eventName } = getQuery(event);
|
||||
if (!eventName) return [];
|
||||
|
||||
const fields: string[] = await Redis.useCache({ key: `metadata_fields:${project_id}:${eventName}`, exp: EVENT_METADATA_FIELDS_EXPIRE_TIME }, async () => {
|
||||
const eventsWithName = await EventModel.find({ project_id, name: eventName }, { metadata: 1 }, { limit: 10, sort: { created_at: -1 } });
|
||||
const allMetadata = eventsWithName.map(e => e.metadata);
|
||||
const allFields = new Set<string>();
|
||||
for (const metadata of allMetadata) {
|
||||
const keys = Object.keys(metadata || {});
|
||||
keys.forEach(key => allFields.add(key));
|
||||
}
|
||||
return Array.from(allFields.values());
|
||||
});
|
||||
|
||||
return fields;
|
||||
|
||||
});
|
||||
@@ -14,18 +14,9 @@ export default defineEventHandler(async event => {
|
||||
const project = await getUserProjectFromId(project_id, user);
|
||||
if (!project) return;
|
||||
|
||||
const names: string[] = await Redis.useCache({
|
||||
key: `counts:${project_id}:event_names`,
|
||||
exp: EVENT_NAMES_EXPIRE_TIME
|
||||
}, async () => {
|
||||
|
||||
const namesAggregation = await EventModel.aggregate([
|
||||
{ $match: { project_id: project._id } },
|
||||
{ $group: { _id: "$name" } }
|
||||
]);
|
||||
|
||||
const names: string[] = await Redis.useCache({ key: `event_names:${project_id}`, exp: EVENT_NAMES_EXPIRE_TIME }, async () => {
|
||||
const namesAggregation = await EventModel.aggregate([{ $match: { project_id: project._id } }, { $group: { _id: "$name" } }]);
|
||||
return namesAggregation.map(e => e._id);
|
||||
|
||||
});
|
||||
|
||||
return names;
|
||||
|
||||
9
dashboard/server/api/user/max_projects.ts
Normal file
9
dashboard/server/api/user/max_projects.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { UserSettingsModel } from "@schema/UserSettings";
|
||||
import { AuthContext } from "~/server/middleware/01-authorization";
|
||||
|
||||
export default defineEventHandler(async event => {
|
||||
const userData: AuthContext = getRequestUser(event) as any;
|
||||
if (!userData.logged) return;
|
||||
const userSettings = await UserSettingsModel.findOne({ user_id: userData.id }, { max_projects: 1 });
|
||||
return userSettings?.max_projects || 3;
|
||||
});
|
||||
@@ -12,6 +12,8 @@ export const COUNTS_SESSIONS_EXPIRE_TIME = 60 * 3;
|
||||
|
||||
export const EVENT_NAMES_EXPIRE_TIME = 60;
|
||||
|
||||
export const EVENT_METADATA_FIELDS_EXPIRE_TIME = 120;
|
||||
|
||||
|
||||
export class Redis {
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ export type TEvent = {
|
||||
|
||||
const EventSchema = new Schema<TEvent>({
|
||||
project_id: { type: Types.ObjectId, index: 1 },
|
||||
name: { type: String, required: true },
|
||||
name: { type: String, required: true, index: 1 },
|
||||
metadata: Schema.Types.Mixed,
|
||||
session: { type: String },
|
||||
flowHash: { type: String },
|
||||
|
||||
Reference in New Issue
Block a user