diff --git a/packages/frontend/core/src/components/filter/conditions/system.tsx b/packages/frontend/core/src/components/filter/conditions/system.tsx
index 29d14df8e..db57d8001 100644
--- a/packages/frontend/core/src/components/filter/conditions/system.tsx
+++ b/packages/frontend/core/src/components/filter/conditions/system.tsx
@@ -37,6 +37,16 @@ export const SystemFilterCondition = ({
const methods = type.filterMethod;
const Value = type.filterValue;
+ if (!methods || !Value) {
+ return (
+
+ );
+ }
+
return (
void;
diff --git a/packages/frontend/core/src/modules/collection-rules/impls/order-by/title.ts b/packages/frontend/core/src/modules/collection-rules/impls/order-by/title.ts
new file mode 100644
index 000000000..5f12a9879
--- /dev/null
+++ b/packages/frontend/core/src/modules/collection-rules/impls/order-by/title.ts
@@ -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>,
+ params: OrderByParams
+ ): Observable {
+ 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);
+ })
+ );
+ }
+}
diff --git a/packages/frontend/core/src/modules/collection-rules/index.ts b/packages/frontend/core/src/modules/collection-rules/index.ts
index 4a56cb4d9..f0cb02935 100644
--- a/packages/frontend/core/src/modules/collection-rules/index.ts
+++ b/packages/frontend/core/src/modules/collection-rules/index.ts
@@ -61,6 +61,7 @@ import { SystemOrderByProvider } from './impls/order-by/system';
import { TagsOrderByProvider } from './impls/order-by/tags';
import { TemplateOrderByProvider } from './impls/order-by/template';
import { TextPropertyOrderByProvider } from './impls/order-by/text';
+import { TitleOrderByProvider } from './impls/order-by/title';
import { UpdatedAtOrderByProvider } from './impls/order-by/updated-at';
import { UpdatedByOrderByProvider } from './impls/order-by/updated-by';
import { FilterProvider, GroupByProvider, OrderByProvider } from './provider';
@@ -365,5 +366,6 @@ export function configureCollectionRulesModule(framework: Framework) {
])
.impl(OrderByProvider('system:template'), TemplateOrderByProvider, [
DocsService,
- ]);
+ ])
+ .impl(OrderByProvider('system:title'), TitleOrderByProvider, [DocsService]);
}
diff --git a/packages/frontend/core/src/modules/doc/services/docs.ts b/packages/frontend/core/src/modules/doc/services/docs.ts
index d63820635..95ca6d81a 100644
--- a/packages/frontend/core/src/modules/doc/services/docs.ts
+++ b/packages/frontend/core/src/modules/doc/services/docs.ts
@@ -81,6 +81,10 @@ export class DocsService extends Service {
return this.store.watchTrashDocIds();
}
+ allDocTitle$() {
+ return this.store.watchAllDocTitle();
+ }
+
constructor(
private readonly store: DocsStore,
private readonly docPropertiesStore: DocPropertiesStore,
diff --git a/packages/frontend/core/src/modules/doc/stores/docs.ts b/packages/frontend/core/src/modules/doc/stores/docs.ts
index c5f1ac36c..8a6947240 100644
--- a/packages/frontend/core/src/modules/doc/stores/docs.ts
+++ b/packages/frontend/core/src/modules/doc/stores/docs.ts
@@ -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() {
return yjsGetPath(
this.workspaceService.workspace.rootYDoc.getMap('meta'),