merlyn/frontend/src/components/WorkspaceChat/index.jsx
Sean Hatfield 727d802779
Light/dark mode UI overhaul (#2629)
* Refactor workspace sidebar component styles (#2380)

rely on css for conditional styles

* New sidebar colors (#2381)

new sidebar colors

* Main container color update (#2382)

* Dark mode setup themes (#2411)

* setup generic tailwind theme + ability to add new themes

* add theme context

* use correct colors from design for sidebar + fix padding

* Settings sidebar UI updates (#2416)

settings sidebar ui updates

* fix sidebar resizing/truncate issue on hover

* Dark mode chat window (#2443)

* Support XLSX files (#2403)

* support xlsx files

* lint

* create seperate docs for each xlsx sheet

* lint

* use node-xlsx pkg for parsing xslx files

* lint

* update error handling

---------

Co-authored-by: timothycarambat <rambat1010@gmail.com>

* wip chat window

* ux+ux improvements and update new colors

* chat window dark mode

* remove comment

---------

Co-authored-by: timothycarambat <rambat1010@gmail.com>

* Dark mode welcome page (#2444)

* dark mode welcome page styles + refactor

* remove AI_BACKGROUND_COLOR and USER_BACKGROUND_COLOR constants

* Dark mode UI for admin and tools pages + mobile view improvements (#2454)

* dark mode ui for admin and tools pages + mobile view improvements

* lint

* ai provider pages + options darkmode ui

* placeholder generic class

* appearance settings styles

* ai providers mobile margin

* dark mode styles for agent skills + experimental features

* mobile styles on security settings

* fine tune flow ui dark mode

* workspace settings page

* lint

* Dark mode onboarding (#2461)

dark mode onboarding

* update all modals + normalize styles (#2471)

* lint

* Dark mode privacy & experimental pages (#2479)

* document watch + privacy pages ui + mobile modal darkmode

* lint

* Dark mode login screens (#2483)

* multi-user auth screen ui update

* dark mode login screen + recovery key modals

* remove unneeded import

* Workspace preset commands modals dark mode (#2484)

update workspace preset dark mode modal

* Document pinning modal ui update (#2490)

document pinning modal ui update

* Experimental agreement modal dark mode (#2491)

experimental agreement modal dark mode

* Serp options dark mode (#2492)

serp options dark mode

* field fixes

* attempt light mode wip

* setting sidebar

* Toasts and threads

* main page content and privacy page

* force rewrite for light

* add border for light mode rightside content

* more fixes

* wip

* wip

* wip light mode implementation

* wip dark light mode file picker

* document picker light mode ui

* slight ui tweaks

* light mode fine tuning flow

* light mode tweaks + qa fixes

* fix md rendering of light mode + tooltip fixes

* lint

* qa bug fixes

* Add developer hook for theme
move provider to outmost layer

* qa light mode bug fixes

* Linting and hotfixes for UI

* Light mode to dev

* accept invite light mode ui fix

* Fix onboarding inputs in dark mode

* fix close icons
last minute items

* patch z-index on tooltips

* patch light mode citations

---------

Co-authored-by: timothycarambat <rambat1010@gmail.com>
2024-11-18 15:40:18 -08:00

107 lines
3.6 KiB
JavaScript

import React, { useEffect, useState } from "react";
import Workspace from "@/models/workspace";
import LoadingChat from "./LoadingChat";
import ChatContainer from "./ChatContainer";
import paths from "@/utils/paths";
import ModalWrapper from "../ModalWrapper";
import { useParams } from "react-router-dom";
import { DnDFileUploaderProvider } from "./ChatContainer/DnDWrapper";
export default function WorkspaceChat({ loading, workspace }) {
const { threadSlug = null } = useParams();
const [history, setHistory] = useState([]);
const [loadingHistory, setLoadingHistory] = useState(true);
useEffect(() => {
async function getHistory() {
if (loading) return;
if (!workspace?.slug) {
setLoadingHistory(false);
return false;
}
const chatHistory = threadSlug
? await Workspace.threads.chatHistory(workspace.slug, threadSlug)
: await Workspace.chatHistory(workspace.slug);
setHistory(chatHistory);
setLoadingHistory(false);
}
getHistory();
}, [workspace, loading]);
if (loadingHistory) return <LoadingChat />;
if (!loading && !loadingHistory && !workspace) {
return (
<>
{loading === false && !workspace && (
<ModalWrapper isOpen={true}>
<div className="relative w-full max-w-2xl bg-theme-bg-secondary rounded-lg shadow border-2 border-theme-modal-border">
<div className="flex flex-col gap-y-4 w-full p-6 text-center">
<p className="font-semibold text-red-500 text-xl">
Workspace not found!
</p>
<p className="text-sm mt-4 text-white">
It looks like a workspace by this name is not available.
</p>
<div className="flex w-full justify-center items-center mt-4">
<a
href={paths.home()}
className="transition-all duration-300 bg-white text-black hover:opacity-60 px-4 py-2 rounded-lg text-sm flex items-center gap-x-2"
>
Go back to homepage
</a>
</div>
</div>
</div>
</ModalWrapper>
)}
<LoadingChat />
</>
);
}
setEventDelegatorForCodeSnippets();
return (
<DnDFileUploaderProvider workspace={workspace}>
<ChatContainer workspace={workspace} knownHistory={history} />
</DnDFileUploaderProvider>
);
}
// Enables us to safely markdown and sanitize all responses without risk of injection
// but still be able to attach a handler to copy code snippets on all elements
// that are code snippets.
function copyCodeSnippet(uuid) {
const target = document.querySelector(`[data-code="${uuid}"]`);
if (!target) return false;
const markdown =
target.parentElement?.parentElement?.querySelector(
"pre:first-of-type"
)?.innerText;
if (!markdown) return false;
window.navigator.clipboard.writeText(markdown);
target.classList.add("text-green-500");
const originalText = target.innerHTML;
target.innerText = "Copied!";
target.setAttribute("disabled", true);
setTimeout(() => {
target.classList.remove("text-green-500");
target.innerHTML = originalText;
target.removeAttribute("disabled");
}, 2500);
}
// Listens and hunts for all data-code-snippet clicks.
function setEventDelegatorForCodeSnippets() {
document?.addEventListener("click", function (e) {
const target = e.target.closest("[data-code-snippet]");
const uuidCode = target?.dataset?.code;
if (!uuidCode) return false;
copyCodeSnippet(uuidCode);
});
}