Compare commits

...

7 Commits

Author SHA1 Message Date
L-Sun
39abd1bbb8 fix(editor): can not create surface block comment (#13115)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Improved comment handling to ensure elements from all selections are
considered, regardless of surface ID.
* Enhanced preview generation for comments to include all relevant
selections without surface-based filtering.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-09 11:05:03 +00:00
Lakr
ecea7bd825 fix: 🚑 compiler issue (#13114) 2025-07-09 10:18:04 +00:00
Wu Yue
d10e5ee92f feat(core): completely remove the dependence on EditorHost (#13110)
Close [AI-260](https://linear.app/affine-design/issue/AI-260)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added theme support to AI chat and message components, enabling
dynamic theming based on the current app theme.
* Introduced a reactive theme signal to the theme service for improved
theme handling.
* Integrated notification and theme services across various AI chat,
playground, and message components for consistent user experience.

* **Refactor**
* Simplified component APIs by removing dependencies on editor host and
related properties across AI chat, message, and tool components.
* Centralized and streamlined clipboard and markdown conversion
utilities, reducing external dependencies.
* Standardized the interface for context file addition and improved type
usage for better consistency.
* Reworked notification service to a class-based implementation for
improved encapsulation.
* Updated AI chat components to use injected notification and theme
services instead of host-based retrieval.

* **Bug Fixes**
* Improved reliability of copy and notification actions by decoupling
them from editor host dependencies.

* **Chores**
* Updated and cleaned up internal imports and removed unused properties
to enhance maintainability.
  * Added test IDs for sidebar close button to improve test reliability.
  * Updated test prompts in end-to-end tests for consistency.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-09 10:16:55 +00:00
Cats Juice
dace1d1738 fix(core): should show delete permanently for trash page multi-select (#13111)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Added a confirmation modal before permanently deleting pages from the
trash, ensuring users must confirm before deletion.
* Permanent deletion now displays a toast notification upon completion.

* **Improvements**
* Enhanced deletion actions with callbacks for handling completion,
cancellation, or errors.
* Permanent delete option is now conditionally available based on user
permissions (admin or owner).

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-09 08:45:26 +00:00
fengmk2
ae74f4ae51 fix(server): should use signed url first (#13109)
#### PR Dependency Tree


* **PR #13109** 👈

This tree was auto-generated by
[Charcoal](https://github.com/danerwilliams/charcoal)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Refactor**
* Updated internal handling of comment attachments to improve processing
logic. No visible changes to end-user features or workflows.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-09 08:12:16 +00:00
Peng Xiao
9071c5032d fix(core): should not be able to commit comments when uploading images (#13108)
#### PR Dependency Tree


* **PR #13108** 👈

This tree was auto-generated by
[Charcoal](https://github.com/danerwilliams/charcoal)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* The commit button in the comment editor is now properly disabled while
attachments are uploading or when the editor is empty without
attachments, preventing accidental or premature submissions.
* **New Features**
* Attachment delete button now shows a loading state during uploads for
clearer user feedback.
* **Style**
* Updated comment editor attachment button styles for a cleaner and more
consistent appearance.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-09 07:56:34 +00:00
DarkSky
8236ecf486 fix(server): chunk session in migration (#13107)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Refactor**
* Improved the process for updating session records to handle them in
smaller batches, enhancing reliability and performance during data
updates. No changes to user-facing features.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-09 07:32:02 +00:00
109 changed files with 2631 additions and 776 deletions

View File

@@ -47,3 +47,7 @@ export const NullCommentInlineSpecExtension =
match: () => false,
renderer: () => html``,
});
// reuse the same identifier
NullCommentInlineSpecExtension.identifier =
CommentInlineSpecExtension.identifier;

View File

@@ -123,8 +123,7 @@ export class BlockElementCommentManager extends LifeCycleWatcher {
const gfx = this.std.get(GfxControllerIdentifier);
const elementsFromSurfaceSelection = selections
.filter(s => s instanceof SurfaceSelection)
.flatMap(({ blockId, elements }) => {
if (blockId !== gfx.surface?.id) return [];
.flatMap(({ elements }) => {
return elements
.map(id => gfx.getElementById<GfxModel>(id))
.filter(m => m !== null);

View File

@@ -40,7 +40,6 @@ export interface NotificationService {
}[];
onClose?: () => void;
}): void;
/**
* Notify with undo action, it is a helper function to notify with undo action.
* And the notification card will be closed when undo action is triggered by shortcut key or other ways.
@@ -55,13 +54,16 @@ export const NotificationProvider = createIdentifier<NotificationService>(
);
export function NotificationExtension(
notificationService: Omit<NotificationService, 'notifyWithUndoAction'>
notificationService: NotificationService
): ExtensionType {
return {
setup: di => {
di.addImpl(NotificationProvider, provider => {
return {
...notificationService,
notify: notificationService.notify,
toast: notificationService.toast,
confirm: notificationService.confirm,
prompt: notificationService.prompt,
notifyWithUndoAction: options => {
notifyWithUndoActionImpl(
provider,

View File

@@ -31,7 +31,7 @@ export interface BlockStdOptions {
extensions: ExtensionType[];
}
const internalExtensions = [
export const internalExtensions = [
ServiceManager,
CommandManager,
UIEventDispatcher,

View File

@@ -195,7 +195,7 @@ export class WorkspacesController {
await this.ac.user(user.id).doc(workspaceId, docId).assert('Doc.Read');
const { body, metadata, redirectUrl } =
await this.commentAttachmentStorage.get(workspaceId, docId, key);
await this.commentAttachmentStorage.get(workspaceId, docId, key, true);
if (redirectUrl) {
return res.redirect(redirectUrl);

View File

@@ -1,4 +1,5 @@
import { PrismaClient } from '@prisma/client';
import { chunk } from 'lodash-es';
type SessionTime = {
sessionId: string;
@@ -17,16 +18,19 @@ export class CorrectSessionUpdateTime1751966744168 {
},
});
await Promise.all(
sessionTime
.filter((s): s is SessionTime => !!s._max.createdAt)
.map(s =>
db.aiSession.update({
where: { id: s.sessionId },
data: { updatedAt: s._max.createdAt },
})
)
);
for (const s of chunk(sessionTime, 100)) {
const sessions = s.filter((s): s is SessionTime => !!s._max.createdAt);
await db.$transaction(async tx => {
await Promise.all(
sessions.map(s =>
tx.aiSession.update({
where: { id: s.sessionId },
data: { updatedAt: s._max.createdAt },
})
)
);
});
}
}
// revert the migration

View File

@@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 77;
objectVersion = 56;
objects = {
/* Begin PBXBuildFile section */
@@ -90,6 +90,8 @@
/* Begin PBXFileSystemSynchronizedRootGroup section */
C45499AB2D140B5000E21978 /* NBStore */ = {
isa = PBXFileSystemSynchronizedRootGroup;
exceptions = (
);
path = NBStore;
sourceTree = "<group>";
};
@@ -337,13 +339,9 @@
);
inputFileListPaths = (
);
inputPaths = (
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-AFFiNE/Pods-AFFiNE-frameworks.sh\"\n";

View File

@@ -0,0 +1,79 @@
// @generated
// This file was automatically generated and should not be edited.
@_exported import ApolloAPI
public struct CopilotChatHistory: AffineGraphQL.SelectionSet, Fragment {
public static var fragmentDefinition: StaticString {
#"fragment CopilotChatHistory on CopilotHistories { __typename sessionId workspaceId docId parentSessionId promptName model optionalModels action pinned title tokens messages { __typename ...CopilotChatMessage } createdAt updatedAt }"#
}
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.CopilotHistories }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("sessionId", String.self),
.field("workspaceId", String.self),
.field("docId", String?.self),
.field("parentSessionId", String?.self),
.field("promptName", String.self),
.field("model", String.self),
.field("optionalModels", [String].self),
.field("action", String?.self),
.field("pinned", Bool.self),
.field("title", String?.self),
.field("tokens", Int.self),
.field("messages", [Message].self),
.field("createdAt", AffineGraphQL.DateTime.self),
.field("updatedAt", AffineGraphQL.DateTime.self),
] }
public var sessionId: String { __data["sessionId"] }
public var workspaceId: String { __data["workspaceId"] }
public var docId: String? { __data["docId"] }
public var parentSessionId: String? { __data["parentSessionId"] }
public var promptName: String { __data["promptName"] }
public var model: String { __data["model"] }
public var optionalModels: [String] { __data["optionalModels"] }
/// An mark identifying which view to use to display the session
public var action: String? { __data["action"] }
public var pinned: Bool { __data["pinned"] }
public var title: String? { __data["title"] }
/// The number of tokens used in the session
public var tokens: Int { __data["tokens"] }
public var messages: [Message] { __data["messages"] }
public var createdAt: AffineGraphQL.DateTime { __data["createdAt"] }
public var updatedAt: AffineGraphQL.DateTime { __data["updatedAt"] }
/// Message
///
/// Parent Type: `ChatMessage`
public struct Message: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.ChatMessage }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.fragment(CopilotChatMessage.self),
] }
public var id: AffineGraphQL.ID? { __data["id"] }
public var role: String { __data["role"] }
public var content: String { __data["content"] }
public var attachments: [String]? { __data["attachments"] }
public var streamObjects: [StreamObject]? { __data["streamObjects"] }
public var createdAt: AffineGraphQL.DateTime { __data["createdAt"] }
public struct Fragments: FragmentContainer {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public var copilotChatMessage: CopilotChatMessage { _toFragment() }
}
public typealias StreamObject = CopilotChatMessage.StreamObject
}
}

View File

@@ -0,0 +1,57 @@
// @generated
// This file was automatically generated and should not be edited.
@_exported import ApolloAPI
public struct CopilotChatMessage: AffineGraphQL.SelectionSet, Fragment {
public static var fragmentDefinition: StaticString {
#"fragment CopilotChatMessage on ChatMessage { __typename id role content attachments streamObjects { __typename type textDelta toolCallId toolName args result } createdAt }"#
}
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.ChatMessage }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("id", AffineGraphQL.ID?.self),
.field("role", String.self),
.field("content", String.self),
.field("attachments", [String]?.self),
.field("streamObjects", [StreamObject]?.self),
.field("createdAt", AffineGraphQL.DateTime.self),
] }
public var id: AffineGraphQL.ID? { __data["id"] }
public var role: String { __data["role"] }
public var content: String { __data["content"] }
public var attachments: [String]? { __data["attachments"] }
public var streamObjects: [StreamObject]? { __data["streamObjects"] }
public var createdAt: AffineGraphQL.DateTime { __data["createdAt"] }
/// StreamObject
///
/// Parent Type: `StreamObject`
public struct StreamObject: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.StreamObject }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("type", String.self),
.field("textDelta", String?.self),
.field("toolCallId", String?.self),
.field("toolName", String?.self),
.field("args", AffineGraphQL.JSON?.self),
.field("result", AffineGraphQL.JSON?.self),
] }
public var type: String { __data["type"] }
public var textDelta: String? { __data["textDelta"] }
public var toolCallId: String? { __data["toolCallId"] }
public var toolName: String? { __data["toolName"] }
public var args: AffineGraphQL.JSON? { __data["args"] }
public var result: AffineGraphQL.JSON? { __data["result"] }
}
}

View File

@@ -0,0 +1,103 @@
// @generated
// This file was automatically generated and should not be edited.
@_exported import ApolloAPI
public struct PaginatedCopilotChats: AffineGraphQL.SelectionSet, Fragment {
public static var fragmentDefinition: StaticString {
#"fragment PaginatedCopilotChats on PaginatedCopilotHistoriesType { __typename pageInfo { __typename hasNextPage hasPreviousPage startCursor endCursor } edges { __typename cursor node { __typename ...CopilotChatHistory } } }"#
}
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.PaginatedCopilotHistoriesType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("pageInfo", PageInfo.self),
.field("edges", [Edge].self),
] }
public var pageInfo: PageInfo { __data["pageInfo"] }
public var edges: [Edge] { __data["edges"] }
/// PageInfo
///
/// Parent Type: `PageInfo`
public struct PageInfo: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.PageInfo }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("hasNextPage", Bool.self),
.field("hasPreviousPage", Bool.self),
.field("startCursor", String?.self),
.field("endCursor", String?.self),
] }
public var hasNextPage: Bool { __data["hasNextPage"] }
public var hasPreviousPage: Bool { __data["hasPreviousPage"] }
public var startCursor: String? { __data["startCursor"] }
public var endCursor: String? { __data["endCursor"] }
}
/// Edge
///
/// Parent Type: `CopilotHistoriesTypeEdge`
public struct Edge: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.CopilotHistoriesTypeEdge }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("cursor", String.self),
.field("node", Node.self),
] }
public var cursor: String { __data["cursor"] }
public var node: Node { __data["node"] }
/// Edge.Node
///
/// Parent Type: `CopilotHistories`
public struct Node: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.CopilotHistories }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.fragment(CopilotChatHistory.self),
] }
public var sessionId: String { __data["sessionId"] }
public var workspaceId: String { __data["workspaceId"] }
public var docId: String? { __data["docId"] }
public var parentSessionId: String? { __data["parentSessionId"] }
public var promptName: String { __data["promptName"] }
public var model: String { __data["model"] }
public var optionalModels: [String] { __data["optionalModels"] }
/// An mark identifying which view to use to display the session
public var action: String? { __data["action"] }
public var pinned: Bool { __data["pinned"] }
public var title: String? { __data["title"] }
/// The number of tokens used in the session
public var tokens: Int { __data["tokens"] }
public var messages: [Message] { __data["messages"] }
public var createdAt: AffineGraphQL.DateTime { __data["createdAt"] }
public var updatedAt: AffineGraphQL.DateTime { __data["updatedAt"] }
public struct Fragments: FragmentContainer {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public var copilotChatHistory: CopilotChatHistory { _toFragment() }
}
public typealias Message = CopilotChatHistory.Message
}
}
}

View File

@@ -0,0 +1,136 @@
// @generated
// This file was automatically generated and should not be edited.
@_exported import ApolloAPI
public class CreateCommentMutation: GraphQLMutation {
public static let operationName: String = "createComment"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"mutation createComment($input: CommentCreateInput!) { createComment(input: $input) { __typename id content resolved createdAt updatedAt user { __typename id name avatarUrl } replies { __typename commentId id content createdAt updatedAt user { __typename id name avatarUrl } } } }"#
))
public var input: CommentCreateInput
public init(input: CommentCreateInput) {
self.input = input
}
public var __variables: Variables? { ["input": input] }
public struct Data: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Mutation }
public static var __selections: [ApolloAPI.Selection] { [
.field("createComment", CreateComment.self, arguments: ["input": .variable("input")]),
] }
public var createComment: CreateComment { __data["createComment"] }
/// CreateComment
///
/// Parent Type: `CommentObjectType`
public struct CreateComment: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.CommentObjectType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("id", AffineGraphQL.ID.self),
.field("content", AffineGraphQL.JSONObject.self),
.field("resolved", Bool.self),
.field("createdAt", AffineGraphQL.DateTime.self),
.field("updatedAt", AffineGraphQL.DateTime.self),
.field("user", User.self),
.field("replies", [Reply].self),
] }
public var id: AffineGraphQL.ID { __data["id"] }
/// The content of the comment
public var content: AffineGraphQL.JSONObject { __data["content"] }
/// Whether the comment is resolved
public var resolved: Bool { __data["resolved"] }
/// The created at time of the comment
public var createdAt: AffineGraphQL.DateTime { __data["createdAt"] }
/// The updated at time of the comment
public var updatedAt: AffineGraphQL.DateTime { __data["updatedAt"] }
/// The user who created the comment
public var user: User { __data["user"] }
/// The replies of the comment
public var replies: [Reply] { __data["replies"] }
/// CreateComment.User
///
/// Parent Type: `PublicUserType`
public struct User: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.PublicUserType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("id", String.self),
.field("name", String.self),
.field("avatarUrl", String?.self),
] }
public var id: String { __data["id"] }
public var name: String { __data["name"] }
public var avatarUrl: String? { __data["avatarUrl"] }
}
/// CreateComment.Reply
///
/// Parent Type: `ReplyObjectType`
public struct Reply: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.ReplyObjectType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("commentId", AffineGraphQL.ID.self),
.field("id", AffineGraphQL.ID.self),
.field("content", AffineGraphQL.JSONObject.self),
.field("createdAt", AffineGraphQL.DateTime.self),
.field("updatedAt", AffineGraphQL.DateTime.self),
.field("user", User.self),
] }
public var commentId: AffineGraphQL.ID { __data["commentId"] }
public var id: AffineGraphQL.ID { __data["id"] }
/// The content of the reply
public var content: AffineGraphQL.JSONObject { __data["content"] }
/// The created at time of the reply
public var createdAt: AffineGraphQL.DateTime { __data["createdAt"] }
/// The updated at time of the reply
public var updatedAt: AffineGraphQL.DateTime { __data["updatedAt"] }
/// The user who created the reply
public var user: User { __data["user"] }
/// CreateComment.Reply.User
///
/// Parent Type: `PublicUserType`
public struct User: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.PublicUserType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("id", String.self),
.field("name", String.self),
.field("avatarUrl", String?.self),
] }
public var id: String { __data["id"] }
public var name: String { __data["name"] }
public var avatarUrl: String? { __data["avatarUrl"] }
}
}
}
}
}

View File

@@ -0,0 +1,82 @@
// @generated
// This file was automatically generated and should not be edited.
@_exported import ApolloAPI
public class CreateReplyMutation: GraphQLMutation {
public static let operationName: String = "createReply"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"mutation createReply($input: ReplyCreateInput!) { createReply(input: $input) { __typename commentId id content createdAt updatedAt user { __typename id name avatarUrl } } }"#
))
public var input: ReplyCreateInput
public init(input: ReplyCreateInput) {
self.input = input
}
public var __variables: Variables? { ["input": input] }
public struct Data: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Mutation }
public static var __selections: [ApolloAPI.Selection] { [
.field("createReply", CreateReply.self, arguments: ["input": .variable("input")]),
] }
public var createReply: CreateReply { __data["createReply"] }
/// CreateReply
///
/// Parent Type: `ReplyObjectType`
public struct CreateReply: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.ReplyObjectType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("commentId", AffineGraphQL.ID.self),
.field("id", AffineGraphQL.ID.self),
.field("content", AffineGraphQL.JSONObject.self),
.field("createdAt", AffineGraphQL.DateTime.self),
.field("updatedAt", AffineGraphQL.DateTime.self),
.field("user", User.self),
] }
public var commentId: AffineGraphQL.ID { __data["commentId"] }
public var id: AffineGraphQL.ID { __data["id"] }
/// The content of the reply
public var content: AffineGraphQL.JSONObject { __data["content"] }
/// The created at time of the reply
public var createdAt: AffineGraphQL.DateTime { __data["createdAt"] }
/// The updated at time of the reply
public var updatedAt: AffineGraphQL.DateTime { __data["updatedAt"] }
/// The user who created the reply
public var user: User { __data["user"] }
/// CreateReply.User
///
/// Parent Type: `PublicUserType`
public struct User: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.PublicUserType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("id", String.self),
.field("name", String.self),
.field("avatarUrl", String?.self),
] }
public var id: String { __data["id"] }
public var name: String { __data["name"] }
public var avatarUrl: String? { __data["avatarUrl"] }
}
}
}
}

View File

@@ -0,0 +1,33 @@
// @generated
// This file was automatically generated and should not be edited.
@_exported import ApolloAPI
public class DeleteCommentMutation: GraphQLMutation {
public static let operationName: String = "deleteComment"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"mutation deleteComment($id: String!) { deleteComment(id: $id) }"#
))
public var id: String
public init(id: String) {
self.id = id
}
public var __variables: Variables? { ["id": id] }
public struct Data: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Mutation }
public static var __selections: [ApolloAPI.Selection] { [
.field("deleteComment", Bool.self, arguments: ["id": .variable("id")]),
] }
/// Delete a comment
public var deleteComment: Bool { __data["deleteComment"] }
}
}

View File

@@ -0,0 +1,33 @@
// @generated
// This file was automatically generated and should not be edited.
@_exported import ApolloAPI
public class DeleteReplyMutation: GraphQLMutation {
public static let operationName: String = "deleteReply"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"mutation deleteReply($id: String!) { deleteReply(id: $id) }"#
))
public var id: String
public init(id: String) {
self.id = id
}
public var __variables: Variables? { ["id": id] }
public struct Data: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Mutation }
public static var __selections: [ApolloAPI.Selection] { [
.field("deleteReply", Bool.self, arguments: ["id": .variable("id")]),
] }
/// Delete a reply
public var deleteReply: Bool { __data["deleteReply"] }
}
}

View File

