feat(core): add more collection rules (#12458)

This commit is contained in:
EYHN
2025-05-23 16:46:02 +09:00
committed by GitHub
parent 0902b2b9c9
commit ac4954f7ad
28 changed files with 1170 additions and 38 deletions
@@ -0,0 +1,46 @@
import type { DocsService } from '@affine/core/modules/doc';
import type { WorkspacePropertyFilter } from '@affine/core/modules/workspace-property';
import { Service } from '@toeverything/infra';
import { map, type Observable } from 'rxjs';
import type { FilterProvider } from '../../provider';
import type { FilterParams } from '../../types';
export class EdgelessThemeFilterProvider
extends Service
implements FilterProvider
{
constructor(private readonly docsService: DocsService) {
super();
}
filter$(params: FilterParams): Observable<Set<string>> {
const method = params.method as WorkspacePropertyFilter<'edgelessTheme'>;
if (method === 'is') {
return this.docsService.propertyValues$('edgelessColorTheme').pipe(
map(values => {
const match = new Set<string>();
for (const [id, value] of values) {
if ((value ?? 'system') === params.value) {
match.add(id);
}
}
return match;
})
);
} else if (method === 'is-not') {
return this.docsService.propertyValues$('edgelessColorTheme').pipe(
map(values => {
const match = new Set<string>();
for (const [id, value] of values) {
if ((value ?? 'system') !== params.value) {
match.add(id);
}
}
return match;
})
);
}
throw new Error(`Unsupported method: ${params.method}`);
}
}
@@ -0,0 +1,45 @@
import type { DocsService } from '@affine/core/modules/doc';
import { Service } from '@toeverything/infra';
import { map, type Observable } from 'rxjs';
import type { FilterProvider } from '../../provider';
import type { FilterParams } from '../../types';
export class IntegrationTypeFilterProvider
extends Service
implements FilterProvider
{
constructor(private readonly docsService: DocsService) {
super();
}
filter$(params: FilterParams): Observable<Set<string>> {
const method = params.method as 'is' | 'is-not';
if (method === 'is') {
return this.docsService.propertyValues$('integrationType').pipe(
map(values => {
const match = new Set<string>();
for (const [id, value] of values) {
if (value === params.value) {
match.add(id);
}
}
return match;
})
);
} else if (method === 'is-not') {
return this.docsService.propertyValues$('integrationType').pipe(
map(values => {
const match = new Set<string>();
for (const [id, value] of values) {
if (value !== params.value) {
match.add(id);
}
}
return match;
})
);
}
throw new Error(`Unsupported method: ${params.method}`);
}
}
@@ -0,0 +1,43 @@
import type { DocsService } from '@affine/core/modules/doc';
import type { WorkspacePropertyFilter } from '@affine/core/modules/workspace-property';
import { Service } from '@toeverything/infra';
import { map, type Observable } from 'rxjs';
import type { FilterProvider } from '../../provider';
import type { FilterParams } from '../../types';
export class PageWidthFilterProvider extends Service implements FilterProvider {
constructor(private readonly docsService: DocsService) {
super();
}
filter$(params: FilterParams): Observable<Set<string>> {
const method = params.method as WorkspacePropertyFilter<'pageWidth'>;
if (method === 'is') {
return this.docsService.propertyValues$('pageWidth').pipe(
map(values => {
const match = new Set<string>();
for (const [id, value] of values) {
if ((value ?? 'standard') === params.value) {
match.add(id);
}
}
return match;
})
);
} else if (method === 'is-not') {
return this.docsService.propertyValues$('pageWidth').pipe(
map(values => {
const match = new Set<string>();
for (const [id, value] of values) {
if ((value ?? 'standard') !== params.value) {
match.add(id);
}
}
return match;
})
);
}
throw new Error(`Unsupported method: ${params.method}`);
}
}
@@ -0,0 +1,43 @@
import type { DocsService } from '@affine/core/modules/doc';
import type { WorkspacePropertyFilter } from '@affine/core/modules/workspace-property';
import { Service } from '@toeverything/infra';
import { map, type Observable } from 'rxjs';
import type { FilterProvider } from '../../provider';
import type { FilterParams } from '../../types';
export class TemplateFilterProvider extends Service implements FilterProvider {
constructor(private readonly docsService: DocsService) {
super();
}
filter$(params: FilterParams): Observable<Set<string>> {
const method = params.method as WorkspacePropertyFilter<'template'>;
if (method === 'is') {
return this.docsService.propertyValues$('isTemplate').pipe(
map(values => {
const match = new Set<string>();
for (const [id, value] of values) {
if ((value ? 'true' : 'false') === params.value) {
match.add(id);
}
}
return match;
})
);
} else if (method === 'is-not') {
return this.docsService.propertyValues$('isTemplate').pipe(
map(values => {
const match = new Set<string>();
for (const [id, value] of values) {
if ((value ? 'true' : 'false') !== params.value) {
match.add(id);
}
}
return match;
})
);
}
throw new Error(`Unsupported method: ${params.method}`);
}
}
@@ -0,0 +1,35 @@
import type { DocsService } from '@affine/core/modules/doc';
import { Service } from '@toeverything/infra';
import { map, type Observable } from 'rxjs';
import type { GroupByProvider } from '../../provider';
import type { GroupByParams } from '../../types';
export class EdgelessThemeGroupByProvider
extends Service
implements GroupByProvider
{
constructor(private readonly docsService: DocsService) {
super();
}
groupBy$(
_items$: Observable<Set<string>>,
_params: GroupByParams
): Observable<Map<string, Set<string>>> {
return this.docsService.propertyValues$('edgelessColorTheme').pipe(
map(values => {
const result = new Map<string, Set<string>>();
for (const [id, value] of values) {
const theme = value ?? 'system';
if (!result.has(theme)) {
result.set(theme, new Set([id]));
} else {
result.get(theme)?.add(id);
}
}
return result;
})
);
}
}
@@ -0,0 +1,38 @@
import type { DocsService } from '@affine/core/modules/doc';
import { Service } from '@toeverything/infra';
import { map, type Observable } from 'rxjs';
import type { GroupByProvider } from '../../provider';
import type { GroupByParams } from '../../types';
export class IntegrationTypeGroupByProvider
extends Service
implements GroupByProvider
{
constructor(private readonly docsService: DocsService) {
super();
}
groupBy$(
_items$: Observable<Set<string>>,
_params: GroupByParams
): Observable<Map<string, Set<string>>> {
return this.docsService.propertyValues$('integrationType').pipe(
map(values => {
const result = new Map<string, Set<string>>();
for (const [id, value] of values) {
const integrationType = value;
if (!integrationType) {
continue;
}
if (!result.has(integrationType)) {
result.set(integrationType, new Set([id]));
} else {
result.get(integrationType)?.add(id);
}
}
return result;
})
);
}
}
@@ -0,0 +1,35 @@
import type { DocsService } from '@affine/core/modules/doc';
import { Service } from '@toeverything/infra';
import { map, type Observable } from 'rxjs';
import type { GroupByProvider } from '../../provider';
import type { GroupByParams } from '../../types';
export class PageWidthGroupByProvider
extends Service
implements GroupByProvider
{
constructor(private readonly docsService: DocsService) {
super();
}
groupBy$(
_items$: Observable<Set<string>>,
_params: GroupByParams
): Observable<Map<string, Set<string>>> {
return this.docsService.propertyValues$('pageWidth').pipe(
map(values => {
const result = new Map<string, Set<string>>();
for (const [id, value] of values) {
const pageWidth = value ?? 'standard';
if (!result.has(pageWidth)) {
result.set(pageWidth, new Set([id]));
} else {
result.get(pageWidth)?.add(id);
}
}
return result;
})
);
}
}
@@ -0,0 +1,35 @@
import type { DocsService } from '@affine/core/modules/doc';
import { Service } from '@toeverything/infra';
import { map, type Observable } from 'rxjs';
import type { GroupByProvider } from '../../provider';
import type { GroupByParams } from '../../types';
export class TemplateGroupByProvider
extends Service
implements GroupByProvider
{
constructor(private readonly docsService: DocsService) {
super();
}
groupBy$(
_items$: Observable<Set<string>>,
_params: GroupByParams
): Observable<Map<string, Set<string>>> {
return this.docsService.propertyValues$('isTemplate').pipe(
map(values => {
const result = new Map<string, Set<string>>();
for (const [id, value] of values) {
const isTemplate = value ? 'true' : 'false';
if (!result.has(isTemplate)) {
result.set(isTemplate, new Set([id]));
} else {
result.get(isTemplate)?.add(id);
}
}
return result;
})
);
}
}
@@ -0,0 +1,39 @@
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 EdgelessThemeOrderByProvider
extends Service
implements OrderByProvider
{
constructor(private readonly docsService: DocsService) {
super();
}
orderBy$(
_items$: Observable<Set<string>>,
params: OrderByParams
): Observable<string[]> {
return this.docsService.propertyValues$('edgelessColorTheme').pipe(
map(values => {
const docs = Array.from(values).map(([id, value]) => ({
id,
theme: value ?? 'system',
}));
if (params.desc) {
return docs
.sort((a, b) => b.theme.localeCompare(a.theme))
.map(doc => doc.id);
} else {
return docs
.sort((a, b) => a.theme.localeCompare(b.theme))
.map(doc => doc.id);
}
})
);
}
}
@@ -0,0 +1,41 @@
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 IntegrationTypeOrderByProvider
extends Service
implements OrderByProvider
{
constructor(private readonly docsService: DocsService) {
super();
}
orderBy$(
_items$: Observable<Set<string>>,
params: OrderByParams
): Observable<string[]> {
return this.docsService.propertyValues$('integrationType').pipe(
map(values => {
const docs = Array.from(values)
.filter(([, value]) => value !== undefined)
.map(([id, value]) => ({
id,
type: value as string,
}));
if (params.desc) {
return docs
.sort((a, b) => b.type.localeCompare(a.type))
.map(doc => doc.id);
} else {
return docs
.sort((a, b) => a.type.localeCompare(b.type))
.map(doc => doc.id);
}
})
);
}
}
@@ -0,0 +1,39 @@
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 PageWidthOrderByProvider
extends Service
implements OrderByProvider
{
constructor(private readonly docsService: DocsService) {
super();
}
orderBy$(
_items$: Observable<Set<string>>,
params: OrderByParams
): Observable<string[]> {
return this.docsService.propertyValues$('pageWidth').pipe(
map(values => {
const docs = Array.from(values).map(([id, value]) => ({
id,
width: value ?? 'standard',
}));
if (params.desc) {
return docs
.sort((a, b) => b.width.localeCompare(a.width))
.map(doc => doc.id);
} else {
return docs
.sort((a, b) => a.width.localeCompare(b.width))
.map(doc => doc.id);
}
})
);
}
}
@@ -0,0 +1,39 @@
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 TemplateOrderByProvider
extends Service
implements OrderByProvider
{
constructor(private readonly docsService: DocsService) {
super();
}
orderBy$(
_items$: Observable<Set<string>>,
params: OrderByParams
): Observable<string[]> {
return this.docsService.propertyValues$('isTemplate').pipe(
map(values => {
const docs = Array.from(values).map(([id, value]) => ({
id,
isTemplate: value ? 'true' : 'false',
}));
if (params.desc) {
return docs
.sort((a, b) => b.isTemplate.localeCompare(a.isTemplate))
.map(doc => doc.id);
} else {
return docs
.sort((a, b) => a.isTemplate.localeCompare(b.isTemplate))
.map(doc => doc.id);
}
})
);
}
}
@@ -12,13 +12,17 @@ import { CreatedAtFilterProvider } from './impls/filters/created-at';
import { CreatedByFilterProvider } from './impls/filters/created-by';
import { DatePropertyFilterProvider } from './impls/filters/date';
import { DocPrimaryModeFilterProvider } from './impls/filters/doc-primary-mode';
import { EdgelessThemeFilterProvider } from './impls/filters/edgeless-theme';
import { EmptyJournalFilterProvider } from './impls/filters/empty-journal';
import { FavoriteFilterProvider } from './impls/filters/favorite';
import { IntegrationTypeFilterProvider } from './impls/filters/integration-type';
import { JournalFilterProvider } from './impls/filters/journal';
import { PageWidthFilterProvider } from './impls/filters/page-width';
import { PropertyFilterProvider } from './impls/filters/property';
import { SharedFilterProvider } from './impls/filters/shared';
import { SystemFilterProvider } from './impls/filters/system';
import { TagsFilterProvider } from './impls/filters/tags';
import { TemplateFilterProvider } from './impls/filters/template';
import { TextPropertyFilterProvider } from './impls/filters/text';
import { TitleFilterProvider } from './impls/filters/title';
import { TrashFilterProvider } from './impls/filters/trash';
@@ -29,10 +33,14 @@ import { CreatedAtGroupByProvider } from './impls/group-by/created-at';
import { CreatedByGroupByProvider } from './impls/group-by/created-by';
import { DatePropertyGroupByProvider } from './impls/group-by/date';
import { DocPrimaryModeGroupByProvider } from './impls/group-by/doc-primary-mode';
import { EdgelessThemeGroupByProvider } from './impls/group-by/edgeless-theme';
import { IntegrationTypeGroupByProvider } from './impls/group-by/integration-type';
import { JournalGroupByProvider } from './impls/group-by/journal';
import { PageWidthGroupByProvider } from './impls/group-by/page-width';
import { PropertyGroupByProvider } from './impls/group-by/property';
import { SystemGroupByProvider } from './impls/group-by/system';
import { TagsGroupByProvider } from './impls/group-by/tags';
import { TemplateGroupByProvider } from './impls/group-by/template';
import { TextPropertyGroupByProvider } from './impls/group-by/text';
import { UpdatedAtGroupByProvider } from './impls/group-by/updated-at';
import { UpdatedByGroupByProvider } from './impls/group-by/updated-by';
@@ -41,10 +49,14 @@ import { CreatedAtOrderByProvider } from './impls/order-by/created-at';
import { CreatedByOrderByProvider } from './impls/order-by/created-by';
import { DatePropertyOrderByProvider } from './impls/order-by/date';
import { DocPrimaryModeOrderByProvider } from './impls/order-by/doc-primary-mode';
import { EdgelessThemeOrderByProvider } from './impls/order-by/edgeless-theme';
import { IntegrationTypeOrderByProvider } from './impls/order-by/integration-type';
import { JournalOrderByProvider } from './impls/order-by/journal';
import { PageWidthOrderByProvider } from './impls/order-by/page-width';
import { PropertyOrderByProvider } from './impls/order-by/property';
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 { UpdatedAtOrderByProvider } from './impls/order-by/updated-at';
import { UpdatedByOrderByProvider } from './impls/order-by/updated-by';
@@ -135,6 +147,31 @@ export function configureCollectionRulesModule(framework: Framework) {
.impl(FilterProvider('system:title'), TitleFilterProvider, [
DocsSearchService,
])
.impl(
FilterProvider('system:integrationType'),
IntegrationTypeFilterProvider,
[DocsService]
)
.impl(
FilterProvider('property:edgelessTheme'),
EdgelessThemeFilterProvider,
[DocsService]
)
.impl(FilterProvider('system:edgelessTheme'), EdgelessThemeFilterProvider, [
DocsService,
])
.impl(FilterProvider('property:template'), TemplateFilterProvider, [
DocsService,
])
.impl(FilterProvider('system:template'), TemplateFilterProvider, [
DocsService,
])
.impl(FilterProvider('property:pageWidth'), PageWidthFilterProvider, [
DocsService,
])
.impl(FilterProvider('system:pageWidth'), PageWidthFilterProvider, [
DocsService,
])
// --------------- Group By ---------------
.impl(GroupByProvider('system'), SystemGroupByProvider)
.impl(GroupByProvider('property'), PropertyGroupByProvider, [
@@ -199,6 +236,33 @@ export function configureCollectionRulesModule(framework: Framework) {
.impl(GroupByProvider('system:updatedBy'), UpdatedByGroupByProvider, [
DocsService,
])
.impl(
GroupByProvider('system:integrationType'),
IntegrationTypeGroupByProvider,
[DocsService]
)
.impl(
GroupByProvider('property:edgelessTheme'),
EdgelessThemeGroupByProvider,
[DocsService]
)
.impl(
GroupByProvider('system:edgelessTheme'),
EdgelessThemeGroupByProvider,
[DocsService]
)
.impl(GroupByProvider('property:pageWidth'), PageWidthGroupByProvider, [
DocsService,
])
.impl(GroupByProvider('system:pageWidth'), PageWidthGroupByProvider, [
DocsService,
])
.impl(GroupByProvider('property:template'), TemplateGroupByProvider, [
DocsService,
])
.impl(GroupByProvider('system:template'), TemplateGroupByProvider, [
DocsService,
])
// --------------- Order By ---------------
.impl(OrderByProvider('system'), SystemOrderByProvider)
.impl(OrderByProvider('property'), PropertyOrderByProvider, [
@@ -262,5 +326,32 @@ export function configureCollectionRulesModule(framework: Framework) {
])
.impl(OrderByProvider('system:updatedBy'), UpdatedByOrderByProvider, [
DocsService,
])
.impl(
OrderByProvider('system:integrationType'),
IntegrationTypeOrderByProvider,
[DocsService]
)
.impl(
OrderByProvider('property:edgelessTheme'),
EdgelessThemeOrderByProvider,
[DocsService]
)
.impl(
OrderByProvider('system:edgelessTheme'),
EdgelessThemeOrderByProvider,
[DocsService]
)
.impl(OrderByProvider('property:pageWidth'), PageWidthOrderByProvider, [
DocsService,
])
.impl(OrderByProvider('system:pageWidth'), PageWidthOrderByProvider, [
DocsService,
])
.impl(OrderByProvider('property:template'), TemplateOrderByProvider, [
DocsService,
])
.impl(OrderByProvider('system:template'), TemplateOrderByProvider, [
DocsService,
]);
}
@@ -39,9 +39,9 @@ export type WorkspacePropertyTypes = {
createdAt: { filter: DateFilters };
docPrimaryMode: { filter: 'is' | 'is-not' };
journal: { filter: 'is' | 'is-not' };
edgelessTheme: { filter: never };
pageWidth: { filter: never };
template: { filter: never };
edgelessTheme: { filter: 'is' | 'is-not' };
pageWidth: { filter: 'is' | 'is-not' };
template: { filter: 'is' | 'is-not' };
unknown: { filter: never };
};
export type WorkspacePropertyType = keyof WorkspacePropertyTypes;