chore(core): tracking events for doc properties (#8651)

fix AF-1565
This commit is contained in:
pengx17 2024-11-05 11:30:57 +00:00
parent 4977055a2e
commit ef82b9d3e7
No known key found for this signature in database
GPG Key ID: 23F23D9E8B3971ED
18 changed files with 301 additions and 116 deletions

View File

@ -64,7 +64,7 @@ export class DocPropertiesStore extends Store {
createDocPropertyInfo(
config: Omit<DocCustomPropertyInfo, 'id'> & { id?: string }
) {
return this.dbService.db.docCustomPropertyInfo.create(config).id;
return this.dbService.db.docCustomPropertyInfo.create(config);
}
removeDocPropertyInfo(id: string) {

View File

@ -3,11 +3,16 @@ import {
useConfirmModal,
useLitPortalFactory,
} from '@affine/component';
import type {
DatabaseRow,
DatabaseValueCell,
} from '@affine/core/modules/doc-info/types';
import { EditorService } from '@affine/core/modules/editor';
import { EditorSettingService } from '@affine/core/modules/editor-setting';
import { JournalService } from '@affine/core/modules/journal';
import { toURLSearchParams } from '@affine/core/modules/navigation';
import { PeekViewService } from '@affine/core/modules/peek-view/services/peek-view';
import track from '@affine/track';
import type { DocMode } from '@blocksuite/affine/blocks';
import {
DocTitle,
@ -16,6 +21,7 @@ import {
} from '@blocksuite/affine/presets';
import type { Doc } from '@blocksuite/affine/store';
import {
type DocCustomPropertyInfo,
DocService,
DocsService,
FeatureFlagService,
@ -239,6 +245,28 @@ export const BlocksuiteDocEditor = forwardRef<
editorSettingService.editorSetting.settings$.selector(s => s.displayDocInfo)
);
const onPropertyChange = useCallback((property: DocCustomPropertyInfo) => {
track.doc.inlineDocInfo.property.editProperty({
type: property.type,
});
}, []);
const onPropertyAdded = useCallback((property: DocCustomPropertyInfo) => {
track.doc.inlineDocInfo.property.addProperty({
type: property.type,
control: 'at menu',
});
}, []);
const onDatabasePropertyChange = useCallback(
(_row: DatabaseRow, cell: DatabaseValueCell) => {
track.doc.inlineDocInfo.databaseProperty.editProperty({
type: cell.property.type$.value,
});
},
[]
);
return (
<>
<div className={styles.affineDocViewport} style={{ height: '100%' }}>
@ -248,7 +276,12 @@ export const BlocksuiteDocEditor = forwardRef<
<BlocksuiteEditorJournalDocTitle page={page} />
)}
{!shared && displayDocInfo ? (
<DocPropertiesTable defaultOpenProperty={defaultOpenProperty} />
<DocPropertiesTable
onDatabasePropertyChange={onDatabasePropertyChange}
onPropertyChange={onPropertyChange}
onPropertyAdded={onPropertyAdded}
defaultOpenProperty={defaultOpenProperty}
/>
) : null}
<adapted.DocEditor
className={styles.docContainer}

View File

@ -1,7 +1,12 @@
import { MenuItem, MenuSeparator } from '@affine/component';
import { generateUniqueNameInSequence } from '@affine/core/utils/unique-name';
import { useI18n } from '@affine/i18n';
import { DocsService, useLiveData, useService } from '@toeverything/infra';
import {
type DocCustomPropertyInfo,
DocsService,
useLiveData,
useService,
} from '@toeverything/infra';
import { useCallback } from 'react';
import {
@ -15,7 +20,7 @@ export const CreatePropertyMenuItems = ({
onCreated,
}: {
at?: 'before' | 'after';
onCreated?: (propertyId: string) => void;
onCreated?: (property: DocCustomPropertyInfo) => void;
}) => {
const t = useI18n();
const docsService = useService(DocsService);
@ -36,13 +41,13 @@ export const CreatePropertyMenuItems = ({
? generateUniqueNameInSequence(option.name, allNames)
: option.name;
const uniqueId = typeDefined.uniqueId;
const newPropertyId = propertyList.createProperty({
const newProperty = propertyList.createProperty({
id: uniqueId,
name,
type: option.type,
index: propertyList.indexAt(at),
});
onCreated?.(newPropertyId);
onCreated?.(newProperty);
},
[at, onCreated, propertyList, properties]
);

View File

@ -1,6 +1,7 @@
import { Divider, IconButton, Tooltip } from '@affine/component';
import { generateUniqueNameInSequence } from '@affine/core/utils/unique-name';
import { useI18n } from '@affine/i18n';
import track from '@affine/track';
import { PlusIcon } from '@blocksuite/icons/rc';
import {
Content as CollapsibleContent,
@ -41,13 +42,17 @@ export const DocPropertySidebar = () => {
const name = nameExists
? generateUniqueNameInSequence(option.name, allNames)
: option.name;
const newPropertyId = propertyList.createProperty({
const newProperty = propertyList.createProperty({
id: typeDefined.uniqueId,
name,
type: option.type,
index: propertyList.indexAt('after'),
});
setNewPropertyId(newPropertyId);
setNewPropertyId(newProperty.id);
track.doc.sidepanel.property.addProperty({
control: 'property list',
type: option.type,
});
},
[propertyList, properties]
);

View File

@ -9,6 +9,10 @@ import {
useDropTarget,
} from '@affine/component';
import { DocDatabaseBacklinkInfo } from '@affine/core/modules/doc-info';
import type {
DatabaseRow,
DatabaseValueCell,
} from '@affine/core/modules/doc-info/types';
import { WorkbenchService } from '@affine/core/modules/workbench';
import { ViewService } from '@affine/core/modules/workbench/services/view';
import type { AffineDNDData } from '@affine/core/types/dnd';
@ -26,7 +30,6 @@ import {
} from '@toeverything/infra';
import clsx from 'clsx';
import type React from 'react';
import type { HTMLProps } from 'react';
import { forwardRef, useCallback, useState } from 'react';
import { DocPropertyIcon } from './icons/doc-property-icon';
@ -47,6 +50,13 @@ export type DefaultOpenProperty =
export interface DocPropertiesTableProps {
defaultOpenProperty?: DefaultOpenProperty;
onPropertyAdded?: (property: DocCustomPropertyInfo) => void;
onPropertyChange?: (property: DocCustomPropertyInfo, value: unknown) => void;
onDatabasePropertyChange?: (
row: DatabaseRow,
cell: DatabaseValueCell,
value: unknown
) => void;
}
interface DocPropertiesTableHeaderProps {
@ -95,11 +105,13 @@ interface DocPropertyRowProps {
propertyInfo: DocCustomPropertyInfo;
showAll?: boolean;
defaultOpenEditMenu?: boolean;
onChange?: (value: unknown) => void;
}
export const DocPropertyRow = ({
propertyInfo,
defaultOpenEditMenu,
onChange,
}: DocPropertyRowProps) => {
const t = useI18n();
const docService = useService(DocService);
@ -123,8 +135,9 @@ export const DocPropertyRow = ({
throw new Error('only allow string value');
}
docService.doc.record.setCustomProperty(propertyInfo.id, value);
onChange?.(value);
},
[docService, propertyInfo]
[docService, onChange, propertyInfo]
);
const docId = docService.doc.id;
@ -214,6 +227,8 @@ interface DocWorkspacePropertiesTableBodyProps {
className?: string;
style?: React.CSSProperties;
defaultOpen?: boolean;
onChange?: (property: DocCustomPropertyInfo, value: unknown) => void;
onPropertyAdded?: (property: DocCustomPropertyInfo) => void;
}
// 🏷️ Tags (⋅ xxx) (⋅ yyy)
@ -221,104 +236,121 @@ interface DocWorkspacePropertiesTableBodyProps {
// + Add a property
const DocWorkspacePropertiesTableBody = forwardRef<
HTMLDivElement,
DocWorkspacePropertiesTableBodyProps & HTMLProps<HTMLDivElement>
>(({ className, style, defaultOpen, ...props }, ref) => {
const t = useI18n();
const docsService = useService(DocsService);
const workbenchService = useService(WorkbenchService);
const viewService = useServiceOptional(ViewService);
const properties = useLiveData(docsService.propertyList.sortedProperties$);
const [propertyCollapsed, setPropertyCollapsed] = useState(true);
DocWorkspacePropertiesTableBodyProps
>(
(
{ className, style, defaultOpen, onChange, onPropertyAdded, ...props },
ref
) => {
const t = useI18n();
const docsService = useService(DocsService);
const workbenchService = useService(WorkbenchService);
const viewService = useServiceOptional(ViewService);
const properties = useLiveData(docsService.propertyList.sortedProperties$);
const [propertyCollapsed, setPropertyCollapsed] = useState(true);
const [newPropertyId, setNewPropertyId] = useState<string | null>(null);
const [newPropertyId, setNewPropertyId] = useState<string | null>(null);
return (
<PropertyCollapsibleSection
ref={ref}
className={clsx(styles.tableBodyRoot, className)}
style={style}
title={t.t('com.affine.workspace.properties')}
defaultCollapsed={!defaultOpen}
{...props}
>
<PropertyCollapsibleContent
collapsible
collapsed={propertyCollapsed}
onCollapseChange={setPropertyCollapsed}
className={styles.tableBodySortable}
collapseButtonText={({ hide, isCollapsed }) =>
isCollapsed
? hide === 1
? t['com.affine.page-properties.more-property.one']({
count: hide.toString(),
})
: t['com.affine.page-properties.more-property.more']({
count: hide.toString(),
})
: hide === 1
? t['com.affine.page-properties.hide-property.one']({
count: hide.toString(),
})
: t['com.affine.page-properties.hide-property.more']({
count: hide.toString(),
})
}
const handlePropertyAdded = useCallback(
(property: DocCustomPropertyInfo) => {
setNewPropertyId(property.id);
onPropertyAdded?.(property);
},
[onPropertyAdded]
);
return (
<PropertyCollapsibleSection
ref={ref}
className={clsx(styles.tableBodyRoot, className)}
style={style}
title={t.t('com.affine.workspace.properties')}
defaultCollapsed={!defaultOpen}
{...props}
>
{properties.map(property => (
<DocPropertyRow
key={property.id}
propertyInfo={property}
defaultOpenEditMenu={newPropertyId === property.id}
/>
))}
<div className={styles.actionContainer}>
<Menu
items={
<CreatePropertyMenuItems
at="after"
onCreated={setNewPropertyId}
/>
}
contentOptions={{
onClick(e) {
e.stopPropagation();
},
}}
>
<Button
variant="plain"
prefix={<PlusIcon />}
className={styles.propertyActionButton}
data-testid="add-property-button"
>
{t['com.affine.page-properties.add-property']()}
</Button>
</Menu>
{viewService ? (
<Button
variant="plain"
prefix={<PropertyIcon />}
className={clsx(
styles.propertyActionButton,
styles.propertyConfigButton
)}
onClick={() => {
viewService.view.activeSidebarTab('properties');
workbenchService.workbench.openSidebar();
<PropertyCollapsibleContent
collapsible
collapsed={propertyCollapsed}
onCollapseChange={setPropertyCollapsed}
className={styles.tableBodySortable}
collapseButtonText={({ hide, isCollapsed }) =>
isCollapsed
? hide === 1
? t['com.affine.page-properties.more-property.one']({
count: hide.toString(),
})
: t['com.affine.page-properties.more-property.more']({
count: hide.toString(),
})
: hide === 1
? t['com.affine.page-properties.hide-property.one']({
count: hide.toString(),
})
: t['com.affine.page-properties.hide-property.more']({
count: hide.toString(),
})
}
>
{properties.map(property => (
<DocPropertyRow
key={property.id}
propertyInfo={property}
defaultOpenEditMenu={newPropertyId === property.id}
onChange={value => onChange?.(property, value)}
/>
))}
<div className={styles.actionContainer}>
<Menu
items={
<CreatePropertyMenuItems
at="after"
onCreated={handlePropertyAdded}
/>
}
contentOptions={{
onClick(e) {
e.stopPropagation();
},
}}
>
{t['com.affine.page-properties.config-properties']()}
</Button>
) : null}
</div>
</PropertyCollapsibleContent>
</PropertyCollapsibleSection>
);
});
<Button
variant="plain"
prefix={<PlusIcon />}
className={styles.propertyActionButton}
data-testid="add-property-button"
>
{t['com.affine.page-properties.add-property']()}
</Button>
</Menu>
{viewService ? (
<Button
variant="plain"
prefix={<PropertyIcon />}
className={clsx(
styles.propertyActionButton,
styles.propertyConfigButton
)}
onClick={() => {
viewService.view.activeSidebarTab('properties');
workbenchService.workbench.openSidebar();
}}
>
{t['com.affine.page-properties.config-properties']()}
</Button>
) : null}
</div>
</PropertyCollapsibleContent>
</PropertyCollapsibleSection>
);
}
);
DocWorkspacePropertiesTableBody.displayName = 'PagePropertiesTableBody';
const DocPropertiesTableInner = ({
defaultOpenProperty,
onPropertyAdded,
onPropertyChange,
onDatabasePropertyChange,
}: DocPropertiesTableProps) => {
const [expanded, setExpanded] = useState(!!defaultOpenProperty);
return (
@ -334,9 +366,12 @@ const DocPropertiesTableInner = ({
defaultOpen={
!defaultOpenProperty || defaultOpenProperty.type === 'workspace'
}
onPropertyAdded={onPropertyAdded}
onChange={onPropertyChange}
/>
<div className={styles.tableHeaderDivider} />
<DocDatabaseBacklinkInfo
onChange={onDatabasePropertyChange}
defaultOpen={
defaultOpenProperty?.type === 'database'
? [
@ -356,8 +391,6 @@ const DocPropertiesTableInner = ({
// this is the main component that renders the page properties table at the top of the page below
// the page title
export const DocPropertiesTable = ({
defaultOpenProperty,
}: DocPropertiesTableProps) => {
return <DocPropertiesTableInner defaultOpenProperty={defaultOpenProperty} />;
export const DocPropertiesTable = (props: DocPropertiesTableProps) => {
return <DocPropertiesTableInner {...props} />;
};

View File

@ -1,6 +1,7 @@
import type { TagLike } from '@affine/component/ui/tags';
import { TagsInlineEditor as TagsInlineEditorComponent } from '@affine/component/ui/tags';
import { TagService, useDeleteTagConfirmModal } from '@affine/core/modules/tag';
import track from '@affine/track';
import {
LiveData,
useLiveData,
@ -38,6 +39,9 @@ export const TagsInlineEditor = ({
const onCreateTag = useCallback(
(name: string, color: string) => {
const newTag = tagService.tagList.createTag(name, color);
track.doc.inlineDocInfo.property.editProperty({
type: 'tags',
});
return {
id: newTag.id,
value: newTag.value$.value,
@ -50,6 +54,9 @@ export const TagsInlineEditor = ({
const onSelectTag = useCallback(
(tagId: string) => {
tagService.tagList.tagByTagId$(tagId).value?.tag(pageId);
track.doc.inlineDocInfo.property.editProperty({
type: 'tags',
});
},
[pageId, tagService.tagList]
);
@ -57,6 +64,9 @@ export const TagsInlineEditor = ({
const onDeselectTag = useCallback(
(tagId: string) => {
tagService.tagList.tagByTagId$(tagId).value?.untag(pageId);
track.doc.inlineDocInfo.property.editProperty({
type: 'tags',
});
},
[pageId, tagService.tagList]
);
@ -68,6 +78,9 @@ export const TagsInlineEditor = ({
} else if (property === 'color') {
tagService.tagList.tagByTagId$(id).value?.changeColor(value);
}
track.doc.inlineDocInfo.property.editProperty({
type: 'tags',
});
},
[tagService.tagList]
);
@ -77,6 +90,9 @@ export const TagsInlineEditor = ({
const onTagDelete = useAsyncCallback(
async (id: string) => {
await deleteTags([id]);
track.doc.inlineDocInfo.property.editProperty({
type: 'tags',
});
},
[deleteTags]
);

View File

@ -8,16 +8,22 @@ import {
import { CreatePropertyMenuItems } from '@affine/core/components/doc-properties/menu/create-doc-property';
import { DocPropertyRow } from '@affine/core/components/doc-properties/table';
import { DocDatabaseBacklinkInfo } from '@affine/core/modules/doc-info';
import type {
DatabaseRow,
DatabaseValueCell,
} from '@affine/core/modules/doc-info/types';
import { DocsSearchService } from '@affine/core/modules/docs-search';
import { useI18n } from '@affine/i18n';
import track from '@affine/track';
import { PlusIcon } from '@blocksuite/icons/rc';
import {
type DocCustomPropertyInfo,
DocsService,
LiveData,
useLiveData,
useServices,
} from '@toeverything/infra';
import { useMemo, useState } from 'react';
import { useCallback, useMemo, useState } from 'react';
import * as styles from './info-modal.css';
import { LinksRow } from './links-row';
@ -49,6 +55,23 @@ export const InfoTable = ({
)
);
const onBacklinkPropertyChange = useCallback(
(_row: DatabaseRow, cell: DatabaseValueCell, _value: unknown) => {
track.$.docInfoPanel.databaseProperty.editProperty({
type: cell.property.type$.value,
});
},
[]
);
const onPropertyAdded = useCallback((property: DocCustomPropertyInfo) => {
setNewPropertyId(property.id);
track.$.docInfoPanel.property.addProperty({
type: property.type,
control: 'at menu',
});
}, []);
return (
<>
{backlinks && backlinks.length > 0 ? (
@ -102,7 +125,7 @@ export const InfoTable = ({
/>
))}
<Menu
items={<CreatePropertyMenuItems onCreated={setNewPropertyId} />}
items={<CreatePropertyMenuItems onCreated={onPropertyAdded} />}
contentOptions={{
onClick(e) {
e.stopPropagation();
@ -120,7 +143,7 @@ export const InfoTable = ({
</PropertyCollapsibleContent>
</PropertyCollapsibleSection>
<Divider size="thinner" />
<DocDatabaseBacklinkInfo />
<DocDatabaseBacklinkInfo onChange={onBacklinkPropertyChange} />
</>
);
};

View File

@ -4,7 +4,13 @@ import { DocPropertyManager } from '@affine/core/components/doc-properties/manag
import { CreatePropertyMenuItems } from '@affine/core/components/doc-properties/menu/create-doc-property';
import { useWorkspaceInfo } from '@affine/core/components/hooks/use-workspace-info';
import { Trans, useI18n } from '@affine/i18n';
import { FrameworkScope, type WorkspaceMetadata } from '@toeverything/infra';
import track from '@affine/track';
import {
type DocCustomPropertyInfo,
FrameworkScope,
type WorkspaceMetadata,
} from '@toeverything/infra';
import { useCallback } from 'react';
import { useWorkspace } from '../../../../../components/hooks/use-workspace';
import * as styles from './styles.css';
@ -12,10 +18,17 @@ import * as styles from './styles.css';
const WorkspaceSettingPropertiesMain = () => {
const t = useI18n();
const onCreated = useCallback((property: DocCustomPropertyInfo) => {
track.$.settingsPanel.workspace.addProperty({
type: property.type,
control: 'at menu',
});
}, []);
return (
<div className={styles.main}>
<div className={styles.listHeader}>
<Menu items={<CreatePropertyMenuItems />}>
<Menu items={<CreatePropertyMenuItems onCreated={onCreated} />}>
<Button variant="primary">
{t['com.affine.settings.workspace.properties.add_property']()}
</Button>

View File

@ -32,4 +32,5 @@ export interface DatabaseCellRendererProps {
rowId: string;
cell: DatabaseValueCell;
dataSource: DatabaseBlockDataSource;
onChange: (value: unknown) => void;
}

View File

@ -8,6 +8,7 @@ export const CheckboxCell = ({
cell,
rowId,
dataSource,
onChange,
}: DatabaseCellRendererProps) => {
const value = useLiveData(cell.value$ as LiveData<boolean>);
return (
@ -16,6 +17,7 @@ export const CheckboxCell = ({
value={value ? 'true' : 'false'}
onChange={v => {
dataSource.cellValueChange(rowId, cell.property.id, v === 'true');
onChange?.(v === 'true');
}}
/>
);

View File

@ -20,6 +20,7 @@ export const DateCell = ({
cell,
rowId,
dataSource,
onChange,
}: DatabaseCellRendererProps) => {
const value = useLiveData(
cell.value$ as LiveData<number | string | undefined>
@ -34,6 +35,7 @@ export const DateCell = ({
cell.property.id,
fromInternalDateString(v)
);
onChange?.(fromInternalDateString(v));
}}
/>
);

View File

@ -21,6 +21,7 @@ export const LinkCell = ({
cell,
dataSource,
rowId,
onChange,
}: DatabaseCellRendererProps) => {
const isEmpty = useLiveData(
cell.value$.map(value => typeof value !== 'string' || !value)
@ -35,7 +36,8 @@ export const LinkCell = ({
dataSource.cellValueChange(rowId, cell.id, tempValue.trim());
setEditing(false);
setTempValue(tempValue.trim());
}, [dataSource, rowId, cell.id, tempValue]);
onChange?.(tempValue.trim());
}, [dataSource, rowId, cell.id, onChange, tempValue]);
const handleOnChange: ChangeEventHandler<HTMLTextAreaElement> = useCallback(
e => {

View File

@ -7,6 +7,7 @@ export const NumberCell = ({
cell,
rowId,
dataSource,
onChange,
}: DatabaseCellRendererProps) => {
const value = useLiveData(cell.value$);
return (
@ -14,6 +15,7 @@ export const NumberCell = ({
value={value}
onChange={v => {
dataSource.cellValueChange(rowId, cell.property.id, v);
onChange?.(v);
}}
/>
);

View File

@ -9,6 +9,7 @@ export const ProgressCell = ({
cell,
dataSource,
rowId,
onChange,
}: DatabaseCellRendererProps) => {
const value = useLiveData(cell.value$ as LiveData<number>);
const isEmpty = value === undefined;
@ -27,6 +28,7 @@ export const ProgressCell = ({
}}
onBlur={() => {
dataSource.cellValueChange(rowId, cell.id, localValue);
onChange?.(localValue);
}}
/>
</PropertyValue>

View File

@ -40,6 +40,7 @@ const renderRichText = ({
export const RichTextCell = ({
cell,
dataSource,
onChange,
}: DatabaseCellRendererProps) => {
const std = useBlockStdScope(dataSource.doc);
const text = useLiveData(cell.value$ as LiveData<Y.Text>);
@ -49,14 +50,19 @@ export const RichTextCell = ({
if (ref.current) {
ref.current.innerHTML = '';
const richText = renderRichText({ doc: dataSource.doc, std, text });
const listener = () => {
onChange(text);
};
if (richText) {
richText.addEventListener('change', listener);
ref.current.append(richText);
return () => {
richText.removeEventListener('change', listener);
richText.remove();
};
}
}
return () => {};
}, [dataSource.doc, std, text]);
}, [dataSource.doc, onChange, std, text]);
return <PropertyValue ref={ref}></PropertyValue>;
};

View File

@ -147,6 +147,7 @@ const BlocksuiteDatabaseSelector = ({
dataSource,
rowId,
multiple,
onChange,
}: DatabaseCellRendererProps & { multiple: boolean }) => {
const tagService = useService(TagService);
const selectCell = cell as any as SingleSelectCell | MultiSelectCell;
@ -177,21 +178,24 @@ const BlocksuiteDatabaseSelector = ({
const onDeleteTag = useCallback(
(tagId: string) => {
adapter.deleteTag(selectCell, dataSource, tagId);
onChange?.(selectCell.value$.value);
},
[dataSource, selectCell]
[dataSource, selectCell, onChange]
);
const onDeselectTag = useCallback(
(tagId: string) => {
adapter.deselectTag(rowId, selectCell, dataSource, tagId, multiple);
onChange?.(selectCell.value$.value);
},
[selectCell, dataSource, rowId, multiple]
[rowId, selectCell, dataSource, multiple, onChange]
);
const onSelectTag = useCallback(
(tagId: string) => {
adapter.selectTag(rowId, selectCell, dataSource, tagId, multiple);
onChange?.(selectCell.value$.value);
},
[rowId, selectCell, dataSource, multiple]
[rowId, selectCell, dataSource, multiple, onChange]
);
const tagColors = useMemo(() => {
@ -237,6 +241,7 @@ export const SelectCell = ({
cell,
dataSource,
rowId,
onChange,
}: DatabaseCellRendererProps) => {
const isEmpty = useLiveData(
cell.value$.map(value => Array.isArray(value) && value.length === 0)
@ -248,6 +253,7 @@ export const SelectCell = ({
dataSource={dataSource}
rowId={rowId}
multiple={false}
onChange={onChange}
/>
</PropertyValue>
);
@ -257,6 +263,7 @@ export const MultiSelectCell = ({
cell,
dataSource,
rowId,
onChange,
}: DatabaseCellRendererProps) => {
const isEmpty = useLiveData(
cell.value$.map(value => Array.isArray(value) && value.length === 0)
@ -268,6 +275,7 @@ export const MultiSelectCell = ({
dataSource={dataSource}
rowId={rowId}
multiple={true}
onChange={onChange}
/>
</PropertyValue>
);

View File

@ -46,10 +46,12 @@ const DatabaseBacklinkCell = ({
cell,
dataSource,
rowId,
onChange,
}: {
cell: DatabaseValueCell;
dataSource: DatabaseBlockDataSource;
rowId: string;
onChange: (value: unknown) => void;
}) => {
const cellType = useLiveData(cell.property.type$);
@ -67,7 +69,12 @@ const DatabaseBacklinkCell = ({
data-testid="database-backlink-cell"
>
<DatabaseBacklinkCellName cell={cell} config={config} />
<config.Renderer cell={cell} dataSource={dataSource} rowId={rowId} />
<config.Renderer
cell={cell}
dataSource={dataSource}
rowId={rowId}
onChange={onChange}
/>
</li>
);
};
@ -79,9 +86,15 @@ const DatabaseBacklinkCell = ({
const DatabaseBacklinkRow = ({
defaultOpen = false,
row$,
onChange,
}: {
defaultOpen: boolean;
row$: Observable<DatabaseRow | undefined>;
onChange?: (
row: DatabaseRow,
cell: DatabaseValueCell,
value: unknown
) => void;
}) => {
const row = useLiveData(
useMemo(() => LiveData.from(row$, undefined), [row$])
@ -132,6 +145,7 @@ const DatabaseBacklinkRow = ({
cell={cell}
dataSource={row.dataSource}
rowId={row.id}
onChange={value => onChange?.(row, cell, value)}
/>
);
})}
@ -142,11 +156,17 @@ const DatabaseBacklinkRow = ({
export const DocDatabaseBacklinkInfo = ({
defaultOpen = [],
onChange,
}: {
defaultOpen?: {
databaseId: string;
rowId: string;
}[];
onChange?: (
row: DatabaseRow,
cell: DatabaseValueCell,
value: unknown
) => void;
}) => {
const doc = useService(DocService).doc;
const docDatabaseBacklinks = useService(DocDatabaseBacklinksService);
@ -173,6 +193,7 @@ export const DocDatabaseBacklinkInfo = ({
backlink.rowId === rowId
)}
row$={row$}
onChange={onChange}
/>
<Divider size="thinner" className={styles.divider} />
</Fragment>

View File

@ -46,7 +46,9 @@ type DocEvents =
| 'openDocOptionsMenu'
| 'openDocInfo'
| 'copyBlockToLink'
| 'bookmark';
| 'bookmark'
| 'editProperty'
| 'addProperty';
type EditorEvents = 'bold' | 'italic' | 'underline' | 'strikeThrough';
// END SECTION
@ -148,10 +150,12 @@ const PageEvents = {
},
docInfoPanel: {
$: ['open'],
property: ['editProperty', 'addProperty'],
databaseProperty: ['editProperty'],
},
settingsPanel: {
menu: ['openSettings'],
workspace: ['viewPlans', 'export'],
workspace: ['viewPlans', 'export', 'addProperty'],
profileAndBadge: ['viewPlans'],
accountUsage: ['viewPlans'],
accountSettings: ['uploadAvatar', 'removeAvatar', 'updateUserName'],
@ -277,6 +281,11 @@ const PageEvents = {
},
inlineDocInfo: {
$: ['toggle'],
property: ['editProperty', 'addProperty'],
databaseProperty: ['editProperty'],
},
sidepanel: {
property: ['addProperty'],
},
},
// remove when type added
@ -413,6 +422,8 @@ export type EventArgs = {
copyBlockToLink: {
type: string;
};
editProperty: { type: string };
addProperty: { type: string; control: 'at menu' | 'property list' };
};
// for type checking