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.
This commit is contained in:
parent
6f60ac76fd
commit
f567098743
15 changed files with 311 additions and 216 deletions
|
|
@ -13,8 +13,8 @@ export default function Account() {
|
|||
};
|
||||
|
||||
return (
|
||||
<div className="bg-gray-200 h-full max-w-[1920px] mx-auto">
|
||||
<video
|
||||
<div className="h-full max-w-[1920px] mx-auto">
|
||||
{/* <video
|
||||
autoPlay
|
||||
loop
|
||||
muted
|
||||
|
|
@ -23,9 +23,9 @@ export default function Account() {
|
|||
>
|
||||
<source src="/videos/background-video-blur.mp4" type="video/mp4" />
|
||||
Your browser does not support the video tag.
|
||||
</video>
|
||||
</video> */}
|
||||
|
||||
<Header />
|
||||
<Header user={user} />
|
||||
|
||||
<div className="relative flex flex-row items-start gap-2.5">
|
||||
<Link href="/dashboard" className="flex-1/5 py-4 px-5 flex flex-row items-center gap-5">
|
||||
|
|
@ -42,7 +42,7 @@ export default function Account() {
|
|||
<div>Plan</div>
|
||||
<div className="text-sm text-gray-400 mb-8">You are using open-source version. Subscribe to get access to hosted cognee with your data!</div>
|
||||
<Link href="/plan">
|
||||
<CTAButton><span className="">Select a plan</span></CTAButton>
|
||||
<CTAButton className="w-full"><span className="">Select a plan</span></CTAButton>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { FormEvent, useCallback, useState } from "react";
|
|||
|
||||
import { LoadingIndicator } from "@/ui/App";
|
||||
import { useModal } from "@/ui/elements/Modal";
|
||||
import { CloseIcon, PlusIcon } from "@/ui/Icons";
|
||||
import { CloseIcon, MinusIcon, PlusIcon } from "@/ui/Icons";
|
||||
import { CTAButton, GhostButton, IconButton, Modal, NeutralButton, Select } from "@/ui/elements";
|
||||
|
||||
import addData from "@/modules/ingestion/addData";
|
||||
|
|
@ -16,16 +16,22 @@ interface AddDataToCogneeProps {
|
|||
}
|
||||
|
||||
export default function AddDataToCognee({ datasets, refreshDatasets, useCloud = false }: AddDataToCogneeProps) {
|
||||
const [filesForUpload, setFilesForUpload] = useState<FileList | null>(null);
|
||||
const [filesForUpload, setFilesForUpload] = useState<File[]>([]);
|
||||
|
||||
const prepareFiles = useCallback((event: FormEvent<HTMLInputElement>) => {
|
||||
const addFiles = useCallback((event: FormEvent<HTMLInputElement>) => {
|
||||
const formElements = event.currentTarget;
|
||||
const files = formElements.files;
|
||||
const newFiles = formElements.files;
|
||||
|
||||
setFilesForUpload(files);
|
||||
if (newFiles?.length) {
|
||||
setFilesForUpload((oldFiles) => [...oldFiles, ...Array.from(newFiles)]);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const processDataWithCognee = useCallback((state: object, event?: FormEvent<HTMLFormElement>) => {
|
||||
const removeFile = useCallback((file: File) => {
|
||||
setFilesForUpload((oldFiles) => oldFiles.filter((f) => f !== file));
|
||||
}, []);
|
||||
|
||||
const processDataWithCognee = useCallback((state?: object, event?: FormEvent<HTMLFormElement>) => {
|
||||
event!.preventDefault();
|
||||
|
||||
if (!filesForUpload) {
|
||||
|
|
@ -41,7 +47,7 @@ export default function AddDataToCognee({ datasets, refreshDatasets, useCloud =
|
|||
} : {
|
||||
name: "main_dataset",
|
||||
},
|
||||
Array.from(filesForUpload),
|
||||
filesForUpload,
|
||||
useCloud
|
||||
)
|
||||
.then(({ dataset_id, dataset_name }) => {
|
||||
|
|
@ -57,7 +63,7 @@ export default function AddDataToCognee({ datasets, refreshDatasets, useCloud =
|
|||
useCloud,
|
||||
)
|
||||
.then(() => {
|
||||
setFilesForUpload(null);
|
||||
setFilesForUpload([]);
|
||||
});
|
||||
});
|
||||
}, [filesForUpload, refreshDatasets, useCloud]);
|
||||
|
|
@ -86,24 +92,25 @@ export default function AddDataToCognee({ datasets, refreshDatasets, useCloud =
|
|||
<div className="mt-8 mb-6">Please select a {useCloud ? "cloud" : "local"} dataset to add data in.<br/> If you don't have any, don't worry, we will create one for you.</div>
|
||||
<form onSubmit={submitDataToCognee}>
|
||||
<div className="max-w-md flex flex-col gap-4">
|
||||
<Select name="datasetName">
|
||||
<Select defaultValue={datasets.length ? datasets[0].id : ""} name="datasetName">
|
||||
{!datasets.length && <option value="">main_dataset</option>}
|
||||
{datasets.map((dataset: Dataset, index) => (
|
||||
<option selected={index===0} key={dataset.id} value={dataset.id}>{dataset.name}</option>
|
||||
{datasets.map((dataset: Dataset) => (
|
||||
<option key={dataset.id} value={dataset.id}>{dataset.name}</option>
|
||||
))}
|
||||
</Select>
|
||||
|
||||
<NeutralButton className="w-full relative justify-start pl-4">
|
||||
<input onChange={prepareFiles} required name="files" tabIndex={-1} type="file" multiple className="absolute w-full h-full cursor-pointer opacity-0" />
|
||||
<input onChange={addFiles} required name="files" tabIndex={-1} type="file" multiple className="absolute w-full h-full cursor-pointer opacity-0" />
|
||||
<span>select files</span>
|
||||
</NeutralButton>
|
||||
|
||||
{filesForUpload?.length && (
|
||||
{!!filesForUpload.length && (
|
||||
<div className="pt-4 mt-4 border-t-1 border-t-gray-100">
|
||||
<div className="mb-1.5">selected files:</div>
|
||||
{Array.from(filesForUpload || []).map((file) => (
|
||||
<div key={file.name} className="py-1.5 pl-2">
|
||||
{filesForUpload.map((file) => (
|
||||
<div key={file.name} className="py-1.5 pl-2 flex flex-row items-center justify-between w-full">
|
||||
<span className="text-sm">{file.name}</span>
|
||||
<IconButton onClick={removeFile.bind(null, file)}><MinusIcon /></IconButton>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { useCallback, useEffect, useRef, useState } from "react";
|
|||
|
||||
import { Header } from "@/ui/Layout";
|
||||
import { SearchIcon } from "@/ui/Icons";
|
||||
import { Notebook } from "@/ui/elements";
|
||||
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";
|
||||
|
|
@ -111,8 +111,8 @@ export default function Dashboard({ accessToken }: DashboardProps) {
|
|||
const isCloudEnv = isCloudEnvironment();
|
||||
|
||||
return (
|
||||
<div className="h-full flex flex-col bg-gray-200">
|
||||
<video
|
||||
<div className="h-full flex flex-col">
|
||||
{/* <video
|
||||
autoPlay
|
||||
loop
|
||||
muted
|
||||
|
|
@ -121,12 +121,12 @@ export default function Dashboard({ accessToken }: DashboardProps) {
|
|||
>
|
||||
<source src="/videos/background-video-blur.mp4" type="video/mp4" />
|
||||
Your browser does not support the video tag.
|
||||
</video>
|
||||
</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 py-2.5">
|
||||
<div className="px-5 py-4 lg:w-96 bg-white rounded-xl min-h-full">
|
||||
<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..." />
|
||||
|
|
@ -152,6 +152,12 @@ export default function Dashboard({ accessToken }: DashboardProps) {
|
|||
/>
|
||||
</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">
|
||||
|
|
|
|||
|
|
@ -36,7 +36,8 @@ export default function InstanceDatasetsAccordion({ onDatasetsChange }: Instance
|
|||
};
|
||||
|
||||
checkConnectionToLocalCognee();
|
||||
}, [setCloudCogneeConnected, setLocalCogneeConnected]);
|
||||
checkConnectionToCloudCognee();
|
||||
}, [checkConnectionToCloudCognee, setCloudCogneeConnected, setLocalCogneeConnected]);
|
||||
|
||||
const {
|
||||
value: isCloudConnectedModalOpen,
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ import { useBoolean } from "@/utils";
|
|||
import { Accordion, CTAButton, GhostButton, IconButton, Input, Modal } from "@/ui/elements";
|
||||
import { CloseIcon, MinusIcon, NotebookIcon, PlusIcon } from "@/ui/Icons";
|
||||
import { Notebook } from "@/ui/elements/Notebook/types";
|
||||
import { LoadingIndicator } from "@/ui/App";
|
||||
import { useModal } from "@/ui/elements/Modal";
|
||||
import { LoadingIndicator } from "@/ui/App";
|
||||
|
||||
interface NotebooksAccordionProps {
|
||||
notebooks: Notebook[];
|
||||
|
|
@ -60,7 +60,7 @@ export default function NotebooksAccordion({
|
|||
.finally(() => setNotebookToRemove(null));
|
||||
};
|
||||
|
||||
const handleNotebookAdd = useCallback((_: object, formEvent?: FormEvent<HTMLFormElement>) => {
|
||||
const handleNotebookAdd = useCallback((_: Notebook, formEvent?: FormEvent<HTMLFormElement>) => {
|
||||
if (!formEvent) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -71,6 +71,7 @@ export default function NotebooksAccordion({
|
|||
const notebookName = formElements.notebookName.value.trim();
|
||||
|
||||
return addNotebook(notebookName)
|
||||
.then(() => {});
|
||||
}, [addNotebook]);
|
||||
|
||||
const {
|
||||
|
|
@ -79,7 +80,7 @@ export default function NotebooksAccordion({
|
|||
closeModal: closeNewNotebookModal,
|
||||
confirmAction: handleNewNotebookSubmit,
|
||||
isActionLoading: isNewDatasetLoading,
|
||||
} = useModal<Notebook | void>(false, handleNotebookAdd);
|
||||
} = useModal<Notebook>(false, handleNotebookAdd);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
@ -91,7 +92,7 @@ export default function NotebooksAccordion({
|
|||
tools={isNewDatasetLoading ? (
|
||||
<LoadingIndicator />
|
||||
) : (
|
||||
<IconButton onClick={openNewNotebookModal}><PlusIcon /></IconButton>
|
||||
<IconButton onClick={() => openNewNotebookModal()}><PlusIcon /></IconButton>
|
||||
)}
|
||||
>
|
||||
{notebooks.length === 0 && (
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
--global-color-primary-active: #500cc5 !important;
|
||||
--global-color-primary-text: white !important;
|
||||
--global-color-secondary: #0DFF00 !important;
|
||||
--global-background-default: #0D051C;
|
||||
--global-background-default: #F4F4F4;
|
||||
--textarea-default-color: #0D051C !important;
|
||||
}
|
||||
|
||||
|
|
@ -20,6 +20,7 @@ body {
|
|||
height: 100%;
|
||||
max-width: 100vw;
|
||||
overflow-x: hidden;
|
||||
background-color: var(--global-background-default);
|
||||
}
|
||||
|
||||
a {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,17 @@
|
|||
"use client";
|
||||
|
||||
import Link from "next/link";
|
||||
import { BackIcon, CheckIcon } from "@/ui/Icons";
|
||||
import { CTAButton, NeutralButton } from "@/ui/elements";
|
||||
import Header from "@/ui/Layout/Header";
|
||||
import { useAuthenticatedUser } from "@/modules/auth";
|
||||
|
||||
export default function Plan() {
|
||||
const { user } = useAuthenticatedUser();
|
||||
|
||||
return (
|
||||
<div className="bg-gray-200 h-full max-w-[1920px] mx-auto">
|
||||
<video
|
||||
<div className="h-full max-w-[1920px] mx-auto">
|
||||
{/* <video
|
||||
autoPlay
|
||||
loop
|
||||
muted
|
||||
|
|
@ -15,88 +20,104 @@ export default function Plan() {
|
|||
>
|
||||
<source src="/videos/background-video-blur.mp4" type="video/mp4" />
|
||||
Your browser does not support the video tag.
|
||||
</video>
|
||||
</video> */}
|
||||
|
||||
<Header />
|
||||
<Header user={user} />
|
||||
|
||||
<div className="relative flex flex-row items-start justify-stretch gap-2.5">
|
||||
<div className="flex-1/5 h-full">
|
||||
<Link href="/dashboard" className="py-4 px-5 flex flex-row items-center gap-5">
|
||||
<BackIcon />
|
||||
<span>back</span>
|
||||
</Link>
|
||||
<div className="flex flex-col justify-between">
|
||||
<Link href="/dashboard" className="py-4 px-5 flex flex-row items-center gap-5">
|
||||
<BackIcon />
|
||||
<span>back</span>
|
||||
</Link>
|
||||
|
||||
{/* <div className="fixed bottom-6 w-[calc(min(1920px,100%)/5)] mx-auto">
|
||||
<div className="text-sm mb-2"></div>
|
||||
<a href="/plan">
|
||||
<CTAButton className="w-full">Select a plan</CTAButton>
|
||||
</a>
|
||||
</div> */}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex-3/5">
|
||||
<div className="bg-[rgba(255,255,255,0.7)] rounded-xl px-5 py-4 mb-2">
|
||||
<div className="bg-white rounded-xl px-5 py-5 mb-2">
|
||||
Affordable and transparent pricing
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-3 gap-x-2.5">
|
||||
<div className="pt-13 py-4 px-5 mb-2.5 rounded-tl-xl rounded-tr-xl bg-[rgba(255,255,255,0.7)] h-full">
|
||||
<div className="pt-13 py-4 px-5 mb-2.5 rounded-tl-xl rounded-tr-xl bg-white h-full">
|
||||
<div>Basic</div>
|
||||
<div className="text-3xl mb-4 font-bold">Free</div>
|
||||
<div className="text-[1.75rem] mb-4 font-bold">Free</div>
|
||||
</div>
|
||||
|
||||
<div className="pt-13 py-4 px-5 mb-2.5 rounded-tl-xl rounded-tr-xl bg-[rgba(255,255,255,0.7)] h-full">
|
||||
<div className="pt-5 py-4 px-5 mb-2.5 rounded-tl-xl rounded-tr-xl bg-white h-full border-indigo-600 border-1 border-b-0">
|
||||
<div className="text-indigo-600 mb-5 text-xs font-black">Most Popular</div>
|
||||
<div>On-prem Subscription</div>
|
||||
<div className="mb-4"><span className="text-3xl font-bold">$2470</span><span className="text-gray-400"> /per month</span></div>
|
||||
<div className="mb-9"><span className="font-bold">Save 20% </span>yearly</div>
|
||||
<div className="mb-2"><span className="text-[1.75rem] font-bold">$2470</span><span className="text-gray-400"> /per month</span></div>
|
||||
<div className=""><span className="font-black">Save 20% </span>yearly</div>
|
||||
</div>
|
||||
|
||||
<div className="pt-13 py-4 px-5 mb-2.5 rounded-tl-xl rounded-tr-xl bg-[rgba(255,255,255,0.7)] h-full">
|
||||
<div className="pt-13 py-4 px-5 mb-2.5 rounded-tl-xl rounded-tr-xl bg-white h-full">
|
||||
<div>Cloud Subscription</div>
|
||||
<div className="mb-4"><span className="text-3xl font-bold">$25</span><span className="text-gray-400"> /per month</span></div>
|
||||
<div className="mb-9 text-gray-400">(beta pricing)</div>
|
||||
<div className="mb-2"><span className="text-[1.75rem] font-bold">$25</span><span className="text-gray-400"> /per month</span></div>
|
||||
<div className=" text-gray-400">(beta pricing)</div>
|
||||
</div>
|
||||
|
||||
<div className="bg-[rgba(255,255,255,0.7)] rounded-bl-xl rounded-br-xl h-full py-4 px-5">
|
||||
<div className="mb-1 invisible">Everything in the free plan, plus...</div>
|
||||
<div className="bg-white rounded-bl-xl rounded-br-xl h-full py-4 px-5">
|
||||
<div className="mb-2 invisible">Everything in the free plan, plus...</div>
|
||||
<div className="flex flex-col gap-3 mb-28">
|
||||
<div className="flex flex-row gap-2"><CheckIcon className="mt-1 shrink-0" />License to use Cognee open source</div>
|
||||
<div className="flex flex-row gap-2"><CheckIcon className="mt-1 shrink-0" />Cognee tasks and pipelines</div>
|
||||
<div className="flex flex-row gap-2"><CheckIcon className="mt-1 shrink-0" />Custom schema and ontology generation</div>
|
||||
<div className="flex flex-row gap-2"><CheckIcon className="mt-1 shrink-0" />Integrated evaluations</div>
|
||||
<div className="flex flex-row gap-2"><CheckIcon className="mt-1 shrink-0" />More than 28 data sources supported</div>
|
||||
<div className="flex flex-row gap-2 leading-5"><CheckIcon className="mt-1 shrink-0" />License to use Cognee open source</div>
|
||||
<div className="flex flex-row gap-2 leading-5"><CheckIcon className="mt-1 shrink-0" />Cognee tasks and pipelines</div>
|
||||
<div className="flex flex-row gap-2 leading-5"><CheckIcon className="mt-1 shrink-0" />Custom schema and ontology generation</div>
|
||||
<div className="flex flex-row gap-2 leading-5"><CheckIcon className="mt-1 shrink-0" />Integrated evaluations</div>
|
||||
<div className="flex flex-row gap-2 leading-5"><CheckIcon className="mt-1 shrink-0" />More than 28 data sources supported</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="bg-[rgba(255,255,255,0.7)] rounded-bl-xl rounded-br-xl h-full py-4 px-5">
|
||||
<div className="mb-1 text-gray-400">Everything in the free plan, plus...</div>
|
||||
<div className="flex flex-col gap-3 mb-10">
|
||||
<div className="flex flex-row gap-2"><CheckIcon className="mt-1 shrink-0" />License to use Cognee open source and Cognee Platform</div>
|
||||
<div className="flex flex-row gap-2"><CheckIcon className="mt-1 shrink-0" />1 day SLA</div>
|
||||
<div className="flex flex-row gap-2"><CheckIcon className="mt-1 shrink-0" />On-prem deployment</div>
|
||||
<div className="flex flex-row gap-2"><CheckIcon className="mt-1 shrink-0" />Hands-on support</div>
|
||||
<div className="flex flex-row gap-2"><CheckIcon className="mt-1 shrink-0" />Architecture review</div>
|
||||
<div className="flex flex-row gap-2"><CheckIcon className="mt-1 shrink-0" />Roadmap prioritization</div>
|
||||
<div className="flex flex-row gap-2"><CheckIcon className="mt-1 shrink-0" />Knowledge transfer</div>
|
||||
<div className="bg-white rounded-bl-xl rounded-br-xl border-indigo-600 border-1 border-t-0 h-full py-4 px-5">
|
||||
<div className="mb-2 text-gray-400">Everything in the free plan, plus...</div>
|
||||
<div className="flex flex-col gap-3 mb-4">
|
||||
<div className="flex flex-row gap-2 leading-5"><CheckIcon className="mt-1 shrink-0" />License to use Cognee open source and Cognee Platform</div>
|
||||
<div className="flex flex-row gap-2 leading-5"><CheckIcon className="mt-1 shrink-0" />1 day SLA</div>
|
||||
<div className="flex flex-row gap-2 leading-5"><CheckIcon className="mt-1 shrink-0" />On-prem deployment</div>
|
||||
<div className="flex flex-row gap-2 leading-5"><CheckIcon className="mt-1 shrink-0" />Hands-on support</div>
|
||||
<div className="flex flex-row gap-2 leading-5"><CheckIcon className="mt-1 shrink-0" />Architecture review</div>
|
||||
<div className="flex flex-row gap-2 leading-5"><CheckIcon className="mt-1 shrink-0" />Roadmap prioritization</div>
|
||||
<div className="flex flex-row gap-2 leading-5"><CheckIcon className="mt-1 shrink-0" />Knowledge transfer</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="bg-[rgba(255,255,255,0.7)] rounded-bl-xl rounded-br-xl h-full py-4 px-5">
|
||||
<div className="mb-1 text-gray-400">Everything in the free plan, plus...</div>
|
||||
<div className="flex flex-col gap-3 mb-10">
|
||||
<div className="flex flex-row gap-2"><CheckIcon className="mt-1 shrink-0" />Fully hosted cloud platform</div>
|
||||
<div className="flex flex-row gap-2"><CheckIcon className="mt-1 shrink-0" />Multi-tenant architecture</div>
|
||||
<div className="flex flex-row gap-2"><CheckIcon className="mt-1 shrink-0" />Comprehensive API endpoints</div>
|
||||
<div className="flex flex-row gap-2"><CheckIcon className="mt-1 shrink-0" />Automated scaling and parallel processing</div>
|
||||
<div className="flex flex-row gap-2"><CheckIcon className="mt-1 shrink-0" />Ability to group memories per user and domain</div>
|
||||
<div className="flex flex-row gap-2"><CheckIcon className="mt-1 shrink-0" />Automatic updates and priority support</div>
|
||||
<div className="flex flex-row gap-2"><CheckIcon className="mt-1 shrink-0" />1 GB ingestion + 10,000 API calls</div>
|
||||
<div className="bg-white rounded-bl-xl rounded-br-xl h-full py-4 px-5">
|
||||
<div className="mb-2 text-gray-400">Everything in the free plan, plus...</div>
|
||||
<div className="flex flex-col gap-3 mb-4">
|
||||
<div className="flex flex-row gap-2 leading-5"><CheckIcon className="mt-1 shrink-0" />Fully hosted cloud platform</div>
|
||||
<div className="flex flex-row gap-2 leading-5"><CheckIcon className="mt-1 shrink-0" />Multi-tenant architecture</div>
|
||||
<div className="flex flex-row gap-2 leading-5"><CheckIcon className="mt-1 shrink-0" />Comprehensive API endpoints</div>
|
||||
<div className="flex flex-row gap-2 leading-5"><CheckIcon className="mt-1 shrink-0" />Automated scaling and parallel processing</div>
|
||||
<div className="flex flex-row gap-2 leading-5"><CheckIcon className="mt-1 shrink-0" />Ability to group memories per user and domain</div>
|
||||
<div className="flex flex-row gap-2 leading-5"><CheckIcon className="mt-1 shrink-0" />Automatic updates and priority support</div>
|
||||
<div className="flex flex-row gap-2 leading-5"><CheckIcon className="mt-1 shrink-0" />1 GB ingestion + 10,000 API calls</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="pt-4 pb-14 mb-2.5">
|
||||
<NeutralButton className="w-full">Try for free</NeutralButton>
|
||||
<a href="https://www.github.com/topoteretes/cognee" target="_blank">
|
||||
<NeutralButton className="w-full">Try for free</NeutralButton>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div className="pt-4 pb-14 mb-2.5">
|
||||
<CTAButton className="w-full">Talk to us</CTAButton>
|
||||
<a href="https://www.cognee.ai/contact-us" target="_blank">
|
||||
<CTAButton className="w-full">Talk to us</CTAButton>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div className="pt-4 pb-14 mb-2.5">
|
||||
<NeutralButton className="w-full">Sign up for Cogwit Beta</NeutralButton>
|
||||
<a href="https://platform.cognee.ai" target="_blank">
|
||||
<NeutralButton className="w-full">Sign up for Cogwit Beta</NeutralButton>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -106,7 +127,7 @@ export default function Plan() {
|
|||
<div className="text-center">On-prem</div>
|
||||
<div className="text-center">Cloud</div>
|
||||
</div>
|
||||
<div className="grid grid-cols-4 py-1 px-5 mb-12 bg-[rgba(255,255,255,0.7)] rounded-xl">
|
||||
<div className="grid grid-cols-4 py-1 px-5 mb-12 bg-white rounded-xl leading-[1]">
|
||||
<div className="border-b-[1px] border-b-gray-100 py-3">Data Sources</div>
|
||||
<div className="text-center border-b-[1px] border-b-gray-100 py-3">28+</div>
|
||||
<div className="text-center border-b-[1px] border-b-gray-100 py-3">28+</div>
|
||||
|
|
@ -134,19 +155,19 @@ export default function Plan() {
|
|||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-x-2.5 gap-y-2.5 mb-12">
|
||||
<div className="bg-[rgba(255,255,255,0.5)] py-4 px-5 rounded-xl">
|
||||
<div className="bg-white py-4 px-5 rounded-xl">
|
||||
<div>Can I change my plan anytime?</div>
|
||||
<div className="text-gray-500 mt-6">Yes, you can upgrade or downgrade your plan at any time. Changes take effect immediately.</div>
|
||||
</div>
|
||||
<div className="bg-[rgba(255,255,255,0.5)] py-4 px-5 rounded-xl">
|
||||
<div className="bg-white py-4 px-5 rounded-xl">
|
||||
<div>What happens to my data if I downgrade?</div>
|
||||
<div className="text-gray-500 mt-6">Your data is preserved, but features may be limited based on your new plan constraints.</div>
|
||||
</div>
|
||||
<div className="bg-[rgba(255,255,255,0.5)] py-4 px-5 rounded-xl">
|
||||
<div className="bg-white py-4 px-5 rounded-xl">
|
||||
<div>Do you offer educational discounts?</div>
|
||||
<div className="text-gray-500 mt-6">Yes, we offer special pricing for educational institutions and students. Contact us for details.</div>
|
||||
</div>
|
||||
<div className="bg-[rgba(255,255,255,0.5)] py-4 px-5 rounded-xl">
|
||||
<div className="bg-white py-4 px-5 rounded-xl">
|
||||
<div>Is there a free trial for paid plans?</div>
|
||||
<div className="text-gray-500 mt-6">All new accounts start with a 14-day free trial of our Pro plan features.</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -32,20 +32,21 @@ export default function Header({ user }: HeaderProps) {
|
|||
|
||||
return (
|
||||
<>
|
||||
<header className="relative bg-[rgba(244,244,244,0.3)] flex flex-row h-14 min-h-14 px-5 items-center justify-between w-full max-w-[1920px] mx-auto">
|
||||
<header className="relative flex flex-row h-14 min-h-14 px-5 items-center justify-between w-full max-w-[1920px] mx-auto">
|
||||
<div className="flex flex-row gap-4 items-center">
|
||||
<CogneeIcon />
|
||||
<div className="text-lg">Cognee Local</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-row items-center gap-2.5">
|
||||
<GhostButton onClick={openSyncModal} className="text-indigo-700 gap-3 pl-4 pr-4">
|
||||
<GhostButton onClick={openSyncModal} className="text-indigo-600 gap-3 pl-4 pr-4">
|
||||
<CloudIcon />
|
||||
<div>Sync</div>
|
||||
</GhostButton>
|
||||
<a href="/plan">
|
||||
<GhostButton className="text-indigo-700 pl-4 pr-4">Premium</GhostButton>
|
||||
<a href="/plan" className="!text-indigo-600 pl-4 pr-4">
|
||||
Premium
|
||||
</a>
|
||||
<a href="https://platform.cognee.ai" className="!text-indigo-600 pl-4 pr-4">API keys</a>
|
||||
{/* <div className="px-2 py-2 mr-3">
|
||||
<SettingsIcon />
|
||||
</div> */}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import classNames from "classnames";
|
||||
import { ButtonHTMLAttributes } from "react";
|
||||
|
||||
export default function CTAButton({ children, className, ...props }: ButtonHTMLAttributes<HTMLButtonElement>) {
|
||||
export default function GhostButton({ children, className, ...props }: ButtonHTMLAttributes<HTMLButtonElement>) {
|
||||
return (
|
||||
<button className={classNames("flex flex-row justify-center items-center gap-2 cursor-pointer rounded-3xl bg-transparent px-10 h-8 text-black hover:bg-gray-200 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600", className)} {...props}>{children}</button>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { FormEvent, useCallback, useState } from "react";
|
||||
import { useBoolean } from "@/utils";
|
||||
|
||||
export default function useModal<ConfirmActionReturnType = void>(initiallyOpen?: boolean, confirmCallback?: (state: object, event?: FormEvent<HTMLFormElement>) => Promise<ConfirmActionReturnType> | ConfirmActionReturnType) {
|
||||
const [modalState, setModalState] = useState<object>({});
|
||||
export default function useModal<ModalState extends object, ConfirmActionEvent = FormEvent<HTMLFormElement>>(initiallyOpen?: boolean, confirmCallback?: (state: ModalState, event?: ConfirmActionEvent) => Promise<void> | void) {
|
||||
const [modalState, setModalState] = useState<ModalState>();
|
||||
const [isActionLoading, setLoading] = useState(false);
|
||||
|
||||
const {
|
||||
|
|
@ -11,7 +11,7 @@ export default function useModal<ConfirmActionReturnType = void>(initiallyOpen?:
|
|||
setFalse: closeModalInternal,
|
||||
} = useBoolean(initiallyOpen || false);
|
||||
|
||||
const openModal = useCallback((state?: object) => {
|
||||
const openModal = useCallback((state?: ModalState) => {
|
||||
if (state) {
|
||||
setModalState(state);
|
||||
}
|
||||
|
|
@ -20,20 +20,21 @@ export default function useModal<ConfirmActionReturnType = void>(initiallyOpen?:
|
|||
|
||||
const closeModal = useCallback(() => {
|
||||
closeModalInternal();
|
||||
setModalState({});
|
||||
setModalState({} as ModalState);
|
||||
}, [closeModalInternal]);
|
||||
|
||||
const confirmAction = useCallback((event?: FormEvent<HTMLFormElement>) => {
|
||||
const confirmAction = useCallback((event?: ConfirmActionEvent) => {
|
||||
if (confirmCallback) {
|
||||
setLoading(true);
|
||||
|
||||
const maybePromise = confirmCallback(modalState, event);
|
||||
const maybePromise = confirmCallback(modalState as ModalState, event);
|
||||
|
||||
if (maybePromise instanceof Promise) {
|
||||
return maybePromise
|
||||
.finally(closeModal)
|
||||
.finally(() => setLoading(false));
|
||||
} else {
|
||||
closeModal();
|
||||
return maybePromise; // Not a promise.
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,10 +2,11 @@
|
|||
|
||||
import { v4 as uuid4 } from "uuid";
|
||||
import classNames from "classnames";
|
||||
import { Fragment, MutableRefObject, useCallback, useEffect, useRef, useState } from "react";
|
||||
import { Fragment, MouseEvent, MutableRefObject, useCallback, useEffect, useRef, useState } from "react";
|
||||
|
||||
import { CaretIcon, PlusIcon } from "@/ui/Icons";
|
||||
import { IconButton, PopupMenu, TextArea } from "@/ui/elements";
|
||||
import { useModal } from "@/ui/elements/Modal";
|
||||
import { CaretIcon, CloseIcon, PlusIcon } from "@/ui/Icons";
|
||||
import { IconButton, PopupMenu, TextArea, Modal, GhostButton, CTAButton } from "@/ui/elements";
|
||||
import { GraphControlsAPI } from "@/app/(graph)/GraphControls";
|
||||
import GraphVisualization, { GraphVisualizationAPI } from "@/app/(graph)/GraphVisualization";
|
||||
|
||||
|
|
@ -60,13 +61,26 @@ export default function Notebook({ notebook, updateNotebook, runCell }: Notebook
|
|||
updateNotebook(newNotebook);
|
||||
}, [notebook, updateNotebook]);
|
||||
|
||||
const handleCellRemove = useCallback((cell: Cell) => {
|
||||
const removeCell = useCallback((cell: Cell, event?: MouseEvent) => {
|
||||
event?.preventDefault();
|
||||
|
||||
updateNotebook({
|
||||
...notebook,
|
||||
cells: notebook.cells.filter((c: Cell) => c.id !== cell.id),
|
||||
});
|
||||
}, [notebook, updateNotebook]);
|
||||
|
||||
const {
|
||||
isModalOpen: isRemoveCellConfirmModalOpen,
|
||||
openModal: openCellRemoveConfirmModal,
|
||||
closeModal: closeCellRemoveConfirmModal,
|
||||
confirmAction: handleCellRemoveConfirm,
|
||||
} = useModal<Cell, MouseEvent>(false, removeCell);
|
||||
|
||||
const handleCellRemove = useCallback((cell: Cell) => {
|
||||
openCellRemoveConfirmModal(cell);
|
||||
}, [openCellRemoveConfirmModal]);
|
||||
|
||||
const handleCellInputChange = useCallback((notebook: NotebookType, cell: Cell, value: string) => {
|
||||
const newCell = {...cell, content: value };
|
||||
|
||||
|
|
@ -134,100 +148,133 @@ export default function Notebook({ notebook, updateNotebook, runCell }: Notebook
|
|||
};
|
||||
|
||||
return (
|
||||
<div className="bg-white rounded-xl flex flex-col gap-0.5 px-7 py-5 flex-1">
|
||||
<div className="mb-5">{notebook.name}</div>
|
||||
<>
|
||||
<div className="bg-white rounded-xl flex flex-col gap-0.5 px-7 py-5 flex-1">
|
||||
<div className="mb-5">{notebook.name}</div>
|
||||
|
||||
{notebook.cells.map((cell: Cell, index) => (
|
||||
<Fragment key={cell.id}>
|
||||
<div key={cell.id} className="flex flex-row rounded-xl border-1 border-gray-100">
|
||||
<div className="flex flex-col flex-1 relative">
|
||||
{cell.type === "code" ? (
|
||||
<>
|
||||
<div className="absolute left-[-1.35rem] top-2.5">
|
||||
<IconButton className="p-[0.25rem] m-[-0.25rem]" onClick={toggleCellOpen.bind(null, cell.id)}>
|
||||
<CaretIcon className={classNames("transition-transform", openCells.has(cell.id) ? "rotate-0" : "rotate-180")} />
|
||||
</IconButton>
|
||||
</div>
|
||||
{notebook.cells.map((cell: Cell, index) => (
|
||||
<Fragment key={cell.id}>
|
||||
<div key={cell.id} className="flex flex-row rounded-xl border-1 border-gray-100">
|
||||
<div className="flex flex-col flex-1 relative">
|
||||
{cell.type === "code" ? (
|
||||
<>
|
||||
<div className="absolute left-[-1.35rem] top-2.5">
|
||||
<IconButton className="p-[0.25rem] m-[-0.25rem]" onClick={toggleCellOpen.bind(null, cell.id)}>
|
||||
<CaretIcon className={classNames("transition-transform", openCells.has(cell.id) ? "rotate-0" : "rotate-180")} />
|
||||
</IconButton>
|
||||
</div>
|
||||
|
||||
<NotebookCellHeader
|
||||
cell={cell}
|
||||
runCell={handleCellRun}
|
||||
renameCell={handleCellRename}
|
||||
removeCell={handleCellRemove}
|
||||
moveCellUp={handleCellUp}
|
||||
moveCellDown={handleCellDown}
|
||||
className="rounded-tl-xl rounded-tr-xl"
|
||||
/>
|
||||
<NotebookCellHeader
|
||||
cell={cell}
|
||||
runCell={handleCellRun}
|
||||
renameCell={handleCellRename}
|
||||
removeCell={handleCellRemove}
|
||||
moveCellUp={handleCellUp}
|
||||
moveCellDown={handleCellDown}
|
||||
className="rounded-tl-xl rounded-tr-xl"
|
||||
/>
|
||||
|
||||
{openCells.has(cell.id) && (
|
||||
<>
|
||||
{openCells.has(cell.id) && (
|
||||
<>
|
||||
<TextArea
|
||||
value={cell.content}
|
||||
onChange={handleCellInputChange.bind(null, notebook, cell)}
|
||||
// onKeyUp={handleCellRunOnEnter}
|
||||
isAutoExpanding
|
||||
name="cellInput"
|
||||
placeholder="Type your code here..."
|
||||
contentEditable={true}
|
||||
className="resize-none min-h-36 max-h-96 overflow-y-auto rounded-tl-none rounded-tr-none rounded-bl-xl rounded-br-xl border-0 !outline-0"
|
||||
/>
|
||||
|
||||
<div className="flex flex-col bg-gray-100 overflow-x-auto max-w-full">
|
||||
{cell.result && (
|
||||
<div className="px-2 py-2">
|
||||
output: <CellResult content={cell.result} />
|
||||
</div>
|
||||
)}
|
||||
{cell.error && (
|
||||
<div className="px-2 py-2">
|
||||
error: {cell.error}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<div className="absolute left-[-1.35rem] top-2.5">
|
||||
<IconButton className="p-[0.25rem] m-[-0.25rem]" onClick={toggleCellOpen.bind(null, cell.id)}>
|
||||
<CaretIcon className={classNames("transition-transform", openCells.has(cell.id) ? "rotate-0" : "rotate-180")} />
|
||||
</IconButton>
|
||||
</div>
|
||||
|
||||
<NotebookCellHeader
|
||||
cell={cell}
|
||||
renameCell={handleCellRename}
|
||||
removeCell={handleCellRemove}
|
||||
moveCellUp={handleCellUp}
|
||||
moveCellDown={handleCellDown}
|
||||
className="rounded-tl-xl rounded-tr-xl"
|
||||
/>
|
||||
|
||||
{openCells.has(cell.id) && (
|
||||
<TextArea
|
||||
value={cell.content}
|
||||
onChange={handleCellInputChange.bind(null, notebook, cell)}
|
||||
// onKeyUp={handleCellRunOnEnter}
|
||||
isAutoExpanding
|
||||
name="cellInput"
|
||||
placeholder="Type your code here..."
|
||||
placeholder="Type your text here..."
|
||||
contentEditable={true}
|
||||
className="resize-none min-h-36 max-h-96 overflow-y-auto rounded-tl-none rounded-tr-none rounded-bl-xl rounded-br-xl border-0 !outline-0"
|
||||
className="resize-none min-h-24 max-h-96 overflow-y-auto rounded-tl-none rounded-tr-none rounded-bl-xl rounded-br-xl border-0 !outline-0"
|
||||
/>
|
||||
|
||||
<div className="flex flex-col bg-gray-100 overflow-x-auto max-w-full">
|
||||
{cell.result && (
|
||||
<div className="px-2 py-2">
|
||||
output: <CellResult content={cell.result} />
|
||||
</div>
|
||||
)}
|
||||
{cell.error && (
|
||||
<div className="px-2 py-2">
|
||||
error: {cell.error}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
openCells.has(cell.id) && (
|
||||
<TextArea
|
||||
value={cell.content}
|
||||
onChange={handleCellInputChange.bind(null, notebook, cell)}
|
||||
// onKeyUp={handleCellRunOnEnter}
|
||||
isAutoExpanding
|
||||
name="cellInput"
|
||||
placeholder="Type your text here..."
|
||||
contentEditable={true}
|
||||
className="resize-none min-h-24 max-h-96 overflow-y-auto rounded-tl-none rounded-tr-none rounded-bl-xl rounded-br-xl border-0 !outline-0"
|
||||
/>
|
||||
)
|
||||
)}
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="ml-[-1.35rem]">
|
||||
<PopupMenu
|
||||
openToRight={true}
|
||||
triggerElement={<PlusIcon />}
|
||||
triggerClassName="p-[0.25rem] m-[-0.25rem]"
|
||||
>
|
||||
<div className="flex flex-col gap-0.5">
|
||||
<button
|
||||
onClick={() => handleCellAdd(index, "markdown")}
|
||||
<div className="ml-[-1.35rem]">
|
||||
<PopupMenu
|
||||
openToRight={true}
|
||||
triggerElement={<PlusIcon />}
|
||||
triggerClassName="p-[0.25rem] m-[-0.25rem]"
|
||||
>
|
||||
<div className="flex flex-col gap-0.5">
|
||||
<button
|
||||
onClick={() => handleCellAdd(index, "markdown")}
|
||||
className="hover:bg-gray-100 w-full text-left px-2 cursor-pointer"
|
||||
>
|
||||
<span>text</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
onClick={() => handleCellAdd(index, "code")}
|
||||
className="hover:bg-gray-100 w-full text-left px-2 cursor-pointer"
|
||||
>
|
||||
<span>text</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
onClick={() => handleCellAdd(index, "code")}
|
||||
className="hover:bg-gray-100 w-full text-left px-2 cursor-pointer"
|
||||
>
|
||||
<span>code</span>
|
||||
</div>
|
||||
</PopupMenu>
|
||||
<span>code</span>
|
||||
</div>
|
||||
</PopupMenu>
|
||||
</div>
|
||||
</Fragment>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<Modal isOpen={isRemoveCellConfirmModalOpen}>
|
||||
<div className="w-full max-w-2xl">
|
||||
<div className="flex flex-row items-center justify-between">
|
||||
<span className="text-2xl">Delete notebook cell?</span>
|
||||
<IconButton onClick={closeCellRemoveConfirmModal}><CloseIcon /></IconButton>
|
||||
</div>
|
||||
</Fragment>
|
||||
))}
|
||||
</div>
|
||||
<div className="mt-8 mb-6">Are you sure you want to delete a notebook cell? This action cannot be undone.</div>
|
||||
<div className="flex flex-row gap-4 mt-4 justify-end">
|
||||
<GhostButton type="button" onClick={closeCellRemoveConfirmModal}>cancel</GhostButton>
|
||||
<CTAButton onClick={handleCellRemoveConfirm} type="submit">delete</CTAButton>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -253,7 +300,7 @@ function CellResult({ content }: { content: [] }) {
|
|||
data={transformInsightsGraphData(line)}
|
||||
ref={graphRef as MutableRefObject<GraphVisualizationAPI>}
|
||||
graphControls={graphControls}
|
||||
className="min-h-48"
|
||||
className="min-h-80"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import { Cell } from "./types";
|
|||
|
||||
interface NotebookCellHeaderProps {
|
||||
cell: Cell;
|
||||
runCell: (cell: Cell, cogneeInstance: string) => Promise<void>;
|
||||
runCell?: (cell: Cell, cogneeInstance: string) => Promise<void>;
|
||||
renameCell: (cell: Cell) => void;
|
||||
removeCell: (cell: Cell) => void;
|
||||
moveCellUp: (cell: Cell) => void;
|
||||
|
|
@ -36,28 +36,36 @@ export default function NotebookCellHeader({
|
|||
const [runInstance, setRunInstance] = useState<string>(isCloudEnvironment() ? "cloud" : "local");
|
||||
|
||||
const handleCellRun = () => {
|
||||
setIsRunningCell();
|
||||
runCell(cell, runInstance)
|
||||
.then(() => {
|
||||
setIsNotRunningCell();
|
||||
});
|
||||
if (runCell) {
|
||||
setIsRunningCell();
|
||||
runCell(cell, runInstance)
|
||||
.then(() => {
|
||||
setIsNotRunningCell();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={classNames("flex flex-row justify-between items-center h-9 bg-gray-100", className)}>
|
||||
<div className="flex flex-row items-center px-3.5">
|
||||
{isRunningCell ? <LoadingIndicator /> : <IconButton onClick={handleCellRun}><PlayIcon /></IconButton>}
|
||||
{runCell && (
|
||||
<>
|
||||
{isRunningCell ? <LoadingIndicator /> : <IconButton onClick={handleCellRun}><PlayIcon /></IconButton>}
|
||||
</>
|
||||
)}
|
||||
<span className="ml-4">{cell.name}</span>
|
||||
</div>
|
||||
<div className="pr-4 flex flex-row items-center gap-8">
|
||||
{isCloudEnvironment() ? (
|
||||
<div>
|
||||
cloud cognee
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
local cognee
|
||||
</div>
|
||||
{runCell && (
|
||||
isCloudEnvironment() ? (
|
||||
<div>
|
||||
cloud cognee
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
local cognee
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
{/* <Select name="cogneeInstance" onChange={(event) => setRunInstance(event.currentTarget.value)} className="!bg-transparent outline-none cursor-pointer !hover:bg-gray-50">
|
||||
<option value="local" className="flex flex-row items-center gap-2">
|
||||
|
|
|
|||
|
|
@ -5,11 +5,11 @@ let numberOfRetries = 0;
|
|||
|
||||
const isAuth0Enabled = process.env.USE_AUTH0_AUTHORIZATION?.toLowerCase() === "true";
|
||||
|
||||
const backendApiUrl = process.env.NEXT_PUBLIC_BACKEND_API_URL || "http://localhost:8000/api";
|
||||
const backendApiUrl = process.env.NEXT_PUBLIC_BACKEND_API_URL || "http://localhost:8000";
|
||||
|
||||
const cloudApiUrl = process.env.NEXT_PUBLIC_CLOUD_API_URL || "http://localhost:8001/api";
|
||||
const cloudApiUrl = process.env.NEXT_PUBLIC_CLOUD_API_URL || "http://localhost:8001";
|
||||
|
||||
let apiKey: string | null = null;
|
||||
let apiKey: string | null = process.env.NEXT_PUBLIC_COGWIT_API_KEY || null;
|
||||
let accessToken: string | null = null;
|
||||
|
||||
export default async function fetch(url: string, options: RequestInit = {}, useCloud = false): Promise<Response> {
|
||||
|
|
@ -30,26 +30,24 @@ export default async function fetch(url: string, options: RequestInit = {}, useC
|
|||
});
|
||||
}
|
||||
|
||||
const authHeaders = useCloud && (!isCloudEnvironment() || !accessToken) ? {
|
||||
"X-Api-Key": apiKey,
|
||||
} : {
|
||||
"Authorization": `Bearer ${accessToken}`,
|
||||
}
|
||||
|
||||
return global.fetch(
|
||||
(useCloud ? cloudApiUrl : backendApiUrl) + (useCloud ? url.replace("/v1", "") : url),
|
||||
(useCloud ? cloudApiUrl : backendApiUrl) + "/api" + (useCloud ? url.replace("/v1", "") : url),
|
||||
{
|
||||
...options,
|
||||
headers: {
|
||||
...options.headers,
|
||||
...(useCloud && !isCloudEnvironment()
|
||||
? {"X-Api-Key": apiKey!}
|
||||
: {"Authorization": `Bearer ${accessToken}`}
|
||||
),
|
||||
},
|
||||
...authHeaders,
|
||||
} as HeadersInit,
|
||||
credentials: "include",
|
||||
},
|
||||
)
|
||||
.then((response) => handleServerErrors(response, retry))
|
||||
.then((response) => {
|
||||
numberOfRetries = 0;
|
||||
|
||||
return response;
|
||||
})
|
||||
.then((response) => handleServerErrors(response, retry, useCloud))
|
||||
.catch((error) => {
|
||||
if (error.detail === undefined) {
|
||||
return Promise.reject(
|
||||
|
|
@ -57,10 +55,10 @@ export default async function fetch(url: string, options: RequestInit = {}, useC
|
|||
);
|
||||
}
|
||||
|
||||
if (error.status === 401) {
|
||||
return retry(error);
|
||||
}
|
||||
return Promise.reject(error);
|
||||
})
|
||||
.finally(() => {
|
||||
numberOfRetries = 0;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { redirect } from "next/navigation";
|
||||
|
||||
export default function handleServerErrors(response: Response, retry?: (response: Response) => Promise<Response>): Promise<Response> {
|
||||
export default function handleServerErrors(response: Response, retry?: (response: Response) => Promise<Response>, useCloud?: boolean): Promise<Response> {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (response.status === 401) {
|
||||
if (response.status === 401 && !useCloud) {
|
||||
if (retry) {
|
||||
return retry(response)
|
||||
.catch(() => {
|
||||
|
|
@ -13,7 +13,10 @@ export default function handleServerErrors(response: Response, retry?: (response
|
|||
}
|
||||
}
|
||||
if (!response.ok) {
|
||||
return response.json().then(error => reject(error));
|
||||
return response.json().then(error => {
|
||||
error.status = response.status;
|
||||
reject(error);
|
||||
});
|
||||
}
|
||||
|
||||
if (response.status >= 200 && response.status < 300) {
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ def get_checks_router():
|
|||
api_token = request.headers.get("X-Api-Key")
|
||||
|
||||
if api_token is None:
|
||||
return CloudApiKeyMissingError()
|
||||
raise CloudApiKeyMissingError()
|
||||
|
||||
return await check_api_key(api_token)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue