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

View File

@@ -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",

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();

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,

View File

@@ -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';

View File

@@ -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';

View File

@@ -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';

View File

@@ -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 {

View File

@@ -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';

View File

@@ -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 {

View File

@@ -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`

View File

@@ -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,

View File

@@ -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,

View File

@@ -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';

View File

@@ -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';

View File

@@ -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,

View File

@@ -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;

View File

@@ -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,

View File

@@ -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';

View File

@@ -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,

View File

@@ -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';

View File

@@ -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';

View File

@@ -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';

View File

@@ -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 {

View File

@@ -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';

View File

@@ -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'

View File

@@ -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 {

View File

@@ -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';

View File

@@ -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';

View File

@@ -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>;

View File

@@ -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[]

View File

@@ -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 {

View File

@@ -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) {

View File

@@ -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,

View File

@@ -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);

View File

@@ -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> =