chore: migrate oxlint & oxfmt (#15464)

#### PR Dependency Tree


* **PR #15464** 👈

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

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

## Summary by CodeRabbit

* **Chores**
* Replaced the project’s formatting and linting workflow with Oxfmt and
Oxlint.
* Added shared formatting and linting configuration, editor integration,
and updated automated checks.
* Updated generated files, scripts, and lint guidance to use the new
tooling.

* **Style**
* Reformatted templates, source code, examples, and configuration files
for consistent readability.
  * No user-facing functionality or rendering behavior changed.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
DarkSky
2026-08-10 23:51:28 +08:00
committed by GitHub
parent 749c83cd8e
commit 0c7b20dc18
292 changed files with 3372 additions and 2866 deletions
@@ -1,4 +1,3 @@
/* eslint-disable rxjs/finnish */
import { computed, signal } from '@preact/signals-core';
import { describe, expect, test, vi } from 'vitest';
@@ -1,4 +1,4 @@
// eslint-disable-next-line import-x/no-extraneous-dependencies
// oxlint-disable-next-line import-x-js/no-extraneous-dependencies
import { PanTool } from '@blocksuite/affine-gfx-pointer';
import { on } from '@blocksuite/affine-shared/utils';
import type { PointerEventState } from '@blocksuite/std';
@@ -51,7 +51,7 @@ export const imageProcessingTypes = [
] as const;
declare global {
// oxlint-disable-next-line @typescript-eslint/no-namespace
// oxlint-disable-next-line typescript/no-namespace
namespace BlockSuitePresets {
type TrackerControl =
| 'format-bar'
@@ -59,9 +59,11 @@ export class AIChatBlockMessage extends LitElement {
<div class="ai-chat-content">
<chat-images .attachments=${attachments}></chat-images>
<div class=${messageClasses}>
${streamObjects?.length
? this.renderStreamObjects(streamObjects)
: this.renderRichText(content)}
${
streamObjects?.length
? this.renderStreamObjects(streamObjects)
: this.renderRichText(content)
}
</div>
</div>
</div>
@@ -75,8 +77,9 @@ export class AIChatBlockMessage extends LitElement {
.host=${this.host}
.state=${this.state}
.extensions=${this.textRendererOptions.extensions}
.affineFeatureFlagService=${this.textRendererOptions
.affineFeatureFlagService}
.affineFeatureFlagService=${
this.textRendererOptions.affineFeatureFlagService
}
.notificationService=${notificationService}
.independentMode=${false}
.theme=${this.host.std.get(ThemeProvider).app$}
@@ -88,8 +91,9 @@ export class AIChatBlockMessage extends LitElement {
.text=${text}
.state=${this.state}
.extensions=${this.textRendererOptions.extensions}
.affineFeatureFlagService=${this.textRendererOptions
.affineFeatureFlagService}
.affineFeatureFlagService=${
this.textRendererOptions.affineFeatureFlagService
}
.theme=${this.host.std.get(ThemeProvider).app$}
></chat-content-rich-text>`;
}
@@ -65,14 +65,16 @@ export class UserInfo extends LitElement {
override render() {
return html`<div class="user-info-container">
<div class="user-avatar-container">
${this.avatarIcon
? this.avatarIcon
: this.avatarUrl && !this.avatarLoadedFailed
? html`<img
.src=${this.avatarUrl}
@error=${this._handleAvatarLoadError}
/>`
: html`<span class="default-avatar"></span>`}
${
this.avatarIcon
? this.avatarIcon
: this.avatarUrl && !this.avatarLoadedFailed
? html`<img
.src=${this.avatarUrl}
@error=${this._handleAvatarLoadError}
/>`
: html`<span class="default-avatar"></span>`
}
</div>
<span class="user-name">${this.userName}</span>
</div>`;
@@ -152,35 +152,43 @@ export class ActionWrapper extends WithDisposable(LitElement) {
<div>${this.promptShow ? ArrowDownIcon() : ArrowUpIcon()}</div>
</div>
</div>
${this.promptShow
? html`
<div class="answer-prompt" data-testid="answer-prompt">
<div class="subtitle">Answer</div>
${HISTORY_IMAGE_ACTIONS.includes(item.action)
? images &&
html`<chat-content-images
.images=${images}
data-testid="generated-image"
></chat-content-images>`
: nothing}
${answer
? createTextRenderer({
customHeading: true,
testId: 'chat-message-action-answer',
theme: this.host.std.get(ThemeProvider).app$,
})(answer)
: nothing}
${originalText
? html`<div class="subtitle prompt">Prompt</div>
${createTextRenderer({
customHeading: true,
testId: 'chat-message-action-prompt',
theme: this.host.std.get(ThemeProvider).app$,
})(item.messages[0].content + originalText)}`
: nothing}
</div>
`
: nothing} `;
${
this.promptShow
? html`
<div class="answer-prompt" data-testid="answer-prompt">
<div class="subtitle">Answer</div>
${
HISTORY_IMAGE_ACTIONS.includes(item.action)
? images &&
html`<chat-content-images
.images=${images}
data-testid="generated-image"
></chat-content-images>`
: nothing
}
${
answer
? createTextRenderer({
customHeading: true,
testId: 'chat-message-action-answer',
theme: this.host.std.get(ThemeProvider).app$,
})(answer)
: nothing
}
${
originalText
? html`<div class="subtitle prompt">Prompt</div>
${createTextRenderer({
customHeading: true,
testId: 'chat-message-action-prompt',
theme: this.host.std.get(ThemeProvider).app$,
})(item.messages[0].content + originalText)}`
: nothing
}
</div>
`
: nothing
} `;
}
}
@@ -23,12 +23,14 @@ export class ActionImageToText extends WithDisposable(ShadowlessElement) {
marginBottom: '12px',
})}
>
${answer
? html`<chat-content-images
data-testid="original-images"
.images=${answer}
></chat-content-images>`
: nothing}
${
answer
? html`<chat-content-images
data-testid="original-images"
.images=${answer}
></chat-content-images>`
: nothing
}
</div>
</action-wrapper>`;
}
@@ -23,12 +23,14 @@ export class ActionImage extends WithDisposable(ShadowlessElement) {
return html`<action-wrapper .host=${this.host} .item=${this.item}>
<div style=${styleMap({ marginBottom: '12px' })}>
${images
? html`<chat-content-images
.images=${images}
data-testid="original-image"
></chat-content-images>`
: nothing}
${
images
? html`<chat-content-images
.images=${images}
data-testid="original-image"
></chat-content-images>`
: nothing
}
</div>
</action-wrapper>`;
}
@@ -61,8 +61,10 @@ export class ChatMessageAction extends WithDisposable(ShadowlessElement) {
return html`<action-text
.item=${item}
.host=${host}
.isCode=${item.action === 'Explain this code' ||
item.action === 'Check code error'}
.isCode=${
item.action === 'Explain this code' ||
item.action === 'Check code error'
}
></action-text>`;
}
}
@@ -111,9 +111,11 @@ export class ChatMessageAssistant extends WithDisposable(ShadowlessElement) {
return html`<div class="user-info">
<chat-assistant-avatar .status=${this.status}></chat-assistant-avatar>
${isWithDocs
? html`<span class="message-info">with your docs</span>`
: nothing}
${
isWithDocs
? html`<span class="message-info">with your docs</span>`
: nothing
}
</div>`;
}
@@ -124,12 +126,16 @@ export class ChatMessageAssistant extends WithDisposable(ShadowlessElement) {
return html`
${this.renderImages()}
${streamObjects?.length
? this.renderStreamObjects(streamObjects)
: this.renderRichText(content)}
${shouldRenderError
? AIChatErrorRenderer(error, host, () => this.retry())
: nothing}
${
streamObjects?.length
? this.renderStreamObjects(streamObjects)
: this.renderRichText(content)
}
${
shouldRenderError
? AIChatErrorRenderer(error, host, () => this.retry())
: nothing
}
${this.renderEditorActions()}
`;
}
@@ -209,17 +215,19 @@ export class ChatMessageAssistant extends WithDisposable(ShadowlessElement) {
.retry=${() => this.retry()}
.notificationService=${this.notificationService}
></chat-copy-more>
${isLast && showActions
? html`<chat-action-list
.actions=${actions}
.host=${host}
.session=${session}
.content=${markdown}
.messageId=${messageId ?? undefined}
.withMargin=${true}
.notificationService=${this.notificationService}
></chat-action-list>`
: nothing}
${
isLast && showActions
? html`<chat-action-list
.actions=${actions}
.host=${host}
.session=${session}
.content=${markdown}
.messageId=${messageId ?? undefined}
.withMargin=${true}
.notificationService=${this.notificationService}
></chat-action-list>`
: nothing
}
`;
}
@@ -61,12 +61,14 @@ export class ChatMessageUser extends WithDisposable(ShadowlessElement) {
});
return html`
${item.attachments
? html`<chat-content-images
class="chat-content-images"
.images=${item.attachments}
></chat-content-images>`
: nothing}
${
item.attachments
? html`<chat-content-images
class="chat-content-images"
.images=${item.attachments}
></chat-content-images>`
: nothing
}
<div
class="text-content-wrapper"
data-test-id="chat-content-user-text"
@@ -74,15 +76,17 @@ export class ChatMessageUser extends WithDisposable(ShadowlessElement) {
>
<chat-content-pure-text .text=${item.content}></chat-content-pure-text>
</div>
${showReceipt
? html`<div class="scope-receipt" data-testid="chat-scope-receipt">
${selectorNames?.join(', ')} ·
${I18n['com.affine.ai.chat-panel.scope.sources']({
count: String(resolvedCount),
})}
· ${new Date(receipt.resolvedAt).toLocaleString()}
</div>`
: nothing}
${
showReceipt
? html`<div class="scope-receipt" data-testid="chat-scope-receipt">
${selectorNames?.join(', ')} ·
${I18n['com.affine.ai.chat-panel.scope.sources']({
count: String(resolvedCount),
})}
· ${new Date(receipt.resolvedAt).toLocaleString()}
</div>`
: nothing
}
`;
}
@@ -64,13 +64,15 @@ export class AIChatAddContext extends SignalWatcher(
@click=${this.toggleAddDocMenu}
>
${PlusIcon()}
${disabled
? html`<affine-tooltip>
${I18n[
'com.affine.ai.chat-panel.local-workspace-context-unavailable'
]()}
</affine-tooltip>`
: null}
${
disabled
? html`<affine-tooltip>
${I18n[
'com.affine.ai.chat-panel.local-workspace-context-unavailable'
]()}
</affine-tooltip>`
: null
}
</div>
`;
}
@@ -351,12 +351,16 @@ export class ChatPanelAddPopover extends SignalWatcher(
const items = resolveSignal(group.items);
const menuGroup = html`<div class="menu-group">
${items.length > 0
? this._renderMenuItems(items, startIndex)
: (group.noResult?.() ?? this._renderNoResult())}
${idx < groups.length - 1
? (group.divider?.() ?? this._renderDivider())
: ''}
${
items.length > 0
? this._renderMenuItems(items, startIndex)
: (group.noResult?.() ?? this._renderNoResult())
}
${
idx < groups.length - 1
? (group.divider?.() ?? this._renderDivider())
: ''
}
</div>`;
startIndex += items.length;
return menuGroup;
@@ -194,19 +194,23 @@ export class ChatPanelChips extends SignalWatcher(
return null;
}
)}
${moreCandidates && !isCollapsed
? html`<div
class="more-candidate-button"
@click=${this._toggleMoreCandidatesMenu}
>
${MoreVerticalIcon()}
</div>`
: nothing}
${isCollapsed
? html`<div class="collapse-button" @click=${this.toggleCollapse}>
+${allChips.length - 1}
</div>`
: nothing}
${
moreCandidates && !isCollapsed
? html`<div
class="more-candidate-button"
@click=${this._toggleMoreCandidatesMenu}
>
${MoreVerticalIcon()}
</div>`
: nothing
}
${
isCollapsed
? html`<div class="collapse-button" @click=${this.toggleCollapse}>
+${allChips.length - 1}
</div>`
: nothing
}
</div>`;
}
@@ -114,15 +114,17 @@ export class ChatPanelChip extends SignalWatcher(
</span>
<affine-tooltip>${this.tooltip}</affine-tooltip>
</div>
${isCandidate
? html`${PlusIcon()}`
: this.closeable
? html`
<div class="chip-card-close" @click=${this.onChipDelete}>
${CloseIcon()}
</div>
`
: ''}
${
isCandidate
? html`${PlusIcon()}`
: this.closeable
? html`
<div class="chip-card-close" @click=${this.onChipDelete}>
${CloseIcon()}
</div>
`
: ''
}
</div>
`;
}
@@ -242,9 +242,13 @@ export class ChatPanelSplitView extends SignalWatcher(
<div class="ai-chat-panel-split-view-divider">
<div class="ai-chat-panel-split-view-divider-handle"></div>
</div>
${this.open || this.isTransitioning
? html` <div class="ai-chat-panel-split-view-right">${this.right}</div>`
: nothing}
${
this.open || this.isTransitioning
? html` <div class="ai-chat-panel-split-view-right">
${this.right}
</div>`
: nothing
}
</div>`;
}
}
@@ -574,37 +574,45 @@ export class AIChatInput extends SignalWatcher(
@dragleave=${this._handleDragLeave}
@drop=${this._handleDrop}
>
${this.isDragOver
? html`<div class="chat-panel-input-drop-overlay">Drop to attach</div>`
: nothing}
${hasImages
? html`
<image-preview-grid
.images=${images}
.onImageRemove=${this._handleImageRemove}
></image-preview-grid>
`
: nothing}
${this.chatContextValue.quote
? html`<div
class="chat-selection-quote"
data-testid="chat-selection-quote"
>
${repeat(
getFirstTwoLines(this.chatContextValue.quote),
line => line,
line => html`<div>${line}</div>`
)}
<div
class="chat-quote-close"
@click=${() => {
this.updateContext({ quote: '', markdown: '' });
}}
${
this.isDragOver
? html`<div class="chat-panel-input-drop-overlay">
Drop to attach
</div>`
: nothing
}
${
hasImages
? html`
<image-preview-grid
.images=${images}
.onImageRemove=${this._handleImageRemove}
></image-preview-grid>
`
: nothing
}
${
this.chatContextValue.quote
? html`<div
class="chat-selection-quote"
data-testid="chat-selection-quote"
>
${CloseIcon()}
</div>
</div>`
: nothing}
${repeat(
getFirstTwoLines(this.chatContextValue.quote),
line => line,
line => html`<div>${line}</div>`
)}
<div
class="chat-quote-close"
@click=${() => {
this.updateContext({ quote: '', markdown: '' });
}}
>
${CloseIcon()}
</div>
</div>`
: nothing
}
<textarea
rows="1"
placeholder="What are your thoughts?"
@@ -646,22 +654,24 @@ export class AIChatInput extends SignalWatcher(
.subscriptionService=${this.subscriptionService}
.onAISubscribe=${this.onAISubscribe}
></chat-input-preference>
${status === 'transmitting' || status === 'loading'
? html`<button
class="chat-panel-stop"
@click=${this._handleAbort}
data-testid="chat-panel-stop"
>
${ChatAbortIcon}
</button>`
: html`<button
@click="${this._onTextareaSend}"
class="chat-panel-send"
aria-disabled=${this.isSendDisabled}
data-testid="chat-panel-send"
>
${ArrowUpBigIcon()}
</button>`}
${
status === 'transmitting' || status === 'loading'
? html`<button
class="chat-panel-stop"
@click=${this._handleAbort}
data-testid="chat-panel-stop"
>
${ChatAbortIcon}
</button>`
: html`<button
@click="${this._onTextareaSend}"
class="chat-panel-send"
aria-disabled=${this.isSendDisabled}
data-testid="chat-panel-send"
>
${ArrowUpBigIcon()}
</button>`
}
</div>
</div>`;
}
@@ -139,9 +139,9 @@ export class ChatInputPreference extends SignalWatcher(
name: 'Auto',
prefix: html`
<div class="ai-model-prefix">
${this.aiModelService.modelId.value
? undefined
: DoneIcon()}
${
this.aiModelService.modelId.value ? undefined : DoneIcon()
}
</div>
`,
select: () => this.aiModelService.resetModel(),
@@ -154,9 +154,11 @@ export class ChatInputPreference extends SignalWatcher(
`,
prefix: html`
<div class="ai-model-prefix">
${model.id === this.aiModelService.modelId.value
? DoneIcon()
: undefined}
${
model.id === this.aiModelService.modelId.value
? DoneIcon()
: undefined
}
</div>
`,
postfix: html`
@@ -337,77 +337,83 @@ export class AIChatMessages extends WithDisposable(ShadowlessElement) {
})}
data-testid="chat-panel-messages-container"
>
${filteredItems.length === 0
? html`<div
class="messages-placeholder"
data-testid="chat-panel-messages-placeholder"
>
${AffineIcon(
isHistoryLoading
? 'var(--affine-icon-secondary)'
: 'var(--affine-primary-color)'
)}
<div
class="messages-placeholder-title"
data-loading=${isHistoryLoading}
${
filteredItems.length === 0
? html`<div
class="messages-placeholder"
data-testid="chat-panel-messages-placeholder"
>
${this.isHistoryLoading
? html`<span data-testid="chat-panel-loading-state"
>AFFiNE AI is loading history...</span
>`
: html`<span data-testid="chat-panel-empty-state"
>What can I help you with?</span
>`}
</div>
${this.independentMode ? nothing : this._renderAIOnboarding()}
</div> `
: repeat(
filteredItems,
(item, index) => this._getMessageKey(item, index),
(item, index) => {
const isLast = index === filteredItems.length - 1;
if (isChatMessage(item) && item.role === 'user') {
return html`<chat-message-user
.item=${item}
></chat-message-user>`;
} else if (isChatMessage(item) && item.role === 'assistant') {
return html`<chat-message-assistant
.host=${this.host}
.session=${this.session}
.item=${item}
.isLast=${isLast}
.status=${isLast ? status : 'idle'}
.error=${isLast ? error : null}
.extensions=${this.extensions}
.affineFeatureFlagService=${this.affineFeatureFlagService}
.affineThemeService=${this.affineThemeService}
.notificationService=${this.notificationService}
.retry=${() => this.retry()}
.width=${this.width}
.independentMode=${this.independentMode}
.docDisplayService=${this.docDisplayService}
.peekViewService=${this.peekViewService}
.onOpenDoc=${this.onOpenDoc}
></chat-message-assistant>`;
} else if (isChatAction(item) && this.host) {
return html`<chat-message-action
.host=${this.host}
.item=${item}
></chat-message-action>`;
${AffineIcon(
isHistoryLoading
? 'var(--affine-icon-secondary)'
: 'var(--affine-primary-color)'
)}
<div
class="messages-placeholder-title"
data-loading=${isHistoryLoading}
>
${
this.isHistoryLoading
? html`<span data-testid="chat-panel-loading-state"
>AFFiNE AI is loading history...</span
>`
: html`<span data-testid="chat-panel-empty-state"
>What can I help you with?</span
>`
}
</div>
${this.independentMode ? nothing : this._renderAIOnboarding()}
</div> `
: repeat(
filteredItems,
(item, index) => this._getMessageKey(item, index),
(item, index) => {
const isLast = index === filteredItems.length - 1;
if (isChatMessage(item) && item.role === 'user') {
return html`<chat-message-user
.item=${item}
></chat-message-user>`;
} else if (isChatMessage(item) && item.role === 'assistant') {
return html`<chat-message-assistant
.host=${this.host}
.session=${this.session}
.item=${item}
.isLast=${isLast}
.status=${isLast ? status : 'idle'}
.error=${isLast ? error : null}
.extensions=${this.extensions}
.affineFeatureFlagService=${this.affineFeatureFlagService}
.affineThemeService=${this.affineThemeService}
.notificationService=${this.notificationService}
.retry=${() => this.retry()}
.width=${this.width}
.independentMode=${this.independentMode}
.docDisplayService=${this.docDisplayService}
.peekViewService=${this.peekViewService}
.onOpenDoc=${this.onOpenDoc}
></chat-message-assistant>`;
} else if (isChatAction(item) && this.host) {
return html`<chat-message-action
.host=${this.host}
.item=${item}
></chat-message-action>`;
}
return nothing;
}
return nothing;
}
)}
)
}
</div>
${showDownIndicator && filteredItems.length > 0
? html`<div
data-testid="chat-panel-scroll-down-indicator"
class="down-indicator"
@click=${this._onDownIndicatorClick}
>
${ArrowDownIcon()}
</div>`
: nothing}
${
showDownIndicator && filteredItems.length > 0
? html`<div
data-testid="chat-panel-scroll-down-indicator"
class="down-indicator"
@click=${this._onDownIndicatorClick}
>
${ArrowDownIcon()}
</div>`
: nothing
}
`;
}
@@ -93,16 +93,18 @@ export class AIChatToolbar extends WithDisposable(ShadowlessElement) {
const pinned = this.session?.pinned;
return html`
<div class="ai-chat-toolbar">
${this.canCreateNewSession
? html` <div
class="chat-toolbar-icon"
@click=${this.onPlusClick}
data-testid="ai-panel-new-chat"
>
${PlusIcon()}
<affine-tooltip>New Chat</affine-tooltip>
</div>`
: null}
${
this.canCreateNewSession
? html` <div
class="chat-toolbar-icon"
@click=${this.onPlusClick}
data-testid="ai-panel-new-chat"
>
${PlusIcon()}
<affine-tooltip>New Chat</affine-tooltip>
</div>`
: null
}
<div
class="chat-toolbar-icon"
@click=${this.onPinClick}
@@ -301,9 +301,11 @@ export class AISessionHistory extends WithDisposable(ShadowlessElement) {
Click to open this chat
</affine-tooltip>
</div>
${session.docId
? this.renderSessionDoc(session.docId, session.sessionId)
: nothing}
${
session.docId
? this.renderSessionDoc(session.docId, session.sessionId)
: nothing
}
<div
class="ai-session-item-delete"
@click=${(e: MouseEvent) => {
@@ -115,11 +115,13 @@ export class AIItemList extends WithDisposable(LitElement) {
const theme = this.host.std.get(ThemeProvider).app$.value;
return html`${repeat(this.groups, group => {
return html`
${group.name
? html`<div class="group-name">
${group.name.toLocaleUpperCase()}
</div>`
: nothing}
${
group.name
? html`<div class="group-name">
${group.name.toLocaleUpperCase()}
</div>`
: nothing
}
${repeat(
group.items,
item => item.name,
@@ -40,13 +40,15 @@ export class AIItem extends WithDisposable(LitElement) {
>
<span class="item-icon">${item.icon}</span>
<div class="item-name">
${item.name}${item.beta
? html`<div class="item-beta">(Beta)</div>`
: nothing}
${item.name}${
item.beta ? html`<div class="item-beta">(Beta)</div>` : nothing
}
</div>
${item.subItem
? html`<span class="arrow-right-icon">${ArrowRightIcon}</span>`
: html`<span class="enter-icon">${EnterIcon}</span>`}
${
item.subItem
? html`<span class="arrow-right-icon">${ArrowRightIcon}</span>`
: html`<span class="enter-icon">${EnterIcon}</span>`
}
</div>`;
}
@@ -25,9 +25,11 @@ export class AssistantAvatar extends ShadowlessElement {
`;
protected override render() {
return html`${this.status === 'transmitting'
? AIStarIconWithAnimation
: AffineAvatarIcon}
return html`${
this.status === 'transmitting'
? AIStarIconWithAnimation
: AffineAvatarIcon
}
AFFiNE AI`;
}
}
@@ -129,7 +129,7 @@ type StreamGroup =
function groupStreamObjects(answer: StreamObject[]): StreamGroup[] {
const groups: StreamGroup[] = [];
for (let index = 0; index < answer.length; ) {
for (let index = 0; index < answer.length;) {
if (!isToolObject(answer[index])) {
groups.push({ type: 'item', item: answer[index] });
index += 1;
@@ -351,9 +351,11 @@ export class ChatContentStreamObjects extends WithDisposable(
}
if (!result || result.error || result.type === 'error') {
return html`<tool-call-failed
.name=${result
? frontendReadError(result)
: I18n['com.affine.ai.chat-panel.tool.live.failed']()}
.name=${
result
? frontendReadError(result)
: I18n['com.affine.ai.chat-panel.tool.live.failed']()
}
.icon=${ViewIcon()}
></tool-call-failed>`;
}
@@ -392,9 +394,11 @@ export class ChatContentStreamObjects extends WithDisposable(
const result = object(streamObject.result);
if (!result || result.error || result.type === 'error') {
return html`<tool-call-failed
.name=${result
? frontendReadError(result)
: I18n['com.affine.ai.chat-panel.tool.canvas.failed']()}
.name=${
result
? frontendReadError(result)
: I18n['com.affine.ai.chat-panel.tool.canvas.failed']()
}
.icon=${ViewIcon()}
></tool-call-failed>`;
}
@@ -152,9 +152,13 @@ export abstract class ArtifactTool<
</div>
</div>
</div>
${banner
? html`<div class="affine-embed-linked-doc-banner">${banner}</div>`
: nothing}
${
banner
? html`<div class="affine-embed-linked-doc-banner">
${banner}
</div>`
: nothing
}
</div>
</div>
`;
@@ -486,14 +486,18 @@ export class CodeArtifactTool extends ArtifactTool<
const { html: htmlContent } = result as { html: string };
return html`<div class="code-artifact-preview">
${this.mode === 'preview'
? html`<affine-html-preview .html=${htmlContent}></affine-html-preview>`
: html`<code-highlighter
.std=${this.std}
.code=${htmlContent}
.language=${'html'}
.showLineNumbers=${true}
></code-highlighter>`}
${
this.mode === 'preview'
? html`<affine-html-preview
.html=${htmlContent}
></affine-html-preview>`
: html`<code-highlighter
.std=${this.std}
.code=${htmlContent}
.language=${'html'}
.showLineNumbers=${true}
></code-highlighter>`
}
</div>`;
}
@@ -120,17 +120,19 @@ export class DocComposeTool extends ArtifactTool<
return html`<div class="doc-compose-result-preview">
<div class="doc-compose-result-preview-title">${title}</div>
${successResult
? html`<text-renderer
.answer=${successResult.markdown}
.schema=${this.std?.store.schema}
.options=${{
customHeading: true,
extensions: getCustomPageEditorBlockSpecs(),
theme: this.theme,
}}
></text-renderer>`
: html``}
${
successResult
? html`<text-renderer
.answer=${successResult.markdown}
.schema=${this.std?.store.schema}
.options=${{
customHeading: true,
extensions: getCustomPageEditorBlockSpecs(),
theme: this.theme,
}}
></text-renderer>`
: html``
}
</div>`;
}
@@ -355,9 +355,9 @@ export class DocEditTool extends WithDisposable(ShadowlessElement) {
<div class="doc-edit-tool-result-wrapper">
<div class="doc-edit-tool-result-title">${op}</div>
<div
class="doc-edit-tool-result-card ${this.isCollapsed
? 'collapsed'
: ''}"
class="doc-edit-tool-result-card ${
this.isCollapsed ? 'collapsed' : ''
}"
>
<div class="doc-edit-tool-result-card-header">
<div class="doc-edit-tool-result-card-header-title">
@@ -173,50 +173,54 @@ export class SectionEditTool extends WithDisposable(ShadowlessElement) {
${CopyIcon()}
<affine-tooltip>Copy</affine-tooltip>
</div>
${this.independentMode
? nothing
: html`<div
class="edit-button"
@click=${async () => {
if (!this.host) return;
if (this.host.std.store.readonly$.value) {
this.notificationService.notify({
title: 'Cannot insert in read-only mode',
accent: 'error',
onClose: () => {},
});
return;
}
if (isInsidePageEditor(this.host)) {
await PAGE_INSERT.handler(
this.host,
result.content,
this.selection
);
} else {
await EDGELESS_INSERT.handler(
this.host,
result.content,
this.selection
);
}
}}
>
${InsertBleowIcon()}
<affine-tooltip>Insert below</affine-tooltip>
</div>`}
${this.independentMode
? nothing
: html`<div
class="edit-button"
@click=${async () => {
if (!this.host) return;
SAVE_AS_DOC.handler(this.host, result.content);
}}
>
${LinkedPageIcon()}
<affine-tooltip>Create new doc</affine-tooltip>
</div>`}
${
this.independentMode
? nothing
: html`<div
class="edit-button"
@click=${async () => {
if (!this.host) return;
if (this.host.std.store.readonly$.value) {
this.notificationService.notify({
title: 'Cannot insert in read-only mode',
accent: 'error',
onClose: () => {},
});
return;
}
if (isInsidePageEditor(this.host)) {
await PAGE_INSERT.handler(
this.host,
result.content,
this.selection
);
} else {
await EDGELESS_INSERT.handler(
this.host,
result.content,
this.selection
);
}
}}
>
${InsertBleowIcon()}
<affine-tooltip>Insert below</affine-tooltip>
</div>`
}
${
this.independentMode
? nothing
: html`<div
class="edit-button"
@click=${async () => {
if (!this.host) return;
SAVE_AS_DOC.handler(this.host, result.content);
}}
>
${LinkedPageIcon()}
<affine-tooltip>Create new doc</affine-tooltip>
</div>`
}
</div>
</div>
<chat-content-rich-text
@@ -260,9 +260,11 @@ export class ToolResultCard extends SignalWatcher(
<div class="ai-tool-header" @click=${this.toggleCard}>
<div class="ai-icon">${this.icon}</div>
<div class="ai-tool-name">${this.name}</div>
${this.isCollapsed
? this.renderFooterIcons()
: html` <div class="ai-icon">${ToggleDownIcon()}</div> `}
${
this.isCollapsed
? this.renderFooterIcons()
: html` <div class="ai-icon">${ToggleDownIcon()}</div> `
}
</div>
<div class="ai-tool-results" data-collapsed=${this.isCollapsed}>
<div class="ai-tool-result-collapse-wrapper">
@@ -285,11 +287,13 @@ export class ToolResultCard extends SignalWatcher(
${this.renderIcon(result.icon)}
</div>
</div>
${result.content
? html`<div class="result-content">
${result.content}
</div>`
: nothing}
${
result.content
? html`<div class="result-content">
${result.content}
</div>`
: nothing
}
</a>
`
)}
@@ -178,74 +178,82 @@ export class ChatCopyMore extends WithDisposable(LitElement) {
}
</style>
<div class="copy-more">
${content
? html`<div
class="button copy"
@click=${async () => {
const success = await copyText(content);
if (success) {
this._notifySuccess('Copied to clipboard');
}
}}
data-testid="action-copy-button"
>
${CopyIcon({ width: '20px', height: '20px' })}
<affine-tooltip>Copy</affine-tooltip>
</div>`
: nothing}
${isLast
? html`<div
class="button retry"
@click=${() => this.retry()}
data-testid="action-retry-button"
>
${ResetIcon({ width: '20px', height: '20px' })}
<affine-tooltip .autoShift=${true}>Retry</affine-tooltip>
</div>`
: nothing}
${showMoreIcon && host
? html`<div
class="button more"
data-testid="action-more-button"
@click=${this._toggle}
>
${MoreHorizontalIcon({ width: '20px', height: '20px' })}
</div> `
: nothing}
${
content
? html`<div
class="button copy"
@click=${async () => {
const success = await copyText(content);
if (success) {
this._notifySuccess('Copied to clipboard');
}
}}
data-testid="action-copy-button"
>
${CopyIcon({ width: '20px', height: '20px' })}
<affine-tooltip>Copy</affine-tooltip>
</div>`
: nothing
}
${
isLast
? html`<div
class="button retry"
@click=${() => this.retry()}
data-testid="action-retry-button"
>
${ResetIcon({ width: '20px', height: '20px' })}
<affine-tooltip .autoShift=${true}>Retry</affine-tooltip>
</div>`
: nothing
}
${
showMoreIcon && host
? html`<div
class="button more"
data-testid="action-more-button"
@click=${this._toggle}
>
${MoreHorizontalIcon({ width: '20px', height: '20px' })}
</div> `
: nothing
}
</div>
<div class="more-menu">
${this._showMoreMenu && host
? repeat(
actions.filter(action => action.showWhen(host)),
action => action.title,
action => {
const currentSelections = {
text: this._currentTextSelection,
blocks: this._currentBlockSelections,
};
return html`<div
@click=${async () => {
const sessionId = this.session?.sessionId;
const success = await action.handler(
host,
content,
currentSelections,
sessionId,
messageId
);
${
this._showMoreMenu && host
? repeat(
actions.filter(action => action.showWhen(host)),
action => action.title,
action => {
const currentSelections = {
text: this._currentTextSelection,
blocks: this._currentBlockSelections,
};
return html`<div
@click=${async () => {
const sessionId = this.session?.sessionId;
const success = await action.handler(
host,
content,
currentSelections,
sessionId,
messageId
);
if (success) {
this._notifySuccess(action.toast);
}
}}
>
${action.icon}
<div>${action.title}</div>
</div>`;
}
)
: nothing}
if (success) {
this._notifySuccess(action.toast);
}
}}
>
${action.icon}
<div>${action.title}</div>
</div>`;
}
)
: nothing
}
</div>`;
}
}
@@ -331,11 +331,13 @@ export class PlaygroundChat extends SignalWatcher(
return html`<div class="chat-panel-container">
<div class="chat-panel-title">
<div class="chat-panel-title-text">
${isSynchronizing
? html`<span data-testid="chat-panel-embedding-progress"
>Synchronizing sources</span
>`
: 'AFFiNE AI'}
${
isSynchronizing
? html`<span data-testid="chat-panel-embedding-progress"
>Synchronizing sources</span
>`
: 'AFFiNE AI'
}
</div>
<div class="chat-panel-add" @click=${this.addChat}>
${NewPageIcon()}
@@ -321,11 +321,11 @@ export class PlaygroundContent extends SignalWatcher(
}
};
// oxlint-disable-next-line @typescript-eslint/no-misused-promises
// oxlint-disable-next-line typescript/no-misused-promises
button.addEventListener('click', handleSendClick);
this._disposables.add(() => {
// oxlint-disable-next-line @typescript-eslint/no-misused-promises
// oxlint-disable-next-line typescript/no-misused-promises
button.removeEventListener('click', handleSendClick);
});
}
@@ -383,8 +383,9 @@ export class PlaygroundContent extends SignalWatcher(
.notificationService=${this.notificationService}
.aiToolsConfigService=${this.aiToolsConfigService}
.aiModelService=${this.aiModelService}
.affineWorkspaceDialogService=${this
.affineWorkspaceDialogService}
.affineWorkspaceDialogService=${
this.affineWorkspaceDialogService
}
.subscriptionService=${this.subscriptionService}
.addChat=${this.addChat}
></playground-chat>
@@ -128,46 +128,56 @@ export class AIErrorWrapper extends SignalWatcher(WithDisposable(LitElement)) {
<div class="icon">${InformationIcon()}</div>
<div class="text-container">
<div>${this.text}</div>
${this.showDetailPanel
? html`<div class="detail-container">
<div
class="detail-title"
@click=${() =>
(this._showDetailContent.value =
!this._showDetailContent.value)}
>
<span>Show detail</span>
<span
class="toggle ${this._showDetailContent.value
? 'down'
: 'up'}"
${
this.showDetailPanel
? html`<div class="detail-container">
<div
class="detail-title"
@click=${() =>
(this._showDetailContent.value =
!this._showDetailContent.value)}
>
${ToggleDownIcon({ width: '16px', height: '16px' })}
</span>
</div>
${this._showDetailContent.value
? html`<div class="detail-content">${this.errorMessage}</div>`
: nothing}
</div>`
: nothing}
<span>Show detail</span>
<span
class="toggle ${
this._showDetailContent.value ? 'down' : 'up'
}"
>
${ToggleDownIcon({ width: '16px', height: '16px' })}
</span>
</div>
${
this._showDetailContent.value
? html`<div class="detail-content">
${this.errorMessage}
</div>`
: nothing
}
</div>`
: nothing
}
</div>
</div>
${this.showAction
? html`<div class="action">
<span
class="action-button"
@click=${this.onClick}
data-testid="ai-error-action-button"
>
${this.actionText}
${this.actionTooltip
? html`<affine-tooltip tip-position="top">
${this.actionTooltip}
</affine-tooltip>`
: nothing}
</span>
</div>`
: nothing}
${
this.showAction
? html`<div class="action">
<span
class="action-button"
@click=${this.onClick}
data-testid="ai-error-action-button"
>
${this.actionText}
${
this.actionTooltip
? html`<affine-tooltip tip-position="top">
${this.actionTooltip}
</affine-tooltip>`
: nothing
}
</span>
</div>`
: nothing
}
</div>`;
}
@@ -41,9 +41,9 @@ export class AIAnswerWrapper extends LitElement {
protected override render() {
return html`<style>
:host {
height: ${this.options?.height
? this.options?.height + 'px'
: '100%'};
height: ${
this.options?.height ? this.options?.height + 'px' : '100%'
};
}
</style>
<slot></slot> `;
@@ -184,23 +184,25 @@ export class MiniMindmapPreview extends WithDisposable(LitElement) {
}).render()}
</div>
${this.templateShow
? html` <div class="select-template-title">Select template</div>
<div class="template">
${repeat(
mindmapStyles,
([style]) => style,
([style, icon]) => {
return html`<div
class=${`template-item ${curStyle === style ? 'active' : ''}`}
@click=${() => this._switchStyle(style as MindmapStyle)}
>
${icon}
</div>`;
}
)}
</div>`
: nothing}
${
this.templateShow
? html` <div class="select-template-title">Select template</div>
<div class="template">
${repeat(
mindmapStyles,
([style]) => style,
([style, icon]) => {
return html`<div
class=${`template-item ${curStyle === style ? 'active' : ''}`}
@click=${() => this._switchStyle(style as MindmapStyle)}
>
${icon}
</div>`;
}
)}
</div>`
: nothing
}
</div>`;
}
@@ -5,7 +5,6 @@ import { Subject } from 'rxjs';
export class MindmapService extends BlockService {
static override readonly flavour = RootBlockSchema.model.flavour;
// eslint-disable-next-line rxjs/finnish
requestCenter = new Subject<void>();
center() {
@@ -1,4 +1,4 @@
/* oxlint-disable @typescript-eslint/no-non-null-assertion */
/* oxlint-disable typescript/no-non-null-assertion */
import {
CanvasRenderer,
type SurfaceBlockModel,
@@ -433,29 +433,33 @@ export class AIChatBlockPeekView extends LitElement {
.textRendererOptions=${this._textRendererOptions}
></ai-chat-block-message>
${shouldRenderError ? AIChatErrorRenderer(error, host) : nothing}
${shouldRenderCopyMore
? html` <chat-copy-more
.host=${host}
.session=${this.forkSession}
.actions=${actions}
.content=${markdown}
.isLast=${isLastReply}
.messageId=${message.id ?? undefined}
.retry=${() => this.retry()}
.notificationService=${notificationService}
></chat-copy-more>`
: nothing}
${shouldRenderActions
? html`<chat-action-list
.host=${host}
.session=${this.forkSession}
.actions=${actions}
.content=${markdown}
.messageId=${message.id ?? undefined}
.layoutDirection=${'horizontal'}
.notificationService=${notificationService}
></chat-action-list>`
: nothing}
${
shouldRenderCopyMore
? html` <chat-copy-more
.host=${host}
.session=${this.forkSession}
.actions=${actions}
.content=${markdown}
.isLast=${isLastReply}
.messageId=${message.id ?? undefined}
.retry=${() => this.retry()}
.notificationService=${notificationService}
></chat-copy-more>`
: nothing
}
${
shouldRenderActions
? html`<chat-action-list
.host=${host}
.session=${this.forkSession}
.actions=${actions}
.content=${markdown}
.messageId=${message.id ?? undefined}
.layoutDirection=${'horizontal'}
.notificationService=${notificationService}
></chat-action-list>`
: nothing
}
</div>`;
}
)}`;
@@ -4,7 +4,6 @@ import { BehaviorSubject, Subject } from 'rxjs';
import type { AIChatParams, AISendParams, AIUserInfo } from './ai-provider';
export const AIAppEvents = {
/* eslint-disable rxjs/finnish */
requestOpenWithChat: new BehaviorSubject<AIChatParams | null>(null),
requestSendWithChat: new BehaviorSubject<AISendParams | null>(null),
requestInsertTemplate: new Subject<{
@@ -15,5 +14,4 @@ export const AIAppEvents = {
requestUpgradePlan: new Subject<{ host?: EditorHost | null }>(),
userInfo: new BehaviorSubject<AIUserInfo | null>(null),
previewPanelOpenChange: new Subject<boolean>(),
/* eslint-enable rxjs/finnish */
};
@@ -1,4 +1,4 @@
/* oxlint-disable @typescript-eslint/no-non-null-assertion */
/* oxlint-disable typescript/no-non-null-assertion */
import { DefaultTool } from '@blocksuite/affine/blocks/surface';
import { IS_MAC } from '@blocksuite/affine/global/env';
import {
@@ -25,7 +25,6 @@ export class CopilotTool extends BaseTool {
private _dragging = false;
// eslint-disable-next-line rxjs/finnish
draggingAreaUpdated = new Subject<boolean | void>();
dragLastPoint: [number, number] = [0, 0];
@@ -529,18 +529,22 @@ export class AffineAIPanelWidget extends WidgetComponent {
[
'generating',
() => html`
${this.answer
? html`
<ai-panel-answer
.finish=${false}
.config=${config.finishStateConfig}
.host=${this.host}
>
${this.answer &&
config.answerRenderer(this.answer, this.state)}
</ai-panel-answer>
`
: nothing}
${
this.answer
? html`
<ai-panel-answer
.finish=${false}
.config=${config.finishStateConfig}
.host=${this.host}
>
${
this.answer &&
config.answerRenderer(this.answer, this.state)
}
</ai-panel-answer>
`
: nothing
}
<ai-panel-generating
.config=${config.generatingStateConfig}
.theme=${theme}
@@ -71,29 +71,33 @@ export class AIFinishTip extends WithDisposable(LitElement) {
return html`<div class="finish-tip">
${WarningIcon}
<div class="text">AI outputs can be misleading or wrong</div>
${this.copy?.allowed
? html`<div class="right">
${this.copied
? html`<div class="copied" data-testid="answer-copied">
${AIDoneIcon}
</div>`
: html`<div
class="copy"
data-testid="answer-copy-button"
@click=${async () => {
this.copied = !!(await this.copy?.onCopy());
if (this.copied) {
this.host.std
.getOptional(NotificationProvider)
?.toast('Copied to clipboard');
}
}}
>
${CopyIcon}
<affine-tooltip>Copy</affine-tooltip>
</div>`}
</div>`
: nothing}
${
this.copy?.allowed
? html`<div class="right">
${
this.copied
? html`<div class="copied" data-testid="answer-copied">
${AIDoneIcon}
</div>`
: html`<div
class="copy"
data-testid="answer-copy-button"
@click=${async () => {
this.copied = !!(await this.copy?.onCopy());
if (this.copied) {
this.host.std
.getOptional(NotificationProvider)
?.toast('Copied to clipboard');
}
}}
>
${CopyIcon}
<affine-tooltip>Copy</affine-tooltip>
</div>`
}
</div>`
: nothing
}
</div>`;
}
@@ -93,9 +93,11 @@ export class GeneratingPlaceholder extends WithDisposable(LitElement) {
height: ${this.height}px;
}
</style>
${this.showHeader
? html`<div class="generating-header">Answer</div>`
: nothing}
${
this.showHeader
? html`<div class="generating-header">Answer</div>`
: nothing
}
<div class="generating-body">
<div class="generating-icon">${LoadingIcon()}</div>
<div class="loading-progress">
@@ -90,48 +90,58 @@ export class AIPanelAnswer extends WithDisposable(LitElement) {
<slot></slot>
</div>
</div>
${this.finish
? html`
<ai-finish-tip
.copy=${this.copy}
.host=${this.host}
></ai-finish-tip>
${responseGroup.length > 0
? html`
<ai-panel-divider></ai-panel-divider>
${responseGroup.map(
(group, index) => html`
${index !== 0
? html`<ai-panel-divider></ai-panel-divider>`
: nothing}
<div
class="response-list-container"
data-testid=${group.testId}
>
${
this.finish
? html`
<ai-finish-tip
.copy=${this.copy}
.host=${this.host}
></ai-finish-tip>
${
responseGroup.length > 0
? html`
<ai-panel-divider></ai-panel-divider>
${responseGroup.map(
(group, index) => html`
${
index !== 0
? html`<ai-panel-divider></ai-panel-divider>`
: nothing
}
<div
class="response-list-container"
data-testid=${group.testId}
>
<ai-item-list
.host=${this.host}
.groups=${[group]}
></ai-item-list>
</div>
`
)}
`
: nothing
}
${
responseGroup.length > 0 && this.config.actions.length > 0
? html`<ai-panel-divider></ai-panel-divider>`
: nothing
}
${
this.config.actions.length > 0
? html`
<div class="action-list-container">
<ai-item-list
.host=${this.host}
.groups=${[group]}
.groups=${this.config.actions}
></ai-item-list>
</div>
`
)}
`
: nothing}
${responseGroup.length > 0 && this.config.actions.length > 0
? html`<ai-panel-divider></ai-panel-divider>`
: nothing}
${this.config.actions.length > 0
? html`
<div class="action-list-container">
<ai-item-list
.host=${this.host}
.groups=${this.config.actions}
></ai-item-list>
</div>
`
: nothing}
`
: nothing}
: nothing
}
`
: nothing
}
`;
}
@@ -214,30 +214,36 @@ export class AIPanelError extends WithDisposable(LitElement) {
</div>
${errorTemplate}
</div>
${this.withAnswer
? html`<ai-finish-tip
.copy=${this.copy}
.host=${this.host}
></ai-finish-tip>`
: nothing}
${responseGroup.length > 0
? html`
<ai-panel-divider></ai-panel-divider>
${responseGroup.map(
(group, index) => html`
${index !== 0
? html`<ai-panel-divider></ai-panel-divider>`
: nothing}
<div class="response-list-container">
<ai-item-list
.host=${this.host}
.groups=${[group]}
></ai-item-list>
</div>
`
)}
`
: nothing}
${
this.withAnswer
? html`<ai-finish-tip
.copy=${this.copy}
.host=${this.host}
></ai-finish-tip>`
: nothing
}
${
responseGroup.length > 0
? html`
<ai-panel-divider></ai-panel-divider>
${responseGroup.map(
(group, index) => html`
${
index !== 0
? html`<ai-panel-divider></ai-panel-divider>`
: nothing
}
<div class="response-list-container">
<ai-item-list
.host=${this.host}
.groups=${[group]}
></ai-item-list>
</div>
`
)}
`
: nothing
}
`;
}
@@ -76,14 +76,16 @@ export class AIPanelGenerating extends WithDisposable(LitElement) {
height = 300,
} = this.config;
return html`
${stages && stages.length > 0
? html`<generating-placeholder
.height=${height}
.loadingProgress=${this.loadingProgress}
.stages=${stages}
.showHeader=${!this.withAnswer}
></generating-placeholder>`
: nothing}
${
stages && stages.length > 0
? html`<generating-placeholder
.height=${height}
.loadingProgress=${this.loadingProgress}
.stages=${stages}
.showHeader=${!this.withAnswer}
></generating-placeholder>`
: nothing
}
<div class="generating-tip" data-testid="ai-generating">
<div class="left">${generatingIcon}</div>
<div class="text">AI is generating...</div>
@@ -239,9 +239,11 @@ export class AIPanelInput extends SignalWatcher(WithDisposable(LitElement)) {
@pointerdown=${stopPropagation}
>
${SendIcon()}
${this._hasContent
? html`<affine-tooltip .offsetY=${12}>Send to AI</affine-tooltip>`
: nothing}
${
this._hasContent
? html`<affine-tooltip .offsetY=${12}>Send to AI</affine-tooltip>`
: nothing
}
</div>
</div>
</div>`;
@@ -280,7 +280,7 @@ const BlockSuiteEditorImpl = ({
export const BlockSuiteEditor = (props: EditorProps) => {
const [isLoading, setIsLoading] = useState(true);
const [longerLoading, setLongerLoading] = useState(false);
// eslint-disable-next-line react-hooks/purity
// oxlint-disable-next-line react-hooks-js/purity
const [loadStartTime] = useState(Date.now());
const workspaceService = useService(WorkspaceService);
@@ -362,7 +362,7 @@ const FileCellComponent: ForwardRefRenderFunction<
> = (props, ref): ReactNode => {
const peekView = useService(PeekViewService);
const manager = useMemo(
() => new FileCellManager(props, peekView), // eslint-disable-line react-hooks/preserve-manual-memoization
() => new FileCellManager(props, peekView), // oxlint-disable-line react-hooks-js/preserve-manual-memoization
[] // oxlint-disable-line react/exhaustive-deps
);
@@ -261,7 +261,7 @@ export const MultiMemberSelect: React.FC<MemberManagerOptions> = props => {
const inputRef = useRef<HTMLInputElement>(null);
const memberListRef = useRef<HTMLDivElement>(null);
const memberManager = useMemo(
() => new MemberManager(props), // eslint-disable-line react-hooks/preserve-manual-memoization
() => new MemberManager(props), // oxlint-disable-line react-hooks-js/preserve-manual-memoization
[] // oxlint-disable-line react/exhaustive-deps
);
@@ -70,7 +70,7 @@ const MemberCellComponent: ForwardRefRenderFunction<
CellRenderProps<{}, MemberCellRawValueType, MemberCellJsonValueType>
> = (props, ref): ReactNode => {
const manager = useMemo(
() => new MemberManager(props), // eslint-disable-line react-hooks/preserve-manual-memoization
() => new MemberManager(props), // oxlint-disable-line react-hooks-js/preserve-manual-memoization
[] // oxlint-disable-line react/exhaustive-deps
);
@@ -3,19 +3,15 @@ import { UserListServiceExtension } from '@blocksuite/affine/shared/services';
export function patchUserListExtensions(memberSearch: MemberSearchService) {
return UserListServiceExtension({
// eslint-disable-next-line rxjs/finnish
hasMore$: memberSearch.hasMore$.signal,
loadMore() {
memberSearch.loadMore();
},
// eslint-disable-next-line rxjs/finnish
isLoading$: memberSearch.isLoading$.signal,
// eslint-disable-next-line rxjs/finnish
searchText$: memberSearch.searchText$.signal,
search(keyword) {
memberSearch.search(keyword);
},
// eslint-disable-next-line rxjs/finnish
users$: memberSearch.result$.map(users =>
users.map(u => ({
id: u.id,
@@ -13,7 +13,6 @@ export function patchUserExtensions(
authService: AuthService
) {
return UserServiceExtension({
// eslint-disable-next-line rxjs/finnish
currentUserInfo$: authService.session.account$.map(account => {
if (!account) {
return null;
@@ -25,15 +24,12 @@ export function patchUserExtensions(
removed: false,
} as AffineUserInfo;
}).signal,
// eslint-disable-next-line rxjs/finnish
userInfo$(id) {
return publicUserService.publicUser$(id).signal;
},
// eslint-disable-next-line rxjs/finnish
isLoading$(id) {
return publicUserService.isLoading$(id).signal;
},
// eslint-disable-next-line rxjs/finnish
error$(id) {
return publicUserService.error$(id).selector(error => {
if (error) {
@@ -479,46 +479,50 @@ export class MermaidPreview extends SignalWatcher(
display: this.state === 'finish' ? undefined : 'none',
})}
>
${this.state === 'finish'
? html`
<div
class="mermaid-preview-svg"
style=${styleMap({
transform: `translate(${this.translateX}px, ${this.translateY}px) scale(${this.scale})`,
})}
>
${this.svgContent
? html`<div .innerHTML=${this.svgContent}></div>`
: nothing}
</div>
<div class="mermaid-controls">
<button
class="mermaid-control-button"
@click=${this._zoomIn}
title="Zoom in"
${
this.state === 'finish'
? html`
<div
class="mermaid-preview-svg"
style=${styleMap({
transform: `translate(${this.translateX}px, ${this.translateY}px) scale(${this.scale})`,
})}
>
+
</button>
<button
class="mermaid-control-button"
@click=${this._zoomOut}
title="Zoom out"
>
</button>
<button
class="mermaid-control-button"
@click=${this._resetTransform}
title="Reset view"
>
</button>
</div>
<div class="mermaid-scale-info">
${Math.round(this.scale * 100)}%
</div>
`
: nothing}
${
this.svgContent
? html`<div .innerHTML=${this.svgContent}></div>`
: nothing
}
</div>
<div class="mermaid-controls">
<button
class="mermaid-control-button"
@click=${this._zoomIn}
title="Zoom in"
>
+
</button>
<button
class="mermaid-control-button"
@click=${this._zoomOut}
title="Zoom out"
>
</button>
<button
class="mermaid-control-button"
@click=${this._resetTransform}
title="Reset view"
>
</button>
</div>
<div class="mermaid-scale-info">
${Math.round(this.scale * 100)}%
</div>
`
: nothing
}
</div>
</div>
`;
@@ -194,8 +194,7 @@ export class TypstPreview extends SignalWatcher(
tabindex="0"
aria-label="Typst error message"
>
${this.errorMessage}</pre
>
${this.errorMessage}</pre>
<div class="typst-copy-row">
<button class="typst-copy-button" @click=${this._copyError}>
${this._copyButtonLabel}
@@ -257,9 +256,11 @@ ${this.errorMessage}</pre
transform: `translate(${this.translateX}px, ${this.translateY}px) scale(${this.scale})`,
})}
>
${this.svgContent
? html`<div .innerHTML=${this.svgContent}></div>`
: nothing}
${
this.svgContent
? html`<div .innerHTML=${this.svgContent}></div>`
: nothing
}
</div>
`
: nothing;
@@ -18,7 +18,6 @@ export function getEditorConfigExtension(
return [
EditorSettingExtension({
// eslint-disable-next-line rxjs/finnish
setting$: editorSettingService.editorSetting.settingSignal,
set: (k, v) => editorSettingService.editorSetting.set(k, v),
}),
@@ -24,16 +24,12 @@ export function KeyboardToolbarExtension(
private readonly _disposables = new DisposableGroup();
// eslint-disable-next-line rxjs/finnish
readonly visible$ = signal(false);
// eslint-disable-next-line rxjs/finnish
readonly height$ = signal(0);
// eslint-disable-next-line rxjs/finnish
readonly staticHeight$ = signal(0);
// eslint-disable-next-line rxjs/finnish
readonly appTabSafeArea$ = signal(`calc(${globalVars.appTabSafeArea})`);
static override setup(di: Container) {
@@ -416,7 +416,11 @@
"nm": "虚线",
"v": { "a": 0, "k": 22, "ix": 1 }
},
{ "n": "o", "nm": "偏移", "v": { "a": 0, "k": 0, "ix": 7 } }
{
"n": "o",
"nm": "偏移",
"v": { "a": 0, "k": 0, "ix": 7 }
}
],
"nm": "描边 1",
"mn": "ADBE Vector Graphic - Stroke",
@@ -23643,7 +23647,11 @@
"nm": "虚线",
"v": { "a": 0, "k": 22, "ix": 1 }
},
{ "n": "o", "nm": "偏移", "v": { "a": 0, "k": 0, "ix": 7 } }
{
"n": "o",
"nm": "偏移",
"v": { "a": 0, "k": 0, "ix": 7 }
}
],
"nm": "描边 1",
"mn": "ADBE Vector Graphic - Stroke",
@@ -416,7 +416,11 @@
"nm": "虚线",
"v": { "a": 0, "k": 22, "ix": 1 }
},
{ "n": "o", "nm": "偏移", "v": { "a": 0, "k": 0, "ix": 7 } }
{
"n": "o",
"nm": "偏移",
"v": { "a": 0, "k": 0, "ix": 7 }
}
],
"nm": "描边 1",
"mn": "ADBE Vector Graphic - Stroke",
@@ -23769,7 +23773,11 @@
"nm": "虚线",
"v": { "a": 0, "k": 22, "ix": 1 }
},
{ "n": "o", "nm": "偏移", "v": { "a": 0, "k": 0, "ix": 7 } }
{
"n": "o",
"nm": "偏移",
"v": { "a": 0, "k": 0, "ix": 7 }
}
],
"nm": "描边 1",
"mn": "ADBE Vector Graphic - Stroke",
@@ -212,7 +212,7 @@ export const EdgelessSwitch = ({
{
/* render blocks */
article.blocks.map((block, key) => {
// eslint-disable-next-line react/no-array-index-key
// oxlint-disable-next-line react/no-array-index-key
return <OnboardingBlock key={key} mode={mode} {...block} />;
})
}
@@ -1,4 +1,3 @@
/* eslint-disable rxjs/finnish */
/**
* @vitest-environment happy-dom
*/
@@ -150,7 +150,7 @@ export const TagsEditor = ({
const idx = tagColors.findIndex(c => c.value === color);
return tagColors[(idx + 1) % tagColors.length].value;
},
// eslint-disable-next-line react-hooks/purity
// oxlint-disable-next-line react-hooks-js/purity
tagColors[Math.floor(Math.random() * tagColors.length)].value
);
@@ -95,7 +95,7 @@ export const CheckboxDocListProperty = ({
return (
<StackProperty icon={<CheckBoxCheckLinearIcon />}>
{/*
{/*
Has circular dependency issue (WorkspacePropertyName -> WorkspacePropertyTypes -> Checkbox)
<WorkspacePropertyName propertyInfo={propertyInfo} />
*/}
@@ -130,7 +130,7 @@ export const EdgelessSnapshot = (props: Props) => {
}, [docName, extensions, firstUpdate, updateElements]);
useEffect(() => {
// oxlint-disable-next-line @typescript-eslint/no-floating-promises
// oxlint-disable-next-line typescript/no-floating-promises
renderEditor();
return () => editorHostRef.current?.remove();
}, [renderEditor]);
@@ -69,7 +69,7 @@ export const McpServerSettingPanel = () => {
);
const revalidate = useCallback(() => {
// oxlint-disable-next-line @typescript-eslint/no-floating-promises
// oxlint-disable-next-line typescript/no-floating-promises
credentialsService.revalidate(workspaceId);
}, [credentialsService, workspaceId]);
@@ -73,7 +73,7 @@ export const SelfHostTeamCard = () => {
license?.expiredAt || 0
).toLocaleDateString(),
leftDays: Math.floor(
// eslint-disable-next-line react-hooks/purity
// oxlint-disable-next-line react-hooks-js/purity
(new Date(license?.expiredAt || 0).getTime() - Date.now()) /
(1000 * 60 * 60 * 24)
).toLocaleString(),
@@ -6,7 +6,7 @@ import {
type LoaderFunction,
redirect,
useLoaderData,
// oxlint-disable-next-line @typescript-eslint/no-restricted-imports
// oxlint-disable-next-line typescript/no-restricted-imports
useNavigate,
} from 'react-router-dom';
import { z } from 'zod';
@@ -1,5 +1,3 @@
/* eslint-disable rxjs/finnish */
import { Framework, LiveData } from '@toeverything/infra';
import { Observable, Subject } from 'rxjs';
import { describe, expect, it, vi } from 'vitest';
@@ -269,7 +269,7 @@ const RandomBars = ({ count, header }: { count: number; header?: boolean }) => {
/>
) : null}
{Array.from({ length: count }).map((_, index) => (
// oxlint-disable-next-line eslint-plugin-react(no-array-index-key)
// oxlint-disable-next-line react/no-array-index-key
<RandomBar key={index} />
))}
</div>
@@ -49,13 +49,10 @@ export class WorkspaceDBTable<
create = this.table.create.bind(this.table) as typeof this.table.create;
update = this.table.update.bind(this.table) as typeof this.table.update;
get = this.table.get.bind(this.table) as typeof this.table.get;
// eslint-disable-next-line rxjs/finnish
get$ = this.table.get$.bind(this.table) as typeof this.table.get$;
find = this.table.find.bind(this.table) as typeof this.table.find;
// eslint-disable-next-line rxjs/finnish
find$ = this.table.find$.bind(this.table) as typeof this.table.find$;
select = this.table.select.bind(this.table) as typeof this.table.select;
// eslint-disable-next-line rxjs/finnish
select$ = this.table.select$.bind(this.table) as typeof this.table.select$;
keys = this.table.keys.bind(this.table) as typeof this.table.keys;
delete = this.table.delete.bind(this.table) as typeof this.table.delete;
@@ -1,4 +1,4 @@
/* oxlint-disable @typescript-eslint/no-non-null-assertion */
/* oxlint-disable typescript/no-non-null-assertion */
import { Entity } from '@toeverything/infra';
import type { DesktopApiProvider } from '../provider';
@@ -1,4 +1,4 @@
/* oxlint-disable @typescript-eslint/no-non-null-assertion */
/* oxlint-disable typescript/no-non-null-assertion */
import { apis, appInfo, events, sharedStorage } from '@affine/electron-api';
import { Service } from '@toeverything/infra';
@@ -1,5 +1,3 @@
/* eslint-disable rxjs/finnish */
import { PropertyValue } from '@affine/component';
import { type TagLike, TagsInlineEditor } from '@affine/core/components/tags';
import { TagService } from '@affine/core/modules/tag';
@@ -1,5 +1,4 @@
/** @vitest-environment happy-dom */
/* eslint-disable rxjs/finnish */
import { Framework } from '@toeverything/infra';
import { firstValueFrom, of } from 'rxjs';
@@ -12,7 +12,6 @@ export type Flag<F extends FlagInfo = FlagInfo> = {
? boolean
: boolean | undefined;
set: (value: boolean) => void;
// eslint-disable-next-line rxjs/finnish
$: F['defaultState'] extends boolean
? LiveData<boolean>
: LiveData<boolean> | LiveData<boolean | undefined>;
@@ -58,7 +58,7 @@ export class ImportClipperService extends Service {
workspaceName: string,
clipperInput: ClipperInput
) {
// oxlint-disable-next-line @typescript-eslint/no-non-null-assertion
// oxlint-disable-next-line typescript/no-non-null-assertion
let docId: string | undefined;
const { id: workspaceId } = await this.workspacesService.create(
flavour,
@@ -49,7 +49,7 @@ export class ImportTemplateService extends Service {
docBinary: Uint8Array
// todo: support doc mode on init
) {
// oxlint-disable-next-line @typescript-eslint/no-non-null-assertion
// oxlint-disable-next-line typescript/no-non-null-assertion
let docId: string = null!;
const { id: workspaceId } = await this.workspacesService.create(
flavour,
@@ -27,10 +27,8 @@ export class UserDBTable<Schema extends TableSchemaBuilder> extends Entity<{
create: typeof this.table.create = this.table.create.bind(this.table);
update: typeof this.table.update = this.table.update.bind(this.table);
get: typeof this.table.get = this.table.get.bind(this.table);
// eslint-disable-next-line rxjs/finnish
get$: typeof this.table.get$ = this.table.get$.bind(this.table);
find: typeof this.table.find = this.table.find.bind(this.table);
// eslint-disable-next-line rxjs/finnish
find$: typeof this.table.find$ = this.table.find$.bind(this.table);
keys: typeof this.table.keys = this.table.keys.bind(this.table);
delete: typeof this.table.delete = this.table.delete.bind(this.table);
@@ -57,7 +57,6 @@ export class Workspace extends Entity {
});
return id;
},
/* eslint-disable rxjs/finnish */
blobState$: key => this.engine.blob.blobState$(key),
upload: key => this.engine.blob.upload(key),
name: 'blob',
@@ -15,12 +15,10 @@ type MetaState = {
};
export class WorkspaceMetaImpl implements WorkspaceMeta {
/* eslint-disable rxjs/finnish */
commonFieldsUpdated = new Subject<void>();
docMetaAdded = new Subject<string>();
docMetaRemoved = new Subject<string>();
docMetaUpdated = new Subject<void>();
/* eslint-enable rxjs/finnish */
private readonly _handleDocCollectionMetaEvents = (
events: Y.YEvent<Y.Array<unknown> | Y.Text | Y.Map<unknown>>[]
@@ -47,9 +47,7 @@ export class WorkspaceImpl implements Workspace {
meta: WorkspaceMeta;
slots = {
/* eslint-disable rxjs/finnish */
docListUpdated: new Subject<void>(),
/* eslint-enable rxjs/finnish */
};
get docs() {
@@ -199,7 +199,7 @@ type Events<F> = {
call: (arg: any) => void;
};
// oxlint-disable-next-line @typescript-eslint/no-unsafe-function-type
// oxlint-disable-next-line typescript/no-unsafe-function-type
function createEvents<F extends Function>(): Events<F> {
let handlers: F[] = [];