Compare commits

..

1 Commits

Author SHA1 Message Date
fengmk2 b1d7011047 chore(server): use jemalloc to reduce RSS 2025-07-10 11:22:37 +08:00
55 changed files with 124 additions and 566 deletions
-6
View File
@@ -4,15 +4,9 @@ inputs:
app-version:
description: 'App Version'
required: true
ios-app-version:
description: 'iOS App Store Version (Optional, use App version if empty)'
required: false
type: string
runs:
using: 'composite'
steps:
- name: 'Write Version'
shell: bash
env:
IOS_APP_VERSION: ${{ inputs.ios-app-version }}
run: ./scripts/set-version.sh ${{ inputs.app-version }}
+2 -6
View File
@@ -12,9 +12,6 @@ on:
build-type:
type: string
required: true
ios-app-version:
type: string
required: false
env:
BUILD_TYPE: ${{ inputs.build-type }}
@@ -81,7 +78,7 @@ jobs:
path: packages/frontend/apps/android/dist
ios:
runs-on: 'macos-15'
runs-on: ${{ github.ref_name == 'canary' && 'macos-latest' || 'blaze/macos-14' }}
needs:
- build-ios-web
steps:
@@ -90,7 +87,6 @@ jobs:
uses: ./.github/actions/setup-version
with:
app-version: ${{ inputs.app-version }}
ios-app-version: ${{ inputs.ios-app-version }}
- name: 'Update Code Sign Identity'
shell: bash
run: ./packages/frontend/apps/ios/update_code_sign_identity.sh
@@ -110,7 +106,7 @@ jobs:
enableScripts: false
- uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: 16.4
xcode-version: 16.2
- name: Install Swiftformat
run: brew install swiftformat
- name: Cap sync
-5
View File
@@ -21,10 +21,6 @@ on:
required: true
type: boolean
default: false
ios-app-version:
description: 'iOS App Store Version (Optional, use tag version if empty)'
required: false
type: string
permissions:
contents: write
@@ -121,4 +117,3 @@ jobs:
build-type: ${{ needs.prepare.outputs.BUILD_TYPE }}
app-version: ${{ needs.prepare.outputs.APP_VERSION }}
git-short-hash: ${{ needs.prepare.outputs.GIT_SHORT_HASH }}
ios-app-version: ${{ inputs.ios-app-version }}
-1
View File
@@ -266,7 +266,6 @@
"./components/toggle-button": "./src/components/toggle-button.ts",
"./components/toggle-switch": "./src/components/toggle-switch.ts",
"./components/toolbar": "./src/components/toolbar.ts",
"./components/tooltip": "./src/components/tooltip.ts",
"./components/view-dropdown-menu": "./src/components/view-dropdown-menu.ts",
"./components/tooltip-content-with-shortcut": "./src/components/tooltip-content-with-shortcut.ts",
"./components/resource": "./src/components/resource.ts",
@@ -1 +0,0 @@
export * from '@blocksuite/affine-components/tooltip';
+1 -2
View File
@@ -73,8 +73,7 @@
"./edgeless-line-styles-panel": "./src/edgeless-line-styles-panel/index.ts",
"./edgeless-shape-color-picker": "./src/edgeless-shape-color-picker/index.ts",
"./open-doc-dropdown-menu": "./src/open-doc-dropdown-menu/index.ts",
"./slider": "./src/slider/index.ts",
"./tooltip": "./src/tooltip/index.ts"
"./slider": "./src/slider/index.ts"
},
"files": [
"src",
@@ -1,4 +1,3 @@
import { effects as tooltipEffects } from '../tooltip/effect.js';
import { EditorIconButton } from './icon-button.js';
import {
EditorMenuAction,
@@ -7,6 +6,7 @@ import {
} from './menu-button.js';
import { EditorToolbarSeparator } from './separator.js';
import { EditorToolbar } from './toolbar.js';
import { Tooltip } from './tooltip.js';
export { EditorChevronDown } from './chevron-down.js';
export { ToolbarMoreMenuConfigExtension } from './config.js';
@@ -20,6 +20,7 @@ export { MenuContext } from './menu-context.js';
export { EditorToolbarSeparator } from './separator.js';
export { darkToolbarStyles, lightToolbarStyles } from './styles.js';
export { EditorToolbar } from './toolbar.js';
export { Tooltip } from './tooltip.js';
export type {
AdvancedMenuItem,
FatMenuItems,
@@ -37,12 +38,11 @@ export {
} from './utils.js';
export function effects() {
tooltipEffects();
customElements.define('editor-toolbar-separator', EditorToolbarSeparator);
customElements.define('editor-toolbar', EditorToolbar);
customElements.define('editor-icon-button', EditorIconButton);
customElements.define('editor-menu-button', EditorMenuButton);
customElements.define('editor-menu-content', EditorMenuContent);
customElements.define('editor-menu-action', EditorMenuAction);
customElements.define('affine-tooltip', Tooltip);
}
@@ -1,7 +0,0 @@
import { Tooltip } from './tooltip.js';
export function effects() {
if (!customElements.get('affine-tooltip')) {
customElements.define('affine-tooltip', Tooltip);
}
}
@@ -1,2 +0,0 @@
export { effects } from './effect.js';
export { Tooltip } from './tooltip.js';
@@ -30,9 +30,9 @@ function inlineTextStyles(
}
return styleMap({
'font-weight': props.bold ? 'bold' : 'inherit',
'font-style': props.italic ? 'italic' : 'inherit',
'text-decoration': textDecorations.length > 0 ? textDecorations : 'inherit',
'font-weight': props.bold ? 'bold' : 'normal',
'font-style': props.italic ? 'italic' : 'normal',
'text-decoration': textDecorations.length > 0 ? textDecorations : 'none',
...inlineCodeStyle,
});
}
@@ -207,7 +207,6 @@ const retry = async (
try {
await callback(t);
} catch (e) {
console.error(`Error during ${action}:`, e);
t.log(`Error during ${action}:`, e);
throw e;
}
@@ -484,34 +483,6 @@ The term **“CRDT”** was first introduced by Marc Shapiro, Nuno Preguiça, Ca
type: 'structured' as const,
prefer: CopilotProviderType.Gemini,
},
{
promptName: ['Conversation Summary'],
messages: [
{
role: 'user' as const,
content: '',
params: {
messages: [
{ role: 'user', content: 'what is single source of truth?' },
{ role: 'assistant', content: TestAssets.SSOT },
],
focus: 'technical decisions',
length: 'comprehensive',
},
},
],
verifier: (t: ExecutionContext<Tester>, result: string) => {
assertNotWrappedInCodeBlock(t, result);
const cleared = result.toLowerCase();
t.assert(
cleared.includes('single source of truth') ||
/single.*source/.test(cleared) ||
cleared.includes('ssot'),
'should include original keyword'
);
},
type: 'text' as const,
},
{
promptName: [
'Summary',
@@ -99,56 +99,3 @@ e2e(
t.is(result2.workspace.doc.public, true);
}
);
e2e('should get doc with title and summary', async t => {
const owner = await app.signup();
const workspace = await app.create(Mockers.Workspace, {
owner: { id: owner.id },
});
const docSnapshot = await app.create(Mockers.DocSnapshot, {
workspaceId: workspace.id,
user: owner,
});
const doc = await app.create(Mockers.DocMeta, {
workspaceId: workspace.id,
docId: docSnapshot.id,
title: 'doc1',
summary: 'summary1',
});
const result = await app.gql({
query: getWorkspacePageByIdQuery,
variables: { workspaceId: workspace.id, pageId: doc.docId },
});
t.is(result.workspace.doc.title, doc.title);
t.is(result.workspace.doc.summary, doc.summary);
});
e2e('should get doc with title and null summary', async t => {
const owner = await app.signup();
const workspace = await app.create(Mockers.Workspace, {
owner: { id: owner.id },
});
const docSnapshot = await app.create(Mockers.DocSnapshot, {
workspaceId: workspace.id,
user: owner,
});
const doc = await app.create(Mockers.DocMeta, {
workspaceId: workspace.id,
docId: docSnapshot.id,
title: 'doc1',
});
const result = await app.gql({
query: getWorkspacePageByIdQuery,
variables: { workspaceId: workspace.id, pageId: doc.docId },
});
t.is(result.workspace.doc.title, doc.title);
t.is(result.workspace.doc.summary, null);
});
@@ -669,10 +669,7 @@ test('should get doc info', async t => {
};
await t.context.doc.upsert(snapshot);
await t.context.doc.upsertMeta(workspace.id, docId, {
title: 'test title',
summary: 'test summary',
});
await t.context.doc.upsertMeta(workspace.id, docId);
const docInfo = await t.context.doc.getDocInfo(workspace.id, docId);
@@ -682,8 +679,6 @@ test('should get doc info', async t => {
updatedAt: new Date(snapshot.timestamp),
creatorId: user.id,
lastUpdaterId: user.id,
title: 'test title',
summary: 'test summary',
});
});
@@ -100,7 +100,7 @@ export class PgWorkspaceDocStorageAdapter extends DocStorageAdapter {
{
// keep it simple to let all update merged in one job
jobId: `doc:merge-pending-updates:${workspaceId}:${docId}`,
delay: 5 * 1000 /* 5s */,
delay: 30 * 1000 /* 30s */,
priority: 100,
}
);
@@ -79,9 +79,6 @@ class DocType {
@Field(() => String, { nullable: true })
title?: string | null;
@Field(() => String, { nullable: true })
summary?: string | null;
}
@InputType()
@@ -253,11 +250,10 @@ export class WorkspaceDocResolver {
deprecationReason: 'use [WorkspaceType.doc] instead',
})
async publicPage(
@CurrentUser() me: CurrentUser,
@Parent() workspace: WorkspaceType,
@Args('pageId') pageId: string
) {
return this.doc(me, workspace, pageId);
return this.doc(workspace, pageId);
}
@ResolveField(() => PaginatedDocType)
@@ -298,14 +294,11 @@ export class WorkspaceDocResolver {
complexity: 2,
})
async doc(
@CurrentUser() me: CurrentUser,
@Parent() workspace: WorkspaceType,
@Args('docId') docId: string
): Promise<DocType> {
const doc = await this.models.doc.getDocInfo(workspace.id, docId);
if (doc) {
// check if doc is readable
await this.ac.user(me.id).doc(workspace.id, docId).assert('Doc.Read');
return doc;
}
@@ -558,8 +558,6 @@ export class DocModel extends BaseModel {
mode: PublicDocMode;
public: boolean;
defaultRole: DocRole;
title: string | null;
summary: string | null;
createdAt: Date;
updatedAt: Date;
creatorId?: string;
@@ -572,8 +570,6 @@ export class DocModel extends BaseModel {
"workspace_pages"."mode" as "mode",
"workspace_pages"."public" as "public",
"workspace_pages"."defaultRole" as "defaultRole",
"workspace_pages"."title" as "title",
"workspace_pages"."summary" as "summary",
"snapshots"."created_at" as "createdAt",
"snapshots"."updated_at" as "updatedAt",
"snapshots"."created_by" as "creatorId",
@@ -366,31 +366,6 @@ Convert a multi-speaker audio recording into a structured JSON format by transcr
requireAttachment: true,
},
},
{
name: 'Conversation Summary',
action: 'Conversation Summary',
model: 'gpt-4.1-2025-04-14',
messages: [
{
role: 'system',
content: `You are an expert conversation summarizer. Your job is to distill long dialogues into clear, compact summaries that preserve every key decision, fact, and open question. When asked, always:
• Honor any explicit “focus” the user gives you.
• Match the desired length style:
- “brief” → 1-2 sentences
- “detailed” → ≈ 5 sentences or short bullet list
- “comprehensive” → full paragraph(s) covering all salient points.
• Write in neutral, third-person prose and never add new information.
Return only the summary text—no headings, labels, or commentary.`,
},
{
role: 'user',
content: `Summarize the conversation below so it can be carried forward without loss.\n\nFocus: {{focus}}\nDesired length: {{length}}\n\nConversation:\n{{#messages}}\n{{role}}: {{content}}\n{{/messages}}`,
},
],
config: {
requireContent: false,
},
},
{
name: 'Summary',
action: 'Summary',
@@ -21,7 +21,6 @@ import {
buildDocKeywordSearchGetter,
buildDocSearchGetter,
createCodeArtifactTool,
createConversationSummaryTool,
createDocComposeTool,
createDocEditTool,
createDocKeywordSearchTool,
@@ -140,10 +139,6 @@ export abstract class CopilotProvider<C = any> {
if (options?.tools?.length) {
this.logger.debug(`getTools: ${JSON.stringify(options.tools)}`);
const ac = this.moduleRef.get(AccessController, { strict: false });
const docReader = this.moduleRef.get(DocReader, { strict: false });
const prompt = this.moduleRef.get(PromptService, {
strict: false,
});
for (const tool of options.tools) {
const toolDef = this.getProviderSpecificTools(tool, model);
@@ -155,20 +150,9 @@ export abstract class CopilotProvider<C = any> {
continue;
}
switch (tool) {
case 'codeArtifact': {
tools.code_artifact = createCodeArtifactTool(prompt, this.factory);
break;
}
case 'conversationSummary': {
tools.conversation_summary = createConversationSummaryTool(
options.session,
prompt,
this.factory
);
break;
}
case 'docEdit': {
const getDocContent = buildContentGetter(ac, docReader);
const doc = this.moduleRef.get(DocReader, { strict: false });
const getDocContent = buildContentGetter(ac, doc);
tools.doc_edit = createDocEditTool(
this.factory,
getDocContent.bind(null, options)
@@ -179,6 +163,7 @@ export abstract class CopilotProvider<C = any> {
const context = this.moduleRef.get(CopilotContextService, {
strict: false,
});
const docContext = options.session
? await context.getBySessionId(options.session)
: null;
@@ -190,6 +175,9 @@ export abstract class CopilotProvider<C = any> {
}
case 'docKeywordSearch': {
if (this.AFFiNEConfig.indexer.enabled) {
const ac = this.moduleRef.get(AccessController, {
strict: false,
});
const indexerService = this.moduleRef.get(IndexerService, {
strict: false,
});
@@ -204,7 +192,9 @@ export abstract class CopilotProvider<C = any> {
break;
}
case 'docRead': {
const ac = this.moduleRef.get(AccessController, { strict: false });
const models = this.moduleRef.get(Models, { strict: false });
const docReader = this.moduleRef.get(DocReader, { strict: false });
const getDoc = buildDocContentGetter(ac, docReader, models);
tools.doc_read = createDocReadTool(getDoc.bind(null, options));
break;
@@ -215,7 +205,23 @@ export abstract class CopilotProvider<C = any> {
break;
}
case 'docCompose': {
tools.doc_compose = createDocComposeTool(prompt, this.factory);
const promptService = this.moduleRef.get(PromptService, {
strict: false,
});
tools.doc_compose = createDocComposeTool(
promptService,
this.factory
);
break;
}
case 'codeArtifact': {
const promptService = this.moduleRef.get(PromptService, {
strict: false,
});
tools.code_artifact = createCodeArtifactTool(
promptService,
this.factory
);
break;
}
}
@@ -60,8 +60,6 @@ export const VertexSchema: JSONSchema = {
export const PromptConfigStrictSchema = z.object({
tools: z
.enum([
'codeArtifact',
'conversationSummary',
// work with morph
'docEdit',
// work with indexer
@@ -73,6 +71,7 @@ export const PromptConfigStrictSchema = z.object({
'webSearch',
// artifact tools
'docCompose',
'codeArtifact',
])
.array()
.nullable()
@@ -6,10 +6,20 @@ import {
ImagePart,
TextPart,
TextStreamPart,
ToolSet,
} from 'ai';
import { ZodType } from 'zod';
import { CustomAITools } from '../tools';
import {
createCodeArtifactTool,
createDocComposeTool,
createDocEditTool,
createDocKeywordSearchTool,
createDocReadTool,
createDocSemanticSearchTool,
createExaCrawlTool,
createExaSearchTool,
} from '../tools';
import { PromptMessage, StreamObject } from './types';
type ChatMessage = CoreUserMessage | CoreAssistantMessage;
@@ -375,6 +385,17 @@ export class CitationParser {
}
}
export interface CustomAITools extends ToolSet {
doc_edit: ReturnType<typeof createDocEditTool>;
doc_semantic_search: ReturnType<typeof createDocSemanticSearchTool>;
doc_keyword_search: ReturnType<typeof createDocKeywordSearchTool>;
doc_read: ReturnType<typeof createDocReadTool>;
doc_compose: ReturnType<typeof createDocComposeTool>;
web_search_exa: ReturnType<typeof createExaSearchTool>;
web_crawl_exa: ReturnType<typeof createExaCrawlTool>;
code_artifact: ReturnType<typeof createCodeArtifactTool>;
}
type ChunkType = TextStreamPart<CustomAITools>['type'];
export function toError(error: unknown): Error {
@@ -430,10 +451,6 @@ export class TextStreamParser {
);
result = this.addPrefix(result);
switch (chunk.toolName) {
case 'conversation_summary': {
result += `\nSummarizing context\n`;
break;
}
case 'web_search_exa': {
result += `\nSearching the web "${chunk.args.query}"\n`;
break;
@@ -1,76 +0,0 @@
import { Logger } from '@nestjs/common';
import { tool } from 'ai';
import { z } from 'zod';
import type { PromptService } from '../prompt';
import type { CopilotProviderFactory } from '../providers';
import { toolError } from './error';
const logger = new Logger('ConversationSummaryTool');
export const createConversationSummaryTool = (
sessionId: string | undefined,
promptService: PromptService,
factory: CopilotProviderFactory
) => {
return tool({
description:
'Create a concise, AI-generated summary of the conversation so far—capturing key topics, decisions, and critical details. Use this tool whenever the context becomes lengthy to preserve essential information that might otherwise be lost to truncation in future turns.',
parameters: z.object({
focus: z
.string()
.optional()
.describe(
'Optional focus area for the summary (e.g., "technical decisions", "user requirements", "project status")'
),
length: z
.enum(['brief', 'detailed', 'comprehensive'])
.default('detailed')
.describe(
'The desired length of the summary: brief (1-2 sentences), detailed (paragraph), comprehensive (multiple paragraphs)'
),
}),
execute: async ({ focus, length }, { messages }) => {
try {
if (!messages || messages.length === 0) {
return toolError(
'No Conversation Context',
'No messages available to summarize'
);
}
const prompt = await promptService.get('Conversation Summary');
const provider = await factory.getProviderByModel(prompt?.model || '');
if (!prompt || !provider) {
return toolError(
'Prompt Not Found',
'Failed to summarize conversation.'
);
}
const summary = await provider.text(
{ modelId: prompt.model },
prompt.finish({
messages: messages.map(m => ({
...m,
content: m.content.toString(),
})),
focus: focus || 'general',
length,
})
);
return {
focusArea: focus || 'general',
messageCount: messages.length,
summary,
timestamp: new Date().toISOString(),
};
} catch (err: any) {
logger.error(`Failed to summarize conversation (${sessionId})`, err);
return toolError('Conversation Summary Failed', err.message);
}
},
});
};
@@ -1,29 +1,4 @@
import { ToolSet } from 'ai';
import { createCodeArtifactTool } from './code-artifact';
import { createConversationSummaryTool } from './conversation-summary';
import { createDocComposeTool } from './doc-compose';
import { createDocEditTool } from './doc-edit';
import { createDocKeywordSearchTool } from './doc-keyword-search';
import { createDocReadTool } from './doc-read';
import { createDocSemanticSearchTool } from './doc-semantic-search';
import { createExaCrawlTool } from './exa-crawl';
import { createExaSearchTool } from './exa-search';
export interface CustomAITools extends ToolSet {
code_artifact: ReturnType<typeof createCodeArtifactTool>;
conversation_summary: ReturnType<typeof createConversationSummaryTool>;
doc_edit: ReturnType<typeof createDocEditTool>;
doc_semantic_search: ReturnType<typeof createDocSemanticSearchTool>;
doc_keyword_search: ReturnType<typeof createDocKeywordSearchTool>;
doc_read: ReturnType<typeof createDocReadTool>;
doc_compose: ReturnType<typeof createDocComposeTool>;
web_search_exa: ReturnType<typeof createExaSearchTool>;
web_crawl_exa: ReturnType<typeof createExaCrawlTool>;
}
export * from './code-artifact';
export * from './conversation-summary';
export * from './doc-compose';
export * from './doc-edit';
export * from './doc-keyword-search';
-1
View File
@@ -595,7 +595,6 @@ type DocType {
mode: PublicDocMode!
permissions: DocPermissions!
public: Boolean!
summary: String
title: String
updatedAt: DateTime
workspaceId: String!
@@ -5,8 +5,6 @@ query getWorkspacePageById($workspaceId: String!, $pageId: String!) {
mode
defaultRole
public
title
summary
}
}
}
@@ -1584,8 +1584,6 @@ export const getWorkspacePageByIdQuery = {
mode
defaultRole
public
title
summary
}
}
}`,
-3
View File
@@ -703,7 +703,6 @@ export interface DocType {
mode: PublicDocMode;
permissions: DocPermissions;
public: Scalars['Boolean']['output'];
summary: Maybe<Scalars['String']['output']>;
title: Maybe<Scalars['String']['output']>;
updatedAt: Maybe<Scalars['DateTime']['output']>;
workspaceId: Scalars['String']['output'];
@@ -5148,8 +5147,6 @@ export type GetWorkspacePageByIdQuery = {
mode: PublicDocMode;
defaultRole: DocRole;
public: boolean;
title: string | null;
summary: string | null;
};
};
};
@@ -541,7 +541,7 @@
"$(inherited)",
"$(PROJECT_DIR)",
);
MARKETING_VERSION = 0.23.1;
MARKETING_VERSION = 0.22.2;
OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\"";
PRODUCT_BUNDLE_IDENTIFIER = app.affine.pro;
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -577,7 +577,7 @@
"$(inherited)",
"$(PROJECT_DIR)",
);
MARKETING_VERSION = 0.23.1;
MARKETING_VERSION = 0.22.2;
ONLY_ACTIVE_ARCH = NO;
PRODUCT_BUNDLE_IDENTIFIER = app.affine.pro;
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -1,6 +1,5 @@
import type { MindmapElementModel } from '@blocksuite/affine/model';
import type { EditorHost } from '@blocksuite/affine/std';
import { ThemeProvider } from '@blocksuite/affine-shared/services';
import { createAIScrollableTextRenderer } from '../components/ai-scrollable-text-renderer';
import {
@@ -53,11 +52,5 @@ export function actionToAnswerRenderer<
return createImageRenderer(host, { height: 300 });
}
return createAIScrollableTextRenderer(
{
theme: host.std.get(ThemeProvider).app$,
},
320,
true
);
return createAIScrollableTextRenderer(host, {}, 320, true);
}
@@ -11,7 +11,6 @@ import {
} from '@blocksuite/affine/shared/utils';
import type { EditorHost } from '@blocksuite/affine/std';
import { GfxControllerIdentifier } from '@blocksuite/affine/std/gfx';
import { ThemeProvider } from '@blocksuite/affine-shared/services';
import {
ChatWithAiIcon,
DeleteIcon,
@@ -307,13 +306,7 @@ export function buildAIPanelConfig(
const ctx = new AIContext();
const searchService = framework.get(AINetworkSearchService);
return {
answerRenderer: createAIScrollableTextRenderer(
{
theme: panel.host.std.get(ThemeProvider).app$,
},
320,
true
),
answerRenderer: createAIScrollableTextRenderer(panel.host, {}, 320, true),
finishStateConfig: buildFinishConfig(panel, 'chat', ctx),
generatingStateConfig: buildGeneratingConfig(),
errorStateConfig: buildErrorConfig(panel),
@@ -30,7 +30,6 @@ import type {
AIPlaygroundConfig,
AIReasoningConfig,
} from '../components/ai-chat-input';
import type { ChatStatus } from '../components/ai-chat-messages';
import { createPlaygroundModal } from '../components/playground/modal';
import { AIProvider } from '../provider';
import type { AppSidebarConfig } from './chat-config';
@@ -139,9 +138,6 @@ export class ChatPanel extends SignalWatcher(
@state()
accessor embeddingProgress: [number, number] = [0, 0];
@state()
accessor status: ChatStatus = 'idle';
private isSidebarOpen: Signal<boolean | undefined> = signal(false);
private sidebarWidth: Signal<number | undefined> = signal(undefined);
@@ -175,7 +171,6 @@ export class ChatPanel extends SignalWatcher(
.session=${this.session}
.workspaceId=${this.doc.workspace.id}
.docId=${this.doc.id}
.status=${this.status}
.onNewSession=${this.newSession}
.onTogglePin=${this.togglePin}
.onOpenSession=${this.openSession}
@@ -364,7 +359,6 @@ export class ChatPanel extends SignalWatcher(
private readonly onContextChange = async (
context: Partial<ChatContextValue>
) => {
this.status = context.status ?? 'idle';
if (context.status === 'success') {
await this.rebindSession();
}
@@ -437,7 +437,6 @@ export class AIChatMessages extends WithDisposable(ShadowlessElement) {
const last = messages[messages.length - 1];
if ('content' in last) {
last.content = '';
last.streamObjects = [];
last.createdAt = new Date().toISOString();
}
this.updateContext({
@@ -15,7 +15,6 @@ import { css, html } from 'lit';
import { property, query } from 'lit/decorators.js';
import type { DocDisplayConfig } from '../ai-chat-chips';
import type { ChatStatus } from '../ai-chat-messages';
export class AIChatToolbar extends WithDisposable(ShadowlessElement) {
@property({ attribute: false })
@@ -27,9 +26,6 @@ export class AIChatToolbar extends WithDisposable(ShadowlessElement) {
@property({ attribute: false })
accessor docId: string | undefined;
@property({ attribute: false })
accessor status!: ChatStatus;
@property({ attribute: false })
accessor onNewSession!: () => void;
@@ -53,10 +49,6 @@ export class AIChatToolbar extends WithDisposable(ShadowlessElement) {
private abortController: AbortController | null = null;
get isGenerating() {
return this.status === 'transmitting' || this.status === 'loading';
}
static override styles = css`
.ai-chat-toolbar {
display: flex;
@@ -80,10 +72,6 @@ export class AIChatToolbar extends WithDisposable(ShadowlessElement) {
height: 16px;
color: ${unsafeCSSVarV2('icon/primary')};
}
&[data-disabled='true'] {
cursor: not-allowed;
}
}
}
`;
@@ -96,11 +84,7 @@ export class AIChatToolbar extends WithDisposable(ShadowlessElement) {
${PlusIcon()}
<affine-tooltip>New Chat</affine-tooltip>
</div>
<div
class="chat-toolbar-icon"
@click=${this.onPinClick}
data-disabled=${this.isGenerating}
>
<div class="chat-toolbar-icon" @click=${this.onTogglePin}>
${pinned ? PinedIcon() : PinIcon()}
<affine-tooltip>
${pinned ? 'Unpin this Chat' : 'Pin this Chat'}
@@ -117,16 +101,6 @@ export class AIChatToolbar extends WithDisposable(ShadowlessElement) {
`;
}
private readonly onPinClick = async () => {
if (this.isGenerating) {
this.notificationService.toast(
'Cannot pin a chat while generating an answer'
);
return;
}
await this.onTogglePin();
};
private readonly unpinConfirm = async () => {
if (this.session && this.session.pinned) {
try {
@@ -1,6 +1,6 @@
import { WithDisposable } from '@blocksuite/affine/global/lit';
import { scrollbarStyle } from '@blocksuite/affine/shared/styles';
import { ShadowlessElement } from '@blocksuite/affine/std';
import { type EditorHost, ShadowlessElement } from '@blocksuite/affine/std';
import type { PropertyValues } from 'lit';
import { css, html } from 'lit';
import { property, query } from 'lit/decorators.js';
@@ -81,6 +81,9 @@ export class AIScrollableTextRenderer extends WithDisposable(
@property({ attribute: false })
accessor answer!: string;
@property({ attribute: false })
accessor host!: EditorHost;
@property({ attribute: false })
accessor state: AffineAIPanelState | undefined;
@@ -98,16 +101,19 @@ export class AIScrollableTextRenderer extends WithDisposable(
}
export const createAIScrollableTextRenderer: (
host: EditorHost,
textRendererOptions: TextRendererOptions,
maxHeight: number,
autoScroll: boolean
) => AffineAIPanelWidgetConfig['answerRenderer'] = (
host,
textRendererOptions,
maxHeight,
autoScroll
) => {
return (answer: string, state: AffineAIPanelState | undefined) => {
return html`<ai-scrollable-text-renderer
.host=${host}
.answer=${answer}
.state=${state}
.textRendererOptions=${textRendererOptions}
@@ -1,4 +1,3 @@
import track from '@affine/track';
import { WithDisposable } from '@blocksuite/affine/global/lit';
import { unsafeCSSVar, unsafeCSSVarV2 } from '@blocksuite/affine/shared/theme';
import { type EditorHost, ShadowlessElement } from '@blocksuite/affine/std';
@@ -204,33 +203,24 @@ export class DocEditTool extends WithDisposable(ShadowlessElement) {
}
private async _handleApply(markdown: string) {
if (!this.host || this.data.type !== 'tool-result') {
if (!this.host) {
return;
}
track.applyModel.chat.$.apply({
instruction: this.data.args.instructions,
});
await this.blockDiffService?.apply(this.host.store, markdown);
}
private async _handleReject(changedMarkdown: string) {
if (!this.host || this.data.type !== 'tool-result') {
if (!this.host) {
return;
}
track.applyModel.chat.$.reject({
instruction: this.data.args.instructions,
});
this.blockDiffService?.setChangedMarkdown(changedMarkdown);
this.blockDiffService?.rejectAll();
}
private async _handleAccept(changedMarkdown: string) {
if (!this.host || this.data.type !== 'tool-result') {
if (!this.host) {
return;
}
track.applyModel.chat.$.accept({
instruction: this.data.args.instructions,
});
await this.blockDiffService?.apply(this.host.store, changedMarkdown);
await this.blockDiffService?.acceptAll(this.host.store);
}
@@ -243,7 +233,6 @@ export class DocEditTool extends WithDisposable(ShadowlessElement) {
if (!this.host) {
return;
}
track.applyModel.chat.$.copy();
const success = await copyText(removeMarkdownComments(changedMarkdown));
if (success) {
this.notificationService.notify({
@@ -1,5 +1,5 @@
import type { CopilotChatHistoryFragment } from '@affine/graphql';
import { Tooltip } from '@blocksuite/affine/components/tooltip';
import { Tooltip } from '@blocksuite/affine/components/toolbar';
import { WithDisposable } from '@blocksuite/affine/global/lit';
import { noop } from '@blocksuite/affine/global/utils';
import { unsafeCSSVarV2 } from '@blocksuite/affine/shared/theme';
@@ -1,5 +1,3 @@
import { effects as tooltipEffects } from '@blocksuite/affine-components/tooltip';
import { AIChatBlockComponent } from './blocks/ai-chat-block/ai-chat-block';
import { EdgelessAIChatBlockComponent } from './blocks/ai-chat-block/ai-chat-edgeless-block';
import { LitTranscriptionBlock } from './blocks/ai-chat-block/ai-transcription-block';
@@ -115,7 +113,6 @@ export function registerAIEffects() {
registerMiniMindmapBlocks();
componentAiItemEffects();
componentPlaygroundEffects();
tooltipEffects();
customElements.define('ask-ai-icon', AskAIIcon);
customElements.define('ask-ai-button', AskAIButton);
@@ -372,7 +372,7 @@ export class AIChatBlockPeekView extends LitElement {
const last = messages[messages.length - 1];
if ('content' in last) {
last.content = '';
last.streamObjects = [];
last.id = '';
last.createdAt = new Date().toISOString();
}
this.updateContext({
@@ -1,4 +1,3 @@
import track from '@affine/track';
import { WithDisposable } from '@blocksuite/affine/global/lit';
import { unsafeCSSVar, unsafeCSSVarV2 } from '@blocksuite/affine/shared/theme';
import { CloseIcon, DoneIcon } from '@blocksuite/icons/lit';
@@ -51,12 +50,12 @@ export class BlockDiffOptions extends WithDisposable(LitElement) {
accessor onReject!: (op: PatchOp) => void;
private readonly _handleAcceptClick = () => {
track.applyModel.widget.block.accept();
console.log('accept', this.op);
this.onAccept(this.op);
};
private readonly _handleRejectClick = () => {
track.applyModel.widget.block.reject();
console.log('reject', this.op);
this.onReject(this.op);
};
@@ -1,4 +1,3 @@
import { track } from '@affine/track';
import { WidgetComponent, WidgetViewExtension } from '@blocksuite/affine/std';
import { unsafeCSSVar, unsafeCSSVarV2 } from '@blocksuite/affine-shared/theme';
import {
@@ -83,16 +82,6 @@ export class AffineBlockDiffWidgetForPage extends WidgetComponent {
diffs[this.currentIndex].scrollIntoView({ behavior: 'smooth' });
}
async _handleAcceptAll() {
track.applyModel.widget.page.acceptAll();
await this.diffService.acceptAll(this.std.store);
}
_handleRejectAll() {
track.applyModel.widget.page.rejectAll();
this.diffService.rejectAll();
}
get diffService() {
return this.std.get(BlockDiffProvider);
}
@@ -123,7 +112,7 @@ export class AffineBlockDiffWidgetForPage extends WidgetComponent {
</div>
<div
class="ai-block-diff-all-option"
@click=${() => this._handleRejectAll()}
@click=${() => this.diffService.rejectAll()}
>
${CloseIcon({
style: `color: ${unsafeCSSVarV2('icon/secondary')}`,
@@ -132,7 +121,7 @@ export class AffineBlockDiffWidgetForPage extends WidgetComponent {
</div>
<div
class="ai-block-diff-all-option"
@click=${() => this._handleAcceptAll()}
@click=${() => this.diffService.acceptAll(this.std.store)}
>
${DoneIcon({
style: `color: ${unsafeCSSVarV2('icon/activated')}`,
@@ -87,7 +87,7 @@ const usePatchSpecs = (mode: DocMode, shared?: boolean) => {
// comment may not be supported by the server
const enableComment =
isCloud && serverConfig.features.includes(ServerFeature.Comment) && !shared;
serverConfig.features.includes(ServerFeature.Comment) && !shared;
const patchedSpecs = useMemo(() => {
const manager = getViewManager()
@@ -44,8 +44,6 @@ const optionsSchema = z.object({
.args(z.custom<ConfirmModalProps>().optional(), z.any().optional()),
closeConfirmModal: z.function(),
}),
scope: z.enum(['doc', 'workspace']).optional(),
});
export type AffineEditorViewOptions = z.infer<typeof optionsSchema>;
@@ -95,7 +93,16 @@ export class AffineEditorViewExtension extends ViewExtensionProvider<AffineEdito
if (!options) {
return;
}
const { framework, reactToLit, confirmModal, scope = 'doc' } = options;
const {
framework,
reactToLit,
confirmModal,
} = options;
const docService = framework.get(DocService);
const docsService = framework.get(DocsService);
const editorService = framework.get(EditorService);
const referenceRenderer = this._getCustomReferenceRenderer(framework);
@@ -105,20 +112,12 @@ export class AffineEditorViewExtension extends ViewExtensionProvider<AffineEdito
patchNotificationService(confirmModal),
patchOpenDocExtension(),
patchSideBarService(framework),
patchDocModeService(docService, docsService, editorService),
patchFileSizeLimitExtension(framework),
buildDocDisplayMetaExtension(framework),
patchForAudioEmbedView(reactToLit),
])
.register(patchDocUrlExtensions(framework))
.register(patchQuickSearchService(framework));
if (scope === 'doc') {
const docService = framework.get(DocService);
const docsService = framework.get(DocsService);
const editorService = framework.get(EditorService);
context.register([
patchDocModeService(docService, docsService, editorService),
]);
}
}
}
@@ -1,9 +1,8 @@
import { IconButton, notify, toast } from '@affine/component';
import { IconButton, notify } 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';
import { PeekViewService } from '@affine/core/modules/peek-view';
import { downloadResourceWithUrl } from '@affine/core/utils/resource';
import { DebugLogger } from '@affine/debug';
import { getAttachmentFileIconRC } from '@blocksuite/affine/components/icons';
import { type RichText, selectTextModel } from '@blocksuite/affine/rich-text';
@@ -81,6 +80,16 @@ export interface CommentEditorRef {
focus: () => void;
}
const download = (url: string, name: string) => {
const element = document.createElement('a');
element.setAttribute('download', name);
element.setAttribute('href', url);
element.style.display = 'none';
document.body.append(element);
element.click();
element.remove();
};
// todo: get rid of circular data changes
const useSnapshotDoc = (
defaultSnapshotOrDoc: DocSnapshot | Store,
@@ -304,28 +313,6 @@ export const CommentEditor = forwardRef<CommentEditorRef, CommentEditorProps>(
[addAttachments]
);
const handleDragOver = useCallback(
(e: React.DragEvent) => {
if (readonly) return;
// Prevent default to allow drop
e.preventDefault();
},
[readonly]
);
const handleDrop = useCallback(
(e: React.DragEvent) => {
if (readonly) return;
e.preventDefault();
e.stopPropagation();
const files = Array.from(e.dataTransfer?.files ?? []);
if (files.length) {
addAttachments(files);
}
},
[addAttachments, readonly]
);
const openFilePicker = useAsyncCallback(async () => {
if (isUploadDisabled) return;
const files = await openFilesWith('Any');
@@ -395,6 +382,8 @@ export const CommentEditor = forwardRef<CommentEditorRef, CommentEditorProps>(
if (!attachments) return;
const att = attachments[index];
if (!att) return;
const url = att.url || att.localUrl;
if (!url) return;
if (isImageAttachment(att)) {
// translate attachment index to image index
const imageAttachments = attachments.filter(isImageAttachment);
@@ -402,19 +391,13 @@ export const CommentEditor = forwardRef<CommentEditorRef, CommentEditorProps>(
if (imageIndex >= 0) {
handleImagePreview(imageIndex);
}
} else if (att.url) {
} else if (att.url || att.localUrl) {
// todo: open attachment preview. for now, just download it
downloadResourceWithUrl(
att.url,
att.filename ?? att.file?.name ?? 'attachment'
).catch(e => {
console.error('Failed to download attachment', e);
notify.error({
title: 'Failed to download attachment',
message: e.message,
});
download(url, att.filename ?? att.file?.name ?? 'attachment');
notify({
title: 'Downloading attachment',
message: 'The attachment is being downloaded to your computer.',
});
toast('The attachment is being downloaded to your computer.');
}
},
[attachments, handleImagePreview]
@@ -555,8 +538,6 @@ export const CommentEditor = forwardRef<CommentEditorRef, CommentEditorProps>(
onClick={readonly ? undefined : handleClickEditor}
onKeyDown={handleKeyDown}
onPaste={handlePaste}
onDragOver={handleDragOver}
onDrop={handleDrop}
data-readonly={!!readonly}
className={clsx(styles.container, 'comment-editor-viewport')}
>
@@ -596,7 +596,7 @@ const CommentList = ({ entity }: { entity: DocCommentEntity }) => {
const [filterState, setFilterState] = useState<CommentFilterState>({
showResolvedComments: false,
onlyMyReplies: false,
onlyCurrentMode: false,
onlyCurrentMode: true,
});
const onFilterChange = useCallback(
@@ -39,7 +39,6 @@ export const commentList = style({
export const empty = style({
height: '100%',
flex: 1,
padding: 32,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
@@ -1,60 +0,0 @@
import { useConfirmModal, useLitPortalFactory } from '@affine/component';
import { getViewManager } from '@affine/core/blocksuite/manager/view';
import { FeatureFlagService } from '@affine/core/modules/feature-flag';
import { WorkspaceService } from '@affine/core/modules/workspace';
import { useFramework, useLiveData, useServices } from '@toeverything/infra';
import { useMemo } from 'react';
import { useEnableAI } from './use-enable-ai';
export const useAISpecs = () => {
const framework = useFramework();
const enableAI = useEnableAI();
const confirmModal = useConfirmModal();
const [reactToLit, _portals] = useLitPortalFactory();
const { workspaceService, featureFlagService } = useServices({
WorkspaceService,
FeatureFlagService,
});
const enablePDFEmbedPreview = useLiveData(
featureFlagService.flags.enable_pdf_embed_preview.$
);
const isCloud = workspaceService.workspace.flavour !== 'local';
const specs = useMemo(() => {
const manager = getViewManager()
.config.init()
.foundation(framework)
.ai(enableAI, framework)
.editorConfig(framework)
.editorView({
framework,
reactToLit,
confirmModal,
scope: 'workspace',
})
.cloud(framework, isCloud)
.pdf(enablePDFEmbedPreview, reactToLit)
.database(framework)
.linkedDoc(framework)
.paragraph(enableAI)
.mobile(framework)
.electron(framework)
.linkPreview(framework)
.codeBlockHtmlPreview(framework).value;
return manager.get('page');
}, [
framework,
reactToLit,
enableAI,
enablePDFEmbedPreview,
isCloud,
confirmModal,
]);
return specs;
};
@@ -1,15 +1,10 @@
import { observeResize, useConfirmModal } from '@affine/component';
import { CopilotClient } from '@affine/core/blocksuite/ai';
import {
AIChatContent,
type ChatContextValue,
} from '@affine/core/blocksuite/ai/components/ai-chat-content';
import type { ChatStatus } from '@affine/core/blocksuite/ai/components/ai-chat-messages';
import { AIChatContent } from '@affine/core/blocksuite/ai/components/ai-chat-content';
import { AIChatToolbar } from '@affine/core/blocksuite/ai/components/ai-chat-toolbar';
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 { useAISpecs } from '@affine/core/components/hooks/affine/use-ai-specs';
import {
EventSourceService,
FetchService,
@@ -27,6 +22,7 @@ import {
WorkbenchService,
} from '@affine/core/modules/workbench';
import { WorkspaceService } from '@affine/core/modules/workspace';
import { useI18n } from '@affine/i18n';
import { type Signal, signal } from '@preact/signals-core';
import { useFramework, useService } from '@toeverything/infra';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
@@ -52,6 +48,7 @@ function useCopilotClient() {
}
export const Component = () => {
const t = useI18n();
const framework = useFramework();
const [isBodyProvided, setIsBodyProvided] = useState(false);
const [isHeaderProvided, setIsHeaderProvided] = useState(false);
@@ -60,7 +57,6 @@ export const Component = () => {
const [currentSession, setCurrentSession] = useState<CopilotSession | null>(
null
);
const [status, setStatus] = useState<ChatStatus>('idle');
const [isTogglingPin, setIsTogglingPin] = useState(false);
const [isOpeningSession, setIsOpeningSession] = useState(false);
const chatContainerRef = useRef<HTMLDivElement>(null);
@@ -135,12 +131,7 @@ export const Component = () => {
[chatContent, chatTool, client, isOpeningSession, workspaceId]
);
const onContextChange = useCallback((context: Partial<ChatContextValue>) => {
setStatus(context.status ?? 'idle');
}, []);
const confirmModal = useConfirmModal();
const specs = useAISpecs();
// init or update ai-chat-content
useEffect(() => {
@@ -156,12 +147,10 @@ export const Component = () => {
content.session = currentSession;
content.workspaceId = workspaceId;
content.extensions = specs;
content.docDisplayConfig = docDisplayConfig;
content.searchMenuConfig = searchMenuConfig;
content.networkSearchConfig = networkSearchConfig;
content.reasoningConfig = reasoningConfig;
content.onContextChange = onContextChange;
content.affineFeatureFlagService = framework.get(FeatureFlagService);
content.affineWorkspaceDialogService = framework.get(
WorkspaceDialogService
@@ -193,8 +182,6 @@ export const Component = () => {
searchMenuConfig,
workspaceId,
confirmModal,
onContextChange,
specs,
]);
// init or update header ai-chat-toolbar
@@ -210,7 +197,6 @@ export const Component = () => {
tool.session = currentSession;
tool.workspaceId = workspaceId;
tool.status = status;
tool.docDisplayConfig = docDisplayConfig;
tool.onOpenSession = onOpenSession;
tool.notificationService = new NotificationServiceImpl(
@@ -253,7 +239,6 @@ export const Component = () => {
workspaceId,
confirmModal,
framework,
status,
]);
const onChatContainerRef = useCallback((node: HTMLDivElement) => {
@@ -281,7 +266,7 @@ export const Component = () => {
return (
<>
<ViewTitle title="AFFiNE Intelligence" />
<ViewTitle title={t['AFFiNE AI']()} />
<ViewIcon icon="ai" />
<ViewHeader>
<div className={styles.chatHeader}>
@@ -119,9 +119,7 @@ const DetailPageImpl = memo(function DetailPageImpl() {
const serverConfig = useLiveData(serverService.server.config$);
// comment may not be supported by the server
const enableComment =
workspace.flavour !== 'local' &&
serverConfig.features.includes(ServerFeature.Comment);
const enableComment = serverConfig.features.includes(ServerFeature.Comment);
useEffect(() => {
if (isActiveView) {
@@ -3,11 +3,11 @@ 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 { useAISpecs } from '@affine/core/components/hooks/affine/use-ai-specs';
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';
import { DocModeProvider } from '@blocksuite/affine/shared/services';
import { createSignalFromObservable } from '@blocksuite/affine/shared/utils';
@@ -55,7 +55,6 @@ export const EditorChatPanel = forwardRef(function EditorChatPanel(
playgroundConfig,
} = useAIChatConfig();
const confirmModal = useConfirmModal();
const specs = useAISpecs();
useEffect(() => {
if (!editor || !editor.host) return;
@@ -82,7 +81,9 @@ export const EditorChatPanel = forwardRef(function EditorChatPanel(
chatPanelRef.current.networkSearchConfig = networkSearchConfig;
chatPanelRef.current.reasoningConfig = reasoningConfig;
chatPanelRef.current.playgroundConfig = playgroundConfig;
chatPanelRef.current.extensions = specs;
chatPanelRef.current.extensions = editor.host.std
.get(ViewExtensionManagerIdentifier)
.get('preview-page');
chatPanelRef.current.affineFeatureFlagService =
framework.get(FeatureFlagService);
chatPanelRef.current.affineWorkspaceDialogService = framework.get(
@@ -126,7 +127,6 @@ export const EditorChatPanel = forwardRef(function EditorChatPanel(
reasoningConfig,
playgroundConfig,
confirmModal,
specs,
]);
const [autoResized, setAutoResized] = useState(false);
@@ -337,7 +337,6 @@ export class DocCommentStore extends Entity<{
}
const res = await graphql.gql({
timeout: 180_000,
query: uploadCommentAttachmentMutation,
variables: {
workspaceId: this.currentWorkspaceId,
@@ -33,14 +33,6 @@ export async function downloadBlob(blob: Blob, filename: string) {
URL.revokeObjectURL(blobUrl);
}
export function downloadFile(url: string, filename: string) {
const a = document.createElement('a');
a.href = url;
a.download = filename;
a.target = '_blank';
a.click();
}
export async function downloadResourceWithUrl(url: string, filename: string) {
// given input url may not have correct mime type
const blob = await resourceUrlToBlob(url);
+1 -1
View File
@@ -8239,7 +8239,7 @@ export function useAFFiNEI18N(): {
*/
["com.affine.comment.comments"](): string;
/**
* `No comments yet, select content to add comment to`
* `No comments yet`
*/
["com.affine.comment.no-comments"](): string;
/**
+1 -1
View File
@@ -2067,7 +2067,7 @@
"com.affine.migration-all-docs-notification.error": "Migration failed: {{errorMessage}}",
"com.affine.migration-all-docs-notification.button": "Migrate data",
"com.affine.comment.comments": "Comments",
"com.affine.comment.no-comments": "No comments yet, select content to add comment to",
"com.affine.comment.no-comments": "No comments yet",
"com.affine.comment.delete.confirm.title": "Delete the thread?",
"com.affine.comment.delete.confirm.description": "All comments will also be deleted, and this action cannot be undone.",
"com.affine.comment.reply.delete.confirm.title": "Delete this reply?",
+1 -31
View File
@@ -207,16 +207,6 @@ type CommentEvents =
| 'resolveComment';
// END SECTION
// SECTION: apply model
type ApplyModelEvents =
| 'acceptAll'
| 'rejectAll'
| 'accept'
| 'reject'
| 'apply'
| 'copy';
// END SECTION
type UserEvents =
| GeneralEvents
| AppEvents
@@ -241,8 +231,7 @@ type UserEvents =
| IntegrationEvents
| MeetingEvents
| MentionEvents
| WorkspaceEmbeddingEvents
| ApplyModelEvents;
| WorkspaceEmbeddingEvents;
interface PageDivision {
[page: string]: {
@@ -575,15 +564,6 @@ interface PageEvents extends PageDivision {
$: ['createDoc'];
};
};
applyModel: {
widget: {
page: ['acceptAll', 'rejectAll'];
block: ['accept', 'reject'];
};
chat: {
$: ['apply', 'accept', 'reject', 'copy'];
};
};
}
type OrganizeItemType = 'doc' | 'folder' | 'collection' | 'tag' | 'favorite';
@@ -655,13 +635,6 @@ type RecordingEventArgs = {
option?: 'Auto transcribing' | 'handle transcribing' | 'on' | 'off';
};
type ApplyModelArgs = {
/* User's complete instruction */
instruction?: string;
/* Split individual semantic change requests */
operation?: string;
};
export type EventArgs = {
createWorkspace: { flavour: string };
signIn: AuthArgs;
@@ -856,9 +829,6 @@ export type EventArgs = {
};
editComment: { type: 'root' | 'node' };
deleteComment: { type: 'root' | 'node' };
accept: ApplyModelArgs;
reject: ApplyModelArgs;
apply: ApplyModelArgs;
};
// for type checking
-1
View File
@@ -99,7 +99,6 @@ update_ios_marketing_version() {
}
new_version=$1
ios_new_version=${IOS_APP_VERSION:-$new_version}
update_app_version_in_helm_charts ".github/helm/affine/Chart.yaml" "$new_version"
update_app_version_in_helm_charts ".github/helm/affine/charts/graphql/Chart.yaml" "$new_version"