mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-05 09:04:56 +00:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a579cc7716 | ||
|
|
b993ab04df | ||
|
|
eef9afd3ed | ||
|
|
06d5d9719c | ||
|
|
f8e51112aa | ||
|
|
e8d5692062 | ||
|
|
d2b0ee40a8 | ||
|
|
3ad5170b71 | ||
|
|
8209e84842 | ||
|
|
fc19180451 | ||
|
|
009b5353b1 | ||
|
|
4beedaa22c | ||
|
|
26fd9a4a1c | ||
|
|
b2c00a2618 | ||
|
|
85637156f6 |
2
.github/helm/affine/Chart.yaml
vendored
2
.github/helm/affine/Chart.yaml
vendored
@@ -3,4 +3,4 @@ name: affine
|
||||
description: AFFiNE cloud chart
|
||||
type: application
|
||||
version: 0.0.0
|
||||
appVersion: "0.15.0"
|
||||
appVersion: "0.16.0"
|
||||
|
||||
@@ -3,7 +3,7 @@ name: graphql
|
||||
description: AFFiNE GraphQL server
|
||||
type: application
|
||||
version: 0.0.0
|
||||
appVersion: "0.15.0"
|
||||
appVersion: "0.16.0"
|
||||
dependencies:
|
||||
- name: gcloud-sql-proxy
|
||||
version: 0.0.0
|
||||
|
||||
2
.github/helm/affine/charts/sync/Chart.yaml
vendored
2
.github/helm/affine/charts/sync/Chart.yaml
vendored
@@ -3,7 +3,7 @@ name: sync
|
||||
description: AFFiNE Sync Server
|
||||
type: application
|
||||
version: 0.0.0
|
||||
appVersion: "0.15.0"
|
||||
appVersion: "0.16.0"
|
||||
dependencies:
|
||||
- name: gcloud-sql-proxy
|
||||
version: 0.0.0
|
||||
|
||||
@@ -19,5 +19,5 @@
|
||||
],
|
||||
"ext": "ts,md,json"
|
||||
},
|
||||
"version": "0.15.0"
|
||||
"version": "0.16.0"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@affine/monorepo",
|
||||
"version": "0.15.0",
|
||||
"version": "0.16.0",
|
||||
"private": true,
|
||||
"author": "toeverything",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@affine/server-native",
|
||||
"version": "0.15.0",
|
||||
"version": "0.16.0",
|
||||
"engines": {
|
||||
"node": ">= 10.16.0 < 11 || >= 11.8.0"
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@affine/server",
|
||||
"private": true,
|
||||
"version": "0.15.0",
|
||||
"version": "0.16.0",
|
||||
"description": "Affine Node.js server",
|
||||
"type": "module",
|
||||
"bin": {
|
||||
|
||||
@@ -9,5 +9,5 @@
|
||||
"@types/debug": "^4.1.12",
|
||||
"vitest": "1.6.0"
|
||||
},
|
||||
"version": "0.15.0"
|
||||
"version": "0.16.0"
|
||||
}
|
||||
|
||||
2
packages/common/env/package.json
vendored
2
packages/common/env/package.json
vendored
@@ -26,5 +26,5 @@
|
||||
"lit": "^3.1.2",
|
||||
"zod": "^3.22.4"
|
||||
},
|
||||
"version": "0.15.0"
|
||||
"version": "0.16.0"
|
||||
}
|
||||
|
||||
@@ -73,5 +73,5 @@
|
||||
"optional": true
|
||||
}
|
||||
},
|
||||
"version": "0.15.0"
|
||||
"version": "0.16.0"
|
||||
}
|
||||
|
||||
@@ -34,6 +34,8 @@ export class Workspace extends Entity {
|
||||
},
|
||||
idGenerator: () => nanoid(),
|
||||
schema: globalBlockSuiteSchema,
|
||||
disableBacklinkIndex: true,
|
||||
disableSearchIndex: true,
|
||||
});
|
||||
}
|
||||
return this._docCollection;
|
||||
|
||||
@@ -61,6 +61,8 @@ export class TestingWorkspaceLocalProvider
|
||||
blobSources: {
|
||||
main: blobStorage,
|
||||
},
|
||||
disableBacklinkIndex: true,
|
||||
disableSearchIndex: true,
|
||||
});
|
||||
|
||||
// apply initial state
|
||||
@@ -95,6 +97,8 @@ export class TestingWorkspaceLocalProvider
|
||||
const bs = new DocCollection({
|
||||
id,
|
||||
schema: globalBlockSuiteSchema,
|
||||
disableBacklinkIndex: true,
|
||||
disableSearchIndex: true,
|
||||
});
|
||||
|
||||
applyUpdate(bs.doc, data);
|
||||
|
||||
@@ -178,11 +178,13 @@ export class FullTextInvertedIndex implements InvertedIndex {
|
||||
const queryTokens = new GeneralTokenizer().tokenize(term);
|
||||
const matched = new Map<
|
||||
number,
|
||||
{
|
||||
score: number;
|
||||
index: number;
|
||||
ranges: [number, number][];
|
||||
}
|
||||
Map<
|
||||
number, // index
|
||||
{
|
||||
score: number;
|
||||
ranges: [number, number][];
|
||||
}
|
||||
>
|
||||
>();
|
||||
for (const token of queryTokens) {
|
||||
const key = InvertedIndexKey.forString(this.fieldKey, token.term);
|
||||
@@ -251,20 +253,42 @@ export class FullTextInvertedIndex implements InvertedIndex {
|
||||
maxScore === minScore
|
||||
? score
|
||||
: (score - minScore) / (maxScore - minScore);
|
||||
const match = matched.get(nid);
|
||||
if (!match || normalizedScore > match.score) {
|
||||
matched.set(nid, {
|
||||
score: normalizedScore,
|
||||
index: position.index,
|
||||
ranges: position.ranges,
|
||||
});
|
||||
}
|
||||
const match =
|
||||
matched.get(nid) ??
|
||||
new Map<
|
||||
number, // index
|
||||
{
|
||||
score: number;
|
||||
ranges: [number, number][];
|
||||
}
|
||||
>();
|
||||
const item = match.get(position.index) || {
|
||||
score: 0,
|
||||
ranges: [],
|
||||
};
|
||||
item.score += normalizedScore;
|
||||
item.ranges.push(...position.ranges);
|
||||
match.set(position.index, item);
|
||||
matched.set(nid, match);
|
||||
}
|
||||
}
|
||||
const match = new Match();
|
||||
for (const [nid, { score, index, ranges }] of matched) {
|
||||
match.addScore(nid, score);
|
||||
match.addHighlighter(nid, this.fieldKey, index, ranges);
|
||||
for (const [nid, items] of matched) {
|
||||
if (items.size === 0) {
|
||||
break;
|
||||
}
|
||||
let highestScore = -1;
|
||||
let highestIndex = -1;
|
||||
let highestRanges: [number, number][] = [];
|
||||
for (const [index, { score, ranges }] of items) {
|
||||
if (score > highestScore) {
|
||||
highestScore = score;
|
||||
highestIndex = index;
|
||||
highestRanges = ranges;
|
||||
}
|
||||
}
|
||||
match.addScore(nid, highestScore);
|
||||
match.addHighlighter(nid, this.fieldKey, highestIndex, highestRanges);
|
||||
}
|
||||
return match;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@affine/admin",
|
||||
"version": "0.15.0",
|
||||
"version": "0.16.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@affine/core": "workspace:*",
|
||||
|
||||
@@ -110,5 +110,5 @@
|
||||
"vite": "^5.2.8",
|
||||
"vitest": "1.6.0"
|
||||
},
|
||||
"version": "0.15.0"
|
||||
"version": "0.16.0"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { KeyboardEvent } from 'react';
|
||||
import type { KeyboardEvent, ReactElement } from 'react';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
|
||||
import Input from '../../ui/input';
|
||||
@@ -8,12 +8,16 @@ export const RenameModal = ({
|
||||
onRename,
|
||||
currentName,
|
||||
open,
|
||||
width = 220,
|
||||
children,
|
||||
onOpenChange,
|
||||
}: {
|
||||
open: boolean;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
onRename: (newName: string) => void;
|
||||
currentName: string;
|
||||
width?: string | number;
|
||||
children?: ReactElement;
|
||||
}) => {
|
||||
const [value, setValue] = useState(currentName);
|
||||
|
||||
@@ -56,11 +60,11 @@ export const RenameModal = ({
|
||||
onEnter={handleRename}
|
||||
onKeyDown={onKeyDown}
|
||||
data-testid="rename-modal-input"
|
||||
style={{ width: 220, height: 34, borderRadius: 4 }}
|
||||
style={{ width, height: 34, borderRadius: 4 }}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<div></div>
|
||||
{children ?? <div />}
|
||||
</Menu>
|
||||
);
|
||||
};
|
||||
|
||||
33
packages/frontend/component/src/hooks/focus-and-select.ts
Normal file
33
packages/frontend/component/src/hooks/focus-and-select.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { useLayoutEffect, useRef } from 'react';
|
||||
|
||||
export const useAutoFocus = <T extends HTMLElement = HTMLElement>(
|
||||
autoFocus?: boolean
|
||||
) => {
|
||||
const ref = useRef<T | null>(null);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (ref.current && autoFocus) {
|
||||
// to avoid clicking on something focusable(e.g MenuItem),
|
||||
// then the input will not be focused
|
||||
setTimeout(() => {
|
||||
ref.current?.focus();
|
||||
}, 0);
|
||||
}
|
||||
}, [autoFocus]);
|
||||
|
||||
return ref;
|
||||
};
|
||||
|
||||
export const useAutoSelect = <T extends HTMLInputElement = HTMLInputElement>(
|
||||
autoSelect?: boolean
|
||||
) => {
|
||||
const ref = useAutoFocus<T>(autoSelect);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (ref.current && autoSelect) {
|
||||
ref.current?.select();
|
||||
}
|
||||
}, [autoSelect, ref]);
|
||||
|
||||
return ref;
|
||||
};
|
||||
1
packages/frontend/component/src/hooks/index.ts
Normal file
1
packages/frontend/component/src/hooks/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { useAutoFocus, useAutoSelect } from './focus-and-select';
|
||||
@@ -7,6 +7,7 @@ import type {
|
||||
} from 'react';
|
||||
import { cloneElement, forwardRef, useCallback } from 'react';
|
||||
|
||||
import { useAutoFocus } from '../../hooks';
|
||||
import { Loading } from '../loading';
|
||||
import { Tooltip, type TooltipProps } from '../tooltip';
|
||||
import * as styles from './button.css';
|
||||
@@ -120,12 +121,15 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
tooltip,
|
||||
tooltipShortcut,
|
||||
tooltipOptions,
|
||||
autoFocus,
|
||||
onClick,
|
||||
|
||||
...otherProps
|
||||
},
|
||||
ref
|
||||
upstreamRef
|
||||
) => {
|
||||
const ref = useAutoFocus<HTMLButtonElement>(autoFocus);
|
||||
|
||||
const handleClick = useCallback(
|
||||
(e: MouseEvent<HTMLButtonElement>) => {
|
||||
if (loading || disabled) return;
|
||||
@@ -134,11 +138,22 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
[disabled, loading, onClick]
|
||||
);
|
||||
|
||||
const buttonRef = (el: HTMLButtonElement | null) => {
|
||||
ref.current = el;
|
||||
if (upstreamRef) {
|
||||
if (typeof upstreamRef === 'function') {
|
||||
upstreamRef(el);
|
||||
} else {
|
||||
upstreamRef.current = el;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Tooltip content={tooltip} shortcut={tooltipShortcut} {...tooltipOptions}>
|
||||
<button
|
||||
{...otherProps}
|
||||
ref={ref}
|
||||
ref={buttonRef}
|
||||
className={clsx(styles.button, className)}
|
||||
data-loading={loading || undefined}
|
||||
data-block={block || undefined}
|
||||
|
||||
@@ -8,14 +8,9 @@ import type {
|
||||
KeyboardEventHandler,
|
||||
ReactNode,
|
||||
} from 'react';
|
||||
import {
|
||||
forwardRef,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useLayoutEffect,
|
||||
useRef,
|
||||
} from 'react';
|
||||
import { forwardRef, useCallback, useEffect } from 'react';
|
||||
|
||||
import { useAutoFocus, useAutoSelect } from '../../hooks';
|
||||
import { input, inputWrapper } from './style.css';
|
||||
|
||||
export type InputProps = {
|
||||
@@ -55,30 +50,31 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(function Input(
|
||||
}: InputProps,
|
||||
upstreamRef: ForwardedRef<HTMLInputElement>
|
||||
) {
|
||||
const inputRef = useRef<HTMLInputElement | null>(null);
|
||||
useLayoutEffect(() => {
|
||||
if (inputRef.current && (autoFocus || autoSelect)) {
|
||||
// to avoid clicking on something focusable(e.g MenuItem),
|
||||
// then the input will not be focused
|
||||
setTimeout(() => {
|
||||
inputRef.current?.focus();
|
||||
}, 0);
|
||||
if (autoSelect) {
|
||||
inputRef.current?.select();
|
||||
const focusRef = useAutoFocus<HTMLInputElement>(autoFocus);
|
||||
const selectRef = useAutoSelect<HTMLInputElement>(autoSelect);
|
||||
|
||||
const inputRef = (el: HTMLInputElement | null) => {
|
||||
focusRef.current = el;
|
||||
selectRef.current = el;
|
||||
if (upstreamRef) {
|
||||
if (typeof upstreamRef === 'function') {
|
||||
upstreamRef(el);
|
||||
} else {
|
||||
upstreamRef.current = el;
|
||||
}
|
||||
}
|
||||
}, [autoFocus, autoSelect, upstreamRef]);
|
||||
};
|
||||
|
||||
// use native blur event to get event after unmount
|
||||
// don't use useLayoutEffect here, because the cleanup function will be called before unmount
|
||||
useEffect(() => {
|
||||
if (!onBlur) return;
|
||||
inputRef.current?.addEventListener('blur', onBlur as any);
|
||||
selectRef.current?.addEventListener('blur', onBlur as any);
|
||||
return () => {
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
inputRef.current?.removeEventListener('blur', onBlur as any);
|
||||
selectRef.current?.removeEventListener('blur', onBlur as any);
|
||||
};
|
||||
}, [onBlur]);
|
||||
}, [onBlur, selectRef]);
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -105,16 +101,7 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(function Input(
|
||||
large: size === 'large',
|
||||
'extra-large': size === 'extraLarge',
|
||||
})}
|
||||
ref={ref => {
|
||||
inputRef.current = ref;
|
||||
if (upstreamRef) {
|
||||
if (typeof upstreamRef === 'function') {
|
||||
upstreamRef(ref);
|
||||
} else {
|
||||
upstreamRef.current = ref;
|
||||
}
|
||||
}
|
||||
}}
|
||||
ref={inputRef}
|
||||
disabled={disabled}
|
||||
style={inputStyle}
|
||||
onChange={useCallback(
|
||||
|
||||
@@ -17,6 +17,11 @@ export interface ConfirmModalProps extends ModalProps {
|
||||
cancelText?: React.ReactNode;
|
||||
cancelButtonOptions?: Omit<ButtonProps, 'children'>;
|
||||
reverseFooter?: boolean;
|
||||
/**
|
||||
* Auto focus on confirm button when modal opened
|
||||
* @default true
|
||||
*/
|
||||
autoFocusConfirm?: boolean;
|
||||
}
|
||||
|
||||
export const ConfirmModal = ({
|
||||
@@ -30,6 +35,7 @@ export const ConfirmModal = ({
|
||||
onConfirm,
|
||||
onCancel,
|
||||
width = 480,
|
||||
autoFocusConfirm = true,
|
||||
...props
|
||||
}: ConfirmModalProps) => {
|
||||
const onConfirmClick = useCallback(() => {
|
||||
@@ -73,6 +79,7 @@ export const ConfirmModal = ({
|
||||
<Button
|
||||
onClick={onConfirmClick}
|
||||
data-testid="confirm-modal-confirm"
|
||||
autoFocus={autoFocusConfirm}
|
||||
{...confirmButtonOptions}
|
||||
>
|
||||
{confirmText}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "@affine/core",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"version": "0.15.0",
|
||||
"version": "0.16.0",
|
||||
"exports": {
|
||||
"./app": "./src/app.tsx",
|
||||
"./router": "./src/router.tsx",
|
||||
|
||||
@@ -213,7 +213,12 @@ export class AISlidesRenderer extends WithDisposable(LitElement) {
|
||||
super.connectedCallback();
|
||||
|
||||
const schema = new Schema().register(AffineSchemas);
|
||||
const collection = new DocCollection({ schema, id: 'SLIDES_PREVIEW' });
|
||||
const collection = new DocCollection({
|
||||
schema,
|
||||
id: 'SLIDES_PREVIEW',
|
||||
disableBacklinkIndex: true,
|
||||
disableSearchIndex: true,
|
||||
});
|
||||
collection.meta.initialize();
|
||||
collection.start();
|
||||
const doc = collection.createDoc();
|
||||
|
||||
@@ -187,7 +187,11 @@ export async function replaceFromMarkdown(
|
||||
export async function markDownToDoc(host: EditorHost, answer: string) {
|
||||
const schema = host.std.doc.collection.schema;
|
||||
// Should not create a new doc in the original collection
|
||||
const collection = new DocCollection({ schema });
|
||||
const collection = new DocCollection({
|
||||
schema,
|
||||
disableBacklinkIndex: true,
|
||||
disableSearchIndex: true,
|
||||
});
|
||||
collection.meta.initialize();
|
||||
const job = new Job({
|
||||
collection,
|
||||
|
||||
@@ -109,6 +109,8 @@ const getOrCreateShellWorkspace = (workspaceId: string) => {
|
||||
main: blobStorage,
|
||||
},
|
||||
schema: globalBlockSuiteSchema,
|
||||
disableBacklinkIndex: true,
|
||||
disableSearchIndex: true,
|
||||
});
|
||||
docCollectionMap.set(workspaceId, docCollection);
|
||||
docCollection.doc.emit('sync', [true, docCollection.doc]);
|
||||
|
||||
@@ -60,7 +60,7 @@ export const AIPlan = () => {
|
||||
) : (
|
||||
<>
|
||||
<AISubscribe
|
||||
className={styles.learnAIButton}
|
||||
className={styles.purchaseButton}
|
||||
displayedFrequency="monthly"
|
||||
/>
|
||||
<a href="https://ai.affine.pro" target="_blank" rel="noreferrer">
|
||||
|
||||
@@ -308,18 +308,20 @@ export const PageHeaderMenuButton = ({
|
||||
{t['com.affine.workbench.tab.page-menu-open']()}
|
||||
</MenuItem>
|
||||
|
||||
<MenuItem
|
||||
preFix={
|
||||
<MenuIcon>
|
||||
<SplitViewIcon />
|
||||
</MenuIcon>
|
||||
}
|
||||
data-testid="editor-option-menu-open-in-split-new"
|
||||
onSelect={handleOpenInSplitView}
|
||||
style={menuItemStyle}
|
||||
>
|
||||
{t['com.affine.workbench.split-view.page-menu-open']()}
|
||||
</MenuItem>
|
||||
{environment.isDesktop && (
|
||||
<MenuItem
|
||||
preFix={
|
||||
<MenuIcon>
|
||||
<SplitViewIcon />
|
||||
</MenuIcon>
|
||||
}
|
||||
data-testid="editor-option-menu-open-in-split-new"
|
||||
onSelect={handleOpenInSplitView}
|
||||
style={menuItemStyle}
|
||||
>
|
||||
{t['com.affine.workbench.split-view.page-menu-open']()}
|
||||
</MenuItem>
|
||||
)}
|
||||
|
||||
<MenuSeparator />
|
||||
|
||||
|
||||
@@ -19,7 +19,12 @@ export const UnknownUserIcon = memo(
|
||||
</defs>
|
||||
</svg>`;
|
||||
|
||||
return <div dangerouslySetInnerHTML={{ __html: svgRaw }} />;
|
||||
return (
|
||||
<div
|
||||
style={{ lineHeight: 0 }}
|
||||
dangerouslySetInnerHTML={{ __html: svgRaw }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
UnknownUserIcon.displayName = 'UnknownUserIcon';
|
||||
|
||||
@@ -79,7 +79,7 @@ async function crawlingDocData({
|
||||
(
|
||||
yRootDoc.getMap('meta').get('pages') as YArray<YMap<any>> | undefined
|
||||
)?.forEach(page => {
|
||||
if (page.get('id') === storageDocId) {
|
||||
if (page.get('id') === docId) {
|
||||
docExists = !(page.get('trash') ?? false);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -750,7 +750,7 @@ export const ExplorerFolderNodeFolder = ({
|
||||
}
|
||||
data-event-props="$.navigationPanel.organize.deleteOrganizeItem"
|
||||
data-event-args-type={node.type$.value}
|
||||
onClick={node.delete}
|
||||
onClick={() => node.delete()}
|
||||
>
|
||||
{t['com.affine.rootAppSidebar.organize.delete-from-folder']()}
|
||||
</MenuItem>
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { cssVar } from '@toeverything/theme';
|
||||
import { style } from '@vanilla-extract/css';
|
||||
|
||||
export const container = style({
|
||||
@@ -19,6 +18,5 @@ export const container = style({
|
||||
});
|
||||
|
||||
export const descriptionHighlight = style({
|
||||
color: cssVar('--affine-warning-color'),
|
||||
fontWeight: 'normal',
|
||||
fontWeight: 'bold',
|
||||
});
|
||||
|
||||
@@ -36,6 +36,14 @@ export const itemRoot = style({
|
||||
},
|
||||
},
|
||||
});
|
||||
export const itemRenameAnchor = style({
|
||||
pointerEvents: 'none',
|
||||
position: 'absolute',
|
||||
left: 0,
|
||||
top: -10,
|
||||
width: 10,
|
||||
height: 10,
|
||||
});
|
||||
export const itemContent = style({
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
@@ -140,7 +148,6 @@ export const contentContainer = style({
|
||||
|
||||
export const draggingContainer = style({
|
||||
background: cssVar('--affine-background-primary-color'),
|
||||
boxShadow: cssVar('--affine-toolbar-shadow'),
|
||||
width: '200px',
|
||||
borderRadius: '6px',
|
||||
});
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
useDropTarget,
|
||||
} from '@affine/component';
|
||||
import { RenameModal } from '@affine/component/rename-modal';
|
||||
import { appSidebarWidthAtom } from '@affine/core/components/app-sidebar/index.jotai';
|
||||
import { WorkbenchLink } from '@affine/core/modules/workbench';
|
||||
import type { AffineDNDData } from '@affine/core/types/dnd';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
@@ -23,6 +24,7 @@ import * as Collapsible from '@radix-ui/react-collapsible';
|
||||
import { assignInlineVars } from '@vanilla-extract/dynamic';
|
||||
import clsx from 'clsx';
|
||||
import type { To } from 'history';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import {
|
||||
Fragment,
|
||||
type RefAttributes,
|
||||
@@ -111,6 +113,7 @@ export const ExplorerTreeNode = ({
|
||||
// If no onClick or to is provided, clicking on the node will toggle the collapse state
|
||||
const clickForCollapse = !onClick && !to && !disabled;
|
||||
const [childCount, setChildCount] = useState(0);
|
||||
const sidebarWidth = useAtomValue(appSidebarWidthAtom);
|
||||
const [renaming, setRenaming] = useState(defaultRenaming);
|
||||
const [lastInGroup, setLastInGroup] = useState(false);
|
||||
const rootRef = useRef<HTMLDivElement>(null);
|
||||
@@ -319,11 +322,14 @@ export const ExplorerTreeNode = ({
|
||||
)}
|
||||
{renameable && renaming && (
|
||||
<RenameModal
|
||||
open={renaming}
|
||||
open
|
||||
width={sidebarWidth - 32}
|
||||
onOpenChange={setRenaming}
|
||||
onRename={handleRename}
|
||||
currentName={name ?? ''}
|
||||
/>
|
||||
>
|
||||
<div className={styles.itemRenameAnchor} />
|
||||
</RenameModal>
|
||||
)}
|
||||
|
||||
<div className={styles.itemContent}>{name}</div>
|
||||
|
||||
@@ -100,6 +100,8 @@ export class CloudWorkspaceFlavourProviderService
|
||||
blobSources: {
|
||||
main: blobStorage,
|
||||
},
|
||||
disableBacklinkIndex: true,
|
||||
disableSearchIndex: true,
|
||||
});
|
||||
|
||||
// apply initial state
|
||||
|
||||
@@ -72,6 +72,8 @@ export class LocalWorkspaceFlavourProvider
|
||||
idGenerator: () => nanoid(),
|
||||
schema: globalBlockSuiteSchema,
|
||||
blobSources: { main: blobStorage },
|
||||
disableBacklinkIndex: true,
|
||||
disableSearchIndex: true,
|
||||
});
|
||||
|
||||
// apply initial state
|
||||
|
||||
@@ -121,11 +121,19 @@ export const Component = function CollectionPage() {
|
||||
if (!collection) {
|
||||
return null;
|
||||
}
|
||||
return isEmpty(collection) ? (
|
||||
const inner = isEmpty(collection) ? (
|
||||
<Placeholder collection={collection} />
|
||||
) : (
|
||||
<CollectionDetail collection={collection} />
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<ViewIcon icon="collection" />
|
||||
<ViewTitle title={collection.name} />
|
||||
{inner}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const Placeholder = ({ collection }: { collection: Collection }) => {
|
||||
@@ -157,8 +165,6 @@ const Placeholder = ({ collection }: { collection: Collection }) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<ViewTitle title={collection.name} />
|
||||
<ViewIcon icon="collection" />
|
||||
<ViewHeader>
|
||||
<div
|
||||
style={{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@affine/electron-api",
|
||||
"version": "0.15.0",
|
||||
"version": "0.16.0",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"main": "./src/index.ts",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@affine/electron",
|
||||
"private": true,
|
||||
"version": "0.15.0",
|
||||
"version": "0.16.0",
|
||||
"author": "toeverything",
|
||||
"repository": {
|
||||
"url": "https://github.com/toeverything/AFFiNE",
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'setimmediate';
|
||||
import '@affine/component/theme/global.css';
|
||||
import '@affine/component/theme/theme.css';
|
||||
import '@affine/core/bootstrap/preload';
|
||||
import '../global.css';
|
||||
|
||||
import { ThemeProvider } from '@affine/component/theme-provider';
|
||||
import { configureAppTabsHeaderModule } from '@affine/core/modules/app-tabs-header';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@affine/graphql",
|
||||
"version": "0.15.0",
|
||||
"version": "0.16.0",
|
||||
"description": "Autogenerated GraphQL client for affine.pro",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
|
||||
@@ -33,5 +33,5 @@
|
||||
"typescript": "^5.4.5",
|
||||
"vitest": "1.6.0"
|
||||
},
|
||||
"version": "0.15.0"
|
||||
"version": "0.16.0"
|
||||
}
|
||||
|
||||
@@ -1141,7 +1141,7 @@
|
||||
"com.affine.rootAppSidebar.migration-data.clean-all": "Empty the old favorites",
|
||||
"com.affine.rootAppSidebar.migration-data.clean-all.cancel": "Cancel",
|
||||
"com.affine.rootAppSidebar.migration-data.clean-all.confirm": "OK",
|
||||
"com.affine.rootAppSidebar.migration-data.clean-all.description": "This action deletes the old Favorites section. b>Your documents are safe</b>, ensure you've moved your frequently accessed documents to the new personal Favorites section.",
|
||||
"com.affine.rootAppSidebar.migration-data.clean-all.description": "This action deletes the old Favorites section. <b>Your documents are safe</b>, ensure you've moved your frequently accessed documents to the new personal Favorites section.",
|
||||
"com.affine.rootAppSidebar.migration-data.help": "The old \"Favorites\" will be replaced",
|
||||
"com.affine.rootAppSidebar.migration-data.help.clean-all": "Empty the old favorites",
|
||||
"com.affine.rootAppSidebar.migration-data.help.confirm": "OK",
|
||||
|
||||
@@ -70,7 +70,7 @@ export const LOCALES = [
|
||||
originalName: '简体中文',
|
||||
flagEmoji: '🇨🇳',
|
||||
base: false,
|
||||
completeRate: 0.99,
|
||||
completeRate: 0.974,
|
||||
res: zh_Hans,
|
||||
},
|
||||
{
|
||||
@@ -214,13 +214,13 @@ export const LOCALES = [
|
||||
res: ur,
|
||||
},
|
||||
{
|
||||
id: 1000134013,
|
||||
id: 1000134005,
|
||||
name: 'Arabic',
|
||||
tag: 'ar',
|
||||
originalName: 'العربية',
|
||||
flagEmoji: '🇸🇦',
|
||||
base: false,
|
||||
completeRate: 0.001,
|
||||
completeRate: 0.974,
|
||||
res: ar,
|
||||
},
|
||||
] as const;
|
||||
|
||||
@@ -1142,7 +1142,7 @@
|
||||
"com.affine.rootAppSidebar.migration-data.clean-all": "清空旧收藏夹",
|
||||
"com.affine.rootAppSidebar.migration-data.clean-all.cancel": "取消",
|
||||
"com.affine.rootAppSidebar.migration-data.clean-all.confirm": "好的",
|
||||
"com.affine.rootAppSidebar.migration-data.clean-all.description": "此操作将删除旧的收藏夹部分。b>您的文档是安全的</b>,请确保您已将经常访问的文档移动到新的个人收藏夹。",
|
||||
"com.affine.rootAppSidebar.migration-data.clean-all.description": "此操作将删除旧的收藏夹部分。<b>您的文档是安全的</b>,请确保您已将经常访问的文档移动到新的个人收藏夹。",
|
||||
"com.affine.rootAppSidebar.migration-data.help": "“收藏夹”将被改为个人收藏夹",
|
||||
"com.affine.rootAppSidebar.migration-data.help.clean-all": "清空旧收藏夹",
|
||||
"com.affine.rootAppSidebar.migration-data.help.confirm": "好的",
|
||||
@@ -1243,7 +1243,7 @@
|
||||
"com.affine.settings.translucent-style-description": "在侧边栏使用半透明效果。",
|
||||
"com.affine.settings.workspace": "工作区",
|
||||
"com.affine.settings.workspace.description": "您可以在此处自定义您的工作区。",
|
||||
"com.affine.settings.workspace.experimental-features": "插件",
|
||||
"com.affine.settings.workspace.experimental-features": "实验性功能",
|
||||
"com.affine.settings.workspace.experimental-features.get-started": "开始使用",
|
||||
"com.affine.settings.workspace.experimental-features.header.plugins": "实验性功能",
|
||||
"com.affine.settings.workspace.experimental-features.prompt-disclaimer": "我已明确风险,并且愿意继续使用它。",
|
||||
|
||||
@@ -57,5 +57,5 @@
|
||||
"test": "ava",
|
||||
"version": "napi version"
|
||||
},
|
||||
"version": "0.15.0"
|
||||
"version": "0.16.0"
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "@affine/templates",
|
||||
"private": true,
|
||||
"sideEffect": false,
|
||||
"version": "0.15.0",
|
||||
"version": "0.16.0",
|
||||
"scripts": {
|
||||
"postinstall": "node ./build-edgeless.mjs && node ./build-stickers.mjs"
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@affine/web",
|
||||
"version": "0.15.0",
|
||||
"version": "0.16.0",
|
||||
"description": "AFFiNE Desktop Web application",
|
||||
"private": true,
|
||||
"browser": "src/index.tsx",
|
||||
|
||||
@@ -9,5 +9,5 @@
|
||||
"@affine-test/kit": "workspace:*",
|
||||
"@playwright/test": "=1.44.1"
|
||||
},
|
||||
"version": "0.15.0"
|
||||
"version": "0.16.0"
|
||||
}
|
||||
|
||||
@@ -11,5 +11,5 @@
|
||||
"@types/fs-extra": "^11.0.4",
|
||||
"fs-extra": "^11.2.0"
|
||||
},
|
||||
"version": "0.15.0"
|
||||
"version": "0.16.0"
|
||||
}
|
||||
|
||||
@@ -13,5 +13,5 @@
|
||||
"fs-extra": "^11.2.0",
|
||||
"playwright": "=1.44.1"
|
||||
},
|
||||
"version": "0.15.0"
|
||||
"version": "0.16.0"
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ import type { PlaywrightTestConfig } from '@playwright/test';
|
||||
const config: PlaywrightTestConfig = {
|
||||
testDir: './e2e',
|
||||
fullyParallel: true,
|
||||
workers: 2,
|
||||
workers: 1,
|
||||
timeout: process.env.CI ? 50_000 : 30_000,
|
||||
expect: {
|
||||
timeout: process.env.CI ? 15_000 : 5_000,
|
||||
|
||||
@@ -14,5 +14,5 @@
|
||||
"http-proxy-middleware": "^3.0.0",
|
||||
"serve": "^14.2.1"
|
||||
},
|
||||
"version": "0.15.0"
|
||||
"version": "0.16.0"
|
||||
}
|
||||
|
||||
@@ -14,5 +14,5 @@
|
||||
"http-proxy-middleware": "^3.0.0",
|
||||
"serve": "^14.2.1"
|
||||
},
|
||||
"version": "0.15.0"
|
||||
"version": "0.16.0"
|
||||
}
|
||||
|
||||
@@ -14,5 +14,5 @@
|
||||
"http-proxy-middleware": "^3.0.0",
|
||||
"serve": "^14.2.1"
|
||||
},
|
||||
"version": "0.15.0"
|
||||
"version": "0.16.0"
|
||||
}
|
||||
|
||||
@@ -14,5 +14,5 @@
|
||||
"http-proxy-middleware": "^3.0.0",
|
||||
"serve": "^14.2.1"
|
||||
},
|
||||
"version": "0.15.0"
|
||||
"version": "0.16.0"
|
||||
}
|
||||
|
||||
@@ -9,5 +9,5 @@
|
||||
"@affine-test/kit": "workspace:*",
|
||||
"@playwright/test": "=1.44.1"
|
||||
},
|
||||
"version": "0.15.0"
|
||||
"version": "0.16.0"
|
||||
}
|
||||
|
||||
@@ -9,5 +9,5 @@
|
||||
"@affine-test/kit": "workspace:*",
|
||||
"@playwright/test": "=1.44.1"
|
||||
},
|
||||
"version": "0.15.0"
|
||||
"version": "0.16.0"
|
||||
}
|
||||
|
||||
2
tests/fixtures/package.json
vendored
2
tests/fixtures/package.json
vendored
@@ -3,5 +3,5 @@
|
||||
"exports": {
|
||||
"./*": "./*"
|
||||
},
|
||||
"version": "0.15.0"
|
||||
"version": "0.16.0"
|
||||
}
|
||||
|
||||
@@ -87,7 +87,9 @@ export const test = base.extend<{
|
||||
window.localStorage.setItem('dismissAiOnboardingLocal', 'true');
|
||||
});
|
||||
|
||||
await page.reload();
|
||||
await page.reload({
|
||||
timeout: 30000,
|
||||
});
|
||||
|
||||
await use(page as Page);
|
||||
},
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "@affine-test/kit",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"version": "0.15.0",
|
||||
"version": "0.16.0",
|
||||
"exports": {
|
||||
"./electron": "./electron.ts",
|
||||
"./playwright": "./playwright.ts",
|
||||
|
||||
2
tools/@types/env/package.json
vendored
2
tools/@types/env/package.json
vendored
@@ -6,5 +6,5 @@
|
||||
"dependencies": {
|
||||
"@affine/env": "workspace:*"
|
||||
},
|
||||
"version": "0.15.0"
|
||||
"version": "0.16.0"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@affine/bump-blocksuite",
|
||||
"version": "0.15.0",
|
||||
"version": "0.16.0",
|
||||
"type": "module",
|
||||
"main": "index.js",
|
||||
"private": true,
|
||||
|
||||
@@ -45,5 +45,5 @@
|
||||
"build": "node --loader ts-node/esm/transpile-only.mjs ./src/bin/build.ts",
|
||||
"dev": "node --loader ts-node/esm/transpile-only.mjs ./src/bin/dev.ts"
|
||||
},
|
||||
"version": "0.15.0"
|
||||
"version": "0.16.0"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@affine/commitlint-config",
|
||||
"version": "0.15.0",
|
||||
"version": "0.16.0",
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"@commitlint/cli": "^19.2.1",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@affine/workers",
|
||||
"version": "0.15.0",
|
||||
"version": "0.16.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "wrangler dev"
|
||||
|
||||
Reference in New Issue
Block a user