Merge pull request #6514 from menloresearch/feat/web-gtag
feat: Add GA Measurement and change keyboard bindings on web
This commit is contained in:
parent
645548e931
commit
359dd8f41e
@ -14,6 +14,7 @@ jobs:
|
|||||||
pull-requests: write
|
pull-requests: write
|
||||||
env:
|
env:
|
||||||
JAN_API_BASE: "https://api.jan.ai/jan/v1"
|
JAN_API_BASE: "https://api.jan.ai/jan/v1"
|
||||||
|
GA_MEASUREMENT_ID: "G-YK53MX8M8M"
|
||||||
CLOUDFLARE_PROJECT_NAME: "jan-server-web"
|
CLOUDFLARE_PROJECT_NAME: "jan-server-web"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|||||||
17
web-app/src/lib/analytics.ts
Normal file
17
web-app/src/lib/analytics.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
/**
|
||||||
|
* Google Analytics utility functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Track custom events with Google Analytics
|
||||||
|
*/
|
||||||
|
export function trackEvent(
|
||||||
|
eventName: string,
|
||||||
|
parameters?: Record<string, unknown>
|
||||||
|
) {
|
||||||
|
if (!window.gtag) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
window.gtag('event', eventName, parameters)
|
||||||
|
}
|
||||||
@ -55,4 +55,10 @@ export const PlatformFeatures: Record<PlatformFeature, boolean> = {
|
|||||||
|
|
||||||
// Authentication (Google OAuth) - enabled for web only
|
// Authentication (Google OAuth) - enabled for web only
|
||||||
[PlatformFeature.AUTHENTICATION]: !isPlatformTauri(),
|
[PlatformFeature.AUTHENTICATION]: !isPlatformTauri(),
|
||||||
|
|
||||||
|
// Google Analytics - enabled for web only
|
||||||
|
[PlatformFeature.GOOGLE_ANALYTICS]: !isPlatformTauri(),
|
||||||
|
|
||||||
|
// Alternate shortcut bindings - enabled for web only (to avoid browser conflicts)
|
||||||
|
[PlatformFeature.ALTERNATE_SHORTCUT_BINDINGS]: !isPlatformTauri(),
|
||||||
}
|
}
|
||||||
@ -57,4 +57,10 @@ export enum PlatformFeature {
|
|||||||
|
|
||||||
// Authentication (Google OAuth, user profiles)
|
// Authentication (Google OAuth, user profiles)
|
||||||
AUTHENTICATION = 'authentication',
|
AUTHENTICATION = 'authentication',
|
||||||
|
|
||||||
|
// Google Analytics tracking (web-only)
|
||||||
|
GOOGLE_ANALYTICS = 'googleAnalytics',
|
||||||
|
|
||||||
|
// Alternate keyboard shortcut bindings (web-only, to avoid browser conflicts)
|
||||||
|
ALTERNATE_SHORTCUT_BINDINGS = 'alternateShortcutBindings',
|
||||||
}
|
}
|
||||||
|
|||||||
41
web-app/src/lib/shortcuts/const.ts
Normal file
41
web-app/src/lib/shortcuts/const.ts
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/**
|
||||||
|
* Shortcuts Configuration
|
||||||
|
* Centralized shortcut definitions based on platform capabilities
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { PlatformFeatures } from '../platform/const'
|
||||||
|
import { PlatformFeature } from '../platform/types'
|
||||||
|
import { ShortcutAction, type ShortcutMap } from './types'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Platform-specific shortcut mappings
|
||||||
|
* Uses alternate bindings for web to avoid browser conflicts
|
||||||
|
*/
|
||||||
|
export const PlatformShortcuts: ShortcutMap = {
|
||||||
|
// Toggle sidebar - same on both platforms (no browser conflict)
|
||||||
|
[ShortcutAction.TOGGLE_SIDEBAR]: {
|
||||||
|
key: 'b',
|
||||||
|
usePlatformMetaKey: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
// New chat - different per platform to avoid browser "new window" conflict
|
||||||
|
[ShortcutAction.NEW_CHAT]: PlatformFeatures[PlatformFeature.ALTERNATE_SHORTCUT_BINDINGS]
|
||||||
|
? { key: 'Enter', usePlatformMetaKey: true }
|
||||||
|
: { key: 'n', usePlatformMetaKey: true },
|
||||||
|
|
||||||
|
// Go to settings - different per platform to avoid browser "preferences" conflict
|
||||||
|
[ShortcutAction.GO_TO_SETTINGS]: PlatformFeatures[PlatformFeature.ALTERNATE_SHORTCUT_BINDINGS]
|
||||||
|
? { key: '.', usePlatformMetaKey: true }
|
||||||
|
: { key: ',', usePlatformMetaKey: true },
|
||||||
|
|
||||||
|
// Zoom shortcuts - same on both platforms (standard shortcuts)
|
||||||
|
[ShortcutAction.ZOOM_IN]: {
|
||||||
|
key: '+',
|
||||||
|
usePlatformMetaKey: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
[ShortcutAction.ZOOM_OUT]: {
|
||||||
|
key: '-',
|
||||||
|
usePlatformMetaKey: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
9
web-app/src/lib/shortcuts/index.ts
Normal file
9
web-app/src/lib/shortcuts/index.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
/**
|
||||||
|
* Shortcuts - Centralized keyboard shortcut system
|
||||||
|
*
|
||||||
|
* Provides platform-aware keyboard shortcuts that avoid browser conflicts
|
||||||
|
* on web while maintaining familiar shortcuts on desktop.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export * from './types'
|
||||||
|
export * from './const'
|
||||||
23
web-app/src/lib/shortcuts/types.ts
Normal file
23
web-app/src/lib/shortcuts/types.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
/**
|
||||||
|
* Keyboard Shortcut Types
|
||||||
|
* Defines semantic actions and shortcut specifications
|
||||||
|
*/
|
||||||
|
|
||||||
|
export enum ShortcutAction {
|
||||||
|
NEW_CHAT = 'newChat',
|
||||||
|
TOGGLE_SIDEBAR = 'toggleSidebar',
|
||||||
|
GO_TO_SETTINGS = 'goSettings',
|
||||||
|
ZOOM_IN = 'zoomIn',
|
||||||
|
ZOOM_OUT = 'zoomOut',
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ShortcutSpec {
|
||||||
|
key: string
|
||||||
|
usePlatformMetaKey?: boolean
|
||||||
|
altKey?: boolean
|
||||||
|
shiftKey?: boolean
|
||||||
|
ctrlKey?: boolean
|
||||||
|
metaKey?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ShortcutMap = Record<ShortcutAction, ShortcutSpec>
|
||||||
62
web-app/src/providers/GoogleAnalyticsProvider.tsx
Normal file
62
web-app/src/providers/GoogleAnalyticsProvider.tsx
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
import { useEffect } from 'react'
|
||||||
|
import { useLocation } from '@tanstack/react-router'
|
||||||
|
|
||||||
|
|
||||||
|
export function GoogleAnalyticsProvider() {
|
||||||
|
const location = useLocation()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Check if GA ID is properly configured
|
||||||
|
if (!GA_MEASUREMENT_ID || GA_MEASUREMENT_ID === 'G-XXXXXXXXXX') {
|
||||||
|
console.warn(
|
||||||
|
'Google Analytics not initialized: Invalid GA_MEASUREMENT_ID'
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load Google Analytics script
|
||||||
|
const script = document.createElement('script')
|
||||||
|
script.async = true
|
||||||
|
script.src = `https://www.googletagmanager.com/gtag/js?id=${GA_MEASUREMENT_ID}`
|
||||||
|
|
||||||
|
// Handle loading errors
|
||||||
|
script.onerror = () => {
|
||||||
|
console.warn('Failed to load Google Analytics script')
|
||||||
|
}
|
||||||
|
|
||||||
|
document.head.appendChild(script)
|
||||||
|
|
||||||
|
// Initialize gtag
|
||||||
|
window.dataLayer = window.dataLayer || []
|
||||||
|
window.gtag = function (...args: unknown[]) {
|
||||||
|
window.dataLayer?.push(args)
|
||||||
|
}
|
||||||
|
window.gtag('js', new Date())
|
||||||
|
window.gtag('config', GA_MEASUREMENT_ID, {
|
||||||
|
send_page_view: false, // We'll manually track page views
|
||||||
|
})
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
// Cleanup: Remove script on unmount
|
||||||
|
if (script.parentNode) {
|
||||||
|
script.parentNode.removeChild(script)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
// Track page views on route change
|
||||||
|
useEffect(() => {
|
||||||
|
if (!window.gtag) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
window.gtag('event', 'page_view', {
|
||||||
|
page_path: location.pathname + location.search,
|
||||||
|
page_location: window.location.href,
|
||||||
|
page_title: document.title,
|
||||||
|
})
|
||||||
|
}, [location])
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
@ -2,34 +2,37 @@ import { useKeyboardShortcut } from '@/hooks/useHotkeys'
|
|||||||
import { useLeftPanel } from '@/hooks/useLeftPanel'
|
import { useLeftPanel } from '@/hooks/useLeftPanel'
|
||||||
import { useRouter } from '@tanstack/react-router'
|
import { useRouter } from '@tanstack/react-router'
|
||||||
import { route } from '@/constants/routes'
|
import { route } from '@/constants/routes'
|
||||||
|
import { PlatformShortcuts, ShortcutAction } from '@/lib/shortcuts'
|
||||||
|
|
||||||
export function KeyboardShortcutsProvider() {
|
export function KeyboardShortcutsProvider() {
|
||||||
const { open, setLeftPanel } = useLeftPanel()
|
const { open, setLeftPanel } = useLeftPanel()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
// Toggle Sidebar (⌘/Ctrl B)
|
// Get shortcut specs from centralized configuration
|
||||||
|
const sidebarShortcut = PlatformShortcuts[ShortcutAction.TOGGLE_SIDEBAR]
|
||||||
|
const newChatShortcut = PlatformShortcuts[ShortcutAction.NEW_CHAT]
|
||||||
|
const settingsShortcut = PlatformShortcuts[ShortcutAction.GO_TO_SETTINGS]
|
||||||
|
|
||||||
|
// Toggle Sidebar
|
||||||
useKeyboardShortcut({
|
useKeyboardShortcut({
|
||||||
key: 'b',
|
...sidebarShortcut,
|
||||||
usePlatformMetaKey: true,
|
|
||||||
callback: () => {
|
callback: () => {
|
||||||
setLeftPanel(!open)
|
setLeftPanel(!open)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
// New Chat (⌘/Ctrl N)
|
// New Chat
|
||||||
useKeyboardShortcut({
|
useKeyboardShortcut({
|
||||||
key: 'n',
|
...newChatShortcut,
|
||||||
usePlatformMetaKey: true,
|
|
||||||
excludeRoutes: [route.home],
|
excludeRoutes: [route.home],
|
||||||
callback: () => {
|
callback: () => {
|
||||||
router.navigate({ to: route.home })
|
router.navigate({ to: route.home })
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
// Go to Settings (⌘/Ctrl ,)
|
// Go to Settings
|
||||||
useKeyboardShortcut({
|
useKeyboardShortcut({
|
||||||
key: ',',
|
...settingsShortcut,
|
||||||
usePlatformMetaKey: true,
|
|
||||||
callback: () => {
|
callback: () => {
|
||||||
router.navigate({ to: route.settings.general })
|
router.navigate({ to: route.settings.general })
|
||||||
},
|
},
|
||||||
|
|||||||
@ -15,6 +15,7 @@ import { ToasterProvider } from '@/providers/ToasterProvider'
|
|||||||
import { useAnalytic } from '@/hooks/useAnalytic'
|
import { useAnalytic } from '@/hooks/useAnalytic'
|
||||||
import { PromptAnalytic } from '@/containers/analytics/PromptAnalytic'
|
import { PromptAnalytic } from '@/containers/analytics/PromptAnalytic'
|
||||||
import { AnalyticProvider } from '@/providers/AnalyticProvider'
|
import { AnalyticProvider } from '@/providers/AnalyticProvider'
|
||||||
|
import { GoogleAnalyticsProvider } from '@/providers/GoogleAnalyticsProvider'
|
||||||
import { useLeftPanel } from '@/hooks/useLeftPanel'
|
import { useLeftPanel } from '@/hooks/useLeftPanel'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
import ToolApproval from '@/containers/dialogs/ToolApproval'
|
import ToolApproval from '@/containers/dialogs/ToolApproval'
|
||||||
@ -110,6 +111,7 @@ const AppLayout = () => {
|
|||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<AnalyticProvider />
|
<AnalyticProvider />
|
||||||
|
{PlatformFeatures[PlatformFeature.GOOGLE_ANALYTICS] && <GoogleAnalyticsProvider />}
|
||||||
<KeyboardShortcutsProvider />
|
<KeyboardShortcutsProvider />
|
||||||
<main className="relative h-svh text-sm antialiased select-none bg-app">
|
<main className="relative h-svh text-sm antialiased select-none bg-app">
|
||||||
{/* Fake absolute panel top to enable window drag */}
|
{/* Fake absolute panel top to enable window drag */}
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import SettingsMenu from '@/containers/SettingsMenu'
|
|||||||
import HeaderPage from '@/containers/HeaderPage'
|
import HeaderPage from '@/containers/HeaderPage'
|
||||||
import { Card, CardItem } from '@/containers/Card'
|
import { Card, CardItem } from '@/containers/Card'
|
||||||
import { useTranslation } from '@/i18n/react-i18next-compat'
|
import { useTranslation } from '@/i18n/react-i18next-compat'
|
||||||
|
import { ShortcutAction, PlatformShortcuts, type ShortcutSpec } from '@/lib/shortcuts'
|
||||||
import { PlatformMetaKey } from '@/containers/PlatformMetaKey'
|
import { PlatformMetaKey } from '@/containers/PlatformMetaKey'
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
@ -11,6 +12,75 @@ export const Route = createFileRoute(route.settings.shortcuts as any)({
|
|||||||
component: Shortcuts,
|
component: Shortcuts,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
interface ShortcutLabelProps {
|
||||||
|
action: ShortcutAction
|
||||||
|
className?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders a keyboard shortcut label consistently across platforms
|
||||||
|
*/
|
||||||
|
function ShortcutLabel({ action, className = '' }: ShortcutLabelProps) {
|
||||||
|
const spec = PlatformShortcuts[action]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={`flex items-center justify-center px-3 py-1 bg-main-view-fg/5 rounded-md ${className}`}>
|
||||||
|
<span className="font-medium">
|
||||||
|
<ShortcutKeys spec={spec} />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders the key combination for a shortcut spec
|
||||||
|
*/
|
||||||
|
function ShortcutKeys({ spec }: { spec: ShortcutSpec }) {
|
||||||
|
const parts: React.ReactNode[] = []
|
||||||
|
|
||||||
|
// Helper function to format key names consistently
|
||||||
|
const formatKey = (key: string) => {
|
||||||
|
const lowerKey = key.toLowerCase()
|
||||||
|
if (lowerKey === 'enter') return 'Enter'
|
||||||
|
if (lowerKey === 'shift') return 'Shift'
|
||||||
|
if (lowerKey === 'ctrl') return 'Ctrl'
|
||||||
|
if (lowerKey === 'alt') return 'Alt'
|
||||||
|
return key.toUpperCase()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add modifier keys
|
||||||
|
if (spec.usePlatformMetaKey) {
|
||||||
|
parts.push(<PlatformMetaKey key="meta" />)
|
||||||
|
}
|
||||||
|
if (spec.ctrlKey) {
|
||||||
|
parts.push('Ctrl')
|
||||||
|
}
|
||||||
|
if (spec.metaKey) {
|
||||||
|
parts.push('⌘')
|
||||||
|
}
|
||||||
|
if (spec.altKey) {
|
||||||
|
parts.push('Alt')
|
||||||
|
}
|
||||||
|
if (spec.shiftKey) {
|
||||||
|
parts.push('Shift')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the main key with proper formatting
|
||||||
|
parts.push(formatKey(spec.key))
|
||||||
|
|
||||||
|
// Join with spaces
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{parts.map((part, index) => (
|
||||||
|
<span key={index}>
|
||||||
|
{part}
|
||||||
|
{index < parts.length - 1 && ' '}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
function Shortcuts() {
|
function Shortcuts() {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
|
||||||
@ -28,46 +98,22 @@ function Shortcuts() {
|
|||||||
<CardItem
|
<CardItem
|
||||||
title={t('settings:shortcuts.newChat')}
|
title={t('settings:shortcuts.newChat')}
|
||||||
description={t('settings:shortcuts.newChatDesc')}
|
description={t('settings:shortcuts.newChatDesc')}
|
||||||
actions={
|
actions={<ShortcutLabel action={ShortcutAction.NEW_CHAT} />}
|
||||||
<div className="flex items-center justify-center px-3 py-1 bg-main-view-fg/5 rounded-md">
|
|
||||||
<span className="font-medium">
|
|
||||||
<PlatformMetaKey /> N
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
<CardItem
|
<CardItem
|
||||||
title={t('settings:shortcuts.toggleSidebar')}
|
title={t('settings:shortcuts.toggleSidebar')}
|
||||||
description={t('settings:shortcuts.toggleSidebarDesc')}
|
description={t('settings:shortcuts.toggleSidebarDesc')}
|
||||||
actions={
|
actions={<ShortcutLabel action={ShortcutAction.TOGGLE_SIDEBAR} />}
|
||||||
<div className="flex items-center justify-center px-3 py-1 bg-main-view-fg/5 rounded-md">
|
|
||||||
<span className="font-medium">
|
|
||||||
<PlatformMetaKey /> B
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
<CardItem
|
<CardItem
|
||||||
title={t('settings:shortcuts.zoomIn')}
|
title={t('settings:shortcuts.zoomIn')}
|
||||||
description={t('settings:shortcuts.zoomInDesc')}
|
description={t('settings:shortcuts.zoomInDesc')}
|
||||||
actions={
|
actions={<ShortcutLabel action={ShortcutAction.ZOOM_IN} />}
|
||||||
<div className="flex items-center justify-center px-3 py-1 bg-main-view-fg/5 rounded-md">
|
|
||||||
<span className="font-medium">
|
|
||||||
<PlatformMetaKey /> +
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
<CardItem
|
<CardItem
|
||||||
title={t('settings:shortcuts.zoomOut')}
|
title={t('settings:shortcuts.zoomOut')}
|
||||||
description={t('settings:shortcuts.zoomOutDesc')}
|
description={t('settings:shortcuts.zoomOutDesc')}
|
||||||
actions={
|
actions={<ShortcutLabel action={ShortcutAction.ZOOM_OUT} />}
|
||||||
<div className="flex items-center justify-center px-3 py-1 bg-main-view-fg/5 rounded-md">
|
|
||||||
<span className="font-medium">
|
|
||||||
<PlatformMetaKey /> -
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
@ -102,13 +148,7 @@ function Shortcuts() {
|
|||||||
<CardItem
|
<CardItem
|
||||||
title={t('settings:shortcuts.goToSettings')}
|
title={t('settings:shortcuts.goToSettings')}
|
||||||
description={t('settings:shortcuts.goToSettingsDesc')}
|
description={t('settings:shortcuts.goToSettingsDesc')}
|
||||||
actions={
|
actions={<ShortcutLabel action={ShortcutAction.GO_TO_SETTINGS} />}
|
||||||
<div className="flex items-center justify-center px-3 py-1 bg-main-view-fg/5 rounded-md">
|
|
||||||
<span className="font-medium">
|
|
||||||
<PlatformMetaKey /> ,
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
3
web-app/src/types/global.d.ts
vendored
3
web-app/src/types/global.d.ts
vendored
@ -21,7 +21,10 @@ declare global {
|
|||||||
declare const POSTHOG_HOST: string
|
declare const POSTHOG_HOST: string
|
||||||
declare const MODEL_CATALOG_URL: string
|
declare const MODEL_CATALOG_URL: string
|
||||||
declare const AUTO_UPDATER_DISABLED: boolean
|
declare const AUTO_UPDATER_DISABLED: boolean
|
||||||
|
declare const GA_MEASUREMENT_ID: string
|
||||||
interface Window {
|
interface Window {
|
||||||
core: AppCore | undefined
|
core: AppCore | undefined
|
||||||
|
gtag?: (...args: unknown[]) => void
|
||||||
|
dataLayer?: unknown[]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -62,6 +62,7 @@ export default defineConfig(({ mode }) => {
|
|||||||
|
|
||||||
POSTHOG_KEY: JSON.stringify(env.POSTHOG_KEY),
|
POSTHOG_KEY: JSON.stringify(env.POSTHOG_KEY),
|
||||||
POSTHOG_HOST: JSON.stringify(env.POSTHOG_HOST),
|
POSTHOG_HOST: JSON.stringify(env.POSTHOG_HOST),
|
||||||
|
GA_MEASUREMENT_ID: JSON.stringify(env.GA_MEASUREMENT_ID),
|
||||||
MODEL_CATALOG_URL: JSON.stringify(
|
MODEL_CATALOG_URL: JSON.stringify(
|
||||||
'https://raw.githubusercontent.com/menloresearch/model-catalog/main/model_catalog.json'
|
'https://raw.githubusercontent.com/menloresearch/model-catalog/main/model_catalog.json'
|
||||||
),
|
),
|
||||||
|
|||||||
@ -58,6 +58,7 @@ export default defineConfig({
|
|||||||
VERSION: JSON.stringify(process.env.npm_package_version || '1.0.0'),
|
VERSION: JSON.stringify(process.env.npm_package_version || '1.0.0'),
|
||||||
POSTHOG_KEY: JSON.stringify(process.env.POSTHOG_KEY || ''),
|
POSTHOG_KEY: JSON.stringify(process.env.POSTHOG_KEY || ''),
|
||||||
POSTHOG_HOST: JSON.stringify(process.env.POSTHOG_HOST || ''),
|
POSTHOG_HOST: JSON.stringify(process.env.POSTHOG_HOST || ''),
|
||||||
|
GA_MEASUREMENT_ID: JSON.stringify(process.env.GA_MEASUREMENT_ID),
|
||||||
MODEL_CATALOG_URL: JSON.stringify(process.env.MODEL_CATALOG_URL || ''),
|
MODEL_CATALOG_URL: JSON.stringify(process.env.MODEL_CATALOG_URL || ''),
|
||||||
},
|
},
|
||||||
server: {
|
server: {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user