mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-08-12 14:40:22 +08:00
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:
@@ -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'
|
||||
|
||||
+11
-7
@@ -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>`;
|
||||
}
|
||||
|
||||
+10
-8
@@ -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
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
+9
-7
@@ -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;
|
||||
|
||||
+17
-13
@@ -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>`;
|
||||
}
|
||||
}
|
||||
|
||||
+56
-46
@@ -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>`;
|
||||
}
|
||||
|
||||
+8
-6
@@ -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`
|
||||
|
||||
+74
-68
@@ -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
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
+12
-10
@@ -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}
|
||||
|
||||
+5
-3
@@ -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>`;
|
||||
}
|
||||
|
||||
|
||||
+5
-3
@@ -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`;
|
||||
}
|
||||
}
|
||||
|
||||
+11
-7
@@ -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}
|
||||
|
||||
+27
-23
@@ -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>`;
|
||||
}
|
||||
|
||||
|
||||
+5
-3
@@ -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">
|
||||
|
||||
+47
-37
@@ -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
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
+30
-24
@@ -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
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
+10
-8
@@ -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
|
||||
);
|
||||
|
||||
|
||||
+1
-1
@@ -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) {
|
||||
|
||||
+43
-39
@@ -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>
|
||||
`;
|
||||
|
||||
+6
-5
@@ -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),
|
||||
}),
|
||||
|
||||
-4
@@ -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) {
|
||||
|
||||
+10
-2
@@ -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",
|
||||
|
||||
+10
-2
@@ -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} />
|
||||
*/}
|
||||
|
||||
+1
-1
@@ -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]);
|
||||
|
||||
+1
-1
@@ -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]);
|
||||
|
||||
|
||||
+1
-1
@@ -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';
|
||||
|
||||
-2
@@ -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[] = [];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user