diff --git a/frontend/src/pages/OrganizationSettings/index.tsx b/frontend/src/pages/OrganizationSettings/index.tsx index 658840f..acc8910 100644 --- a/frontend/src/pages/OrganizationSettings/index.tsx +++ b/frontend/src/pages/OrganizationSettings/index.tsx @@ -74,7 +74,6 @@ export default function OrganizationSettingsView() { setConnector(newConnector)} /> diff --git a/frontend/src/pages/Tools/ToolsList/index.tsx b/frontend/src/pages/Tools/ToolsList/index.tsx index a24918f..d6786b2 100644 --- a/frontend/src/pages/Tools/ToolsList/index.tsx +++ b/frontend/src/pages/Tools/ToolsList/index.tsx @@ -2,23 +2,27 @@ import { useState } from 'react'; import { Info } from 'react-feather'; import { APP_NAME } from '../../../utils/constants'; import paths from '../../../utils/paths'; +import { CaretDown } from '@phosphor-icons/react'; export default function ToolsList({ organization }: { organization: any }) { return ( -
-
-
-

- Advanced management tools -

-

- below are a list of advanced {APP_NAME} only tools and services that - you can use to manage your connected vector database. -

-
+
+
+ +
Organization Tools
-
+
+
+ Below are a list of advanced {APP_NAME} only tools and services that + you can use to manage your connected vector database. +
+ { const [show, setShow] = useState(false); return ( -
+
- {title} - + {title} + {description}
{!available ? ( -
+
-

feature under development.

+

Feature under development.

) : (

Open tool →

diff --git a/frontend/src/pages/Tools/index.tsx b/frontend/src/pages/Tools/index.tsx index 72e2f59..546362d 100644 --- a/frontend/src/pages/Tools/index.tsx +++ b/frontend/src/pages/Tools/index.tsx @@ -5,8 +5,18 @@ import DefaultLayout from '../../layout/DefaultLayout'; import User from '../../models/user'; import paths from '../../utils/paths'; import AppLayout from '../../layout/AppLayout'; -import { useParams } from 'react-router-dom'; +import { NavLink, useParams } from 'react-router-dom'; import ToolsList from './ToolsList'; +import Organization from '../../models/organization'; + +import ChromaLogo from '../../images/vectordbs/chroma.png'; +import PineconeLogoInverted from '../../images/vectordbs/pinecone-inverted.png'; +import PineconeLogo from '../../images/vectordbs/pinecone.png'; +import qDrantLogo from '../../images/vectordbs/qdrant.png'; +import WeaviateLogo from '../../images/vectordbs/weaviate.png'; +import truncate from 'truncate'; +import { GearSix, Prohibit } from '@phosphor-icons/react'; +import { titleCase } from 'title-case'; export default function OrganizationToolsView() { const { user } = useUser(); @@ -14,6 +24,7 @@ export default function OrganizationToolsView() { const [loading, setLoading] = useState(true); const [organizations, setOrganizations] = useState([]); const [organization, setOrganization] = useState(null); + const [connector, setConnector] = useState(null); useEffect(() => { async function userOrgs() { @@ -27,6 +38,8 @@ export default function OrganizationToolsView() { const focusedOrg = orgs?.find((org: any) => org.slug === slug) || orgs?.[0]; + const _connector = await Organization.connector(focusedOrg.slug); + setConnector(_connector); setOrganizations(orgs); setOrganization(focusedOrg); @@ -50,12 +63,1038 @@ export default function OrganizationToolsView() { organizations={organizations} organization={organization} workspaces={[]} + headerExtendedItems={ + + } >
+ setConnector(newConnector)} + /> +
); } + +function OrganizationHeader({ organization, connector }: any) { + let logo; + switch (connector?.type) { + case 'chroma': + logo = ChromaLogo; + break; + case 'qdrant': + logo = qDrantLogo; + break; + case 'weaviate': + logo = WeaviateLogo; + break; + case 'pinecone': + logo = PineconeLogoInverted; + break; + } + + return ( + <> +
+
+ + {truncate(organization?.name, 20)} + +
+
+
+ + + + + + + +
+ + ); +} + +const NewConnectorModal = ({ + organization, + onNew, +}: { + organization: any; + onNew: (newConnector: any) => void; +}) => { + const [loading, setLoading] = useState(false); + const [type, setType] = useState('chroma'); + const [error, setError] = useState(null); + const [success, setSuccess] = useState(false); + const handleSubmit = async (e: any) => { + e.preventDefault(); + setError(null); + setLoading(true); + const data = { type }; + const form = new FormData(e.target); + for (var [_k, value] of form.entries()) { + if (_k.includes('::')) { + const [_key, __key] = _k.split('::'); + if (!data.hasOwnProperty(_key)) data[_key] = {}; + data[_key][__key] = value; + } else { + data[_k] = value; + } + } + + const { connector, error } = await Organization.addConnector( + organization.slug, + data + ); + + if (!connector) { + setLoading(false); + setError(error); + return false; + } + + setLoading(false); + setSuccess(true); + setTimeout(() => { + onNew(connector); + setSuccess(false); + }, 1500); + }; + + return ( + + event.target == event.currentTarget && event.currentTarget?.close() + } + > +
+
+

+ Connect to Vector Database +

+

+ {APP_NAME} is a tool to help you manage vectors in a vector + database, but without access to a valid vector database you will be + limited to read-only actions and limited functionality - you should + connect to a vector database provider to unlock full functionality. +

+
+ + + + +
+
+ ); +}; + +const UpdateConnectorModal = ({ + organization, + connector, + onUpdate, +}: { + organization: any; + connector: any; + onUpdate: (newConnector: any) => void; +}) => { + const [loading, setLoading] = useState(false); + const [type, setType] = useState(connector?.type); + const [error, setError] = useState(null); + const [success, setSuccess] = useState(false); + const settings = JSON.parse(connector?.settings); + + const handleSubmit = async (e: any) => { + e.preventDefault(); + setError(null); + setLoading(true); + const data = { type }; + const form = new FormData(e.target); + for (var [_k, value] of form.entries()) { + if (_k.includes('::')) { + const [_key, __key] = _k.split('::'); + if (!data.hasOwnProperty(_key)) data[_key] = {}; + data[_key][__key] = value; + } else { + data[_k] = value; + } + } + + const { connector, error } = await Organization.updateConnector( + organization.slug, + data + ); + if (!connector) { + setLoading(false); + setError(error); + return false; + } + + setLoading(false); + setSuccess(true); + setTimeout(() => { + onUpdate(connector); + setSuccess(false); + }, 1500); + }; + + return ( + + event.target == event.currentTarget && event.currentTarget?.close() + } + > +
+
+

+ Update Vector Database Connection +

+

+ Currently connected to a {connector.type} vector database instance. + You can update your configuration settings here if they have + changed. +

+
+ {loading ? ( +
+
+ +
+
+ ) : ( +
+
    +
  • setType('chroma')} className="w-[250px]"> + + +
  • +
  • setType('pinecone')} className="w-[250px]"> + + +
  • +
  • setType('qdrant')} className="w-[250px]"> + + +
  • +
  • setType('weaviate')} className="w-[250px]"> + + +
  • +
+ + {type === 'chroma' && ( +
+
+
+ +

+ This is the URL your chroma instance is reachable at. +

+
+ +
+
+
+ +

+ If your hosted Chroma instance is protected by an API key + - enter the header and api key here. +

+
+
+ + +
+
+
+ )} + + {type === 'pinecone' && ( +
+
+
+ +

+ You can find this on your Pinecone index. +

+
+ +
+ +
+
+ +

+ You can find this on your Pinecone index. +

+
+ +
+ +
+
+ +

+ If your hosted Chroma instance is protected by an API key + - enter it here. +

+
+ +
+
+ )} + + {type === 'qdrant' && ( +
+
+
+ +

+ You can find this in your cloud hosted qDrant cluster or + just using the URL to your local docker container. +

+
+ +
+ +
+
+ +

+ (optional) If you are using qDrant cloud you will need an + API key. +

+
+ +
+
+ )} + + {type === 'weaviate' && ( +
+
+
+ +

+ You can find this in your cloud hosted Weaviate cluster or + just using the URL to your local docker container. +

+
+ +
+ +
+
+ +

+ (optional) If you are using Weaviate cloud you will need + an API key. +

+
+ +
+
+ )} + +
+ {error && ( +

+ {error} +

+ )} + {success && ( +

+ Connector changes saved +

+ )} + +
+
+ )} +
+
+ ); +}; + +const SyncConnectorModal = ({ + organization, + connector, +}: { + organization: any; + connector: any; +}) => { + const [synced, setSynced] = useState(false); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + const sync = async () => { + setError(null); + setLoading(true); + const { job, error } = await Organization.syncConnector( + organization.slug, + connector.id + ); + + if (!job) { + setError(error); + setLoading(false); + setSynced(false); + return; + } + + setLoading(false); + setSynced(true); + }; + + return ( + + event.target == event.currentTarget && event.currentTarget?.close() + } + > +
+
+

+ Sync Vector Database Connection +

+

+ Automatically sync existing information in your{' '} + {titleCase(connector.type)}{' '} + {connector.type === 'chroma' ? 'collections' : 'namespaces'} so you + can manage it more easily. This process can take a long time to + complete depending on how much data you have embedded already. +
+
+ Once you start this process you can check on its progress in the{' '} + + job queue. + +

+
+
+ {error && ( +

+ {error} +

+ )} + {synced ? ( + + ) : ( + + )} +
+
+
+ ); +};