@@ -0,0 +1,27 @@
// @generated
// This file was automatically generated and should not be edited.
@_exported import ApolloAPI
public class ReadAllNotificationsMutation: GraphQLMutation {
public static let operationName: String = "readAllNotifications"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"mutation readAllNotifications { readAllNotifications }"#
))
public init() {}
public struct Data: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Mutation }
public static var __selections: [ApolloAPI.Selection] { [
.field("readAllNotifications", Bool.self),
] }
/// mark all notifications as read
public var readAllNotifications: Bool { __data["readAllNotifications"] }
}
}

View File

@@ -0,0 +1,33 @@
// @generated
// This file was automatically generated and should not be edited.
@_exported import ApolloAPI
public class ResolveCommentMutation: GraphQLMutation {
public static let operationName: String = "resolveComment"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"mutation resolveComment($input: CommentResolveInput!) { resolveComment(input: $input) }"#
))
public var input: CommentResolveInput
public init(input: CommentResolveInput) {
self.input = input
}
public var __variables: Variables? { ["input": input] }
public struct Data: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Mutation }
public static var __selections: [ApolloAPI.Selection] { [
.field("resolveComment", Bool.self, arguments: ["input": .variable("input")]),
] }
/// Resolve a comment or not
public var resolveComment: Bool { __data["resolveComment"] }
}
}

View File

@@ -0,0 +1,33 @@
// @generated
// This file was automatically generated and should not be edited.
@_exported import ApolloAPI
public class UpdateCommentMutation: GraphQLMutation {
public static let operationName: String = "updateComment"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"mutation updateComment($input: CommentUpdateInput!) { updateComment(input: $input) }"#
))
public var input: CommentUpdateInput
public init(input: CommentUpdateInput) {
self.input = input
}
public var __variables: Variables? { ["input": input] }
public struct Data: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Mutation }
public static var __selections: [ApolloAPI.Selection] { [
.field("updateComment", Bool.self, arguments: ["input": .variable("input")]),
] }
/// Update a comment content
public var updateComment: Bool { __data["updateComment"] }
}
}

View File

@@ -0,0 +1,33 @@
// @generated
// This file was automatically generated and should not be edited.
@_exported import ApolloAPI
public class UpdateReplyMutation: GraphQLMutation {
public static let operationName: String = "updateReply"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"mutation updateReply($input: ReplyUpdateInput!) { updateReply(input: $input) }"#
))
public var input: ReplyUpdateInput
public init(input: ReplyUpdateInput) {
self.input = input
}
public var __variables: Variables? { ["input": input] }
public struct Data: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Mutation }
public static var __selections: [ApolloAPI.Selection] { [
.field("updateReply", Bool.self, arguments: ["input": .variable("input")]),
] }
/// Update a reply content
public var updateReply: Bool { __data["updateReply"] }
}
}

View File

@@ -0,0 +1,49 @@
// @generated
// This file was automatically generated and should not be edited.
@_exported import ApolloAPI
public class UploadCommentAttachmentMutation: GraphQLMutation {
public static let operationName: String = "uploadCommentAttachment"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"mutation uploadCommentAttachment($workspaceId: String!, $docId: String!, $attachment: Upload!) { uploadCommentAttachment( workspaceId: $workspaceId docId: $docId attachment: $attachment ) }"#
))
public var workspaceId: String
public var docId: String
public var attachment: Upload
public init(
workspaceId: String,
docId: String,
attachment: Upload
) {
self.workspaceId = workspaceId
self.docId = docId
self.attachment = attachment
}
public var __variables: Variables? { [
"workspaceId": workspaceId,
"docId": docId,
"attachment": attachment
] }
public struct Data: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Mutation }
public static var __selections: [ApolloAPI.Selection] { [
.field("uploadCommentAttachment", String.self, arguments: [
"workspaceId": .variable("workspaceId"),
"docId": .variable("docId"),
"attachment": .variable("attachment")
]),
] }
/// Upload a comment attachment and return the access url
public var uploadCommentAttachment: String { __data["uploadCommentAttachment"] }
}
}

View File

@@ -0,0 +1,114 @@
// @generated
// This file was automatically generated and should not be edited.
@_exported import ApolloAPI
public class GetCopilotDocSessionsQuery: GraphQLQuery {
public static let operationName: String = "getCopilotDocSessions"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"query getCopilotDocSessions($workspaceId: String!, $docId: String!, $pagination: PaginationInput!, $options: QueryChatHistoriesInput) { currentUser { __typename copilot(workspaceId: $workspaceId) { __typename chats(pagination: $pagination, docId: $docId, options: $options) { __typename ...PaginatedCopilotChats } } } }"#,
fragments: [CopilotChatHistory.self, CopilotChatMessage.self, PaginatedCopilotChats.self]
))
public var workspaceId: String
public var docId: String
public var pagination: PaginationInput
public var options: GraphQLNullable<QueryChatHistoriesInput>
public init(
workspaceId: String,
docId: String,
pagination: PaginationInput,
options: GraphQLNullable<QueryChatHistoriesInput>
) {
self.workspaceId = workspaceId
self.docId = docId
self.pagination = pagination
self.options = options
}
public var __variables: Variables? { [
"workspaceId": workspaceId,
"docId": docId,
"pagination": pagination,
"options": options
] }
public struct Data: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Query }
public static var __selections: [ApolloAPI.Selection] { [
.field("currentUser", CurrentUser?.self),
] }
/// Get current user
public var currentUser: CurrentUser? { __data["currentUser"] }
/// CurrentUser
///
/// Parent Type: `UserType`
public struct CurrentUser: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.UserType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("copilot", Copilot.self, arguments: ["workspaceId": .variable("workspaceId")]),
] }
public var copilot: Copilot { __data["copilot"] }
/// CurrentUser.Copilot
///
/// Parent Type: `Copilot`
public struct Copilot: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Copilot }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("chats", Chats.self, arguments: [
"pagination": .variable("pagination"),
"docId": .variable("docId"),
"options": .variable("options")
]),
] }
public var chats: Chats { __data["chats"] }
/// CurrentUser.Copilot.Chats
///
/// Parent Type: `PaginatedCopilotHistoriesType`
public struct Chats: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.PaginatedCopilotHistoriesType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.fragment(PaginatedCopilotChats.self),
] }
public var pageInfo: PageInfo { __data["pageInfo"] }
public var edges: [Edge] { __data["edges"] }
public struct Fragments: FragmentContainer {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public var paginatedCopilotChats: PaginatedCopilotChats { _toFragment() }
}
public typealias PageInfo = PaginatedCopilotChats.PageInfo
public typealias Edge = PaginatedCopilotChats.Edge
}
}
}
}
}

View File

@@ -7,25 +7,30 @@ public class GetCopilotHistoriesQuery: GraphQLQuery {
public static let operationName: String = "getCopilotHistories"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"query getCopilotHistories($workspaceId: String!, $docId: String, $options: QueryChatHistoriesInput) { currentUser { __typename copilot(workspaceId: $workspaceId) { __typename histories(docId: $docId, options: $options) { __typename sessionId pinned tokens action createdAt messages { __typename id role content streamObjects { __typename type textDelta toolCallId toolName args result } attachments createdAt } } } } }"#
#"query getCopilotHistories($workspaceId: String!, $pagination: PaginationInput!, $docId: String, $options: QueryChatHistoriesInput) { currentUser { __typename copilot(workspaceId: $workspaceId) { __typename chats(pagination: $pagination, docId: $docId, options: $options) { __typename ...PaginatedCopilotChats } } } }"#,
fragments: [CopilotChatHistory.self, CopilotChatMessage.self, PaginatedCopilotChats.self]
))
public var workspaceId: String
public var pagination: PaginationInput
public var docId: GraphQLNullable<String>
public var options: GraphQLNullable<QueryChatHistoriesInput>
public init(
workspaceId: String,
pagination: PaginationInput,
docId: GraphQLNullable<String>,
options: GraphQLNullable<QueryChatHistoriesInput>
) {
self.workspaceId = workspaceId
self.pagination = pagination
self.docId = docId
self.options = options
}
public var __variables: Variables? { [
"workspaceId": workspaceId,
"pagination": pagination,
"docId": docId,
"options": options
] }
@@ -67,92 +72,41 @@ public class GetCopilotHistoriesQuery: GraphQLQuery {
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Copilot }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("histories", [History].self, arguments: [
.field("chats", Chats.self, arguments: [
"pagination": .variable("pagination"),
"docId": .variable("docId"),
"options": .variable("options")
]),
] }
public var histories: [History] { __data["histories"] }
public var chats: Chats { __data["chats"] }
/// CurrentUser.Copilot.History
/// CurrentUser.Copilot.Chats
///
/// Parent Type: `CopilotHistories`
public struct History: AffineGraphQL.SelectionSet {
/// Parent Type: `PaginatedCopilotHistoriesType`
public struct Chats: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.CopilotHistories }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.PaginatedCopilotHistoriesType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("sessionId", String.self),
.field("pinned", Bool.self),
.field("tokens", Int.self),
.field("action", String?.self),
.field("createdAt", AffineGraphQL.DateTime.self),
.field("messages", [Message].self),
.fragment(PaginatedCopilotChats.self),
] }
public var sessionId: String { __data["sessionId"] }
public var pinned: Bool { __data["pinned"] }
/// The number of tokens used in the session
public var tokens: Int { __data["tokens"] }
/// An mark identifying which view to use to display the session
public var action: String? { __data["action"] }
public var createdAt: AffineGraphQL.DateTime { __data["createdAt"] }
public var messages: [Message] { __data["messages"] }
public var pageInfo: PageInfo { __data["pageInfo"] }
public var edges: [Edge] { __data["edges"] }
/// CurrentUser.Copilot.History.Message
///
/// Parent Type: `ChatMessage`
public struct Message: AffineGraphQL.SelectionSet {
public struct Fragments: FragmentContainer {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.ChatMessage }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("id", AffineGraphQL.ID?.self),
.field("role", String.self),
.field("content", String.self),
.field("streamObjects", [StreamObject]?.self),
.field("attachments", [String]?.self),
.field("createdAt", AffineGraphQL.DateTime.self),
] }
public var id: AffineGraphQL.ID? { __data["id"] }
public var role: String { __data["role"] }
public var content: String { __data["content"] }
public var streamObjects: [StreamObject]? { __data["streamObjects"] }
public var attachments: [String]? { __data["attachments"] }
public var createdAt: AffineGraphQL.DateTime { __data["createdAt"] }
/// CurrentUser.Copilot.History.Message.StreamObject
///
/// Parent Type: `StreamObject`
public struct StreamObject: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.StreamObject }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("type", String.self),
.field("textDelta", String?.self),
.field("toolCallId", String?.self),
.field("toolName", String?.self),
.field("args", AffineGraphQL.JSON?.self),
.field("result", AffineGraphQL.JSON?.self),
] }
public var type: String { __data["type"] }
public var textDelta: String? { __data["textDelta"] }
public var toolCallId: String? { __data["toolCallId"] }
public var toolName: String? { __data["toolName"] }
public var args: AffineGraphQL.JSON? { __data["args"] }
public var result: AffineGraphQL.JSON? { __data["result"] }
}
public var paginatedCopilotChats: PaginatedCopilotChats { _toFragment() }
}
public typealias PageInfo = PaginatedCopilotChats.PageInfo
public typealias Edge = PaginatedCopilotChats.Edge
}
}
}

View File

@@ -7,25 +7,29 @@ public class GetCopilotHistoryIdsQuery: GraphQLQuery {
public static let operationName: String = "getCopilotHistoryIds"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"query getCopilotHistoryIds($workspaceId: String!, $docId: String, $options: QueryChatHistoriesInput) { currentUser { __typename copilot(workspaceId: $workspaceId) { __typename histories(docId: $docId, options: $options) { __typename sessionId pinned messages { __typename id role createdAt } } } } }"#
#"query getCopilotHistoryIds($workspaceId: String!, $pagination: PaginationInput!, $docId: String, $options: QueryChatHistoriesInput) { currentUser { __typename copilot(workspaceId: $workspaceId) { __typename chats(pagination: $pagination, docId: $docId, options: $options) { __typename pageInfo { __typename hasNextPage hasPreviousPage startCursor endCursor } edges { __typename cursor node { __typename sessionId pinned messages { __typename id role createdAt } } } } } } }"#
))
public var workspaceId: String
public var pagination: PaginationInput
public var docId: GraphQLNullable<String>
public var options: GraphQLNullable<QueryChatHistoriesInput>
public init(
workspaceId: String,
pagination: PaginationInput,
docId: GraphQLNullable<String>,
options: GraphQLNullable<QueryChatHistoriesInput>
) {
self.workspaceId = workspaceId
self.pagination = pagination
self.docId = docId
self.options = options
}
public var __variables: Variables? { [
"workspaceId": workspaceId,
"pagination": pagination,
"docId": docId,
"options": options
] }
@@ -67,51 +71,110 @@ public class GetCopilotHistoryIdsQuery: GraphQLQuery {
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Copilot }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("histories", [History].self, arguments: [
.field("chats", Chats.self, arguments: [
"pagination": .variable("pagination"),
"docId": .variable("docId"),
"options": .variable("options")
]),
] }
public var histories: [History] { __data["histories"] }
public var chats: Chats { __data["chats"] }
/// CurrentUser.Copilot.History
/// CurrentUser.Copilot.Chats
///
/// Parent Type: `CopilotHistories`
public struct History: AffineGraphQL.SelectionSet {
/// Parent Type: `PaginatedCopilotHistoriesType`
public struct Chats: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.CopilotHistories }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.PaginatedCopilotHistoriesType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("sessionId", String.self),
.field("pinned", Bool.self),
.field("messages", [Message].self),
.field("pageInfo", PageInfo.self),
.field("edges", [Edge].self),
] }
public var sessionId: String { __data["sessionId"] }
public var pinned: Bool { __data["pinned"] }
public var messages: [Message] { __data["messages"] }
public var pageInfo: PageInfo { __data["pageInfo"] }
public var edges: [Edge] { __data["edges"] }
/// CurrentUser.Copilot.History.Message
/// CurrentUser.Copilot.Chats.PageInfo
///
/// Parent Type: `ChatMessage`
public struct Message: AffineGraphQL.SelectionSet {
/// Parent Type: `PageInfo`
public struct PageInfo: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.ChatMessage }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.PageInfo }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("id", AffineGraphQL.ID?.self),
.field("role", String.self),
.field("createdAt", AffineGraphQL.DateTime.self),
.field("hasNextPage", Bool.self),
.field("hasPreviousPage", Bool.self),
.field("startCursor", String?.self),
.field("endCursor", String?.self),
] }
public var id: AffineGraphQL.ID? { __data["id"] }
public var role: String { __data["role"] }
public var createdAt: AffineGraphQL.DateTime { __data["createdAt"] }
public var hasNextPage: Bool { __data["hasNextPage"] }
public var hasPreviousPage: Bool { __data["hasPreviousPage"] }
public var startCursor: String? { __data["startCursor"] }
public var endCursor: String? { __data["endCursor"] }
}
/// CurrentUser.Copilot.Chats.Edge
///
/// Parent Type: `CopilotHistoriesTypeEdge`
public struct Edge: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.CopilotHistoriesTypeEdge }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("cursor", String.self),
.field("node", Node.self),
] }
public var cursor: String { __data["cursor"] }
public var node: Node { __data["node"] }
/// CurrentUser.Copilot.Chats.Edge.Node
///
/// Parent Type: `CopilotHistories`
public struct Node: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.CopilotHistories }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("sessionId", String.self),
.field("pinned", Bool.self),
.field("messages", [Message].self),
] }
public var sessionId: String { __data["sessionId"] }
public var pinned: Bool { __data["pinned"] }
public var messages: [Message] { __data["messages"] }
/// CurrentUser.Copilot.Chats.Edge.Node.Message
///
/// Parent Type: `ChatMessage`
public struct Message: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.ChatMessage }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("id", AffineGraphQL.ID?.self),
.field("role", String.self),
.field("createdAt", AffineGraphQL.DateTime.self),
] }
public var id: AffineGraphQL.ID? { __data["id"] }
public var role: String { __data["role"] }
public var createdAt: AffineGraphQL.DateTime { __data["createdAt"] }
}
}
}
}
}

View File

@@ -7,7 +7,8 @@ public class GetCopilotLatestDocSessionQuery: GraphQLQuery {
public static let operationName: String = "getCopilotLatestDocSession"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"query getCopilotLatestDocSession($workspaceId: String!, $docId: String!) { currentUser { __typename copilot(workspaceId: $workspaceId) { __typename histories( docId: $docId options: { limit: 1, sessionOrder: desc, action: false, fork: false } ) { __typename sessionId workspaceId docId pinned action tokens createdAt updatedAt messages { __typename id role content attachments params createdAt } } } } }"#
#"query getCopilotLatestDocSession($workspaceId: String!, $docId: String!) { currentUser { __typename copilot(workspaceId: $workspaceId) { __typename chats( pagination: { first: 1 } docId: $docId options: { sessionOrder: desc, action: false, fork: false, withMessages: true } ) { __typename ...PaginatedCopilotChats } } } }"#,
fragments: [CopilotChatHistory.self, CopilotChatMessage.self, PaginatedCopilotChats.self]
))
public var workspaceId: String
@@ -63,77 +64,46 @@ public class GetCopilotLatestDocSessionQuery: GraphQLQuery {
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Copilot }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("histories", [History].self, arguments: [
.field("chats", Chats.self, arguments: [
"pagination": ["first": 1],
"docId": .variable("docId"),
"options": [
"limit": 1,
"sessionOrder": "desc",
"action": false,
"fork": false
"fork": false,
"withMessages": true
]
]),
] }
public var histories: [History] { __data["histories"] }
public var chats: Chats { __data["chats"] }
/// CurrentUser.Copilot.History
/// CurrentUser.Copilot.Chats
///
/// Parent Type: `CopilotHistories`
public struct History: AffineGraphQL.SelectionSet {
/// Parent Type: `PaginatedCopilotHistoriesType`
public struct Chats: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.CopilotHistories }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.PaginatedCopilotHistoriesType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("sessionId", String.self),
.field("workspaceId", String.self),
.field("docId", String?.self),
.field("pinned", Bool.self),
.field("action", String?.self),
.field("tokens", Int.self),
.field("createdAt", AffineGraphQL.DateTime.self),
.field("updatedAt", AffineGraphQL.DateTime.self),
.field("messages", [Message].self),
.fragment(PaginatedCopilotChats.self),
] }
public var sessionId: String { __data["sessionId"] }
public var workspaceId: String { __data["workspaceId"] }
public var docId: String? { __data["docId"] }
public var pinned: Bool { __data["pinned"] }
/// An mark identifying which view to use to display the session
public var action: String? { __data["action"] }
/// The number of tokens used in the session
public var tokens: Int { __data["tokens"] }
public var createdAt: AffineGraphQL.DateTime { __data["createdAt"] }
public var updatedAt: AffineGraphQL.DateTime { __data["updatedAt"] }
public var messages: [Message] { __data["messages"] }
public var pageInfo: PageInfo { __data["pageInfo"] }
public var edges: [Edge] { __data["edges"] }
/// CurrentUser.Copilot.History.Message
///
/// Parent Type: `ChatMessage`
public struct Message: AffineGraphQL.SelectionSet {
public struct Fragments: FragmentContainer {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.ChatMessage }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("id", AffineGraphQL.ID?.self),
.field("role", String.self),
.field("content", String.self),
.field("attachments", [String]?.self),
.field("params", AffineGraphQL.JSON?.self),
.field("createdAt", AffineGraphQL.DateTime.self),
] }
public var id: AffineGraphQL.ID? { __data["id"] }
public var role: String { __data["role"] }
public var content: String { __data["content"] }
public var attachments: [String]? { __data["attachments"] }
public var params: AffineGraphQL.JSON? { __data["params"] }
public var createdAt: AffineGraphQL.DateTime { __data["createdAt"] }
public var paginatedCopilotChats: PaginatedCopilotChats { _toFragment() }
}
public typealias PageInfo = PaginatedCopilotChats.PageInfo
public typealias Edge = PaginatedCopilotChats.Edge
}
}
}

View File

