mirror of
https://github.com/toeverything/AFFiNE.git
synced 2025-01-04 23:32:31 +03:00
feat(core): add outgoing links to doc info (#7955)
close AF-1270 ![CleanShot 2024-08-23 at 13 22 38@2x](https://github.com/user-attachments/assets/7eb21db5-ab33-41ad-a51a-fd2cf46a0e30)
This commit is contained in:
parent
3ce92f2abc
commit
5e8683c9be
@ -5,6 +5,7 @@ import {
|
|||||||
Scrollable,
|
Scrollable,
|
||||||
} from '@affine/component';
|
} from '@affine/component';
|
||||||
import { DocsSearchService } from '@affine/core/modules/docs-search';
|
import { DocsSearchService } from '@affine/core/modules/docs-search';
|
||||||
|
import { useI18n } from '@affine/i18n';
|
||||||
import { LiveData, useLiveData, useServices } from '@toeverything/infra';
|
import { LiveData, useLiveData, useServices } from '@toeverything/infra';
|
||||||
import { Suspense, useCallback, useContext, useMemo, useRef } from 'react';
|
import { Suspense, useCallback, useContext, useMemo, useRef } from 'react';
|
||||||
|
|
||||||
@ -16,8 +17,8 @@ import {
|
|||||||
SortableProperties,
|
SortableProperties,
|
||||||
usePagePropertiesManager,
|
usePagePropertiesManager,
|
||||||
} from '../table';
|
} from '../table';
|
||||||
import { BackLinksRow } from './back-links-row';
|
|
||||||
import * as styles from './info-modal.css';
|
import * as styles from './info-modal.css';
|
||||||
|
import { LinksRow } from './links-row';
|
||||||
import { TagsRow } from './tags-row';
|
import { TagsRow } from './tags-row';
|
||||||
import { TimeRow } from './time-row';
|
import { TimeRow } from './time-row';
|
||||||
|
|
||||||
@ -30,22 +31,12 @@ export const InfoModal = ({
|
|||||||
onOpenChange: (open: boolean) => void;
|
onOpenChange: (open: boolean) => void;
|
||||||
docId: string;
|
docId: string;
|
||||||
}) => {
|
}) => {
|
||||||
const { docsSearchService } = useServices({
|
|
||||||
DocsSearchService,
|
|
||||||
});
|
|
||||||
const titleInputHandleRef = useRef<InlineEditHandle>(null);
|
const titleInputHandleRef = useRef<InlineEditHandle>(null);
|
||||||
const manager = usePagePropertiesManager(docId);
|
const manager = usePagePropertiesManager(docId);
|
||||||
const handleClose = useCallback(() => {
|
const handleClose = useCallback(() => {
|
||||||
onOpenChange(false);
|
onOpenChange(false);
|
||||||
}, [onOpenChange]);
|
}, [onOpenChange]);
|
||||||
|
|
||||||
const references = useLiveData(
|
|
||||||
useMemo(
|
|
||||||
() => LiveData.from(docsSearchService.watchRefsFrom(docId), null),
|
|
||||||
[docId, docsSearchService]
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!manager.page || manager.readonly) {
|
if (!manager.page || manager.readonly) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -76,7 +67,6 @@ export const InfoModal = ({
|
|||||||
<InfoTable
|
<InfoTable
|
||||||
docId={docId}
|
docId={docId}
|
||||||
onClose={handleClose}
|
onClose={handleClose}
|
||||||
references={references}
|
|
||||||
readonly={manager.readonly}
|
readonly={manager.readonly}
|
||||||
/>
|
/>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
@ -90,29 +80,52 @@ export const InfoModal = ({
|
|||||||
|
|
||||||
const InfoTable = ({
|
const InfoTable = ({
|
||||||
onClose,
|
onClose,
|
||||||
references,
|
|
||||||
docId,
|
docId,
|
||||||
readonly,
|
readonly,
|
||||||
}: {
|
}: {
|
||||||
docId: string;
|
docId: string;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
readonly: boolean;
|
readonly: boolean;
|
||||||
references:
|
|
||||||
| {
|
|
||||||
docId: string;
|
|
||||||
title: string;
|
|
||||||
}[]
|
|
||||||
| null;
|
|
||||||
}) => {
|
}) => {
|
||||||
|
const t = useI18n();
|
||||||
const manager = useContext(managerContext);
|
const manager = useContext(managerContext);
|
||||||
|
const { docsSearchService } = useServices({
|
||||||
|
DocsSearchService,
|
||||||
|
});
|
||||||
|
const links = useLiveData(
|
||||||
|
useMemo(
|
||||||
|
() => LiveData.from(docsSearchService.watchRefsFrom(docId), null),
|
||||||
|
[docId, docsSearchService]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
const backlinks = useLiveData(
|
||||||
|
useMemo(
|
||||||
|
() => LiveData.from(docsSearchService.watchRefsTo(docId), null),
|
||||||
|
[docId, docsSearchService]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<TimeRow docId={docId} />
|
<TimeRow docId={docId} />
|
||||||
<Divider size="thinner" />
|
<Divider size="thinner" />
|
||||||
{references && references.length > 0 ? (
|
{backlinks && backlinks.length > 0 ? (
|
||||||
<>
|
<>
|
||||||
<BackLinksRow references={references} onClick={onClose} />
|
<LinksRow
|
||||||
|
references={backlinks}
|
||||||
|
onClick={onClose}
|
||||||
|
label={t['com.affine.page-properties.backlinks']()}
|
||||||
|
/>
|
||||||
|
<Divider size="thinner" />
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
|
{links && links.length > 0 ? (
|
||||||
|
<>
|
||||||
|
<LinksRow
|
||||||
|
references={links}
|
||||||
|
onClick={onClose}
|
||||||
|
label={t['com.affine.page-properties.outgoing-links']()}
|
||||||
|
/>
|
||||||
<Divider size="thinner" />
|
<Divider size="thinner" />
|
||||||
</>
|
</>
|
||||||
) : null}
|
) : null}
|
||||||
|
@ -1,22 +1,24 @@
|
|||||||
import { useI18n } from '@affine/i18n';
|
import type { Backlink, Link } from '@affine/core/modules/doc-link';
|
||||||
import { useContext } from 'react';
|
import { useContext } from 'react';
|
||||||
|
|
||||||
import { AffinePageReference } from '../../reference-link';
|
import { AffinePageReference } from '../../reference-link';
|
||||||
import { managerContext } from '../common';
|
import { managerContext } from '../common';
|
||||||
import * as styles from './back-links-row.css';
|
import * as styles from './links-row.css';
|
||||||
export const BackLinksRow = ({
|
|
||||||
|
export const LinksRow = ({
|
||||||
references,
|
references,
|
||||||
|
label,
|
||||||
onClick,
|
onClick,
|
||||||
}: {
|
}: {
|
||||||
references: { docId: string; title: string }[];
|
references: Backlink[] | Link[];
|
||||||
|
label: string;
|
||||||
onClick?: () => void;
|
onClick?: () => void;
|
||||||
}) => {
|
}) => {
|
||||||
const manager = useContext(managerContext);
|
const manager = useContext(managerContext);
|
||||||
const t = useI18n();
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className={styles.title}>
|
<div className={styles.title}>
|
||||||
{t['com.affine.page-properties.backlinks']()} · {references.length}
|
{label} · {references.length}
|
||||||
</div>
|
</div>
|
||||||
{references.map(link => (
|
{references.map(link => (
|
||||||
<AffinePageReference
|
<AffinePageReference
|
@ -1,4 +1,5 @@
|
|||||||
import { DocLinksService } from '@affine/core/modules/doc-link';
|
import { DocLinksService } from '@affine/core/modules/doc-link';
|
||||||
|
import { useI18n } from '@affine/i18n';
|
||||||
import {
|
import {
|
||||||
useLiveData,
|
useLiveData,
|
||||||
useServices,
|
useServices,
|
||||||
@ -15,6 +16,7 @@ export const BiDirectionalLinkPanel = () => {
|
|||||||
DocLinksService,
|
DocLinksService,
|
||||||
WorkspaceService,
|
WorkspaceService,
|
||||||
});
|
});
|
||||||
|
const t = useI18n();
|
||||||
|
|
||||||
const links = useLiveData(docLinksService.links.links$);
|
const links = useLiveData(docLinksService.links.links$);
|
||||||
const backlinks = useLiveData(docLinksService.backlinks.backlinks$);
|
const backlinks = useLiveData(docLinksService.backlinks.backlinks$);
|
||||||
@ -44,7 +46,7 @@ export const BiDirectionalLinkPanel = () => {
|
|||||||
</div>
|
</div>
|
||||||
<div className={styles.linksContainer}>
|
<div className={styles.linksContainer}>
|
||||||
<div className={styles.linksTitles}>
|
<div className={styles.linksTitles}>
|
||||||
Backlinks · {backlinks.length}
|
{t['com.affine.page-properties.backlinks']()} · {backlinks.length}
|
||||||
</div>
|
</div>
|
||||||
{backlinks.map(link => (
|
{backlinks.map(link => (
|
||||||
<div key={link.docId} className={styles.link}>
|
<div key={link.docId} className={styles.link}>
|
||||||
@ -58,7 +60,8 @@ export const BiDirectionalLinkPanel = () => {
|
|||||||
</div>
|
</div>
|
||||||
<div className={styles.linksContainer}>
|
<div className={styles.linksContainer}>
|
||||||
<div className={styles.linksTitles}>
|
<div className={styles.linksTitles}>
|
||||||
Outgoing links · {links.length}
|
{t['com.affine.page-properties.outgoing-links']()} ·{' '}
|
||||||
|
{links.length}
|
||||||
</div>
|
</div>
|
||||||
{links.map(link => (
|
{links.map(link => (
|
||||||
<div key={link.docId} className={styles.link}>
|
<div key={link.docId} className={styles.link}>
|
||||||
|
@ -3,7 +3,7 @@ import { Entity, LiveData } from '@toeverything/infra';
|
|||||||
|
|
||||||
import type { DocsSearchService } from '../../docs-search';
|
import type { DocsSearchService } from '../../docs-search';
|
||||||
|
|
||||||
interface Backlink {
|
export interface Backlink {
|
||||||
docId: string;
|
docId: string;
|
||||||
blockId: string;
|
blockId: string;
|
||||||
title: string;
|
title: string;
|
||||||
|
@ -3,7 +3,7 @@ import { Entity, LiveData } from '@toeverything/infra';
|
|||||||
|
|
||||||
import type { DocsSearchService } from '../../docs-search';
|
import type { DocsSearchService } from '../../docs-search';
|
||||||
|
|
||||||
interface Link {
|
export interface Link {
|
||||||
docId: string;
|
docId: string;
|
||||||
title: string;
|
title: string;
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,8 @@ import { DocBacklinks } from './entities/doc-backlinks';
|
|||||||
import { DocLinks } from './entities/doc-links';
|
import { DocLinks } from './entities/doc-links';
|
||||||
import { DocLinksService } from './services/doc-links';
|
import { DocLinksService } from './services/doc-links';
|
||||||
|
|
||||||
|
export type { Backlink } from './entities/doc-backlinks';
|
||||||
|
export type { Link } from './entities/doc-links';
|
||||||
export { DocLinksService } from './services/doc-links';
|
export { DocLinksService } from './services/doc-links';
|
||||||
|
|
||||||
export function configureDocLinksModule(framework: Framework) {
|
export function configureDocLinksModule(framework: Framework) {
|
||||||
|
@ -851,6 +851,7 @@
|
|||||||
"com.affine.page-properties.add-property.menu.create": "Create property",
|
"com.affine.page-properties.add-property.menu.create": "Create property",
|
||||||
"com.affine.page-properties.add-property.menu.header": "Properties",
|
"com.affine.page-properties.add-property.menu.header": "Properties",
|
||||||
"com.affine.page-properties.backlinks": "Backlinks",
|
"com.affine.page-properties.backlinks": "Backlinks",
|
||||||
|
"com.affine.page-properties.outgoing-links": "Outgoing links",
|
||||||
"com.affine.page-properties.create-property.menu.header": "Type",
|
"com.affine.page-properties.create-property.menu.header": "Type",
|
||||||
"com.affine.page-properties.icons": "Icons",
|
"com.affine.page-properties.icons": "Icons",
|
||||||
"com.affine.page-properties.page-info": "Info",
|
"com.affine.page-properties.page-info": "Info",
|
||||||
|
Loading…
Reference in New Issue
Block a user