From 06768b6cdcfada2a4ce10281163ea07a765bbe2c Mon Sep 17 00:00:00 2001 From: Emily Date: Thu, 5 Dec 2024 17:30:28 +0100 Subject: [PATCH] add selfhosted env + start fix dates --- .../components/dashboard/ActionableChart.vue | 9 +++- dashboard/components/dashboard/TopSection.vue | 3 +- .../composables/snapshots/BaseSnapshots.ts | 14 +++++- dashboard/composables/useSelfhosted.ts | 7 +++ dashboard/composables/useSnapshot.ts | 4 +- dashboard/layouts/dashboard.vue | 6 ++- dashboard/nuxt.config.ts | 6 ++- dashboard/pages/analyst.vue | 15 +++++- dashboard/pages/dashboard/events.vue | 9 +++- dashboard/pages/dashboard/visits.vue | 9 +++- dashboard/pages/index.vue | 5 +- dashboard/server/api/project/generate_csv.ts | 9 +++- .../server/api/timeline/bouncing_rate.ts | 4 +- dashboard/server/api/timeline/events.ts | 3 ++ dashboard/server/api/timeline/visits.ts | 4 +- dashboard/server/services/TimelineService.ts | 50 +------------------ shared/services/DateService.ts | 29 ++++++----- 17 files changed, 100 insertions(+), 86 deletions(-) create mode 100644 dashboard/composables/useSelfhosted.ts diff --git a/dashboard/components/dashboard/ActionableChart.vue b/dashboard/components/dashboard/ActionableChart.vue index 4887d97..b7c8100 100644 --- a/dashboard/components/dashboard/ActionableChart.vue +++ b/dashboard/components/dashboard/ActionableChart.vue @@ -24,9 +24,12 @@ const chartOptions = ref>({ color: '#CCCCCC22', // borderDash: [5, 10] }, + beginAtZero: true, }, x: { ticks: { display: true }, + stacked: false, + offset: false, grid: { display: true, drawBorder: false, @@ -136,7 +139,7 @@ const { snapshotDuration } = useSnapshot(); const selectLabels: { label: string, value: Slice }[] = [ { label: 'Hour', value: 'hour' }, { label: 'Day', value: 'day' }, - { label: 'Week', value: 'week' }, + // { label: 'Week', value: 'week' }, { label: 'Month', value: 'month' }, ]; @@ -220,6 +223,9 @@ function onDataReady() { const maxChartY = Math.max(...visitsData.data.value.data, ...sessionsData.data.value.data); const maxEventSize = Math.max(...eventsData.data.value.data) + + const currentDateTime = Date.now(); + chartData.value.datasets[0].data = visitsData.data.value.data; chartData.value.datasets[1].data = sessionsData.data.value.data; chartData.value.datasets[2].data = eventsData.data.value.data.map(e => { @@ -227,6 +233,7 @@ function onDataReady() { return { x: 0, y: maxChartY + 70, r: isNaN(rValue) ? 0 : rValue, r2: e } }); + chartData.value.datasets[0].backgroundColor = [createGradient('#5655d7')]; chartData.value.datasets[1].backgroundColor = [createGradient('#4abde8')]; chartData.value.datasets[2].backgroundColor = [createGradient('#fbbf24')]; diff --git a/dashboard/components/dashboard/TopSection.vue b/dashboard/components/dashboard/TopSection.vue index adf2530..c41f333 100644 --- a/dashboard/components/dashboard/TopSection.vue +++ b/dashboard/components/dashboard/TopSection.vue @@ -7,6 +7,7 @@ const { onlineUsers, stopWatching, startWatching } = useOnlineUsers(); onMounted(() => startWatching()); onUnmounted(() => stopWatching()); +const selfhosted = useSelfhosted(); const { createAlert } = useAlert(); @@ -62,7 +63,7 @@ function showAnomalyInfoAlert() { --> -
+
AI Anomaly Detector
diff --git a/dashboard/composables/snapshots/BaseSnapshots.ts b/dashboard/composables/snapshots/BaseSnapshots.ts index 534fe8c..c6a9469 100644 --- a/dashboard/composables/snapshots/BaseSnapshots.ts +++ b/dashboard/composables/snapshots/BaseSnapshots.ts @@ -6,7 +6,7 @@ import * as fns from 'date-fns'; export type DefaultSnapshot = TProjectSnapshot & { default: true } export type GenericSnapshot = TProjectSnapshot | DefaultSnapshot; -export function getDefaultSnapshots(project_id: TProjectSnapshot['project_id']) { +export function getDefaultSnapshots(project_id: TProjectSnapshot['project_id'], project_created_at: Date | string) { const today: DefaultSnapshot = { project_id, @@ -70,9 +70,19 @@ export function getDefaultSnapshots(project_id: TProjectSnapshot['project_id']) } + const allTime: DefaultSnapshot = { + project_id, + _id: '___allTime' as any, + name: 'All Time', + from: new Date(project_created_at.toString()), + to: new Date(Date.now()), + color: '#CC11CC', + default: true + } - const snapshotList = [lastDay, today, lastMonth, currentMonth, lastWeek, currentWeek] + + const snapshotList = [lastDay, today, lastMonth, currentMonth, lastWeek, currentWeek, allTime] return snapshotList; diff --git a/dashboard/composables/useSelfhosted.ts b/dashboard/composables/useSelfhosted.ts new file mode 100644 index 0000000..d40f9ed --- /dev/null +++ b/dashboard/composables/useSelfhosted.ts @@ -0,0 +1,7 @@ + + +const app = useRuntimeConfig(); + +export function useSelfhosted() { + return app.public.SELFHOSTED === 'TRUE'; +} \ No newline at end of file diff --git a/dashboard/composables/useSnapshot.ts b/dashboard/composables/useSnapshot.ts index e0b4d35..b37bb76 100644 --- a/dashboard/composables/useSnapshot.ts +++ b/dashboard/composables/useSnapshot.ts @@ -15,11 +15,11 @@ const remoteSnapshots = useFetch('/api/project/snapshots', { watch(project, async () => { await remoteSnapshots.refresh(); - snapshot.value = isLiveDemo.value ? snapshots.value[0] : snapshots.value[1]; + snapshot.value = isLiveDemo.value ? snapshots.value[2] : snapshots.value[2]; }); const snapshots = computed(() => { - const defaultSnapshots: GenericSnapshot[] = project.value?._id ? getDefaultSnapshots(project.value._id as any) : []; + const defaultSnapshots: GenericSnapshot[] = project.value?._id ? getDefaultSnapshots(project.value._id as any, project.value.created_at) : []; return [...defaultSnapshots, ...(remoteSnapshots.data.value || [])]; }) diff --git a/dashboard/layouts/dashboard.vue b/dashboard/layouts/dashboard.vue index 45f65bf..51c85c9 100644 --- a/dashboard/layouts/dashboard.vue +++ b/dashboard/layouts/dashboard.vue @@ -9,6 +9,8 @@ const { project } = useProject(); const pricingDrawer = usePricingDrawer(); +const selfhosted = useSelfhosted(); + const sections: Section[] = [ { title: '', @@ -16,10 +18,12 @@ const sections: Section[] = [ { label: 'Web Analytics', to: '/', icon: 'fal fa-table-layout' }, { label: 'Custom Events', to: '/events', icon: 'fal fa-square-bolt' }, { label: 'Ask AI', to: '/analyst', icon: 'fal fa-sparkles' }, - { label: 'Security', to: '/security', icon: 'fal fa-shield' }, + { label: 'Security', to: '/security', icon: 'fal fa-shield', disabled: selfhosted }, + // { label: 'Insights (soon)', to: '#', icon: 'fal fa-lightbulb', disabled: true }, // { label: 'Links (soon)', to: '#', icon: 'fal fa-globe-pointer', disabled: true }, // { label: 'Integrations (soon)', to: '/integrations', icon: 'fal fa-cube', disabled: true }, + { label: 'Settings', to: '/settings', icon: 'fal fa-gear' }, { grow: true, diff --git a/dashboard/nuxt.config.ts b/dashboard/nuxt.config.ts index 489fe7d..a912c52 100644 --- a/dashboard/nuxt.config.ts +++ b/dashboard/nuxt.config.ts @@ -55,10 +55,12 @@ export default defineNuxtConfig({ STRIPE_SECRET_TEST: process.env.STRIPE_SECRET_TEST, STRIPE_WH_SECRET_TEST: process.env.STRIPE_WH_SECRET_TEST, NOAUTH_USER_EMAIL: process.env.NOAUTH_USER_EMAIL, - NOAUTH_USER_NAME: process.env.NOAUTH_USER_NAME, + NOAUTH_USER_NAME: process.env.NOAUTH_USER_NAME || 'FALSE', + SELFHOSTED: process.env.SELFHOSTED, public: { AUTH_MODE: process.env.AUTH_MODE, - GITHUB_CLIENT_ID: process.env.GITHUB_AUTH_CLIENT_ID || 'NONE' + GITHUB_CLIENT_ID: process.env.GITHUB_AUTH_CLIENT_ID || 'NONE', + SELFHOSTED: process.env.SELFHOSTED || 'FALSE', } }, diff --git a/dashboard/pages/analyst.vue b/dashboard/pages/analyst.vue index a7a4ff0..4ec1a08 100644 --- a/dashboard/pages/analyst.vue +++ b/dashboard/pages/analyst.vue @@ -60,12 +60,21 @@ async function sendMessage() { } catch (ex: any) { + if (ex.message.includes('CHAT_LIMIT_REACHED')) { currentChatMessages.value.push({ role: 'assistant', content: 'You have reached your current tier chat limit.\n Upgrade to an higher tier. Upgrade now. ', }); } + + if (ex.message.includes('Unauthorized')) { + currentChatMessages.value.push({ + role: 'assistant', + content: 'To use AI you need to provide AI_ORG, AI_PROJECT and AI_KEY in docker compose', + }); + } + } @@ -89,7 +98,7 @@ async function openChat(chat_id?: string) { } currentChatId.value = chat_id; const messages = await $fetch(`/api/ai/${chat_id}/get_messages`, { - headers: useComputedHeaders({useSnapshotDates:false}).value + headers: useComputedHeaders({ useSnapshotDates: false }).value }); if (!messages) return; @@ -132,7 +141,7 @@ async function deleteChat(chat_id: string) { currentChatMessages.value = []; } await $fetch(`/api/ai/${chat_id}/delete`, { - headers: useComputedHeaders({useSnapshotDates:false}).value + headers: useComputedHeaders({ useSnapshotDates: false }).value }); await reloadChatsList(); } @@ -148,6 +157,7 @@ const { visible: pricingDrawerVisible } = usePricingDrawer()
+
@@ -164,6 +174,7 @@ const { visible: pricingDrawerVisible } = usePricingDrawer()
+
diff --git a/dashboard/pages/dashboard/events.vue b/dashboard/pages/dashboard/events.vue index d74d73e..f956cef 100644 --- a/dashboard/pages/dashboard/events.vue +++ b/dashboard/pages/dashboard/events.vue @@ -7,6 +7,11 @@ definePageMeta({ layout: 'dashboard' }); const { project } = useProject(); const isPremium = computed(() => (project.value?.premium_type || 0) > 0); +const selfhosted = useSelfhosted(); +const canDownload = computed(() => { + if (selfhosted) return true; + return isPremium.value; +}); const metricsInfo = ref(0); @@ -105,12 +110,12 @@ function goToUpgrade() { }" v-model="selectedTimeFrom" :options="options">
-
Download CSV
-
Upgrade plan for CSV diff --git a/dashboard/pages/dashboard/visits.vue b/dashboard/pages/dashboard/visits.vue index f8a1b99..f8785fc 100644 --- a/dashboard/pages/dashboard/visits.vue +++ b/dashboard/pages/dashboard/visits.vue @@ -7,6 +7,11 @@ definePageMeta({ layout: 'dashboard' }); const { project } = useProject(); const isPremium = computed(() => (project.value?.premium_type || 0) > 0); +const selfhosted = useSelfhosted(); +const canDownload = computed(() => { + if (selfhosted) return true; + return isPremium.value; +}); const metricsInfo = ref(0); @@ -110,12 +115,12 @@ function goToUpgrade() { }" v-model="selectedTimeFrom" :options="options">
-
Download CSV
-
Upgrade plan for CSV diff --git a/dashboard/pages/index.vue b/dashboard/pages/index.vue index b525a88..b877ff5 100644 --- a/dashboard/pages/index.vue +++ b/dashboard/pages/index.vue @@ -31,6 +31,7 @@ const firstInteraction = useFetch('/api/project/first_interaction', { const showDashboard = computed(() => project.value && firstInteraction.data.value); +const selfhosted = useSelfhosted();