mirror of
https://github.com/danswer-ai/danswer.git
synced 2025-09-27 04:18:35 +02:00
Prepare EE to merge with MIT
This commit is contained in:
@@ -1,11 +1,11 @@
|
||||
FROM node:20-alpine AS base
|
||||
|
||||
LABEL com.danswer.maintainer="founders@danswer.ai"
|
||||
LABEL com.danswer.description="This image is the Enterprise Edition (Paid Edition) \
|
||||
frontend/webserver of Danswer. If you do not have a contract or agreement with DanswerAI, you are \
|
||||
not permitted to use this container outside of personal development or testing purposes. Please \
|
||||
reach out to founders@danswer.ai for more information. You can access the MIT version of Danswer \
|
||||
at https://github.com/danswer-ai/danswer"
|
||||
LABEL com.danswer.description="This image is the web/frontend container of Danswer which \
|
||||
contains code for both the Community and Enterprise editions of Danswer. If you do not \
|
||||
have a contract or agreement with DanswerAI, you are not permitted to use the Enterprise \
|
||||
Edition features outside of personal development or testing purposes. Please reach out to \
|
||||
founders@danswer.ai for more information. Please visit https://github.com/danswer-ai/danswer"
|
||||
|
||||
# Default DANSWER_VERSION, typically overriden during builds by GitHub Actions.
|
||||
ARG DANSWER_VERSION=0.3-dev
|
||||
|
@@ -9,64 +9,17 @@ const nextConfig = {
|
||||
output: "standalone",
|
||||
swcMinify: true,
|
||||
rewrites: async () => {
|
||||
const eeRedirects =
|
||||
process.env.NEXT_PUBLIC_ENABLE_PAID_EE_FEATURES?.toLowerCase() === "true"
|
||||
? [
|
||||
// user group pages
|
||||
{
|
||||
source: "/admin/groups",
|
||||
destination: "/ee/admin/groups",
|
||||
},
|
||||
{
|
||||
source: "/admin/groups/:path*",
|
||||
destination: "/ee/admin/groups/:path*",
|
||||
},
|
||||
{
|
||||
source: "/admin/api-key",
|
||||
destination: "/ee/admin/api-key",
|
||||
},
|
||||
// analytics / audit log pages
|
||||
{
|
||||
source: "/admin/performance/usage",
|
||||
destination: "/ee/admin/performance/usage",
|
||||
},
|
||||
{
|
||||
source: "/admin/performance/query-history",
|
||||
destination: "/ee/admin/performance/query-history",
|
||||
},
|
||||
{
|
||||
source: "/admin/performance/query-history/:path*",
|
||||
destination: "/ee/admin/performance/query-history/:path*",
|
||||
},
|
||||
// whitelabeling
|
||||
{
|
||||
source: "/admin/whitelabeling",
|
||||
destination: "/ee/admin/whitelabeling",
|
||||
},
|
||||
// custom analytics/tracking
|
||||
{
|
||||
source: "/admin/performance/custom-analytics",
|
||||
destination: "/ee/admin/performance/custom-analytics",
|
||||
},
|
||||
// token rate limits
|
||||
{
|
||||
source: "/admin/token-rate-limits",
|
||||
destination: "/ee/admin/token-rate-limits",
|
||||
},
|
||||
]
|
||||
: [];
|
||||
|
||||
// In production, something else (nginx in the one box setup) should take
|
||||
// care of this rewrite. TODO (chris): better support setups where
|
||||
// web_server and api_server are on different machines.
|
||||
if (process.env.NODE_ENV === "production") return eeRedirects;
|
||||
if (process.env.NODE_ENV === "production") return [];
|
||||
|
||||
return [
|
||||
{
|
||||
source: "/api/:path*",
|
||||
destination: "http://127.0.0.1:8080/:path*", // Proxy to Backend
|
||||
},
|
||||
].concat(eeRedirects);
|
||||
];
|
||||
},
|
||||
redirects: async () => {
|
||||
// In production, something else (nginx in the one box setup) should take
|
||||
|
@@ -25,7 +25,6 @@ import {
|
||||
} from "@/components/admin/connectors/Field";
|
||||
import { HidableSection } from "./HidableSection";
|
||||
import { FiPlus, FiX } from "react-icons/fi";
|
||||
import { EE_ENABLED } from "@/lib/constants";
|
||||
import { useUserGroups } from "@/lib/hooks";
|
||||
import { Bubble } from "@/components/Bubble";
|
||||
import { GroupsIcon } from "@/components/icons/icons";
|
||||
@@ -37,6 +36,8 @@ import { ToolSnapshot } from "@/lib/tools/interfaces";
|
||||
import { checkUserIsNoAuthUser } from "@/lib/user";
|
||||
import { addAssistantToList } from "@/lib/assistants/updateAssistantPreferences";
|
||||
import { checkLLMSupportsImageInput } from "@/lib/llm/utils";
|
||||
import { SettingsContext } from "@/components/settings/SettingsProvider";
|
||||
import { usePaidEnterpriseFeaturesEnabled } from "@/components/settings/usePaidEnterpriseFeaturesEnabled";
|
||||
|
||||
function findSearchTool(tools: ToolSnapshot[]) {
|
||||
return tools.find((tool) => tool.in_code_tool_id === "SearchTool");
|
||||
@@ -80,6 +81,8 @@ export function AssistantEditor({
|
||||
const router = useRouter();
|
||||
const { popup, setPopup } = usePopup();
|
||||
|
||||
const isPaidEnterpriseFeaturesEnabled = usePaidEnterpriseFeaturesEnabled();
|
||||
|
||||
// EE only
|
||||
const { data: userGroups, isLoading: userGroupsIsLoading } = useUserGroups();
|
||||
|
||||
@@ -868,7 +871,7 @@ export function AssistantEditor({
|
||||
|
||||
<Divider />
|
||||
|
||||
{EE_ENABLED &&
|
||||
{isPaidEnterpriseFeaturesEnabled &&
|
||||
userGroups &&
|
||||
(!user || user.role === "admin") && (
|
||||
<>
|
||||
|
@@ -25,13 +25,15 @@ import { getNameFromPath } from "@/lib/fileUtils";
|
||||
import { Button, Card, Divider, Text } from "@tremor/react";
|
||||
import { AdminPageTitle } from "@/components/admin/Title";
|
||||
import IsPublicField from "@/components/admin/connectors/IsPublicField";
|
||||
import { EE_ENABLED } from "@/lib/constants";
|
||||
import { usePaidEnterpriseFeaturesEnabled } from "@/components/settings/usePaidEnterpriseFeaturesEnabled";
|
||||
|
||||
const Main = () => {
|
||||
const [selectedFiles, setSelectedFiles] = useState<File[]>([]);
|
||||
const [filesAreUploading, setFilesAreUploading] = useState<boolean>(false);
|
||||
const { popup, setPopup } = usePopup();
|
||||
|
||||
const isPaidEnterpriseFeaturesEnabled = usePaidEnterpriseFeaturesEnabled();
|
||||
|
||||
const { mutate } = useSWRConfig();
|
||||
|
||||
const {
|
||||
@@ -90,13 +92,13 @@ const Main = () => {
|
||||
initialValues={{
|
||||
name: "",
|
||||
selectedFiles: [],
|
||||
is_public: EE_ENABLED ? false : undefined,
|
||||
is_public: isPaidEnterpriseFeaturesEnabled ? false : undefined,
|
||||
}}
|
||||
validationSchema={Yup.object().shape({
|
||||
name: Yup.string().required(
|
||||
"Please enter a descriptive name for the files"
|
||||
),
|
||||
...(EE_ENABLED && {
|
||||
...(isPaidEnterpriseFeaturesEnabled && {
|
||||
is_public: Yup.boolean().required(),
|
||||
}),
|
||||
})}
|
||||
@@ -226,7 +228,7 @@ const Main = () => {
|
||||
setSelectedFiles={setSelectedFiles}
|
||||
/>
|
||||
|
||||
{EE_ENABLED && (
|
||||
{isPaidEnterpriseFeaturesEnabled && (
|
||||
<>
|
||||
<Divider />
|
||||
<IsPublicField />
|
||||
|
@@ -1,3 +1,5 @@
|
||||
"use client";
|
||||
|
||||
import { ArrayHelpers, FieldArray, Form, Formik } from "formik";
|
||||
import * as Yup from "yup";
|
||||
import { PopupSpec } from "@/components/admin/connectors/Popup";
|
||||
@@ -9,8 +11,8 @@ import {
|
||||
} from "@/components/admin/connectors/Field";
|
||||
import { ConnectorTitle } from "@/components/admin/connectors/ConnectorTitle";
|
||||
import { Button, Divider, Text } from "@tremor/react";
|
||||
import { EE_ENABLED } from "@/lib/constants";
|
||||
import { FiUsers } from "react-icons/fi";
|
||||
import { usePaidEnterpriseFeaturesEnabled } from "@/components/settings/usePaidEnterpriseFeaturesEnabled";
|
||||
|
||||
interface SetCreationPopupProps {
|
||||
ccPairs: ConnectorIndexingStatus<any, any>[];
|
||||
@@ -27,6 +29,8 @@ export const DocumentSetCreationForm = ({
|
||||
setPopup,
|
||||
existingDocumentSet,
|
||||
}: SetCreationPopupProps) => {
|
||||
const isPaidEnterpriseFeaturesEnabled = usePaidEnterpriseFeaturesEnabled();
|
||||
|
||||
const isUpdate = existingDocumentSet !== undefined;
|
||||
|
||||
return (
|
||||
@@ -167,46 +171,48 @@ export const DocumentSetCreationForm = ({
|
||||
)}
|
||||
/>
|
||||
|
||||
{EE_ENABLED && userGroups && userGroups.length > 0 && (
|
||||
<div>
|
||||
<Divider />
|
||||
{isPaidEnterpriseFeaturesEnabled &&
|
||||
userGroups &&
|
||||
userGroups.length > 0 && (
|
||||
<div>
|
||||
<Divider />
|
||||
|
||||
<BooleanFormField
|
||||
name="is_public"
|
||||
label="Is Public?"
|
||||
subtext={
|
||||
<BooleanFormField
|
||||
name="is_public"
|
||||
label="Is Public?"
|
||||
subtext={
|
||||
<>
|
||||
If the document set is public, then it will be visible
|
||||
to <b>all users</b>. If it is not public, then only
|
||||
users in the specified groups will be able to see it.
|
||||
</>
|
||||
}
|
||||
/>
|
||||
|
||||
<Divider />
|
||||
<h2 className="mb-1 font-medium text-base">
|
||||
Groups with Access
|
||||
</h2>
|
||||
{!values.is_public ? (
|
||||
<>
|
||||
If the document set is public, then it will be visible to{" "}
|
||||
<b>all users</b>. If it is not public, then only users in
|
||||
the specified groups will be able to see it.
|
||||
</>
|
||||
}
|
||||
/>
|
||||
|
||||
<Divider />
|
||||
<h2 className="mb-1 font-medium text-base">
|
||||
Groups with Access
|
||||
</h2>
|
||||
{!values.is_public ? (
|
||||
<>
|
||||
<Text className="mb-3">
|
||||
If any groups are specified, then this Document Set will
|
||||
only be visible to the specified groups. If no groups are
|
||||
specified, then the Document Set will be visible to all
|
||||
users.
|
||||
</Text>
|
||||
<FieldArray
|
||||
name="groups"
|
||||
render={(arrayHelpers: ArrayHelpers) => (
|
||||
<div className="flex gap-2 flex-wrap">
|
||||
{userGroups.map((userGroup) => {
|
||||
const ind = values.groups.indexOf(userGroup.id);
|
||||
let isSelected = ind !== -1;
|
||||
return (
|
||||
<div
|
||||
key={userGroup.id}
|
||||
className={
|
||||
`
|
||||
<Text className="mb-3">
|
||||
If any groups are specified, then this Document Set will
|
||||
only be visible to the specified groups. If no groups
|
||||
are specified, then the Document Set will be visible to
|
||||
all users.
|
||||
</Text>
|
||||
<FieldArray
|
||||
name="groups"
|
||||
render={(arrayHelpers: ArrayHelpers) => (
|
||||
<div className="flex gap-2 flex-wrap">
|
||||
{userGroups.map((userGroup) => {
|
||||
const ind = values.groups.indexOf(userGroup.id);
|
||||
let isSelected = ind !== -1;
|
||||
return (
|
||||
<div
|
||||
key={userGroup.id}
|
||||
className={
|
||||
`
|
||||
px-3
|
||||
py-1
|
||||
rounded-lg
|
||||
@@ -215,38 +221,38 @@ export const DocumentSetCreationForm = ({
|
||||
w-fit
|
||||
flex
|
||||
cursor-pointer ` +
|
||||
(isSelected
|
||||
? " bg-background-strong"
|
||||
: " hover:bg-hover")
|
||||
}
|
||||
onClick={() => {
|
||||
if (isSelected) {
|
||||
arrayHelpers.remove(ind);
|
||||
} else {
|
||||
arrayHelpers.push(userGroup.id);
|
||||
(isSelected
|
||||
? " bg-background-strong"
|
||||
: " hover:bg-hover")
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div className="my-auto flex">
|
||||
<FiUsers className="my-auto mr-2" />{" "}
|
||||
{userGroup.name}
|
||||
onClick={() => {
|
||||
if (isSelected) {
|
||||
arrayHelpers.remove(ind);
|
||||
} else {
|
||||
arrayHelpers.push(userGroup.id);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div className="my-auto flex">
|
||||
<FiUsers className="my-auto mr-2" />{" "}
|
||||
{userGroup.name}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<Text>
|
||||
This Document Set is public, so this does not apply. If you
|
||||
want to control which user groups see this Document Set,
|
||||
mark it as non-public!
|
||||
</Text>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<Text>
|
||||
This Document Set is public, so this does not apply. If
|
||||
you want to control which user groups see this Document
|
||||
Set, mark it as non-public!
|
||||
</Text>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<div className="flex mt-6">
|
||||
<Button
|
||||
type="submit"
|
||||
|
@@ -1,4 +1,3 @@
|
||||
import { EE_ENABLED } from "@/lib/constants";
|
||||
import { errorHandlingFetcher } from "@/lib/fetcher";
|
||||
import { DocumentSet } from "@/lib/types";
|
||||
import useSWR, { mutate } from "swr";
|
||||
|
@@ -1,6 +1,5 @@
|
||||
import { NotebookIcon } from "@/components/icons/icons";
|
||||
import { getWebVersion, getBackendVersion } from "@/lib/version";
|
||||
import { EE_ENABLED } from "@/lib/constants";
|
||||
|
||||
const Page = async () => {
|
||||
let web_version: string | null = null;
|
||||
@@ -22,9 +21,6 @@ const Page = async () => {
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<p className="font-bold text-lg my-auto mb-2">
|
||||
{EE_ENABLED ? "Danswer Enterprise Edition" : "Danswer MIT"}
|
||||
</p>
|
||||
<div className="flex mb-2">
|
||||
<p className="my-auto mr-1">Backend Version: </p>
|
||||
<p className="text-base my-auto text-slate-400 italic">
|
||||
|
@@ -22,7 +22,7 @@ import { GenericTokenRateLimitTable } from "./TokenRateLimitTables";
|
||||
import { mutate } from "swr";
|
||||
import { usePopup } from "@/components/admin/connectors/Popup";
|
||||
import { CreateRateLimitModal } from "./CreateRateLimitModal";
|
||||
import { EE_ENABLED } from "@/lib/constants";
|
||||
import { usePaidEnterpriseFeaturesEnabled } from "@/components/settings/usePaidEnterpriseFeaturesEnabled";
|
||||
|
||||
const BASE_URL = "/api/admin/token-rate-limits";
|
||||
const GLOBAL_TOKEN_FETCH_URL = `${BASE_URL}/global`;
|
||||
@@ -69,6 +69,8 @@ function Main() {
|
||||
const [modalIsOpen, setModalIsOpen] = useState(false);
|
||||
const { popup, setPopup } = usePopup();
|
||||
|
||||
const isPaidEnterpriseFeaturesEnabled = usePaidEnterpriseFeaturesEnabled();
|
||||
|
||||
const updateTable = (target_scope: Scope) => {
|
||||
if (target_scope === Scope.GLOBAL) {
|
||||
mutate(GLOBAL_TOKEN_FETCH_URL);
|
||||
@@ -120,7 +122,7 @@ function Main() {
|
||||
token spend.
|
||||
</Text>
|
||||
</li>
|
||||
{EE_ENABLED && (
|
||||
{isPaidEnterpriseFeaturesEnabled && (
|
||||
<>
|
||||
<li>
|
||||
<Text>
|
||||
@@ -150,7 +152,7 @@ function Main() {
|
||||
Create a Token Rate Limit
|
||||
</Button>
|
||||
|
||||
{EE_ENABLED && (
|
||||
{isPaidEnterpriseFeaturesEnabled && (
|
||||
<TabGroup className="mt-6" index={tabIndex} onIndexChange={setTabIndex}>
|
||||
<TabList variant="line">
|
||||
<Tab icon={FiGlobe}>Global</Tab>
|
||||
@@ -191,7 +193,7 @@ function Main() {
|
||||
</TabGroup>
|
||||
)}
|
||||
|
||||
{!EE_ENABLED && (
|
||||
{!isPaidEnterpriseFeaturesEnabled && (
|
||||
<div className="mt-6">
|
||||
<GenericTokenRateLimitTable
|
||||
fetchUrl={GLOBAL_TOKEN_FETCH_URL}
|
||||
@@ -206,7 +208,9 @@ function Main() {
|
||||
setIsOpen={() => setModalIsOpen(false)}
|
||||
setPopup={setPopup}
|
||||
onSubmit={handleSubmit}
|
||||
forSpecificScope={EE_ENABLED ? undefined : Scope.GLOBAL}
|
||||
forSpecificScope={
|
||||
isPaidEnterpriseFeaturesEnabled ? undefined : Scope.GLOBAL
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
@@ -1,5 +1,5 @@
|
||||
The DanswerAI Enterprise license (the “Enterprise License”)
|
||||
Copyright (c) 2023 DanswerAI, Inc.
|
||||
Copyright (c) 2023-present DanswerAI, Inc.
|
||||
|
||||
With regard to the Danswer Software:
|
||||
|
||||
|
@@ -1,11 +1,11 @@
|
||||
import { EE_ENABLED } from "@/lib/constants";
|
||||
import { SERVER_SIDE_ONLY__PAID_ENTERPRISE_FEATURES_ENABLED } from "@/lib/constants";
|
||||
|
||||
export default async function AdminLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
if (!EE_ENABLED) {
|
||||
if (!SERVER_SIDE_ONLY__PAID_ENTERPRISE_FEATURES_ENABLED) {
|
||||
return (
|
||||
<div className="flex h-screen">
|
||||
<div className="mx-auto my-auto text-lg font-bold text-red-500">
|
||||
|
@@ -19,7 +19,7 @@ import {
|
||||
getAuthTypeMetadataSS,
|
||||
getCurrentUserSS,
|
||||
} from "@/lib/userSS";
|
||||
import { EE_ENABLED } from "@/lib/constants";
|
||||
import { SERVER_SIDE_ONLY__PAID_ENTERPRISE_FEATURES_ENABLED } from "@/lib/constants";
|
||||
import { redirect } from "next/navigation";
|
||||
import {
|
||||
FiActivity,
|
||||
@@ -194,7 +194,7 @@ export async function Layout({ children }: { children: React.ReactNode }) {
|
||||
),
|
||||
link: "/admin/users",
|
||||
},
|
||||
...(EE_ENABLED
|
||||
...(SERVER_SIDE_ONLY__PAID_ENTERPRISE_FEATURES_ENABLED
|
||||
? [
|
||||
{
|
||||
name: (
|
||||
@@ -227,7 +227,7 @@ export async function Layout({ children }: { children: React.ReactNode }) {
|
||||
},
|
||||
],
|
||||
},
|
||||
...(EE_ENABLED
|
||||
...(SERVER_SIDE_ONLY__PAID_ENTERPRISE_FEATURES_ENABLED
|
||||
? [
|
||||
{
|
||||
name: "Performance",
|
||||
@@ -275,7 +275,7 @@ export async function Layout({ children }: { children: React.ReactNode }) {
|
||||
),
|
||||
link: "/admin/settings",
|
||||
},
|
||||
...(EE_ENABLED
|
||||
...(SERVER_SIDE_ONLY__PAID_ENTERPRISE_FEATURES_ENABLED
|
||||
? [
|
||||
{
|
||||
name: (
|
||||
|
@@ -1,3 +1,5 @@
|
||||
"use client";
|
||||
|
||||
import React, { useState } from "react";
|
||||
import { Formik, Form } from "formik";
|
||||
import * as Yup from "yup";
|
||||
@@ -14,8 +16,8 @@ import { BooleanFormField, TextFormField } from "./Field";
|
||||
import { createCredential, linkCredential } from "@/lib/credential";
|
||||
import { useSWRConfig } from "swr";
|
||||
import { Button, Divider } from "@tremor/react";
|
||||
import { EE_ENABLED } from "@/lib/constants";
|
||||
import IsPublicField from "./IsPublicField";
|
||||
import { usePaidEnterpriseFeaturesEnabled } from "@/components/settings/usePaidEnterpriseFeaturesEnabled";
|
||||
|
||||
const BASE_CONNECTOR_URL = "/api/manage/admin/connector";
|
||||
|
||||
@@ -76,7 +78,6 @@ interface BaseProps<T extends Yup.AnyObject> {
|
||||
// If specified, then we will create an empty credential and associate
|
||||
// the connector with it. If credentialId is specified, then this will be ignored
|
||||
shouldCreateEmptyCredentialForConnector?: boolean;
|
||||
showNonPublicOption?: boolean;
|
||||
}
|
||||
|
||||
type ConnectorFormProps<T extends Yup.AnyObject> = RequireAtLeastOne<
|
||||
@@ -98,12 +99,13 @@ export function ConnectorForm<T extends Yup.AnyObject>({
|
||||
pruneFreq,
|
||||
onSubmit,
|
||||
shouldCreateEmptyCredentialForConnector,
|
||||
// only show this option for EE, since groups are not supported in CE
|
||||
showNonPublicOption = EE_ENABLED,
|
||||
}: ConnectorFormProps<T>): JSX.Element {
|
||||
const { mutate } = useSWRConfig();
|
||||
const { popup, setPopup } = usePopup();
|
||||
|
||||
// only show this option for EE, since groups are not supported in CE
|
||||
const showNonPublicOption = usePaidEnterpriseFeaturesEnabled();
|
||||
|
||||
const shouldHaveNameInput = credentialId !== undefined && !ccPairNameBuilder;
|
||||
|
||||
const ccPairNameInitialValue = shouldHaveNameInput
|
||||
|
@@ -1,10 +1,13 @@
|
||||
import { EnterpriseSettings, Settings } from "@/app/admin/settings/interfaces";
|
||||
import { CUSTOM_ANALYTICS_ENABLED, EE_ENABLED } from "@/lib/constants";
|
||||
import {
|
||||
CUSTOM_ANALYTICS_ENABLED,
|
||||
SERVER_SIDE_ONLY__PAID_ENTERPRISE_FEATURES_ENABLED,
|
||||
} from "@/lib/constants";
|
||||
import { fetchSS } from "@/lib/utilsSS";
|
||||
|
||||
export async function fetchSettingsSS() {
|
||||
const tasks = [fetchSS("/settings")];
|
||||
if (EE_ENABLED) {
|
||||
if (SERVER_SIDE_ONLY__PAID_ENTERPRISE_FEATURES_ENABLED) {
|
||||
tasks.push(fetchSS("/enterprise-settings"));
|
||||
if (CUSTOM_ANALYTICS_ENABLED) {
|
||||
tasks.push(fetchSS("/enterprise-settings/custom-analytics-script"));
|
||||
|
@@ -0,0 +1,12 @@
|
||||
"use client";
|
||||
|
||||
import { useContext } from "react";
|
||||
import { SettingsContext } from "./SettingsProvider";
|
||||
|
||||
export function usePaidEnterpriseFeaturesEnabled() {
|
||||
const combinedSettings = useContext(SettingsContext);
|
||||
if (!combinedSettings) {
|
||||
return null;
|
||||
}
|
||||
return combinedSettings.enterpriseSettings !== null;
|
||||
}
|
@@ -25,14 +25,13 @@ export const HEADER_PADDING = `pt-[64px]`;
|
||||
export const LOGOUT_DISABLED =
|
||||
process.env.NEXT_PUBLIC_DISABLE_LOGOUT?.toLowerCase() === "true";
|
||||
|
||||
// NOTE: since this is a `NEXT_PUBLIC_` variable, it will be set at
|
||||
// build-time
|
||||
// TODO: consider moving this to an API call so that the api_server
|
||||
// can be the single source of truth
|
||||
export const EE_ENABLED =
|
||||
process.env.NEXT_PUBLIC_ENABLE_PAID_EE_FEATURES?.toLowerCase() === "true";
|
||||
/* Enterprise-only settings */
|
||||
|
||||
// NOTE: this should ONLY be used on the server-side. If used client side,
|
||||
// it will not be accurate (will always be false).
|
||||
export const SERVER_SIDE_ONLY__PAID_ENTERPRISE_FEATURES_ENABLED =
|
||||
process.env.ENABLE_PAID_EE_FEATURES?.toLowerCase() === "true";
|
||||
|
||||
// Enterprise-only settings
|
||||
export const CUSTOM_ANALYTICS_ENABLED = process.env.CUSTOM_ANALYTICS_SECRET_KEY
|
||||
? true
|
||||
: false;
|
||||
|
@@ -11,10 +11,10 @@ import { errorHandlingFetcher } from "./fetcher";
|
||||
import { useState } from "react";
|
||||
import { DateRangePickerValue } from "@tremor/react";
|
||||
import { SourceMetadata } from "./search/interfaces";
|
||||
import { EE_ENABLED } from "./constants";
|
||||
import { destructureValue } from "./llm/utils";
|
||||
import { ChatSession } from "@/app/chat/interfaces";
|
||||
import { UsersResponse } from "./users/interfaces";
|
||||
import { usePaidEnterpriseFeaturesEnabled } from "@/components/settings/usePaidEnterpriseFeaturesEnabled";
|
||||
|
||||
const CREDENTIAL_URL = "/api/manage/admin/credential";
|
||||
|
||||
@@ -192,8 +192,9 @@ export const useUserGroups = (): {
|
||||
refreshUserGroups: () => void;
|
||||
} => {
|
||||
const swrResponse = useSWR<UserGroup[]>(USER_GROUP_URL, errorHandlingFetcher);
|
||||
const isPaidEnterpriseFeaturesEnabled = usePaidEnterpriseFeaturesEnabled();
|
||||
|
||||
if (!EE_ENABLED) {
|
||||
if (!isPaidEnterpriseFeaturesEnabled) {
|
||||
return {
|
||||
...{
|
||||
data: [],
|
||||
|
39
web/src/middleware.ts
Normal file
39
web/src/middleware.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import type { NextRequest } from "next/server";
|
||||
import { SERVER_SIDE_ONLY__PAID_ENTERPRISE_FEATURES_ENABLED } from "./lib/constants";
|
||||
|
||||
const eePaths = [
|
||||
"/admin/groups",
|
||||
"/admin/api-key",
|
||||
"/admin/performance/usage",
|
||||
"/admin/performance/query-history",
|
||||
"/admin/whitelabeling",
|
||||
"/admin/performance/custom-analytics",
|
||||
];
|
||||
const eePathsForMatcher = eePaths.map((path) => `${path}/:path*`);
|
||||
|
||||
export async function middleware(request: NextRequest) {
|
||||
if (SERVER_SIDE_ONLY__PAID_ENTERPRISE_FEATURES_ENABLED) {
|
||||
const pathname = request.nextUrl.pathname;
|
||||
|
||||
// Check if the current path is in the eePaths list
|
||||
if (eePaths.some((path) => pathname.startsWith(path))) {
|
||||
// Add '/ee' to the beginning of the pathname
|
||||
const newPathname = `/ee${pathname}`;
|
||||
|
||||
// Create a new URL with the modified pathname
|
||||
const newUrl = new URL(newPathname, request.url);
|
||||
|
||||
// Rewrite to the new URL
|
||||
return NextResponse.rewrite(newUrl);
|
||||
}
|
||||
}
|
||||
|
||||
// Continue with the response if no rewrite is needed
|
||||
return NextResponse.next();
|
||||
}
|
||||
|
||||
// Specify the paths that the middleware should run for
|
||||
export const config = {
|
||||
matcher: eePathsForMatcher,
|
||||
};
|
@@ -1,13 +1,11 @@
|
||||
var merge = require("lodash/merge");
|
||||
|
||||
const baseThemes = require("./tailwind-themes/tailwind.config.js");
|
||||
const customThemes =
|
||||
process.env.NEXT_PUBLIC_ENABLE_PAID_EE_FEATURES &&
|
||||
process.env.NEXT_PUBLIC_THEME
|
||||
? require(
|
||||
`./tailwind-themes/custom/${process.env.NEXT_PUBLIC_THEME}/tailwind.config.js`
|
||||
)
|
||||
: null;
|
||||
const customThemes = process.env.NEXT_PUBLIC_THEME
|
||||
? require(
|
||||
`./tailwind-themes/custom/${process.env.NEXT_PUBLIC_THEME}/tailwind.config.js`
|
||||
)
|
||||
: null;
|
||||
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = customThemes ? merge(baseThemes, customThemes) : baseThemes;
|
||||
|
Reference in New Issue
Block a user