diff --git a/ee/tabby-db/migrations/0042_page-section.up.sql b/ee/tabby-db/migrations/0042_page-section.up.sql index faac8e45b267..6ed347029b53 100644 --- a/ee/tabby-db/migrations/0042_page-section.up.sql +++ b/ee/tabby-db/migrations/0042_page-section.up.sql @@ -5,7 +5,7 @@ CREATE TABLE pages( author_id INTEGER NOT NULL, title TEXT, - summary TEXT, + content TEXT, created_at TIMESTAMP NOT NULL DEFAULT (DATETIME('now')), updated_at TIMESTAMP NOT NULL DEFAULT (DATETIME('now')), @@ -17,14 +17,11 @@ CREATE TABLE page_sections( id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, page_id INTEGER NOT NULL, - position INTEGER NOT NULL, - title TEXT NOT NULL, content TEXT NOT NULL, created_at TIMESTAMP NOT NULL DEFAULT (DATETIME('now')), updated_at TIMESTAMP NOT NULL DEFAULT (DATETIME('now')), - FOREIGN KEY(page_id) REFERENCES pages(id) ON DELETE CASCADE, - CONSTRAINT `page_id_position` UNIQUE(page_id, position) + FOREIGN KEY(page_id) REFERENCES pages(id) ON DELETE CASCADE ); diff --git a/ee/tabby-db/schema.sqlite b/ee/tabby-db/schema.sqlite index f6d9acf109e6..92a11f41ba3b 100644 Binary files a/ee/tabby-db/schema.sqlite and b/ee/tabby-db/schema.sqlite differ diff --git a/ee/tabby-db/schema/schema.sql b/ee/tabby-db/schema/schema.sql index 78e20c951681..12a9bab4ca40 100644 --- a/ee/tabby-db/schema/schema.sql +++ b/ee/tabby-db/schema/schema.sql @@ -266,7 +266,7 @@ CREATE TABLE pages( -- The user who created the page author_id INTEGER NOT NULL, title TEXT, - summary TEXT, + content TEXT, created_at TIMESTAMP NOT NULL DEFAULT(DATETIME('now')), updated_at TIMESTAMP NOT NULL DEFAULT(DATETIME('now')), FOREIGN KEY(author_id) REFERENCES users(id) ON DELETE CASCADE @@ -274,11 +274,9 @@ CREATE TABLE pages( CREATE TABLE page_sections( id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, page_id INTEGER NOT NULL, - position INTEGER NOT NULL, title TEXT NOT NULL, content TEXT NOT NULL, created_at TIMESTAMP NOT NULL DEFAULT(DATETIME('now')), updated_at TIMESTAMP NOT NULL DEFAULT(DATETIME('now')), - FOREIGN KEY(page_id) REFERENCES pages(id) ON DELETE CASCADE, - CONSTRAINT `page_id_position` UNIQUE(page_id, position) + FOREIGN KEY(page_id) REFERENCES pages(id) ON DELETE CASCADE ); diff --git a/ee/tabby-db/schema/schema.svg b/ee/tabby-db/schema/schema.svg index 41f09841c62c..c893828be175 100644 --- a/ee/tabby-db/schema/schema.svg +++ b/ee/tabby-db/schema/schema.svg @@ -4,11 +4,11 @@ - - + + structs - + _sqlx_migrations @@ -252,208 +252,204 @@ notifications - -notifications - -🔑 - -id - -  - -created_at - -  - -updated_at - -  - -recipient - -  - -content + +notifications + +🔑 + +id + +  + +created_at + +  + +updated_at + +  + +recipient + +  + +content oauth_credential - -oauth_credential - -🔑 - -id - -  - -provider - -  - -client_id - -  - -client_secret - -  - -created_at - -  - -updated_at + +oauth_credential + +🔑 + +id + +  + +provider + +  + +client_id + +  + +client_secret + +  + +created_at + +  + +updated_at page_sections - -page_sections - -🔑 - -id - -  - -page_id - -  - -position - -  - -title - -  - -content - -  - -created_at - -  - -updated_at + +page_sections + +🔑 + +id + +  + +page_id + +  + +title + +  + +content + +  + +created_at + +  + +updated_at pages - -pages - -🔑 - -id - -  - -author_id - -  - -title - -  - -summary - -  - -created_at - -  - -updated_at + +pages + +🔑 + +id + +  + +author_id + +  + +title + +  + +content + +  + +created_at + +  + +updated_at page_sections:e->pages:w - - + + users - -users - -🔑 - -id - -  - -email - -  - -is_admin - -  - -created_at - -  - -updated_at - -  - -auth_token - -  - -active - -  - -password_encrypted - -  - -avatar - -  - -name + +users + +🔑 + +id + +  + +email + +  + +is_admin + +  + +created_at + +  + +updated_at + +  + +auth_token + +  + +active + +  + +password_encrypted + +  + +avatar + +  + +name pages:e->users:w - - + + password_reset - -password_reset - -🔑 - -id - -  - -user_id - -  - -code - -  - -created_at + +password_reset + +🔑 + +id + +  + +user_id + +  + +code + +  + +created_at password_reset:e->users:w - - + + @@ -502,432 +498,432 @@ read_notifications - -read_notifications - -🔑 - -id - -  - -user_id - -  - -notification_id - -  - -created_at - -  - -updated_at + +read_notifications + +🔑 + +id + +  + +user_id + +  + +notification_id + +  + +created_at + +  + +updated_at read_notifications:e->notifications:w - - + + read_notifications:e->users:w - - + + refresh_tokens - -refresh_tokens - -🔑 - -id - -  - -user_id - -  - -token - -  - -expires_at - -  - -created_at + +refresh_tokens + +🔑 + +id + +  + +user_id + +  + +token + +  + +expires_at + +  + +created_at refresh_tokens:e->users:w - - + + registration_token - -registration_token - -🔑 - -id - -  - -token - -  - -created_at - -  - -updated_at + +registration_token + +🔑 + +id + +  + +token + +  + +created_at + +  + +updated_at repositories - -repositories - -🔑 - -id - -  - -name - -  - -git_url + +repositories + +🔑 + +id + +  + +name + +  + +git_url server_setting - -server_setting - -🔑 - -id - -  - -security_allowed_register_domain_list - -  - -security_disable_client_side_telemetry - -  - -network_external_url - -  - -billing_enterprise_license + +server_setting + +🔑 + +id + +  + +security_allowed_register_domain_list + +  + +security_disable_client_side_telemetry + +  + +network_external_url + +  + +billing_enterprise_license source_id_read_access_policies - -source_id_read_access_policies - -🔑 - -id - -  - -source_id - -  - -user_group_id - -  - -created_at - -  - -updated_at + +source_id_read_access_policies + +🔑 + +id + +  + +source_id + +  + +user_group_id + +  + +created_at + +  + +updated_at user_groups - -user_groups - -🔑 - -id - -  - -name - -  - -created_at - -  - -updated_at + +user_groups + +🔑 + +id + +  + +name + +  + +created_at + +  + +updated_at source_id_read_access_policies:e->user_groups:w - - + + thread_messages - -thread_messages - -🔑 - -id - -  - -thread_id - -  - -role - -  - -content - -  - -code_attachments - -  - -client_code_attachments - -  - -doc_attachments - -  - -created_at - -  - -updated_at - -  - -code_source_id + +thread_messages + +🔑 + +id + +  + +thread_id + +  + +role + +  + +content + +  + +code_attachments + +  + +client_code_attachments + +  + +doc_attachments + +  + +created_at + +  + +updated_at + +  + +code_source_id threads - -threads - -🔑 - -id - -  - -is_ephemeral - -  - -user_id - -  - -created_at - -  - -updated_at - -  - -relevant_questions + +threads + +🔑 + +id + +  + +is_ephemeral + +  + +user_id + +  + +created_at + +  + +updated_at + +  + +relevant_questions thread_messages:e->threads:w - - + + threads:e->users:w - - + + user_completions - -user_completions - -🔑 - -id - -  - -user_id - -  - -completion_id - -  - -language - -  - -views - -  - -selects - -  - -dismisses - -  - -created_at - -  - -updated_at + +user_completions + +🔑 + +id + +  + +user_id + +  + +completion_id + +  + +language + +  + +views + +  + +selects + +  + +dismisses + +  + +created_at + +  + +updated_at user_completions:e->users:w - - + + user_events - -user_events - -🔑 - -id - -  - -user_id - -  - -kind - -  - -created_at - -  - -payload + +user_events + +🔑 + +id + +  + +user_id + +  + +kind + +  + +created_at + +  + +payload user_events:e->users:w - - + + user_group_memberships - -user_group_memberships - -🔑 - -id - -  - -user_id - -  - -user_group_id - -  - -is_group_admin - -  - -created_at - -  - -updated_at + +user_group_memberships + +🔑 + +id + +  + +user_id + +  + +user_group_id + +  + +is_group_admin + +  + +created_at + +  + +updated_at user_group_memberships:e->user_groups:w - - + + user_group_memberships:e->users:w - - + + web_documents - -web_documents - -🔑 - -id - -  - -name - -  - -url - -  - -is_preset - -  - -created_at - -  - -updated_at + +web_documents + +🔑 + +id + +  + +name + +  + +url + +  + +is_preset + +  + +created_at + +  + +updated_at diff --git a/ee/tabby-db/src/lib.rs b/ee/tabby-db/src/lib.rs index e28ee27c23c0..7f1d418cc20b 100644 --- a/ee/tabby-db/src/lib.rs +++ b/ee/tabby-db/src/lib.rs @@ -11,7 +11,7 @@ pub use job_runs::JobRunDAO; pub use ldap_credential::LdapCredentialDAO; pub use notifications::NotificationDAO; pub use oauth_credential::OAuthCredentialDAO; -pub use pages::PageDAO; +pub use pages::{PageDAO, PageSectionDAO}; pub use provided_repositories::ProvidedRepositoryDAO; pub use repositories::RepositoryDAO; pub use server_setting::ServerSettingDAO; diff --git a/ee/tabby-db/src/pages.rs b/ee/tabby-db/src/pages.rs index 3b0e2a7d9b84..b87468dd444a 100644 --- a/ee/tabby-db/src/pages.rs +++ b/ee/tabby-db/src/pages.rs @@ -10,7 +10,7 @@ pub struct PageDAO { pub id: i64, pub author_id: i64, pub title: Option, - pub summary: Option, + pub content: Option, pub created_at: DateTime, pub updated_at: DateTime, } @@ -20,7 +20,6 @@ pub struct PageSectionDAO { pub id: i64, pub page_id: i64, - pub position: i64, pub title: String, pub content: String, @@ -37,26 +36,6 @@ impl DbConn { Ok(res.last_insert_rowid()) } - pub async fn create_page_section( - &self, - page_id: i64, - position: i64, - title: &str, - content: &str, - ) -> Result { - let res = query!( - "INSERT INTO page_sections(page_id, position, title, content) VALUES (?, ?, ?, ?)", - page_id, - position, - title, - content - ) - .execute(&self.pool) - .await?; - - Ok(res.last_insert_rowid()) - } - pub async fn update_page_title(&self, page_id: i64, title: &str) -> Result<()> { query!( "UPDATE pages SET title = ?, updated_at = DATETIME('now') WHERE id = ?", @@ -69,10 +48,10 @@ impl DbConn { Ok(()) } - pub async fn update_page_summary(&self, page_id: i64, summary: &str) -> Result<()> { + pub async fn update_page_content(&self, page_id: i64, content: &str) -> Result<()> { query!( - "UPDATE pages SET summary = ?, updated_at = DATETIME('now') WHERE id = ?", - summary, + "UPDATE pages SET content = ?, updated_at = DATETIME('now') WHERE id = ?", + content, page_id ) .execute(&self.pool) @@ -106,7 +85,7 @@ impl DbConn { "id", "author_id", "title", - "summary", + "content", "created_at" as "created_at: DateTime", "updated_at" as "updated_at: DateTime" ], @@ -136,7 +115,7 @@ impl DbConn { id, author_id, title, - summary, + content, created_at as "created_at: DateTime", updated_at as "updated_at: DateTime" FROM pages @@ -163,7 +142,6 @@ impl DbConn { [ "id", "page_id", - "position", "title", "content", "created_at" as "created_at: DateTime", @@ -179,4 +157,50 @@ impl DbConn { Ok(sections) } + + pub async fn get_page_section(&self, id: i64) -> Result> { + let section = query_as!( + PageSectionDAO, + r#"SELECT + id, + page_id, + title, + content, + created_at as "created_at: DateTime", + updated_at as "updated_at: DateTime" + FROM page_sections + WHERE id = ?"#, + id + ) + .fetch_optional(&self.pool) + .await?; + + Ok(section) + } + + pub async fn create_page_section( + &self, + page_id: i64, + title: &str, + content: &str, + ) -> Result { + let res = query!( + "INSERT INTO page_sections(page_id, title, content) VALUES (?, ?, ?)", + page_id, + title, + content + ) + .execute(&self.pool) + .await?; + + Ok(res.last_insert_rowid()) + } + + pub async fn delete_page_section(&self, id: i64) -> Result<()> { + query!("DELETE FROM page_sections WHERE id = ?", id,) + .execute(&self.pool) + .await?; + + Ok(()) + } } diff --git a/ee/tabby-schema/graphql/schema.graphql b/ee/tabby-schema/graphql/schema.graphql index 892615efc7bc..a8e39485e8ca 100644 --- a/ee/tabby-schema/graphql/schema.graphql +++ b/ee/tabby-schema/graphql/schema.graphql @@ -112,6 +112,11 @@ enum Role { ASSISTANT } +input AddPageSectionInput { + pageId: ID! + title: String! +} + input CodeQueryInput { filepath: String language: String @@ -206,12 +211,6 @@ input PasswordResetInput { password2: String! } -input ReorderSectionInput { - pageId: ID! - id: ID! - position: Int! -} - input RequestInvitationInput { email: String! } @@ -275,13 +274,6 @@ input UpdateOAuthCredentialInput { clientSecret: String } -input UpdateSectionInput { - pageId: ID! - id: ID! - title: String! - regenerate: Boolean! -} - input UpsertUserGroupMembershipInput { userGroupId: ID! userId: ID! @@ -665,13 +657,24 @@ type Mutation { "Turn on persisted status for a thread." setThreadPersisted(threadId: ID!): Boolean! updateThreadMessage(input: UpdateMessageInput!): Boolean! + """ + Utilize an existing thread and its messages to create a page. + This will automatically generate the page title and a summary of the content. + + Every two messages will be converted into a page section. + The user's message will serve as the title of the section. + The assistant's message will become the content of the section. + """ convertThreadToPage(threadId: ID!): ID! - generatePageTitle(id: ID!): String! - generatePageSummary(id: ID!): String! + "delete a page and all its sections." deletePage(id: ID!): Boolean! - updatePageSection(input: UpdateSectionInput!): Section! - reorderPageSections(input: ReorderSectionInput!): Boolean! - deletePageSection(pageId: ID!, sectionId: ID!): Boolean! + """ + Creates a new page section. + Only the title is required; the answer will be generated as the content. + """ + addPageSection(input: AddPageSectionInput!): ID! + "delete a single page section." + deletePageSection(sectionId: ID!): Boolean! createCustomDocument(input: CreateCustomDocumentInput!): ID! deleteCustomDocument(id: ID!): Boolean! setPresetDocumentActive(input: SetPresetDocumentActiveInput!): Boolean! @@ -706,7 +709,7 @@ type Page { id: ID! authorId: ID! title: String - summary: String + content: String createdAt: DateTime! updatedAt: DateTime! } @@ -827,6 +830,7 @@ type Query { Thread is public within an instance, so no need to check for ownership. """ threadMessages(threadId: ID!, after: String, before: String, first: Int, last: Int): MessageConnection! + "Read pages by page IDs." pages(ids: [ID!], after: String, before: String, first: Int, last: Int): PageConnection! pageSections(pageId: ID!, after: String, before: String, first: Int, last: Int): SectionConnection! customWebDocuments(ids: [ID!], after: String, before: String, first: Int, last: Int): CustomDocumentConnection! @@ -878,7 +882,6 @@ type RepositoryGrepOutput { type Section { id: ID! pageId: ID! - position: Int! title: String! content: String! createdAt: DateTime! diff --git a/ee/tabby-schema/src/dao.rs b/ee/tabby-schema/src/dao.rs index 47fc38cf294e..22d20723a56c 100644 --- a/ee/tabby-schema/src/dao.rs +++ b/ee/tabby-schema/src/dao.rs @@ -3,9 +3,10 @@ use hash_ids::HashIds; use lazy_static::lazy_static; use tabby_db::{ EmailSettingDAO, IntegrationDAO, InvitationDAO, JobRunDAO, LdapCredentialDAO, NotificationDAO, - OAuthCredentialDAO, PageDAO, ServerSettingDAO, ThreadDAO, ThreadMessageAttachmentClientCode, - ThreadMessageAttachmentCode, ThreadMessageAttachmentDoc, ThreadMessageAttachmentIssueDoc, - ThreadMessageAttachmentPullDoc, ThreadMessageAttachmentWebDoc, UserEventDAO, + OAuthCredentialDAO, PageDAO, PageSectionDAO, ServerSettingDAO, ThreadDAO, + ThreadMessageAttachmentClientCode, ThreadMessageAttachmentCode, ThreadMessageAttachmentDoc, + ThreadMessageAttachmentIssueDoc, ThreadMessageAttachmentPullDoc, ThreadMessageAttachmentWebDoc, + UserEventDAO, }; use crate::{ @@ -354,7 +355,20 @@ impl From for page::Page { id: value.id.as_id(), author_id: value.author_id.as_id(), title: value.title, - summary: value.summary, + content: value.content, + created_at: value.created_at, + updated_at: value.updated_at, + } + } +} + +impl From for page::Section { + fn from(value: PageSectionDAO) -> Self { + Self { + id: value.id.as_id(), + page_id: value.page_id.as_id(), + title: value.title, + content: value.content, created_at: value.created_at, updated_at: value.updated_at, } diff --git a/ee/tabby-schema/src/schema/mod.rs b/ee/tabby-schema/src/schema/mod.rs index 9c89da9ef89d..46c6d2206231 100644 --- a/ee/tabby-schema/src/schema/mod.rs +++ b/ee/tabby-schema/src/schema/mod.rs @@ -699,6 +699,7 @@ impl Query { .await } + /// Read pages by page IDs. async fn pages( ctx: &Context, ids: Option>, @@ -708,7 +709,20 @@ impl Query { last: Option, ) -> Result> { check_user(ctx).await?; - Err(CoreError::Other(anyhow::anyhow!("Not implemented"))) + + relay::query_async( + after, + before, + first, + last, + |after, before, first, last| async move { + ctx.locator + .page() + .list(ids.as_deref(), after, before, first, last) + .await + }, + ) + .await } async fn page_sections( @@ -720,7 +734,20 @@ impl Query { last: Option, ) -> Result> { check_user(ctx).await?; - Err(CoreError::Other(anyhow::anyhow!("Not implemented"))) + + relay::query_async( + after, + before, + first, + last, + |after, before, first, last| async move { + ctx.locator + .page() + .list_sections(&page_id, after, before, first, last) + .await + }, + ) + .await } async fn custom_web_documents( @@ -1333,6 +1360,13 @@ impl Mutation { } // page mutations + + /// Utilize an existing thread and its messages to create a page. + /// This will automatically generate the page title and a summary of the content. + /// + /// Every two messages will be converted into a page section. + /// The user's message will serve as the title of the section. + /// The assistant's message will become the content of the section. async fn convert_thread_to_page(ctx: &Context, thread_id: ID) -> Result { let user = check_user(ctx).await?; @@ -1340,26 +1374,7 @@ impl Mutation { svc.convert_thread_to_page(&user.id, &thread_id).await } - async fn generate_page_title(ctx: &Context, id: ID) -> Result { - let user = check_user(ctx).await?; - - let svc = ctx.locator.page(); - let page = svc.get(&id).await?; - - user.policy.check_update_page(&page.author_id)?; - svc.generate_page_title(&id).await - } - - async fn generate_page_summary(ctx: &Context, id: ID) -> Result { - let user = check_user(ctx).await?; - - let svc = ctx.locator.page(); - let page = svc.get(&id).await?; - - user.policy.check_update_page(&page.author_id)?; - svc.generate_page_summary(&id).await - } - + /// delete a page and all its sections. async fn delete_page(ctx: &Context, id: ID) -> Result { let user = check_user(ctx).await?; @@ -1370,43 +1385,30 @@ impl Mutation { svc.delete(&id).await.map(|_| true) } - async fn update_page_section( - ctx: &Context, - input: page::UpdateSectionInput, - ) -> Result { + /// Creates a new page section. + /// Only the title is required; the answer will be generated as the content. + async fn add_page_section(ctx: &Context, input: page::AddPageSectionInput) -> Result { let user = check_user(ctx).await?; let svc = ctx.locator.page(); let page = svc.get(&input.page_id).await?; user.policy.check_update_page(&page.author_id)?; - svc.update_section(&input).await - } - - // when update a section order, the order of the rest of the sections will be updated - async fn reorder_page_sections( - ctx: &Context, - input: page::ReorderSectionInput, - ) -> Result { - let user = check_user(ctx).await?; - let svc = ctx.locator.page(); - let page = svc.get(&input.page_id).await?; - - user.policy.check_update_page(&page.author_id)?; - svc.reorder_section(&input).await.map(|_| true) + svc.add_section(&input).await } - async fn delete_page_section(ctx: &Context, page_id: ID, section_id: ID) -> Result { + /// delete a single page section. + async fn delete_page_section(ctx: &Context, section_id: ID) -> Result { let user = check_user(ctx).await?; let svc = ctx.locator.page(); - let page = svc.get(&page_id).await?; + let section = svc.get_section(§ion_id).await?; + let page = svc.get(§ion.page_id).await?; user.policy.check_update_page(&page.author_id)?; - svc.delete_section(&page_id, §ion_id) - .await - .map(|_| true) + + svc.delete_section(§ion_id).await.map(|_| true) } async fn create_custom_document(ctx: &Context, input: CreateCustomDocumentInput) -> Result { diff --git a/ee/tabby-schema/src/schema/page.rs b/ee/tabby-schema/src/schema/page.rs index af25b9bcfadf..be620938fa48 100644 --- a/ee/tabby-schema/src/schema/page.rs +++ b/ee/tabby-schema/src/schema/page.rs @@ -10,9 +10,8 @@ pub trait PageService: Send + Sync { async fn convert_thread_to_page(&self, author_id: &ID, thread_id: &ID) -> Result; async fn generate_page_title(&self, id: &ID) -> Result; - async fn generate_page_summary(&self, id: &ID) -> Result; + async fn generate_page_content(&self, id: &ID) -> Result; - async fn get(&self, id: &ID) -> Result; async fn list( &self, ids: Option<&[ID]>, @@ -21,11 +20,18 @@ pub trait PageService: Send + Sync { first: Option, last: Option, ) -> Result>; + async fn get(&self, id: &ID) -> Result; async fn delete(&self, id: &ID) -> Result<()>; - async fn update_section(&self, input: &UpdateSectionInput) -> Result
; - async fn reorder_section(&self, input: &ReorderSectionInput) -> Result<()>; - - async fn get_section(&self, page_id: &ID, id: &ID) -> Result
; - async fn delete_section(&self, page_id: &ID, id: &ID) -> Result<()>; + async fn list_sections( + &self, + page_id: &ID, + after: Option, + before: Option, + first: Option, + last: Option, + ) -> Result>; + async fn add_section(&self, input: &AddPageSectionInput) -> Result; + async fn get_section(&self, id: &ID) -> Result
; + async fn delete_section(&self, id: &ID) -> Result<()>; } diff --git a/ee/tabby-schema/src/schema/page/types.rs b/ee/tabby-schema/src/schema/page/types.rs index aa11a4d0d752..29231e5d6b7e 100644 --- a/ee/tabby-schema/src/schema/page/types.rs +++ b/ee/tabby-schema/src/schema/page/types.rs @@ -9,7 +9,7 @@ pub struct Page { pub id: ID, pub author_id: ID, pub title: Option, - pub summary: Option, + pub content: Option, pub created_at: DateTime, pub updated_at: DateTime, } @@ -35,7 +35,6 @@ impl NodeType for Page { pub struct Section { pub id: ID, pub page_id: ID, - pub position: i32, pub title: String, pub content: String, @@ -60,16 +59,7 @@ impl NodeType for Section { } #[derive(GraphQLInputObject)] -pub struct UpdateSectionInput { +pub struct AddPageSectionInput { pub page_id: ID, - pub id: ID, pub title: String, - pub regenerate: bool, -} - -#[derive(GraphQLInputObject)] -pub struct ReorderSectionInput { - pub page_id: ID, - pub id: ID, - pub position: i32, } diff --git a/ee/tabby-webserver/src/service/page.rs b/ee/tabby-webserver/src/service/page.rs index aabcd328ea38..1f829d1a03fc 100644 --- a/ee/tabby-webserver/src/service/page.rs +++ b/ee/tabby-webserver/src/service/page.rs @@ -1,12 +1,11 @@ use std::sync::Arc; -use anyhow::anyhow; use async_trait::async_trait; use juniper::ID; use tabby_db::DbConn; use tabby_schema::{ auth::AuthenticationService, - page::{Page, PageService, ReorderSectionInput, Section, UpdateSectionInput}, + page::{AddPageSectionInput, Page, PageService, Section}, thread::ThreadService, AsID, AsRowid, CoreError, Result, }; @@ -49,32 +48,32 @@ impl PageService for PageServiceImpl { .list_thread_messages(thread_id, None, None, None, None) .await?; - for (i, qa) in messages.chunks(2).enumerate() { + for qa in messages.chunks(2) { if let [question, answer] = qa { let question = question.content.clone(); let answer = answer.content.clone(); self.db - .create_page_section(page_id, i as i64, &question, &answer) + .create_page_section(page_id, &question, &answer) .await?; } } self.generate_page_title(&page_id.as_id()).await?; - self.generate_page_summary(&page_id.as_id()).await?; + self.generate_page_content(&page_id.as_id()).await?; Ok(page_id.as_id()) } - //TODO: generate page title and summary + //TODO: generate page title and content async fn generate_page_title(&self, id: &ID) -> Result { self.db.update_page_title(id.as_rowid()?, "Title").await?; Ok("Title".into()) } - async fn generate_page_summary(&self, id: &ID) -> Result { + async fn generate_page_content(&self, id: &ID) -> Result { self.db - .update_page_summary(id.as_rowid()?, "Summary") + .update_page_content(id.as_rowid()?, "Content") .await?; - Ok("Summary".into()) + Ok("Content".into()) } async fn delete(&self, id: &ID) -> Result<()> { @@ -114,19 +113,44 @@ impl PageService for PageServiceImpl { Ok(pages.into_iter().map(Into::into).collect()) } - async fn get_section(&self, page_id: &ID, id: &ID) -> Result
{ - Err(CoreError::Other(anyhow!("Not implemented"))) + async fn list_sections( + &self, + page_id: &ID, + after: Option, + before: Option, + first: Option, + last: Option, + ) -> Result> { + let (limit, skip_id, backwards) = graphql_pagination_to_filter(after, before, first, last)?; + + let sections = self + .db + .list_page_sections(page_id.as_rowid()?, limit, skip_id, backwards) + .await?; + + Ok(sections.into_iter().map(Into::into).collect()) } - async fn update_section(&self, input: &UpdateSectionInput) -> Result
{ - Err(CoreError::Other(anyhow!("Not implemented"))) + async fn get_section(&self, id: &ID) -> Result
{ + let section = self + .db + .get_page_section(id.as_rowid()?) + .await? + .ok_or_else(|| CoreError::NotFound("Section not found"))?; + Ok(section.into()) } - async fn reorder_section(&self, input: &ReorderSectionInput) -> Result<()> { - Err(CoreError::Other(anyhow!("Not implemented"))) + async fn add_section(&self, input: &AddPageSectionInput) -> Result { + //TODO: generate section content + let section = self + .db + .create_page_section(input.page_id.as_rowid()?, &input.title, "Content") + .await?; + Ok(section.as_id()) } - async fn delete_section(&self, page_id: &ID, id: &ID) -> Result<()> { - Err(CoreError::Other(anyhow!("Not implemented"))) + async fn delete_section(&self, id: &ID) -> Result<()> { + self.db.delete_page_section(id.as_rowid()?).await?; + Ok(()) } }