mirror of
https://github.com/danswer-ai/danswer.git
synced 2025-05-28 12:39:54 +02:00
Custom banner
This commit is contained in:
parent
91cf45165f
commit
3466f6d3a4
@ -304,9 +304,7 @@ def _prepare_index_attempt(db_session: Session, index_attempt_id: int) -> IndexA
|
||||
return attempt
|
||||
|
||||
|
||||
def run_indexing_entrypoint(
|
||||
index_attempt_id: int, is_ee: bool = False
|
||||
) -> None:
|
||||
def run_indexing_entrypoint(index_attempt_id: int, is_ee: bool = False) -> None:
|
||||
"""Entrypoint for indexing run when using dask distributed.
|
||||
Wraps the actual logic in a `try` block so that we can catch any exceptions
|
||||
and mark the attempt as failed."""
|
||||
|
@ -35,10 +35,10 @@ from danswer.db.models import IndexModelStatus
|
||||
from danswer.db.swap_index import check_index_swap
|
||||
from danswer.search.search_nlp_models import warm_up_encoders
|
||||
from danswer.utils.logger import setup_logger
|
||||
from danswer.utils.variable_functionality import global_version
|
||||
from shared_configs.configs import INDEXING_MODEL_SERVER_HOST
|
||||
from shared_configs.configs import LOG_LEVEL
|
||||
from shared_configs.configs import MODEL_SERVER_PORT
|
||||
from danswer.utils.variable_functionality import global_version
|
||||
|
||||
logger = setup_logger()
|
||||
|
||||
|
@ -9,5 +9,10 @@ class EnterpriseSettings(BaseModel):
|
||||
application_name: str | None = None
|
||||
use_custom_logo: bool = False
|
||||
|
||||
# custom Chat components
|
||||
custom_header_content: str | None = None
|
||||
custom_popup_header: str | None = None
|
||||
custom_popup_content: str | None = None
|
||||
|
||||
def check_validity(self) -> None:
|
||||
return
|
||||
|
@ -41,13 +41,14 @@ import { usePopup } from "@/components/admin/connectors/Popup";
|
||||
import { ResizableSection } from "@/components/resizable/ResizableSection";
|
||||
import { DanswerInitializingLoader } from "@/components/DanswerInitializingLoader";
|
||||
import { ChatIntro } from "./ChatIntro";
|
||||
import { HEADER_PADDING } from "@/lib/constants";
|
||||
import { computeAvailableFilters } from "@/lib/filters";
|
||||
import { useDocumentSelection } from "./useDocumentSelection";
|
||||
import { StarterMessage } from "./StarterMessage";
|
||||
import { ShareChatSessionModal } from "./modal/ShareChatSessionModal";
|
||||
import { SEARCH_PARAM_NAMES, shouldSubmitOnLoad } from "./searchParams";
|
||||
import { Persona } from "../admin/assistants/interfaces";
|
||||
import { ChatBanner } from "./ChatBanner";
|
||||
import { HEADER_PADDING } from "@/lib/constants";
|
||||
|
||||
const MAX_INPUT_HEIGHT = 200;
|
||||
|
||||
@ -594,6 +595,10 @@ export const Chat = ({
|
||||
className={`w-full h-full ${HEADER_PADDING} flex flex-col overflow-y-auto overflow-x-hidden relative`}
|
||||
ref={scrollableDivRef}
|
||||
>
|
||||
{/* ChatBanner is a custom banner that displays a admin-specified message at
|
||||
the top of the chat page. Only used in the EE version of the app. */}
|
||||
<ChatBanner />
|
||||
|
||||
{livePersona && (
|
||||
<div className="sticky top-0 left-80 z-10 w-full bg-background/90 flex">
|
||||
<div className="ml-2 p-1 rounded mt-2 w-fit">
|
||||
|
48
web/src/app/chat/ChatBanner.tsx
Normal file
48
web/src/app/chat/ChatBanner.tsx
Normal file
@ -0,0 +1,48 @@
|
||||
"use client";
|
||||
|
||||
import ReactMarkdown from "react-markdown";
|
||||
import { SettingsContext } from "@/components/settings/SettingsProviderClientSideHelper";
|
||||
import { useContext } from "react";
|
||||
import remarkGfm from "remark-gfm";
|
||||
|
||||
export function ChatBanner() {
|
||||
const settings = useContext(SettingsContext);
|
||||
if (!settings?.enterpriseSettings?.custom_header_content) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`
|
||||
z-[39]
|
||||
w-full
|
||||
h-[30px]
|
||||
bg-background-custom-header
|
||||
border-border
|
||||
border-b
|
||||
flex`}
|
||||
>
|
||||
<div className="mx-auto text-emphasis text-sm flex flex-col">
|
||||
<div className="my-auto">
|
||||
<ReactMarkdown
|
||||
className="prose max-w-full"
|
||||
components={{
|
||||
a: ({ node, ...props }) => (
|
||||
<a
|
||||
{...props}
|
||||
className="text-sm text-link hover:text-link-hover"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
/>
|
||||
),
|
||||
p: ({ node, ...props }) => <p {...props} className="text-sm" />,
|
||||
}}
|
||||
remarkPlugins={[remarkGfm]}
|
||||
>
|
||||
{settings.enterpriseSettings.custom_header_content}
|
||||
</ReactMarkdown>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
@ -72,6 +72,7 @@ import { useChatContext } from "@/components/context/ChatContext";
|
||||
import { UserDropdown } from "@/components/UserDropdown";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { orderAssistantsForUser } from "@/lib/assistants/orderAssistants";
|
||||
import { ChatPopup } from "./ChatPopup";
|
||||
|
||||
const MAX_INPUT_HEIGHT = 200;
|
||||
const TEMP_USER_MESSAGE_ID = -1;
|
||||
@ -872,6 +873,10 @@ export function ChatPage({
|
||||
<HealthCheckBanner />
|
||||
<InstantSSRAutoRefresh />
|
||||
|
||||
{/* ChatPopup is a custom popup that displays a admin-specified message on initial user visit.
|
||||
Only used in the EE version of the app. */}
|
||||
<ChatPopup />
|
||||
|
||||
<div className="flex relative bg-background text-default overflow-x-hidden">
|
||||
<ChatSidebar
|
||||
existingChats={chatSessions}
|
||||
|
73
web/src/app/chat/ChatPopup.tsx
Normal file
73
web/src/app/chat/ChatPopup.tsx
Normal file
@ -0,0 +1,73 @@
|
||||
"use client";
|
||||
|
||||
import { Modal } from "@/components/Modal";
|
||||
import { SettingsContext } from "@/components/settings/SettingsProviderClientSideHelper";
|
||||
import { Button } from "@tremor/react";
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import ReactMarkdown from "react-markdown";
|
||||
import remarkGfm from "remark-gfm";
|
||||
|
||||
const ALL_USERS_INITIAL_POPUP_FLOW_COMPLETED =
|
||||
"allUsersInitialPopupFlowCompleted";
|
||||
|
||||
export function ChatPopup() {
|
||||
const [completedFlow, setCompletedFlow] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
setCompletedFlow(
|
||||
localStorage.getItem(ALL_USERS_INITIAL_POPUP_FLOW_COMPLETED) === "true"
|
||||
);
|
||||
});
|
||||
|
||||
const settings = useContext(SettingsContext);
|
||||
if (!settings?.enterpriseSettings?.custom_popup_content || completedFlow) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let popupTitle = settings.enterpriseSettings.custom_popup_header;
|
||||
if (!popupTitle) {
|
||||
popupTitle = `Welcome to ${
|
||||
settings.enterpriseSettings.application_name || "Danswer"
|
||||
}!`;
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal width="w-3/6 xl:w-[700px]" title={popupTitle}>
|
||||
<>
|
||||
<ReactMarkdown
|
||||
className="prose max-w-full"
|
||||
components={{
|
||||
a: ({ node, ...props }) => (
|
||||
<a
|
||||
{...props}
|
||||
className="text-link hover:text-link-hover"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
/>
|
||||
),
|
||||
p: ({ node, ...props }) => <p {...props} className="text-sm" />,
|
||||
}}
|
||||
remarkPlugins={[remarkGfm]}
|
||||
>
|
||||
{settings.enterpriseSettings.custom_popup_content}
|
||||
</ReactMarkdown>
|
||||
|
||||
<div className="flex w-full">
|
||||
<Button
|
||||
className="mx-auto mt-4"
|
||||
size="xs"
|
||||
onClick={() => {
|
||||
localStorage.setItem(
|
||||
ALL_USERS_INITIAL_POPUP_FLOW_COMPLETED,
|
||||
"true"
|
||||
);
|
||||
setCompletedFlow(true);
|
||||
}}
|
||||
>
|
||||
Get started!
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
</Modal>
|
||||
);
|
||||
}
|
@ -7,8 +7,8 @@ import { SelectedDocumentDisplay } from "./SelectedDocumentDisplay";
|
||||
import { removeDuplicateDocs } from "@/lib/documentUtils";
|
||||
import { BasicSelectable } from "@/components/BasicClickable";
|
||||
import { Message, RetrievalType } from "../interfaces";
|
||||
import { HEADER_PADDING } from "@/lib/constants";
|
||||
import { HoverPopup } from "@/components/HoverPopup";
|
||||
import { HEADER_PADDING } from "@/lib/constants";
|
||||
|
||||
function SectionHeader({
|
||||
name,
|
||||
|
@ -11,7 +11,7 @@ import {
|
||||
SubLabel,
|
||||
TextFormField,
|
||||
} from "@/components/admin/connectors/Field";
|
||||
import { Button } from "@tremor/react";
|
||||
import { Button, Divider } from "@tremor/react";
|
||||
import { ImageUpload } from "./ImageUpload";
|
||||
|
||||
export function WhitelabelingForm() {
|
||||
@ -42,7 +42,6 @@ export function WhitelabelingForm() {
|
||||
alert(`Failed to update settings. ${errorMsg}`);
|
||||
}
|
||||
}
|
||||
console.log(enterpriseSettings);
|
||||
|
||||
return (
|
||||
<div>
|
||||
@ -50,10 +49,17 @@ export function WhitelabelingForm() {
|
||||
initialValues={{
|
||||
application_name: enterpriseSettings?.application_name || null,
|
||||
use_custom_logo: enterpriseSettings?.use_custom_logo || false,
|
||||
custom_header_content:
|
||||
enterpriseSettings?.custom_header_content || "",
|
||||
custom_popup_header: enterpriseSettings?.custom_popup_header || "",
|
||||
custom_popup_content: enterpriseSettings?.custom_popup_content || "",
|
||||
}}
|
||||
validationSchema={Yup.object().shape({
|
||||
application_name: Yup.string(),
|
||||
application_name: Yup.string().nullable(),
|
||||
use_custom_logo: Yup.boolean().required(),
|
||||
custom_header_content: Yup.string().nullable(),
|
||||
custom_popup_header: Yup.string().nullable(),
|
||||
custom_popup_content: Yup.string().nullable(),
|
||||
})}
|
||||
onSubmit={async (values, formikHelpers) => {
|
||||
formikHelpers.setSubmitting(true);
|
||||
@ -138,6 +144,44 @@ export function WhitelabelingForm() {
|
||||
setSelectedFile={setSelectedFile}
|
||||
/>
|
||||
|
||||
<Divider />
|
||||
|
||||
<div className="mt-4">
|
||||
<TextFormField
|
||||
label="Custom Chat Header Content"
|
||||
name="custom_header_content"
|
||||
subtext={`Custom Markdown content that will be displayed as a banner at the top of the Chat page.`}
|
||||
placeholder="Your header content..."
|
||||
disabled={isSubmitting}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Divider />
|
||||
|
||||
<div className="mt-4">
|
||||
<TextFormField
|
||||
label="Custom Popup Header"
|
||||
name="custom_popup_header"
|
||||
subtext={`The title for the popup that will be displayed for each user on their initial visit
|
||||
to the application. If left blank AND Custom Popup Content is specified, will use "Welcome to ${
|
||||
values.application_name || "Danswer"
|
||||
}!".`}
|
||||
placeholder="Initial Popup Header"
|
||||
disabled={isSubmitting}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mt-4">
|
||||
<TextFormField
|
||||
label="Custom Popup Content"
|
||||
name="custom_popup_content"
|
||||
subtext={`Custom Markdown content that will be displayed as a popup on initial visit to the application.`}
|
||||
placeholder="Your popup content..."
|
||||
isTextArea
|
||||
disabled={isSubmitting}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Button type="submit" className="mt-4">
|
||||
Update
|
||||
</Button>
|
||||
|
@ -23,6 +23,7 @@ import { personaComparator } from "../admin/assistants/lib";
|
||||
import { FullEmbeddingModelResponse } from "../admin/models/embedding/embeddingModels";
|
||||
import { NoSourcesModal } from "@/components/initialSetup/search/NoSourcesModal";
|
||||
import { NoCompleteSourcesModal } from "@/components/initialSetup/search/NoCompleteSourceModal";
|
||||
import { ChatPopup } from "../chat/ChatPopup";
|
||||
|
||||
export default async function Home() {
|
||||
// Disable caching so we always get the up to date connector / document set / persona info
|
||||
@ -163,6 +164,10 @@ export default async function Home() {
|
||||
<NoCompleteSourcesModal ccPairs={ccPairs} />
|
||||
)}
|
||||
|
||||
{/* ChatPopup is a custom popup that displays a admin-specified message on initial user visit.
|
||||
Only used in the EE version of the app. */}
|
||||
<ChatPopup />
|
||||
|
||||
<InstantSSRAutoRefresh />
|
||||
|
||||
<div className="px-24 pt-10 flex flex-col items-center min-h-screen">
|
||||
|
@ -15,7 +15,7 @@ export const GOOGLE_DRIVE_AUTH_IS_ADMIN_COOKIE_NAME =
|
||||
|
||||
export const SEARCH_TYPE_COOKIE_NAME = "search_type";
|
||||
|
||||
export const HEADER_PADDING = "pt-[64px]";
|
||||
export const HEADER_PADDING = `pt-[64px]`;
|
||||
|
||||
export const LOGOUT_DISABLED =
|
||||
process.env.NEXT_PUBLIC_DISABLE_LOGOUT?.toLowerCase() === "true";
|
||||
|
@ -42,9 +42,11 @@ module.exports = {
|
||||
"background-emphasis": "#f6f7f8",
|
||||
"background-strong": "#eaecef",
|
||||
"background-search": "#ffffff",
|
||||
"background-custom-header": "#f3f4f6",
|
||||
|
||||
// text or icons
|
||||
link: "#3b82f6", // blue-500
|
||||
"link-hover": "#1d4ed8", // blue-700
|
||||
subtle: "#6b7280", // gray-500
|
||||
default: "#4b5563", // gray-600
|
||||
emphasis: "#374151", // gray-700
|
||||
|
Loading…
x
Reference in New Issue
Block a user