feat(core): new doc list for editing collection docs and rules (#12320)

close AF-2626

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

- **New Features**
  - Added support for debounced input changes in input fields, improving performance for rapid typing scenarios.
  - Enhanced document explorer with dynamic visibility controls for drag handles and "more" menu options.
  - Introduced a new filter for searching documents by title, enabling more precise filtering in collections.
  - Added a direct search method for document titles to improve search accuracy and speed.

- **Bug Fixes**
  - Improved layout and centering of icons in document list items.
  - Updated border styles across collection editor components for a more consistent appearance.

- **Refactor**
  - Simplified page selection and rule-matching logic in collection and selector components by consolidating state management and leveraging context-driven rendering.
  - Removed deprecated and redundant hooks for page list configuration.

- **Chores**
  - Updated code to use new theme variables for border colors, ensuring visual consistency with the latest design standards.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
CatsJuice
2025-05-22 09:42:33 +00:00
parent 4b9428e6f4
commit 6d662b8a54
16 changed files with 334 additions and 345 deletions
@@ -0,0 +1,24 @@
import type { DocsSearchService } from '@affine/core/modules/docs-search';
import { Service } from '@toeverything/infra';
import { map, type Observable } from 'rxjs';
import type { FilterProvider } from '../../provider';
import type { FilterParams } from '../../types';
export class TitleFilterProvider extends Service implements FilterProvider {
constructor(private readonly docsSearchService: DocsSearchService) {
super();
}
filter$(params: FilterParams): Observable<Set<string>> {
const method = params.method as 'match';
if (method === 'match') {
return this.docsSearchService
.searchTitle$(params.value ?? '')
.pipe(map(list => new Set(list)));
}
throw new Error(`Unsupported method: ${params.method}`);
}
}
@@ -1,6 +1,7 @@
import type { Framework } from '@toeverything/infra';
import { DocsService } from '../doc';
import { DocsSearchService } from '../docs-search';
import { FavoriteService } from '../favorite';
import { ShareDocsListService } from '../share-doc';
import { TagService } from '../tag';
@@ -19,6 +20,7 @@ import { SharedFilterProvider } from './impls/filters/shared';
import { SystemFilterProvider } from './impls/filters/system';
import { TagsFilterProvider } from './impls/filters/tags';
import { TextPropertyFilterProvider } from './impls/filters/text';
import { TitleFilterProvider } from './impls/filters/title';
import { TrashFilterProvider } from './impls/filters/trash';
import { UpdatedAtFilterProvider } from './impls/filters/updated-at';
import { UpdatedByFilterProvider } from './impls/filters/updated-by';
@@ -130,6 +132,9 @@ export function configureCollectionRulesModule(framework: Framework) {
ShareDocsListService,
DocsService,
])
.impl(FilterProvider('system:title'), TitleFilterProvider, [
DocsSearchService,
])
// --------------- Group By ---------------
.impl(GroupByProvider('system'), SystemGroupByProvider)
.impl(GroupByProvider('property'), PropertyGroupByProvider, [
@@ -26,6 +26,29 @@ export class DocsSearchService extends Service {
errorMessage: null,
} as IndexerSyncState);
searchTitle$(query: string) {
return this.indexer
.search$(
'doc',
{
type: 'match',
field: 'title',
match: query,
},
{
pagination: {
skip: 0,
limit: Infinity,
},
}
)
.pipe(
map(({ nodes }) => {
return nodes.map(node => node.id);
})
);
}
search$(query: string): Observable<
{
docId: string;