Skip to content

Commit 9847172

Browse files
trangdoan982claudecursoragent
authored
ENG-1693 Add insert backlink checkbox to ModifyNodeModal (#1018)
* ENG-1693 Add insert backlink checkbox to ModifyNodeModal with smart defaults - Add "Insert backlink" checkbox to ModifyNodeModal (create mode only) - Default true when pre-filled text exists (user had text selected) or existing node is chosen; false otherwise - Gate backlink insertion in canvas flow and editor command flow on checkbox value Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * small fixes * clear console * revert the canvas bug * Gate insert backlink checkbox on explicit caller support Only editor flows that honor insertBacklink via createModifyNodeModalSubmitHandler show the toggle, fixing misleading UI in image conversion and tag-node flows. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 3b34820 commit 9847172

4 files changed

Lines changed: 39 additions & 5 deletions

File tree

apps/obsidian/src/components/ModifyNodeModal.tsx

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,16 @@ type ModifyNodeFormProps = {
4949
/** DiscourseRelation.id; when set, relation is created with currentFile as the other end. */
5050
relationshipId?: string;
5151
relationshipTargetFile?: TFile;
52+
insertBacklink: boolean;
5253
}) => Promise<void>;
5354
onCancel: () => void;
5455
initialTitle?: string;
5556
initialNodeType?: DiscourseNode;
5657
initialFile?: TFile; // for edit mode
5758
currentFile?: TFile; // the file where the node is being created from
5859
plugin: DiscourseGraphPlugin;
60+
/** When true, show the insert-backlink checkbox (editor flows that honor insertBacklink). */
61+
showInsertBacklinkOption?: boolean;
5962
};
6063

