mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-26 10:45:57 +08:00
refactor(editor): add cache extension for link preview service (#12196)
Closes: [BS-2578](https://linear.app/affine-design/issue/BS-2578/优化-footnote-预览的逻辑:支持缓存结果,避免重复-loading) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Introduced a link preview caching mechanism, enabling faster and more efficient reuse of link preview data across the app. - Added a feature flag for enabling or disabling link preview cache, configurable through workspace experimental settings. - Enhanced localization with new entries describing the link preview cache feature. - **Improvements** - Updated link preview service architecture for better extensibility and maintainability. - Improved integration of feature flags throughout chat and rendering components. - **Bug Fixes** - Fixed tooltip formatting for footnote URLs. - **Chores** - Updated dependencies and localization completeness tracking. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -1,9 +1,11 @@
|
||||
import { Peekable } from '@blocksuite/affine/components/peek';
|
||||
import { ViewExtensionManagerIdentifier } from '@blocksuite/affine/ext-loader';
|
||||
import { BlockComponent } from '@blocksuite/affine/std';
|
||||
import { computed } from '@preact/signals-core';
|
||||
import { html } from 'lit';
|
||||
|
||||
import { ChatMessagesSchema } from '../../components/ai-chat-messages';
|
||||
import type { TextRendererOptions } from '../../components/text-renderer';
|
||||
import { ChatWithAIIcon } from './components/icon';
|
||||
import { type AIChatBlockModel } from './model';
|
||||
import { AIChatBlockStyles } from './styles';
|
||||
@@ -17,6 +19,8 @@ import { AIChatBlockStyles } from './styles';
|
||||
export class AIChatBlockComponent extends BlockComponent<AIChatBlockModel> {
|
||||
static override styles = AIChatBlockStyles;
|
||||
|
||||
private _textRendererOptions: TextRendererOptions = {};
|
||||
|
||||
// Deserialize messages from JSON string and verify the type using zod
|
||||
private readonly _deserializeChatMessages = computed(() => {
|
||||
const messages = this.model.props.messages$.value;
|
||||
@@ -32,18 +36,23 @@ export class AIChatBlockComponent extends BlockComponent<AIChatBlockModel> {
|
||||
}
|
||||
});
|
||||
|
||||
override connectedCallback() {
|
||||
super.connectedCallback();
|
||||
this._textRendererOptions = {
|
||||
customHeading: true,
|
||||
extensions: this.previewExtensions,
|
||||
};
|
||||
}
|
||||
|
||||
override renderBlock() {
|
||||
const messages = this._deserializeChatMessages.value.slice(-2);
|
||||
const textRendererOptions = {
|
||||
customHeading: true,
|
||||
};
|
||||
|
||||
return html`<div class="affine-ai-chat-block-container">
|
||||
<div class="ai-chat-messages-container">
|
||||
<ai-chat-messages
|
||||
.host=${this.host}
|
||||
.messages=${messages}
|
||||
.textRendererOptions=${textRendererOptions}
|
||||
.textRendererOptions=${this._textRendererOptions}
|
||||
.withMask=${true}
|
||||
></ai-chat-messages>
|
||||
</div>
|
||||
@@ -52,6 +61,10 @@ export class AIChatBlockComponent extends BlockComponent<AIChatBlockModel> {
|
||||
</div>
|
||||
</div> `;
|
||||
}
|
||||
|
||||
get previewExtensions() {
|
||||
return this.std.get(ViewExtensionManagerIdentifier).get('preview-page');
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
||||
@@ -158,6 +158,9 @@ export class ChatPanelMessages extends WithDisposable(ShadowlessElement) {
|
||||
@property({ attribute: false })
|
||||
accessor extensions!: ExtensionType[];
|
||||
|
||||
@property({ attribute: false })
|
||||
accessor affineFeatureFlagService!: FeatureFlagService;
|
||||
|
||||
@query('.chat-panel-messages-container')
|
||||
accessor messagesContainer: HTMLDivElement | null = null;
|
||||
|
||||
@@ -271,6 +274,7 @@ export class ChatPanelMessages extends WithDisposable(ShadowlessElement) {
|
||||
.status=${isLast ? status : 'idle'}
|
||||
.error=${isLast ? error : null}
|
||||
.extensions=${this.extensions}
|
||||
.affineFeatureFlagService=${this.affineFeatureFlagService}
|
||||
.getSessionId=${this.getSessionId}
|
||||
.retry=${() => this.retry()}
|
||||
></chat-message-assistant>`;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { FeatureFlagService } from '@affine/core/modules/feature-flag';
|
||||
import { WithDisposable } from '@blocksuite/affine/global/lit';
|
||||
import type { EditorHost } from '@blocksuite/affine/std';
|
||||
import { ShadowlessElement } from '@blocksuite/affine/std';
|
||||
@@ -20,11 +21,15 @@ export class ChatContentRichText extends WithDisposable(ShadowlessElement) {
|
||||
@property({ attribute: false })
|
||||
accessor extensions!: ExtensionType[];
|
||||
|
||||
@property({ attribute: false })
|
||||
accessor affineFeatureFlagService!: FeatureFlagService;
|
||||
|
||||
protected override render() {
|
||||
const { text, host } = this;
|
||||
return html`${createTextRenderer(host, {
|
||||
customHeading: true,
|
||||
extensions: this.extensions,
|
||||
affineFeatureFlagService: this.affineFeatureFlagService,
|
||||
})(text, this.state)}`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import './chat-panel-messages';
|
||||
|
||||
import type { FeatureFlagService } from '@affine/core/modules/feature-flag';
|
||||
import type { ContextEmbedStatus } from '@affine/graphql';
|
||||
import { SignalWatcher, WithDisposable } from '@blocksuite/affine/global/lit';
|
||||
import type { EditorHost } from '@blocksuite/affine/std';
|
||||
@@ -205,6 +206,9 @@ export class ChatPanel extends SignalWatcher(
|
||||
@property({ attribute: false })
|
||||
accessor extensions!: ExtensionType[];
|
||||
|
||||
@property({ attribute: false })
|
||||
accessor affineFeatureFlagService!: FeatureFlagService;
|
||||
|
||||
@state()
|
||||
accessor isLoading = false;
|
||||
|
||||
@@ -399,6 +403,7 @@ export class ChatPanel extends SignalWatcher(
|
||||
.host=${this.host}
|
||||
.isLoading=${this.isLoading}
|
||||
.extensions=${this.extensions}
|
||||
.affineFeatureFlagService=${this.affineFeatureFlagService}
|
||||
></chat-panel-messages>
|
||||
<ai-chat-composer
|
||||
.host=${this.host}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import '../content/assistant-avatar';
|
||||
import '../content/rich-text';
|
||||
|
||||
import type { FeatureFlagService } from '@affine/core/modules/feature-flag';
|
||||
import { WithDisposable } from '@blocksuite/affine/global/lit';
|
||||
import { isInsidePageEditor } from '@blocksuite/affine/shared/utils';
|
||||
import type { EditorHost } from '@blocksuite/affine/std';
|
||||
@@ -48,6 +49,9 @@ export class ChatMessageAssistant extends WithDisposable(ShadowlessElement) {
|
||||
@property({ attribute: false })
|
||||
accessor extensions!: ExtensionType[];
|
||||
|
||||
@property({ attribute: false })
|
||||
accessor affineFeatureFlagService!: FeatureFlagService;
|
||||
|
||||
@property({ attribute: false })
|
||||
accessor getSessionId!: () => Promise<string | undefined>;
|
||||
|
||||
@@ -93,6 +97,7 @@ export class ChatMessageAssistant extends WithDisposable(ShadowlessElement) {
|
||||
.text=${item.content}
|
||||
.state=${state}
|
||||
.extensions=${this.extensions}
|
||||
.affineFeatureFlagService=${this.affineFeatureFlagService}
|
||||
></chat-content-rich-text>
|
||||
${shouldRenderError ? AIChatErrorRenderer(host, error) : nothing}
|
||||
${this.renderEditorActions()}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { createReactComponentFromLit } from '@affine/component';
|
||||
import type { FeatureFlagService } from '@affine/core/modules/feature-flag';
|
||||
import { Container, type ServiceProvider } from '@blocksuite/affine/global/di';
|
||||
import { WithDisposable } from '@blocksuite/affine/global/lit';
|
||||
import {
|
||||
@@ -6,10 +7,7 @@ import {
|
||||
defaultImageProxyMiddleware,
|
||||
ImageProxyService,
|
||||
} from '@blocksuite/affine/shared/adapters';
|
||||
import {
|
||||
LinkPreviewerService,
|
||||
ThemeProvider,
|
||||
} from '@blocksuite/affine/shared/services';
|
||||
import { ThemeProvider } from '@blocksuite/affine/shared/services';
|
||||
import { unsafeCSSVarV2 } from '@blocksuite/affine/shared/theme';
|
||||
import {
|
||||
BlockStdScope,
|
||||
@@ -104,6 +102,7 @@ export type TextRendererOptions = {
|
||||
extensions?: ExtensionType[];
|
||||
additionalMiddlewares?: TransformerMiddleware[];
|
||||
testId?: string;
|
||||
affineFeatureFlagService?: FeatureFlagService;
|
||||
};
|
||||
|
||||
// todo: refactor it for more general purpose usage instead of AI only?
|
||||
@@ -266,7 +265,14 @@ export class TextRenderer extends WithDisposable(ShadowlessElement) {
|
||||
codeBlockWrapMiddleware(true),
|
||||
...(this.options.additionalMiddlewares ?? []),
|
||||
];
|
||||
markDownToDoc(provider, schema, latestAnswer, middlewares)
|
||||
const affineFeatureFlagService = this.options.affineFeatureFlagService;
|
||||
markDownToDoc(
|
||||
provider,
|
||||
schema,
|
||||
latestAnswer,
|
||||
middlewares,
|
||||
affineFeatureFlagService
|
||||
)
|
||||
.then(doc => {
|
||||
this.disposeDoc();
|
||||
this._doc = doc.doc.getStore({
|
||||
@@ -278,16 +284,10 @@ export class TextRenderer extends WithDisposable(ShadowlessElement) {
|
||||
this._doc.readonly = true;
|
||||
this.requestUpdate();
|
||||
if (this.state !== 'generating') {
|
||||
// LinkPreviewerService & ImageProxyService config should read from host settings
|
||||
const linkPreviewerService =
|
||||
this.host?.std.store.get(LinkPreviewerService);
|
||||
this._doc.load();
|
||||
// LinkPreviewService & ImageProxyService config should read from host settings
|
||||
const imageProxyService =
|
||||
this.host?.std.store.get(ImageProxyService);
|
||||
if (linkPreviewerService) {
|
||||
this._doc
|
||||
?.get(LinkPreviewerService)
|
||||
.setEndpoint(linkPreviewerService.endpoint);
|
||||
}
|
||||
if (imageProxyService) {
|
||||
this._doc
|
||||
?.get(ImageProxyService)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { FeatureFlagService } from '@affine/core/modules/feature-flag';
|
||||
import type { ContextEmbedStatus } from '@affine/graphql';
|
||||
import {
|
||||
CanvasElementType,
|
||||
@@ -445,7 +446,10 @@ export class AIChatBlockPeekView extends LitElement {
|
||||
.get(ViewExtensionManagerIdentifier)
|
||||
.get('preview-page');
|
||||
|
||||
this._textRendererOptions = { extensions };
|
||||
this._textRendererOptions = {
|
||||
extensions,
|
||||
affineFeatureFlagService: this.affineFeatureFlagService,
|
||||
};
|
||||
this._historyMessages = this._deserializeHistoryChatMessages(
|
||||
this.historyMessagesString
|
||||
);
|
||||
@@ -556,6 +560,9 @@ export class AIChatBlockPeekView extends LitElement {
|
||||
@property({ attribute: false })
|
||||
accessor searchMenuConfig!: SearchMenuConfig;
|
||||
|
||||
@property({ attribute: false })
|
||||
accessor affineFeatureFlagService!: FeatureFlagService;
|
||||
|
||||
@state()
|
||||
accessor _historyMessages: ChatMessage[] = [];
|
||||
|
||||
@@ -584,7 +591,8 @@ export const AIChatBlockPeekViewTemplate = (
|
||||
docDisplayConfig: DocDisplayConfig,
|
||||
searchMenuConfig: SearchMenuConfig,
|
||||
networkSearchConfig: AINetworkSearchConfig,
|
||||
reasoningConfig: AIReasoningConfig
|
||||
reasoningConfig: AIReasoningConfig,
|
||||
affineFeatureFlagService: FeatureFlagService
|
||||
) => {
|
||||
return html`<ai-chat-block-peek-view
|
||||
.blockModel=${blockModel}
|
||||
@@ -593,5 +601,6 @@ export const AIChatBlockPeekViewTemplate = (
|
||||
.docDisplayConfig=${docDisplayConfig}
|
||||
.searchMenuConfig=${searchMenuConfig}
|
||||
.reasoningConfig=${reasoningConfig}
|
||||
.affineFeatureFlagService=${affineFeatureFlagService}
|
||||
></ai-chat-block-peek-view>`;
|
||||
};
|
||||
|
||||
@@ -170,7 +170,8 @@ const usePreviewExtensions = () => {
|
||||
.theme(framework)
|
||||
.database(framework)
|
||||
.linkedDoc(framework)
|
||||
.paragraph(enableAI).value;
|
||||
.paragraph(enableAI)
|
||||
.linkPreview(framework).value;
|
||||
const specs = manager.get('preview-page');
|
||||
return [...specs, patchReferenceRenderer(reactToLit, referenceRenderer)];
|
||||
}, [reactToLit, referenceRenderer, framework, enableAI]);
|
||||
|
||||
@@ -19,7 +19,6 @@ import {
|
||||
ImageProxyService,
|
||||
} from '@blocksuite/affine/shared/adapters';
|
||||
import { focusBlockEnd } from '@blocksuite/affine/shared/commands';
|
||||
import { LinkPreviewerService } from '@blocksuite/affine/shared/services';
|
||||
import { getLastNoteBlock } from '@blocksuite/affine/shared/utils';
|
||||
import type { BlockStdScope, EditorHost } from '@blocksuite/affine/std';
|
||||
import type { Store } from '@blocksuite/affine/store';
|
||||
@@ -212,13 +211,7 @@ const BlockSuiteEditorImpl = ({
|
||||
server.baseUrl
|
||||
).toString();
|
||||
|
||||
const linkPreviewUrl = new URL(
|
||||
BUILD_CONFIG.linkPreviewUrl,
|
||||
server.baseUrl
|
||||
).toString();
|
||||
|
||||
editor.std.clipboard.use(customImageProxyMiddleware(imageProxyUrl));
|
||||
page.get(LinkPreviewerService).setEndpoint(linkPreviewUrl);
|
||||
page.get(ImageProxyService).setImageProxyURL(imageProxyUrl);
|
||||
|
||||
editor.updateComplete
|
||||
|
||||
@@ -101,7 +101,8 @@ const usePatchSpecs = (mode: DocMode) => {
|
||||
.linkedDoc(framework)
|
||||
.paragraph(enableAI)
|
||||
.mobile(framework)
|
||||
.electron(framework).value;
|
||||
.electron(framework)
|
||||
.linkPreview(framework).value;
|
||||
|
||||
if (BUILD_CONFIG.isMobileEdition) {
|
||||
if (mode === 'page') {
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
import {
|
||||
type ViewExtensionContext,
|
||||
ViewExtensionProvider,
|
||||
} from '@blocksuite/affine/ext-loader';
|
||||
import { FrameworkProvider } from '@toeverything/infra';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { patchLinkPreviewService } from './link-preview-service';
|
||||
|
||||
const optionsSchema = z.object({
|
||||
framework: z.instanceof(FrameworkProvider).optional(),
|
||||
});
|
||||
|
||||
type AffineLinkPreviewViewOptions = z.infer<typeof optionsSchema>;
|
||||
|
||||
export class AffineLinkPreviewExtension extends ViewExtensionProvider<AffineLinkPreviewViewOptions> {
|
||||
override name = 'affine-link-preview-extension';
|
||||
|
||||
override schema = optionsSchema;
|
||||
|
||||
override setup(
|
||||
context: ViewExtensionContext,
|
||||
options?: AffineLinkPreviewViewOptions
|
||||
) {
|
||||
super.setup(context, options);
|
||||
if (!options?.framework) {
|
||||
return;
|
||||
}
|
||||
const { framework } = options;
|
||||
context.register(patchLinkPreviewService(framework));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
import { DEFAULT_LINK_PREVIEW_ENDPOINT } from '@blocksuite/affine/shared/consts';
|
||||
import {
|
||||
LinkPreviewCacheIdentifier,
|
||||
type LinkPreviewCacheProvider,
|
||||
LinkPreviewService,
|
||||
LinkPreviewServiceIdentifier,
|
||||
} from '@blocksuite/affine/shared/services';
|
||||
import { type BlockStdScope, StdIdentifier } from '@blocksuite/affine/std';
|
||||
import { type ExtensionType } from '@blocksuite/affine/store';
|
||||
import type { Container } from '@blocksuite/global/di';
|
||||
import type { FrameworkProvider } from '@toeverything/infra';
|
||||
|
||||
import { ServerService } from '../../../modules/cloud/services/server';
|
||||
|
||||
class AffineLinkPreviewService extends LinkPreviewService {
|
||||
constructor(
|
||||
endpoint: string,
|
||||
std: BlockStdScope,
|
||||
cache: LinkPreviewCacheProvider
|
||||
) {
|
||||
super(std, cache);
|
||||
this.setEndpoint(endpoint);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Patch the link preview service, set the endpoint and cache
|
||||
* @param framework
|
||||
* @returns
|
||||
*/
|
||||
export function patchLinkPreviewService(
|
||||
framework: FrameworkProvider
|
||||
): ExtensionType {
|
||||
// get link preview service endpoint from server and BUILD_CONFIG
|
||||
let linkPreviewUrl: string;
|
||||
try {
|
||||
const server = framework.get(ServerService).server;
|
||||
linkPreviewUrl = new URL(
|
||||
BUILD_CONFIG.linkPreviewUrl || '/',
|
||||
server.baseUrl
|
||||
).toString();
|
||||
} catch (err) {
|
||||
console.error(
|
||||
'Invalid BUILD_CONFIG.linkPreviewUrl, falling back to default',
|
||||
err
|
||||
);
|
||||
linkPreviewUrl = DEFAULT_LINK_PREVIEW_ENDPOINT;
|
||||
}
|
||||
|
||||
return {
|
||||
setup: (di: Container) => {
|
||||
di.override(LinkPreviewServiceIdentifier, provider => {
|
||||
return new AffineLinkPreviewService(
|
||||
linkPreviewUrl,
|
||||
provider.get(StdIdentifier),
|
||||
provider.get(LinkPreviewCacheIdentifier)
|
||||
);
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import { AffineEditorConfigViewExtension } from '@affine/core/blocksuite/extensi
|
||||
import { createDatabaseOptionsConfig } from '@affine/core/blocksuite/extensions/editor-config/database';
|
||||
import { createLinkedWidgetConfig } from '@affine/core/blocksuite/extensions/editor-config/linked';
|
||||
import { ElectronViewExtension } from '@affine/core/blocksuite/extensions/electron';
|
||||
import { AffineLinkPreviewExtension } from '@affine/core/blocksuite/extensions/link-preview-service';
|
||||
import { MobileViewExtension } from '@affine/core/blocksuite/extensions/mobile';
|
||||
import { PdfViewExtension } from '@affine/core/blocksuite/extensions/pdf';
|
||||
import { AffineThemeViewExtension } from '@affine/core/blocksuite/extensions/theme';
|
||||
@@ -44,6 +45,7 @@ type Configure = {
|
||||
mobile: (framework?: FrameworkProvider) => Configure;
|
||||
ai: (enable?: boolean, framework?: FrameworkProvider) => Configure;
|
||||
electron: (framework?: FrameworkProvider) => Configure;
|
||||
linkPreview: (framework?: FrameworkProvider) => Configure;
|
||||
|
||||
value: ViewExtensionManager;
|
||||
};
|
||||
@@ -75,6 +77,7 @@ class ViewProvider {
|
||||
MobileViewExtension,
|
||||
AIViewExtension,
|
||||
ElectronViewExtension,
|
||||
AffineLinkPreviewExtension,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -99,6 +102,7 @@ class ViewProvider {
|
||||
mobile: this._configureMobile,
|
||||
ai: this._configureAI,
|
||||
electron: this._configureElectron,
|
||||
linkPreview: this._configureLinkPreview,
|
||||
value: this._manager,
|
||||
};
|
||||
}
|
||||
@@ -118,7 +122,8 @@ class ViewProvider {
|
||||
.pdf()
|
||||
.mobile()
|
||||
.ai()
|
||||
.electron();
|
||||
.electron()
|
||||
.linkPreview();
|
||||
|
||||
return this.config;
|
||||
};
|
||||
@@ -256,6 +261,11 @@ class ViewProvider {
|
||||
this._manager.configure(ElectronViewExtension, { framework });
|
||||
return this.config;
|
||||
};
|
||||
|
||||
private readonly _configureLinkPreview = (framework?: FrameworkProvider) => {
|
||||
this._manager.configure(AffineLinkPreviewExtension, { framework });
|
||||
return this.config;
|
||||
};
|
||||
}
|
||||
|
||||
export function getViewManager() {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { FeatureFlagService } from '@affine/core/modules/feature-flag';
|
||||
import { WorkspaceImpl } from '@affine/core/modules/workspace/impls/workspace';
|
||||
import type { ServiceProvider } from '@blocksuite/affine/global/di';
|
||||
import {
|
||||
@@ -161,11 +162,13 @@ export async function markDownToDoc(
|
||||
provider: ServiceProvider,
|
||||
schema: Schema,
|
||||
answer: string,
|
||||
middlewares?: TransformerMiddleware[]
|
||||
middlewares?: TransformerMiddleware[],
|
||||
affineFeatureFlagService?: FeatureFlagService
|
||||
) {
|
||||
// Should not create a new doc in the original collection
|
||||
const collection = new WorkspaceImpl({
|
||||
rootDoc: new YDoc({ guid: 'markdownToDoc' }),
|
||||
featureFlagService: affineFeatureFlagService,
|
||||
});
|
||||
collection.meta.initialize();
|
||||
const transformer = new Transformer({
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { ChatPanel } from '@affine/core/blocksuite/ai';
|
||||
import type { AffineEditorContainer } from '@affine/core/blocksuite/block-suite-editor';
|
||||
import { useAIChatConfig } from '@affine/core/components/hooks/affine/use-ai-chat-config';
|
||||
import { FeatureFlagService } from '@affine/core/modules/feature-flag';
|
||||
import { WorkbenchService } from '@affine/core/modules/workbench';
|
||||
import { ViewExtensionManagerIdentifier } from '@blocksuite/affine/ext-loader';
|
||||
import { RefNodeSlotsProvider } from '@blocksuite/affine/inlines/reference';
|
||||
@@ -75,6 +76,8 @@ export const EditorChatPanel = forwardRef(function EditorChatPanel(
|
||||
chatPanelRef.current.extensions = editor.host.std
|
||||
.get(ViewExtensionManagerIdentifier)
|
||||
.get('preview-page');
|
||||
chatPanelRef.current.affineFeatureFlagService =
|
||||
framework.get(FeatureFlagService);
|
||||
|
||||
containerRef.current?.append(chatPanelRef.current);
|
||||
} else {
|
||||
|
||||
@@ -27,7 +27,6 @@ import {
|
||||
customImageProxyMiddleware,
|
||||
ImageProxyService,
|
||||
} from '@blocksuite/affine/shared/adapters';
|
||||
import { LinkPreviewerService } from '@blocksuite/affine/shared/services';
|
||||
import {
|
||||
FrameworkScope,
|
||||
useLiveData,
|
||||
@@ -139,11 +138,6 @@ const DetailPageImpl = () => {
|
||||
server.baseUrl
|
||||
).toString();
|
||||
|
||||
const linkPreviewUrl = new URL(
|
||||
BUILD_CONFIG.linkPreviewUrl,
|
||||
server.baseUrl
|
||||
).toString();
|
||||
|
||||
editorContainer.std.clipboard.use(
|
||||
customImageProxyMiddleware(imageProxyUrl)
|
||||
);
|
||||
@@ -151,9 +145,6 @@ const DetailPageImpl = () => {
|
||||
.get(ImageProxyService)
|
||||
.setImageProxyURL(imageProxyUrl);
|
||||
|
||||
// provide link preview endpoint to blocksuite
|
||||
editorContainer.doc.get(LinkPreviewerService).setEndpoint(linkPreviewUrl);
|
||||
|
||||
// provide page mode and updated date to blocksuite
|
||||
const refNodeService =
|
||||
editorContainer.std.getOptional(RefNodeSlotsProvider);
|
||||
|
||||
@@ -106,6 +106,16 @@ export const AFFINE_FLAGS = {
|
||||
configurable: isCanaryBuild,
|
||||
defaultState: isCanaryBuild,
|
||||
},
|
||||
enable_link_preview_cache: {
|
||||
category: 'blocksuite',
|
||||
bsFlag: 'enable_link_preview_cache',
|
||||
displayName:
|
||||
'com.affine.settings.workspace.experimental-features.enable-link-preview-cache.name',
|
||||
description:
|
||||
'com.affine.settings.workspace.experimental-features.enable-link-preview-cache.description',
|
||||
configurable: isCanaryBuild,
|
||||
defaultState: isCanaryBuild,
|
||||
},
|
||||
|
||||
enable_emoji_folder_icon: {
|
||||
category: 'affine',
|
||||
|
||||
@@ -2,7 +2,9 @@ import { toReactNode } from '@affine/component';
|
||||
import { AIChatBlockPeekViewTemplate } from '@affine/core/blocksuite/ai';
|
||||
import type { AIChatBlockModel } from '@affine/core/blocksuite/ai/blocks/ai-chat-block/model/ai-chat-model';
|
||||
import { useAIChatConfig } from '@affine/core/components/hooks/affine/use-ai-chat-config';
|
||||
import { FeatureFlagService } from '@affine/core/modules/feature-flag';
|
||||
import type { EditorHost } from '@blocksuite/affine/std';
|
||||
import { useFramework } from '@toeverything/infra';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export type AIChatBlockPeekViewProps = {
|
||||
@@ -21,6 +23,9 @@ export const AIChatBlockPeekView = ({
|
||||
reasoningConfig,
|
||||
} = useAIChatConfig();
|
||||
|
||||
const framework = useFramework();
|
||||
const affineFeatureFlagService = framework.get(FeatureFlagService);
|
||||
|
||||
return useMemo(() => {
|
||||
const template = AIChatBlockPeekViewTemplate(
|
||||
model,
|
||||
@@ -28,7 +33,8 @@ export const AIChatBlockPeekView = ({
|
||||
docDisplayConfig,
|
||||
searchMenuConfig,
|
||||
networkSearchConfig,
|
||||
reasoningConfig
|
||||
reasoningConfig,
|
||||
affineFeatureFlagService
|
||||
);
|
||||
return toReactNode(template);
|
||||
}, [
|
||||
@@ -38,5 +44,6 @@ export const AIChatBlockPeekView = ({
|
||||
searchMenuConfig,
|
||||
networkSearchConfig,
|
||||
reasoningConfig,
|
||||
affineFeatureFlagService,
|
||||
]);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user