diff --git a/packages/frontend/core/src/components/affine/page-properties/common.ts b/packages/frontend/core/src/components/affine/page-properties/common.ts index 11b8fc1628..f7bea4ec90 100644 --- a/packages/frontend/core/src/components/affine/page-properties/common.ts +++ b/packages/frontend/core/src/components/affine/page-properties/common.ts @@ -1,6 +1,38 @@ -import { createContext } from 'react'; +import { useQuery } from '@affine/core/hooks/use-query'; +import type { PagePropertyType } from '@affine/core/modules/properties/services/schema'; +import { WorkspaceFlavour } from '@affine/env/workspace'; +import { getWorkspacePageMetaByIdQuery } from '@affine/graphql'; +import { createContext, useContext } from 'react'; +import type { Middleware } from 'swr'; import type { PagePropertiesManager } from './page-properties-manager'; // @ts-expect-error this should always be set export const managerContext = createContext(); + +export const useCloudPageMeta = (type: PagePropertyType) => { + const manager = useContext(managerContext); + const isCloud = manager.workspace.flavour === WorkspaceFlavour.AFFINE_CLOUD; + const { data, error, isLoading } = useQuery({ + query: getWorkspacePageMetaByIdQuery, + variables: { + id: manager.workspace.id, + pageId: manager.pageId, + }, + }); + + if (!!error || !data?.workspace?.pageMeta) return { isCloud, isLoading }; + const pageMeta = data.workspace.pageMeta; + return { + isCloud, + isLoading, + metadata: pageMeta[type as keyof typeof pageMeta], + }; +}; + +export const SWRCustomHandler: Middleware = + next => (key, fetcher: any, config: any) => { + const wrappedFetcher = (...args: any[]) => + fetcher?.(...args).catch(() => null); + return next(key, wrappedFetcher, config); + }; diff --git a/packages/frontend/core/src/components/affine/page-properties/icons-mapping.tsx b/packages/frontend/core/src/components/affine/page-properties/icons-mapping.tsx index ba192afa6f..350b063011 100644 --- a/packages/frontend/core/src/components/affine/page-properties/icons-mapping.tsx +++ b/packages/frontend/core/src/components/affine/page-properties/icons-mapping.tsx @@ -109,6 +109,10 @@ export const getDefaultIconName = ( return 'checkBoxCheckLinear'; case 'number': return 'number'; + case 'createdBy': + return 'account'; + case 'updatedBy': + return 'account'; default: return 'text'; } diff --git a/packages/frontend/core/src/components/affine/page-properties/page-properties-manager.ts b/packages/frontend/core/src/components/affine/page-properties/page-properties-manager.ts index 6db0607a62..8e7da1bc56 100644 --- a/packages/frontend/core/src/components/affine/page-properties/page-properties-manager.ts +++ b/packages/frontend/core/src/components/affine/page-properties/page-properties-manager.ts @@ -35,6 +35,8 @@ export const newPropertyTypes: PagePropertyType[] = [ PagePropertyType.Number, PagePropertyType.Checkbox, PagePropertyType.Date, + PagePropertyType.CreatedBy, + PagePropertyType.UpdatedBy, // TODO(@Peng): add more ]; diff --git a/packages/frontend/core/src/components/affine/page-properties/property-row-value-renderer.tsx b/packages/frontend/core/src/components/affine/page-properties/property-row-value-renderer.tsx index f894280898..9629e9587c 100644 --- a/packages/frontend/core/src/components/affine/page-properties/property-row-value-renderer.tsx +++ b/packages/frontend/core/src/components/affine/page-properties/property-row-value-renderer.tsx @@ -1,16 +1,25 @@ -import { Checkbox, DatePicker, Menu } from '@affine/component'; +import { Avatar, Checkbox, DatePicker, Menu } from '@affine/component'; +import { AuthService } from '@affine/core/modules/cloud'; import type { PageInfoCustomProperty, PageInfoCustomPropertyMeta, PagePropertyType, } from '@affine/core/modules/properties/services/schema'; import { i18nTime, useI18n } from '@affine/i18n'; -import { DocService, useService } from '@toeverything/infra'; +import { DocService, useLiveData, useService } from '@toeverything/infra'; import { noop } from 'lodash-es'; import type { ChangeEventHandler } from 'react'; -import { useCallback, useContext, useEffect, useRef, useState } from 'react'; +import { + useCallback, + useContext, + useEffect, + useMemo, + useRef, + useState, +} from 'react'; +import { SWRConfig } from 'swr'; -import { managerContext } from './common'; +import { managerContext, SWRCustomHandler, useCloudPageMeta } from './common'; import * as styles from './styles.css'; import { TagsInlineEditor } from './tags-inline-editor'; @@ -190,6 +199,63 @@ export const TagsValue = () => { ); }; +const CloudUserAvatar = (props: { type: PagePropertyType }) => { + const session = useService(AuthService).session; + const account = useLiveData(session.account$); + const { isCloud, isLoading, metadata } = useCloudPageMeta(props.type); + + const user = useMemo(() => { + if (isCloud) { + if (!metadata || typeof metadata !== 'object') return null; + return metadata; + } else { + if (!account) return null; + return { name: account.label, avatarUrl: account.avatar }; + } + }, [account, isCloud, metadata]); + + const t = useI18n(); + + if (isLoading) return null; + if (isCloud) { + if (user) { + return ( + <> + + {user.name} + + ); + } + return ( + <> + + + {t['com.affine.page-properties.property-user-avatar-no-record']()} + + + ); + } + if (account) { + return ( + <> + + {account.label} + + ); + } + return null; +}; + +export const UserValue = ({ meta }: PropertyRowValueProps) => { + return ( +
+ ({ ...parent, use: [SWRCustomHandler] })}> + + +
+ ); +}; + export const propertyValueRenderers: Record< PagePropertyType, typeof DateValue @@ -198,6 +264,8 @@ export const propertyValueRenderers: Record< checkbox: CheckboxValue, text: TextValue, number: NumberValue, + createdBy: UserValue, + updatedBy: UserValue, // TODO(@Peng): fix following tags: TagsValue, progress: TextValue, diff --git a/packages/frontend/core/src/components/affine/page-properties/styles.css.ts b/packages/frontend/core/src/components/affine/page-properties/styles.css.ts index fcccab3ebf..61f305e375 100644 --- a/packages/frontend/core/src/components/affine/page-properties/styles.css.ts +++ b/packages/frontend/core/src/components/affine/page-properties/styles.css.ts @@ -349,6 +349,16 @@ export const propertyRowValueTextCell = style([ }, ]); +export const propertyRowValueUserCell = style([ + propertyRowValueCell, + { + border: 'none', + height: '100%', + overflow: 'hidden', + columnGap: '0.5rem', + }, +]); + export const propertyRowValueTextarea = style([ propertyRowValueCell, { diff --git a/packages/frontend/core/src/modules/properties/services/schema.ts b/packages/frontend/core/src/modules/properties/services/schema.ts index b93a607b3e..a7995c7b20 100644 --- a/packages/frontend/core/src/modules/properties/services/schema.ts +++ b/packages/frontend/core/src/modules/properties/services/schema.ts @@ -21,6 +21,8 @@ export enum PagePropertyType { Progress = 'progress', Checkbox = 'checkbox', Tags = 'tags', + CreatedBy = 'createdBy', + UpdatedBy = 'updatedBy', } export const PagePropertyMetaBaseSchema = z.object({ diff --git a/packages/frontend/i18n/src/resources/en.json b/packages/frontend/i18n/src/resources/en.json index 8ae47575df..ec2418cfdf 100644 --- a/packages/frontend/i18n/src/resources/en.json +++ b/packages/frontend/i18n/src/resources/en.json @@ -856,6 +856,7 @@ "com.affine.page-properties.page-info": "Info", "com.affine.page-properties.page-info.view": "View Info", "com.affine.page-properties.property-value-placeholder": "Empty", + "com.affine.page-properties.property-user-avatar-no-record": "No Record", "com.affine.page-properties.property.always-hide": "Always hide", "com.affine.page-properties.property.always-show": "Always show", "com.affine.page-properties.property.checkbox": "Checkbox", @@ -870,6 +871,8 @@ "com.affine.page-properties.property.show-in-view": "Show in view", "com.affine.page-properties.property.tags": "Tags", "com.affine.page-properties.property.text": "Text", + "com.affine.page-properties.property.createdBy": "Created by", + "com.affine.page-properties.property.updatedBy": "Updated by", "com.affine.page-properties.settings.title": "customize properties", "com.affine.page-properties.tags.open-tags-page": "Open tag page", "com.affine.page-properties.tags.selector-header-title": "Select tag or create one",