θΏ™ζ˜―indexlocζδΎ›ηš„ζœεŠ‘οΌŒδΈθ¦θΎ“ε…₯任何密码
Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion frontend/src/components/Modals/NewWorkspace.jsx
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -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();
Expand Down Expand Up @@ -55,6 +63,7 @@ export default function NewWorkspaceModal({ hideModal = noop }) {
{t("common.workspaces-name")}
</label>
<input
ref={inputRef}
name="name"
type="text"
id="name"
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/components/SettingsButton/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ export default function SettingsButton() {
return (
<div className="flex w-fit">
<Link
to={paths.home()}
to={paths.lastActiveChat()}
className="transition-all duration-300 p-2 rounded-full bg-theme-sidebar-footer-icon hover:bg-theme-sidebar-footer-icon-hover"
aria-label="Home"
aria-label="Back"
data-tooltip-id="footer-item"
data-tooltip-content="Back to workspaces"
data-tooltip-content="Back to last workspace"
>
<ArrowUUpLeft
className="h-5 w-5"
Expand Down
21 changes: 21 additions & 0 deletions frontend/src/components/Sidebar/ActiveWorkspaces/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,27 @@ export default function ActiveWorkspaces() {
getWorkspaces();
}, []);

useEffect(() => {
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 (
<Skeleton.default
Expand Down
62 changes: 28 additions & 34 deletions frontend/src/components/Sidebar/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,32 +53,24 @@ export default function Sidebar() {
</div>
<div
ref={sidebarRef}
className="relative m-[16px] rounded-[16px] bg-theme-bg-sidebar border-[2px] border-theme-sidebar-border light:border-none min-w-[250px] p-[10px] h-[calc(100%-76px)]"
className="relative m-[16px] rounded-[16px] bg-theme-bg-sidebar border-[2px] border-theme-sidebar-border light:border-none min-w-[250px] p-[10px] h-[calc(100%-76px)] flex flex-col"
>
<div className="flex flex-col h-full overflow-x-hidden">
<div className="flex-grow flex flex-col min-w-[235px]">
<div className="relative h-[calc(100%-60px)] flex flex-col w-full justify-between pt-[10px] overflow-y-scroll no-scroll">
<div className="flex flex-col gap-y-2 pb-[60px] overflow-y-scroll no-scroll">
<div className="flex gap-x-2 items-center justify-between">
{(!user || user?.role !== "default") && (
<button
onClick={showNewWsModal}
className="light:bg-[#C2E7FE] light:hover:bg-[#7CD4FD] flex flex-grow w-[75%] h-[44px] gap-x-2 py-[5px] px-2.5 mb-2 bg-white rounded-[8px] text-sidebar justify-center items-center hover:bg-opacity-80 transition-all duration-300"
>
<Plus size={18} weight="bold" />
<p className="text-sidebar text-sm font-semibold">
{t("new-workspace.title")}
</p>
</button>
)}
</div>
<ActiveWorkspaces />
</div>
</div>
<div className="absolute bottom-0 left-0 right-0 pt-4 pb-3 rounded-b-[16px] bg-theme-bg-sidebar bg-opacity-80 backdrop-filter backdrop-blur-md z-1">
<Footer />
</div>
</div>
{(!user || user?.role !== "default") && (
<button
onClick={showNewWsModal}
className="light:bg-[#C2E7FE] light:hover:bg-[#7CD4FD] flex w-full h-[44px] gap-x-2 py-[5px] px-2.5 mb-4 bg-white rounded-[8px] text-sidebar justify-center items-center hover:bg-opacity-80 transition-all duration-300"
>
<Plus size={18} weight="bold" />
<p className="text-sidebar text-sm font-semibold">
{t("new-workspace.title")}
</p>
</button>
)}
<div className="flex flex-col gap-y-2 overflow-y-auto no-scroll h-full pb-[80px]">
<ActiveWorkspaces />
</div>
<div className="absolute bottom-0 left-0 right-0 pt-4 pb-3 rounded-b-[16px] bg-theme-bg-sidebar bg-opacity-80 backdrop-filter backdrop-blur-md z-10">
<Footer />
</div>
</div>
{showingNewWsModal && <NewWorkspaceModal hideModal={hideNewWsModal} />}
Expand Down Expand Up @@ -179,15 +171,17 @@ export function SidebarMobileHeader() {
<div className=" flex flex-col gap-y-4 overflow-y-scroll no-scroll pb-[60px]">
<div className="flex gap-x-2 items-center justify-between">
{(!user || user?.role !== "default") && (
<button
onClick={showNewWsModal}
className="flex flex-grow w-[75%] h-[44px] gap-x-2 py-[5px] px-4 bg-white rounded-lg text-sidebar justify-center items-center hover:bg-opacity-80 transition-all duration-300"
>
<Plus className="h-5 w-5" />
<p className="text-sidebar text-sm font-semibold">
{t("new-workspace.title")}
</p>
</button>
<div className="w-full flex justify-between">
<button
onClick={showNewWsModal}
className="flex flex-grow w-[75%] h-[44px] gap-x-2 py-[5px] px-4 bg-white rounded-lg text-sidebar justify-center items-center hover:bg-opacity-80 transition-all duration-300"
>
<Plus className="h-5 w-5" />
<p className="text-sidebar text-sm font-semibold">
{t("new-workspace.title")}
</p>
</button>
</div>
)}
</div>
<ActiveWorkspaces />
Expand Down
49 changes: 33 additions & 16 deletions frontend/src/components/WorkspaceChat/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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;
}
Expand All @@ -41,24 +50,32 @@ export default function WorkspaceChat({ loading, workspace }) {
<>
{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 className="w-full max-w-2xl bg-theme-bg-secondary rounded-lg shadow border-2 border-theme-modal-border overflow-hidden">
<div className="relative p-6 border-b rounded-t border-theme-modal-border">
<div className="w-full flex gap-x-2 items-center">
<WarningCircle
className="text-red-500 w-6 h-6"
weight="fill"
/>
<h3 className="text-xl font-semibold text-red-500 overflow-hidden overflow-ellipsis whitespace-nowrap">
Workspace not found
</h3>
</div>
</div>
<div className="py-7 px-9 space-y-2 flex-col">
<p className="text-white text-sm">
The workspace you&apos;re looking for is not available. It may
have been deleted or you may not have access to it.
</p>
</div>
<div className="flex w-full justify-end items-center p-6 space-x-2 border-t border-theme-modal-border rounded-b">
<a
href={paths.home()}
className="transition-all duration-300 bg-white text-black hover:opacity-60 px-4 py-2 rounded-lg text-sm"
>
Return to homepage
</a>
</div>
</div>
</ModalWrapper>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -28,6 +29,8 @@ export default function DeleteWorkspace({ workspace }) {
return;
}

clearLastActive();

workspace.slug === slug
? (window.location = paths.home())
: window.location.reload();
Expand Down
24 changes: 24 additions & 0 deletions frontend/src/utils/lastActive.js
Original file line number Diff line number Diff line change
@@ -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);
};
9 changes: 9 additions & 0 deletions frontend/src/utils/paths.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { API_BASE } from "./constants";
import { getLastActive } from "./lastActive";

function applyOptions(path, options = {}) {
let updatedPath = path;
Expand All @@ -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" : ""}`;
},
Expand Down