diff --git a/packages/common/infra/src/modules/doc/entities/record.ts b/packages/common/infra/src/modules/doc/entities/record.ts index 1d2db1ffe0..eeca7c5982 100644 --- a/packages/common/infra/src/modules/doc/entities/record.ts +++ b/packages/common/infra/src/modules/doc/entities/record.ts @@ -43,6 +43,12 @@ export class DocRecord extends Entity<{ id: string }> { }); } + setProperty(propertyId: string, value: string) { + this.docPropertiesStore.updateDocProperties(this.id, { + [propertyId]: value, + }); + } + setMeta(meta: Partial): void { this.docsStore.setDocMeta(this.id, meta); } diff --git a/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/custom/widgets/linked.ts b/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/custom/widgets/linked.ts index a1f1adf1e1..e9d490c7e1 100644 --- a/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/custom/widgets/linked.ts +++ b/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/custom/widgets/linked.ts @@ -1,5 +1,5 @@ import { DocDisplayMetaService } from '@affine/core/modules/doc-display-meta'; -import { WorkspacePropertiesAdapter } from '@affine/core/modules/properties'; +import { JournalService } from '@affine/core/modules/journal'; import { I18n } from '@affine/i18n'; import { track } from '@affine/track'; import type { EditorHost } from '@blocksuite/affine/block-std'; @@ -21,9 +21,9 @@ export function createLinkedWidgetConfig( ) => { const currentWorkspace = framework.get(WorkspaceService).workspace; const rawMetas = currentWorkspace.docCollection.meta.docMetas; - const adapter = framework.get(WorkspacePropertiesAdapter); + const journalService = framework.get(JournalService); const isJournal = (d: DocMeta) => - !!adapter.getJournalPageDateString(d.id); + !!journalService.journalDate$(d.id).value; const docDisplayMetaService = framework.get(DocDisplayMetaService); const docMetas = rawMetas diff --git a/packages/frontend/core/src/components/blocksuite/block-suite-header/favorite/index.tsx b/packages/frontend/core/src/components/blocksuite/block-suite-header/favorite/index.tsx index d60e686bf6..3111ed8995 100644 --- a/packages/frontend/core/src/components/blocksuite/block-suite-header/favorite/index.tsx +++ b/packages/frontend/core/src/components/blocksuite/block-suite-header/favorite/index.tsx @@ -1,5 +1,5 @@ import { FavoriteTag } from '@affine/core/components/page-list'; -import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/properties'; +import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/favorite'; import { toast } from '@affine/core/utils'; import { useI18n } from '@affine/i18n'; import { track } from '@affine/track'; diff --git a/packages/frontend/core/src/components/doc-properties/tags-inline-editor.tsx b/packages/frontend/core/src/components/doc-properties/tags-inline-editor.tsx index 5ee759e9a0..07e84b5137 100644 --- a/packages/frontend/core/src/components/doc-properties/tags-inline-editor.tsx +++ b/packages/frontend/core/src/components/doc-properties/tags-inline-editor.tsx @@ -9,12 +9,11 @@ import { Scrollable, } from '@affine/component'; import { useNavigateHelper } from '@affine/core/components/hooks/use-navigate-helper'; -import { WorkspaceLegacyProperties } from '@affine/core/modules/properties'; import type { Tag } from '@affine/core/modules/tag'; import { DeleteTagConfirmModal, TagService } from '@affine/core/modules/tag'; import { useI18n } from '@affine/i18n'; import { DeleteIcon, MoreHorizontalIcon, TagsIcon } from '@blocksuite/icons/rc'; -import { useLiveData, useService } from '@toeverything/infra'; +import { useLiveData, useService, WorkspaceService } from '@toeverything/infra'; import clsx from 'clsx'; import { clamp } from 'lodash-es'; import type { HTMLAttributes, PropsWithChildren } from 'react'; @@ -84,7 +83,7 @@ export const EditTagMenu = ({ onTagDelete: (tagIds: string[]) => void; }>) => { const t = useI18n(); - const legacyProperties = useService(WorkspaceLegacyProperties); + const workspaceService = useService(WorkspaceService); const tagService = useService(TagService); const tagList = tagService.tagList; const tag = useLiveData(tagList.tagByTagId$(tagId)); @@ -135,7 +134,7 @@ export const EditTagMenu = ({ } onClick={() => { - navigate.jumpToTag(legacyProperties.workspaceId, tag?.id || ''); + navigate.jumpToTag(workspaceService.workspace.id, tag?.id || ''); }} > {t['com.affine.page-properties.tags.open-tags-page']()} @@ -171,7 +170,7 @@ export const EditTagMenu = ({ ), } satisfies Partial; }, [ - legacyProperties.workspaceId, + workspaceService, navigate, onTagDelete, t, diff --git a/packages/frontend/core/src/components/hooks/affine/use-all-page-list-config.tsx b/packages/frontend/core/src/components/hooks/affine/use-all-page-list-config.tsx index 73fc04de10..77490a5966 100644 --- a/packages/frontend/core/src/components/hooks/affine/use-all-page-list-config.tsx +++ b/packages/frontend/core/src/components/hooks/affine/use-all-page-list-config.tsx @@ -1,7 +1,7 @@ import { toast } from '@affine/component'; import { useBlockSuiteDocMeta } from '@affine/core/components/hooks/use-block-suite-page-meta'; import { FavoriteTag } from '@affine/core/components/page-list/components/favorite-tag'; -import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/properties'; +import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/favorite'; import { ShareDocsListService } from '@affine/core/modules/share-doc'; import { PublicPageMode } from '@affine/graphql'; import { useI18n } from '@affine/i18n'; diff --git a/packages/frontend/core/src/components/hooks/affine/use-register-blocksuite-editor-commands.tsx b/packages/frontend/core/src/components/hooks/affine/use-register-blocksuite-editor-commands.tsx index 917221082c..bce9f0d93b 100644 --- a/packages/frontend/core/src/components/hooks/affine/use-register-blocksuite-editor-commands.tsx +++ b/packages/frontend/core/src/components/hooks/affine/use-register-blocksuite-editor-commands.tsx @@ -5,7 +5,7 @@ import { } from '@affine/core/commands'; import { DocInfoService } from '@affine/core/modules/doc-info'; import type { Editor } from '@affine/core/modules/editor'; -import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/properties'; +import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/favorite'; import { WorkspaceFlavour } from '@affine/env/workspace'; import { useI18n } from '@affine/i18n'; import { track } from '@affine/track'; diff --git a/packages/frontend/core/src/components/hooks/use-affine-adapter.ts b/packages/frontend/core/src/components/hooks/use-affine-adapter.ts deleted file mode 100644 index a4e23a4d74..0000000000 --- a/packages/frontend/core/src/components/hooks/use-affine-adapter.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { useService } from '@toeverything/infra'; -import { useDebouncedState } from 'foxact/use-debounced-state'; -import { useEffect } from 'react'; - -import { WorkspacePropertiesAdapter } from '../../modules/properties'; - -function getProxy(obj: T) { - return new Proxy(obj, {}); -} - -const useReactiveAdapter = (adapter: WorkspacePropertiesAdapter) => { - // hack: delay proxy creation to avoid unnecessary re-render + render in another component issue - const [proxy, setProxy] = useDebouncedState(adapter, 0); - useEffect(() => { - // TODO(@Peng): track which properties are used and then filter by property path change - // using Y.YEvent.path - function observe() { - setProxy(getProxy(adapter)); - } - const disposables: (() => void)[] = []; - disposables.push( - adapter.workspace.docCollection.meta.docMetaUpdated.on(observe).dispose - ); - adapter.properties.observeDeep(observe); - disposables.push(() => adapter.properties.unobserveDeep(observe)); - return () => { - for (const dispose of disposables) { - dispose(); - } - }; - }, [adapter, setProxy]); - - return proxy; -}; - -export function useCurrentWorkspacePropertiesAdapter() { - const adapter = useService(WorkspacePropertiesAdapter); - return useReactiveAdapter(adapter); -} diff --git a/packages/frontend/core/src/components/hooks/use-journal.ts b/packages/frontend/core/src/components/hooks/use-journal.ts index b5e87f9656..69d984fcda 100644 --- a/packages/frontend/core/src/components/hooks/use-journal.ts +++ b/packages/frontend/core/src/components/hooks/use-journal.ts @@ -1,4 +1,5 @@ import { EditorSettingService } from '@affine/core/modules/editor-settting'; +import { JournalService } from '@affine/core/modules/journal'; import { i18nTime } from '@affine/i18n'; import { track } from '@affine/track'; import { type DocCollection, Text } from '@blocksuite/affine/store'; @@ -13,7 +14,6 @@ import dayjs from 'dayjs'; import { useCallback, useMemo } from 'react'; import { WorkbenchService } from '../../modules/workbench'; -import { useCurrentWorkspacePropertiesAdapter } from './use-affine-adapter'; import { useDocCollectionHelper } from './use-block-suite-workspace-helper'; type MaybeDate = Date | string | number; @@ -30,14 +30,16 @@ function toDayjs(j?: string | false) { return day; } +/** + * @deprecated use `JournalService` directly + */ export const useJournalHelper = (docCollection: DocCollection) => { const bsWorkspaceHelper = useDocCollectionHelper(docCollection); - const { docsService, editorSettingService } = useServices({ + const { docsService, editorSettingService, journalService } = useServices({ DocsService, EditorSettingService, + JournalService, }); - const adapter = useCurrentWorkspacePropertiesAdapter(); - const { isPageJournal } = useJournalInfoHelper(); /** * @internal @@ -62,10 +64,10 @@ export const useJournalHelper = (docCollection: DocCollection) => { note: editorSettingService.editorSetting.get('affine:note'), }; initDocFromProps(page, docProps); - adapter.setJournalPageDateString(page.id, title); + journalService.setJournalDate(page.id, title); return page; }, - [adapter, bsWorkspaceHelper, docsService.list, editorSettingService] + [journalService, bsWorkspaceHelper, docsService.list, editorSettingService] ); /** @@ -73,17 +75,11 @@ export const useJournalHelper = (docCollection: DocCollection) => { */ const getJournalsByDate = useCallback( (maybeDate: MaybeDate) => { - const day = dayjs(maybeDate); - return Array.from(docCollection.docs.values()).filter(page => { - const pageId = page.id; - if (!isPageJournal(pageId)) return false; - if (page.meta?.trash) return false; - const journalDate = adapter.getJournalPageDateString(page.id); - if (!journalDate) return false; - return day.isSame(journalDate, 'day'); - }); + return journalService.getJournalsByDate( + dayjs(maybeDate).format(JOURNAL_DATE_FORMAT) + ); }, - [adapter, isPageJournal, docCollection.docs] + [journalService] ); /** @@ -92,34 +88,18 @@ export const useJournalHelper = (docCollection: DocCollection) => { const getJournalByDate = useCallback( (maybeDate: MaybeDate) => { const pages = getJournalsByDate(maybeDate); - if (pages.length) return pages[0].getDoc(); + if (pages.length) return pages[0]; return _createJournal(maybeDate); }, [_createJournal, getJournalsByDate] ); - const appendContentToToday = useCallback( - async (content: string) => { - if (!content) return; - const page = getJournalByDate(dayjs().format(JOURNAL_DATE_FORMAT)); - if (!page) return; - const blockId = page.addBlock( - 'affine:paragraph', - { text: new page.Text(content) }, - page.getBlockByFlavour('affine:note')[0].id - ); - return { page, blockId }; - }, - [getJournalByDate] - ); - return useMemo( () => ({ getJournalsByDate, getJournalByDate, - appendContentToToday, }), - [getJournalsByDate, getJournalByDate, appendContentToToday] + [getJournalsByDate, getJournalByDate] ); }; @@ -164,31 +144,33 @@ export const useJournalRouteHelper = (docCollection: DocCollection) => { ); }; -// get journal info that don't rely on `docCollection` +/** + * @deprecated use `JournalService` directly + */ export const useJournalInfoHelper = (pageId?: string | null) => { - const adapter = useCurrentWorkspacePropertiesAdapter(); + const journalService = useService(JournalService); const isPageJournal = useCallback( (pageId: string) => { - return !!adapter.getJournalPageDateString(pageId); + return !!journalService.journalDate$(pageId).value; }, - [adapter] + [journalService] ); const isPageTodayJournal = useCallback( (pageId: string) => { const date = dayjs().format(JOURNAL_DATE_FORMAT); - const d = adapter.getJournalPageDateString(pageId); + const d = journalService.journalDate$(pageId).value; return isPageJournal(pageId) && d === date; }, - [adapter, isPageJournal] + [isPageJournal, journalService] ); const getJournalDateString = useCallback( (pageId: string) => { - return adapter.getJournalPageDateString(pageId); + return journalService.journalDate$(pageId).value; }, - [adapter] + [journalService] ); const getLocalizedJournalDateString = useCallback( diff --git a/packages/frontend/core/src/components/page-list/collections/select-collection.tsx b/packages/frontend/core/src/components/page-list/collections/select-collection.tsx index 5325053653..9ffeb93282 100644 --- a/packages/frontend/core/src/components/page-list/collections/select-collection.tsx +++ b/packages/frontend/core/src/components/page-list/collections/select-collection.tsx @@ -1,6 +1,6 @@ import { toast } from '@affine/component'; import { CollectionService } from '@affine/core/modules/collection'; -import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/properties'; +import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/favorite'; import { useI18n } from '@affine/i18n'; import { useLiveData, useService, WorkspaceService } from '@toeverything/infra'; import { useCallback, useMemo, useState } from 'react'; diff --git a/packages/frontend/core/src/components/page-list/group-definitions.tsx b/packages/frontend/core/src/components/page-list/group-definitions.tsx index 7a180d48b9..6f85ca1bb9 100644 --- a/packages/frontend/core/src/components/page-list/group-definitions.tsx +++ b/packages/frontend/core/src/components/page-list/group-definitions.tsx @@ -1,4 +1,4 @@ -import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/properties'; +import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/favorite'; import type { Tag } from '@affine/core/modules/tag'; import { TagService } from '@affine/core/modules/tag'; import { useI18n } from '@affine/i18n'; diff --git a/packages/frontend/core/src/components/page-list/operation-cell.tsx b/packages/frontend/core/src/components/page-list/operation-cell.tsx index 36d02a986a..785c702720 100644 --- a/packages/frontend/core/src/components/page-list/operation-cell.tsx +++ b/packages/frontend/core/src/components/page-list/operation-cell.tsx @@ -9,8 +9,10 @@ import { useBlockSuiteMetaHelper } from '@affine/core/components/hooks/affine/us import { useTrashModalHelper } from '@affine/core/components/hooks/affine/use-trash-modal-helper'; import { useCatchEventCallback } from '@affine/core/components/hooks/use-catch-event-hook'; import { DocInfoService } from '@affine/core/modules/doc-info'; -import { FavoriteService } from '@affine/core/modules/favorite'; -import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/properties'; +import { + CompatibleFavoriteItemsAdapter, + FavoriteService, +} from '@affine/core/modules/favorite'; import { WorkbenchService } from '@affine/core/modules/workbench'; import type { Collection, DeleteCollectionInfo } from '@affine/env/filter'; import { useI18n } from '@affine/i18n'; diff --git a/packages/frontend/core/src/components/page-list/use-filtered-page-metas.tsx b/packages/frontend/core/src/components/page-list/use-filtered-page-metas.tsx index c5b7aa0df8..140c9720ac 100644 --- a/packages/frontend/core/src/components/page-list/use-filtered-page-metas.tsx +++ b/packages/frontend/core/src/components/page-list/use-filtered-page-metas.tsx @@ -1,4 +1,4 @@ -import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/properties'; +import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/favorite'; import { ShareDocsListService } from '@affine/core/modules/share-doc'; import type { Collection, Filter } from '@affine/env/filter'; import { PublicPageMode } from '@affine/graphql'; diff --git a/packages/frontend/core/src/components/page-list/view/collection-operations.tsx b/packages/frontend/core/src/components/page-list/view/collection-operations.tsx index e249ee2011..df7a862321 100644 --- a/packages/frontend/core/src/components/page-list/view/collection-operations.tsx +++ b/packages/frontend/core/src/components/page-list/view/collection-operations.tsx @@ -1,7 +1,7 @@ import type { MenuItemProps } from '@affine/component'; import { Menu, MenuItem } from '@affine/component'; import { useDeleteCollectionInfo } from '@affine/core/components/hooks/affine/use-delete-collection-info'; -import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/properties'; +import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/favorite'; import { WorkbenchService } from '@affine/core/modules/workbench'; import type { Collection } from '@affine/env/filter'; import { useI18n } from '@affine/i18n'; diff --git a/packages/frontend/core/src/components/page-list/view/edit-collection/rules-mode.tsx b/packages/frontend/core/src/components/page-list/view/edit-collection/rules-mode.tsx index 9bcf2c30e3..ddd19a3999 100644 --- a/packages/frontend/core/src/components/page-list/view/edit-collection/rules-mode.tsx +++ b/packages/frontend/core/src/components/page-list/view/edit-collection/rules-mode.tsx @@ -1,5 +1,5 @@ import { Button, IconButton, Tooltip } from '@affine/component'; -import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/properties'; +import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/favorite'; import type { Collection } from '@affine/env/filter'; import { Trans, useI18n } from '@affine/i18n'; import type { DocMeta } from '@blocksuite/affine/store'; diff --git a/packages/frontend/core/src/components/page-list/view/edit-collection/select-page.tsx b/packages/frontend/core/src/components/page-list/view/edit-collection/select-page.tsx index 28a34848cb..20d24de0c3 100644 --- a/packages/frontend/core/src/components/page-list/view/edit-collection/select-page.tsx +++ b/packages/frontend/core/src/components/page-list/view/edit-collection/select-page.tsx @@ -1,6 +1,6 @@ import { IconButton, Menu, toast } from '@affine/component'; import { useBlockSuiteDocMeta } from '@affine/core/components/hooks/use-block-suite-page-meta'; -import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/properties'; +import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/favorite'; import { ShareDocsListService } from '@affine/core/modules/share-doc'; import { PublicPageMode } from '@affine/graphql'; import { Trans, useI18n } from '@affine/i18n'; diff --git a/packages/frontend/core/src/mobile/components/doc-card/index.tsx b/packages/frontend/core/src/mobile/components/doc-card/index.tsx index 6b0a75aec7..dfd0509735 100644 --- a/packages/frontend/core/src/mobile/components/doc-card/index.tsx +++ b/packages/frontend/core/src/mobile/components/doc-card/index.tsx @@ -2,7 +2,7 @@ import { IconButton } from '@affine/component'; import { useCatchEventCallback } from '@affine/core/components/hooks/use-catch-event-hook'; import { PagePreview } from '@affine/core/components/page-list/page-content-preview'; import { IsFavoriteIcon } from '@affine/core/components/pure/icons'; -import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/properties'; +import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/favorite'; import { WorkbenchLink, type WorkbenchLinkProps, diff --git a/packages/frontend/core/src/mobile/views/all-docs/collection/item.tsx b/packages/frontend/core/src/mobile/views/all-docs/collection/item.tsx index 9fe31a420c..e192724b4f 100644 --- a/packages/frontend/core/src/mobile/views/all-docs/collection/item.tsx +++ b/packages/frontend/core/src/mobile/views/all-docs/collection/item.tsx @@ -1,7 +1,7 @@ import { IconButton } from '@affine/component'; import type { CollectionMeta } from '@affine/core/components/page-list'; import { IsFavoriteIcon } from '@affine/core/components/pure/icons'; -import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/properties'; +import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/favorite'; import { WorkbenchLink } from '@affine/core/modules/workbench'; import { ViewLayersIcon } from '@blocksuite/icons/rc'; import { useLiveData, useService } from '@toeverything/infra'; diff --git a/packages/frontend/core/src/mobile/views/all-docs/tag/item.tsx b/packages/frontend/core/src/mobile/views/all-docs/tag/item.tsx index fbcb20968d..1ae29eebb0 100644 --- a/packages/frontend/core/src/mobile/views/all-docs/tag/item.tsx +++ b/packages/frontend/core/src/mobile/views/all-docs/tag/item.tsx @@ -1,6 +1,6 @@ import { IconButton } from '@affine/component'; import { IsFavoriteIcon } from '@affine/core/components/pure/icons'; -import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/properties'; +import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/favorite'; import type { Tag } from '@affine/core/modules/tag'; import { WorkbenchLink } from '@affine/core/modules/workbench'; import { useLiveData, useService } from '@toeverything/infra'; diff --git a/packages/frontend/core/src/modules/doc-display-meta/index.ts b/packages/frontend/core/src/modules/doc-display-meta/index.ts index 90422c98fb..1c612be44e 100644 --- a/packages/frontend/core/src/modules/doc-display-meta/index.ts +++ b/packages/frontend/core/src/modules/doc-display-meta/index.ts @@ -5,7 +5,7 @@ import { WorkspaceScope, } from '@toeverything/infra'; -import { WorkspacePropertiesAdapter } from '../properties'; +import { JournalService } from '../journal'; import { DocDisplayMetaService } from './services/doc-display-meta'; export { DocDisplayMetaService }; @@ -14,7 +14,7 @@ export function configureDocDisplayMetaModule(framework: Framework) { framework .scope(WorkspaceScope) .service(DocDisplayMetaService, [ - WorkspacePropertiesAdapter, + JournalService, DocsService, FeatureFlagService, ]); diff --git a/packages/frontend/core/src/modules/doc-display-meta/services/doc-display-meta.ts b/packages/frontend/core/src/modules/doc-display-meta/services/doc-display-meta.ts index 6f82dc5566..0f66163fa1 100644 --- a/packages/frontend/core/src/modules/doc-display-meta/services/doc-display-meta.ts +++ b/packages/frontend/core/src/modules/doc-display-meta/services/doc-display-meta.ts @@ -29,7 +29,7 @@ import { LiveData, Service } from '@toeverything/infra'; import type { Dayjs } from 'dayjs'; import dayjs from 'dayjs'; -import type { WorkspacePropertiesAdapter } from '../../properties'; +import type { JournalService } from '../../journal'; type IconType = 'rc' | 'lit'; interface DocDisplayIconOptions { @@ -83,7 +83,7 @@ const icons = { rc: rcIcons, lit: litIcons } as { export class DocDisplayMetaService extends Service { constructor( - private readonly propertiesAdapter: WorkspacePropertiesAdapter, + private readonly journalService: JournalService, private readonly docsService: DocsService, private readonly featureFlagService: FeatureFlagService ) { @@ -110,7 +110,7 @@ export class DocDisplayMetaService extends Service { // journal icon const journalDate = this._toDayjs( - this.propertiesAdapter.getJournalPageDateString(docId) + this.journalService.journalDate$(docId).value ); if (journalDate) { if (!options?.compareDate) return iconSet.TodayIcon; @@ -148,8 +148,7 @@ export class DocDisplayMetaService extends Service { const doc = get(this.docsService.list.doc$(docId)); const docTitle = doc ? get(doc.title$) : undefined; - const journalDateString = - this.propertiesAdapter.getJournalPageDateString(docId); + const journalDateString = get(this.journalService.journalDate$(docId)); // journal if (journalDateString) { diff --git a/packages/frontend/core/src/modules/explorer/views/nodes/collection/index.tsx b/packages/frontend/core/src/modules/explorer/views/nodes/collection/index.tsx index eceadff47a..632dc47085 100644 --- a/packages/frontend/core/src/modules/explorer/views/nodes/collection/index.tsx +++ b/packages/frontend/core/src/modules/explorer/views/nodes/collection/index.tsx @@ -10,7 +10,7 @@ import { useEditCollection, } from '@affine/core/components/page-list'; import { CollectionService } from '@affine/core/modules/collection'; -import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/properties'; +import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/favorite'; import { ShareDocsListService } from '@affine/core/modules/share-doc'; import type { AffineDNDData } from '@affine/core/types/dnd'; import type { Collection } from '@affine/env/filter'; diff --git a/packages/frontend/core/src/modules/explorer/views/nodes/collection/operations.tsx b/packages/frontend/core/src/modules/explorer/views/nodes/collection/operations.tsx index c66496ce7f..2d57ec7192 100644 --- a/packages/frontend/core/src/modules/explorer/views/nodes/collection/operations.tsx +++ b/packages/frontend/core/src/modules/explorer/views/nodes/collection/operations.tsx @@ -8,7 +8,7 @@ import { usePageHelper } from '@affine/core/components/blocksuite/block-suite-pa import { useDeleteCollectionInfo } from '@affine/core/components/hooks/affine/use-delete-collection-info'; import { IsFavoriteIcon } from '@affine/core/components/pure/icons'; import { CollectionService } from '@affine/core/modules/collection'; -import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/properties'; +import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/favorite'; import { WorkbenchService } from '@affine/core/modules/workbench'; import { useI18n } from '@affine/i18n'; import { track } from '@affine/track'; diff --git a/packages/frontend/core/src/modules/explorer/views/nodes/doc/index.tsx b/packages/frontend/core/src/modules/explorer/views/nodes/doc/index.tsx index 5af452654b..d86b2f5f4c 100644 --- a/packages/frontend/core/src/modules/explorer/views/nodes/doc/index.tsx +++ b/packages/frontend/core/src/modules/explorer/views/nodes/doc/index.tsx @@ -56,7 +56,6 @@ export const ExplorerDocNode = ({ DocDisplayMetaService, FeatureFlagService, }); - // const pageInfoAdapter = useCurrentWorkspacePropertiesAdapter(); const active = useLiveData(globalContextService.globalContext.docId.$) === docId; diff --git a/packages/frontend/core/src/modules/explorer/views/nodes/doc/operations.tsx b/packages/frontend/core/src/modules/explorer/views/nodes/doc/operations.tsx index 24bbe6dd6f..654f903f53 100644 --- a/packages/frontend/core/src/modules/explorer/views/nodes/doc/operations.tsx +++ b/packages/frontend/core/src/modules/explorer/views/nodes/doc/operations.tsx @@ -9,7 +9,7 @@ import { usePageHelper } from '@affine/core/components/blocksuite/block-suite-pa import { useBlockSuiteMetaHelper } from '@affine/core/components/hooks/affine/use-block-suite-meta-helper'; import { useAsyncCallback } from '@affine/core/components/hooks/affine-async-hooks'; import { IsFavoriteIcon } from '@affine/core/components/pure/icons'; -import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/properties'; +import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/favorite'; import { WorkbenchService } from '@affine/core/modules/workbench'; import { useI18n } from '@affine/i18n'; import { track } from '@affine/track'; diff --git a/packages/frontend/core/src/modules/explorer/views/nodes/folder/index.tsx b/packages/frontend/core/src/modules/explorer/views/nodes/folder/index.tsx index 141a9df1bd..d0ccf0a87a 100644 --- a/packages/frontend/core/src/modules/explorer/views/nodes/folder/index.tsx +++ b/packages/frontend/core/src/modules/explorer/views/nodes/folder/index.tsx @@ -15,11 +15,11 @@ import { useSelectDoc, useSelectTag, } from '@affine/core/components/page-list/selector'; +import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/favorite'; import { type FolderNode, OrganizeService, } from '@affine/core/modules/organize'; -import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/properties'; import { WorkbenchService } from '@affine/core/modules/workbench'; import type { AffineDNDData } from '@affine/core/types/dnd'; import { Unreachable } from '@affine/env/constant'; diff --git a/packages/frontend/core/src/modules/explorer/views/nodes/folder/operations.tsx b/packages/frontend/core/src/modules/explorer/views/nodes/folder/operations.tsx index f57156755f..b2a851e700 100644 --- a/packages/frontend/core/src/modules/explorer/views/nodes/folder/operations.tsx +++ b/packages/frontend/core/src/modules/explorer/views/nodes/folder/operations.tsx @@ -1,6 +1,6 @@ import { MenuItem } from '@affine/component'; import { IsFavoriteIcon } from '@affine/core/components/pure/icons'; -import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/properties'; +import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/favorite'; import { useI18n } from '@affine/i18n'; import { useLiveData, useService } from '@toeverything/infra'; import { useMemo } from 'react'; diff --git a/packages/frontend/core/src/modules/explorer/views/sections/migration-favorites/index.tsx b/packages/frontend/core/src/modules/explorer/views/sections/migration-favorites/index.tsx index 703b9e2df2..6e8c404999 100644 --- a/packages/frontend/core/src/modules/explorer/views/sections/migration-favorites/index.tsx +++ b/packages/frontend/core/src/modules/explorer/views/sections/migration-favorites/index.tsx @@ -1,6 +1,6 @@ import { IconButton, useConfirmModal } from '@affine/component'; import { ExplorerTreeRoot } from '@affine/core/modules/explorer/views/tree'; -import { MigrationFavoriteItemsAdapter } from '@affine/core/modules/properties'; +import { MigrationFavoriteItemsAdapter } from '@affine/core/modules/favorite'; import { Trans, useI18n } from '@affine/i18n'; import { track } from '@affine/track'; import { BroomIcon, HelpIcon } from '@blocksuite/icons/rc'; diff --git a/packages/frontend/core/src/modules/favorite/index.ts b/packages/frontend/core/src/modules/favorite/index.ts index 983860ae26..441fc13724 100644 --- a/packages/frontend/core/src/modules/favorite/index.ts +++ b/packages/frontend/core/src/modules/favorite/index.ts @@ -8,16 +8,26 @@ import { import { AuthService } from '../cloud'; import { FavoriteList } from './entities/favorite-list'; import { FavoriteService } from './services/favorite'; +import { + CompatibleFavoriteItemsAdapter, + MigrationFavoriteItemsAdapter, +} from './services/old/adapter'; import { FavoriteStore } from './stores/favorite'; export { FavoriteSupportType, isFavoriteSupportType } from './constant'; export type { FavoriteList } from './entities/favorite-list'; export { FavoriteService } from './services/favorite'; +export { + CompatibleFavoriteItemsAdapter, + MigrationFavoriteItemsAdapter, +} from './services/old/adapter'; export function configureFavoriteModule(framework: Framework) { framework .scope(WorkspaceScope) .service(FavoriteService) .entity(FavoriteList, [FavoriteStore]) - .store(FavoriteStore, [AuthService, WorkspaceDBService, WorkspaceService]); + .store(FavoriteStore, [AuthService, WorkspaceDBService, WorkspaceService]) + .service(MigrationFavoriteItemsAdapter, [WorkspaceService]) + .service(CompatibleFavoriteItemsAdapter, [FavoriteService]); } diff --git a/packages/frontend/core/src/modules/properties/services/adapter.ts b/packages/frontend/core/src/modules/favorite/services/old/adapter.ts similarity index 95% rename from packages/frontend/core/src/modules/properties/services/adapter.ts rename to packages/frontend/core/src/modules/favorite/services/old/adapter.ts index d40ee7ecef..8a94138a44 100644 --- a/packages/frontend/core/src/modules/properties/services/adapter.ts +++ b/packages/frontend/core/src/modules/favorite/services/old/adapter.ts @@ -6,7 +6,8 @@ import { LiveData, Service } from '@toeverything/infra'; import { defaultsDeep } from 'lodash-es'; import { Observable } from 'rxjs'; -import type { FavoriteService, FavoriteSupportType } from '../../favorite'; +import type { FavoriteSupportType } from '../../constant'; +import type { FavoriteService } from '../favorite'; import { PagePropertyType, PageSystemPropertyId, @@ -23,8 +24,10 @@ const AFFINE_PROPERTIES_ID = 'affine:workspace-properties'; * May abstract the adapter for each property type, e.g. PagePropertiesAdapter, SchemaAdapter, etc. * So that the adapter could be more focused and easier to maintain (like assigning default values) * However the properties for an abstraction may not be limited to a single yjs map. + * + * @deprecated use docService.doc.properties$ */ -export class WorkspacePropertiesAdapter extends Service { +class WorkspacePropertiesAdapter { // provides a easy-to-use interface for workspace properties public readonly proxy: WorkspaceAffineProperties; public readonly properties: Y.Map; @@ -38,7 +41,6 @@ export class WorkspacePropertiesAdapter extends Service { } constructor(public readonly workspaceService: WorkspaceService) { - super(); // check if properties exists, if not, create one const rootDoc = workspaceService.workspace.docCollection.doc; this.properties = rootDoc.getMap(AFFINE_PROPERTIES_ID); @@ -165,7 +167,9 @@ export class WorkspacePropertiesAdapter extends Service { } export class MigrationFavoriteItemsAdapter extends Service { - constructor(private readonly adapter: WorkspacePropertiesAdapter) { + adapter = new WorkspacePropertiesAdapter(this.workspaceService); + + constructor(public readonly workspaceService: WorkspaceService) { super(); } diff --git a/packages/frontend/core/src/modules/properties/services/schema.ts b/packages/frontend/core/src/modules/favorite/services/old/schema.ts similarity index 100% rename from packages/frontend/core/src/modules/properties/services/schema.ts rename to packages/frontend/core/src/modules/favorite/services/old/schema.ts diff --git a/packages/frontend/core/src/modules/index.ts b/packages/frontend/core/src/modules/index.ts index 90297ef27a..000fbd996d 100644 --- a/packages/frontend/core/src/modules/index.ts +++ b/packages/frontend/core/src/modules/index.ts @@ -16,11 +16,11 @@ import { configureFavoriteModule } from './favorite'; import { configureFindInPageModule } from './find-in-page'; import { configureI18nModule } from './i18n'; import { configureImportTemplateModule } from './import-template'; +import { configureJournalModule } from './journal'; import { configureNavigationModule } from './navigation'; import { configureOrganizeModule } from './organize'; import { configurePeekViewModule } from './peek-view'; import { configurePermissionsModule } from './permissions'; -import { configureWorkspacePropertiesModule } from './properties'; import { configureQuickSearchModule } from './quicksearch'; import { configureShareDocsModule } from './share-doc'; import { configureShareSettingModule } from './share-setting'; @@ -36,7 +36,6 @@ export function configureCommonModules(framework: Framework) { configureCollectionModule(framework); configureNavigationModule(framework); configureTagModule(framework); - configureWorkspacePropertiesModule(framework); configureCloudModule(framework); configureQuotaModule(framework); configurePermissionsModule(framework); @@ -61,4 +60,5 @@ export function configureCommonModules(framework: Framework) { configureUserspaceModule(framework); configureDocInfoModule(framework); configureAppSidebarModule(framework); + configureJournalModule(framework); } diff --git a/packages/frontend/core/src/modules/journal/index.ts b/packages/frontend/core/src/modules/journal/index.ts new file mode 100644 index 0000000000..8f97409ca5 --- /dev/null +++ b/packages/frontend/core/src/modules/journal/index.ts @@ -0,0 +1,23 @@ +import { + DocScope, + DocService, + DocsService, + type Framework, + WorkspaceScope, +} from '@toeverything/infra'; + +import { JournalService } from './services/journal'; +import { JournalDocService } from './services/journal-doc'; +import { JournalStore } from './store/journal'; + +export { JournalService } from './services/journal'; +export { JournalDocService } from './services/journal-doc'; + +export function configureJournalModule(framework: Framework) { + framework + .scope(WorkspaceScope) + .service(JournalService, [JournalStore]) + .store(JournalStore, [DocsService]) + .scope(DocScope) + .service(JournalDocService, [DocService, JournalService]); +} diff --git a/packages/frontend/core/src/modules/journal/services/journal-doc.ts b/packages/frontend/core/src/modules/journal/services/journal-doc.ts new file mode 100644 index 0000000000..ead865bc1b --- /dev/null +++ b/packages/frontend/core/src/modules/journal/services/journal-doc.ts @@ -0,0 +1,20 @@ +import { type DocService, Service } from '@toeverything/infra'; + +import type { JournalService } from './journal'; + +export class JournalDocService extends Service { + constructor( + private readonly docService: DocService, + private readonly journalService: JournalService + ) { + super(); + } + + readonly journalDate$ = this.journalService.journalDate$( + this.docService.doc.id + ); + + setJournalDate(date: string) { + this.journalService.setJournalDate(this.docService.doc.id, date); + } +} diff --git a/packages/frontend/core/src/modules/journal/services/journal.ts b/packages/frontend/core/src/modules/journal/services/journal.ts new file mode 100644 index 0000000000..39ec9ed482 --- /dev/null +++ b/packages/frontend/core/src/modules/journal/services/journal.ts @@ -0,0 +1,21 @@ +import { LiveData, Service } from '@toeverything/infra'; + +import type { JournalStore } from '../store/journal'; + +export class JournalService extends Service { + constructor(private readonly store: JournalStore) { + super(); + } + + journalDate$(docId: string) { + return LiveData.from(this.store.watchDocJournalDate(docId), undefined); + } + + setJournalDate(docId: string, date: string) { + this.store.setDocJournalDate(docId, date); + } + + getJournalsByDate(date: string) { + return this.store.getDocsByJournalDate(date); + } +} diff --git a/packages/frontend/core/src/modules/journal/store/journal.ts b/packages/frontend/core/src/modules/journal/store/journal.ts new file mode 100644 index 0000000000..658b50adb9 --- /dev/null +++ b/packages/frontend/core/src/modules/journal/store/journal.ts @@ -0,0 +1,43 @@ +import type { DocsService } from '@toeverything/infra'; +import { LiveData, Store } from '@toeverything/infra'; +import type { Observable } from 'rxjs'; + +function isJournalString(j?: string | false) { + return j ? !!j?.match(/^\d{4}-\d{2}-\d{2}$/) : false; +} + +export class JournalStore extends Store { + constructor(private readonly docsService: DocsService) { + super(); + } + + watchDocJournalDate(docId: string): Observable { + return LiveData.computed(get => { + const doc = get(this.docsService.list.doc$(docId)); + if (!doc) { + // if doc not exists + return undefined; + } + const journal = get(doc.properties$.selector(p => p.journal)); + if (journal && !isJournalString(journal)) { + return undefined; + } + return journal ?? undefined; + }); + } + + setDocJournalDate(docId: string, date: string) { + const doc = this.docsService.list.doc$(docId).value; + if (!doc) { + // doc not exists, do nothing + return; + } + doc.setProperty('journal', date); + } + + getDocsByJournalDate(date: string) { + return this.docsService.list.docs$.value.filter( + doc => doc.properties$.value.journal === date + ); + } +} diff --git a/packages/frontend/core/src/modules/properties/index.ts b/packages/frontend/core/src/modules/properties/index.ts deleted file mode 100644 index 135dd49568..0000000000 --- a/packages/frontend/core/src/modules/properties/index.ts +++ /dev/null @@ -1,29 +0,0 @@ -export { - CompatibleFavoriteItemsAdapter, - MigrationFavoriteItemsAdapter, - WorkspacePropertiesAdapter, -} from './services/adapter'; -export { WorkspaceLegacyProperties } from './services/legacy-properties'; - -import { - type Framework, - WorkspaceScope, - WorkspaceService, -} from '@toeverything/infra'; - -import { FavoriteService } from '../favorite'; -import { - CompatibleFavoriteItemsAdapter, - MigrationFavoriteItemsAdapter, - WorkspacePropertiesAdapter, -} from './services/adapter'; -import { WorkspaceLegacyProperties } from './services/legacy-properties'; - -export function configureWorkspacePropertiesModule(framework: Framework) { - framework - .scope(WorkspaceScope) - .service(WorkspaceLegacyProperties, [WorkspaceService]) - .service(WorkspacePropertiesAdapter, [WorkspaceService]) - .service(MigrationFavoriteItemsAdapter, [WorkspacePropertiesAdapter]) - .service(CompatibleFavoriteItemsAdapter, [FavoriteService]); -} diff --git a/packages/frontend/core/src/modules/properties/services/legacy-properties.ts b/packages/frontend/core/src/modules/properties/services/legacy-properties.ts deleted file mode 100644 index ec98809e2b..0000000000 --- a/packages/frontend/core/src/modules/properties/services/legacy-properties.ts +++ /dev/null @@ -1,86 +0,0 @@ -import type { Tag } from '@affine/env/filter'; -import type { DocsPropertiesMeta } from '@blocksuite/affine/store'; -import type { WorkspaceService } from '@toeverything/infra'; -import { LiveData, Service } from '@toeverything/infra'; -import { Observable } from 'rxjs'; - -/** - * @deprecated use WorkspacePropertiesAdapter instead (later) - */ -export class WorkspaceLegacyProperties extends Service { - constructor(private readonly workspaceService: WorkspaceService) { - super(); - } - - get workspaceId() { - return this.workspaceService.workspace.id; - } - - get properties() { - return this.workspaceService.workspace.docCollection.meta.properties; - } - get tagOptions() { - return this.properties.tags?.options ?? []; - } - - updateProperties = (properties: DocsPropertiesMeta) => { - this.workspaceService.workspace.docCollection.meta.setProperties( - properties - ); - }; - - subscribe(cb: () => void) { - const disposable = - this.workspaceService.workspace.docCollection.meta.docMetaUpdated.on(cb); - return disposable.dispose; - } - - properties$ = LiveData.from( - new Observable(sub => { - return this.subscribe(() => sub.next(this.properties)); - }), - this.properties - ); - - tagOptions$ = LiveData.from( - new Observable(sub => { - return this.subscribe(() => sub.next(this.tagOptions)); - }), - this.tagOptions - ); - - updateTagOptions = (options: Tag[]) => { - this.updateProperties({ - ...this.properties, - tags: { - options, - }, - }); - }; - - updateTagOption = (id: string, option: Tag) => { - this.updateTagOptions(this.tagOptions.map(o => (o.id === id ? option : o))); - }; - - removeTagOption = (id: string) => { - this.workspaceService.workspace.docCollection.doc.transact(() => { - this.updateTagOptions(this.tagOptions.filter(o => o.id !== id)); - // need to remove tag from all pages - this.workspaceService.workspace.docCollection.docs.forEach(doc => { - const tags = doc.meta?.tags ?? []; - if (tags.includes(id)) { - this.updatePageTags( - doc.id, - tags.filter(t => t !== id) - ); - } - }); - }); - }; - - updatePageTags = (pageId: string, tags: string[]) => { - this.workspaceService.workspace.docCollection.setDocMeta(pageId, { - tags, - }); - }; -} diff --git a/packages/frontend/core/src/modules/tag/index.ts b/packages/frontend/core/src/modules/tag/index.ts index 69c0f1f750..69179f7aa0 100644 --- a/packages/frontend/core/src/modules/tag/index.ts +++ b/packages/frontend/core/src/modules/tag/index.ts @@ -7,9 +7,9 @@ import { DocsService, type Framework, WorkspaceScope, + WorkspaceService, } from '@toeverything/infra'; -import { WorkspaceLegacyProperties } from '../properties'; import { Tag } from './entities/tag'; import { TagList } from './entities/tag-list'; import { TagService } from './service/tag'; @@ -19,7 +19,7 @@ export function configureTagModule(framework: Framework) { framework .scope(WorkspaceScope) .service(TagService) - .store(TagStore, [WorkspaceLegacyProperties]) + .store(TagStore, [WorkspaceService]) .entity(TagList, [TagStore, DocsService]) .entity(Tag, [TagStore, DocsService]); } diff --git a/packages/frontend/core/src/modules/tag/stores/tag.ts b/packages/frontend/core/src/modules/tag/stores/tag.ts index 28ce9e760d..f22435d2f6 100644 --- a/packages/frontend/core/src/modules/tag/stores/tag.ts +++ b/packages/frontend/core/src/modules/tag/stores/tag.ts @@ -1,24 +1,43 @@ -import type { Tag as TagSchema } from '@affine/env/filter'; -import { Store } from '@toeverything/infra'; +import type { Tag, Tag as TagSchema } from '@affine/env/filter'; +import type { DocsPropertiesMeta } from '@blocksuite/affine/store'; +import type { WorkspaceService } from '@toeverything/infra'; +import { LiveData, Store } from '@toeverything/infra'; import { nanoid } from 'nanoid'; - -import type { WorkspaceLegacyProperties } from '../../properties'; +import { Observable } from 'rxjs'; export class TagStore extends Store { - constructor(private readonly properties: WorkspaceLegacyProperties) { + get properties() { + return this.workspaceService.workspace.docCollection.meta.properties; + } + get tagOptions() { + return this.properties.tags?.options ?? []; + } + + tagOptions$ = LiveData.from( + new Observable(sub => { + return this.subscribe(() => sub.next(this.tagOptions)); + }), + this.tagOptions + ); + + subscribe(cb: () => void) { + const disposable = + this.workspaceService.workspace.docCollection.meta.docMetaUpdated.on(cb); + return disposable.dispose; + } + + constructor(private readonly workspaceService: WorkspaceService) { super(); } watchTagIds() { - return this.properties.tagOptions$ - .map(tags => tags.map(tag => tag.id)) - .asObservable(); + return this.tagOptions$.map(tags => tags.map(tag => tag.id)).asObservable(); } createNewTag(value: string, color: string) { const newId = nanoid(); - this.properties.updateTagOptions([ - ...this.properties.tagOptions$.value, + this.updateTagOptions([ + ...this.tagOptions$.value, { id: newId, value, @@ -30,24 +49,65 @@ export class TagStore extends Store { return newId; } + updateProperties = (properties: DocsPropertiesMeta) => { + this.workspaceService.workspace.docCollection.meta.setProperties( + properties + ); + }; + + updateTagOptions = (options: Tag[]) => { + this.updateProperties({ + ...this.properties, + tags: { + options, + }, + }); + }; + + updateTagOption = (id: string, option: Tag) => { + this.updateTagOptions(this.tagOptions.map(o => (o.id === id ? option : o))); + }; + + removeTagOption = (id: string) => { + this.workspaceService.workspace.docCollection.doc.transact(() => { + this.updateTagOptions(this.tagOptions.filter(o => o.id !== id)); + // need to remove tag from all pages + this.workspaceService.workspace.docCollection.docs.forEach(doc => { + const tags = doc.meta?.tags ?? []; + if (tags.includes(id)) { + this.updatePageTags( + doc.id, + tags.filter(t => t !== id) + ); + } + }); + }); + }; + + updatePageTags = (pageId: string, tags: string[]) => { + this.workspaceService.workspace.docCollection.setDocMeta(pageId, { + tags, + }); + }; + deleteTag(id: string) { - this.properties.removeTagOption(id); + this.removeTagOption(id); } watchTagInfo(id: string) { - return this.properties.tagOptions$.map( + return this.tagOptions$.map( tags => tags.find(tag => tag.id === id) as TagSchema | undefined ); } updateTagInfo(id: string, tagInfo: Partial) { - const tag = this.properties.tagOptions$.value.find(tag => tag.id === id) as + const tag = this.tagOptions$.value.find(tag => tag.id === id) as | TagSchema | undefined; if (!tag) { return; } - this.properties.updateTagOption(id, { + this.updateTagOption(id, { id: id, value: tag.value, color: tag.color,