6164
export const ModifyNodeForm = ({
@@ -67,6 +70,7 @@ export const ModifyNodeForm = ({
6770
initialFile,
6871
currentFile,
6972
plugin,
73+
showInsertBacklinkOption = false,
7074
}: ModifyNodeFormProps) => {
7175
const isEditMode = !!initialFile;
7276
const [title, setTitle] = useState(initialFile?.basename || initialTitle);
@@ -83,6 +87,7 @@ export const ModifyNodeForm = ({
8387
const [selectedRelationshipKey, setSelectedRelationshipKey] = useState<
8488
string | undefined
8589
>(undefined);
90+
const [insertBacklink, setInsertBacklink] = useState(!!initialTitle);
8691
const queryEngine = useRef(new QueryEngine(plugin.app));
8792
const titleInputRef = useRef<HTMLTextAreaElement>(null);
8893
const popoverRef = useRef<HTMLDivElement>(null);
@@ -278,6 +283,7 @@ export const ModifyNodeForm = ({
278283
setSelectedExistingNode(file);
279284
setQuery(file.basename);
280285
setTitle(file.basename);
286+
setInsertBacklink(true);
281287
// Auto-detect node type from the selected file's frontmatter
282288
const nodeTypeId = await getNodeTypeIdForFile(plugin, file);
283289
if (nodeTypeId && selectedFileRef.current === file) {
@@ -291,12 +297,13 @@ export const ModifyNodeForm = ({
291297
const handleClearSelection = useCallback(() => {
292298
selectedFileRef.current = null;
293299
setSelectedExistingNode(null);
300+
setInsertBacklink(!!initialTitle);
294301
setQuery("");
295302
setTitle("");
296303
setTimeout(() => {
297304
titleInputRef.current?.focus();
298305
}, 50);
299-
}, []);
306+
}, [initialTitle]);
300307

301308
const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
302309
if (selectedExistingNode) {
@@ -391,6 +398,7 @@ export const ModifyNodeForm = ({
391398
selectedExistingNode: selectedExistingNode || undefined,
392399
relationshipId: selectedRel?.uniqueKey || undefined,
393400
relationshipTargetFile: currentFile || undefined,
401+
insertBacklink,
394402
});
395403
onCancel();
396404
} catch (error) {
@@ -418,6 +426,7 @@ export const ModifyNodeForm = ({
418426
selectedRelationshipKey,
419427
currentFile,
420428
availableRelationships,
429+
insertBacklink,
421430
]);
422431

423432
return (
@@ -568,6 +577,20 @@ export const ModifyNodeForm = ({
568577
</div>
569578
)}
570579

580+
{!isEditMode && showInsertBacklinkOption && (
581+
<div className="setting-item">
582+
<div className="setting-item-name">Insert backlink</div>
583+
<div className="setting-item-control">
584+
<input
585+
type="checkbox"
586+
checked={insertBacklink}
587+
onChange={(e) => setInsertBacklink(e.target.checked)}
588+
disabled={isSubmitting}
589+
/>
590+
</div>
591+
</div>
592+
)}
593+
571594
<div className="modal-button-container mt-5 flex justify-end gap-2">
572595
<button
573596
type="button"
@@ -606,11 +629,13 @@ type ModifyNodeModalProps = {
606629
selectedExistingNode?: TFile;
607630
relationshipId?: string;
608631
relationshipTargetFile?: TFile;
632+
insertBacklink: boolean;
609633
}) => Promise<void>;
610634
initialTitle?: string;
611635
initialNodeType?: DiscourseNode;
612636
initialFile?: TFile;
613637
currentFile?: TFile;
638+
showInsertBacklinkOption?: boolean;
614639
};
615640

616641
class ModifyNodeModal extends Modal {
@@ -622,13 +647,15 @@ class ModifyNodeModal extends Modal {
622647
selectedExistingNode?: TFile;
623648
relationshipId?: string;
624649
relationshipTargetFile?: TFile;
650+
insertBacklink: boolean;
625651
}) => Promise<void>;
626652
private root: Root | null = null;
627653
private initialTitle?: string;
628654
private initialNodeType?: DiscourseNode;
629655
private initialFile?: TFile;
630656
private currentFile?: TFile;
631657
private plugin: DiscourseGraphPlugin;
658+
private showInsertBacklinkOption?: boolean;
632659

633660
constructor(app: App, props: ModifyNodeModalProps) {
634661
super(app);
@@ -639,6 +666,7 @@ class ModifyNodeModal extends Modal {
639666
this.initialFile = props.initialFile;
640667
this.currentFile = props.currentFile;
641668
this.plugin = props.plugin;
669+
this.showInsertBacklinkOption = props.showInsertBacklinkOption;
642670
}
643671

644672
onOpen() {
@@ -657,6 +685,7 @@ class ModifyNodeModal extends Modal {
657685
initialFile={this.initialFile}
658686
currentFile={this.currentFile}
659687
plugin={this.plugin}
688+
showInsertBacklinkOption={this.showInsertBacklinkOption}
660689
/>
661690
</StrictMode>,
662691
);

apps/obsidian/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@ export default class DiscourseGraphPlugin extends Plugin {
236236
initialTitle: selection,
237237
initialNodeType: nodeType,
238238
currentFile,
239+
showInsertBacklinkOption: true,
239240
onSubmit: createModifyNodeModalSubmitHandler(this, editor),
240241
}).open();
241242
},

apps/obsidian/src/utils/createNode.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ export const createDiscourseNode = async ({
134134
nodeType,
135135
});
136136

137-
if (newFile && editor && editor.somethingSelected()) {
137+
if (newFile && editor) {
138138
editor.replaceSelection(`[[${formattedNodeName}]]`);
139139
}
140140

apps/obsidian/src/utils/registerCommands.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ type ModifyNodeSubmitParams = {
2222
selectedExistingNode?: TFile;
2323
relationshipId?: string;
2424
relationshipTargetFile?: TFile;
25+
insertBacklink: boolean;
2526
};
2627

2728
export const createModifyNodeModalSubmitHandler = (
@@ -34,10 +35,11 @@ export const createModifyNodeModalSubmitHandler = (
3435
selectedExistingNode,
3536
relationshipId,
3637
relationshipTargetFile,
38+
insertBacklink,
3739
}: ModifyNodeSubmitParams) => {
3840
if (selectedExistingNode) {
39-
if (editor && editor.somethingSelected()) {
40-
editor?.replaceSelection(`[[${selectedExistingNode.basename}]]`);
41+
if (insertBacklink && editor) {
42+
editor.replaceSelection(`[[${selectedExistingNode.basename}]]`);
4143
}
4244
await addRelationIfRequested(plugin, selectedExistingNode, {
4345
relationshipId,
@@ -48,7 +50,7 @@ export const createModifyNodeModalSubmitHandler = (
4850
plugin,
4951
nodeType,
5052
text: title,
51-
editor,
53+
editor: insertBacklink ? editor : undefined,
5254
});
5355
if (newFile) {
5456
await addRelationIfRequested(plugin, newFile, {
@@ -84,6 +86,7 @@ export const registerCommands = (plugin: DiscourseGraphPlugin) => {
8486
nodeTypes: plugin.settings.nodeTypes,
8587
plugin,
8688
currentFile,
89+
showInsertBacklinkOption: true,
8790
onSubmit: createModifyNodeModalSubmitHandler(plugin, editor),
8891
}).open();
8992
}
@@ -103,6 +106,7 @@ export const registerCommands = (plugin: DiscourseGraphPlugin) => {
103106
plugin,
104107
currentFile,
105108
initialTitle: selectedText,
109+
showInsertBacklinkOption: !!editor,
106110
onSubmit: createModifyNodeModalSubmitHandler(plugin, editor),
107111
}).open();
108112
},

0 commit comments

Comments
 (0)