mirror of
https://github.com/Mintplex-Labs/vector-admin.git
synced 2026-07-19 13:16:03 -04:00
working organization dashboard table, WIP quick actions & workspaces sidebar
This commit is contained in:
@@ -11,6 +11,8 @@ import UploadDocumentModal from './UploadModal';
|
||||
import UploadModalNoKey from './UploadModal/UploadModalNoKey';
|
||||
import DocumentListPagination from '../../../components/DocumentPaginator';
|
||||
import useQuery from '../../../hooks/useQuery';
|
||||
import Document from '../../../models/document';
|
||||
import { File, Trash } from '@phosphor-icons/react';
|
||||
|
||||
export default function DocumentsList({
|
||||
organization,
|
||||
@@ -41,6 +43,18 @@ export default function DocumentsList({
|
||||
setCurrentPage(setTo);
|
||||
}
|
||||
|
||||
const deleteDocument = async (documentId: number) => {
|
||||
if (
|
||||
!confirm(
|
||||
'Are you sure you want to delete this document? This will remove the document from your vector database and remove it from the cache. This process cannot be undone.'
|
||||
)
|
||||
)
|
||||
return false;
|
||||
const success = await Document.delete(documentId);
|
||||
if (!success) return false;
|
||||
document.getElementById(`document-row-${documentId}`)?.remove();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
async function getDocs(slug?: string) {
|
||||
if (!slug) return false;
|
||||
@@ -59,30 +73,17 @@ export default function DocumentsList({
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="col-span-12 flex-1 rounded-sm border border-stroke bg-main py-6 shadow-default dark:border-strokedark dark:bg-boxdark xl:col-span-4">
|
||||
<div className="flex items-start justify-between px-4">
|
||||
<div>
|
||||
<h4 className="mb-6 px-4 text-xl font-semibold text-black dark:text-white">
|
||||
Documents {totalDocuments! > 0 ? `(${totalDocuments})` : ''}
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex h-60 w-full items-center justify-center px-7.5">
|
||||
<div className="h-full w-full animate-pulse rounded-lg bg-slate-100" />
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="mb-9 flex h-screen flex-col overflow-hidden bg-main py-6 transition-all duration-300"
|
||||
style={{ height: `calc(100vh - 210px` }}
|
||||
></div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="col-span-12 flex-1 rounded-sm border border-stroke bg-white py-6 shadow-default dark:border-strokedark dark:bg-boxdark xl:col-span-4">
|
||||
{/* <div className="flex-grow overflow-y-auto rounded-xl border-2 border-white/20 bg-main">
|
||||
<div className="flex items-start justify-between px-4">
|
||||
<div>
|
||||
<h4 className="mb-6 px-4 text-xl font-semibold text-black dark:text-white">
|
||||
Documents {totalDocuments! > 0 ? `(${totalDocuments})` : ''}
|
||||
</h4>
|
||||
</div>
|
||||
{workspaces.length > 0 ? (
|
||||
<>
|
||||
{!!knownConnector ? (
|
||||
@@ -128,16 +129,41 @@ export default function DocumentsList({
|
||||
<span className="font-medium">Workspace</span>
|
||||
</div>
|
||||
<div className="hidden w-4/12 md:block xl:w-3/12">
|
||||
<span className="font-medium">Created</span>
|
||||
<span className="font-medium">Date</span>
|
||||
</div>
|
||||
<div className="w-5/12 2xsm:w-4/12 md:w-3/12 xl:w-2/12">
|
||||
<span className="font-medium">Status</span>
|
||||
<span className="font-medium">Vectors</span>
|
||||
</div>
|
||||
<div className="hidden w-2/12 text-center 2xsm:block md:w-1/12">
|
||||
<span className="font-medium"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{documents?.length === 0 && (
|
||||
<div className="-mt-10 flex h-full w-full items-center justify-center">
|
||||
<div className="flex flex-col items-center justify-center gap-y-4 text-center">
|
||||
<div className="text-center font-medium text-white text-opacity-40">
|
||||
0 Documents
|
||||
</div>
|
||||
<div className="text-center text-sm font-light text-white text-opacity-80">
|
||||
Upload documents to your workspace
|
||||
</div>
|
||||
<button
|
||||
onClick={() => {
|
||||
window.document
|
||||
?.getElementById('upload-document-modal')
|
||||
?.showModal();
|
||||
}}
|
||||
className="mt-4 inline-flex items-center justify-center gap-2.5 rounded-lg bg-white p-2.5 px-36 shadow"
|
||||
>
|
||||
<div className="text-center text-sm font-bold leading-tight text-zinc-900">
|
||||
Upload Documents
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<>
|
||||
{documents.map((document) => {
|
||||
return (
|
||||
@@ -216,17 +242,212 @@ export default function DocumentsList({
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div> */}
|
||||
<div
|
||||
className="mb-9 flex h-screen flex-col overflow-hidden bg-main transition-all duration-300"
|
||||
style={{ height: `calc(100vh - 160px)` }}
|
||||
>
|
||||
<div className="flex-grow overflow-y-auto rounded-xl border-2 border-white/20 bg-main">
|
||||
<table className="w-full rounded-xl text-left text-xs font-medium text-white text-opacity-80">
|
||||
<thead className="sticky top-0 w-full border-b-2 border-white/20 bg-main ">
|
||||
<tr className="mt-10">
|
||||
<th
|
||||
scope="col"
|
||||
className="px-6 pb-2 pt-6 text-xs font-light text-white text-opacity-80"
|
||||
>
|
||||
Name
|
||||
</th>
|
||||
<th
|
||||
scope="col"
|
||||
className="px-6 pb-2 pt-6 text-xs font-light text-white text-opacity-80"
|
||||
>
|
||||
Workspace
|
||||
</th>
|
||||
<th
|
||||
scope="col"
|
||||
className="px-6 pb-2 pt-6 text-xs font-light text-white text-opacity-80"
|
||||
>
|
||||
Date
|
||||
</th>
|
||||
<th
|
||||
scope="col"
|
||||
className="px-6 pb-2 pt-6 text-xs font-light text-white text-opacity-80"
|
||||
>
|
||||
Vectors
|
||||
</th>
|
||||
<th
|
||||
scope="col"
|
||||
className="px-6 pb-2 pt-6 text-xs font-light text-white text-opacity-80"
|
||||
>
|
||||
{' '}
|
||||
</th>
|
||||
<th
|
||||
hidden={workspaces.length === 0}
|
||||
scope="col"
|
||||
className="relative px-6 pb-2 pt-6"
|
||||
>
|
||||
<button
|
||||
onClick={() => {
|
||||
document
|
||||
.getElementById('upload-document-modal')
|
||||
?.showModal();
|
||||
}}
|
||||
className="inline-flex h-[26px] w-[98px] items-center justify-center gap-2.5 rounded-[100px] bg-white bg-opacity-10 px-2.5 py-1"
|
||||
>
|
||||
<div className="font-['Satoshi'] text-xs font-black tracking-tight text-sky-400">
|
||||
UPLOAD
|
||||
</div>
|
||||
</button>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
{documents?.length > 0 && (
|
||||
<tbody className="bg-main">
|
||||
{documents.map((document, index) => (
|
||||
<Fragment
|
||||
key={document?.id}
|
||||
document={document}
|
||||
index={index}
|
||||
deleteDocument={deleteDocument}
|
||||
organization={organization}
|
||||
/>
|
||||
))}
|
||||
</tbody>
|
||||
)}
|
||||
</table>
|
||||
|
||||
{workspaces?.length === 0 && (
|
||||
<div className="-mt-10 flex h-full w-full items-center justify-center">
|
||||
<div className="flex flex-col items-center justify-center gap-y-4 text-center">
|
||||
<div className="text-center font-medium text-white text-opacity-40">
|
||||
Create a workspace to get started
|
||||
</div>
|
||||
<div className="text-center text-sm font-light text-white text-opacity-80">
|
||||
Workspaces are used to organize your documents
|
||||
</div>
|
||||
<button
|
||||
onClick={() => {
|
||||
window.document
|
||||
?.getElementById('workspace-creation-modal')
|
||||
?.showModal();
|
||||
}}
|
||||
className="mt-4 inline-flex items-center justify-center gap-2.5 rounded-lg bg-white p-2.5 px-36 shadow"
|
||||
>
|
||||
<div className="text-center text-sm font-bold leading-tight text-zinc-900">
|
||||
Create Workspace
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{documents?.length === 0 && workspaces?.length > 0 && (
|
||||
<div className="-mt-10 flex h-full w-full items-center justify-center">
|
||||
<div className="flex flex-col items-center justify-center gap-y-4 text-center">
|
||||
<div className="text-center font-medium text-white text-opacity-40">
|
||||
0 Documents
|
||||
</div>
|
||||
<div className="text-center text-sm font-light text-white text-opacity-80">
|
||||
Upload documents to your workspace
|
||||
</div>
|
||||
<button
|
||||
onClick={() => {
|
||||
window.document
|
||||
?.getElementById('upload-document-modal')
|
||||
?.showModal();
|
||||
}}
|
||||
className="mt-4 inline-flex items-center justify-center gap-2.5 rounded-lg bg-white p-2.5 px-36 shadow"
|
||||
>
|
||||
<div className="text-center text-sm font-bold leading-tight text-zinc-900">
|
||||
Upload Documents
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="pt-20">
|
||||
<DocumentListPagination
|
||||
pageCount={Math.ceil(
|
||||
totalDocuments! / Organization.documentPageSize
|
||||
)}
|
||||
currentPage={currentPage}
|
||||
gotoPage={updatePage}
|
||||
/>
|
||||
</div>
|
||||
{canUpload ? (
|
||||
<UploadDocumentModal workspaces={workspaces} />
|
||||
) : (
|
||||
<UploadModalNoKey />
|
||||
)}
|
||||
</div>
|
||||
<DocumentListPagination
|
||||
pageCount={Math.ceil(totalDocuments! / Organization.documentPageSize)}
|
||||
currentPage={currentPage}
|
||||
gotoPage={updatePage}
|
||||
/>
|
||||
{canUpload ? (
|
||||
<UploadDocumentModal workspaces={workspaces} />
|
||||
) : (
|
||||
<UploadModalNoKey />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const Fragment = ({
|
||||
document,
|
||||
index,
|
||||
deleteDocument,
|
||||
organization,
|
||||
}: {
|
||||
document: any;
|
||||
index: number;
|
||||
deleteDocument: any;
|
||||
organization: any;
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
<tr
|
||||
key={document?.id}
|
||||
id={`document-row-${document?.id}`}
|
||||
className={`h-9 hover:bg-white/10 ${
|
||||
index % 2 === 0 ? 'bg-main-2' : 'bg-main'
|
||||
}`}
|
||||
>
|
||||
<td className="flex items-center gap-x-1 px-6 py-2 text-sm font-light text-white">
|
||||
<File className="flex-shrink-0" size={16} weight="fill" />
|
||||
<p>{truncate(document?.name, 35)}</p>
|
||||
</td>
|
||||
<td className="px-6 ">
|
||||
<a
|
||||
href={paths.workspace(organization.slug, document.workspace.slug)}
|
||||
className="hover:text-sky-400 hover:underline"
|
||||
>
|
||||
<span className="font-medium">
|
||||
{truncate(document.workspace.name, 20) || ''}
|
||||
</span>
|
||||
</a>
|
||||
</td>
|
||||
<td className="px-6 ">{moment(document?.createdAt).format('lll')}</td>
|
||||
<td className="px-6 ">Cached</td>
|
||||
<td className="px-6 ">
|
||||
<a
|
||||
href={paths.document(
|
||||
organization.slug,
|
||||
document.workspace.slug,
|
||||
document.id
|
||||
)}
|
||||
className="rounded-lg px-2 py-1 text-sky-400 transition-all duration-300 hover:bg-blue-50"
|
||||
>
|
||||
Details
|
||||
</a>
|
||||
</td>
|
||||
<td className="px-6">
|
||||
<div className="flex items-center gap-x-4">
|
||||
<div className=" flex items-center gap-x-6">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => deleteDocument(document?.id)}
|
||||
className="rounded-lg px-2 py-1 text-white transition-all duration-300 hover:bg-red-50 hover:text-red-600"
|
||||
>
|
||||
<Trash size={16} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -20,7 +20,7 @@ export default function WorkspacesList({
|
||||
totalWorkspaces?: number;
|
||||
}) {
|
||||
return (
|
||||
<div className="col-span-12 flex-1 rounded-sm border border-stroke bg-white py-6 shadow-default dark:border-strokedark dark:bg-boxdark xl:col-span-4">
|
||||
<div className="col-span-12 max-w-[217px] flex-1 rounded-sm border border-stroke bg-white py-6 shadow-default dark:border-strokedark dark:bg-boxdark xl:col-span-4">
|
||||
<div className=" top-0 z-10 bg-white">
|
||||
<div className="mb-6 flex w-full items-center justify-between px-7.5">
|
||||
<h4 className="text-xl font-semibold text-black dark:text-white">
|
||||
|
||||
@@ -135,8 +135,8 @@ export default function Dashboard() {
|
||||
</div>
|
||||
)}
|
||||
<Statistics organization={organization} />
|
||||
<div className="mt-4 grid grid-cols-12 gap-4 md:mt-6 md:gap-6 2xl:mt-7.5 2xl:gap-7.5">
|
||||
<div className="col-span-12 xl:col-span-8">
|
||||
<div className="mt-4 flex w-full">
|
||||
<div className="mr-6.5 w-full">
|
||||
<DocumentsList
|
||||
knownConnector={connector}
|
||||
organization={organization}
|
||||
@@ -229,10 +229,10 @@ const UpdateConnectorModal = ({
|
||||
onUpdate: (newConnector: any) => void;
|
||||
}) => {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [type, setType] = useState(connector.type);
|
||||
const [type, setType] = useState(connector?.type);
|
||||
const [error, setError] = useState<null | string>(null);
|
||||
const [success, setSuccess] = useState<null | boolean>(false);
|
||||
const settings = JSON.parse(connector.settings);
|
||||
const settings = JSON.parse(connector?.settings);
|
||||
|
||||
const handleSubmit = async (e: any) => {
|
||||
e.preventDefault();
|
||||
|
||||
Reference in New Issue
Block a user