diff --git a/frontend/src/components/Modals/NewWorkspace.jsx b/frontend/src/components/Modals/NewWorkspace.jsx index 5eed3773340..ae5248a2384 100644 --- a/frontend/src/components/Modals/NewWorkspace.jsx +++ b/frontend/src/components/Modals/NewWorkspace.jsx @@ -1,4 +1,4 @@ -import React, { useRef, useState } from "react"; +import React, { useRef, useState, useEffect } from "react"; import { X } from "@phosphor-icons/react"; import Workspace from "@/models/workspace"; import paths from "@/utils/paths"; @@ -8,8 +8,16 @@ import ModalWrapper from "@/components/ModalWrapper"; const noop = () => false; export default function NewWorkspaceModal({ hideModal = noop }) { const formEl = useRef(null); + const inputRef = useRef(null); const [error, setError] = useState(null); const { t } = useTranslation(); + + useEffect(() => { + if (inputRef.current) { + inputRef.current.focus(); + } + }, []); + const handleCreate = async (e) => { setError(null); e.preventDefault(); @@ -55,6 +63,7 @@ export default function NewWorkspaceModal({ hideModal = noop }) { {t("common.workspaces-name")} { + if (!loading && slug) { + setTimeout(() => { + const activeWorkspace = document.querySelector( + `[data-workspace-slug="${slug}"]` + ); + if (activeWorkspace) { + const scrollContainer = activeWorkspace.closest(".overflow-y-auto"); + if (scrollContainer) { + const containerHeight = scrollContainer.clientHeight; + const elementOffset = activeWorkspace.offsetTop; + scrollContainer.scrollTo({ + top: Math.max(0, elementOffset - containerHeight * 0.3), + behavior: "smooth", + }); + } + } + }, 100); + } + }, [loading, slug, workspaces]); + if (loading) { return (
-
-
-
-
-
- {(!user || user?.role !== "default") && ( - - )} -
- -
-
-
-
-
-
+ {(!user || user?.role !== "default") && ( + + )} +
+ +
+
+
{showingNewWsModal && } @@ -179,15 +171,17 @@ export function SidebarMobileHeader() {
{(!user || user?.role !== "default") && ( - +
+ +
)}
diff --git a/frontend/src/components/WorkspaceChat/index.jsx b/frontend/src/components/WorkspaceChat/index.jsx index 0621693ec77..41b8e446568 100644 --- a/frontend/src/components/WorkspaceChat/index.jsx +++ b/frontend/src/components/WorkspaceChat/index.jsx @@ -6,6 +6,8 @@ import paths from "@/utils/paths"; import ModalWrapper from "../ModalWrapper"; import { useParams } from "react-router-dom"; import { DnDFileUploaderProvider } from "./ChatContainer/DnDWrapper"; +import { saveLastActive, clearLastActive } from "@/utils/lastActive"; +import { WarningCircle } from "@phosphor-icons/react"; import { TTSProvider, useWatchForAutoPlayAssistantTTSResponse, @@ -17,10 +19,17 @@ export default function WorkspaceChat({ loading, workspace }) { const [history, setHistory] = useState([]); const [loadingHistory, setLoadingHistory] = useState(true); + useEffect(() => { + if (!loading && workspace?.slug) { + saveLastActive(workspace.slug, threadSlug); + } + }, [workspace?.slug, threadSlug, loading]); + useEffect(() => { async function getHistory() { if (loading) return; if (!workspace?.slug) { + clearLastActive(); setLoadingHistory(false); return false; } @@ -41,24 +50,32 @@ export default function WorkspaceChat({ loading, workspace }) { <> {loading === false && !workspace && ( -
-
-

- Workspace not found! -

-

- It looks like a workspace by this name is not available. -

- -
- - Go back to homepage - +
+
+
+ +

+ Workspace not found +

+
+

+ The workspace you're looking for is not available. It may + have been deleted or you may not have access to it. +

+
+
)} diff --git a/frontend/src/pages/WorkspaceSettings/GeneralAppearance/DeleteWorkspace/index.jsx b/frontend/src/pages/WorkspaceSettings/GeneralAppearance/DeleteWorkspace/index.jsx index 0023e33010a..43b8f24fe57 100644 --- a/frontend/src/pages/WorkspaceSettings/GeneralAppearance/DeleteWorkspace/index.jsx +++ b/frontend/src/pages/WorkspaceSettings/GeneralAppearance/DeleteWorkspace/index.jsx @@ -4,6 +4,7 @@ import Workspace from "@/models/workspace"; import paths from "@/utils/paths"; import { useTranslation } from "react-i18next"; import showToast from "@/utils/toast"; +import { clearLastActive } from "@/utils/lastActive"; export default function DeleteWorkspace({ workspace }) { const { slug } = useParams(); @@ -28,6 +29,8 @@ export default function DeleteWorkspace({ workspace }) { return; } + clearLastActive(); + workspace.slug === slug ? (window.location = paths.home()) : window.location.reload(); diff --git a/frontend/src/utils/lastActive.js b/frontend/src/utils/lastActive.js new file mode 100644 index 00000000000..836f7356ad9 --- /dev/null +++ b/frontend/src/utils/lastActive.js @@ -0,0 +1,24 @@ +const LAST_ACTIVE_KEY = "anythingllm_last_active_location"; + +export const saveLastActive = (workspace, thread = null) => { + const location = { + workspace, + thread, + timestamp: Date.now(), + }; + localStorage.setItem(LAST_ACTIVE_KEY, JSON.stringify(location)); +}; + +export const getLastActive = () => { + try { + const stored = localStorage.getItem(LAST_ACTIVE_KEY); + if (!stored) return null; + return JSON.parse(stored); + } catch (e) { + return null; + } +}; + +export const clearLastActive = () => { + localStorage.removeItem(LAST_ACTIVE_KEY); +}; diff --git a/frontend/src/utils/paths.js b/frontend/src/utils/paths.js index 48c28141b39..6449ef09c0d 100644 --- a/frontend/src/utils/paths.js +++ b/frontend/src/utils/paths.js @@ -1,4 +1,5 @@ import { API_BASE } from "./constants"; +import { getLastActive } from "./lastActive"; function applyOptions(path, options = {}) { let updatedPath = path; @@ -15,6 +16,14 @@ export default { home: () => { return "/"; }, + lastActiveChat: () => { + const lastActive = getLastActive(); + if (!lastActive?.workspace) return "/"; + if (lastActive.thread) { + return `/workspace/${lastActive.workspace}/t/${lastActive.thread}`; + } + return `/workspace/${lastActive.workspace}`; + }, login: (noTry = false) => { return `/login${noTry ? "?nt=1" : ""}`; },