@@ -0,0 +1,118 @@
// @generated
// This file was automatically generated and should not be edited.
@_exported import ApolloAPI
public class GetCopilotPinnedSessionsQuery: GraphQLQuery {
public static let operationName: String = "getCopilotPinnedSessions"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"query getCopilotPinnedSessions($workspaceId: String!, $docId: String, $messageOrder: ChatHistoryOrder, $withPrompt: Boolean) { currentUser { __typename copilot(workspaceId: $workspaceId) { __typename chats( pagination: { first: 1 } docId: $docId options: { pinned: true, messageOrder: $messageOrder, withPrompt: $withPrompt } ) { __typename ...PaginatedCopilotChats } } } }"#,
fragments: [CopilotChatHistory.self, CopilotChatMessage.self, PaginatedCopilotChats.self]
))
public var workspaceId: String
public var docId: GraphQLNullable<String>
public var messageOrder: GraphQLNullable<GraphQLEnum<ChatHistoryOrder>>
public var withPrompt: GraphQLNullable<Bool>
public init(
workspaceId: String,
docId: GraphQLNullable<String>,
messageOrder: GraphQLNullable<GraphQLEnum<ChatHistoryOrder>>,
withPrompt: GraphQLNullable<Bool>
) {
self.workspaceId = workspaceId
self.docId = docId
self.messageOrder = messageOrder
self.withPrompt = withPrompt
}
public var __variables: Variables? { [
"workspaceId": workspaceId,
"docId": docId,
"messageOrder": messageOrder,
"withPrompt": withPrompt
] }
public struct Data: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Query }
public static var __selections: [ApolloAPI.Selection] { [
.field("currentUser", CurrentUser?.self),
] }
/// Get current user
public var currentUser: CurrentUser? { __data["currentUser"] }
/// CurrentUser
///
/// Parent Type: `UserType`
public struct CurrentUser: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.UserType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("copilot", Copilot.self, arguments: ["workspaceId": .variable("workspaceId")]),
] }
public var copilot: Copilot { __data["copilot"] }
/// CurrentUser.Copilot
///
/// Parent Type: `Copilot`
public struct Copilot: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Copilot }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("chats", Chats.self, arguments: [
"pagination": ["first": 1],
"docId": .variable("docId"),
"options": [
"pinned": true,
"messageOrder": .variable("messageOrder"),
"withPrompt": .variable("withPrompt")
]
]),
] }
public var chats: Chats { __data["chats"] }
/// CurrentUser.Copilot.Chats
///
/// Parent Type: `PaginatedCopilotHistoriesType`
public struct Chats: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.PaginatedCopilotHistoriesType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.fragment(PaginatedCopilotChats.self),
] }
public var pageInfo: PageInfo { __data["pageInfo"] }
public var edges: [Edge] { __data["edges"] }
public struct Fragments: FragmentContainer {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public var paginatedCopilotChats: PaginatedCopilotChats { _toFragment() }
}
public typealias PageInfo = PaginatedCopilotChats.PageInfo
public typealias Edge = PaginatedCopilotChats.Edge
}
}
}
}
}

View File

@@ -7,7 +7,8 @@ public class GetCopilotRecentSessionsQuery: GraphQLQuery {
public static let operationName: String = "getCopilotRecentSessions"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"query getCopilotRecentSessions($workspaceId: String!, $limit: Int = 10) { currentUser { __typename copilot(workspaceId: $workspaceId) { __typename histories(options: { limit: $limit, sessionOrder: desc }) { __typename sessionId workspaceId docId pinned action tokens createdAt updatedAt } } } }"#
#"query getCopilotRecentSessions($workspaceId: String!, $limit: Int = 10) { currentUser { __typename copilot(workspaceId: $workspaceId) { __typename chats( pagination: { first: $limit } options: { fork: false, sessionOrder: desc, withMessages: true } ) { __typename ...PaginatedCopilotChats } } } }"#,
fragments: [CopilotChatHistory.self, CopilotChatMessage.self, PaginatedCopilotChats.self]
))
public var workspaceId: String
@@ -63,44 +64,44 @@ public class GetCopilotRecentSessionsQuery: GraphQLQuery {
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Copilot }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("histories", [History].self, arguments: ["options": [
"limit": .variable("limit"),
"sessionOrder": "desc"
]]),
.field("chats", Chats.self, arguments: [
"pagination": ["first": .variable("limit")],
"options": [
"fork": false,
"sessionOrder": "desc",
"withMessages": true
]
]),
] }
public var histories: [History] { __data["histories"] }
public var chats: Chats { __data["chats"] }
/// CurrentUser.Copilot.History
/// CurrentUser.Copilot.Chats
///
/// Parent Type: `CopilotHistories`
public struct History: AffineGraphQL.SelectionSet {
/// Parent Type: `PaginatedCopilotHistoriesType`
public struct Chats: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.CopilotHistories }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.PaginatedCopilotHistoriesType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("sessionId", String.self),
.field("workspaceId", String.self),
.field("docId", String?.self),
.field("pinned", Bool.self),
.field("action", String?.self),
.field("tokens", Int.self),
.field("createdAt", AffineGraphQL.DateTime.self),
.field("updatedAt", AffineGraphQL.DateTime.self),
.fragment(PaginatedCopilotChats.self),
] }
public var sessionId: String { __data["sessionId"] }
public var workspaceId: String { __data["workspaceId"] }
public var docId: String? { __data["docId"] }
public var pinned: Bool { __data["pinned"] }
/// An mark identifying which view to use to display the session
public var action: String? { __data["action"] }
/// The number of tokens used in the session
public var tokens: Int { __data["tokens"] }
public var createdAt: AffineGraphQL.DateTime { __data["createdAt"] }
public var updatedAt: AffineGraphQL.DateTime { __data["updatedAt"] }
public var pageInfo: PageInfo { __data["pageInfo"] }
public var edges: [Edge] { __data["edges"] }
public struct Fragments: FragmentContainer {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public var paginatedCopilotChats: PaginatedCopilotChats { _toFragment() }
}
public typealias PageInfo = PaginatedCopilotChats.PageInfo
public typealias Edge = PaginatedCopilotChats.Edge
}
}
}

View File

@@ -7,7 +7,8 @@ public class GetCopilotSessionQuery: GraphQLQuery {
public static let operationName: String = "getCopilotSession"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"query getCopilotSession($workspaceId: String!, $sessionId: String!) { currentUser { __typename copilot(workspaceId: $workspaceId) { __typename session(sessionId: $sessionId) { __typename id parentSessionId docId pinned promptName model optionalModels } } } }"#
#"query getCopilotSession($workspaceId: String!, $sessionId: String!) { currentUser { __typename copilot(workspaceId: $workspaceId) { __typename chats(pagination: { first: 1 }, options: { sessionId: $sessionId }) { __typename ...PaginatedCopilotChats } } } }"#,
fragments: [CopilotChatHistory.self, CopilotChatMessage.self, PaginatedCopilotChats.self]
))
public var workspaceId: String
@@ -63,38 +64,40 @@ public class GetCopilotSessionQuery: GraphQLQuery {
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Copilot }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("session", Session.self, arguments: ["sessionId": .variable("sessionId")]),
.field("chats", Chats.self, arguments: [
"pagination": ["first": 1],
"options": ["sessionId": .variable("sessionId")]
]),
] }
/// Get the session by id
public var session: Session { __data["session"] }
public var chats: Chats { __data["chats"] }
/// CurrentUser.Copilot.Session
/// CurrentUser.Copilot.Chats
///
/// Parent Type: `CopilotSessionType`
public struct Session: AffineGraphQL.SelectionSet {
/// Parent Type: `PaginatedCopilotHistoriesType`
public struct Chats: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.CopilotSessionType }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.PaginatedCopilotHistoriesType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("id", AffineGraphQL.ID.self),
.field("parentSessionId", AffineGraphQL.ID?.self),
.field("docId", String?.self),
.field("pinned", Bool.self),
.field("promptName", String.self),
.field("model", String.self),
.field("optionalModels", [String].self),
.fragment(PaginatedCopilotChats.self),
] }
public var id: AffineGraphQL.ID { __data["id"] }
public var parentSessionId: AffineGraphQL.ID? { __data["parentSessionId"] }
public var docId: String? { __data["docId"] }
public var pinned: Bool { __data["pinned"] }
public var promptName: String { __data["promptName"] }
public var model: String { __data["model"] }
public var optionalModels: [String] { __data["optionalModels"] }
public var pageInfo: PageInfo { __data["pageInfo"] }
public var edges: [Edge] { __data["edges"] }
public struct Fragments: FragmentContainer {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public var paginatedCopilotChats: PaginatedCopilotChats { _toFragment() }
}
public typealias PageInfo = PaginatedCopilotChats.PageInfo
public typealias Edge = PaginatedCopilotChats.Edge
}
}
}

View File

@@ -7,25 +7,30 @@ public class GetCopilotSessionsQuery: GraphQLQuery {
public static let operationName: String = "getCopilotSessions"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"query getCopilotSessions($workspaceId: String!, $docId: String, $options: QueryChatSessionsInput) { currentUser { __typename copilot(workspaceId: $workspaceId) { __typename sessions(docId: $docId, options: $options) { __typename id parentSessionId docId pinned promptName model optionalModels } } } }"#
#"query getCopilotSessions($workspaceId: String!, $pagination: PaginationInput!, $docId: String, $options: QueryChatHistoriesInput) { currentUser { __typename copilot(workspaceId: $workspaceId) { __typename chats(pagination: $pagination, docId: $docId, options: $options) { __typename ...PaginatedCopilotChats } } } }"#,
fragments: [CopilotChatHistory.self, CopilotChatMessage.self, PaginatedCopilotChats.self]
))
public var workspaceId: String
public var pagination: PaginationInput
public var docId: GraphQLNullable<String>
public var options: GraphQLNullable<QueryChatSessionsInput>
public var options: GraphQLNullable<QueryChatHistoriesInput>
public init(
workspaceId: String,
pagination: PaginationInput,
docId: GraphQLNullable<String>,
options: GraphQLNullable<QueryChatSessionsInput>
options: GraphQLNullable<QueryChatHistoriesInput>
) {
self.workspaceId = workspaceId
self.pagination = pagination
self.docId = docId
self.options = options
}
public var __variables: Variables? { [
"workspaceId": workspaceId,
"pagination": pagination,
"docId": docId,
"options": options
] }
@@ -67,41 +72,41 @@ public class GetCopilotSessionsQuery: GraphQLQuery {
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Copilot }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("sessions", [Session].self, arguments: [
.field("chats", Chats.self, arguments: [
"pagination": .variable("pagination"),
"docId": .variable("docId"),
"options": .variable("options")
]),
] }
/// Get the session list in the workspace
public var sessions: [Session] { __data["sessions"] }
public var chats: Chats { __data["chats"] }
/// CurrentUser.Copilot.Session
/// CurrentUser.Copilot.Chats
///
/// Parent Type: `CopilotSessionType`
public struct Session: AffineGraphQL.SelectionSet {
/// Parent Type: `PaginatedCopilotHistoriesType`
public struct Chats: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.CopilotSessionType }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.PaginatedCopilotHistoriesType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("id", AffineGraphQL.ID.self),
.field("parentSessionId", AffineGraphQL.ID?.self),
.field("docId", String?.self),
.field("pinned", Bool.self),
.field("promptName", String.self),
.field("model", String.self),
.field("optionalModels", [String].self),
.fragment(PaginatedCopilotChats.self),
] }
public var id: AffineGraphQL.ID { __data["id"] }
public var parentSessionId: AffineGraphQL.ID? { __data["parentSessionId"] }
public var docId: String? { __data["docId"] }
public var pinned: Bool { __data["pinned"] }
public var promptName: String { __data["promptName"] }
public var model: String { __data["model"] }
public var optionalModels: [String] { __data["optionalModels"] }
public var pageInfo: PageInfo { __data["pageInfo"] }
public var edges: [Edge] { __data["edges"] }
public struct Fragments: FragmentContainer {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public var paginatedCopilotChats: PaginatedCopilotChats { _toFragment() }
}
public typealias PageInfo = PaginatedCopilotChats.PageInfo
public typealias Edge = PaginatedCopilotChats.Edge
}
}
}

View File

@@ -0,0 +1,110 @@
// @generated
// This file was automatically generated and should not be edited.
@_exported import ApolloAPI
public class GetCopilotWorkspaceSessionsQuery: GraphQLQuery {
public static let operationName: String = "getCopilotWorkspaceSessions"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"query getCopilotWorkspaceSessions($workspaceId: String!, $pagination: PaginationInput!, $options: QueryChatHistoriesInput) { currentUser { __typename copilot(workspaceId: $workspaceId) { __typename chats(pagination: $pagination, docId: null, options: $options) { __typename ...PaginatedCopilotChats } } } }"#,
fragments: [CopilotChatHistory.self, CopilotChatMessage.self, PaginatedCopilotChats.self]
))
public var workspaceId: String
public var pagination: PaginationInput
public var options: GraphQLNullable<QueryChatHistoriesInput>
public init(
workspaceId: String,
pagination: PaginationInput,
options: GraphQLNullable<QueryChatHistoriesInput>
) {
self.workspaceId = workspaceId
self.pagination = pagination
self.options = options
}
public var __variables: Variables? { [
"workspaceId": workspaceId,
"pagination": pagination,
"options": options
] }
public struct Data: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Query }
public static var __selections: [ApolloAPI.Selection] { [
.field("currentUser", CurrentUser?.self),
] }
/// Get current user
public var currentUser: CurrentUser? { __data["currentUser"] }
/// CurrentUser
///
/// Parent Type: `UserType`
public struct CurrentUser: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.UserType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("copilot", Copilot.self, arguments: ["workspaceId": .variable("workspaceId")]),
] }
public var copilot: Copilot { __data["copilot"] }
/// CurrentUser.Copilot
///
/// Parent Type: `Copilot`
public struct Copilot: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Copilot }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("chats", Chats.self, arguments: [
"pagination": .variable("pagination"),
"docId": .null,
"options": .variable("options")
]),
] }
public var chats: Chats { __data["chats"] }
/// CurrentUser.Copilot.Chats
///
/// Parent Type: `PaginatedCopilotHistoriesType`
public struct Chats: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.PaginatedCopilotHistoriesType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.fragment(PaginatedCopilotChats.self),
] }
public var pageInfo: PageInfo { __data["pageInfo"] }
public var edges: [Edge] { __data["edges"] }
public struct Fragments: FragmentContainer {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public var paginatedCopilotChats: PaginatedCopilotChats { _toFragment() }
}
public typealias PageInfo = PaginatedCopilotChats.PageInfo
public typealias Edge = PaginatedCopilotChats.Edge
}
}
}
}
}

View File

@@ -7,7 +7,7 @@ public class GetDocRolePermissionsQuery: GraphQLQuery {
public static let operationName: String = "getDocRolePermissions"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"query getDocRolePermissions($workspaceId: String!, $docId: String!) { workspace(id: $workspaceId) { __typename doc(docId: $docId) { __typename permissions { __typename Doc_Copy Doc_Delete Doc_Duplicate Doc_Properties_Read Doc_Properties_Update Doc_Publish Doc_Read Doc_Restore Doc_TransferOwner Doc_Trash Doc_Update Doc_Users_Manage Doc_Users_Read } } } }"#
#"query getDocRolePermissions($workspaceId: String!, $docId: String!) { workspace(id: $workspaceId) { __typename doc(docId: $docId) { __typename permissions { __typename Doc_Copy Doc_Delete Doc_Duplicate Doc_Properties_Read Doc_Properties_Update Doc_Publish Doc_Read Doc_Restore Doc_TransferOwner Doc_Trash Doc_Update Doc_Users_Manage Doc_Users_Read Doc_Comments_Create Doc_Comments_Delete Doc_Comments_Read Doc_Comments_Resolve } } } }"#
))
public var workspaceId: String
@@ -92,6 +92,10 @@ public class GetDocRolePermissionsQuery: GraphQLQuery {
.field("Doc_Update", Bool.self),
.field("Doc_Users_Manage", Bool.self),
.field("Doc_Users_Read", Bool.self),
.field("Doc_Comments_Create", Bool.self),
.field("Doc_Comments_Delete", Bool.self),
.field("Doc_Comments_Read", Bool.self),
.field("Doc_Comments_Resolve", Bool.self),
] }
public var doc_Copy: Bool { __data["Doc_Copy"] }
@@ -107,6 +111,10 @@ public class GetDocRolePermissionsQuery: GraphQLQuery {
public var doc_Update: Bool { __data["Doc_Update"] }
public var doc_Users_Manage: Bool { __data["Doc_Users_Manage"] }
public var doc_Users_Read: Bool { __data["Doc_Users_Read"] }
public var doc_Comments_Create: Bool { __data["Doc_Comments_Create"] }
public var doc_Comments_Delete: Bool { __data["Doc_Comments_Delete"] }
public var doc_Comments_Read: Bool { __data["Doc_Comments_Read"] }
public var doc_Comments_Resolve: Bool { __data["Doc_Comments_Resolve"] }
}
}
}

View File

@@ -7,7 +7,7 @@ public class GetUserSettingsQuery: GraphQLQuery {
public static let operationName: String = "getUserSettings"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"query getUserSettings { currentUser { __typename settings { __typename receiveInvitationEmail receiveMentionEmail } } }"#
#"query getUserSettings { currentUser { __typename settings { __typename receiveInvitationEmail receiveMentionEmail receiveCommentEmail } } }"#
))
public init() {}
@@ -52,12 +52,15 @@ public class GetUserSettingsQuery: GraphQLQuery {
.field("__typename", String.self),
.field("receiveInvitationEmail", Bool.self),
.field("receiveMentionEmail", Bool.self),
.field("receiveCommentEmail", Bool.self),
] }
/// Receive invitation email
public var receiveInvitationEmail: Bool { __data["receiveInvitationEmail"] }
/// Receive mention email
public var receiveMentionEmail: Bool { __data["receiveMentionEmail"] }
/// Receive comment email
public var receiveCommentEmail: Bool { __data["receiveCommentEmail"] }
}
}
}

View File

@@ -0,0 +1,149 @@
// @generated
// This file was automatically generated and should not be edited.
@_exported import ApolloAPI
public class ListCommentChangesQuery: GraphQLQuery {
public static let operationName: String = "listCommentChanges"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"query listCommentChanges($workspaceId: String!, $docId: String!, $pagination: PaginationInput!) { workspace(id: $workspaceId) { __typename commentChanges(docId: $docId, pagination: $pagination) { __typename totalCount edges { __typename cursor node { __typename action id commentId item } } pageInfo { __typename startCursor endCursor hasNextPage hasPreviousPage } } } }"#
))
public var workspaceId: String
public var docId: String
public var pagination: PaginationInput
public init(
workspaceId: String,
docId: String,
pagination: PaginationInput
) {
self.workspaceId = workspaceId
self.docId = docId
self.pagination = pagination
}
public var __variables: Variables? { [
"workspaceId": workspaceId,
"docId": docId,
"pagination": pagination
] }
public struct Data: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Query }
public static var __selections: [ApolloAPI.Selection] { [
.field("workspace", Workspace.self, arguments: ["id": .variable("workspaceId")]),
] }
/// Get workspace by id
public var workspace: Workspace { __data["workspace"] }
/// Workspace
///
/// Parent Type: `WorkspaceType`
public struct Workspace: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.WorkspaceType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("commentChanges", CommentChanges.self, arguments: [
"docId": .variable("docId"),
"pagination": .variable("pagination")
]),
] }
/// Get comment changes of a doc
public var commentChanges: CommentChanges { __data["commentChanges"] }
/// Workspace.CommentChanges
///
/// Parent Type: `PaginatedCommentChangeObjectType`
public struct CommentChanges: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.PaginatedCommentChangeObjectType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("totalCount", Int.self),
.field("edges", [Edge].self),
.field("pageInfo", PageInfo.self),
] }
public var totalCount: Int { __data["totalCount"] }
public var edges: [Edge] { __data["edges"] }
public var pageInfo: PageInfo { __data["pageInfo"] }
/// Workspace.CommentChanges.Edge
///
/// Parent Type: `CommentChangeObjectTypeEdge`
public struct Edge: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.CommentChangeObjectTypeEdge }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("cursor", String.self),
.field("node", Node.self),
] }
public var cursor: String { __data["cursor"] }
public var node: Node { __data["node"] }
/// Workspace.CommentChanges.Edge.Node
///
/// Parent Type: `CommentChangeObjectType`
public struct Node: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.CommentChangeObjectType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("action", GraphQLEnum<AffineGraphQL.CommentChangeAction>.self),
.field("id", AffineGraphQL.ID.self),
.field("commentId", AffineGraphQL.ID?.self),
.field("item", AffineGraphQL.JSONObject.self),
] }
/// The action of the comment change
public var action: GraphQLEnum<AffineGraphQL.CommentChangeAction> { __data["action"] }
public var id: AffineGraphQL.ID { __data["id"] }
public var commentId: AffineGraphQL.ID? { __data["commentId"] }
/// The item of the comment or reply, different types have different fields, see UnionCommentObjectType
public var item: AffineGraphQL.JSONObject { __data["item"] }
}
}
/// Workspace.CommentChanges.PageInfo
///
/// Parent Type: `PageInfo`
public struct PageInfo: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.PageInfo }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("startCursor", String?.self),
.field("endCursor", String?.self),
.field("hasNextPage", Bool.self),
.field("hasPreviousPage", Bool.self),
] }
public var startCursor: String? { __data["startCursor"] }
public var endCursor: String? { __data["endCursor"] }
public var hasNextPage: Bool { __data["hasNextPage"] }
public var hasPreviousPage: Bool { __data["hasPreviousPage"] }
}
}
}
}
}

View File

