mirror of
https://github.com/danswer-ai/danswer.git
synced 2025-05-03 08:20:40 +02:00
add posthog + layout rework (#2926)
* add posthog + layout rework * remove posthog node * nit
This commit is contained in:
parent
5e01d6befb
commit
9def9f0dba
@ -61,6 +61,10 @@ ENV NEXT_PUBLIC_DISABLE_LOGOUT=${NEXT_PUBLIC_DISABLE_LOGOUT}
|
||||
ARG NEXT_PUBLIC_CUSTOM_REFRESH_URL
|
||||
ENV NEXT_PUBLIC_CUSTOM_REFRESH_URL=${NEXT_PUBLIC_CUSTOM_REFRESH_URL}
|
||||
|
||||
ARG NEXT_PUBLIC_POSTHOG_KEY
|
||||
ARG NEXT_PUBLIC_POSTHOG_HOST
|
||||
ENV NEXT_PUBLIC_POSTHOG_KEY=${NEXT_PUBLIC_POSTHOG_KEY}
|
||||
ENV NEXT_PUBLIC_POSTHOG_HOST=${NEXT_PUBLIC_POSTHOG_HOST}
|
||||
|
||||
RUN npx next build
|
||||
|
||||
@ -122,6 +126,13 @@ ENV NEXT_PUBLIC_DISABLE_LOGOUT=${NEXT_PUBLIC_DISABLE_LOGOUT}
|
||||
ARG NEXT_PUBLIC_CUSTOM_REFRESH_URL
|
||||
ENV NEXT_PUBLIC_CUSTOM_REFRESH_URL=${NEXT_PUBLIC_CUSTOM_REFRESH_URL}
|
||||
|
||||
|
||||
ARG NEXT_PUBLIC_POSTHOG_KEY
|
||||
ARG NEXT_PUBLIC_POSTHOG_HOST
|
||||
ENV NEXT_PUBLIC_POSTHOG_KEY=${NEXT_PUBLIC_POSTHOG_KEY}
|
||||
ENV NEXT_PUBLIC_POSTHOG_HOST=${NEXT_PUBLIC_POSTHOG_HOST}
|
||||
|
||||
|
||||
# Note: Don't expose ports here, Compose will handle that for us if necessary.
|
||||
# If you want to run this without compose, specify the ports to
|
||||
# expose via cli
|
||||
|
41
web/package-lock.json
generated
41
web/package-lock.json
generated
@ -33,6 +33,7 @@
|
||||
"next": "^14.2.3",
|
||||
"npm": "^10.8.0",
|
||||
"postcss": "^8.4.31",
|
||||
"posthog-js": "^1.176.0",
|
||||
"prismjs": "^1.29.0",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
@ -4493,6 +4494,16 @@
|
||||
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
|
||||
"integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="
|
||||
},
|
||||
"node_modules/core-js": {
|
||||
"version": "3.38.1",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.38.1.tgz",
|
||||
"integrity": "sha512-OP35aUorbU3Zvlx7pjsFdu1rGNnD4pgw/CWoYzRY3t2EzoVT7shKHY1dlAy3f41cGIO7ZDPQimhGFTlEYkG/Hw==",
|
||||
"hasInstallScript": true,
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/core-js"
|
||||
}
|
||||
},
|
||||
"node_modules/cosmiconfig": {
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
|
||||
@ -5639,6 +5650,11 @@
|
||||
"reusify": "^1.0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/fflate": {
|
||||
"version": "0.4.8",
|
||||
"resolved": "https://registry.npmjs.org/fflate/-/fflate-0.4.8.tgz",
|
||||
"integrity": "sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA=="
|
||||
},
|
||||
"node_modules/file-entry-cache": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
|
||||
@ -11136,6 +11152,26 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/posthog-js": {
|
||||
"version": "1.176.0",
|
||||
"resolved": "https://registry.npmjs.org/posthog-js/-/posthog-js-1.176.0.tgz",
|
||||
"integrity": "sha512-T5XKNtRzp7q6CGb7Vc7wAI76rWap9fiuDUPxPsyPBPDkreKya91x9RIsSapAVFafwD1AEin1QMczCmt9Le9BWw==",
|
||||
"dependencies": {
|
||||
"core-js": "^3.38.1",
|
||||
"fflate": "^0.4.8",
|
||||
"preact": "^10.19.3",
|
||||
"web-vitals": "^4.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/preact": {
|
||||
"version": "10.24.3",
|
||||
"resolved": "https://registry.npmjs.org/preact/-/preact-10.24.3.tgz",
|
||||
"integrity": "sha512-Z2dPnBnMUfyQfSQ+GBdsGa16hz35YmLmtTLhM169uW944hYL6xzTYkJjC07j+Wosz733pMWx0fgON3JNw1jJQA==",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/preact"
|
||||
}
|
||||
},
|
||||
"node_modules/prelude-ls": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
|
||||
@ -13192,6 +13228,11 @@
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/web-vitals": {
|
||||
"version": "4.2.4",
|
||||
"resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-4.2.4.tgz",
|
||||
"integrity": "sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw=="
|
||||
},
|
||||
"node_modules/webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
|
@ -34,6 +34,7 @@
|
||||
"next": "^14.2.3",
|
||||
"npm": "^10.8.0",
|
||||
"postcss": "^8.4.31",
|
||||
"posthog-js": "^1.176.0",
|
||||
"prismjs": "^1.29.0",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
|
30
web/src/app/PostHogPageView.tsx
Normal file
30
web/src/app/PostHogPageView.tsx
Normal file
@ -0,0 +1,30 @@
|
||||
"use client";
|
||||
|
||||
import { usePathname, useSearchParams } from "next/navigation";
|
||||
import { useEffect } from "react";
|
||||
import { usePostHog } from "posthog-js/react";
|
||||
|
||||
export default function PostHogPageView(): null {
|
||||
const pathname = usePathname();
|
||||
const searchParams = useSearchParams();
|
||||
const posthog = usePostHog();
|
||||
|
||||
useEffect(() => {
|
||||
if (!posthog) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Track pageviews
|
||||
if (pathname) {
|
||||
let url = window.origin + pathname;
|
||||
if (searchParams.toString()) {
|
||||
url = url + `?${searchParams.toString()}`;
|
||||
}
|
||||
posthog.capture("$pageview", {
|
||||
$current_url: url,
|
||||
});
|
||||
}
|
||||
}, [pathname, searchParams, posthog]);
|
||||
|
||||
return null;
|
||||
}
|
@ -8,19 +8,21 @@ import {
|
||||
CUSTOM_ANALYTICS_ENABLED,
|
||||
SERVER_SIDE_ONLY__PAID_ENTERPRISE_FEATURES_ENABLED,
|
||||
} from "@/lib/constants";
|
||||
import { SettingsProvider } from "@/components/settings/SettingsProvider";
|
||||
import { Metadata } from "next";
|
||||
import { buildClientUrl } from "@/lib/utilsSS";
|
||||
import { Inter } from "next/font/google";
|
||||
import Head from "next/head";
|
||||
import { EnterpriseSettings, GatingType } from "./admin/settings/interfaces";
|
||||
import { Card } from "@tremor/react";
|
||||
import { HeaderTitle } from "@/components/header/HeaderTitle";
|
||||
import { Logo } from "@/components/Logo";
|
||||
import { UserProvider } from "@/components/user/UserProvider";
|
||||
import { ProviderContextProvider } from "@/components/chat_search/ProviderContext";
|
||||
import { fetchAssistantData } from "@/lib/chat/fetchAssistantdata";
|
||||
import { AppProvider } from "@/components/context/AppProvider";
|
||||
import { PHProvider } from "./providers";
|
||||
import { default as dynamicImport } from "next/dynamic";
|
||||
|
||||
const PostHogPageView = dynamicImport(() => import("./PostHogPageView"), {
|
||||
ssr: false,
|
||||
});
|
||||
|
||||
const inter = Inter({
|
||||
subsets: ["latin"],
|
||||
@ -57,139 +59,124 @@ export default async function RootLayout({
|
||||
}) {
|
||||
const combinedSettings = await fetchSettingsSS();
|
||||
|
||||
const data = await fetchAssistantData();
|
||||
|
||||
const { assistants, hasAnyConnectors, hasImageCompatibleModel } = data;
|
||||
|
||||
const productGating =
|
||||
combinedSettings?.settings.product_gating ?? GatingType.NONE;
|
||||
|
||||
if (!combinedSettings) {
|
||||
return (
|
||||
<html lang="en" className={`${inter.variable} font-sans`}>
|
||||
<Head>
|
||||
<title>Settings Unavailable | Danswer</title>
|
||||
</Head>
|
||||
<body className="bg-background text-default">
|
||||
<div className="flex flex-col items-center justify-center min-h-screen">
|
||||
<div className="mb-2 flex items-center max-w-[175px]">
|
||||
<HeaderTitle>Danswer</HeaderTitle>
|
||||
<Logo height={40} width={40} />
|
||||
</div>
|
||||
|
||||
<Card className="p-8 max-w-md">
|
||||
<h1 className="text-2xl font-bold mb-4 text-error">Error</h1>
|
||||
<p className="text-text-500">
|
||||
Your Danswer instance was not configured properly and your
|
||||
settings could not be loaded. This could be due to an admin
|
||||
configuration issue or an incomplete setup.
|
||||
</p>
|
||||
<p className="mt-4">
|
||||
If you're an admin, please check{" "}
|
||||
<a
|
||||
className="text-link"
|
||||
href="https://docs.danswer.dev/introduction?utm_source=app&utm_medium=error_page&utm_campaign=config_error"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
our docs
|
||||
</a>{" "}
|
||||
to see how to configure Danswer properly. If you're a user,
|
||||
please contact your admin to fix this error.
|
||||
</p>
|
||||
<p className="mt-4">
|
||||
For additional support and guidance, you can reach out to our
|
||||
community on{" "}
|
||||
<a
|
||||
className="text-link"
|
||||
href="https://danswer.ai?utm_source=app&utm_medium=error_page&utm_campaign=config_error"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Slack
|
||||
</a>
|
||||
.
|
||||
</p>
|
||||
</Card>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
if (productGating === GatingType.FULL) {
|
||||
return (
|
||||
<html lang="en" className={`${inter.variable} font-sans`}>
|
||||
<Head>
|
||||
<title>Access Restricted | Danswer</title>
|
||||
</Head>
|
||||
<body className="bg-background text-default">
|
||||
<div className="flex flex-col items-center justify-center min-h-screen">
|
||||
<div className="mb-2 flex items-center max-w-[175px]">
|
||||
<HeaderTitle>Danswer</HeaderTitle>
|
||||
<Logo height={40} width={40} />
|
||||
</div>
|
||||
<Card className="p-8 max-w-md">
|
||||
<h1 className="text-2xl font-bold mb-4 text-error">
|
||||
Access Restricted
|
||||
</h1>
|
||||
<p className="text-text-500 mb-4">
|
||||
We regret to inform you that your access to Danswer has been
|
||||
temporarily suspended due to a lapse in your subscription.
|
||||
</p>
|
||||
<p className="text-text-500 mb-4">
|
||||
To reinstate your access and continue benefiting from
|
||||
Danswer's powerful features, please update your payment
|
||||
information.
|
||||
</p>
|
||||
<p className="text-text-500">
|
||||
If you're an admin, you can resolve this by visiting the
|
||||
billing section. For other users, please reach out to your
|
||||
administrator to address this matter.
|
||||
</p>
|
||||
</Card>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<html lang="en">
|
||||
<Head>
|
||||
const getPageContent = (content: React.ReactNode) => (
|
||||
<html lang="en" className={`${inter.variable} font-sans`}>
|
||||
<head>
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0, interactive-widget=resizes-content"
|
||||
/>
|
||||
</Head>
|
||||
|
||||
{CUSTOM_ANALYTICS_ENABLED && combinedSettings.customAnalyticsScript && (
|
||||
<head>
|
||||
<script
|
||||
type="text/javascript"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: combinedSettings.customAnalyticsScript,
|
||||
}}
|
||||
/>
|
||||
</head>
|
||||
)}
|
||||
|
||||
{CUSTOM_ANALYTICS_ENABLED &&
|
||||
combinedSettings?.customAnalyticsScript && (
|
||||
<script
|
||||
type="text/javascript"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: combinedSettings.customAnalyticsScript,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</head>
|
||||
<body className={`relative ${inter.variable} font-sans`}>
|
||||
<div
|
||||
className={`text-default min-h-screen bg-background ${
|
||||
// TODO: remove this once proper dark mode exists
|
||||
process.env.THEME_IS_DARK?.toLowerCase() === "true" ? "dark" : ""
|
||||
}`}
|
||||
>
|
||||
<AppProvider
|
||||
settings={combinedSettings}
|
||||
assistants={assistants}
|
||||
hasAnyConnectors={hasAnyConnectors}
|
||||
hasImageCompatibleModel={hasImageCompatibleModel}
|
||||
>
|
||||
{children}
|
||||
</AppProvider>
|
||||
<PHProvider>{content}</PHProvider>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
|
||||
if (!combinedSettings) {
|
||||
return getPageContent(
|
||||
<div className="flex flex-col items-center justify-center min-h-screen">
|
||||
<div className="mb-2 flex items-center max-w-[175px]">
|
||||
<HeaderTitle>Danswer</HeaderTitle>
|
||||
<Logo height={40} width={40} />
|
||||
</div>
|
||||
|
||||
<Card className="p-8 max-w-md">
|
||||
<h1 className="text-2xl font-bold mb-4 text-error">Error</h1>
|
||||
<p className="text-text-500">
|
||||
Your Danswer instance was not configured properly and your settings
|
||||
could not be loaded. This could be due to an admin configuration
|
||||
issue or an incomplete setup.
|
||||
</p>
|
||||
<p className="mt-4">
|
||||
If you're an admin, please check{" "}
|
||||
<a
|
||||
className="text-link"
|
||||
href="https://docs.danswer.dev/introduction?utm_source=app&utm_medium=error_page&utm_campaign=config_error"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
our docs
|
||||
</a>{" "}
|
||||
to see how to configure Danswer properly. If you're a user,
|
||||
please contact your admin to fix this error.
|
||||
</p>
|
||||
<p className="mt-4">
|
||||
For additional support and guidance, you can reach out to our
|
||||
community on{" "}
|
||||
<a
|
||||
className="text-link"
|
||||
href="https://danswer.ai?utm_source=app&utm_medium=error_page&utm_campaign=config_error"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Slack
|
||||
</a>
|
||||
.
|
||||
</p>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
if (productGating === GatingType.FULL) {
|
||||
return getPageContent(
|
||||
<div className="flex flex-col items-center justify-center min-h-screen">
|
||||
<div className="mb-2 flex items-center max-w-[175px]">
|
||||
<HeaderTitle>Danswer</HeaderTitle>
|
||||
<Logo height={40} width={40} />
|
||||
</div>
|
||||
<Card className="p-8 max-w-md">
|
||||
<h1 className="text-2xl font-bold mb-4 text-error">
|
||||
Access Restricted
|
||||
</h1>
|
||||
<p className="text-text-500 mb-4">
|
||||
We regret to inform you that your access to Danswer has been
|
||||
temporarily suspended due to a lapse in your subscription.
|
||||
</p>
|
||||
<p className="text-text-500 mb-4">
|
||||
To reinstate your access and continue benefiting from Danswer's
|
||||
powerful features, please update your payment information.
|
||||
</p>
|
||||
<p className="text-text-500">
|
||||
If you're an admin, you can resolve this by visiting the
|
||||
billing section. For other users, please reach out to your
|
||||
administrator to address this matter.
|
||||
</p>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const data = await fetchAssistantData();
|
||||
const { assistants, hasAnyConnectors, hasImageCompatibleModel } = data;
|
||||
|
||||
return getPageContent(
|
||||
<AppProvider
|
||||
settings={combinedSettings}
|
||||
assistants={assistants}
|
||||
hasAnyConnectors={hasAnyConnectors}
|
||||
hasImageCompatibleModel={hasImageCompatibleModel}
|
||||
>
|
||||
<PostHogPageView />
|
||||
{children}
|
||||
</AppProvider>
|
||||
);
|
||||
}
|
||||
|
26
web/src/app/providers.tsx
Normal file
26
web/src/app/providers.tsx
Normal file
@ -0,0 +1,26 @@
|
||||
"use client";
|
||||
import posthog from "posthog-js";
|
||||
import { PostHogProvider } from "posthog-js/react";
|
||||
import { useEffect } from "react";
|
||||
|
||||
const isPostHogEnabled = !!(
|
||||
process.env.NEXT_PUBLIC_POSTHOG_KEY && process.env.NEXT_PUBLIC_POSTHOG_HOST
|
||||
);
|
||||
|
||||
export function PHProvider({ children }: { children: React.ReactNode }) {
|
||||
useEffect(() => {
|
||||
if (isPostHogEnabled) {
|
||||
posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {
|
||||
api_host: process.env.NEXT_PUBLIC_POSTHOG_HOST!,
|
||||
person_profiles: "identified_only",
|
||||
capture_pageview: false,
|
||||
});
|
||||
}
|
||||
}, []);
|
||||
|
||||
if (!isPostHogEnabled) {
|
||||
return <>{children}</>;
|
||||
}
|
||||
|
||||
return <PostHogProvider client={posthog}>{children}</PostHogProvider>;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user