Skip to content
This repository was archived by the owner on Jul 28, 2025. It is now read-only.

Commit 8a1f86d

Browse files
committed
Merge branch '170-link-and-backlink-columns'
2 parents fd6f18d + 1663150 commit 8a1f86d

File tree

13 files changed

+166
-25
lines changed

13 files changed

+166
-25
lines changed

src/cdm/DatabaseModel.ts

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,5 @@ export type TableOptionsResponse = {
4848
}
4949

5050
export type NoteInfoPage = Omit<SMarkdownPage, "file"> & {
51-
file:
52-
{
53-
link: {
54-
fileName: () => string, path: string
55-
},
56-
path: string,
57-
ctime: DateTime,
58-
mtime: DateTime,
59-
tasks?: STask[]
60-
}
51+
file: Pick<SMarkdownPage["file"], "link" | "path" | "ctime" | "mtime" | "tasks" | "outlinks" | "inlinks">
6152
};

src/cdm/SettingsModel.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ export interface LocalSettings {
3131
show_metadata_created: boolean;
3232
show_metadata_modified: boolean;
3333
show_metadata_tasks: boolean;
34+
show_metadata_inlinks: boolean;
35+
show_metadata_outlinks: boolean;
3436
source_form_result: string;
3537
source_destination_path: string;
3638
source_data: string;

src/components/Columns.tsx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,31 @@ export async function obtainMetadataColumns(
6464
delete yamlColumns[MetadataColumns.TASKS];
6565
}
6666

67+
if (localSetting.show_metadata_inlinks) {
68+
// If INLINKS is not already in the table, add it
69+
yamlColumns[MetadataColumns.INLINKS] = {
70+
...MetadataDatabaseColumns.INLINKS,
71+
...(yamlColumns[MetadataColumns.INLINKS] ?? {}),
72+
};
73+
} else {
74+
delete yamlColumns[MetadataColumns.INLINKS];
75+
}
76+
77+
if (localSetting.show_metadata_outlinks) {
78+
// If OUTLINKS is not already in the table, add it
79+
yamlColumns[MetadataColumns.OUTLINKS] = {
80+
...MetadataDatabaseColumns.OUTLINKS,
81+
...(yamlColumns[MetadataColumns.OUTLINKS] ?? {}),
82+
};
83+
} else {
84+
delete yamlColumns[MetadataColumns.OUTLINKS];
85+
}
86+
6787
yamlColumns[MetadataColumns.ADD_COLUMN] = {
6888
...MetadataDatabaseColumns.ADD_COLUMN,
6989
position: DatabaseLimits.MAX_COLUMNS + 1,
7090
};
91+
7192
return yamlColumns;
7293
}
7394

src/components/DefaultCell.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@ import MarkdownCell from "components/cellTypes/MarkdownCell";
1111
import TagsPortal from "components/portals/TagsPortal";
1212
import NumberCell from "components/cellTypes/NumberCell";
1313
import TextCell from "components/cellTypes/TextCell";
14+
import MetadataTimeCell from "components/cellTypes/MetadataTimeCell";
15+
import InOutLinksCell from "components/cellTypes/InOutLinksCell";
1416
import { CellContext } from "@tanstack/react-table";
1517
import { Literal } from "obsidian-dataview";
16-
import MetadataTimeCell from "./cellTypes/MetadataTimeCell";
1718

