mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-08-11 22:18:54 +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
-1
@@ -1,5 +1,5 @@
|
||||
/* auto-generated by NAPI-RS */
|
||||
/* eslint-disable */
|
||||
/* oxlint-disable */
|
||||
|
||||
declare const _default: typeof import('./index')
|
||||
export default _default
|
||||
|
||||
Vendored
+1
-1
@@ -1,5 +1,5 @@
|
||||
/* auto-generated by NAPI-RS */
|
||||
/* eslint-disable */
|
||||
/* oxlint-disable */
|
||||
|
||||
declare const _default: typeof import('./index')
|
||||
export default _default
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* eslint-disable */
|
||||
/* oxlint-disable */
|
||||
import '../src/prelude';
|
||||
import '../src/app.module';
|
||||
|
||||
|
||||
@@ -261,7 +261,7 @@ export class AuthGuard implements CanActivate, OnModuleInit {
|
||||
|
||||
private getVersionRange(versionRange: string): semver.Range | null {
|
||||
if (this.cachedVersionRange.has(versionRange)) {
|
||||
// oxlint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
// oxlint-disable-next-line typescript/no-non-null-assertion
|
||||
return this.cachedVersionRange.get(versionRange)!;
|
||||
}
|
||||
|
||||
|
||||
@@ -132,7 +132,7 @@ export class AuthService implements OnApplicationBootstrap {
|
||||
// fallback to the first valid session if user provided userId is invalid
|
||||
if (!userSession) {
|
||||
// checked
|
||||
// oxlint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
// oxlint-disable-next-line typescript/no-non-null-assertion
|
||||
userSession = sessions.at(-1)!;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ export class Lock {
|
||||
private release: () => void = () => {};
|
||||
|
||||
async acquire() {
|
||||
// oxlint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
// oxlint-disable-next-line typescript/no-non-null-assertion
|
||||
let release: () => void = null!;
|
||||
const nextLock = new Promise<void>(resolve => {
|
||||
release = resolve;
|
||||
|
||||
@@ -35,7 +35,7 @@ export class DocID {
|
||||
return this.variant === DocVariant.Workspace
|
||||
? this.workspace
|
||||
: // sub is always truthy when variant is not workspace
|
||||
// oxlint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
// oxlint-disable-next-line typescript/no-non-null-assertion
|
||||
this.sub!;
|
||||
}
|
||||
|
||||
|
||||
@@ -165,7 +165,7 @@ function fetchContent(
|
||||
|
||||
if (Array.isArray(content.props.children)) {
|
||||
return content.props.children.map((child, i) => {
|
||||
/* oxlint-disable-next-line eslint-plugin-react/no-array-index-key */
|
||||
/* oxlint-disable-next-line react/no-array-index-key */
|
||||
return <Row key={i}>{child}</Row>;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -351,7 +351,7 @@ export class CopilotTranscriptionResolver {
|
||||
user.id,
|
||||
workspaceId,
|
||||
blobId,
|
||||
// oxlint-disable-next-line @typescript-eslint/await-thenable
|
||||
// oxlint-disable-next-line typescript/await-thenable
|
||||
await Promise.all(allBlobs),
|
||||
input ?? undefined
|
||||
);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
hooks:
|
||||
afterOneFileWrite:
|
||||
- prettier --write
|
||||
- oxfmt --write
|
||||
config:
|
||||
strict: true
|
||||
maybeValue: T | null
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
"@graphql-codegen/typescript": "^5.0.9",
|
||||
"@graphql-codegen/typescript-operations": "^5.0.9",
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"prettier": "^3.7.4",
|
||||
"oxfmt": "0.63.0",
|
||||
"vitest": "^4.1.8"
|
||||
},
|
||||
"scripts": {
|
||||
|
||||
@@ -64,7 +64,7 @@ export abstract class FrameworkProvider {
|
||||
|
||||
createEntity = <
|
||||
T extends Entity<any>,
|
||||
Props extends T extends Component<infer P> ? P : never,
|
||||
Props extends (T extends Component<infer P> ? P : never),
|
||||
>(
|
||||
identifier: GeneralIdentifier<T>,
|
||||
...[props]: Props extends Record<string, never> ? [] : [Props]
|
||||
@@ -78,7 +78,7 @@ export abstract class FrameworkProvider {
|
||||
|
||||
createScope = <
|
||||
T extends Scope<any>,
|
||||
Props extends T extends Component<infer P> ? P : never,
|
||||
Props extends (T extends Component<infer P> ? P : never),
|
||||
>(
|
||||
root: GeneralIdentifier<T>,
|
||||
...[props]: Props extends Record<string, never> ? [] : [Props]
|
||||
|
||||
@@ -514,7 +514,7 @@ export class LiveData<T = unknown>
|
||||
const subscription = this.subscribe(v => {
|
||||
if (predicate(v)) {
|
||||
resolve(v as any);
|
||||
// oxlint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
// oxlint-disable-next-line typescript/no-floating-promises
|
||||
Promise.resolve().then(() => {
|
||||
subscription.unsubscribe();
|
||||
});
|
||||
@@ -552,7 +552,7 @@ export class LiveData<T = unknown>
|
||||
throw this.poisonedError;
|
||||
}
|
||||
this.ops$.next('watch');
|
||||
// oxlint-disable-next-line @typescript-eslint/no-floating-promises -- never throw
|
||||
// oxlint-disable-next-line typescript/no-floating-promises -- never throw
|
||||
Promise.resolve().then(() => {
|
||||
this.ops$.next('unwatch');
|
||||
});
|
||||
|
||||
@@ -27,25 +27,29 @@ type Typeof<F extends FieldSchemaBuilder> =
|
||||
F extends FieldSchemaBuilder<infer Type> ? Type : never;
|
||||
|
||||
type RequiredFields<T extends TableSchemaBuilder> = {
|
||||
[K in TableDefinedFieldNames<T> as T[K] extends FieldSchemaBuilder<
|
||||
any,
|
||||
infer Optional
|
||||
>
|
||||
? Optional extends false
|
||||
? K
|
||||
[
|
||||
K in TableDefinedFieldNames<T> as T[K] extends FieldSchemaBuilder<
|
||||
any,
|
||||
infer Optional
|
||||
>
|
||||
? Optional extends false
|
||||
? K
|
||||
: never
|
||||
: never
|
||||
: never]: Typeof<T[K]>;
|
||||
]: Typeof<T[K]>;
|
||||
};
|
||||
|
||||
type OptionalFields<T extends TableSchemaBuilder> = {
|
||||
[K in TableDefinedFieldNames<T> as T[K] extends FieldSchemaBuilder<
|
||||
any,
|
||||
infer Optional
|
||||
>
|
||||
? Optional extends true
|
||||
? K
|
||||
[
|
||||
K in TableDefinedFieldNames<T> as T[K] extends FieldSchemaBuilder<
|
||||
any,
|
||||
infer Optional
|
||||
>
|
||||
? Optional extends true
|
||||
? K
|
||||
: never
|
||||
: never
|
||||
: never]?: Typeof<T[K]> | null;
|
||||
]?: Typeof<T[K]> | null;
|
||||
};
|
||||
|
||||
type PrimaryKeyField<T extends TableSchemaBuilder> = {
|
||||
@@ -104,7 +108,9 @@ export type UpdateEntityInput<T extends TableSchemaBuilder> = Pretty<
|
||||
MaybeDocumentEntityWrapper<
|
||||
T,
|
||||
{
|
||||
[key in NonPrimaryKeyFieldNames<T>]?: key extends keyof TableDefinedEntity<T>
|
||||
[
|
||||
key in NonPrimaryKeyFieldNames<T>
|
||||
]?: key extends keyof TableDefinedEntity<T>
|
||||
? TableDefinedEntity<T>[key]
|
||||
: never;
|
||||
}
|
||||
@@ -115,7 +121,9 @@ export type FindEntityInput<T extends TableSchemaBuilder> = Pretty<
|
||||
MaybeDocumentEntityWrapper<
|
||||
T,
|
||||
{
|
||||
[key in TableDefinedFieldNames<T>]?: key extends keyof TableDefinedEntity<T>
|
||||
[
|
||||
key in TableDefinedFieldNames<T>
|
||||
]?: key extends keyof TableDefinedEntity<T>
|
||||
?
|
||||
| TableDefinedEntity<T>[key]
|
||||
| { not: TableDefinedEntity<T>[key] | null }
|
||||
|
||||
@@ -30,14 +30,21 @@ import type { ConnectionStatus } from '@affine/nbstore';
|
||||
import { IndexedDBDocStorage } from '@affine/nbstore/idb';
|
||||
import { SqliteBlobStorage } from '@affine/nbstore/sqlite';
|
||||
|
||||
const storage = new SpaceStorage([new IndexedDBDocStorage({}), new SqliteBlobStorage({})]);
|
||||
const storage = new SpaceStorage([
|
||||
new IndexedDBDocStorage({}),
|
||||
new SqliteBlobStorage({}),
|
||||
]);
|
||||
|
||||
await storage.connect();
|
||||
storage.on('connection', ({ storage, status, error }) => {
|
||||
ui.show(storage, status, error);
|
||||
});
|
||||
|
||||
await storage.get('doc').pushDocUpdate({ docId: 'my-first-doc', bin: new Uint8Array(), editor: 'me' });
|
||||
await storage.get('doc').pushDocUpdate({
|
||||
docId: 'my-first-doc',
|
||||
bin: new Uint8Array(),
|
||||
editor: 'me',
|
||||
});
|
||||
await storage.tryGet('blob')?.get('img');
|
||||
```
|
||||
|
||||
@@ -61,7 +68,11 @@ client.ob$('connection', ({ storage, status, error }) => {
|
||||
ui.show(storage, status, error);
|
||||
});
|
||||
|
||||
await client.call('pushDocUpdate', { docId: 'my-first-doc', bin: new Uint8Array(), editor: 'me' });
|
||||
await client.call('pushDocUpdate', {
|
||||
docId: 'my-first-doc',
|
||||
bin: new Uint8Array(),
|
||||
editor: 'me',
|
||||
});
|
||||
|
||||
// call unregistered op will leads to Error
|
||||
// Error { message: 'Handler for operation [listHistory] is not registered.' }
|
||||
|
||||
@@ -52,7 +52,7 @@ export class NGramTokenizer implements Tokenizer {
|
||||
|
||||
tokenize(text: string): Token[] {
|
||||
const splitted: Token[] = [];
|
||||
for (let i = 0; i < text.length; ) {
|
||||
for (let i = 0; i < text.length;) {
|
||||
const nextBreak = Graphemer.nextBreak(text, i);
|
||||
const c = text.substring(i, nextBreak);
|
||||
|
||||
@@ -119,7 +119,7 @@ export class GeneralTokenizer implements Tokenizer {
|
||||
let end = 0;
|
||||
let lang: string | null = null;
|
||||
|
||||
for (let i = 0; i < text.length; ) {
|
||||
for (let i = 0; i < text.length;) {
|
||||
const nextBreak = Graphemer.nextBreak(text, i);
|
||||
const c = text.substring(i, nextBreak);
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ export class IndexedDBLocker implements Locker {
|
||||
async lock(domain: string, resource: string) {
|
||||
const key = `${domain}:${resource}`;
|
||||
|
||||
// eslint-disable-next-line no-constant-condition
|
||||
// oxlint-disable-next-line no-constant-condition
|
||||
while (true) {
|
||||
const trx = this.db.transaction('locks', 'readwrite');
|
||||
const record = await trx.store.get(key);
|
||||
|
||||
@@ -26,7 +26,7 @@ export class Lock {
|
||||
private release: () => void = () => {};
|
||||
|
||||
async acquire() {
|
||||
// oxlint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
// oxlint-disable-next-line typescript/no-non-null-assertion
|
||||
let release: () => void = null!;
|
||||
const nextLock = new Promise<void>(resolve => {
|
||||
release = resolve;
|
||||
|
||||
@@ -190,7 +190,7 @@ export class BlobSyncImpl implements BlobSync {
|
||||
): Promise<void> {
|
||||
return Promise.race([
|
||||
Promise.all(
|
||||
// oxlint-disable-next-line @typescript-eslint/await-thenable
|
||||
// oxlint-disable-next-line typescript/await-thenable
|
||||
peerId
|
||||
? [this.fullDownloadPeer(peerId)]
|
||||
: this.peers.map(p => this.fullDownloadPeer(p.peerId))
|
||||
|
||||
@@ -94,7 +94,7 @@ export class BlobSyncPeer {
|
||||
Math.pow(2, attempts - 1) * backoffRetry.delay,
|
||||
backoffRetry.maxDelay
|
||||
);
|
||||
// oxlint-disable-next-line @typescript-eslint/no-misused-promises
|
||||
// oxlint-disable-next-line typescript/no-misused-promises
|
||||
setTimeout(attempt, waitTime);
|
||||
} else {
|
||||
// reach the max retry times, resolve the promise with false
|
||||
@@ -107,7 +107,7 @@ export class BlobSyncPeer {
|
||||
}
|
||||
};
|
||||
|
||||
// oxlint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
// oxlint-disable-next-line typescript/no-floating-promises
|
||||
attempt();
|
||||
})
|
||||
.catch(error => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// eslint-disable
|
||||
// oxlint-disable
|
||||
// @ts-nocheck
|
||||
import { Node } from './utils/node';
|
||||
import { encodeLink } from './utils/url';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// eslint-disable
|
||||
// oxlint-disable
|
||||
// @ts-nocheck
|
||||
import { Node } from './utils/node';
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// eslint-disable
|
||||
// oxlint-disable
|
||||
// @ts-nocheck
|
||||
let id = 0;
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ export function SharedDataTable<TData extends { id: string }, TValue>({
|
||||
setColumnFilters([]);
|
||||
}, [resetFiltersDeps]);
|
||||
|
||||
// eslint-disable-next-line react-hooks/incompatible-library
|
||||
// oxlint-disable-next-line react-hooks-js/incompatible-library
|
||||
const table = useReactTable({
|
||||
data,
|
||||
columns,
|
||||
|
||||
@@ -38,7 +38,7 @@ const CommandInput = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Input>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>
|
||||
>(({ className, ...props }, ref) => (
|
||||
// eslint-disable-next-line react/no-unknown-property
|
||||
// oxlint-disable-next-line react/no-unknown-property
|
||||
<div className="flex items-center px-3 border-b" cmdk-input-wrapper="">
|
||||
<Search className="w-4 h-4 mr-2 opacity-50 shrink-0" />
|
||||
<CommandPrimitive.Input
|
||||
|
||||
@@ -5,5 +5,5 @@ import { createRoot } from 'react-dom/client';
|
||||
|
||||
import { App } from './app';
|
||||
|
||||
// oxlint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
// oxlint-disable-next-line typescript/no-non-null-assertion
|
||||
createRoot(document.getElementById('app')!).render(<App />);
|
||||
|
||||
@@ -323,7 +323,7 @@ export const useExportUsers = () => {
|
||||
});
|
||||
dataToCopy.push(row);
|
||||
});
|
||||
// oxlint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
// oxlint-disable-next-line typescript/no-floating-promises
|
||||
navigator.clipboard.writeText(JSON.stringify(dataToCopy, null, 2));
|
||||
callback?.();
|
||||
},
|
||||
|
||||
@@ -18,7 +18,7 @@ function main() {
|
||||
}
|
||||
|
||||
function mountApp() {
|
||||
// oxlint-disable-next-line typescript-eslint/no-non-null-assertion
|
||||
// oxlint-disable-next-line typescript/no-non-null-assertion
|
||||
const root = document.getElementById('app')!;
|
||||
createRoot(root).render(
|
||||
<StrictMode>
|
||||
|
||||
@@ -98,7 +98,7 @@ export const config = (): BuildOptions => {
|
||||
JSON.stringify(val) ??
|
||||
String(
|
||||
val
|
||||
) /* JSON.stringify(undefined) == undefined, but we need 'undefined' */;
|
||||
); /* JSON.stringify(undefined) == undefined, but we need 'undefined' */
|
||||
return def;
|
||||
},
|
||||
{} as Record<string, string>
|
||||
|
||||
@@ -39,7 +39,7 @@ async function getWorkspaceDB(spaceType: SpaceType, id: string) {
|
||||
process.on('beforeExit', cleanup);
|
||||
}
|
||||
|
||||
// oxlint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
// oxlint-disable-next-line typescript/no-non-null-assertion
|
||||
return db!;
|
||||
}
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ if (overrideSession) {
|
||||
app.setPath('sessionData', userDataPath);
|
||||
}
|
||||
|
||||
// oxlint-disable-next-line @typescript-eslint/no-var-requires
|
||||
// oxlint-disable-next-line typescript/no-var-requires
|
||||
if (require('electron-squirrel-startup')) app.quit();
|
||||
|
||||
if (process.env.SKIP_ONBOARDING) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// eslint-disable no-var-requires
|
||||
// oxlint-disable typescript/no-var-requires
|
||||
|
||||
// Should not load @affine/native for unsupported platforms
|
||||
|
||||
|
||||
@@ -132,7 +132,6 @@ function createWorkspaceRef() {
|
||||
parentId?: string
|
||||
) => string;
|
||||
getBlock: (id: string) => MockBlockRecord;
|
||||
// eslint-disable-next-line rxjs/finnish
|
||||
getBlock$: (id: string) => MockBlockRecord;
|
||||
};
|
||||
const attachments: Array<{
|
||||
@@ -180,7 +179,6 @@ function createWorkspaceRef() {
|
||||
addBlock: (...args: Parameters<typeof blockSuiteDoc.addBlock>) =>
|
||||
blockSuiteDoc.addBlock(...args),
|
||||
getBlock: (blockId: string) => blockSuiteDoc.getBlock(blockId),
|
||||
// eslint-disable-next-line rxjs/finnish
|
||||
getBlock$: (blockId: string) => blockSuiteDoc.getBlock(blockId),
|
||||
},
|
||||
};
|
||||
|
||||
@@ -87,7 +87,7 @@ Follow the guidelines in `AGENTS.md`:
|
||||
### Testing and Quality
|
||||
|
||||
- TypeScript strict mode enabled
|
||||
- ESLint/Prettier configuration from workspace root
|
||||
- Oxlint/Oxfmt configuration from workspace root
|
||||
- No specific test commands in this package (tests likely in workspace root)
|
||||
|
||||
# Swift Code Style Guidelines
|
||||
|
||||
@@ -13,7 +13,7 @@ import { NbStoreNativeDBApis } from './plugins/nbstore';
|
||||
bindNativeDBApis(NbStoreNativeDBApis);
|
||||
|
||||
function mountApp() {
|
||||
// oxlint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
// oxlint-disable-next-line typescript/no-non-null-assertion
|
||||
const root = document.getElementById('app')!;
|
||||
createRoot(root).render(
|
||||
<StrictMode>
|
||||
|
||||
@@ -7,7 +7,7 @@ import { createRoot } from 'react-dom/client';
|
||||
import { App } from './app';
|
||||
|
||||
function mountApp() {
|
||||
// oxlint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
// oxlint-disable-next-line typescript/no-non-null-assertion
|
||||
const root = document.getElementById('app')!;
|
||||
createRoot(root).render(
|
||||
<StrictMode>
|
||||
|
||||
@@ -216,7 +216,7 @@ export const OnboardingPage = ({
|
||||
],
|
||||
};
|
||||
|
||||
// oxlint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
// oxlint-disable-next-line typescript/no-floating-promises
|
||||
fetch('/api/worker/questionnaire', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(answer),
|
||||
|
||||
@@ -12,7 +12,6 @@ import {
|
||||
useState,
|
||||
} from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
|
||||
const UniReactNode = memo(
|
||||
function UniReactNode(props: {
|
||||
ele: HTMLElement;
|
||||
|
||||
@@ -45,7 +45,7 @@ const HeaderLayout = memo(function HeaderLayout({
|
||||
const isRight = index === length - 1;
|
||||
return (
|
||||
<div
|
||||
// eslint-disable-next-line react/no-array-index-key
|
||||
// oxlint-disable-next-line react/no-array-index-key
|
||||
key={index}
|
||||
data-length={length}
|
||||
data-is-left={isLeft}
|
||||
|
||||
@@ -136,7 +136,7 @@ export const YearPicker = memo(function YearPicker(
|
||||
<div className={styles.decadeViewBody}>
|
||||
{matrix.map((row, i) => {
|
||||
return (
|
||||
// eslint-disable-next-line react/no-array-index-key
|
||||
// oxlint-disable-next-line react/no-array-index-key
|
||||
<div key={i} className={styles.decadeViewRow}>
|
||||
{row.map(year => {
|
||||
const isDisabled =
|
||||
|
||||
@@ -48,10 +48,12 @@ export type toExternalData<D extends DNDData> = (
|
||||
args: DraggableGetFeedbackArgs,
|
||||
data?: DraggableGet<D['draggable']>
|
||||
) => {
|
||||
[Key in
|
||||
| 'text/uri-list'
|
||||
| 'text/plain'
|
||||
| 'text/html'
|
||||
| 'Files'
|
||||
| (string & {})]?: string;
|
||||
[
|
||||
Key in
|
||||
| 'text/uri-list'
|
||||
| 'text/plain'
|
||||
| 'text/html'
|
||||
| 'Files'
|
||||
| (string & {})
|
||||
]?: string;
|
||||
};
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user