@@ -0,0 +1,229 @@
// @generated
// This file was automatically generated and should not be edited.
@_exported import ApolloAPI
public class ListCommentsQuery: GraphQLQuery {
public static let operationName: String = "listComments"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"query listComments($workspaceId: String!, $docId: String!, $pagination: PaginationInput) { workspace(id: $workspaceId) { __typename comments(docId: $docId, pagination: $pagination) { __typename totalCount edges { __typename cursor node { __typename id content resolved createdAt updatedAt user { __typename id name avatarUrl } replies { __typename commentId id content createdAt updatedAt user { __typename id name avatarUrl } } } } pageInfo { __typename startCursor endCursor hasNextPage hasPreviousPage } } } }"#
))
public var workspaceId: String
public var docId: String
public var pagination: GraphQLNullable<PaginationInput>
public init(
workspaceId: String,
docId: String,
pagination: GraphQLNullable<PaginationInput>
) {
self.workspaceId = workspaceId
self.docId = docId
self.pagination = pagination
}
public var __variables: Variables? { [
"workspaceId": workspaceId,
"docId": docId,
"pagination": pagination
] }
public struct Data: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Query }
public static var __selections: [ApolloAPI.Selection] { [
.field("workspace", Workspace.self, arguments: ["id": .variable("workspaceId")]),
] }
/// Get workspace by id
public var workspace: Workspace { __data["workspace"] }
/// Workspace
///
/// Parent Type: `WorkspaceType`
public struct Workspace: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.WorkspaceType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("comments", Comments.self, arguments: [
"docId": .variable("docId"),
"pagination": .variable("pagination")
]),
] }
/// Get comments of a doc
public var comments: Comments { __data["comments"] }
/// Workspace.Comments
///
/// Parent Type: `PaginatedCommentObjectType`
public struct Comments: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.PaginatedCommentObjectType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("totalCount", Int.self),
.field("edges", [Edge].self),
.field("pageInfo", PageInfo.self),
] }
public var totalCount: Int { __data["totalCount"] }
public var edges: [Edge] { __data["edges"] }
public var pageInfo: PageInfo { __data["pageInfo"] }
/// Workspace.Comments.Edge
///
/// Parent Type: `CommentObjectTypeEdge`
public struct Edge: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.CommentObjectTypeEdge }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("cursor", String.self),
.field("node", Node.self),
] }
public var cursor: String { __data["cursor"] }
public var node: Node { __data["node"] }
/// Workspace.Comments.Edge.Node
///
/// Parent Type: `CommentObjectType`
public struct Node: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.CommentObjectType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("id", AffineGraphQL.ID.self),
.field("content", AffineGraphQL.JSONObject.self),
.field("resolved", Bool.self),
.field("createdAt", AffineGraphQL.DateTime.self),
.field("updatedAt", AffineGraphQL.DateTime.self),
.field("user", User.self),
.field("replies", [Reply].self),
] }
public var id: AffineGraphQL.ID { __data["id"] }
/// The content of the comment
public var content: AffineGraphQL.JSONObject { __data["content"] }
/// Whether the comment is resolved
public var resolved: Bool { __data["resolved"] }
/// The created at time of the comment
public var createdAt: AffineGraphQL.DateTime { __data["createdAt"] }
/// The updated at time of the comment
public var updatedAt: AffineGraphQL.DateTime { __data["updatedAt"] }
/// The user who created the comment
public var user: User { __data["user"] }
/// The replies of the comment
public var replies: [Reply] { __data["replies"] }
/// Workspace.Comments.Edge.Node.User
///
/// Parent Type: `PublicUserType`
public struct User: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.PublicUserType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("id", String.self),
.field("name", String.self),
.field("avatarUrl", String?.self),
] }
public var id: String { __data["id"] }
public var name: String { __data["name"] }
public var avatarUrl: String? { __data["avatarUrl"] }
}
/// Workspace.Comments.Edge.Node.Reply
///
/// Parent Type: `ReplyObjectType`
public struct Reply: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.ReplyObjectType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("commentId", AffineGraphQL.ID.self),
.field("id", AffineGraphQL.ID.self),
.field("content", AffineGraphQL.JSONObject.self),
.field("createdAt", AffineGraphQL.DateTime.self),
.field("updatedAt", AffineGraphQL.DateTime.self),
.field("user", User.self),
] }
public var commentId: AffineGraphQL.ID { __data["commentId"] }
public var id: AffineGraphQL.ID { __data["id"] }
/// The content of the reply
public var content: AffineGraphQL.JSONObject { __data["content"] }
/// The created at time of the reply
public var createdAt: AffineGraphQL.DateTime { __data["createdAt"] }
/// The updated at time of the reply
public var updatedAt: AffineGraphQL.DateTime { __data["updatedAt"] }
/// The user who created the reply
public var user: User { __data["user"] }
/// Workspace.Comments.Edge.Node.Reply.User
///
/// Parent Type: `PublicUserType`
public struct User: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.PublicUserType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("id", String.self),
.field("name", String.self),
.field("avatarUrl", String?.self),
] }
public var id: String { __data["id"] }
public var name: String { __data["name"] }
public var avatarUrl: String? { __data["avatarUrl"] }
}
}
}
}
/// Workspace.Comments.PageInfo
///
/// Parent Type: `PageInfo`
public struct PageInfo: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.PageInfo }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("startCursor", String?.self),
.field("endCursor", String?.self),
.field("hasNextPage", Bool.self),
.field("hasPreviousPage", Bool.self),
] }
public var startCursor: String? { __data["startCursor"] }
public var endCursor: String? { __data["endCursor"] }
public var hasNextPage: Bool { __data["hasNextPage"] }
public var hasPreviousPage: Bool { __data["hasPreviousPage"] }
}
}
}
}
}

View File

@@ -0,0 +1,10 @@
// @generated
// This file was automatically generated and should not be edited.
import ApolloAPI
/// Comment change action
public enum CommentChangeAction: String, EnumType {
case delete = "delete"
case update = "update"
}

View File