1819
export default function DefaultCell(
1920
defaultCell: CellContext<RowDataType, Literal>
@@ -63,6 +64,11 @@ export default function DefaultCell(
6364
case InputType.TASK:
6465
return <TaskCell defaultCell={defaultCell} />;
6566

67+
/** InOut links option */
68+
case InputType.INLINKS:
69+
case InputType.OUTLINKS:
70+
return <InOutLinksCell defaultCell={defaultCell} />;
71+
6672
/** Checkbox option */
6773
case InputType.CHECKBOX:
6874
return <CheckboxCell defaultCell={defaultCell} />;

src/components/DefaultHeader.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,10 @@ export default function DefaultHeader(headerProps: DatabaseHeaderProps) {
104104
case InputType.TAGS:
105105
propertyIcon = <TagsIcon />;
106106
break;
107+
case InputType.INLINKS:
108+
case InputType.OUTLINKS:
109+
propertyIcon = <TaskIcon />;
110+
break;
107111
case InputType.TASK:
108112
case InputType.CHECKBOX:
109113
propertyIcon = <TaskIcon />;
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { CellComponentProps } from "cdm/ComponentsModel";
2+
import { renderMarkdown } from "components/obsidianArq/MarkdownRenderer";
3+
import { c } from "helpers/StylesHelper";
4+
import { Link } from "obsidian-dataview";
5+
import React, { useEffect, useRef } from "react";
6+
7+
const InOutLinksCell = (mdProps: CellComponentProps) => {
8+
const { defaultCell } = mdProps;
9+
const { table, row, column } = defaultCell;
10+
const { tableState } = table.options.meta;
11+
const markdownRow = tableState.data((state) => state.rows[row.index]);
12+
const mdRef = useRef<HTMLDivElement>();
13+
useEffect(() => {
14+
if (mdRef.current !== null) {
15+
mdRef.current.innerHTML = "";
16+
const links = markdownRow[column.id] as Link[];
17+
const markdownLinks: string[] = [];
18+
links.forEach((link) => {
19+
markdownLinks.push(`- ${link.markdown()}`);
20+
});
21+
renderMarkdown(defaultCell, markdownLinks.join("\n"), mdRef.current, 5);
22+
}
23+
});
24+
return <span ref={mdRef} className={c("md_cell text-align-left")}></span>;
25+
};
26+
27+
export default InOutLinksCell;

src/components/cellTypes/TaskCell.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ const TaskCell = (taskProps: CellComponentProps) => {
3535
}, []);
3636
const taskRef = useRef<HTMLDivElement>();
3737

38-
return <div ref={taskRef} className={c("text-align-left")}></div>;
38+
return <div ref={taskRef} className={c("md_cell text-align-left")}></div>;
3939
};
4040

4141
export default TaskCell;

src/helpers/Constants.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ export const InputType = Object.freeze({
1919
CALENDAR_TIME: 'calendar_time',
2020
METATADA_TIME: 'metadata_time',
2121
TASK: 'task',
22+
INLINKS: 'inlinks',
23+
OUTLINKS: 'outlinks',
2224
CHECKBOX: 'checkbox',
2325
NEW_COLUMN: 'new_column'
2426
});
@@ -53,6 +55,8 @@ export const MetadataColumns = Object.freeze({
5355
MODIFIED: `__modified__`,
5456
ADD_COLUMN: `__add_column__`,
5557
TASKS: `__tasks__`,
58+
OUTLINKS: `__outlinks__`,
59+
INLINKS: `__inlinks__`,
5660
ROW_CONTEXT_MENU: "__rowContextMenu__"
5761
});
5862

@@ -62,6 +66,8 @@ export const MetadataLabels = Object.freeze({
6266
CREATED: 'Created',
6367
MODIFIED: 'Modified',
6468
TASK: 'Task',
69+
OUTLINKS: 'Outlinks',
70+
INLINKS: 'Inlinks',
6571
});
6672

6773
export const DEFAULT_COLUMN_CONFIG: ConfigColumn = Object.freeze({
@@ -133,6 +139,29 @@ export const MetadataDatabaseColumns: MetadataColumnsModel = Object.freeze({
133139
csvCandidate: false,
134140
config: DEFAULT_COLUMN_CONFIG
135141
},
142+
INLINKS: {
143+
key: MetadataColumns.INLINKS,
144+
input: InputType.INLINKS,
145+
label: MetadataLabels.INLINKS,
146+
accessorKey: MetadataColumns.INLINKS,
147+
isMetadata: true,
148+
isDragDisabled: false,
149+
skipPersist: false,
150+
csvCandidate: false,
151+
config: DEFAULT_COLUMN_CONFIG
152+
},
153+
OUTLINKS: {
154+
key: MetadataColumns.OUTLINKS,
155+
input: InputType.OUTLINKS,
156+
label: MetadataLabels.OUTLINKS,
157+
accessorKey: MetadataColumns.OUTLINKS,
158+
isMetadata: true,
159+
isDragDisabled: false,
160+
skipPersist: false,
161+
csvCandidate: false,
162+
config: DEFAULT_COLUMN_CONFIG
163+
164+
},
136165
ROW_CONTEXT_MENU: {
137166
id: MetadataColumns.ROW_CONTEXT_MENU,
138167
key: MetadataColumns.ROW_CONTEXT_MENU,
@@ -313,6 +342,8 @@ export const DEFAULT_SETTINGS: DatabaseSettings = {
313342
show_metadata_created: false,
314343
show_metadata_modified: false,
315344
show_metadata_tasks: false,
345+
show_metadata_inlinks: false,
346+
show_metadata_outlinks: false,
316347
source_data: SourceDataTypes.CURRENT_FOLDER,
317348
source_form_result: 'root',
318349
source_destination_path: '/',

src/services/NoteInfo.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ import { DataviewService } from "services/DataviewService";
55
import { Literal } from "obsidian-dataview/lib/data-model/value";
66
import { LocalSettings } from "cdm/SettingsModel";
77
import { resolve_tfile } from "helpers/FileManagement";
8-
import { SMarkdownPage, STask } from "obsidian-dataview/lib/data-model/serialized/markdown";
9-
import { DateTime } from "luxon";
108
import { NoteInfoPage } from "cdm/DatabaseModel";
119
/**
1210
* Keep info about a note and offer methods to manipulate it
@@ -26,12 +24,14 @@ export default class NoteInfo {
2624
__note__: this
2725
}
2826
const dataviewFile = this.page;
29-
27+
dataviewFile
3028
/** Metadata fields */
3129
aFile[MetadataColumns.FILE] = `${dataviewFile.file.link.fileName()}|${dataviewFile.file.link.path}`;
3230
aFile[MetadataColumns.CREATED] = dataviewFile.file.ctime;
3331
aFile[MetadataColumns.MODIFIED] = dataviewFile.file.mtime;
3432
aFile[MetadataColumns.TASKS] = dataviewFile.file.tasks;
33+
aFile[MetadataColumns.OUTLINKS] = dataviewFile.file.outlinks;
34+
aFile[MetadataColumns.INLINKS] = dataviewFile.file.inlinks;
3535
/** Parse data with the type of column */
3636
columns.forEach(column => {
3737
if (dataviewFile[column.key] !== undefined) {

src/settings/handlers/columns/MetadataToggleGroupHandler.ts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ export class MetadataToggleGroupHandler extends AbstractSettingsHandler {
8181
});
8282
}
8383
}
84+
8485
new Setting(metadata_section)
8586
.setName("Tasks")
8687
.setDesc("Enable/disable File Tasks Column")
@@ -89,6 +90,60 @@ export class MetadataToggleGroupHandler extends AbstractSettingsHandler {
8990
.onChange(metadata_tasks_toggle_promise)
9091
);
9192

93+
/*************************
94+
* INLINKS COLUMN
95+
*************************/
96+
const metadata_inlinks_toggle_promise = async (value: boolean): Promise<void> => {
97+
// Check context to define correct promise
98+
if (local) {
99+
// Persist value
100+
view.diskConfig.updateConfig({ show_metadata_inlinks: value });
101+
} else {
102+
// switch show task on/off
103+
const update_local_settings = settingsManager.plugin.settings.local_settings;
104+
update_local_settings.show_metadata_inlinks = value;
105+
// update settings
106+
await settingsManager.plugin.updateSettings({
107+
local_settings: update_local_settings
108+
});
109+
}
110+
}
111+
112+
new Setting(metadata_section)
113+
.setName("Inlinks")
114+
.setDesc("Enable/disable File Inlinks Column")
115+
.addToggle(toggle =>
116+
toggle.setValue(local ? view.diskConfig.yaml.config.show_metadata_inlinks : settingsManager.plugin.settings.local_settings.show_metadata_inlinks)
117+
.onChange(metadata_inlinks_toggle_promise)
118+
);
119+
120+
/*************************
121+
* OUTLINKS COLUMN
122+
*************************/
123+
const metadata_outlinks_toggle_promise = async (value: boolean): Promise<void> => {
124+
// Check context to define correct promise
125+
if (local) {
126+
// Persist value
127+
view.diskConfig.updateConfig({ show_metadata_outlinks: value });
128+
} else {
129+
// switch show task on/off
130+
const update_local_settings = settingsManager.plugin.settings.local_settings;
131+
update_local_settings.show_metadata_outlinks = value;
132+
// update settings
133+
await settingsManager.plugin.updateSettings({
134+
local_settings: update_local_settings
135+
});
136+
}
137+
}
138+
139+
new Setting(metadata_section)
140+
.setName("Outlinks")
141+
.setDesc("Enable/disable File Outlinks Column")
142+
.addToggle(toggle =>
143+
toggle.setValue(local ? view.diskConfig.yaml.config.show_metadata_outlinks : settingsManager.plugin.settings.local_settings.show_metadata_outlinks)
144+
.onChange(metadata_outlinks_toggle_promise)
145+
);
146+
92147
return this.goNext(settingHandlerResponse);
93148
}
94149
}

0 commit comments

Comments
 (0)