mirror of
https://github.com/Mintplex-Labs/vector-admin.git
synced 2026-07-19 13:16:03 -04:00
WIP searching workspace complete, need to clean up unused vars/add loading states
This commit is contained in:
@@ -59,7 +59,7 @@ export default function DocumentsList({
|
||||
|
||||
if (loading) {
|
||||
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 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">
|
||||
|
||||
@@ -107,7 +107,7 @@ export default function FragmentList({
|
||||
</div>
|
||||
) : (
|
||||
<table className="w-full rounded-xl text-left text-xs font-medium text-white text-opacity-80">
|
||||
<thead className="sticky top-0 w-full bg-main">
|
||||
<thead className="sticky top-0 w-full border-b-2 border-white/20 bg-main">
|
||||
<tr className="mt-10">
|
||||
<th
|
||||
scope="col"
|
||||
|
||||
@@ -6,6 +6,7 @@ import moment from 'moment';
|
||||
import paths from '../../../../utils/paths';
|
||||
import Workspace from '../../../../models/workspace';
|
||||
import { SEARCH_MODES, ISearchTypes } from '../../../../utils/constants';
|
||||
import { CaretDown, MagnifyingGlass, X } from '@phosphor-icons/react';
|
||||
|
||||
export default function SearchView({
|
||||
organization,
|
||||
@@ -13,12 +14,18 @@ export default function SearchView({
|
||||
workspaces,
|
||||
stopSearching,
|
||||
deleteDocument,
|
||||
searchMode,
|
||||
setSearchMode,
|
||||
handleSearchResults,
|
||||
}: {
|
||||
organization: object;
|
||||
workspace: object;
|
||||
workspaces: object[];
|
||||
stopSearching: VoidFunction;
|
||||
deleteDocument: (documentId: number) => void;
|
||||
searchMode: boolean;
|
||||
setSearchMode: (searchMode: boolean) => void;
|
||||
handleSearchResults: (results: any) => void;
|
||||
}) {
|
||||
const formEl = useRef<HTMLFormElement>(null);
|
||||
const [searching, setSearching] = useState(false);
|
||||
@@ -36,6 +43,7 @@ export default function SearchView({
|
||||
};
|
||||
const handleSearch = async (e: SyntheticEvent<HTMLElement, SubmitEvent>) => {
|
||||
e.preventDefault();
|
||||
setSearchMode(true);
|
||||
const formData = new FormData(e.target as any);
|
||||
const query = formData.get('query') as string;
|
||||
|
||||
@@ -48,215 +56,109 @@ export default function SearchView({
|
||||
);
|
||||
setDocuments(matches);
|
||||
setSearching(false);
|
||||
|
||||
handleSearchResults(matches);
|
||||
};
|
||||
|
||||
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="mx-4 mb-6 flex items-center">
|
||||
<form onSubmit={handleSearch} className="w-full">
|
||||
<div className="relative flex">
|
||||
<button
|
||||
onClick={() => setShowSearchMethods(!showSearchMethods)}
|
||||
className="z-10 inline-flex flex-shrink-0 items-center rounded-l-lg border border-gray-300 bg-gray-100 px-4 py-2.5 text-center text-sm font-medium text-gray-900 hover:bg-gray-200 focus:outline-none focus:ring-4 focus:ring-gray-100 dark:border-gray-600 dark:bg-gray-700 dark:text-white dark:hover:bg-gray-600 dark:focus:ring-gray-700"
|
||||
type="button"
|
||||
>
|
||||
{SEARCH_MODES[searchBy].display}
|
||||
<ChevronDown size={18} />
|
||||
</button>
|
||||
<div className="flex items-center">
|
||||
<form ref={formEl} onSubmit={handleSearch} className="w-full">
|
||||
<div className="relative flex">
|
||||
<button
|
||||
onClick={() => setShowSearchMethods(!showSearchMethods)}
|
||||
className="z-10 inline-flex h-9 flex-shrink-0 items-center rounded-[100px] bg-zinc-700 px-5 text-center text-sm font-medium text-white transition-all duration-300 hover:bg-zinc-800 focus:outline-none"
|
||||
type="button"
|
||||
>
|
||||
{SEARCH_MODES['exactText'].display}
|
||||
<div
|
||||
hidden={!showSearchMethods}
|
||||
className="absolute left-0 top-12 z-99 w-44 divide-y divide-gray-100 rounded-lg bg-white shadow dark:bg-gray-700"
|
||||
className={`ml-2 transition-all duration-300 ${
|
||||
showSearchMethods ? '' : 'rotate-180'
|
||||
}`}
|
||||
>
|
||||
<ul
|
||||
className="py-2 text-sm text-gray-700 dark:text-gray-200"
|
||||
aria-labelledby="dropdown-button"
|
||||
>
|
||||
{Object.keys(SEARCH_MODES).map((_key, i) => {
|
||||
const method = _key as ISearchTypes;
|
||||
return (
|
||||
<li key={i}>
|
||||
<button
|
||||
onClick={() => {
|
||||
setSearchBy(method);
|
||||
setShowSearchMethods(false);
|
||||
setDocuments([]);
|
||||
}}
|
||||
type="button"
|
||||
className="inline-flex w-full px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white"
|
||||
>
|
||||
{SEARCH_MODES[method].display}
|
||||
</button>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
<CaretDown size={16} weight="bold" />
|
||||
</div>
|
||||
<div className="relative w-full">
|
||||
<input
|
||||
type="search"
|
||||
name="query"
|
||||
className="z-20 block w-full rounded-r-lg border border-l-2 border-gray-300 border-l-gray-50 bg-gray-50 p-2.5 text-sm text-gray-900 focus:border-blue-500 focus:ring-blue-500 dark:border-gray-600 dark:border-l-gray-700 dark:bg-gray-700 dark:text-white dark:placeholder-gray-400 dark:focus:border-blue-500"
|
||||
placeholder={SEARCH_MODES[searchBy].placeholder}
|
||||
required
|
||||
/>
|
||||
</button>
|
||||
<div
|
||||
className={`absolute left-0 top-12 z-99 w-44 divide-y divide-gray-100 rounded-lg bg-zinc-700 shadow ${
|
||||
showSearchMethods ? 'slide-down' : 'slide-up'
|
||||
}`}
|
||||
style={{
|
||||
animationDuration: '0.15s',
|
||||
}}
|
||||
>
|
||||
<ul
|
||||
className="py-2 text-sm text-white"
|
||||
aria-labelledby="dropdown-button"
|
||||
>
|
||||
{Object.keys(SEARCH_MODES).map((_key, i) => {
|
||||
const method = _key as ISearchTypes;
|
||||
return (
|
||||
<li key={i}>
|
||||
<button
|
||||
onClick={() => {
|
||||
setSearchBy(method);
|
||||
setShowSearchMethods(false);
|
||||
setSearchMode(false);
|
||||
}}
|
||||
type="button"
|
||||
className="inline-flex w-full px-4 py-2 hover:bg-zinc-800"
|
||||
>
|
||||
{SEARCH_MODES[method].display}
|
||||
</button>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
</div>
|
||||
<div className="relative w-full">
|
||||
<input
|
||||
name="query"
|
||||
placeholder={SEARCH_MODES[searchBy].placeholder}
|
||||
className="z-20 -ml-4 block h-9 w-full rounded-r-[100px] bg-main-2 pl-8 text-sm text-white focus:outline-none"
|
||||
required
|
||||
/>
|
||||
{false ? (
|
||||
<div className="absolute right-0 top-0 mr-4.5 flex h-full p-2.5 text-sm font-medium text-white focus:outline-none">
|
||||
<div className="h-4 w-4 animate-spin rounded-full border-2 border-solid border-white border-t-transparent" />
|
||||
</div>
|
||||
) : searchMode ? (
|
||||
<button
|
||||
onClick={clearSearch}
|
||||
className="absolute right-0 top-0 mr-4.5 flex h-full items-center justify-center p-2.5 text-sm font-medium text-white focus:outline-none"
|
||||
>
|
||||
<X
|
||||
size={16}
|
||||
className="text-sky-400 transition-all duration-300 hover:text-sky-700"
|
||||
weight="bold"
|
||||
/>
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
type="submit"
|
||||
disabled={searching}
|
||||
className="absolute right-0 top-0 h-full rounded-r-lg border border-blue-700 bg-blue-700 p-2.5 text-sm font-medium text-white hover:bg-blue-800 focus:outline-none focus:ring-4 focus:ring-blue-300 dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800"
|
||||
className="absolute -right-1 top-0 mr-4.5 flex h-full items-center justify-center rounded-r-[100px] bg-[#303237] p-2.5 text-sm font-medium text-white focus:outline-none"
|
||||
>
|
||||
{searching ? (
|
||||
<Loader size={18} className="animate-spin" />
|
||||
) : (
|
||||
<Search size={18} />
|
||||
)}
|
||||
<span className="sr-only">Search</span>
|
||||
<MagnifyingGlass
|
||||
className="text-sky-400 transition-all duration-300 hover:text-sky-700"
|
||||
size={18}
|
||||
weight="bold"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
onClick={clearSearch}
|
||||
type="button"
|
||||
className="ml-2 flex items-center rounded-lg px-4 py-2 text-center text-black hover:bg-gray-200"
|
||||
>
|
||||
X
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{searching ? (
|
||||
<div>
|
||||
<div className="flex min-h-[40vh] w-full px-8">
|
||||
<div className="flex flex h-auto w-full flex-col items-center justify-center gap-y-2 rounded-lg bg-slate-50">
|
||||
<Loader size={15} className="animate-spin rounded-sm" />
|
||||
<p className="text-sm">
|
||||
Running {SEARCH_MODES[searchBy].display} for{' '}
|
||||
<code className="bg-gray-200 px-2">"{searchTerm}"</code>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
window.document
|
||||
?.getElementById('upload-document-modal')
|
||||
?.showModal();
|
||||
}}
|
||||
className="flex w-18 items-center justify-center rounded-[100px] bg-sky-400 px-2.5 text-xs"
|
||||
>
|
||||
<div className="font-bold uppercase text-black">Upload</div>
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
{documents.length > 0 ? (
|
||||
<div>
|
||||
<div className="border-b border-stroke px-4 pb-5 dark:border-strokedark md:px-6 xl:px-7.5">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-2/12 xl:w-3/12">
|
||||
<span className="font-medium">Document Name</span>
|
||||
</div>
|
||||
<div className="w-6/12 2xsm:w-5/12 md:w-3/12">
|
||||
<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>
|
||||
</div>
|
||||
<div className="w-5/12 2xsm:w-4/12 md:w-3/12 xl:w-2/12">
|
||||
<span className="font-medium">Status</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.map((document) => {
|
||||
return (
|
||||
<div
|
||||
id={`document-row-${document.id}`}
|
||||
key={document.id}
|
||||
className="flex w-full items-center gap-5 px-7.5 py-3 text-gray-600 hover:bg-gray-3 dark:hover:bg-meta-4"
|
||||
>
|
||||
<div className="flex w-full items-center gap-3">
|
||||
<div className="w-2/12 xl:w-3/12">
|
||||
<div className="flex items-center gap-x-1">
|
||||
<FileText className="h-4 w-4" />
|
||||
<span className="hidden font-medium xl:block">
|
||||
{truncate(document.name, 20)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-6/12 2xsm:w-5/12 md:w-3/12">
|
||||
<span className="font-medium">
|
||||
{workspace.name || ''}
|
||||
</span>
|
||||
</div>
|
||||
<div className="hidden w-3/12 overflow-x-scroll md:block xl:w-3/12">
|
||||
<span className="font-medium">
|
||||
{moment(document.createdAt).format('lll')}
|
||||
</span>
|
||||
</div>
|
||||
<div className="w-5/12 2xsm:w-4/12 md:w-3/12 xl:w-2/12">
|
||||
<span className="inline-block rounded bg-green-500 bg-opacity-25 px-2.5 py-0.5 text-sm font-medium text-green-500">
|
||||
Cached
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className=" flex items-center gap-x-2">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
window.document
|
||||
.getElementById(
|
||||
`copy-document-${document.id}-modal`
|
||||
)
|
||||
?.showModal()
|
||||
}
|
||||
className="rounded-lg px-2 py-1 text-gray-400 transition-all duration-300 hover:bg-gray-50 hover:text-gray-600"
|
||||
>
|
||||
Clone
|
||||
</button>
|
||||
<a
|
||||
href={paths.document(
|
||||
organization.slug,
|
||||
workspace.slug,
|
||||
document.id
|
||||
)}
|
||||
className="rounded-lg px-2 py-1 text-blue-400 transition-all duration-300 hover:bg-blue-50 hover:text-blue-600"
|
||||
>
|
||||
Details
|
||||
</a>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => deleteDocument(document.id)}
|
||||
className="rounded-lg px-2 py-1 text-red-400 transition-all duration-300 hover:bg-red-50 hover:text-red-600"
|
||||
>
|
||||
Delete
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<CopyDocToModal
|
||||
key={`copy-document-${document.id}`}
|
||||
document={document}
|
||||
workspace={workspace}
|
||||
workspaces={workspaces}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<div>
|
||||
<div className="flex min-h-[40vh] w-full px-8">
|
||||
<div className="flex flex h-auto w-full flex-col items-center justify-center gap-y-2 rounded-lg bg-slate-50">
|
||||
{!!searchTerm ? (
|
||||
<p className="text-sm">
|
||||
No results on {SEARCH_MODES[searchBy].display} for{' '}
|
||||
<code className="bg-gray-200 px-2">"{searchTerm}"</code>
|
||||
</p>
|
||||
) : (
|
||||
<p className="text-sm">
|
||||
Type in a query to search for a document
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import UploadDocumentModal from './UploadModal';
|
||||
import UploadModalNoKey from './UploadModal/UploadModalNoKey';
|
||||
import Document from '../../../models/document';
|
||||
import useQuery from '../../../hooks/useQuery';
|
||||
import { APP_NAME, SEARCH_MODES } from '../../../utils/constants';
|
||||
import { APP_NAME, ISearchTypes, SEARCH_MODES } from '../../../utils/constants';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import DocumentListPagination from '../../../components/DocumentPaginator';
|
||||
import SearchView from './SearchView';
|
||||
@@ -40,6 +40,8 @@ export default function DocumentsList({
|
||||
const [documents, setDocuments] = useState([]);
|
||||
const [totalDocuments, setTotalDocuments] = useState(0);
|
||||
const [canUpload, setCanUpload] = useState(false);
|
||||
const [searchBy, setSearchBy] = useState<ISearchTypes>('exactText');
|
||||
const [searchResults, setSearchResults] = useState<any[]>([]);
|
||||
const [currentPage, setCurrentPage] = useState(
|
||||
Number(query.get('docPage')) || 1
|
||||
);
|
||||
@@ -69,6 +71,11 @@ export default function DocumentsList({
|
||||
document.getElementById(`document-row-${documentId}`)?.remove();
|
||||
};
|
||||
|
||||
const handleSearchResults = (results: any[]) => {
|
||||
setSearchResults(results);
|
||||
setSearchMode(true);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
async function getDocs(orgSlug: string, wsSlug?: string) {
|
||||
if (!orgSlug || !wsSlug) return false;
|
||||
@@ -87,7 +94,7 @@ export default function DocumentsList({
|
||||
|
||||
if (loading) {
|
||||
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 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">
|
||||
@@ -102,17 +109,6 @@ export default function DocumentsList({
|
||||
);
|
||||
}
|
||||
|
||||
if (searchMode)
|
||||
return (
|
||||
<SearchView
|
||||
organization={organization}
|
||||
workspace={workspace}
|
||||
workspaces={workspaces}
|
||||
stopSearching={() => setSearchMode(false)}
|
||||
deleteDocument={deleteDocument}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
@@ -120,7 +116,7 @@ export default function DocumentsList({
|
||||
style={{ height: `calc(100vh - ${searchMode ? '130px' : '130px'})` }}
|
||||
>
|
||||
<div className="flex items-start justify-between px-4">
|
||||
<div className="mb-6 flex items-center gap-x-2">
|
||||
<div className="mb-6 flex items-center gap-x-6">
|
||||
<div className="flex items-center gap-x-1">
|
||||
<span className="font-['Plus Jakarta Sans'] text-sm font-bold uppercase leading-[18px] tracking-wide text-white">
|
||||
Documents
|
||||
@@ -132,343 +128,106 @@ export default function DocumentsList({
|
||||
({workspace?.documentCount})
|
||||
</span>
|
||||
</div>
|
||||
{/* <button
|
||||
onClick={() => setSearchMode(true)}
|
||||
className="group flex items-center gap-2 rounded-lg bg-transparent px-4 py-2 hover:bg-blue-300/20"
|
||||
>
|
||||
<Search
|
||||
size={20}
|
||||
className="text-gray-600 group-hover:text-blue-600"
|
||||
/>
|
||||
<p className="pointer-events-none text-gray-600 transition-all duration-[300ms] group-hover:text-blue-600">
|
||||
Search documents
|
||||
</p>
|
||||
</button> */}
|
||||
<>
|
||||
<div className="w-full flex-1">
|
||||
<div className="flex items-center">
|
||||
<form
|
||||
ref={formEl}
|
||||
onSubmit={() => console.log('search')}
|
||||
className="w-full"
|
||||
>
|
||||
<div className="relative flex">
|
||||
<button
|
||||
onClick={() => setShowSearchMethods(!showSearchMethods)}
|
||||
className="z-10 inline-flex h-9 flex-shrink-0 items-center rounded-[100px] bg-zinc-700 px-5 text-center text-sm font-medium text-white transition-all duration-300 hover:bg-zinc-800 focus:outline-none"
|
||||
type="button"
|
||||
>
|
||||
{SEARCH_MODES['exactText'].display}
|
||||
<div
|
||||
className={`ml-2 transition-all duration-300 ${
|
||||
showSearchMethods ? '' : 'rotate-180'
|
||||
}`}
|
||||
>
|
||||
<CaretDown size={16} weight="bold" />
|
||||
</div>
|
||||
</button>
|
||||
<div
|
||||
className={`absolute left-0 top-12 z-99 w-44 divide-y divide-gray-100 rounded-lg bg-zinc-700 shadow ${
|
||||
showSearchMethods ? 'slide-down' : 'slide-up'
|
||||
}`}
|
||||
style={{
|
||||
animationDuration: '0.15s',
|
||||
}}
|
||||
>
|
||||
<ul
|
||||
className="py-2 text-sm text-white"
|
||||
aria-labelledby="dropdown-button"
|
||||
>
|
||||
{Object.keys(SEARCH_MODES).map((_key, i) => {
|
||||
const method = _key as ISearchTypes;
|
||||
return (
|
||||
<li key={i}>
|
||||
<button
|
||||
onClick={() => {
|
||||
setSearchBy(method);
|
||||
setShowSearchMethods(false);
|
||||
setSearchMode(false);
|
||||
}}
|
||||
type="button"
|
||||
className="inline-flex w-full px-4 py-2 hover:bg-zinc-800"
|
||||
>
|
||||
{SEARCH_MODES[method].display}
|
||||
</button>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
</div>
|
||||
<div className="relative w-full">
|
||||
<input
|
||||
name="query"
|
||||
className="z-20 -ml-4 block h-9 w-full rounded-r-[100px] bg-main-2 pl-8 text-sm text-white focus:outline-none"
|
||||
required
|
||||
/>
|
||||
{false ? (
|
||||
<div className="absolute right-0 top-0 mr-4.5 flex h-full p-2.5 text-sm font-medium text-white focus:outline-none">
|
||||
<div className="h-4 w-4 animate-spin rounded-full border-2 border-solid border-white border-t-transparent" />
|
||||
</div>
|
||||
) : searchMode ? (
|
||||
<button
|
||||
// onClick={clearSearch}
|
||||
className="absolute right-0 top-0 mr-4.5 flex h-full items-center justify-center p-2.5 text-sm font-medium text-white focus:outline-none"
|
||||
>
|
||||
<X
|
||||
size={16}
|
||||
className="text-sky-400 transition-all duration-300 hover:text-sky-700"
|
||||
weight="bold"
|
||||
/>
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
type="submit"
|
||||
className="absolute -right-1 top-0 mr-4.5 flex h-full items-center justify-center rounded-r-[100px] bg-[#303237] p-2.5 text-sm font-medium text-white focus:outline-none"
|
||||
>
|
||||
<MagnifyingGlass
|
||||
className="text-sky-400 transition-all duration-300 hover:text-sky-700"
|
||||
size={18}
|
||||
weight="bold"
|
||||
/>
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
<button
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
window.document
|
||||
?.getElementById('upload-document-modal')
|
||||
?.showModal();
|
||||
}}
|
||||
className="flex w-18 items-center justify-center rounded-[100px] bg-sky-400 px-2.5 text-xs"
|
||||
>
|
||||
<div className="font-bold uppercase text-black">
|
||||
Upload
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
<SearchView
|
||||
searchMode={searchMode}
|
||||
organization={organization}
|
||||
workspace={workspace}
|
||||
workspaces={workspaces}
|
||||
stopSearching={() => setSearchMode(false)}
|
||||
deleteDocument={deleteDocument}
|
||||
setSearchMode={setSearchMode}
|
||||
handleSearchResults={handleSearchResults}
|
||||
/>
|
||||
</div>
|
||||
{!!knownConnector ? (
|
||||
<button
|
||||
onClick={() => {
|
||||
document.getElementById('upload-document-modal')?.showModal();
|
||||
}}
|
||||
className="rounded-lg px-2 py-1 text-sm text-slate-800 hover:bg-slate-200"
|
||||
>
|
||||
Add Document
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
type="button"
|
||||
disabled={true}
|
||||
className="flex items-center gap-x-1 rounded-lg bg-red-50 px-2 py-1 text-sm text-red-800"
|
||||
>
|
||||
<AlertOctagon className="h4- w-4" /> Requires Vector Database
|
||||
Connection
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{documents.length > 0 ? (
|
||||
<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 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"
|
||||
>
|
||||
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>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<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"
|
||||
>
|
||||
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>
|
||||
</tr>
|
||||
</thead>
|
||||
{!searchMode && documents?.length > 0 && (
|
||||
<tbody className="bg-main">
|
||||
{documents.map((document, index) => (
|
||||
<>
|
||||
<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 size={16} weight="fill" />
|
||||
<p>{truncate(document?.name, 35)}</p>
|
||||
</td>
|
||||
<td className="px-6 ">
|
||||
{moment(document?.createdAt).format('lll')}
|
||||
</td>
|
||||
<td className="px-6 ">Cached</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={() =>
|
||||
window.document
|
||||
.getElementById(
|
||||
`copy-document-${document?.id}-modal`
|
||||
)
|
||||
?.showModal()
|
||||
}
|
||||
className="rounded-lg px-2 py-1 text-gray-400 transition-all duration-300 hover:bg-gray-50 hover:text-gray-600"
|
||||
>
|
||||
Clone
|
||||
</button>
|
||||
<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>
|
||||
<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>
|
||||
<CopyDocToModal
|
||||
key={`copy-document-${document?.id}`}
|
||||
document={document}
|
||||
workspace={workspace}
|
||||
workspaces={workspaces}
|
||||
/>
|
||||
</>
|
||||
<Fragment
|
||||
key={document?.id}
|
||||
document={document}
|
||||
index={index}
|
||||
deleteDocument={deleteDocument}
|
||||
organization={organization}
|
||||
workspace={workspace}
|
||||
workspaces={workspaces}
|
||||
/>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
{/* <>
|
||||
{documents.map((document) => {
|
||||
console.log(document);
|
||||
return (
|
||||
<div
|
||||
id={`document-row-${document.id}`}
|
||||
key={document.id}
|
||||
className="flex w-full items-center gap-5 px-7.5 py-3 text-white"
|
||||
>
|
||||
<div className="flex w-full items-center gap-3">
|
||||
<div className="w-2/12 xl:w-3/12">
|
||||
<div className="flex items-center gap-x-1">
|
||||
<File className="h-4 w-4" weight="fill" />
|
||||
<span className="hidden font-medium xl:block">
|
||||
{truncate(document.name, 20)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-6/12 2xsm:w-5/12 md:w-3/12">
|
||||
<span className="font-medium">
|
||||
{document.workspace.name || ''}
|
||||
</span>
|
||||
</div>
|
||||
<div className="hidden w-3/12 overflow-x-scroll md:block xl:w-3/12">
|
||||
<span className="font-medium">
|
||||
{moment(document.createdAt).format('lll')}
|
||||
</span>
|
||||
</div>
|
||||
<div className="w-5/12 2xsm:w-4/12 md:w-3/12 xl:w-2/12">
|
||||
<span className="inline-block rounded bg-green-500 bg-opacity-25 px-2.5 py-0.5 text-sm font-medium text-green-500">
|
||||
Cached
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{searchMode && searchResults?.length > 0 && (
|
||||
<tbody className="bg-main">
|
||||
{searchResults.map((document, index) => (
|
||||
<Fragment
|
||||
key={document?.id}
|
||||
document={document}
|
||||
index={index}
|
||||
deleteDocument={deleteDocument}
|
||||
organization={organization}
|
||||
workspace={workspace}
|
||||
workspaces={workspaces}
|
||||
/>
|
||||
))}
|
||||
</tbody>
|
||||
)}
|
||||
</table>
|
||||
|
||||
<div className=" flex items-center gap-x-2">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
window.document
|
||||
.getElementById(
|
||||
`copy-document-${document.id}-modal`
|
||||
)
|
||||
?.showModal()
|
||||
}
|
||||
className="rounded-lg px-2 py-1 text-gray-400 transition-all duration-300 hover:bg-gray-50 hover:text-gray-600"
|
||||
>
|
||||
Clone
|
||||
</button>
|
||||
<a
|
||||
href={paths.document(
|
||||
organization.slug,
|
||||
document.workspace.slug,
|
||||
document.id
|
||||
)}
|
||||
className="rounded-lg px-2 py-1 text-blue-400 transition-all duration-300 hover:bg-blue-50 hover:text-blue-600"
|
||||
>
|
||||
Details
|
||||
</a>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => deleteDocument(document.id)}
|
||||
className="rounded-lg px-2 py-1 text-red-400 transition-all duration-300 hover:bg-red-50 hover:text-red-600"
|
||||
>
|
||||
Delete
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<CopyDocToModal
|
||||
key={`copy-document-${document.id}`}
|
||||
document={document}
|
||||
workspace={workspace}
|
||||
workspaces={workspaces}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</> */}
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<div>
|
||||
<div className="flex min-h-[40vh] w-full px-8">
|
||||
<div className="flex flex h-auto w-full flex-col items-center justify-center gap-y-2 rounded-lg bg-slate-50">
|
||||
<p>You have no documents in any workspaces!</p>
|
||||
<p>
|
||||
Get started managing documents by adding them to workspaces
|
||||
via the UI or code.
|
||||
</p>
|
||||
<button
|
||||
type="button"
|
||||
className="text-xl text-blue-500 underline"
|
||||
>
|
||||
Show code example (coming soon)
|
||||
</button>
|
||||
{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>
|
||||
{/* <CodeExampleModal organization={organization} /> */}
|
||||
</>
|
||||
)}
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<DocumentListPagination
|
||||
pageCount={Math.ceil(totalDocuments! / Workspace.documentPageSize)}
|
||||
@@ -484,6 +243,81 @@ export default function DocumentsList({
|
||||
);
|
||||
}
|
||||
|
||||
const Fragment = ({
|
||||
document,
|
||||
index,
|
||||
deleteDocument,
|
||||
organization,
|
||||
workspace,
|
||||
workspaces,
|
||||
}: {
|
||||
document: any;
|
||||
index: number;
|
||||
deleteDocument: any;
|
||||
organization: any;
|
||||
workspace: any;
|
||||
workspaces: 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 size={16} weight="fill" />
|
||||
<p>{truncate(document?.name, 35)}</p>
|
||||
</td>
|
||||
<td className="px-6 ">{moment(document?.createdAt).format('lll')}</td>
|
||||
<td className="px-6 ">Cached</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={() =>
|
||||
window.document
|
||||
.getElementById(`copy-document-${document?.id}-modal`)
|
||||
?.showModal()
|
||||
}
|
||||
className="rounded-lg px-2 py-1 text-gray-400 transition-all duration-300 hover:bg-gray-50 hover:text-gray-600"
|
||||
>
|
||||
Clone
|
||||
</button>
|
||||
<a
|
||||
href={paths.document(
|
||||
organization.slug,
|
||||
workspace?.slug,
|
||||
document?.id
|
||||
)}
|
||||
className="rounded-lg px-2 py-1 text-sky-400 transition-all duration-300 hover:bg-blue-50"
|
||||
>
|
||||
Details
|
||||
</a>
|
||||
<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>
|
||||
<CopyDocToModal
|
||||
key={`copy-document-${document?.id}`}
|
||||
document={document}
|
||||
workspace={workspace}
|
||||
workspaces={workspaces}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const CopyDocToModal = memo(
|
||||
({
|
||||
document,
|
||||
|
||||
Reference in New Issue
Block a user