refactor(core): refactor tag to use di (#6079)

use case
```
const tagService = useService(TagService);
const tags = useLiveData(tagService.tags);
const currentTagLiveData = tagService.tagByTagId(tagId);
const currentTag = useLiveData(currentTagLiveData);

```
This commit is contained in:
JimmFly
2024-03-19 08:39:15 +00:00
parent 332cd3b380
commit 9030ca511e
24 changed files with 468 additions and 355 deletions
@@ -1,6 +1,7 @@
import {
GlobalCache,
GlobalState,
PageRecordList,
type ServiceCollection,
Workspace,
WorkspaceScope,
@@ -13,6 +14,7 @@ import {
} from './infra-web/storage';
import { Navigator } from './navigation';
import { RightSidebar } from './right-sidebar/entities/right-sidebar';
import { TagService } from './tag';
import { Workbench } from './workbench';
import {
CurrentWorkspaceService,
@@ -29,7 +31,8 @@ export function configureBusinessServices(services: ServiceCollection) {
.add(RightSidebar)
.add(WorkspacePropertiesAdapter, [Workspace])
.add(CollectionService, [Workspace])
.add(WorkspaceLegacyProperties, [Workspace]);
.add(WorkspaceLegacyProperties, [Workspace])
.add(TagService, [WorkspaceLegacyProperties, PageRecordList]);
}
export function configureWebInfraServices(services: ServiceCollection) {
@@ -0,0 +1,71 @@
import type { Tag as TagSchema } from '@affine/env/filter';
import { LiveData, type PageRecordList } from '@toeverything/infra';
import type { WorkspaceLegacyProperties } from '../../workspace';
export class Tag {
constructor(
readonly id: string,
private readonly properties: WorkspaceLegacyProperties,
private readonly pageRecordList: PageRecordList
) {}
private readonly tagOption = this.properties.tagOptions$.map(
tags => tags.find(tag => tag.id === this.id) as TagSchema
);
value = this.tagOption.map(tag => tag?.value || '');
color = this.tagOption.map(tag => tag?.color || '');
createDate = this.tagOption.map(tag => tag?.createDate || Date.now());
updateDate = this.tagOption.map(tag => tag?.updateDate || Date.now());
rename(value: string) {
this.properties.updateTagOption(this.id, {
id: this.id,
value,
color: this.color.value,
createDate: this.createDate.value,
updateDate: Date.now(),
});
}
changeColor(color: string) {
this.properties.updateTagOption(this.id, {
id: this.id,
value: this.value.value,
color,
createDate: this.createDate.value,
updateDate: Date.now(),
});
}
tag(pageId: string) {
const pageRecord = this.pageRecordList.record(pageId).value;
if (!pageRecord) {
return;
}
pageRecord?.setMeta({
tags: [...pageRecord.meta.value.tags, this.id],
});
}
untag(pageId: string) {
const pageRecord = this.pageRecordList.record(pageId).value;
if (!pageRecord) {
return;
}
pageRecord?.setMeta({
tags: pageRecord.meta.value.tags.filter(tagId => tagId !== this.id),
});
}
readonly pageIds = LiveData.computed(get => {
const pages = get(this.pageRecordList.records);
return pages
.filter(page => get(page.meta).tags.includes(this.id))
.map(page => page.id);
});
}
@@ -0,0 +1,16 @@
// hack: map var(--affine-tag-xxx) colors to var(--affine-palette-line-xxx)
export const tagColorMap = (color: string) => {
const mapping: Record<string, string> = {
'var(--affine-tag-red)': 'var(--affine-palette-line-red)',
'var(--affine-tag-teal)': 'var(--affine-palette-line-green)',
'var(--affine-tag-blue)': 'var(--affine-palette-line-blue)',
'var(--affine-tag-yellow)': 'var(--affine-palette-line-yellow)',
'var(--affine-tag-pink)': 'var(--affine-palette-line-magenta)',
'var(--affine-tag-white)': 'var(--affine-palette-line-grey)',
'var(--affine-tag-gray)': 'var(--affine-palette-line-grey)',
'var(--affine-tag-orange)': 'var(--affine-palette-line-orange)',
'var(--affine-tag-purple)': 'var(--affine-palette-line-purple)',
'var(--affine-tag-green)': 'var(--affine-palette-line-green)',
};
return mapping[color] || color;
};
@@ -0,0 +1,3 @@
export { Tag } from './entities/tag';
export { tagColorMap } from './entities/utils';
export { TagService } from './service/tag';
@@ -0,0 +1,85 @@
import { LiveData, type PageRecordList } from '@toeverything/infra';
import { nanoid } from 'nanoid';
import type { WorkspaceLegacyProperties } from '../../workspace';
import { Tag } from '../entities/tag';
export class TagService {
constructor(
private readonly properties: WorkspaceLegacyProperties,
private readonly pageRecordList: PageRecordList
) {}
readonly tags = this.properties.tagOptions$.map(tags =>
tags.map(tag => new Tag(tag.id, this.properties, this.pageRecordList))
);
createTag(value: string, color: string) {
const newId = nanoid();
this.properties.updateTagOptions([
...this.properties.tagOptions$.value,
{
id: newId,
value,
color,
createDate: Date.now(),
updateDate: Date.now(),
},
]);
const newTag = new Tag(newId, this.properties, this.pageRecordList);
return newTag;
}
deleteTag(tagId: string) {
this.properties.removeTagOption(tagId);
}
tagsByPageId(pageId: string) {
return LiveData.computed(get => {
const pageRecord = get(this.pageRecordList.record(pageId));
if (!pageRecord) return [];
const tagIds = get(pageRecord.meta).tags;
return get(this.tags).filter(tag => tagIds.includes(tag.id));
});
}
tagIdsByPageId(pageId: string) {
return this.tagsByPageId(pageId).map(tags => tags.map(tag => tag.id));
}
tagByTagId(tagId?: string) {
return this.tags.map(tags => tags.find(tag => tag.id === tagId));
}
tagMetas = LiveData.computed(get => {
return get(this.tags).map(tag => {
return {
id: tag.id,
title: get(tag.value),
color: get(tag.color),
pageCount: get(tag.pageIds).length,
createDate: get(tag.createDate),
updatedDate: get(tag.updateDate),
};
});
});
private filterFn(value: string, query?: string) {
const trimmedQuery = query?.trim().toLowerCase() ?? '';
const trimmedValue = value.trim().toLowerCase();
return trimmedValue.includes(trimmedQuery);
}
filterTagsByName(name: string) {
return LiveData.computed(get => {
return get(this.tags).filter(tag => this.filterFn(get(tag.value), name));
});
}
tagByTagValue(value: string) {
return LiveData.computed(get => {
return get(this.tags).find(tag => this.filterFn(get(tag.value), value));
});
}
}
@@ -1,4 +1,5 @@
import type { DocsPropertiesMeta, Tag } from '@blocksuite/store';
import type { Tag } from '@affine/env/filter';
import type { DocsPropertiesMeta } from '@blocksuite/store';
import { LiveData } from '@toeverything/infra/livedata';
import type { Workspace } from '@toeverything/infra/workspace';
import { Observable } from 'rxjs';