fix(core): doc info event tracking issues (#8868)

fix AF-1769
This commit is contained in:
pengx17
2024-11-20 01:15:51 +00:00
parent 401106203c
commit 3f5dadb4f5
10 changed files with 51 additions and 43 deletions
@@ -131,11 +131,13 @@ export const DocPropertyRow = ({
typeInfo && 'value' in typeInfo ? typeInfo.value : undefined; typeInfo && 'value' in typeInfo ? typeInfo.value : undefined;
const handleChange = useCallback( const handleChange = useCallback(
(value: any) => { (value: any, skipCommit?: boolean) => {
if (typeof value !== 'string') { if (!skipCommit) {
throw new Error('only allow string value'); if (typeof value !== 'string') {
throw new Error('only allow string value');
}
docService.doc.record.setCustomProperty(propertyInfo.id, value);
} }
docService.doc.record.setCustomProperty(propertyInfo.id, value);
onChange?.(value); onChange?.(value);
}, },
[docService, onChange, propertyInfo] [docService, onChange, propertyInfo]
@@ -1,6 +1,5 @@
import { TagService, useDeleteTagConfirmModal } from '@affine/core/modules/tag'; import { TagService, useDeleteTagConfirmModal } from '@affine/core/modules/tag';
import { useI18n } from '@affine/i18n'; import { useI18n } from '@affine/i18n';
import track from '@affine/track';
import { TagsIcon } from '@blocksuite/icons/rc'; import { TagsIcon } from '@blocksuite/icons/rc';
import { import {
LiveData, LiveData,
@@ -26,6 +25,7 @@ interface TagsEditorProps {
interface TagsInlineEditorProps extends TagsEditorProps { interface TagsInlineEditorProps extends TagsEditorProps {
placeholder?: string; placeholder?: string;
className?: string; className?: string;
onChange?: (value: unknown) => void;
} }
export const TagsInlineEditor = ({ export const TagsInlineEditor = ({
@@ -33,19 +33,18 @@ export const TagsInlineEditor = ({
readonly, readonly,
placeholder, placeholder,
className, className,
onChange,
}: TagsInlineEditorProps) => { }: TagsInlineEditorProps) => {
const workspace = useService(WorkspaceService); const workspace = useService(WorkspaceService);
const tagService = useService(TagService); const tagService = useService(TagService);
const tagIds = useLiveData(tagService.tagList.tagIdsByPageId$(pageId)); const tagIds$ = tagService.tagList.tagIdsByPageId$(pageId);
const tagIds = useLiveData(tagIds$);
const tags = useLiveData(tagService.tagList.tags$); const tags = useLiveData(tagService.tagList.tags$);
const tagColors = tagService.tagColors; const tagColors = tagService.tagColors;
const onCreateTag = useCallback( const onCreateTag = useCallback(
(name: string, color: string) => { (name: string, color: string) => {
const newTag = tagService.tagList.createTag(name, color); const newTag = tagService.tagList.createTag(name, color);
track.doc.inlineDocInfo.property.editProperty({
type: 'tags',
});
return { return {
id: newTag.id, id: newTag.id,
value: newTag.value$.value, value: newTag.value$.value,
@@ -58,21 +57,17 @@ export const TagsInlineEditor = ({
const onSelectTag = useCallback( const onSelectTag = useCallback(
(tagId: string) => { (tagId: string) => {
tagService.tagList.tagByTagId$(tagId).value?.tag(pageId); tagService.tagList.tagByTagId$(tagId).value?.tag(pageId);
track.doc.inlineDocInfo.property.editProperty({ onChange?.(tagIds$.value);
type: 'tags',
});
}, },
[pageId, tagService.tagList] [onChange, pageId, tagIds$, tagService.tagList]
); );
const onDeselectTag = useCallback( const onDeselectTag = useCallback(
(tagId: string) => { (tagId: string) => {
tagService.tagList.tagByTagId$(tagId).value?.untag(pageId); tagService.tagList.tagByTagId$(tagId).value?.untag(pageId);
track.doc.inlineDocInfo.property.editProperty({ onChange?.(tagIds$.value);
type: 'tags',
});
}, },
[pageId, tagService.tagList] [onChange, pageId, tagIds$, tagService.tagList]
); );
const onTagChange = useCallback( const onTagChange = useCallback(
@@ -82,11 +77,9 @@ export const TagsInlineEditor = ({
} else if (property === 'color') { } else if (property === 'color') {
tagService.tagList.tagByTagId$(id).value?.changeColor(value); tagService.tagList.tagByTagId$(id).value?.changeColor(value);
} }
track.doc.inlineDocInfo.property.editProperty({ onChange?.(tagIds$.value);
type: 'tags',
});
}, },
[tagService.tagList] [onChange, tagIds$, tagService.tagList]
); );
const deleteTags = useDeleteTagConfirmModal(); const deleteTags = useDeleteTagConfirmModal();
@@ -94,11 +87,9 @@ export const TagsInlineEditor = ({
const onTagDelete = useAsyncCallback( const onTagDelete = useAsyncCallback(
async (id: string) => { async (id: string) => {
await deleteTags([id]); await deleteTags([id]);
track.doc.inlineDocInfo.property.editProperty({ onChange?.(tagIds$.value);
type: 'tags',
});
}, },
[deleteTags] [onChange, tagIds$, deleteTags]
); );
const adaptedTags = useLiveData( const adaptedTags = useLiveData(
@@ -10,8 +10,9 @@ import { DocService, useLiveData, useService } from '@toeverything/infra';
import { useCallback, useMemo } from 'react'; import { useCallback, useMemo } from 'react';
import * as styles from './doc-primary-mode.css'; import * as styles from './doc-primary-mode.css';
import type { PropertyValueProps } from './types';
export const DocPrimaryModeValue = () => { export const DocPrimaryModeValue = ({ onChange }: PropertyValueProps) => {
const t = useI18n(); const t = useI18n();
const doc = useService(DocService).doc; const doc = useService(DocService).doc;
@@ -44,8 +45,9 @@ export const DocPrimaryModeValue = () => {
? t['com.affine.toastMessage.defaultMode.page.message']() ? t['com.affine.toastMessage.defaultMode.page.message']()
: t['com.affine.toastMessage.defaultMode.edgeless.message'](), : t['com.affine.toastMessage.defaultMode.edgeless.message'](),
}); });
onChange?.(mode, true);
}, },
[doc, t] [doc, t, onChange]
); );
return ( return (
<PropertyValue className={styles.container} hoverable={false}> <PropertyValue className={styles.container} hoverable={false}>
@@ -4,6 +4,7 @@ import { DocService, useLiveData, useService } from '@toeverything/infra';
import { useCallback, useMemo } from 'react'; import { useCallback, useMemo } from 'react';
import * as styles from './edgeless-theme.css'; import * as styles from './edgeless-theme.css';
import type { PropertyValueProps } from './types';
const getThemeOptions = (t: ReturnType<typeof useI18n>) => const getThemeOptions = (t: ReturnType<typeof useI18n>) =>
[ [
@@ -21,7 +22,7 @@ const getThemeOptions = (t: ReturnType<typeof useI18n>) =>
}, },
] satisfies RadioItem[]; ] satisfies RadioItem[];
export const EdgelessThemeValue = () => { export const EdgelessThemeValue = ({ onChange }: PropertyValueProps) => {
const t = useI18n(); const t = useI18n();
const doc = useService(DocService).doc; const doc = useService(DocService).doc;
const edgelessTheme = useLiveData(doc.properties$).edgelessColorTheme; const edgelessTheme = useLiveData(doc.properties$).edgelessColorTheme;
@@ -29,8 +30,9 @@ export const EdgelessThemeValue = () => {
const handleChange = useCallback( const handleChange = useCallback(
(theme: string) => { (theme: string) => {
doc.record.setProperty('edgelessColorTheme', theme); doc.record.setProperty('edgelessColorTheme', theme);
onChange?.(theme, true);
}, },
[doc] [doc, onChange]
); );
const themeItems = useMemo<RadioItem[]>(() => getThemeOptions(t), [t]); const themeItems = useMemo<RadioItem[]>(() => getThemeOptions(t), [t]);
@@ -13,8 +13,9 @@ import dayjs from 'dayjs';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import * as styles from './journal.css'; import * as styles from './journal.css';
import type { PropertyValueProps } from './types';
export const JournalValue = () => { export const JournalValue = ({ onChange }: PropertyValueProps) => {
const t = useI18n(); const t = useI18n();
const journalService = useService(JournalService); const journalService = useService(JournalService);
@@ -50,8 +51,9 @@ export const JournalValue = () => {
const date = dayjs(day).format('YYYY-MM-DD'); const date = dayjs(day).format('YYYY-MM-DD');
setSelectedDate(date); setSelectedDate(date);
journalService.setJournalDate(doc.id, date); journalService.setJournalDate(doc.id, date);
onChange?.(date, true);
}, },
[journalService, doc.id] [journalService, doc.id, onChange]
); );
const handleCheck = useCallback( const handleCheck = useCallback(
@@ -59,11 +61,12 @@ export const JournalValue = () => {
if (!v) { if (!v) {
journalService.removeJournalDate(doc.id); journalService.removeJournalDate(doc.id);
setShowDatePicker(false); setShowDatePicker(false);
onChange?.(null, true);
} else { } else {
handleDateSelect(selectedDate); handleDateSelect(selectedDate);
} }
}, },
[handleDateSelect, journalService, doc.id, selectedDate] [onChange, journalService, doc.id, handleDateSelect, selectedDate]
); );
const workbench = useService(WorkbenchService).workbench; const workbench = useService(WorkbenchService).workbench;
@@ -101,11 +104,7 @@ export const JournalValue = () => {
onClick={toggle} onClick={toggle}
> >
<div className={styles.root}> <div className={styles.root}>
<Checkbox <Checkbox className={styles.checkbox} checked={checked} />
className={styles.checkbox}
checked={checked}
onChange={handleCheck}
/>
{checked ? ( {checked ? (
<Menu <Menu
contentOptions={{ contentOptions={{
@@ -5,9 +5,9 @@ import { DocService, useLiveData, useService } from '@toeverything/infra';
import { useCallback, useMemo } from 'react'; import { useCallback, useMemo } from 'react';
import { container } from './page-width.css'; import { container } from './page-width.css';
import type { PageLayoutMode } from './types'; import type { PageLayoutMode, PropertyValueProps } from './types';
export const PageWidthValue = () => { export const PageWidthValue = ({ onChange }: PropertyValueProps) => {
const t = useI18n(); const t = useI18n();
const editorSetting = useService(EditorSettingService).editorSetting; const editorSetting = useService(EditorSettingService).editorSetting;
const defaultPageWidth = useLiveData(editorSetting.settings$).fullWidthLayout; const defaultPageWidth = useLiveData(editorSetting.settings$).fullWidthLayout;
@@ -44,8 +44,9 @@ export const PageWidthValue = () => {
const handleChange = useCallback( const handleChange = useCallback(
(value: PageLayoutMode) => { (value: PageLayoutMode) => {
doc.record.setProperty('pageWidth', value); doc.record.setProperty('pageWidth', value);
onChange?.(value, true);
}, },
[doc] [doc, onChange]
); );
return ( return (
<PropertyValue className={container} hoverable={false}> <PropertyValue className={container} hoverable={false}>
@@ -5,8 +5,9 @@ import { DocService, useLiveData, useService } from '@toeverything/infra';
import { TagsInlineEditor } from '../tags-inline-editor'; import { TagsInlineEditor } from '../tags-inline-editor';
import * as styles from './tags.css'; import * as styles from './tags.css';
import type { PropertyValueProps } from './types';
export const TagsValue = () => { export const TagsValue = ({ onChange }: PropertyValueProps) => {
const t = useI18n(); const t = useI18n();
const doc = useService(DocService).doc; const doc = useService(DocService).doc;
@@ -27,6 +28,7 @@ export const TagsValue = () => {
'com.affine.page-properties.property-value-placeholder' 'com.affine.page-properties.property-value-placeholder'
]()} ]()}
pageId={doc.id} pageId={doc.id}
onChange={value => onChange(value, true)}
/> />
</PropertyValue> </PropertyValue>
); );
@@ -69,7 +69,6 @@ export const textInvisible = style({
visibility: 'hidden', visibility: 'hidden',
fontSize: cssVar('fontSm'), fontSize: cssVar('fontSm'),
lineHeight: '22px', lineHeight: '22px',
padding: `6px`,
}); });
export const mobileTextInvisible = style([textInvisible, mobileTextareaBase]); export const mobileTextInvisible = style([textInvisible, mobileTextareaBase]);
@@ -3,7 +3,7 @@ import type { DocCustomPropertyInfo } from '@toeverything/infra';
export interface PropertyValueProps { export interface PropertyValueProps {
propertyInfo?: DocCustomPropertyInfo; propertyInfo?: DocCustomPropertyInfo;
value: any; value: any;
onChange: (value: any) => void; onChange: (value: any, skipCommit?: boolean) => void; // if skipCommit is true, the change will be handled in the component itself
} }
export type PageLayoutMode = 'standard' | 'fullWidth'; export type PageLayoutMode = 'standard' | 'fullWidth';
@@ -72,6 +72,15 @@ export const InfoTable = ({
}); });
}, []); }, []);
const onPropertyChange = useCallback(
(property: DocCustomPropertyInfo, _value: unknown) => {
track.$.docInfoPanel.property.editProperty({
type: property.type,
});
},
[]
);
return ( return (
<> <>
{backlinks && backlinks.length > 0 ? ( {backlinks && backlinks.length > 0 ? (
@@ -122,6 +131,7 @@ export const InfoTable = ({
key={property.id} key={property.id}
propertyInfo={property} propertyInfo={property}
defaultOpenEditMenu={newPropertyId === property.id} defaultOpenEditMenu={newPropertyId === property.id}
onChange={value => onPropertyChange(property, value)}
/> />
))} ))}
<Menu <Menu