refactor: move ai-item components to frontend core (#10369)

### TL;DR

Relocated AI item components from BlockSuite to the frontend codebase and updated related imports.

### What changed?

- Moved AI item components from `blocksuite/affine/components/src/ai-item` to `packages/frontend/core/src/blocksuite/presets/ai/_common/components/ai-item`
- Updated all imports referencing the old AI item component location to point to the new location
- Removed AI item exports from BlockSuite's package.json and effects registration
- Added AI item effects registration to frontend presets

### How to test?

1. Verify AI functionality works as expected in:
   - Chat panels
   - AI toolbars
   - Edgeless copilot
   - Slash menu
2. Confirm no AI-related console errors appear
3. Test error handling scenarios (unauthorized, payment required, network errors)

### Why make this change?

This change consolidates AI-related components into the frontend codebase where they are primarily used, rather than keeping them in BlockSuite. This improves code organization by placing components closer to their implementation and usage, while reducing unnecessary coupling between packages.
This commit is contained in:
Saul-Mirone
2025-02-22 17:03:07 +00:00
parent 3ff6176306
commit f8cabe8bb1
38 changed files with 85 additions and 94 deletions
@@ -40,7 +40,6 @@
},
"exports": {
".": "./src/index.ts",
"./ai-item": "./src/ai-item/index.ts",
"./color-picker": "./src/color-picker/index.ts",
"./icons": "./src/icons/index.ts",
"./peek": "./src/peek/index.ts",
-2
View File
@@ -16,7 +16,6 @@ import { effects as blockRootEffects } from '@blocksuite/affine-block-root/effec
import { effects as blockSurfaceEffects } from '@blocksuite/affine-block-surface/effects';
import { effects as blockSurfaceRefEffects } from '@blocksuite/affine-block-surface-ref/effects';
import { effects as blockTableEffects } from '@blocksuite/affine-block-table/effects';
import { effects as componentAiItemEffects } from '@blocksuite/affine-components/ai-item';
import { BlockSelection } from '@blocksuite/affine-components/block-selection';
import { BlockZeroWidth } from '@blocksuite/affine-components/block-zero-width';
import { effects as componentCaptionEffects } from '@blocksuite/affine-components/caption';
@@ -82,7 +81,6 @@ export function effects() {
componentToolbarEffects();
componentDropIndicatorEffects();
componentToggleButtonEffects();
componentAiItemEffects();
componentColorPickerEffects();
componentEmbedCardModalEffects();
componentDocTitleEffects();
-11
View File
@@ -19,17 +19,6 @@ export * from '@blocksuite/affine-block-root';
export * from '@blocksuite/affine-block-surface';
export * from '@blocksuite/affine-block-surface-ref';
export * from '@blocksuite/affine-block-table';
export {
type AIError,
AIErrorType,
type AIItemConfig,
type AIItemGroupConfig,
AIItemList,
type AISubItemConfig,
GeneralNetworkError,
PaymentRequiredError,
UnauthorizedError,
} from '@blocksuite/affine-components/ai-item';
export {
menu,
type MenuOptions,
@@ -2,15 +2,15 @@ import {
EditorHost,
PropTypes,
requiredProperties,
} from '@blocksuite/block-std';
import { WithDisposable } from '@blocksuite/global/utils';
} from '@blocksuite/affine/block-std';
import { createLitPortal } from '@blocksuite/affine/blocks';
import { WithDisposable } from '@blocksuite/affine/global/utils';
import { flip, offset } from '@floating-ui/dom';
import { baseTheme } from '@toeverything/theme';
import { css, html, LitElement, nothing, unsafeCSS } from 'lit';
import { property } from 'lit/decorators.js';
import { repeat } from 'lit/directives/repeat.js';
import { createLitPortal } from '../portal';
import type { AIItem } from './ai-item';
import { SUBMENU_OFFSET_CROSS_AXIS, SUBMENU_OFFSET_MAIN_AXIS } from './const';
import type { AIItemConfig, AIItemGroupConfig } from './types';
@@ -2,12 +2,12 @@ import {
EditorHost,
PropTypes,
requiredProperties,
} from '@blocksuite/block-std';
import { WithDisposable } from '@blocksuite/global/utils';
} from '@blocksuite/affine/block-std';
import { ArrowRightIcon, EnterIcon } from '@blocksuite/affine/blocks';
import { WithDisposable } from '@blocksuite/affine/global/utils';
import { css, html, LitElement, nothing } from 'lit';
import { property, query } from 'lit/decorators.js';
import { ArrowRightIcon, EnterIcon } from '../icons';
import { menuItemStyles } from './styles';
import type { AIItemConfig } from './types';
@@ -2,13 +2,13 @@ import {
EditorHost,
PropTypes,
requiredProperties,
} from '@blocksuite/block-std';
import { WithDisposable } from '@blocksuite/global/utils';
} from '@blocksuite/affine/block-std';
import { EnterIcon } from '@blocksuite/affine/blocks';
import { WithDisposable } from '@blocksuite/affine/global/utils';
import { baseTheme } from '@toeverything/theme';
import { css, html, LitElement, nothing, unsafeCSS } from 'lit';
import { property } from 'lit/decorators.js';
import { EnterIcon } from '../icons';
import { menuItemStyles } from './styles';
import type { AIItemConfig, AISubItemConfig } from './types';
@@ -1,5 +1,9 @@
import type { DocMode } from '@blocksuite/affine-model';
import type { Chain, EditorHost, InitCommandCtx } from '@blocksuite/block-std';
import type {
Chain,
EditorHost,
InitCommandCtx,
} from '@blocksuite/affine/block-std';
import type { DocMode } from '@blocksuite/affine/blocks';
import type { TemplateResult } from 'lit';
export interface AIItemGroupConfig {
@@ -1,11 +1,7 @@
import './ask-ai-panel';
import { type EditorHost } from '@blocksuite/affine/block-std';
import {
type AIItemGroupConfig,
createLitPortal,
HoverController,
} from '@blocksuite/affine/blocks';
import { createLitPortal, HoverController } from '@blocksuite/affine/blocks';
import { WithDisposable } from '@blocksuite/affine/global/utils';
import { flip, offset } from '@floating-ui/dom';
import { css, html, LitElement, nothing } from 'lit';
@@ -13,6 +9,7 @@ import { property, query } from 'lit/decorators.js';
import { ref } from 'lit/directives/ref.js';
import { styleMap } from 'lit/directives/style-map.js';
import type { AIItemGroupConfig } from './ai-item/types';
import type { ButtonSize } from './ask-ai-icon';
type toggleType = 'hover' | 'click';
@@ -1,15 +1,13 @@
import { type EditorHost } from '@blocksuite/affine/block-std';
import {
type AIItemGroupConfig,
DocModeProvider,
scrollbarStyle,
} from '@blocksuite/affine/blocks';
import { DocModeProvider, scrollbarStyle } from '@blocksuite/affine/blocks';
import { WithDisposable } from '@blocksuite/affine/global/utils';
import { cssVar } from '@toeverything/theme';
import { css, html, LitElement, unsafeCSS } from 'lit';
import { property } from 'lit/decorators.js';
import { styleMap } from 'lit/directives/style-map.js';
import type { AIItemGroupConfig } from './ai-item/types';
export class AskAIPanel extends WithDisposable(LitElement) {
static override styles = css`
:host {
@@ -3,10 +3,7 @@ import {
type EditorHost,
TextSelection,
} from '@blocksuite/affine/block-std';
import {
type AIItemGroupConfig,
createLitPortal,
} from '@blocksuite/affine/blocks';
import { createLitPortal } from '@blocksuite/affine/blocks';
import { WithDisposable } from '@blocksuite/affine/global/utils';
import { flip, offset } from '@floating-ui/dom';
import { css, html, LitElement } from 'lit';
@@ -16,6 +13,7 @@ import { AIProvider } from '../../provider';
import { getAIPanelWidget } from '../../utils/ai-widgets';
import { extractSelectedContent } from '../../utils/extract';
import type { AffineAIPanelWidgetConfig } from '../../widgets/ai-panel/type';
import type { AIItemGroupConfig } from './ai-item/types';
export class AskAIToolbarButton extends WithDisposable(LitElement) {
static override styles = css`
@@ -1,7 +1,5 @@
import type { Chain, InitCommandCtx } from '@blocksuite/affine/block-std';
import {
type AIItemGroupConfig,
type AISubItemConfig,
CodeBlockModel,
getSelectedModelsCommand,
ImageBlockModel,
@@ -19,6 +17,10 @@ import {
} from '../actions/types';
import { AIProvider } from '../provider';
import { getAIPanelWidget } from '../utils/ai-widgets';
import type {
AIItemGroupConfig,
AISubItemConfig,
} from './components/ai-item/types';
import {
AIDoneIcon,
AIImageIcon,
@@ -1,7 +1,5 @@
import { type EditorHost, TextSelection } from '@blocksuite/affine/block-std';
import {
type AIError,
type AIItemGroupConfig,
AIStarIconWithAnimation,
createLitPortal,
} from '@blocksuite/affine/blocks';
@@ -9,6 +7,10 @@ import { assertExists } from '@blocksuite/affine/global/utils';
import { flip, offset } from '@floating-ui/dom';
import { html, type TemplateResult } from 'lit';
import type {
AIError,
AIItemGroupConfig,
} from '../_common/components/ai-item/types';
import {
buildCopyConfig,
buildErrorConfig,
@@ -3,7 +3,6 @@ import {
GfxControllerIdentifier,
type GfxModel,
} from '@blocksuite/affine/block-std/gfx';
import type { AIError } from '@blocksuite/affine/blocks';
import {
CodeBlockModel,
EdgelessTextBlockModel,
@@ -21,6 +20,7 @@ import type { TemplateResult } from 'lit';
import { AIChatBlockModel } from '../../../blocks';
import { getContentFromSlice } from '../../_common';
import type { AIError } from '../_common/components/ai-item/types';
import { AIProvider } from '../provider';
import { reportResponse } from '../utils/action-reporter';
import { getAIPanelWidget } from '../utils/ai-widgets';
@@ -1,7 +1,6 @@
import type { EditorHost } from '@blocksuite/affine/block-std';
import { GfxControllerIdentifier } from '@blocksuite/affine/block-std/gfx';
import type {
AIItemConfig,
EdgelessElementToolbarWidget,
MindmapElementModel,
ShapeElementModel,
@@ -28,6 +27,7 @@ import { html, type TemplateResult } from 'lit';
import { styleMap } from 'lit/directives/style-map.js';
import { insertFromMarkdown } from '../../_common';
import type { AIItemConfig } from '../_common/components/ai-item/types';
import { AIPenIcon, ChatWithAIIcon } from '../_common/icons';
import { AIProvider } from '../provider';
import { reportResponse } from '../utils/action-reporter';
@@ -2,7 +2,6 @@ import { AINetworkSearchService } from '@affine/core/modules/ai-button/services/
import type { EditorHost } from '@blocksuite/affine/block-std';
import { GfxControllerIdentifier } from '@blocksuite/affine/block-std/gfx';
import {
type AIItemConfig,
ImageBlockModel,
isInsideEdgelessEditor,
matchModels,
@@ -14,6 +13,7 @@ import type { FrameworkProvider } from '@toeverything/infra';
import type { TemplateResult } from 'lit';
import { createTextRenderer, insertFromMarkdown } from '../_common';
import type { AIItemConfig } from './_common/components/ai-item/types';
import {
AIPenIcon,
AIStarIconWithAnimation,
@@ -1,6 +1,7 @@
import type { AIError } from '@blocksuite/affine/blocks';
import type { Signal } from '@preact/signals-core';
import type { AIError } from '../_common/components/ai-item/types';
export type ChatMessage = {
id: string;
content: string;
@@ -1,16 +1,13 @@
import { stopPropagation } from '@affine/core/utils';
import type { EditorHost } from '@blocksuite/affine/block-std';
import {
type AIError,
openFileOrFiles,
unsafeCSSVarV2,
} from '@blocksuite/affine/blocks';
import { openFileOrFiles, unsafeCSSVarV2 } from '@blocksuite/affine/blocks';
import { SignalWatcher, WithDisposable } from '@blocksuite/affine/global/utils';
import { ImageIcon, PublishIcon } from '@blocksuite/icons/lit';
import { css, html, LitElement, nothing } from 'lit';
import { property, query, state } from 'lit/decorators.js';
import { repeat } from 'lit/directives/repeat.js';
import type { AIError } from '../_common/components/ai-item/types';
import {
ChatAbortIcon,
ChatClearIcon,
@@ -1,13 +1,10 @@
import type { EditorHost } from '@blocksuite/affine/block-std';
import { ShadowlessElement } from '@blocksuite/affine/block-std';
import {
type AIError,
DocModeProvider,
FeatureFlagService,
isInsidePageEditor,
PaymentRequiredError,
type SpecBuilder,
UnauthorizedError,
} from '@blocksuite/affine/blocks';
import { WithDisposable } from '@blocksuite/affine/global/utils';
import type { BaseSelection } from '@blocksuite/affine/store';
@@ -21,6 +18,11 @@ import {
EdgelessEditorActions,
PageEditorActions,
} from '../_common/chat-actions-handle';
import {
type AIError,
PaymentRequiredError,
UnauthorizedError,
} from '../_common/components/ai-item/types';
import { AffineAvatarIcon, AffineIcon, DownArrowIcon } from '../_common/icons';
import { AIChatErrorRenderer } from '../messages/error';
import { AIProvider } from '../provider';
@@ -1,5 +1,4 @@
import {
type AIItemGroupConfig,
AIStarIconWithAnimation,
MindmapElementModel,
ShapeElementModel,
@@ -7,6 +6,7 @@ import {
TextElementModel,
} from '@blocksuite/affine/blocks';
import type { AIItemGroupConfig } from '../../_common/components/ai-item/types';
import {
AIExpandMindMapIcon,
AIImageIcon,
@@ -1,5 +1,4 @@
import type {
AIItemGroupConfig,
DocMode,
EdgelessElementToolbarWidget,
EdgelessRootBlockComponent,
@@ -7,6 +6,7 @@ import type {
import { noop } from '@blocksuite/affine/global/utils';
import { html } from 'lit';
import type { AIItemGroupConfig } from '../../_common/components/ai-item/types';
import { AIProvider } from '../../provider';
import { getAIPanelWidget } from '../../utils/ai-widgets';
import { getEdgelessCopilotWidget } from '../../utils/edgeless';
@@ -4,7 +4,6 @@ import {
type AffineSlashMenuItem,
AffineSlashMenuWidget,
type AffineSlashSubMenu,
type AIItemConfig,
AIStarIcon,
DocModeProvider,
} from '@blocksuite/affine/blocks';
@@ -12,6 +11,7 @@ import { assertExists } from '@blocksuite/affine/global/utils';
import { MoreHorizontalIcon } from '@blocksuite/icons/lit';
import { html } from 'lit';
import type { AIItemConfig } from '../../_common/components/ai-item/types';
import { pageAIGroups } from '../../_common/config';
import { handleInlineAskAIAction } from '../../actions/doc-handler';
import { AIProvider } from '../../provider';
@@ -1,11 +1,5 @@
import { type EditorHost } from '@blocksuite/affine/block-std';
import {
type AIError,
PaymentRequiredError,
scrollbarStyle,
UnauthorizedError,
unsafeCSSVarV2,
} from '@blocksuite/affine/blocks';
import { scrollbarStyle, unsafeCSSVarV2 } from '@blocksuite/affine/blocks';
import { SignalWatcher, WithDisposable } from '@blocksuite/affine/global/utils';
import { ToggleDownIcon } from '@blocksuite/icons/lit';
import { signal } from '@preact/signals-core';
@@ -13,6 +7,11 @@ import { baseTheme } from '@toeverything/theme';
import { css, html, LitElement, nothing, unsafeCSS } from 'lit';
import { property } from 'lit/decorators.js';
import {
type AIError,
PaymentRequiredError,
UnauthorizedError,
} from '../_common/components/ai-item/types';
import { ErrorTipIcon } from '../_common/icons';
import { AIProvider } from '../provider';
@@ -1,9 +1,5 @@
import type { EditorHost } from '@blocksuite/affine/block-std';
import {
type AIError,
openFileOrFiles,
unsafeCSSVarV2,
} from '@blocksuite/affine/blocks';
import { openFileOrFiles, unsafeCSSVarV2 } from '@blocksuite/affine/blocks';
import { SignalWatcher } from '@blocksuite/affine/global/utils';
import { ImageIcon, PublishIcon } from '@blocksuite/icons/lit';
import { css, html, LitElement, nothing } from 'lit';
@@ -11,6 +7,7 @@ import { property, query, state } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import type { ChatMessage } from '../../../blocks';
import type { AIError } from '../_common/components/ai-item/types';
import { ChatAbortIcon, ChatClearIcon, ChatSendIcon } from '../_common/icons';
import type { AINetworkSearchConfig } from '../chat-panel/chat-config';
import {
@@ -1,6 +1,5 @@
import { type EditorHost } from '@blocksuite/affine/block-std';
import type { EditorHost } from '@blocksuite/affine/block-std';
import {
type AIError,
CanvasElementType,
ConnectorMode,
DocModeProvider,
@@ -26,6 +25,7 @@ import {
constructUserInfoWithMessages,
queryHistoryMessages,
} from '../_common/chat-actions-handle';
import type { AIError } from '../_common/components/ai-item/types';
import { SmallHintIcon } from '../_common/icons';
import type { AINetworkSearchConfig } from '../chat-panel/chat-config';
import { AIChatErrorRenderer } from '../messages/error';
@@ -1,6 +1,5 @@
import type { AIError } from '@blocksuite/affine/blocks';
import type { ChatMessage } from '../../../blocks';
import type { AIError } from '../_common/components/ai-item/types';
export type ChatStatus =
| 'success'
@@ -1,11 +1,11 @@
import type { EditorHost } from '@blocksuite/affine/block-std';
import {
PaymentRequiredError,
UnauthorizedError,
} from '@blocksuite/affine/blocks';
import { Slot } from '@blocksuite/affine/global/utils';
import { captureException } from '@sentry/react';
import {
PaymentRequiredError,
UnauthorizedError,
} from './_common/components/ai-item/types';
import type { ChatContextValue } from './chat-panel/chat-context';
export interface AIUserInfo {
@@ -4,7 +4,6 @@ import {
AFFINE_FORMAT_BAR_WIDGET,
AFFINE_VIEWPORT_OVERLAY_WIDGET,
type AffineViewportOverlayWidget,
type AIError,
DocModeProvider,
getPageRootByElement,
NotificationProvider,
@@ -27,6 +26,7 @@ import { css, html, nothing, type PropertyValues } from 'lit';
import { property, query } from 'lit/decorators.js';
import { choose } from 'lit/directives/choose.js';
import type { AIError } from '../../_common/components/ai-item/types.js';
import type { AIPanelGenerating } from './components/index.js';
import type { AffineAIPanelState, AffineAIPanelWidgetConfig } from './type.js';
@@ -1,11 +1,14 @@
import type { EditorHost } from '@blocksuite/affine/block-std';
import { AIErrorType, type AIItemGroupConfig } from '@blocksuite/affine/blocks';
import { WithDisposable } from '@blocksuite/affine/global/utils';
import { baseTheme } from '@toeverything/theme';
import { css, html, LitElement, nothing, unsafeCSS } from 'lit';
import { property } from 'lit/decorators.js';
import { choose } from 'lit/directives/choose.js';
import {
AIErrorType,
type AIItemGroupConfig,
} from '../../../../_common/components/ai-item/types.js';
import type { AIPanelErrorConfig, CopyConfig } from '../../type.js';
import { filterAIItemGroup } from '../../utils.js';
@@ -1,7 +1,11 @@
import type { AIError, AIItemGroupConfig } from '@blocksuite/affine/blocks';
import type { Signal } from '@preact/signals-core';
import type { nothing, TemplateResult } from 'lit';
import type {
AIError,
AIItemGroupConfig,
} from '../../_common/components/ai-item/types';
export interface CopyConfig {
allowed: boolean;
onCopy: () => boolean | Promise<boolean>;
@@ -1,7 +1,8 @@
import type { EditorHost } from '@blocksuite/affine/block-std';
import type { AIItemGroupConfig } from '@blocksuite/affine/blocks';
import { isInsidePageEditor } from '@blocksuite/affine/blocks';
import type { AIItemGroupConfig } from '../../_common/components/ai-item/types';
export function filterAIItemGroup(
host: EditorHost,
configs: AIItemGroupConfig[]
@@ -1,10 +1,11 @@
import type { EditorHost } from '@blocksuite/affine/block-std';
import type { AIItemGroupConfig } from '@blocksuite/affine/blocks';
import { on, scrollbarStyle, stopPropagation } from '@blocksuite/affine/blocks';
import { WithDisposable } from '@blocksuite/affine/global/utils';
import { css, html, LitElement, nothing } from 'lit';
import { property } from 'lit/decorators.js';
import type { AIItemGroupConfig } from '../../_common/components/ai-item/types';
export class EdgelessCopilotPanel extends WithDisposable(LitElement) {
static override styles = css`
:host {
@@ -3,12 +3,12 @@ import {
GfxControllerIdentifier,
isGfxGroupCompatibleModel,
} from '@blocksuite/affine/block-std/gfx';
import type { AIItemGroupConfig } from '@blocksuite/affine/blocks';
import { AIStarIcon, sortEdgelessElements } from '@blocksuite/affine/blocks';
import { WithDisposable } from '@blocksuite/affine/global/utils';
import { css, html, LitElement } from 'lit';
import { property } from 'lit/decorators.js';
import type { AIItemGroupConfig } from '../../_common/components/ai-item/types';
import type { CopilotTool } from '../../tool/copilot-tool';
export class EdgelessCopilotToolbarEntry extends WithDisposable(LitElement) {
@@ -1,9 +1,6 @@
import { WidgetComponent } from '@blocksuite/affine/block-std';
import { GfxControllerIdentifier } from '@blocksuite/affine/block-std/gfx';
import type {
AIItemGroupConfig,
RootBlockModel,
} from '@blocksuite/affine/blocks';
import type { RootBlockModel } from '@blocksuite/affine/blocks';
import {
EdgelessLegacySlotIdentifier,
MOUSE_BUTTON,
@@ -26,6 +23,7 @@ import { css, html, nothing } from 'lit';
import { query, state } from 'lit/decorators.js';
import { styleMap } from 'lit/directives/style-map.js';
import type { AIItemGroupConfig } from '../../_common/components/ai-item/types.js';
import {
AFFINE_AI_PANEL_WIDGET,
AffineAIPanelWidget,
@@ -11,6 +11,7 @@ import {
import { ImagePlaceholder } from '../blocks/ai-chat-block/components/image-placeholder';
import { UserInfo } from '../blocks/ai-chat-block/components/user-info';
import { TextRenderer } from './_common/components/text-renderer';
import { effects as componentAiItemEffects } from './ai/_common/components/ai-item';
import { AskAIButton } from './ai/_common/components/ask-ai-button';
import { AskAIIcon } from './ai/_common/components/ask-ai-icon';
import { AskAIPanel } from './ai/_common/components/ask-ai-panel';
@@ -61,9 +62,10 @@ import {
} from './ai/widgets/edgeless-copilot';
import { EdgelessCopilotPanel } from './ai/widgets/edgeless-copilot-panel';
import { EdgelessCopilotToolbarEntry } from './ai/widgets/edgeless-copilot-panel/toolbar-entry';
export function registerBlocksuitePresetsCustomComponents() {
registerMiniMindmapBlocks();
componentAiItemEffects();
customElements.define('ask-ai-icon', AskAIIcon);
customElements.define('ask-ai-button', AskAIButton);
customElements.define('ask-ai-toolbar-button', AskAIToolbarButton);
@@ -1,3 +1,8 @@
import {
GeneralNetworkError,
PaymentRequiredError,
UnauthorizedError,
} from '@affine/core/blocksuite/presets/ai/_common/components/ai-item/types';
import { showAILoginRequiredAtom } from '@affine/core/components/affine/auth/ai-login-required';
import {
addContextDocMutation,
@@ -20,11 +25,6 @@ import {
updateCopilotSessionMutation,
UserFriendlyError,
} from '@affine/graphql';
import {
GeneralNetworkError,
PaymentRequiredError,
UnauthorizedError,
} from '@blocksuite/affine/blocks';
import { getCurrentStore } from '@toeverything/infra';
type OptionsField<T extends GraphQLQuery> =