@@ -5,6 +5,7 @@ import ApolloAPI
/// User permission in doc
public enum DocRole: String, EnumType {
case commenter = "Commenter"
case editor = "Editor"
case external = "External"
case manager = "Manager"

View File

@@ -5,6 +5,8 @@ import ApolloAPI
/// Notification type
public enum NotificationType: String, EnumType {
case comment = "Comment"
case commentMention = "CommentMention"
case invitation = "Invitation"
case invitationAccepted = "InvitationAccepted"
case invitationBlocked = "InvitationBlocked"

View File

@@ -5,9 +5,11 @@ import ApolloAPI
public enum ServerFeature: String, EnumType {
case captcha = "Captcha"
case comment = "Comment"
case copilot = "Copilot"
case copilotEmbedding = "CopilotEmbedding"
case indexer = "Indexer"
case localWorkspace = "LocalWorkspace"
case oAuth = "OAuth"
case payment = "Payment"
}

View File

@@ -11,7 +11,7 @@ public struct AddContextFileInput: InputObject {
}
public init(
blobId: String,
blobId: GraphQLNullable<String> = nil,
contextId: String
) {
__data = InputDict([
@@ -20,7 +20,7 @@ public struct AddContextFileInput: InputObject {
])
}
public var blobId: String {
public var blobId: GraphQLNullable<String> {
get { __data["blobId"] }
set { __data["blobId"] = newValue }
}

View File

@@ -0,0 +1,61 @@
// @generated
// This file was automatically generated and should not be edited.
import ApolloAPI
public struct CommentCreateInput: InputObject {
public private(set) var __data: InputDict
public init(_ data: InputDict) {
__data = data
}
public init(
content: JSONObject,
docId: ID,
docMode: GraphQLEnum<DocMode>,
docTitle: String,
mentions: GraphQLNullable<[String]> = nil,
workspaceId: ID
) {
__data = InputDict([
"content": content,
"docId": docId,
"docMode": docMode,
"docTitle": docTitle,
"mentions": mentions,
"workspaceId": workspaceId
])
}
public var content: JSONObject {
get { __data["content"] }
set { __data["content"] = newValue }
}
public var docId: ID {
get { __data["docId"] }
set { __data["docId"] = newValue }
}
public var docMode: GraphQLEnum<DocMode> {
get { __data["docMode"] }
set { __data["docMode"] = newValue }
}
public var docTitle: String {
get { __data["docTitle"] }
set { __data["docTitle"] = newValue }
}
/// The mention user ids, if not provided, the comment will not be mentioned
public var mentions: GraphQLNullable<[String]> {
get { __data["mentions"] }
set { __data["mentions"] = newValue }
}
public var workspaceId: ID {
get { __data["workspaceId"] }
set { __data["workspaceId"] = newValue }
}
}

View File

@@ -0,0 +1,33 @@
// @generated
// This file was automatically generated and should not be edited.
import ApolloAPI
public struct CommentResolveInput: InputObject {
public private(set) var __data: InputDict
public init(_ data: InputDict) {
__data = data
}
public init(
id: ID,
resolved: Bool
) {
__data = InputDict([
"id": id,
"resolved": resolved
])
}
public var id: ID {
get { __data["id"] }
set { __data["id"] = newValue }
}
/// Whether the comment is resolved
public var resolved: Bool {
get { __data["resolved"] }
set { __data["resolved"] = newValue }
}
}

View File

@@ -0,0 +1,32 @@
// @generated
// This file was automatically generated and should not be edited.
import ApolloAPI
public struct CommentUpdateInput: InputObject {
public private(set) var __data: InputDict
public init(_ data: InputDict) {
__data = data
}
public init(
content: JSONObject,
id: ID
) {
__data = InputDict([
"content": content,
"id": id
])
}
public var content: JSONObject {
get { __data["content"] }
set { __data["content"] = newValue }
}
public var id: ID {
get { __data["id"] }
set { __data["id"] = newValue }
}
}

View File

@@ -14,12 +14,14 @@ public struct CreateChatSessionInput: InputObject {
docId: GraphQLNullable<String> = nil,
pinned: GraphQLNullable<Bool> = nil,
promptName: String,
reuseLatestChat: GraphQLNullable<Bool> = nil,
workspaceId: String
) {
__data = InputDict([
"docId": docId,
"pinned": pinned,
"promptName": promptName,
"reuseLatestChat": reuseLatestChat,
"workspaceId": workspaceId
])
}
@@ -40,6 +42,12 @@ public struct CreateChatSessionInput: InputObject {
set { __data["promptName"] = newValue }
}
/// true by default, compliant for old version
public var reuseLatestChat: GraphQLNullable<Bool> {
get { __data["reuseLatestChat"] }
set { __data["reuseLatestChat"] = newValue }
}
public var workspaceId: String {
get { __data["workspaceId"] }
set { __data["workspaceId"] = newValue }

View File

@@ -19,6 +19,7 @@ public struct QueryChatHistoriesInput: InputObject {
sessionId: GraphQLNullable<String> = nil,
sessionOrder: GraphQLNullable<GraphQLEnum<ChatHistoryOrder>> = nil,
skip: GraphQLNullable<Int> = nil,
withMessages: GraphQLNullable<Bool> = nil,
withPrompt: GraphQLNullable<Bool> = nil
) {
__data = InputDict([
@@ -30,6 +31,7 @@ public struct QueryChatHistoriesInput: InputObject {
"sessionId": sessionId,
"sessionOrder": sessionOrder,
"skip": skip,
"withMessages": withMessages,
"withPrompt": withPrompt
])
}
@@ -74,6 +76,11 @@ public struct QueryChatHistoriesInput: InputObject {
set { __data["skip"] = newValue }
}
public var withMessages: GraphQLNullable<Bool> {
get { __data["withMessages"] }
set { __data["withMessages"] = newValue }
}
public var withPrompt: GraphQLNullable<Bool> {
get { __data["withPrompt"] }
set { __data["withPrompt"] = newValue }

View File

@@ -1,53 +0,0 @@
// @generated
// This file was automatically generated and should not be edited.
import ApolloAPI
public struct QueryChatSessionsInput: InputObject {
public private(set) var __data: InputDict
public init(_ data: InputDict) {
__data = data
}
public init(
action: GraphQLNullable<Bool> = nil,
fork: GraphQLNullable<Bool> = nil,
limit: GraphQLNullable<Int> = nil,
pinned: GraphQLNullable<Bool> = nil,
skip: GraphQLNullable<Int> = nil
) {
__data = InputDict([
"action": action,
"fork": fork,
"limit": limit,
"pinned": pinned,
"skip": skip
])
}
public var action: GraphQLNullable<Bool> {
get { __data["action"] }
set { __data["action"] = newValue }
}
public var fork: GraphQLNullable<Bool> {
get { __data["fork"] }
set { __data["fork"] = newValue }
}
public var limit: GraphQLNullable<Int> {
get { __data["limit"] }
set { __data["limit"] = newValue }
}
public var pinned: GraphQLNullable<Bool> {
get { __data["pinned"] }
set { __data["pinned"] = newValue }
}
public var skip: GraphQLNullable<Int> {
get { __data["skip"] }
set { __data["skip"] = newValue }
}
}

View File

@@ -0,0 +1,54 @@
// @generated
// This file was automatically generated and should not be edited.
import ApolloAPI
public struct ReplyCreateInput: InputObject {
public private(set) var __data: InputDict
public init(_ data: InputDict) {
__data = data
}
public init(
commentId: ID,
content: JSONObject,
docMode: GraphQLEnum<DocMode>,
docTitle: String,
mentions: GraphQLNullable<[String]> = nil
) {
__data = InputDict([
"commentId": commentId,
"content": content,
"docMode": docMode,
"docTitle": docTitle,
"mentions": mentions
])
}
public var commentId: ID {
get { __data["commentId"] }
set { __data["commentId"] = newValue }
}
public var content: JSONObject {
get { __data["content"] }
set { __data["content"] = newValue }
}
public var docMode: GraphQLEnum<DocMode> {
get { __data["docMode"] }
set { __data["docMode"] = newValue }
}
public var docTitle: String {
get { __data["docTitle"] }
set { __data["docTitle"] = newValue }
}
/// The mention user ids, if not provided, the comment reply will not be mentioned
public var mentions: GraphQLNullable<[String]> {
get { __data["mentions"] }
set { __data["mentions"] = newValue }
}
}

View File

@@ -0,0 +1,32 @@
// @generated
// This file was automatically generated and should not be edited.
import ApolloAPI
public struct ReplyUpdateInput: InputObject {
public private(set) var __data: InputDict
public init(_ data: InputDict) {
__data = data
}
public init(
content: JSONObject,
id: ID
) {
__data = InputDict([
"content": content,
"id": id
])
}
public var content: JSONObject {
get { __data["content"] }
set { __data["content"] = newValue }
}
public var id: ID {
get { __data["id"] }
set { __data["id"] = newValue }
}
}

View File

@@ -11,15 +11,23 @@ public struct UpdateUserSettingsInput: InputObject {
}
public init(
receiveCommentEmail: GraphQLNullable<Bool> = nil,
receiveInvitationEmail: GraphQLNullable<Bool> = nil,
receiveMentionEmail: GraphQLNullable<Bool> = nil
) {
__data = InputDict([
"receiveCommentEmail": receiveCommentEmail,
"receiveInvitationEmail": receiveInvitationEmail,
"receiveMentionEmail": receiveMentionEmail
])
}
/// Receive comment email
public var receiveCommentEmail: GraphQLNullable<Bool> {
get { __data["receiveCommentEmail"] }
set { __data["receiveCommentEmail"] = newValue }
}
/// Receive invitation email
public var receiveInvitationEmail: GraphQLNullable<Bool> {
get { __data["receiveInvitationEmail"] }

View File

@@ -0,0 +1,12 @@
// @generated
// This file was automatically generated and should not be edited.
import ApolloAPI
public extension Objects {
static let CommentChangeObjectType = ApolloAPI.Object(
typename: "CommentChangeObjectType",
implementedInterfaces: [],
keyFields: nil
)
}

View File

@@ -0,0 +1,12 @@
// @generated
// This file was automatically generated and should not be edited.
import ApolloAPI
public extension Objects {
static let CommentChangeObjectTypeEdge = ApolloAPI.Object(
typename: "CommentChangeObjectTypeEdge",
implementedInterfaces: [],
keyFields: nil
)
}

View File

@@ -4,8 +4,8 @@
import ApolloAPI
public extension Objects {
static let CopilotSessionType = ApolloAPI.Object(
typename: "CopilotSessionType",
static let CommentObjectType = ApolloAPI.Object(
typename: "CommentObjectType",
implementedInterfaces: [],
keyFields: nil
)

View File

@@ -0,0 +1,12 @@
// @generated
// This file was automatically generated and should not be edited.
import ApolloAPI
public extension Objects {
static let CommentObjectTypeEdge = ApolloAPI.Object(
typename: "CommentObjectTypeEdge",
implementedInterfaces: [],
keyFields: nil
)
}

View File

@@ -0,0 +1,12 @@
// @generated
// This file was automatically generated and should not be edited.
import ApolloAPI
public extension Objects {
static let CopilotHistoriesTypeEdge = ApolloAPI.Object(
typename: "CopilotHistoriesTypeEdge",
implementedInterfaces: [],
keyFields: nil
)
}

View File

@@ -0,0 +1,12 @@
// @generated
// This file was automatically generated and should not be edited.
import ApolloAPI
public extension Objects {
static let PaginatedCommentChangeObjectType = ApolloAPI.Object(
typename: "PaginatedCommentChangeObjectType",
implementedInterfaces: [],
keyFields: nil
)
}

View File

@@ -0,0 +1,12 @@
// @generated
// This file was automatically generated and should not be edited.
import ApolloAPI
public extension Objects {
static let PaginatedCommentObjectType = ApolloAPI.Object(
typename: "PaginatedCommentObjectType",
implementedInterfaces: [],
keyFields: nil
)
}

View File

@@ -0,0 +1,12 @@
// @generated
// This file was automatically generated and should not be edited.
import ApolloAPI
public extension Objects {
static let PaginatedCopilotHistoriesType = ApolloAPI.Object(
typename: "PaginatedCopilotHistoriesType",
implementedInterfaces: [],
keyFields: nil
)
}

View File

@@ -0,0 +1,12 @@
// @generated
// This file was automatically generated and should not be edited.
import ApolloAPI
public extension Objects {
static let ReplyObjectType = ApolloAPI.Object(
typename: "ReplyObjectType",
implementedInterfaces: [],
keyFields: nil
)
}

View File

@@ -25,6 +25,10 @@ public enum SchemaMetadata: ApolloAPI.SchemaMetadata {
case "AggregateResultObjectType": return AffineGraphQL.Objects.AggregateResultObjectType
case "AppConfigValidateResult": return AffineGraphQL.Objects.AppConfigValidateResult
case "ChatMessage": return AffineGraphQL.Objects.ChatMessage
case "CommentChangeObjectType": return AffineGraphQL.Objects.CommentChangeObjectType
case "CommentChangeObjectTypeEdge": return AffineGraphQL.Objects.CommentChangeObjectTypeEdge
case "CommentObjectType": return AffineGraphQL.Objects.CommentObjectType
case "CommentObjectTypeEdge": return AffineGraphQL.Objects.CommentObjectTypeEdge
case "ContextMatchedDocChunk": return AffineGraphQL.Objects.ContextMatchedDocChunk
case "ContextMatchedFileChunk": return AffineGraphQL.Objects.ContextMatchedFileChunk
case "ContextWorkspaceEmbeddingStatus": return AffineGraphQL.Objects.ContextWorkspaceEmbeddingStatus
@@ -35,11 +39,11 @@ public enum SchemaMetadata: ApolloAPI.SchemaMetadata {
case "CopilotContextFile": return AffineGraphQL.Objects.CopilotContextFile
case "CopilotDocType": return AffineGraphQL.Objects.CopilotDocType
case "CopilotHistories": return AffineGraphQL.Objects.CopilotHistories
case "CopilotHistoriesTypeEdge": return AffineGraphQL.Objects.CopilotHistoriesTypeEdge
case "CopilotPromptConfigType": return AffineGraphQL.Objects.CopilotPromptConfigType
case "CopilotPromptMessageType": return AffineGraphQL.Objects.CopilotPromptMessageType
case "CopilotPromptType": return AffineGraphQL.Objects.CopilotPromptType
case "CopilotQuota": return AffineGraphQL.Objects.CopilotQuota
case "CopilotSessionType": return AffineGraphQL.Objects.CopilotSessionType
case "CopilotWorkspaceConfig": return AffineGraphQL.Objects.CopilotWorkspaceConfig
case "CopilotWorkspaceFile": return AffineGraphQL.Objects.CopilotWorkspaceFile
case "CopilotWorkspaceFileTypeEdge": return AffineGraphQL.Objects.CopilotWorkspaceFileTypeEdge
@@ -67,6 +71,9 @@ public enum SchemaMetadata: ApolloAPI.SchemaMetadata {
case "NotificationObjectType": return AffineGraphQL.Objects.NotificationObjectType
case "NotificationObjectTypeEdge": return AffineGraphQL.Objects.NotificationObjectTypeEdge
case "PageInfo": return AffineGraphQL.Objects.PageInfo
case "PaginatedCommentChangeObjectType": return AffineGraphQL.Objects.PaginatedCommentChangeObjectType
case "PaginatedCommentObjectType": return AffineGraphQL.Objects.PaginatedCommentObjectType
case "PaginatedCopilotHistoriesType": return AffineGraphQL.Objects.PaginatedCopilotHistoriesType
case "PaginatedCopilotWorkspaceFileType": return AffineGraphQL.Objects.PaginatedCopilotWorkspaceFileType
case "PaginatedDocType": return AffineGraphQL.Objects.PaginatedDocType
case "PaginatedGrantedDocUserType": return AffineGraphQL.Objects.PaginatedGrantedDocUserType
@@ -77,6 +84,7 @@ public enum SchemaMetadata: ApolloAPI.SchemaMetadata {
case "Query": return AffineGraphQL.Objects.Query
case "ReleaseVersionType": return AffineGraphQL.Objects.ReleaseVersionType
case "RemoveAvatar": return AffineGraphQL.Objects.RemoveAvatar
case "ReplyObjectType": return AffineGraphQL.Objects.ReplyObjectType
case "SearchDocObjectType": return AffineGraphQL.Objects.SearchDocObjectType
case "SearchNodeObjectType": return AffineGraphQL.Objects.SearchNodeObjectType
case "SearchResultObjectType": return AffineGraphQL.Objects.SearchResultObjectType

View File

@@ -33,7 +33,7 @@ extension ChatManager {
append(sessionId: sessionId, UserMessageCellViewModel(
id: .init(),
content: inputBoxData.text,
timestamp: .init(),
timestamp: .init()
))
append(sessionId: sessionId, UserHintCellViewModel(
id: .init(),

View File

@@ -55,7 +55,7 @@ class AssistantMessageCell: ChatBaseCell {
)
markdownViewForSizeCalculation.setMarkdown(
vm.documentBlocks,
renderedContent: vm.documentRenderedContent,
renderedContent: vm.documentRenderedContent
)
let boundingSize = markdownViewForSizeCalculation.boundingSize(for: width)
return ceil(boundingSize.height)

View File

@@ -1,4 +1,5 @@
import type {
AddContextFileInput,
ContextMatchedDocChunk,
ContextMatchedFileChunk,
ContextWorkspaceEmbeddingStatus,
@@ -295,10 +296,7 @@ declare global {
}) => Promise<boolean>;
addContextFile: (
file: File,
options: {
contextId: string;
blobId: string;
}
options: AddContextFileInput
) => Promise<CopilotContextFile>;
removeContextFile: (options: {
contextId: string;

View File

@@ -1,5 +1,9 @@
import type { TextRendererOptions } from '@affine/core/blocksuite/ai/components/text-renderer';
import type { EditorHost } from '@blocksuite/affine/std';
import {
NotificationProvider,
ThemeProvider,
} from '@blocksuite/affine-shared/services';
import { css, html, LitElement } from 'lit';
import { property } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
@@ -65,6 +69,7 @@ export class AIChatBlockMessage extends LitElement {
}
private renderStreamObjects(answer: StreamObject[]) {
const notificationService = this.host.std.get(NotificationProvider);
return html`<chat-content-stream-objects
.answer=${answer}
.host=${this.host}
@@ -72,17 +77,19 @@ export class AIChatBlockMessage extends LitElement {
.extensions=${this.textRendererOptions.extensions}
.affineFeatureFlagService=${this.textRendererOptions
.affineFeatureFlagService}
.notificationService=${notificationService}
.theme=${this.host.std.get(ThemeProvider).app$}
></chat-content-stream-objects>`;
}
private renderRichText(text: string) {
return html`<chat-content-rich-text
.host=${this.host}
.text=${text}
.state=${this.state}
.extensions=${this.textRendererOptions.extensions}
.affineFeatureFlagService=${this.textRendererOptions
.affineFeatureFlagService}
.theme=${this.host.std.get(ThemeProvider).app$}
></chat-content-rich-text>`;
}

View File

@@ -1,6 +1,7 @@
import { WithDisposable } from '@blocksuite/affine/global/lit';
import { unsafeCSSVar, unsafeCSSVarV2 } from '@blocksuite/affine/shared/theme';
import type { EditorHost } from '@blocksuite/affine/std';
import { ThemeProvider } from '@blocksuite/affine-shared/services';
import {
ArrowDownBigIcon as ArrowDownIcon,
ArrowUpBigIcon as ArrowUpIcon,
@@ -163,16 +164,18 @@ export class ActionWrapper extends WithDisposable(LitElement) {
></chat-content-images>`
: nothing}
${answer
? createTextRenderer(this.host, {
? createTextRenderer({
customHeading: true,
testId: 'chat-message-action-answer',
theme: this.host.std.get(ThemeProvider).app$,
})(answer)
: nothing}
${originalText
? html`<div class="subtitle prompt">Prompt</div>
${createTextRenderer(this.host, {
${createTextRenderer({
customHeading: true,
testId: 'chat-message-action-prompt',
theme: this.host.std.get(ThemeProvider).app$,
})(item.messages[0].content + originalText)}`
: nothing}
</div>

View File

@@ -3,6 +3,7 @@ import './action-wrapper';
import { WithDisposable } from '@blocksuite/affine/global/lit';
import { unsafeCSSVar } from '@blocksuite/affine/shared/theme';
import type { EditorHost } from '@blocksuite/affine/std';
import { ThemeProvider } from '@blocksuite/affine-shared/services';
import { css, html, LitElement } from 'lit';
import { property } from 'lit/decorators.js';
import { styleMap } from 'lit/directives/style-map.js';
@@ -57,8 +58,9 @@ export class ActionText extends WithDisposable(LitElement) {
class="original-text"
data-testid="original-text"
>
${createTextRenderer(this.host, {
${createTextRenderer({
customHeading: true,
theme: this.host.std.get(ThemeProvider).app$,
})(originalText)}
</div>
</action-wrapper>`;

View File

@@ -1,5 +1,6 @@
import type { WorkspaceDialogService } from '@affine/core/modules/dialogs';
import type { FeatureFlagService } from '@affine/core/modules/feature-flag';
import type { AppThemeService } from '@affine/core/modules/theme';
import type { WorkbenchService } from '@affine/core/modules/workbench';
import type {
ContextEmbedStatus,
@@ -7,7 +8,7 @@ import type {
UpdateChatSessionInput,
} from '@affine/graphql';
import { SignalWatcher, WithDisposable } from '@blocksuite/affine/global/lit';
import { NotificationProvider } from '@blocksuite/affine/shared/services';
import { type NotificationService } from '@blocksuite/affine/shared/services';
import { unsafeCSSVarV2 } from '@blocksuite/affine/shared/theme';
import type { EditorHost } from '@blocksuite/affine/std';
import { ShadowlessElement } from '@blocksuite/affine/std';
@@ -125,6 +126,12 @@ export class ChatPanel extends SignalWatcher(
@property({ attribute: false })
accessor affineWorkbenchService!: WorkbenchService;
@property({ attribute: false })
accessor affineThemeService!: AppThemeService;
@property({ attribute: false })
accessor notificationService!: NotificationService;
@state()
accessor session: CopilotChatHistoryFragment | null | undefined;
@@ -144,7 +151,6 @@ export class ChatPanel extends SignalWatcher(
private get chatTitle() {
const [done, total] = this.embeddingProgress;
const isEmbedding = total > 0 && done < total;
const notification = this.host.std.getOptional(NotificationProvider);
return html`
<div class="chat-panel-title-text">
@@ -170,7 +176,7 @@ export class ChatPanel extends SignalWatcher(
.onOpenSession=${this.openSession}
.onOpenDoc=${this.openDoc}
.docDisplayConfig=${this.docDisplayConfig}
.notification=${notification}
.notificationService=${this.notificationService}
></ai-chat-toolbar>
`;
}
@@ -371,6 +377,8 @@ export class ChatPanel extends SignalWatcher(
.docDisplayConfig=${this.docDisplayConfig}
.extensions=${this.extensions}
.affineFeatureFlagService=${this.affineFeatureFlagService}
.affineThemeService=${this.affineThemeService}
.notificationService=${this.notificationService}
></playground-content>
`;
@@ -444,6 +452,8 @@ export class ChatPanel extends SignalWatcher(
.extensions=${this.extensions}
.affineFeatureFlagService=${this.affineFeatureFlagService}
.affineWorkspaceDialogService=${this.affineWorkspaceDialogService}
.affineThemeService=${this.affineThemeService}
.notificationService=${this.notificationService}
.onEmbeddingProgressChange=${this.onEmbeddingProgressChange}
.onContextChange=${this.onContextChange}
.width=${this.sidebarWidth}

View File

@@ -1,10 +1,12 @@
import type { FeatureFlagService } from '@affine/core/modules/feature-flag';
import type { AppThemeService } from '@affine/core/modules/theme';
import type { CopilotChatHistoryFragment } from '@affine/graphql';
import { WithDisposable } from '@blocksuite/affine/global/lit';
import { isInsidePageEditor } from '@blocksuite/affine/shared/utils';
import type { EditorHost } from '@blocksuite/affine/std';
import { ShadowlessElement } from '@blocksuite/affine/std';
import type { ExtensionType } from '@blocksuite/affine/store';
import type { NotificationService } from '@blocksuite/affine-shared/services';
import type { Signal } from '@preact/signals-core';
import { css, html, nothing } from 'lit';
import { property } from 'lit/decorators.js';
@@ -35,9 +37,6 @@ export class ChatMessageAssistant extends WithDisposable(ShadowlessElement) {
@property({ attribute: false })
accessor host: EditorHost | null | undefined;
@property({ attribute: false })
accessor docId: string | undefined;
@property({ attribute: false })
accessor item!: ChatMessage;
@@ -56,6 +55,9 @@ export class ChatMessageAssistant extends WithDisposable(ShadowlessElement) {
@property({ attribute: false })
accessor affineFeatureFlagService!: FeatureFlagService;
@property({ attribute: false })
accessor affineThemeService!: AppThemeService;
@property({ attribute: false })
accessor session!: CopilotChatHistoryFragment | null | undefined;
@@ -68,6 +70,9 @@ export class ChatMessageAssistant extends WithDisposable(ShadowlessElement) {
@property({ attribute: false })
accessor width: Signal<number | undefined> | undefined;
@property({ attribute: false })
accessor notificationService!: NotificationService;
get state() {
const { isLast, status } = this;
return isLast
@@ -118,27 +123,29 @@ export class ChatMessageAssistant extends WithDisposable(ShadowlessElement) {
private renderStreamObjects(answer: StreamObject[]) {
return html`<chat-content-stream-objects
.answer=${answer}
.host=${this.host}
.answer=${answer}
.state=${this.state}
.width=${this.width}
.extensions=${this.extensions}
.affineFeatureFlagService=${this.affineFeatureFlagService}
.notificationService=${this.notificationService}
.theme=${this.affineThemeService.appTheme.themeSignal}
></chat-content-stream-objects>`;
}
private renderRichText(text: string) {
return html`<chat-content-rich-text
.host=${this.host}
.text=${text}
.state=${this.state}
.extensions=${this.extensions}
.affineFeatureFlagService=${this.affineFeatureFlagService}
.theme=${this.affineThemeService.appTheme.themeSignal}
></chat-content-rich-text>`;
}
private renderEditorActions() {
const { item, isLast, status, host, session, docId } = this;
const { item, isLast, status, host, session } = this;
if (!isChatMessage(item) || item.role !== 'assistant') return nothing;
@@ -161,7 +168,7 @@ export class ChatMessageAssistant extends WithDisposable(ShadowlessElement) {
: EdgelessEditorActions
: null;
const showActions = host && docId && !!markdown;
const showActions = host && !!markdown;
return html`
<chat-copy-more
@@ -173,6 +180,7 @@ export class ChatMessageAssistant extends WithDisposable(ShadowlessElement) {
.messageId=${messageId}
.withMargin=${true}
.retry=${() => this.retry()}
.notificationService=${this.notificationService}
></chat-copy-more>
${isLast && showActions
? html`<chat-action-list
@@ -182,6 +190,7 @@ export class ChatMessageAssistant extends WithDisposable(ShadowlessElement) {
.content=${markdown}
.messageId=${messageId ?? undefined}
.withMargin=${true}
.notificationService=${this.notificationService}
></chat-action-list>`
: nothing}
`;

View File

@@ -2,7 +2,7 @@ import type { TagMeta } from '@affine/core/components/page-list';
import { createLitPortal } from '@blocksuite/affine/components/portal';
import { SignalWatcher, WithDisposable } from '@blocksuite/affine/global/lit';
import { unsafeCSSVarV2 } from '@blocksuite/affine/shared/theme';
import { type EditorHost, ShadowlessElement } from '@blocksuite/affine/std';
import { ShadowlessElement } from '@blocksuite/affine/std';
import { MoreVerticalIcon, PlusIcon } from '@blocksuite/icons/lit';
import { flip, offset } from '@floating-ui/dom';
import { computed, type Signal, signal } from '@preact/signals-core';
@@ -82,9 +82,6 @@ export class ChatPanelChips extends SignalWatcher(
private _abortController: AbortController | null = null;
@property({ attribute: false })
accessor host: EditorHost | null | undefined;
@property({ attribute: false })
accessor chips!: ChatChip[];
@@ -167,7 +164,6 @@ export class ChatPanelChips extends SignalWatcher(
.removeChip=${this._removeChip}
.checkTokenLimit=${this._checkTokenLimit}
.docDisplayConfig=${this.docDisplayConfig}
.host=${this.host}
></chat-panel-doc-chip>`;
}
if (isFileChip(chip)) {
@@ -407,13 +403,8 @@ export class ChatPanelChips extends SignalWatcher(
if (!contextId || !AIProvider.context) {
throw new Error('Context not found');
}
if (!this.host) {
throw new Error('Host not found');
}
const blobId = await this.host.store.blobSync.set(chip.file);
const contextFile = await AIProvider.context.addContextFile(chip.file, {
contextId,
blobId,
});
this._updateChip(chip, {
state: contextFile.status,

View File

@@ -1,6 +1,6 @@
import track from '@affine/track';
import { SignalWatcher, WithDisposable } from '@blocksuite/affine/global/lit';
import { type EditorHost, ShadowlessElement } from '@blocksuite/affine/std';
import { ShadowlessElement } from '@blocksuite/affine/std';
import { Signal } from '@preact/signals-core';
import { html, type PropertyValues } from 'lit';
import { property } from 'lit/decorators.js';
@@ -36,9 +36,6 @@ export class ChatPanelDocChip extends SignalWatcher(
@property({ attribute: false })
accessor docDisplayConfig!: DocDisplayConfig;
@property({ attribute: false })
accessor host: EditorHost | null | undefined;
private chipName = new Signal<string>('');
override connectedCallback() {
@@ -103,9 +100,6 @@ export class ChatPanelDocChip extends SignalWatcher(
};
private readonly processDocChip = async () => {
if (!this.host) {
return;
}
try {
const doc = this.docDisplayConfig.getDoc(this.chip.docId);
if (!doc) {
@@ -114,10 +108,7 @@ export class ChatPanelDocChip extends SignalWatcher(
if (!doc.ready) {
doc.load();
}
const value = await extractMarkdownFromDoc(
doc,
this.host.std.store.provider
);
const value = await extractMarkdownFromDoc(doc);
const tokenCount = estimateTokenCount(value);
if (this.checkTokenLimit(this.chip, tokenCount)) {
const markdown = this.chip.markdown ?? new Signal<string>('');

View File

@@ -120,7 +120,6 @@ export class AIChatComposer extends SignalWatcher(
override render() {
return html`
<chat-panel-chips
.host=${this.host}
.chips=${this.chips}
.createContextId=${this._createContextId}
.updateChips=${this.updateChips}

View File

@@ -1,5 +1,6 @@
import type { WorkspaceDialogService } from '@affine/core/modules/dialogs';
import type { FeatureFlagService } from '@affine/core/modules/feature-flag';
import type { AppThemeService } from '@affine/core/modules/theme';
import type {
ContextEmbedStatus,
CopilotChatHistoryFragment,
@@ -8,6 +9,7 @@ import { SignalWatcher, WithDisposable } from '@blocksuite/affine/global/lit';
import type { EditorHost } from '@blocksuite/affine/std';
import { ShadowlessElement } from '@blocksuite/affine/std';
import type { ExtensionType } from '@blocksuite/affine/store';
import type { NotificationService } from '@blocksuite/affine-shared/services';
import { type Signal } from '@preact/signals-core';
import {
css,
@@ -160,6 +162,12 @@ export class AIChatContent extends SignalWatcher(
@property({ attribute: false })
accessor affineWorkspaceDialogService!: WorkspaceDialogService;
@property({ attribute: false })
accessor affineThemeService!: AppThemeService;
@property({ attribute: false })
accessor notificationService!: NotificationService;
@property({ attribute: false })
accessor onEmbeddingProgressChange!: (
count: Record<ContextEmbedStatus, number>
@@ -401,6 +409,8 @@ export class AIChatContent extends SignalWatcher(
.isHistoryLoading=${this.isHistoryLoading}
.extensions=${this.extensions}
.affineFeatureFlagService=${this.affineFeatureFlagService}
.affineThemeService=${this.affineThemeService}
.notificationService=${this.notificationService}
.networkSearchConfig=${this.networkSearchConfig}
.reasoningConfig=${this.reasoningConfig}
.width=${this.width}

View File

@@ -1,8 +1,10 @@
import type { AppThemeService } from '@affine/core/modules/theme';
import type { CopilotChatHistoryFragment } from '@affine/graphql';
import { WithDisposable } from '@blocksuite/affine/global/lit';
import {
DocModeProvider,
FeatureFlagService,
type FeatureFlagService,
type NotificationService,
} from '@blocksuite/affine/shared/services';
import type { EditorHost } from '@blocksuite/affine/std';
import { ShadowlessElement } from '@blocksuite/affine/std';
@@ -187,6 +189,12 @@ export class AIChatMessages extends WithDisposable(ShadowlessElement) {
@property({ attribute: false })
accessor affineFeatureFlagService!: FeatureFlagService;
@property({ attribute: false })
accessor affineThemeService!: AppThemeService;
@property({ attribute: false })
accessor notificationService!: NotificationService;
@property({ attribute: false })
accessor networkSearchConfig!: AINetworkSearchConfig;
@@ -222,8 +230,7 @@ export class AIChatMessages extends WithDisposable(ShadowlessElement) {
}
private _renderAIOnboarding() {
return this.isHistoryLoading ||
!this.host?.store.get(FeatureFlagService).getFlag('enable_ai_onboarding')
return this.isHistoryLoading
? nothing
: html`<div class="onboarding-wrapper" data-testid="ai-onboarding">
${repeat(
@@ -311,7 +318,6 @@ export class AIChatMessages extends WithDisposable(ShadowlessElement) {
} else if (isChatMessage(item) && item.role === 'assistant') {
return html`<chat-message-assistant
.host=${this.host}
.docId=${this.docId}
.session=${this.session}
.item=${item}
.isLast=${isLast}
@@ -319,6 +325,8 @@ export class AIChatMessages extends WithDisposable(ShadowlessElement) {
.error=${isLast ? error : null}
.extensions=${this.extensions}
.affineFeatureFlagService=${this.affineFeatureFlagService}
.affineThemeService=${this.affineThemeService}
.notificationService=${this.notificationService}
.retry=${() => this.retry()}
.width=${this.width}
></chat-message-assistant>`;

View File

@@ -42,7 +42,7 @@ export class AIChatToolbar extends WithDisposable(ShadowlessElement) {
accessor docDisplayConfig!: DocDisplayConfig;
@property({ attribute: false })
accessor notification: NotificationService | null | undefined;
accessor notificationService!: NotificationService;
@query('.history-button')
accessor historyButton!: HTMLDivElement;
@@ -104,21 +104,19 @@ export class AIChatToolbar extends WithDisposable(ShadowlessElement) {
private readonly unpinConfirm = async () => {
if (this.session && this.session.pinned) {
try {
const confirm = this.notification
? await this.notification.confirm({
title: 'Switch Chat? Current chat is pinned',
message:
'Switching will unpinned the current chat. This will change the active chat panel, allowing you to navigate between different conversation histories.',
confirmText: 'Switch Chat',
cancelText: 'Cancel',
})
: true;
const confirm = await this.notificationService.confirm({
title: 'Switch Chat? Current chat is pinned',
message:
'Switching will unpinned the current chat. This will change the active chat panel, allowing you to navigate between different conversation histories.',
confirmText: 'Switch Chat',
cancelText: 'Cancel',
});
if (!confirm) {
return false;
}
await this.onTogglePin();
} catch {
this.notification?.toast('Failed to unpin the chat');
this.notificationService.toast('Failed to unpin the chat');
}
}
return true;
@@ -133,7 +131,7 @@ export class AIChatToolbar extends WithDisposable(ShadowlessElement) {
private readonly onSessionClick = async (sessionId: string) => {
if (this.session?.sessionId === sessionId) {
this.notification?.toast('You are already in this chat');
this.notificationService.toast('You are already in this chat');
return;
}
const confirm = await this.unpinConfirm();
@@ -144,7 +142,7 @@ export class AIChatToolbar extends WithDisposable(ShadowlessElement) {
private readonly onDocClick = async (docId: string, sessionId: string) => {
if (this.docId === docId && this.session?.sessionId === sessionId) {
this.notification?.toast('You are already in this chat');
this.notificationService.toast('You are already in this chat');
return;
}
this.onOpenDoc(docId, sessionId);
@@ -169,7 +167,6 @@ export class AIChatToolbar extends WithDisposable(ShadowlessElement) {
.docDisplayConfig=${this.docDisplayConfig}
.onSessionClick=${this.onSessionClick}
.onDocClick=${this.onDocClick}
.notification=${this.notification}
></ai-session-history>
`,
portalStyles: {

View File

@@ -1,6 +1,5 @@
import type { CopilotSessionType } from '@affine/graphql';
import { WithDisposable } from '@blocksuite/affine/global/lit';
import type { NotificationService } from '@blocksuite/affine/shared/services';
import { scrollbarStyle } from '@blocksuite/affine/shared/styles';
import { unsafeCSSVar, unsafeCSSVarV2 } from '@blocksuite/affine/shared/theme';
import { ShadowlessElement } from '@blocksuite/affine/std';
@@ -134,9 +133,6 @@ export class AISessionHistory extends WithDisposable(ShadowlessElement) {
@property({ attribute: false })
accessor onDocClick!: (docId: string, sessionId: string) => void;
@property({ attribute: false })
accessor notification: NotificationService | null | undefined;
@state()
private accessor sessions: BlockSuitePresets.AIRecentSession[] = [];

View File

@@ -18,7 +18,7 @@ export class AIHistoryClear extends WithDisposable(ShadowlessElement) {
accessor session!: CopilotChatHistoryFragment | null | undefined;
@property({ attribute: false })
accessor notification: NotificationService | null | undefined;
accessor notificationService!: NotificationService;
@property({ attribute: false })
accessor doc!: Store;
@@ -52,15 +52,13 @@ export class AIHistoryClear extends WithDisposable(ShadowlessElement) {
}
const sessionId = this.session.sessionId;
try {
const confirm = this.notification
? await this.notification.confirm({
title: 'Clear History',
message:
'Are you sure you want to clear all history? This action will permanently delete all content, including all chat logs and data, and cannot be undone.',
confirmText: 'Confirm',
cancelText: 'Cancel',
})
: true;
const confirm = await this.notificationService.confirm({
title: 'Clear History',
message:
'Are you sure you want to clear all history? This action will permanently delete all content, including all chat logs and data, and cannot be undone.',
confirmText: 'Confirm',
cancelText: 'Cancel',
});
if (confirm) {
const actionIds = this.chatContextValue.messages
@@ -71,11 +69,11 @@ export class AIHistoryClear extends WithDisposable(ShadowlessElement) {
this.doc.id,
[...(sessionId ? [sessionId] : []), ...(actionIds || [])]
);
this.notification?.toast('History cleared');
this.notificationService.toast('History cleared');
this.onHistoryCleared?.();
}
} catch {
this.notification?.toast('Failed to clear history');
this.notificationService.toast('Failed to clear history');
}
};

View File

@@ -1,17 +1,15 @@
import type { FeatureFlagService } from '@affine/core/modules/feature-flag';
import { WithDisposable } from '@blocksuite/affine/global/lit';
import type { EditorHost } from '@blocksuite/affine/std';
import type { ColorScheme } from '@blocksuite/affine/model';
import { ShadowlessElement } from '@blocksuite/affine/std';
import type { ExtensionType } from '@blocksuite/affine/store';
import type { Signal } from '@preact/signals-core';
import { html } from 'lit';
import { property } from 'lit/decorators.js';
import { createTextRenderer } from '../../components/text-renderer';
export class ChatContentRichText extends WithDisposable(ShadowlessElement) {
@property({ attribute: false })
accessor host: EditorHost | null | undefined;
@property({ attribute: false })
accessor text!: string;
@@ -24,12 +22,16 @@ export class ChatContentRichText extends WithDisposable(ShadowlessElement) {
@property({ attribute: false })
accessor affineFeatureFlagService!: FeatureFlagService;
@property({ attribute: false })
accessor theme!: Signal<ColorScheme>;
protected override render() {
const { text, host } = this;
return html`${createTextRenderer(host, {
const { text } = this;
return html`${createTextRenderer({
customHeading: true,
extensions: this.extensions,
affineFeatureFlagService: this.affineFeatureFlagService,
theme: this.theme,
})(text, this.state)}`;
}
}

View File

@@ -1,14 +1,13 @@
import type { FeatureFlagService } from '@affine/core/modules/feature-flag';
import { WithDisposable } from '@blocksuite/affine/global/lit';
import { ImageProxyService } from '@blocksuite/affine/shared/adapters';
import type { EditorHost } from '@blocksuite/affine/std';
import { ShadowlessElement } from '@blocksuite/affine/std';
import type { ColorScheme } from '@blocksuite/affine/model';
import { type EditorHost, ShadowlessElement } from '@blocksuite/affine/std';
import type { ExtensionType } from '@blocksuite/affine/store';
import type { NotificationService } from '@blocksuite/affine-shared/services';
import type { Signal } from '@preact/signals-core';
import { css, html, nothing } from 'lit';
import { property } from 'lit/decorators.js';
import { BlockDiffProvider } from '../../services/block-diff';
import type { AffineAIPanelState } from '../../widgets/ai-panel/type';
import type { StreamObject } from '../ai-chat-messages';
@@ -42,12 +41,16 @@ export class ChatContentStreamObjects extends WithDisposable(
@property({ attribute: false })
accessor affineFeatureFlagService!: FeatureFlagService;
@property({ attribute: false })
accessor theme!: Signal<ColorScheme>;
@property({ attribute: false })
accessor notificationService!: NotificationService;
private renderToolCall(streamObject: StreamObject) {
if (streamObject.type !== 'tool-call') {
return nothing;
}
const imageProxyService = this.host?.store.get(ImageProxyService);
const blockDiffService = this.host?.view.std.getOptional(BlockDiffProvider);
switch (streamObject.toolName) {
case 'web_crawl_exa':
@@ -55,7 +58,6 @@ export class ChatContentStreamObjects extends WithDisposable(
<web-crawl-tool
.data=${streamObject}
.width=${this.width}
.imageProxyService=${imageProxyService}
></web-crawl-tool>
`;
case 'web_search_exa':
@@ -63,7 +65,6 @@ export class ChatContentStreamObjects extends WithDisposable(
<web-search-tool
.data=${streamObject}
.width=${this.width}
.imageProxyService=${imageProxyService}
></web-search-tool>
`;
case 'doc_compose':
@@ -72,7 +73,8 @@ export class ChatContentStreamObjects extends WithDisposable(
.std=${this.host?.std}
.data=${streamObject}
.width=${this.width}
.imageProxyService=${imageProxyService}
.theme=${this.theme}
.notificationService=${this.notificationService}
></doc-compose-tool>
`;
case 'code_artifact':
@@ -81,7 +83,6 @@ export class ChatContentStreamObjects extends WithDisposable(
.std=${this.host?.std}
.data=${streamObject}
.width=${this.width}
.imageProxyService=${imageProxyService}
></code-artifact-tool>
`;
case 'doc_edit':
@@ -89,7 +90,7 @@ export class ChatContentStreamObjects extends WithDisposable(
<doc-edit-tool
.data=${streamObject}
.doc=${this.host?.store}
.blockDiffService=${blockDiffService}
.notificationService=${this.notificationService}
></doc-edit-tool>
`;
default: {
@@ -105,8 +106,6 @@ export class ChatContentStreamObjects extends WithDisposable(
if (streamObject.type !== 'tool-result') {
return nothing;
}
const imageProxyService = this.host?.store.get(ImageProxyService);
const blockDiffService = this.host?.view.std.getOptional(BlockDiffProvider);
switch (streamObject.toolName) {
case 'web_crawl_exa':
@@ -114,7 +113,6 @@ export class ChatContentStreamObjects extends WithDisposable(
<web-crawl-tool
.data=${streamObject}
.width=${this.width}
.imageProxyService=${imageProxyService}
></web-crawl-tool>
`;
case 'web_search_exa':
@@ -122,7 +120,6 @@ export class ChatContentStreamObjects extends WithDisposable(
<web-search-tool
.data=${streamObject}
.width=${this.width}
.imageProxyService=${imageProxyService}
></web-search-tool>
`;
case 'doc_compose':
@@ -131,7 +128,8 @@ export class ChatContentStreamObjects extends WithDisposable(
.std=${this.host?.std}
.data=${streamObject}
.width=${this.width}
.imageProxyService=${imageProxyService}
.theme=${this.theme}
.notificationService=${this.notificationService}
></doc-compose-tool>
`;
case 'code_artifact':
@@ -140,7 +138,6 @@ export class ChatContentStreamObjects extends WithDisposable(
.std=${this.host?.std}
.data=${streamObject}
.width=${this.width}
.imageProxyService=${imageProxyService}
></code-artifact-tool>
`;
case 'doc_edit':
@@ -148,8 +145,8 @@ export class ChatContentStreamObjects extends WithDisposable(
<doc-edit-tool
.data=${streamObject}
.host=${this.host}
.blockDiffService=${blockDiffService}
.renderRichText=${this.renderRichText.bind(this)}
.notificationService=${this.notificationService}
></doc-edit-tool>
`;
default: {
@@ -158,7 +155,6 @@ export class ChatContentStreamObjects extends WithDisposable(
<tool-result-card
.name=${name}
.width=${this.width}
.imageProxyService=${imageProxyService}
></tool-result-card>
`;
}
@@ -167,11 +163,11 @@ export class ChatContentStreamObjects extends WithDisposable(
private renderRichText(text: string) {
return html`<chat-content-rich-text
.host=${this.host}
.text=${text}
.state=${this.state}
.extensions=${this.extensions}
.affineFeatureFlagService=${this.affineFeatureFlagService}
.theme=${this.theme}
></chat-content-rich-text>`;
}

View File

@@ -62,7 +62,7 @@ export class AIScrollableTextRenderer extends WithDisposable(
}
override render() {
const { host, answer, state, textRendererOptions } = this;
const { answer, state, textRendererOptions } = this;
return html` <style>
.ai-scrollable-text-renderer {
@@ -71,7 +71,6 @@ export class AIScrollableTextRenderer extends WithDisposable(
</style>
<div class="ai-scrollable-text-renderer" @wheel=${this._onWheel}>
<text-renderer
.host=${host}
.answer=${answer}
.state=${state}
.options=${textRendererOptions}
@@ -83,7 +82,7 @@ export class AIScrollableTextRenderer extends WithDisposable(
accessor answer!: string;
@property({ attribute: false })
accessor host: EditorHost | null | undefined;
accessor host!: EditorHost;
@property({ attribute: false })
accessor state: AffineAIPanelState | undefined;

View File

@@ -1,7 +1,6 @@
import { CodeBlockHighlighter } from '@blocksuite/affine/blocks/code';
import { toast } from '@blocksuite/affine/components/toast';
import { SignalWatcher, WithDisposable } from '@blocksuite/affine/global/lit';
import type { ImageProxyService } from '@blocksuite/affine/shared/adapters';
import { unsafeCSSVar, unsafeCSSVarV2 } from '@blocksuite/affine/shared/theme';
import { type BlockStdScope, ShadowlessElement } from '@blocksuite/affine/std';
import { CopyIcon, PageIcon, ToolIcon } from '@blocksuite/icons/lit';
@@ -296,9 +295,6 @@ export class CodeArtifactTool extends WithDisposable(ShadowlessElement) {
@property({ attribute: false })
accessor width: Signal<number | undefined> | undefined;
@property({ attribute: false })
accessor imageProxyService: ImageProxyService | null | undefined;
@property({ attribute: false })
accessor std: BlockStdScope | undefined;

View File

@@ -5,14 +5,11 @@ import { LoadingIcon } from '@blocksuite/affine/components/icons';
import { toast } from '@blocksuite/affine/components/toast';
import { WithDisposable } from '@blocksuite/affine/global/lit';
import { RefNodeSlotsProvider } from '@blocksuite/affine/inlines/reference';
import type { ImageProxyService } from '@blocksuite/affine/shared/adapters';
import {
NotificationProvider,
ThemeProvider,
} from '@blocksuite/affine/shared/services';
import type { ColorScheme } from '@blocksuite/affine/model';
import { unsafeCSSVarV2 } from '@blocksuite/affine/shared/theme';
import { type BlockStdScope, ShadowlessElement } from '@blocksuite/affine/std';
import { MarkdownTransformer } from '@blocksuite/affine/widgets/linked-doc';
import type { NotificationService } from '@blocksuite/affine-shared/services';
import { CopyIcon, PageIcon, ToolIcon } from '@blocksuite/icons/lit';
import { type Signal } from '@preact/signals-core';
import { css, html, nothing, type PropertyValues } from 'lit';
@@ -110,10 +107,13 @@ export class DocComposeTool extends WithDisposable(ShadowlessElement) {
accessor width: Signal<number | undefined> | undefined;
@property({ attribute: false })
accessor imageProxyService: ImageProxyService | null | undefined;
accessor std: BlockStdScope | undefined;
@property({ attribute: false })
accessor std: BlockStdScope | undefined;
accessor notificationService!: NotificationService;
@property({ attribute: false })
accessor theme!: Signal<ColorScheme>;
override updated(changedProperties: PropertyValues) {
super.updated(changedProperties);
@@ -147,7 +147,6 @@ export class DocComposeTool extends WithDisposable(ShadowlessElement) {
return;
}
const workspace = std.store.workspace;
const notificationService = std.get(NotificationProvider);
const refNodeSlots = std.getOptional(RefNodeSlotsProvider);
const docId = await MarkdownTransformer.importMarkdownToDoc({
collection: workspace,
@@ -157,7 +156,7 @@ export class DocComposeTool extends WithDisposable(ShadowlessElement) {
extensions: getStoreManager().config.init().value.get('store'),
});
if (docId) {
const open = await notificationService.confirm({
const open = await this.notificationService.confirm({
title: 'Open the doc you just created',
message: 'Doc saved successfully! Would you like to open it now?',
cancelText: 'Cancel',
@@ -200,8 +199,6 @@ export class DocComposeTool extends WithDisposable(ShadowlessElement) {
${successResult
? html`<text-renderer
.answer=${successResult.markdown}
.host=${std.host}
.schema=${std.store.schema}
.options=${{
customHeading: true,
extensions: getCustomPageEditorBlockSpecs(),
@@ -237,10 +234,8 @@ export class DocComposeTool extends WithDisposable(ShadowlessElement) {
></tool-call-failed>`;
}
const theme = this.std.get(ThemeProvider).theme;
const { LinkedDocEmptyBanner } = getEmbedLinkedDocIcons(
theme,
this.theme.value,
'page',
'horizontal'
);

View File

@@ -1,7 +1,7 @@
import { WithDisposable } from '@blocksuite/affine/global/lit';
import { NotificationProvider } from '@blocksuite/affine/shared/services';
import { unsafeCSSVar, unsafeCSSVarV2 } from '@blocksuite/affine/shared/theme';
import { type EditorHost, ShadowlessElement } from '@blocksuite/affine/std';
import type { NotificationService } from '@blocksuite/affine-shared/services';
import {
CloseIcon,
CopyIcon,
@@ -14,7 +14,7 @@ import {
import { css, html, nothing } from 'lit';
import { property, state } from 'lit/decorators.js';
import type { BlockDiffService } from '../../services/block-diff';
import { BlockDiffProvider } from '../../services/block-diff';
import { diffMarkdown } from '../../utils/apply-model/markdown-diff';
import { copyText } from '../../utils/editor-actions';
import type { ToolError } from './type';
@@ -190,14 +190,18 @@ export class DocEditTool extends WithDisposable(ShadowlessElement) {
accessor data!: DocEditToolCall | DocEditToolResult;
@property({ attribute: false })
accessor blockDiffService: BlockDiffService | undefined;
accessor renderRichText!: (text: string) => string;
@property({ attribute: false })
accessor renderRichText!: (text: string) => string;
accessor notificationService!: NotificationService;
@state()
accessor isCollapsed = false;
get blockDiffService() {
return this.host?.std.getOptional(BlockDiffProvider);
}
private async _handleApply(markdown: string) {
if (!this.host) {
return;
@@ -229,14 +233,9 @@ export class DocEditTool extends WithDisposable(ShadowlessElement) {
if (!this.host) {
return;
}
const success = await copyText(
this.host,
removeMarkdownComments(changedMarkdown)
);
const success = await copyText(removeMarkdownComments(changedMarkdown));
if (success) {
const notificationService =
this.host?.std.getOptional(NotificationProvider);
notificationService?.notify({
this.notificationService.notify({
title: 'Copied to clipboard',
accent: 'success',
onClose: function (): void {},

View File

@@ -1,7 +1,7 @@
import { SignalWatcher, WithDisposable } from '@blocksuite/affine/global/lit';
import { type ImageProxyService } from '@blocksuite/affine/shared/adapters';
import { unsafeCSSVarV2 } from '@blocksuite/affine/shared/theme';
import { ShadowlessElement } from '@blocksuite/affine/std';
import { DEFAULT_IMAGE_PROXY_ENDPOINT } from '@blocksuite/affine-shared/consts';
import { ToggleDownIcon, ToolIcon } from '@blocksuite/icons/lit';
import { type Signal } from '@preact/signals-core';
import { css, html, nothing, type TemplateResult } from 'lit';
@@ -205,12 +205,11 @@ export class ToolResultCard extends SignalWatcher(
@property({ attribute: false })
accessor width: Signal<number | undefined> | undefined;
@property({ attribute: false })
accessor imageProxyService: ImageProxyService | null | undefined;
@state()
private accessor isCollapsed = true;
private readonly imageProxyURL = DEFAULT_IMAGE_PROXY_ENDPOINT;
protected override render() {
return html`
<div class="ai-tool-result-wrapper">
@@ -272,15 +271,20 @@ export class ToolResultCard extends SignalWatcher(
`;
}
buildUrl(imageUrl: string) {
if (imageUrl.startsWith(this.imageProxyURL)) {
return imageUrl;
}
return `${this.imageProxyURL}?url=${encodeURIComponent(imageUrl)}`;
}
private renderIcon(icon: string | TemplateResult<1> | undefined) {
if (!icon) {
return nothing;
}
if (typeof icon === 'string') {
if (this.imageProxyService) {
return html`<img src=${this.imageProxyService.buildUrl(icon)} />`;
}
return html`<img src=${icon} />`;
return html`<img src=${this.buildUrl(icon)} />`;
}
return html`${icon}`;
}

View File

@@ -1,5 +1,4 @@
import { WithDisposable } from '@blocksuite/affine/global/lit';
import type { ImageProxyService } from '@blocksuite/affine/shared/adapters';
import { ShadowlessElement } from '@blocksuite/affine/std';
import { WebIcon } from '@blocksuite/icons/lit';
import type { Signal } from '@preact/signals-core';
@@ -40,9 +39,6 @@ export class WebCrawlTool extends WithDisposable(ShadowlessElement) {
@property({ attribute: false })
accessor width: Signal<number | undefined> | undefined;
@property({ attribute: false })
accessor imageProxyService: ImageProxyService | null | undefined;
renderToolCall() {
return html`
<tool-call-card
@@ -73,7 +69,6 @@ export class WebCrawlTool extends WithDisposable(ShadowlessElement) {
},
]}
.width=${this.width}
.imageProxyService=${this.imageProxyService}
></tool-result-card>
`;
}

View File

@@ -1,5 +1,4 @@
import { WithDisposable } from '@blocksuite/affine/global/lit';
import type { ImageProxyService } from '@blocksuite/affine/shared/adapters';
import { ShadowlessElement } from '@blocksuite/affine/std';
import { WebIcon } from '@blocksuite/icons/lit';
import type { Signal } from '@preact/signals-core';
@@ -40,9 +39,6 @@ export class WebSearchTool extends WithDisposable(ShadowlessElement) {
@property({ attribute: false })
accessor width: Signal<number | undefined> | undefined;
@property({ attribute: false })
accessor imageProxyService: ImageProxyService | null | undefined;
renderToolCall() {
return html`
<tool-call-card
@@ -75,7 +71,6 @@ export class WebSearchTool extends WithDisposable(ShadowlessElement) {
.footerIcons=${footerIcons}
.results=${results}
.width=${this.width}
.imageProxyService=${this.imageProxyService}
></tool-result-card>
`;
}

View File

@@ -1,11 +1,11 @@
import type { CopilotChatHistoryFragment } from '@affine/graphql';
import type { ImageSelection } from '@blocksuite/affine/shared/selection';
import { NotificationProvider } from '@blocksuite/affine/shared/services';
import type {
BlockSelection,
EditorHost,
TextSelection,
} from '@blocksuite/affine/std';
import type { NotificationService } from '@blocksuite/affine-shared/services';
import { css, html, LitElement, nothing } from 'lit';
import { property } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
@@ -96,6 +96,9 @@ export class ChatActionList extends LitElement {
@property({ attribute: 'data-testid', reflect: true })
accessor testId = 'chat-action-list';
@property({ attribute: false })
accessor notificationService!: NotificationService;
override render() {
const { actions } = this;
if (!actions.length) {
@@ -148,7 +151,7 @@ export class ChatActionList extends LitElement {
messageId
);
if (success) {
this.host.std.getOptional(NotificationProvider)?.notify({
this.notificationService.notify({
title: action.toast,
accent: 'success',
onClose: function (): void {},

View File

@@ -2,7 +2,6 @@ import type { CopilotChatHistoryFragment } from '@affine/graphql';
import { Tooltip } from '@blocksuite/affine/components/toolbar';
import { WithDisposable } from '@blocksuite/affine/global/lit';
import { noop } from '@blocksuite/affine/global/utils';
import { NotificationProvider } from '@blocksuite/affine/shared/services';
import { unsafeCSSVarV2 } from '@blocksuite/affine/shared/theme';
import { createButtonPopper } from '@blocksuite/affine/shared/utils';
import type {
@@ -10,6 +9,7 @@ import type {
EditorHost,
TextSelection,
} from '@blocksuite/affine/std';
import type { NotificationService } from '@blocksuite/affine-shared/services';
import { CopyIcon, MoreHorizontalIcon, ResetIcon } from '@blocksuite/icons/lit';
import { css, html, LitElement, nothing, type PropertyValues } from 'lit';
import { property, query, state } from 'lit/decorators.js';
@@ -131,14 +131,15 @@ export class ChatCopyMore extends WithDisposable(LitElement) {
@property({ attribute: 'data-testid', reflect: true })
accessor testId = 'chat-actions';
@property({ attribute: false })
accessor notificationService!: NotificationService;
private _toggle() {
this._morePopper?.toggle();
}
private readonly _notifySuccess = (title: string) => {
const notificationService =
this.host?.std.getOptional(NotificationProvider);
notificationService?.notify({
this.notificationService.notify({
title: title,
accent: 'success',
onClose: function (): void {},
@@ -165,7 +166,7 @@ export class ChatCopyMore extends WithDisposable(LitElement) {
override render() {
const { host, content, isLast, messageId, actions } = this;
const showMoreIcon = !isLast && host && actions.length > 0;
const showMoreIcon = !isLast && actions.length > 0;
return html`<style>
.copy-more {
margin-top: ${this.withMargin ? '8px' : '0px'};
@@ -176,11 +177,11 @@ export class ChatCopyMore extends WithDisposable(LitElement) {
}
</style>
<div class="copy-more">
${content && host
${content
? html`<div
class="button copy"
@click=${async () => {
const success = await copyText(host, content);
const success = await copyText(content);
if (success) {
this._notifySuccess('Copied to clipboard');
}
@@ -201,7 +202,7 @@ export class ChatCopyMore extends WithDisposable(LitElement) {
<affine-tooltip .autoShift=${true}>Retry</affine-tooltip>
</div>`
: nothing}
${showMoreIcon
${showMoreIcon && host
? html`<div
class="button more"
data-testid="action-more-button"

View File

@@ -1,10 +1,11 @@
import type { FeatureFlagService } from '@affine/core/modules/feature-flag';
import type { AppThemeService } from '@affine/core/modules/theme';
import type {
ContextEmbedStatus,
CopilotChatHistoryFragment,
} from '@affine/graphql';
import { SignalWatcher, WithDisposable } from '@blocksuite/affine/global/lit';
import { NotificationProvider } from '@blocksuite/affine/shared/services';
import { type NotificationService } from '@blocksuite/affine/shared/services';
import { unsafeCSSVarV2 } from '@blocksuite/affine/shared/theme';
import type { EditorHost } from '@blocksuite/affine/std';
import { ShadowlessElement } from '@blocksuite/affine/std';
@@ -16,6 +17,7 @@ import { createRef, type Ref, ref } from 'lit/directives/ref.js';
import { throttle } from 'lodash-es';
import type { AppSidebarConfig } from '../../chat-panel/chat-config';
import { HISTORY_IMAGE_ACTIONS } from '../../chat-panel/const';
import { AIProvider } from '../../provider';
import type { DocDisplayConfig, SearchMenuConfig } from '../ai-chat-chips';
import type { ChatContextValue } from '../ai-chat-content';
@@ -29,6 +31,7 @@ import {
type ChatAction,
type ChatMessage,
type HistoryMessage,
isChatMessage,
} from '../ai-chat-messages';
const DEFAULT_CHAT_CONTEXT_VALUE: ChatContextValue = {
@@ -159,6 +162,12 @@ export class PlaygroundChat extends SignalWatcher(
@property({ attribute: false })
accessor affineFeatureFlagService!: FeatureFlagService;
@property({ attribute: false })
accessor affineThemeService!: AppThemeService;
@property({ attribute: false })
accessor notificationService!: NotificationService;
@property({ attribute: false })
accessor addChat!: () => Promise<void>;
@@ -177,6 +186,17 @@ export class PlaygroundChat extends SignalWatcher(
// request counter to track the latest request
private _updateHistoryCounter = 0;
get messages() {
return this.chatContextValue.messages.filter(item => {
return (
isChatMessage(item) ||
item.messages?.length === 3 ||
(HISTORY_IMAGE_ACTIONS.includes(item.action) &&
item.messages?.length === 2)
);
});
}
private readonly _initPanel = async () => {
const userId = (await AIProvider.userInfo)?.id;
if (!userId) return;
@@ -276,7 +296,6 @@ export class PlaygroundChat extends SignalWatcher(
override render() {
const [done, total] = this.embeddingProgress;
const isEmbedding = total > 0 && done < total;
const notification = this.host.std.getOptional(NotificationProvider);
return html`<div class="chat-panel-container">
<div class="chat-panel-title">
@@ -294,7 +313,7 @@ export class PlaygroundChat extends SignalWatcher(
<ai-history-clear
.doc=${this.doc}
.session=${this.session}
.notification=${notification}
.notificationService=${this.notificationService}
.onHistoryCleared=${this._updateHistory}
.chatContextValue=${this.chatContextValue}
></ai-history-clear>
@@ -312,8 +331,11 @@ export class PlaygroundChat extends SignalWatcher(
.updateContext=${this.updateContext}
.extensions=${this.extensions}
.affineFeatureFlagService=${this.affineFeatureFlagService}
.affineThemeService=${this.affineThemeService}
.notificationService=${this.notificationService}
.networkSearchConfig=${this.networkSearchConfig}
.reasoningConfig=${this.reasoningConfig}
.messages=${this.messages}
></ai-chat-messages>
<ai-chat-composer
.host=${this.host}

View File

@@ -1,9 +1,11 @@
import type { FeatureFlagService } from '@affine/core/modules/feature-flag';
import type { AppThemeService } from '@affine/core/modules/theme';
import type { CopilotChatHistoryFragment } from '@affine/graphql';
import { SignalWatcher, WithDisposable } from '@blocksuite/affine/global/lit';
import type { EditorHost } from '@blocksuite/affine/std';
import { ShadowlessElement } from '@blocksuite/affine/std';
import type { ExtensionType, Store } from '@blocksuite/affine/store';
import type { NotificationService } from '@blocksuite/affine-shared/services';
import { css, html } from 'lit';
import { property, state } from 'lit/decorators.js';
import { repeat } from 'lit/directives/repeat.js';
@@ -83,6 +85,12 @@ export class PlaygroundContent extends SignalWatcher(
@property({ attribute: false })
accessor affineFeatureFlagService!: FeatureFlagService;
@property({ attribute: false })
accessor affineThemeService!: AppThemeService;
@property({ attribute: false })
accessor notificationService!: NotificationService;
@state()
accessor sessions: CopilotChatHistoryFragment[] = [];
@@ -336,6 +344,8 @@ export class PlaygroundContent extends SignalWatcher(
.docDisplayConfig=${this.docDisplayConfig}
.extensions=${this.extensions}
.affineFeatureFlagService=${this.affineFeatureFlagService}
.affineThemeService=${this.affineThemeService}
.notificationService=${this.notificationService}
.addChat=${this.addChat}
></playground-chat>
</div>

View File

@@ -1,17 +1,15 @@
import { createReactComponentFromLit } from '@affine/component';
import { getStoreManager } from '@affine/core/blocksuite/manager/store';
import { getViewManager } from '@affine/core/blocksuite/manager/view';
import type { FeatureFlagService } from '@affine/core/modules/feature-flag';
import { PeekViewProvider } from '@blocksuite/affine/components/peek';
import { Container, type ServiceProvider } from '@blocksuite/affine/global/di';
import { SignalWatcher, WithDisposable } from '@blocksuite/affine/global/lit';
import { RefNodeSlotsProvider } from '@blocksuite/affine/inlines/reference';
import type { ColorScheme } from '@blocksuite/affine/model';
import {
codeBlockWrapMiddleware,
defaultImageProxyMiddleware,
ImageProxyService,
} from '@blocksuite/affine/shared/adapters';
import { ThemeProvider } from '@blocksuite/affine/shared/services';
import { unsafeCSSVarV2 } from '@blocksuite/affine/shared/theme';
import {
BlockStdScope,
@@ -22,10 +20,10 @@ import {
import type {
ExtensionType,
Query,
Schema,
Store,
TransformerMiddleware,
} from '@blocksuite/affine/store';
import type { Signal } from '@preact/signals-core';
import {
darkCssVariablesV2,
lightCssVariablesV2,
@@ -103,6 +101,7 @@ export type TextRendererOptions = {
additionalMiddlewares?: TransformerMiddleware[];
testId?: string;
affineFeatureFlagService?: FeatureFlagService;
theme?: Signal<ColorScheme>;
};
// todo: refactor it for more general purpose usage instead of AI only?
@@ -221,6 +220,8 @@ export class TextRenderer extends SignalWatcher(
private _doc: Store | null = null;
private _host: EditorHost | null = null;
private readonly _query: Query = {
mode: 'strict',
match: [
@@ -243,7 +244,7 @@ export class TextRenderer extends SignalWatcher(
private _timer?: ReturnType<typeof setInterval> | null = null;
private readonly _subscribeDocLinkClicked = () => {
const refNodeSlots = this.host?.std.getOptional(RefNodeSlotsProvider);
const refNodeSlots = this._host?.std.getOptional(RefNodeSlotsProvider);
if (!refNodeSlots) return;
this.disposables.add(
refNodeSlots.docLinkClicked
@@ -254,7 +255,7 @@ export class TextRenderer extends SignalWatcher(
)
.subscribe(options => {
// Open the doc in center peek
this.host?.std
this._host?.std
.getOptional(PeekViewProvider)
?.peek({
docId: options.pageId,
@@ -268,40 +269,27 @@ export class TextRenderer extends SignalWatcher(
if (this._answers.length > 0) {
const latestAnswer = this._answers.pop();
this._answers = [];
const schema = this.schema ?? this.host?.std.store.schema;
let provider: ServiceProvider;
if (this.host) {
provider = this.host.std.store.provider;
} else {
const container = new Container();
getStoreManager()
.config.init()
.value.get('store')
.forEach(ext => {
ext.setup(container);
});
provider = container.provider();
}
if (latestAnswer && schema) {
if (latestAnswer) {
const middlewares = [
defaultImageProxyMiddleware,
codeBlockWrapMiddleware(true),
...(this.options.additionalMiddlewares ?? []),
];
const affineFeatureFlagService = this.options.affineFeatureFlagService;
markDownToDoc(
provider,
schema,
latestAnswer,
middlewares,
affineFeatureFlagService
this.options.affineFeatureFlagService
)
.then(doc => {
this.disposeDoc();
this._doc = doc.doc.getStore({
query: this._query,
});
this._host = new BlockStdScope({
store: this._doc,
extensions:
this.options.extensions ?? getCustomPageEditorBlockSpecs(),
}).render();
this.disposables.add(() => {
doc.doc.removeStore({ query: this._query });
});
@@ -309,14 +297,10 @@ export class TextRenderer extends SignalWatcher(
this.requestUpdate();
if (this.state !== 'generating') {
this._doc.load();
// LinkPreviewService & ImageProxyService config should read from host settings
const imageProxyService =
this.host?.std.store.get(ImageProxyService);
if (imageProxyService) {
this._doc
?.get(ImageProxyService)
.setImageProxyURL(imageProxyService.imageProxyURL);
}
const imageProxyService = this._host.std.get(ImageProxyService);
imageProxyService.setImageProxyURL(
imageProxyService.imageProxyURL
);
this._clearTimer();
}
})
@@ -341,7 +325,6 @@ export class TextRenderer extends SignalWatcher(
private disposeDoc() {
this._doc?.dispose();
this._doc?.workspace.dispose();
}
override disconnectedCallback() {
@@ -355,22 +338,22 @@ export class TextRenderer extends SignalWatcher(
return nothing;
}
const { customHeading, testId } = this.options;
const { customHeading, testId = 'ai-text-renderer' } = this.options;
const classes = classMap({
'text-renderer-container': true,
'custom-heading': !!customHeading,
});
const theme = this.host?.std.get(ThemeProvider).app$.value;
const theme = this.options.theme?.value;
return html`
<div class=${classes} data-testid=${testId} data-app-theme=${theme}>
<div
class=${classes}
data-testid=${testId}
data-app-theme=${theme ?? 'light'}
>
${keyed(
this._doc,
html`<div class="ai-answer-text-editor affine-page-viewport">
${new BlockStdScope({
store: this._doc,
extensions:
this.options.extensions ?? getCustomPageEditorBlockSpecs(),
}).render()}
${this._host}
</div>`
)}
</div>
@@ -416,12 +399,6 @@ export class TextRenderer extends SignalWatcher(
@property({ attribute: false })
accessor answer!: string;
@property({ attribute: false })
accessor host: EditorHost | null | undefined;
@property({ attribute: false })
accessor schema: Schema | null = null;
@property({ attribute: false })
accessor options!: TextRendererOptions;
@@ -429,14 +406,10 @@ export class TextRenderer extends SignalWatcher(
accessor state: AffineAIPanelState | undefined = undefined;
}
export const createTextRenderer = (
host: EditorHost | null | undefined,
options: TextRendererOptions
) => {
export const createTextRenderer = (options: TextRendererOptions) => {
return (answer: string, state?: AffineAIPanelState) => {
return html`<text-renderer
contenteditable="false"
.host=${host}
.answer=${answer}
.state=${state}
.options=${options}

View File

@@ -468,6 +468,8 @@ export class AIChatBlockPeekView extends LitElement {
return html`<ai-loading></ai-loading>`;
}
const notificationService = this.host.std.get(NotificationProvider);
return html`<div class=${messageClasses}>
<ai-chat-block-message
.host=${host}
@@ -485,6 +487,7 @@ export class AIChatBlockPeekView extends LitElement {
.isLast=${isLastReply}
.messageId=${message.id ?? undefined}
.retry=${() => this.retry()}
.notificationService=${notificationService}
></chat-copy-more>`
: nothing}
${shouldRenderActions
@@ -495,6 +498,7 @@ export class AIChatBlockPeekView extends LitElement {
.content=${markdown}
.messageId=${message.id ?? undefined}
.layoutDirection=${'horizontal'}
.notificationService=${notificationService}
></chat-action-list>`
: nothing}
</div>`;
@@ -569,7 +573,7 @@ export class AIChatBlockPeekView extends LitElement {
} = this;
const { messages: currentChatMessages } = chatContext;
const notification = this.host.std.getOptional(NotificationProvider);
const notificationService = this.host.std.get(NotificationProvider);
return html`<div class="ai-chat-block-peek-view-container">
<div class="history-clear-container">
@@ -578,7 +582,7 @@ export class AIChatBlockPeekView extends LitElement {
.session=${this.forkSession}
.onHistoryCleared=${this._onHistoryCleared}
.chatContextValue=${chatContext}
.notification=${notification}
.notificationService=${notificationService}
></ai-history-clear>
</div>
<div class="ai-chat-messages-container">

View File

@@ -2,6 +2,7 @@ import { toggleGeneralAIOnboarding } from '@affine/core/components/affine/ai-onb
import type { AuthAccountInfo, AuthService } from '@affine/core/modules/cloud';
import type { GlobalDialogService } from '@affine/core/modules/dialogs';
import {
type AddContextFileInput,
ContextCategories,
type ContextWorkspaceEmbeddingStatus,
type getCopilotHistoriesQuery,
@@ -609,10 +610,7 @@ Could you make a new website based on these notes and send back just the html fi
removeContextDoc: async (options: { contextId: string; docId: string }) => {
return client.removeContextDoc(options);
},
addContextFile: async (
file: File,
options: { contextId: string; blobId: string }
) => {
addContextFile: async (file: File, options: AddContextFileInput) => {
return client.addContextFile(file, options);
},
removeContextFile: async (options: {

View File

@@ -1,10 +1,13 @@
import { WorkspaceImpl } from '@affine/core/modules/workspace/impls/workspace';
import { clipboardConfigs } from '@blocksuite/affine/foundation/clipboard';
import { defaultImageProxyMiddleware } from '@blocksuite/affine/shared/adapters';
import { replaceSelectedTextWithBlocksCommand } from '@blocksuite/affine/shared/commands';
import { isInsideEdgelessEditor } from '@blocksuite/affine/shared/utils';
import {
type BlockComponent,
BlockSelection,
BlockStdScope,
Clipboard,
type EditorHost,
SurfaceSelection,
type TextSelection,
@@ -185,27 +188,25 @@ export const replace = async (
};
export const copyTextAnswer = async (panel: AffineAIPanelWidget) => {
const host = panel.host;
if (!panel.answer) {
return false;
}
return copyText(host, panel.answer);
return copyText(panel.answer);
};
export const copyText = async (host: EditorHost, text: string) => {
const previewDoc = await markDownToDoc(
host.std.store.provider,
host.std.store.schema,
text,
[defaultImageProxyMiddleware]
);
export const copyText = async (text: string) => {
const previewDoc = await markDownToDoc(text, [defaultImageProxyMiddleware]);
const models = previewDoc
.getBlocksByFlavour('affine:note')
.map(b => b.model)
.flatMap(model => model.children);
const slice = Slice.fromModels(previewDoc, models);
await host.std.clipboard.copySlice(slice);
const std = new BlockStdScope({
store: previewDoc,
extensions: [...clipboardConfigs],
});
const clipboard = std.provider.get(Clipboard);
await clipboard.copySlice(slice);
previewDoc.dispose();
previewDoc.workspace.dispose();
return true;
};

View File

@@ -1,4 +1,3 @@
import type { ServiceProvider } from '@blocksuite/affine/global/di';
import {
DatabaseBlockModel,
ImageBlockModel,
@@ -19,10 +18,11 @@ import {
isInsideEdgelessEditor,
matchModels,
} from '@blocksuite/affine/shared/utils';
import type { EditorHost } from '@blocksuite/affine/std';
import { BlockStdScope, type EditorHost } from '@blocksuite/affine/std';
import type { BlockModel, Store } from '@blocksuite/affine/store';
import { Slice, toDraftModel } from '@blocksuite/affine/store';
import { getStoreManager } from '../../manager/store';
import type { ChatContextValue } from '../components/ai-chat-content';
import {
getSelectedImagesAsBlobs,
@@ -96,12 +96,13 @@ async function extractPageSelected(
}
}
export async function extractMarkdownFromDoc(
doc: Store,
provider: ServiceProvider
): Promise<string> {
export async function extractMarkdownFromDoc(doc: Store): Promise<string> {
const std = new BlockStdScope({
store: doc,
extensions: getStoreManager().config.init().value.get('store'),
});
const transformer = await getTransformer(doc);
const adapter = new MarkdownAdapter(transformer, provider);
const adapter = new MarkdownAdapter(transformer, std.provider);
const blockModels = getNoteBlockModels(doc);
const textModels = blockModels.filter(
model => !matchModels(model, [ImageBlockModel, DatabaseBlockModel])

View File

@@ -1,4 +1,5 @@
import { WidgetComponent, WidgetViewExtension } from '@blocksuite/affine/std';
import { ThemeProvider } from '@blocksuite/affine-shared/services';
import { unsafeCSSVarV2 } from '@blocksuite/affine-shared/theme';
import { css, html, nothing, type TemplateResult } from 'lit';
import { literal, unsafeStatic } from 'lit/static-html.js';
@@ -98,9 +99,9 @@ export class AffineBlockDiffWidgetForBlock extends WidgetComponent {
: html`<div class="ai-block-diff insert" data-diff-id=${diffId}>
<chat-content-rich-text
.text=${block.content}
.host=${this.host}
.state="finished"
.extensions=${this.userExtensions}
.theme=${this.host.std.get(ThemeProvider).app$}
></chat-content-rich-text>
<ai-block-diff-options
class="diff-options"
@@ -132,9 +133,9 @@ export class AffineBlockDiffWidgetForBlock extends WidgetComponent {
<div class="ai-block-diff update" data-diff-id=${diffId}>
<chat-content-rich-text
.text=${content}
.host=${this.host}
.state="finished"
.extensions=${this.userExtensions}
.theme=${this.host.std.get(ThemeProvider).app$}
></chat-content-rich-text>
<ai-block-diff-options
class="diff-options"

View File

@@ -15,10 +15,7 @@ import {
import { toDocSearchParams } from '@affine/core/modules/navigation/utils';
import { GlobalSessionStateService } from '@affine/core/modules/storage';
import { WorkbenchLink } from '@affine/core/modules/workbench';
import {
getAFFiNEWorkspaceSchema,
WorkspaceService,
} from '@affine/core/modules/workspace';
import { WorkspaceService } from '@affine/core/modules/workspace';
import { useI18n } from '@affine/i18n';
import track from '@affine/track';
import type {
@@ -338,7 +335,6 @@ export const LinkPreview = ({
<LitTextRenderer
className={styles.linkPreviewRenderer}
answer={link.markdownPreview}
schema={getAFFiNEWorkspaceSchema()}
options={textRendererOptions}
/>
)}

View File

@@ -1,6 +1,5 @@
import type { FeatureFlagService } from '@affine/core/modules/feature-flag';
import { WorkspaceImpl } from '@affine/core/modules/workspace/impls/workspace';
import type { ServiceProvider } from '@blocksuite/affine/global/di';
import {
defaultImageProxyMiddleware,
embedSyncedDocMiddleware,
@@ -11,6 +10,7 @@ import {
titleMiddleware,
} from '@blocksuite/affine/shared/adapters';
import {
BlockStdScope,
type EditorHost,
type TextRangePoint,
TextSelection,
@@ -19,7 +19,6 @@ import type {
BlockModel,
BlockSnapshot,
DraftModel,
Schema,
Slice,
SliceSnapshot,
Store,
@@ -27,6 +26,43 @@ import type {
} from '@blocksuite/affine/store';
import { toDraftModel, Transformer } from '@blocksuite/affine/store';
import { Doc as YDoc } from 'yjs';
import { getStoreManager } from '../manager/store';
interface MarkdownWorkspace {
collection: WorkspaceImpl;
std: BlockStdScope;
}
let markdownWorkspace: MarkdownWorkspace | null = null;
const getMarkdownWorkspace = (
featureFlagService?: FeatureFlagService
): MarkdownWorkspace => {
if (markdownWorkspace) {
return markdownWorkspace;
}
const collection = new WorkspaceImpl({
rootDoc: new YDoc({ guid: 'markdownToDoc' }),
featureFlagService: featureFlagService,
});
collection.meta.initialize();
const mockDoc = collection.createDoc('mock-id');
const std = new BlockStdScope({
store: mockDoc.getStore(),
extensions: getStoreManager().config.init().value.get('store'),
});
markdownWorkspace = {
collection,
std,
};
return markdownWorkspace;
};
const updateSnapshotText = (
point: TextRangePoint,
snapshot: BlockSnapshot,
@@ -184,20 +220,14 @@ export async function replaceFromMarkdown(
}
export async function markDownToDoc(
provider: ServiceProvider,
schema: Schema,
answer: string,
middlewares?: TransformerMiddleware[],
affineFeatureFlagService?: FeatureFlagService
) {
// Should not create a new doc in the original collection
const collection = new WorkspaceImpl({
rootDoc: new YDoc({ guid: 'markdownToDoc' }),
featureFlagService: affineFeatureFlagService,
});
collection.meta.initialize();
const { collection, std } = getMarkdownWorkspace(affineFeatureFlagService);
const transformer = new Transformer({
schema,
schema: std.store.schema,
blobCRUD: collection.blobSync,
docCRUD: {
create: (id: string) => collection.createDoc(id).getStore({ id }),
@@ -206,7 +236,7 @@ export async function markDownToDoc(
},
middlewares,
});
const mdAdapter = new MarkdownAdapter(transformer, provider);
const mdAdapter = new MarkdownAdapter(transformer, std.store.provider);
const doc = await mdAdapter.toDoc({
file: answer,
assets: transformer.assetsManager,

View File

@@ -50,10 +50,7 @@ function getPreviewFromSelections(
} else if (selection instanceof ImageSelection) {
// Return <"Image"> for ImageSelection
previews.push('<Image>');
} else if (
selection instanceof SurfaceSelection &&
gfx.surface?.id === selection.blockId
) {
} else if (selection instanceof SurfaceSelection) {
selection.elements.forEach(elementId => {
const model = gfx.getElementById(elementId);
if (model instanceof GfxPrimitiveElementModel) {

View File

@@ -1,4 +1,5 @@
import {
type ConfirmModalProps,
Input,
type Notification,
notify,
@@ -7,127 +8,156 @@ import {
toReactNode,
type useConfirmModal,
} from '@affine/component';
import { NotificationExtension } from '@blocksuite/affine/shared/services';
import {
NotificationExtension,
type NotificationService,
} from '@blocksuite/affine/shared/services';
export class NotificationServiceImpl implements NotificationService {
constructor(
private readonly closeConfirmModal: () => void,
private readonly openConfirmModal: (props: ConfirmModalProps) => void
) {}
confirm = async ({
title,
message,
confirmText,
cancelText,
abort,
}: Parameters<NotificationService['confirm']>[0]) => {
return new Promise<boolean>(resolve => {
this.openConfirmModal({
title: toReactNode(title),
description: toReactNode(message),
confirmText,
confirmButtonOptions: {
variant: 'primary',
},
cancelText,
onConfirm: () => {
resolve(true);
},
onCancel: () => {
resolve(false);
},
});
abort?.addEventListener('abort', () => {
resolve(false);
this.closeConfirmModal();
});
});
};
prompt = async ({
title,
message,
confirmText,
placeholder,
cancelText,
autofill,
abort,
}: Parameters<NotificationService['prompt']>[0]) => {
return new Promise<string | null>(resolve => {
let value = autofill || '';
const description = (
<div>
<span style={{ marginBottom: 12 }}>{toReactNode(message)}</span>
<Input
autoSelect={true}
placeholder={placeholder}
defaultValue={value}
onChange={e => (value = e)}
/>
</div>
);
this.openConfirmModal({
title: toReactNode(title),
description: description,
confirmText: confirmText ?? 'Confirm',
confirmButtonOptions: {
variant: 'primary',
},
cancelText: cancelText ?? 'Cancel',
onConfirm: () => {
resolve(value);
},
onCancel: () => {
resolve(null);
},
autoFocusConfirm: false,
});
abort?.addEventListener('abort', () => {
resolve(null);
this.closeConfirmModal();
});
});
};
toast = (message: string, options: ToastOptions) => {
return toast(message, options);
};
notify = (notification: Parameters<NotificationService['notify']>[0]) => {
const accentToNotify = {
error: notify.error,
success: notify.success,
warning: notify.warning,
info: notify,
};
const fn = accentToNotify[notification.accent || 'info'];
if (!fn) {
throw new Error('Invalid notification accent');
}
const toAffineNotificationActions = (
actions: (typeof notification)['actions']
): Notification['actions'] => {
if (!actions) return undefined;
return actions.map(({ label, onClick, key }) => {
return {
key,
label: toReactNode(label),
onClick,
};
});
};
const toastId = fn(
{
title: toReactNode(notification.title),
message: toReactNode(notification.message),
actions: toAffineNotificationActions(notification.actions),
onDismiss: notification.onClose,
},
{
duration: notification.duration || 0,
onDismiss: notification.onClose,
onAutoClose: notification.onClose,
}
);
notification.abort?.addEventListener('abort', () => {
notify.dismiss(toastId);
});
};
notifyWithUndoAction = (
options: Parameters<NotificationService['notifyWithUndoAction']>[0]
) => {
this.notify(options);
};
}
export function patchNotificationService({
closeConfirmModal,
openConfirmModal,
}: ReturnType<typeof useConfirmModal>) {
return NotificationExtension({
confirm: async ({ title, message, confirmText, cancelText, abort }) => {
return new Promise<boolean>(resolve => {
openConfirmModal({
title: toReactNode(title),
description: toReactNode(message),
confirmText,
confirmButtonOptions: {
variant: 'primary',
},
cancelText,
onConfirm: () => {
resolve(true);
},
onCancel: () => {
resolve(false);
},
});
abort?.addEventListener('abort', () => {
resolve(false);
closeConfirmModal();
});
});
},
prompt: async ({
title,
message,
confirmText,
placeholder,
cancelText,
autofill,
abort,
}) => {
return new Promise<string | null>(resolve => {
let value = autofill || '';
const description = (
<div>
<span style={{ marginBottom: 12 }}>{toReactNode(message)}</span>
<Input
autoSelect={true}
placeholder={placeholder}
defaultValue={value}
onChange={e => (value = e)}
/>
</div>
);
openConfirmModal({
title: toReactNode(title),
description: description,
confirmText: confirmText ?? 'Confirm',
confirmButtonOptions: {
variant: 'primary',
},
cancelText: cancelText ?? 'Cancel',
onConfirm: () => {
resolve(value);
},
onCancel: () => {
resolve(null);
},
autoFocusConfirm: false,
});
abort?.addEventListener('abort', () => {
resolve(null);
closeConfirmModal();
});
});
},
toast: (message: string, options: ToastOptions) => {
return toast(message, options);
},
notify: notification => {
const accentToNotify = {
error: notify.error,
success: notify.success,
warning: notify.warning,
info: notify,
};
const fn = accentToNotify[notification.accent || 'info'];
if (!fn) {
throw new Error('Invalid notification accent');
}
const toAffineNotificationActions = (
actions: (typeof notification)['actions']
): Notification['actions'] => {
if (!actions) return undefined;
return actions.map(({ label, onClick, key }) => {
return {
key,
label: toReactNode(label),
onClick,
};
});
};
const toastId = fn(
{
title: toReactNode(notification.title),
message: toReactNode(notification.message),
actions: toAffineNotificationActions(notification.actions),
onDismiss: notification.onClose,
},
{
duration: notification.duration || 0,
onDismiss: notification.onClose,
onAutoClose: notification.onClose,
}
);
notification.abort?.addEventListener('abort', () => {
notify.dismiss(toastId);
});
},
});
const notificationService = new NotificationServiceImpl(
closeConfirmModal,
openConfirmModal
);
return NotificationExtension(notificationService);
}

View File

@@ -1,4 +1,4 @@
import { IconButton, Loading } from '@affine/component';
import { IconButton } from '@affine/component';
import { LitDocEditor, type PageEditor } from '@affine/core/blocksuite/editors';
import { SnapshotHelper } from '@affine/core/modules/comment/services/snapshot-helper';
import type { CommentAttachment } from '@affine/core/modules/comment/types';
@@ -144,6 +144,11 @@ export const CommentEditor = forwardRef<CommentEditorRef, CommentEditorProps>(
);
const isImageUploadDisabled = (attachments?.length ?? 0) >= MAX_IMAGE_COUNT;
const uploadingAttachments = attachments?.some(
att => att.status === 'uploading'
);
const commitDisabled =
(empty && (attachments?.length ?? 0) === 0) || uploadingAttachments;
const addImages = useAsyncCallback(
async (files: File[]) => {
@@ -296,13 +301,13 @@ export const CommentEditor = forwardRef<CommentEditorRef, CommentEditorProps>(
// upload attachments and call original onCommit
const handleCommit = useAsyncCallback(async () => {
if (readonly) return;
if (readonly || commitDisabled) return;
onCommit?.();
setAttachments(prev => {
prev.forEach(att => att.localUrl && URL.revokeObjectURL(att.localUrl));
return [];
});
}, [readonly, onCommit, setAttachments]);
}, [readonly, commitDisabled, onCommit, setAttachments]);
const focusEditor = useAsyncCallback(async () => {
if (editorRef.current) {
@@ -447,20 +452,17 @@ export const CommentEditor = forwardRef<CommentEditorRef, CommentEditorProps>(
onClick={e => handleImageClick(e, index)}
>
{!readonly && (
<div
className={styles.deleteBtn}
<IconButton
size={12}
className={styles.attachmentButton}
loading={att.status === 'uploading'}
variant="danger"
onClick={e => {
e.stopPropagation();
handleImageRemove(att.id);
}}
>
<CloseIcon width={12} height={12} />
</div>
)}
{att.status === 'uploading' && (
<div className={styles.spinnerWrapper}>
<Loading size={16} />
</div>
icon={<CloseIcon />}
/>
)}
</div>
))}
@@ -480,7 +482,7 @@ export const CommentEditor = forwardRef<CommentEditorRef, CommentEditorProps>(
<button
onClick={handleCommit}
className={styles.commitButton}
disabled={empty && (attachments?.length ?? 0) === 0}
disabled={commitDisabled}
>
<ArrowUpBigIcon />
</button>

View File

@@ -91,36 +91,18 @@ export const previewBox = style({
},
});
export const deleteBtn = style({
export const attachmentButton = style({
position: 'absolute',
top: -6,
right: -6,
width: 16,
height: 16,
borderRadius: 4,
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
border: `0.5px solid ${cssVarV2('layer/insideBorder/border')}`,
backgroundColor: cssVarV2('layer/background/primary'),
cursor: 'pointer',
background: cssVarV2('layer/background/primary'),
border: '1px solid',
borderColor: cssVarV2('layer/insideBorder/border'),
selectors: {
'&:hover': {
backgroundColor: cssVarV2('layer/background/error'),
background: cssVarV2('layer/background/error'),
borderColor: cssVarV2('button/error'),
color: cssVarV2('button/error'),
},
},
});
export const spinnerWrapper = style({
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '100%',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'rgba(255,255,255,0.6)',
});

View File

@@ -108,7 +108,14 @@ export const DocsExplorer = ({
masonryItemWidthMin?: number;
onRestore?: (ids: string[]) => void;
/** Override the default delete action */
onDelete?: (ids: string[]) => void;
onDelete?: (
ids: string[],
callbacks?: {
onFinished?: () => void;
onAbort?: () => void;
onError?: (error: Error) => void;
}
) => void;
}) => {
const t = useI18n();
const contextValue = useContext(DocExplorerContext);
@@ -163,8 +170,11 @@ export const DocsExplorer = ({
return;
}
if (onDelete) {
onDelete(contextValue.selectedDocIds$.value);
handleCloseFloatingToolbar();
onDelete(contextValue.selectedDocIds$.value, {
onFinished: () => {
handleCloseFloatingToolbar();
},
});
return;
}

View File

@@ -1,11 +1,10 @@
import { observeResize } from '@affine/component';
import { observeResize, useConfirmModal } from '@affine/component';
import { CopilotClient } from '@affine/core/blocksuite/ai';
import { AIChatContent } from '@affine/core/blocksuite/ai/components/ai-chat-content';
import { AIChatToolbar } from '@affine/core/blocksuite/ai/components/ai-chat-toolbar';
import { getCustomPageEditorBlockSpecs } from '@affine/core/blocksuite/ai/components/text-renderer';
import type { PromptKey } from '@affine/core/blocksuite/ai/provider/prompt';
import { NotificationServiceImpl } from '@affine/core/blocksuite/view-extensions/editor-view/notification-service';
import { useAIChatConfig } from '@affine/core/components/hooks/affine/use-ai-chat-config';
import { getCollection } from '@affine/core/desktop/dialogs/setting/general-setting/editor/edgeless/docs';
import {
EventSourceService,
FetchService,
@@ -13,6 +12,7 @@ import {
} from '@affine/core/modules/cloud';
import { WorkspaceDialogService } from '@affine/core/modules/dialogs';
import { FeatureFlagService } from '@affine/core/modules/feature-flag';
import { AppThemeService } from '@affine/core/modules/theme';
import {
ViewBody,
ViewHeader,
@@ -21,8 +21,6 @@ import {
} from '@affine/core/modules/workbench';
import { WorkspaceService } from '@affine/core/modules/workspace';
import { useI18n } from '@affine/i18n';
import type { Doc, Store } from '@blocksuite/affine/store';
import { BlockStdScope, type EditorHost } from '@blocksuite/std';
import { type Signal, signal } from '@preact/signals-core';
import { useFramework, useService } from '@toeverything/infra';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
@@ -52,7 +50,6 @@ export const Component = () => {
const framework = useFramework();
const [isBodyProvided, setIsBodyProvided] = useState(false);
const [isHeaderProvided, setIsHeaderProvided] = useState(false);
const [host, setHost] = useState<EditorHost | null>(null);
const [chatContent, setChatContent] = useState<AIChatContent | null>(null);
const [chatTool, setChatTool] = useState<AIChatToolbar | null>(null);
const [currentSession, setCurrentSession] = useState<CopilotSession | null>(
@@ -132,28 +129,11 @@ export const Component = () => {
[chatContent, chatTool, client, isOpeningSession, workspaceId]
);
// create a temp doc/host for ai-chat-content
useEffect(() => {
let tempDoc: Doc | null = null;
const collection = getCollection();
const doc = collection.createDoc();
tempDoc = doc;
doc.load(() => {
const host = new BlockStdScope({
store: tempDoc?.getStore() as Store,
extensions: getCustomPageEditorBlockSpecs(),
}).render();
setHost(host);
});
return () => {
tempDoc?.dispose();
};
}, []);
const confirmModal = useConfirmModal();
// init or update ai-chat-content
useEffect(() => {
if (!isBodyProvided || !host) {
if (!isBodyProvided) {
return;
}
@@ -164,7 +144,6 @@ export const Component = () => {
}
content.session = currentSession;
content.host = host;
content.workspaceId = workspaceId;
content.docDisplayConfig = docDisplayConfig;
content.searchMenuConfig = searchMenuConfig;
@@ -174,6 +153,11 @@ export const Component = () => {
content.affineWorkspaceDialogService = framework.get(
WorkspaceDialogService
);
content.affineThemeService = framework.get(AppThemeService);
content.notificationService = new NotificationServiceImpl(
confirmModal.closeConfirmModal,
confirmModal.openConfirmModal
);
if (!chatContent) {
// initial values that won't change
@@ -190,12 +174,12 @@ export const Component = () => {
currentSession,
docDisplayConfig,
framework,
host,
isBodyProvided,
networkSearchConfig,
reasoningConfig,
searchMenuConfig,
workspaceId,
confirmModal,
]);
// init or update header ai-chat-toolbar
@@ -213,6 +197,10 @@ export const Component = () => {
tool.workspaceId = workspaceId;
tool.docDisplayConfig = docDisplayConfig;
tool.onOpenSession = onOpenSession;
tool.notificationService = new NotificationServiceImpl(
confirmModal.closeConfirmModal,
confirmModal.openConfirmModal
);
tool.onNewSession = () => {
if (!currentSession) return;
@@ -239,6 +227,7 @@ export const Component = () => {
onOpenSession,
togglePin,
workspaceId,
confirmModal,
]);
const onChatContainerRef = useCallback((node: HTMLDivElement) => {

View File

@@ -1,8 +1,11 @@
import { useConfirmModal } from '@affine/component';
import { AIProvider, ChatPanel } from '@affine/core/blocksuite/ai';
import type { AffineEditorContainer } from '@affine/core/blocksuite/block-suite-editor';
import { NotificationServiceImpl } from '@affine/core/blocksuite/view-extensions/editor-view/notification-service';
import { useAIChatConfig } from '@affine/core/components/hooks/affine/use-ai-chat-config';
import { WorkspaceDialogService } from '@affine/core/modules/dialogs';
import { FeatureFlagService } from '@affine/core/modules/feature-flag';
import { AppThemeService } from '@affine/core/modules/theme';
import { WorkbenchService } from '@affine/core/modules/workbench';
import { ViewExtensionManagerIdentifier } from '@blocksuite/affine/ext-loader';
import { RefNodeSlotsProvider } from '@blocksuite/affine/inlines/reference';
@@ -51,6 +54,7 @@ export const EditorChatPanel = forwardRef(function EditorChatPanel(
reasoningConfig,
playgroundConfig,
} = useAIChatConfig();
const confirmModal = useConfirmModal();
useEffect(() => {
if (!editor || !editor.host) return;
@@ -87,6 +91,11 @@ export const EditorChatPanel = forwardRef(function EditorChatPanel(
);
chatPanelRef.current.affineWorkbenchService =
framework.get(WorkbenchService);
chatPanelRef.current.affineThemeService = framework.get(AppThemeService);
chatPanelRef.current.notificationService = new NotificationServiceImpl(
confirmModal.closeConfirmModal,
confirmModal.openConfirmModal
);
containerRef.current?.append(chatPanelRef.current);
} else {
@@ -117,6 +126,7 @@ export const EditorChatPanel = forwardRef(function EditorChatPanel(
searchMenuConfig,
reasoningConfig,
playgroundConfig,
confirmModal,
]);
const [autoResized, setAutoResized] = useState(false);

Some files were not shown because too many files have changed in this diff Show More