diff --git a/backend/open_webui/test/apps/webui/routers/test_documents.py b/backend/open_webui/test/apps/webui/routers/test_documents.py deleted file mode 100644 index 4d30b35e4..000000000 --- a/backend/open_webui/test/apps/webui/routers/test_documents.py +++ /dev/null @@ -1,105 +0,0 @@ -from test.util.abstract_integration_test import AbstractPostgresTest -from test.util.mock_user import mock_webui_user - - -class TestDocuments(AbstractPostgresTest): - BASE_PATH = "/api/v1/documents" - - def setup_class(cls): - super().setup_class() - from open_webui.apps.webui.models.documents import Documents - - cls.documents = Documents - - def test_documents(self): - # Empty database - assert len(self.documents.get_docs()) == 0 - with mock_webui_user(id="2"): - response = self.fast_api_client.get(self.create_url("/")) - assert response.status_code == 200 - assert len(response.json()) == 0 - - # Create a new document - with mock_webui_user(id="2"): - response = self.fast_api_client.post( - self.create_url("/create"), - json={ - "name": "doc_name", - "title": "doc title", - "collection_name": "custom collection", - "filename": "doc_name.pdf", - "content": "", - }, - ) - assert response.status_code == 200 - assert response.json()["name"] == "doc_name" - assert len(self.documents.get_docs()) == 1 - - # Get the document - with mock_webui_user(id="2"): - response = self.fast_api_client.get(self.create_url("/doc?name=doc_name")) - assert response.status_code == 200 - data = response.json() - assert data["collection_name"] == "custom collection" - assert data["name"] == "doc_name" - assert data["title"] == "doc title" - assert data["filename"] == "doc_name.pdf" - assert data["content"] == {} - - # Create another document - with mock_webui_user(id="2"): - response = self.fast_api_client.post( - self.create_url("/create"), - json={ - "name": "doc_name 2", - "title": "doc title 2", - "collection_name": "custom collection 2", - "filename": "doc_name2.pdf", - "content": "", - }, - ) - assert response.status_code == 200 - assert response.json()["name"] == "doc_name 2" - assert len(self.documents.get_docs()) == 2 - - # Get all documents - with mock_webui_user(id="2"): - response = self.fast_api_client.get(self.create_url("/")) - assert response.status_code == 200 - assert len(response.json()) == 2 - - # Update the first document - with mock_webui_user(id="2"): - response = self.fast_api_client.post( - self.create_url("/doc/update?name=doc_name"), - json={"name": "doc_name rework", "title": "updated title"}, - ) - assert response.status_code == 200 - data = response.json() - assert data["name"] == "doc_name rework" - assert data["title"] == "updated title" - - # Tag the first document - with mock_webui_user(id="2"): - response = self.fast_api_client.post( - self.create_url("/doc/tags"), - json={ - "name": "doc_name rework", - "tags": [{"name": "testing-tag"}, {"name": "another-tag"}], - }, - ) - assert response.status_code == 200 - data = response.json() - assert data["name"] == "doc_name rework" - assert data["content"] == { - "tags": [{"name": "testing-tag"}, {"name": "another-tag"}] - } - assert len(self.documents.get_docs()) == 2 - - # Delete the first document - with mock_webui_user(id="2"): - response = self.fast_api_client.delete( - self.create_url("/doc/delete?name=doc_name rework") - ) - assert response.status_code == 200 - assert len(self.documents.get_docs()) == 1 diff --git a/cypress/e2e/documents.cy.ts b/cypress/e2e/documents.cy.ts index 6ca14980d..b14b1de20 100644 --- a/cypress/e2e/documents.cy.ts +++ b/cypress/e2e/documents.cy.ts @@ -1,46 +1,2 @@ // eslint-disable-next-line @typescript-eslint/triple-slash-reference /// - -describe('Documents', () => { - const timestamp = Date.now(); - - before(() => { - cy.uploadTestDocument(timestamp); - }); - - after(() => { - cy.deleteTestDocument(timestamp); - }); - - context('Admin', () => { - beforeEach(() => { - // Login as the admin user - cy.loginAdmin(); - // Visit the home page - cy.visit('/workspace/documents'); - cy.get('button').contains('#cypress-test').click(); - }); - - it('can see documents', () => { - cy.get('div').contains(`document-test-initial-${timestamp}.txt`).should('have.length', 1); - }); - - it('can see edit button', () => { - cy.get('div') - .contains(`document-test-initial-${timestamp}.txt`) - .get("button[aria-label='Edit Doc']") - .should('exist'); - }); - - it('can see delete button', () => { - cy.get('div') - .contains(`document-test-initial-${timestamp}.txt`) - .get("button[aria-label='Delete Doc']") - .should('exist'); - }); - - it('can see upload button', () => { - cy.get("button[aria-label='Add Docs']").should('exist'); - }); - }); -}); diff --git a/cypress/support/e2e.ts b/cypress/support/e2e.ts index 984788733..0b94c4787 100644 --- a/cypress/support/e2e.ts +++ b/cypress/support/e2e.ts @@ -73,50 +73,6 @@ Cypress.Commands.add('register', (name, email, password) => register(name, email Cypress.Commands.add('registerAdmin', () => registerAdmin()); Cypress.Commands.add('loginAdmin', () => loginAdmin()); -Cypress.Commands.add('uploadTestDocument', (suffix: any) => { - // Login as admin - cy.loginAdmin(); - // upload example document - cy.visit('/workspace/documents'); - // Create a document - cy.get("button[aria-label='Add Docs']").click(); - cy.readFile('cypress/data/example-doc.txt').then((text) => { - // select file - cy.get('#upload-doc-input').selectFile( - { - contents: Cypress.Buffer.from(text + Date.now()), - fileName: `document-test-initial-${suffix}.txt`, - mimeType: 'text/plain', - lastModified: Date.now() - }, - { - force: true - } - ); - // open tag input - cy.get("button[aria-label='Add Tag']").click(); - cy.get("input[placeholder='Add a tag']").type('cypress-test'); - cy.get("button[aria-label='Save Tag']").click(); - - // submit to upload - cy.get("button[type='submit']").click(); - - // wait for upload to finish - cy.get('button').contains('#cypress-test').should('exist'); - cy.get('div').contains(`document-test-initial-${suffix}.txt`).should('exist'); - }); -}); - -Cypress.Commands.add('deleteTestDocument', (suffix: any) => { - cy.loginAdmin(); - cy.visit('/workspace/documents'); - // clean up uploaded documents - cy.get('div') - .contains(`document-test-initial-${suffix}.txt`) - .find("button[aria-label='Delete Doc']") - .click(); -}); - before(() => { cy.registerAdmin(); }); diff --git a/src/lib/apis/documents/index.ts b/src/lib/apis/documents/index.ts deleted file mode 100644 index 9d42feb19..000000000 --- a/src/lib/apis/documents/index.ts +++ /dev/null @@ -1,232 +0,0 @@ -import { WEBUI_API_BASE_URL } from '$lib/constants'; - -export const createNewDoc = async ( - token: string, - collection_name: string, - filename: string, - name: string, - title: string, - content: object | null = null -) => { - let error = null; - - const res = await fetch(`${WEBUI_API_BASE_URL}/documents/create`, { - method: 'POST', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - authorization: `Bearer ${token}` - }, - body: JSON.stringify({ - collection_name: collection_name, - filename: filename, - name: name, - title: title, - ...(content ? { content: JSON.stringify(content) } : {}) - }) - }) - .then(async (res) => { - if (!res.ok) throw await res.json(); - return res.json(); - }) - .catch((err) => { - error = err.detail; - console.log(err); - return null; - }); - - if (error) { - throw error; - } - - return res; -}; - -export const getDocs = async (token: string = '') => { - let error = null; - - const res = await fetch(`${WEBUI_API_BASE_URL}/documents/`, { - method: 'GET', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - authorization: `Bearer ${token}` - } - }) - .then(async (res) => { - if (!res.ok) throw await res.json(); - return res.json(); - }) - .then((json) => { - return json; - }) - .catch((err) => { - error = err.detail; - console.log(err); - return null; - }); - - if (error) { - throw error; - } - - return res; -}; - -export const getDocByName = async (token: string, name: string) => { - let error = null; - - const searchParams = new URLSearchParams(); - searchParams.append('name', name); - - const res = await fetch(`${WEBUI_API_BASE_URL}/documents/docs?${searchParams.toString()}`, { - method: 'GET', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - authorization: `Bearer ${token}` - } - }) - .then(async (res) => { - if (!res.ok) throw await res.json(); - return res.json(); - }) - .then((json) => { - return json; - }) - .catch((err) => { - error = err.detail; - - console.log(err); - return null; - }); - - if (error) { - throw error; - } - - return res; -}; - -type DocUpdateForm = { - name: string; - title: string; -}; - -export const updateDocByName = async (token: string, name: string, form: DocUpdateForm) => { - let error = null; - - const searchParams = new URLSearchParams(); - searchParams.append('name', name); - - const res = await fetch(`${WEBUI_API_BASE_URL}/documents/doc/update?${searchParams.toString()}`, { - method: 'POST', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - authorization: `Bearer ${token}` - }, - body: JSON.stringify({ - name: form.name, - title: form.title - }) - }) - .then(async (res) => { - if (!res.ok) throw await res.json(); - return res.json(); - }) - .then((json) => { - return json; - }) - .catch((err) => { - error = err.detail; - - console.log(err); - return null; - }); - - if (error) { - throw error; - } - - return res; -}; - -type TagDocForm = { - name: string; - tags: string[]; -}; - -export const tagDocByName = async (token: string, name: string, form: TagDocForm) => { - let error = null; - - const searchParams = new URLSearchParams(); - searchParams.append('name', name); - - const res = await fetch(`${WEBUI_API_BASE_URL}/documents/doc/tags?${searchParams.toString()}`, { - method: 'POST', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - authorization: `Bearer ${token}` - }, - body: JSON.stringify({ - name: form.name, - tags: form.tags - }) - }) - .then(async (res) => { - if (!res.ok) throw await res.json(); - return res.json(); - }) - .then((json) => { - return json; - }) - .catch((err) => { - error = err.detail; - - console.log(err); - return null; - }); - - if (error) { - throw error; - } - - return res; -}; - -export const deleteDocByName = async (token: string, name: string) => { - let error = null; - - const searchParams = new URLSearchParams(); - searchParams.append('name', name); - - const res = await fetch(`${WEBUI_API_BASE_URL}/documents/doc/delete?${searchParams.toString()}`, { - method: 'DELETE', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - authorization: `Bearer ${token}` - } - }) - .then(async (res) => { - if (!res.ok) throw await res.json(); - return res.json(); - }) - .then((json) => { - return json; - }) - .catch((err) => { - error = err.detail; - - console.log(err); - return null; - }); - - if (error) { - throw error; - } - - return res; -}; diff --git a/src/lib/components/documents/AddDocModal.svelte b/src/lib/components/documents/AddDocModal.svelte deleted file mode 100644 index 8c4d478f7..000000000 --- a/src/lib/components/documents/AddDocModal.svelte +++ /dev/null @@ -1,166 +0,0 @@ - - - -
-
-
{$i18n.t('Add Docs')}
- -
-
-
-
{ - submitHandler(); - }} - > -
- - - -
- -
-
-
{$i18n.t('Tags')}
- - -
-
- -
- -
-
-
-
-
-
- - diff --git a/src/lib/components/documents/EditDocModal.svelte b/src/lib/components/documents/EditDocModal.svelte deleted file mode 100644 index 47577bd48..000000000 --- a/src/lib/components/documents/EditDocModal.svelte +++ /dev/null @@ -1,181 +0,0 @@ - - - -
-
-
{$i18n.t('Edit Doc')}
- -
-
-
-
{ - submitHandler(); - }} - > -
-
-
{$i18n.t('Name Tag')}
- -
-
- # -
- -
-
- -
-
{$i18n.t('Title')}
- -
- -
-
- -
-
{$i18n.t('Tags')}
- - -
-
- -
- -
-
-
-
-
-
- - diff --git a/src/lib/components/workspace/Documents.svelte b/src/lib/components/workspace/Documents.svelte deleted file mode 100644 index 0fa50278c..000000000 --- a/src/lib/components/workspace/Documents.svelte +++ /dev/null @@ -1,627 +0,0 @@ - - - - - {$i18n.t('Documents')} | {$WEBUI_NAME} - - - -{#if dragged} -
-
-
-
- -
- Drop any files here to add to my documents -
-
-
-
-
-
-{/if} - -{#key selectedDoc} - -{/key} - - - -
-
-
- {$i18n.t('Documents')} -
- {$documents.length} -
-
-
- -
-
-
- - - -
- -
- -
- -
-
- - - -
- -{#if tags.length > 0} -
-
- doc?.selected === 'checked').length === - filteredDocs.length - ? 'checked' - : 'unchecked'} - indeterminate={filteredDocs.filter((doc) => doc?.selected === 'checked').length > 0 && - filteredDocs.filter((doc) => doc?.selected === 'checked').length !== filteredDocs.length} - on:change={(e) => { - if (e.detail === 'checked') { - filteredDocs = filteredDocs.map((doc) => ({ ...doc, selected: 'checked' })); - } else if (e.detail === 'unchecked') { - filteredDocs = filteredDocs.map((doc) => ({ ...doc, selected: 'unchecked' })); - } - }} - /> -
- - {#if filteredDocs.filter((doc) => doc?.selected === 'checked').length === 0} - - - {#each tags as tag} - - {/each} - {:else} -
-
- {filteredDocs.filter((doc) => doc?.selected === 'checked').length} Selected -
- -
- - - -
-
- {/if} -
-{/if} - -
- {#each filteredDocs as doc} - - - - - -
- - {/each} -
- -
- ⓘ {$i18n.t("Use '#' in the prompt input to load and select your documents.")} -
- -
-
- { - console.log(importFiles); - - const reader = new FileReader(); - reader.onload = async (event) => { - const savedDocs = JSON.parse(event.target.result); - console.log(savedDocs); - - for (const doc of savedDocs) { - await createNewDoc( - localStorage.token, - doc.collection_name, - doc.filename, - doc.name, - doc.title, - doc.content - ).catch((error) => { - toast.error(error); - return null; - }); - } - - await documents.set(await getDocs(localStorage.token)); - }; - - reader.readAsText(importFiles[0]); - }} - /> - - - - -
-
diff --git a/src/routes/(app)/admin/+layout.svelte b/src/routes/(app)/admin/+layout.svelte index 7a2fc3c11..d3eaa3a27 100644 --- a/src/routes/(app)/admin/+layout.svelte +++ b/src/routes/(app)/admin/+layout.svelte @@ -67,22 +67,6 @@ : ''} transition" href="/admin/settings">{$i18n.t('Settings')} - -