cognee/cognee-frontend/src/app/dashboard/Dashboard.tsx
Boris f567098743
fix: UI fixes (#1435)
<!-- .github/pull_request_template.md -->

## Description
<!-- 
Please provide a clear, human-generated description of the changes in
this PR.
DO NOT use AI-generated descriptions. We want to understand your thought
process and reasoning.
-->

## Type of Change
<!-- Please check the relevant option -->
- [x] Bug fix (non-breaking change that fixes an issue)
- [x] New feature (non-breaking change that adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] Documentation update
- [ ] Code refactoring
- [ ] Performance improvement
- [ ] Other (please specify):

## Changes Made
<!-- List the specific changes made in this PR -->
- 
- 
- 

## Testing
<!-- Describe how you tested your changes -->

## Screenshots/Videos (if applicable)
<!-- Add screenshots or videos to help explain your changes -->

## Pre-submission Checklist
<!-- Please check all boxes that apply before submitting your PR -->
- [ ] **I have tested my changes thoroughly before submitting this PR**
- [ ] **This PR contains minimal changes necessary to address the
issue/feature**
- [ ] My code follows the project's coding standards and style
guidelines
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] I have added necessary documentation (if applicable)
- [ ] All new and existing tests pass
- [ ] I have searched existing PRs to ensure this change hasn't been
submitted already
- [ ] I have linked any relevant issues in the description
- [ ] My commits have clear and descriptive messages

## Related Issues
<!-- Link any related issues using "Fixes #issue_number" or "Relates to
#issue_number" -->

## Additional Notes
<!-- Add any additional notes, concerns, or context for reviewers -->

## DCO Affirmation
I affirm that all code in every commit of this pull request conforms to
the terms of the Topoteretes Developer Certificate of Origin.
2025-09-18 13:53:27 +02:00

176 lines
5.5 KiB
TypeScript

"use client";
import { useCallback, useEffect, useRef, useState } from "react";
import { Header } from "@/ui/Layout";
import { SearchIcon } from "@/ui/Icons";
import { CTAButton, Notebook } from "@/ui/elements";
import { fetch, isCloudEnvironment } from "@/utils";
import { Notebook as NotebookType } from "@/ui/elements/Notebook/types";
import { useAuthenticatedUser } from "@/modules/auth";
import { Dataset } from "@/modules/ingestion/useDatasets";
import useNotebooks from "@/modules/notebooks/useNotebooks";
import AddDataToCognee from "./AddDataToCognee";
import NotebooksAccordion from "./NotebooksAccordion";
import CogneeInstancesAccordion from "./CogneeInstancesAccordion";
import InstanceDatasetsAccordion from "./InstanceDatasetsAccordion";
interface DashboardProps {
user?: {
id: string;
name: string;
email: string;
picture: string;
};
accessToken: string;
}
export default function Dashboard({ accessToken }: DashboardProps) {
fetch.setAccessToken(accessToken);
const { user } = useAuthenticatedUser();
const {
notebooks,
refreshNotebooks,
runCell,
addNotebook,
updateNotebook,
saveNotebook,
removeNotebook,
} = useNotebooks();
useEffect(() => {
if (!notebooks.length) {
refreshNotebooks()
.then((notebooks) => {
if (notebooks[0]) {
setSelectedNotebookId(notebooks[0].id);
}
});
}
}, [notebooks.length, refreshNotebooks]);
const [selectedNotebookId, setSelectedNotebookId] = useState<string | null>(null);
const handleNotebookRemove = useCallback((notebookId: string) => {
return removeNotebook(notebookId)
.then(() => {
setSelectedNotebookId((currentSelectedNotebookId) => (
currentSelectedNotebookId === notebookId ? null : currentSelectedNotebookId
));
});
}, [removeNotebook]);
const saveNotebookTimeoutRef = useRef<number | null>(null);
const saveNotebookThrottled = useCallback((notebook: NotebookType) => {
const throttleTime = 1000;
if (saveNotebookTimeoutRef.current) {
clearTimeout(saveNotebookTimeoutRef.current);
saveNotebookTimeoutRef.current = null;
}
saveNotebookTimeoutRef.current = setTimeout(() => {
saveNotebook(notebook);
}, throttleTime) as unknown as number;
}, [saveNotebook]);
useEffect(() => {
return () => {
if (saveNotebookTimeoutRef.current) {
clearTimeout(saveNotebookTimeoutRef.current);
saveNotebookTimeoutRef.current = null;
}
};
}, []);
const handleNotebookUpdate = useCallback((notebook: NotebookType) => {
updateNotebook(notebook);
saveNotebookThrottled(notebook);
}, [saveNotebookThrottled, updateNotebook]);
const selectedNotebook = notebooks.find((notebook) => notebook.id === selectedNotebookId);
// ############################
// Datasets logic
const [datasets, setDatasets] = useState<Dataset[]>([]);
const refreshDatasetsRef = useRef(() => {});
const handleDatasetsChange = useCallback((payload: { datasets: Dataset[], refreshDatasets: () => void }) => {
const {
datasets,
refreshDatasets,
} = payload;
refreshDatasetsRef.current = refreshDatasets;
setDatasets(datasets);
}, []);
const isCloudEnv = isCloudEnvironment();
return (
<div className="h-full flex flex-col">
{/* <video
autoPlay
loop
muted
playsInline
className="fixed inset-0 z-0 object-cover w-full h-full"
>
<source src="/videos/background-video-blur.mp4" type="video/mp4" />
Your browser does not support the video tag.
</video> */}
<Header user={user} />
<div className="relative flex-1 flex flex-row gap-2.5 items-start w-full max-w-[1920px] max-h-[calc(100% - 3.5rem)] overflow-hidden mx-auto px-2.5 pb-2.5">
<div className="px-5 py-4 lg:w-96 bg-white rounded-xl h-[calc(100%-2.75rem)]">
<div className="relative mb-2">
<label htmlFor="search-input"><SearchIcon className="absolute left-3 top-[10px] cursor-text" /></label>
<input id="search-input" className="text-xs leading-3 w-full h-8 flex flex-row items-center gap-2.5 rounded-3xl pl-9 placeholder-gray-300 border-gray-300 border-[1px] focus:outline-indigo-600" placeholder="Search datasets..." />
</div>
<AddDataToCognee
datasets={datasets}
refreshDatasets={refreshDatasetsRef.current}
useCloud={isCloudEnv}
/>
<NotebooksAccordion
notebooks={notebooks}
addNotebook={addNotebook}
removeNotebook={handleNotebookRemove}
openNotebook={setSelectedNotebookId}
/>
<div className="mt-7 mb-14">
<CogneeInstancesAccordion>
<InstanceDatasetsAccordion
onDatasetsChange={handleDatasetsChange}
/>
</CogneeInstancesAccordion>
</div>
<div className="fixed bottom-2.5 w-[calc(min(1920px,100%)/5)] lg:w-96 ml-[-1.25rem] mx-auto">
<a href="/plan">
<CTAButton className="w-full">Select a plan</CTAButton>
</a>
</div>
</div>
<div className="flex-1 flex flex-col justify-between h-full overflow-y-auto">
{selectedNotebook && (
<Notebook
key={selectedNotebook.id}
notebook={selectedNotebook}
updateNotebook={handleNotebookUpdate}
runCell={runCell}
/>
)}
</div>
</div>
</div>
);
}