diff --git a/src/app/(main)/settings/preferences/PreferenceSettings.tsx b/src/app/(main)/settings/preferences/PreferenceSettings.tsx
index a2890ce9..cc2d1b62 100644
--- a/src/app/(main)/settings/preferences/PreferenceSettings.tsx
+++ b/src/app/(main)/settings/preferences/PreferenceSettings.tsx
@@ -4,6 +4,7 @@ import { DateRangeSetting } from './DateRangeSetting';
import { LanguageSetting } from './LanguageSetting';
import { ThemeSetting } from './ThemeSetting';
import { TimezoneSetting } from './TimezoneSetting';
+import { VersionSetting } from './VersionSetting';
export function PreferenceSettings() {
const { user } = useLoginQuery();
@@ -31,6 +32,10 @@ export function PreferenceSettings() {
+
+
+
+
);
}
diff --git a/src/app/(main)/settings/preferences/VersionSetting.tsx b/src/app/(main)/settings/preferences/VersionSetting.tsx
new file mode 100644
index 00000000..2cfdbeb7
--- /dev/null
+++ b/src/app/(main)/settings/preferences/VersionSetting.tsx
@@ -0,0 +1,31 @@
+'use client';
+
+import { Text } from '@umami/react-zen';
+import { useEffect, useState } from 'react';
+
+export function VersionSetting() {
+ const [version, setVersion] = useState('');
+ const [loading, setLoading] = useState(true);
+
+ useEffect(() => {
+ const fetchVersion = async () => {
+ try {
+ const response = await fetch('/api/version');
+ const data = await response.json();
+ setVersion(data.version || 'unknown');
+ } catch (error) {
+ setVersion('unknown');
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ fetchVersion();
+ }, []);
+
+ if (loading) {
+ return Loading...;
+ }
+
+ return {version};
+}
diff --git a/src/app/api/version/route.ts b/src/app/api/version/route.ts
new file mode 100644
index 00000000..af548f73
--- /dev/null
+++ b/src/app/api/version/route.ts
@@ -0,0 +1,35 @@
+import { readFile } from 'fs/promises';
+import { join } from 'path';
+import { parseRequest } from '@/lib/request';
+import { json } from '@/lib/response';
+
+let cachedVersion: string | null = null;
+
+async function getVersion(): Promise {
+ if (cachedVersion) {
+ return cachedVersion;
+ }
+
+ try {
+ const packageJsonPath = join(process.cwd(), 'package.json');
+ const data = await readFile(packageJsonPath, 'utf-8');
+ const packageJson = JSON.parse(data);
+ cachedVersion = packageJson.version || 'unknown';
+ } catch (error) {
+ cachedVersion = 'unknown';
+ }
+
+ return cachedVersion;
+}
+
+export async function GET(request: Request) {
+ const { error } = await parseRequest(request, null, { skipAuth: true });
+
+ if (error) {
+ return error();
+ }
+
+ const version = await getVersion();
+
+ return json({ version });
+}
diff --git a/src/components/messages.ts b/src/components/messages.ts
index 0438c06e..712495d8 100644
--- a/src/components/messages.ts
+++ b/src/components/messages.ts
@@ -351,6 +351,7 @@ export const labels = defineMessages({
growth: { id: 'label.growth', defaultMessage: 'Growth' },
account: { id: 'label.account', defaultMessage: 'Account' },
application: { id: 'label.application', defaultMessage: 'Application' },
+ version: { id: 'label.version', defaultMessage: 'Version' },
saveSegment: { id: 'label.save-segment', defaultMessage: 'Save as segment' },
saveCohort: { id: 'label.save-cohort', defaultMessage: 'Save as cohort' },
analysis: { id: 'label.analysis', defaultMessage: 'Analysis' },