feat(core): add title order by (#12696)
<!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Added support for ordering documents by their title. - Introduced a new "title" system property type with an associated icon and display name. - **Improvements** - Enhanced system property types to allow more flexible filtering options. - Improved filter condition handling to show an unknown filter UI when filtering methods or values are unavailable. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -37,6 +37,16 @@ export const SystemFilterCondition = ({
|
|||||||
const methods = type.filterMethod;
|
const methods = type.filterMethod;
|
||||||
const Value = type.filterValue;
|
const Value = type.filterValue;
|
||||||
|
|
||||||
|
if (!methods || !Value) {
|
||||||
|
return (
|
||||||
|
<UnknownFilterCondition
|
||||||
|
isDraft={isDraft}
|
||||||
|
onDraftCompleted={onDraftCompleted}
|
||||||
|
filter={filter}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Condition
|
<Condition
|
||||||
filter={filter}
|
filter={filter}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import {
|
|||||||
MemberIcon,
|
MemberIcon,
|
||||||
TagIcon,
|
TagIcon,
|
||||||
TemplateIcon,
|
TemplateIcon,
|
||||||
|
TitleIcon,
|
||||||
} from '@blocksuite/icons/rc';
|
} from '@blocksuite/icons/rc';
|
||||||
|
|
||||||
import type { GroupHeaderProps } from '../explorer/types';
|
import type { GroupHeaderProps } from '../explorer/types';
|
||||||
@@ -55,6 +56,11 @@ import {
|
|||||||
} from './template';
|
} from './template';
|
||||||
|
|
||||||
export const SystemPropertyTypes = {
|
export const SystemPropertyTypes = {
|
||||||
|
title: {
|
||||||
|
icon: TitleIcon,
|
||||||
|
name: 'Title',
|
||||||
|
allowInOrderBy: true,
|
||||||
|
},
|
||||||
tags: {
|
tags: {
|
||||||
icon: TagIcon,
|
icon: TagIcon,
|
||||||
name: 'Tags',
|
name: 'Tags',
|
||||||
@@ -213,8 +219,8 @@ export const SystemPropertyTypes = {
|
|||||||
|
|
||||||
allowInOrderBy?: boolean;
|
allowInOrderBy?: boolean;
|
||||||
allowInGroupBy?: boolean;
|
allowInGroupBy?: boolean;
|
||||||
filterMethod: { [key: string]: I18nString };
|
filterMethod?: { [key: string]: I18nString };
|
||||||
filterValue: React.FC<{
|
filterValue?: React.FC<{
|
||||||
filter: FilterParams;
|
filter: FilterParams;
|
||||||
isDraft?: boolean;
|
isDraft?: boolean;
|
||||||
onDraftCompleted?: () => void;
|
onDraftCompleted?: () => void;
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import type { DocsService } from '@affine/core/modules/doc';
|
||||||
|
import { Service } from '@toeverything/infra';
|
||||||
|
import { map, type Observable } from 'rxjs';
|
||||||
|
|
||||||
|
import type { OrderByProvider } from '../../provider';
|
||||||
|
import type { OrderByParams } from '../../types';
|
||||||
|
|
||||||
|
export class TitleOrderByProvider extends Service implements OrderByProvider {
|
||||||
|
constructor(private readonly docsService: DocsService) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
orderBy$(
|
||||||
|
_items$: Observable<Set<string>>,
|
||||||
|
params: OrderByParams
|
||||||
|
): Observable<string[]> {
|
||||||
|
const isDesc = params.desc;
|
||||||
|
return this.docsService.allDocTitle$().pipe(
|
||||||
|
map(o => {
|
||||||
|
return o
|
||||||
|
.sort(
|
||||||
|
(a, b) =>
|
||||||
|
(a.title === b.title ? 0 : a.title > b.title ? 1 : -1) *
|
||||||
|
(isDesc ? -1 : 1)
|
||||||
|
)
|
||||||
|
.map(i => i.id);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -61,6 +61,7 @@ import { SystemOrderByProvider } from './impls/order-by/system';
|
|||||||
import { TagsOrderByProvider } from './impls/order-by/tags';
|
import { TagsOrderByProvider } from './impls/order-by/tags';
|
||||||
import { TemplateOrderByProvider } from './impls/order-by/template';
|
import { TemplateOrderByProvider } from './impls/order-by/template';
|
||||||
import { TextPropertyOrderByProvider } from './impls/order-by/text';
|
import { TextPropertyOrderByProvider } from './impls/order-by/text';
|
||||||
|
import { TitleOrderByProvider } from './impls/order-by/title';
|
||||||
import { UpdatedAtOrderByProvider } from './impls/order-by/updated-at';
|
import { UpdatedAtOrderByProvider } from './impls/order-by/updated-at';
|
||||||
import { UpdatedByOrderByProvider } from './impls/order-by/updated-by';
|
import { UpdatedByOrderByProvider } from './impls/order-by/updated-by';
|
||||||
import { FilterProvider, GroupByProvider, OrderByProvider } from './provider';
|
import { FilterProvider, GroupByProvider, OrderByProvider } from './provider';
|
||||||
@@ -365,5 +366,6 @@ export function configureCollectionRulesModule(framework: Framework) {
|
|||||||
])
|
])
|
||||||
.impl(OrderByProvider('system:template'), TemplateOrderByProvider, [
|
.impl(OrderByProvider('system:template'), TemplateOrderByProvider, [
|
||||||
DocsService,
|
DocsService,
|
||||||
]);
|
])
|
||||||
|
.impl(OrderByProvider('system:title'), TitleOrderByProvider, [DocsService]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,6 +81,10 @@ export class DocsService extends Service {
|
|||||||
return this.store.watchTrashDocIds();
|
return this.store.watchTrashDocIds();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
allDocTitle$() {
|
||||||
|
return this.store.watchAllDocTitle();
|
||||||
|
}
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly store: DocsStore,
|
private readonly store: DocsStore,
|
||||||
private readonly docPropertiesStore: DocPropertiesStore,
|
private readonly docPropertiesStore: DocPropertiesStore,
|
||||||
|
|||||||
@@ -142,6 +142,25 @@ export class DocsStore extends Store {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
watchAllDocTitle() {
|
||||||
|
return yjsGetPath(
|
||||||
|
this.workspaceService.workspace.rootYDoc.getMap('meta'),
|
||||||
|
'pages'
|
||||||
|
).pipe(
|
||||||
|
switchMap(pages => yjsObservePath(pages, '*.title')),
|
||||||
|
map(pages => {
|
||||||
|
if (pages instanceof YArray) {
|
||||||
|
return pages.map(v => ({
|
||||||
|
id: v.get('id') as string,
|
||||||
|
title: (v.get('title') ?? '') as string,
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
watchNonTrashDocIds() {
|
watchNonTrashDocIds() {
|
||||||
return yjsGetPath(
|
return yjsGetPath(
|
||||||
this.workspaceService.workspace.rootYDoc.getMap('meta'),
|
this.workspaceService.workspace.rootYDoc.getMap('meta'),
|
||||||
|
|||||||
Reference in New Issue
Block a user