Skip to content

Commit 82055e1

Browse files
[ENG-1513] Node type folder locations (#877)
* Add per-node-type folder location settings - Add folderPath field to DiscourseNode type - Update NodeTypeSettings UI with folder path input using FolderSuggestInput - Modify createDiscourseNodeFile and convertPageToDiscourseNode to use node-type-specific folder paths - Folder path priority: node type folderPath > global nodesFolderPath > root/current folder - Resolves ENG-1513 * Refactor to use per-node-type folder paths exclusively - Remove global nodesFolderPath setting from Settings type and UI - Add folder path input directly to NodeTypeSettings UI using FolderSuggestInput - Update node creation and conversion logic to use only node-type-specific folder paths - Update canvas node rename to use node-type folder path - Simplify relations.json to always save in root folder - Default behavior: if no folder path set on node type, create nodes in root/current folder Resolves ENG-1513 * Restore global nodesFolderPath as fallback for node types - Add nodesFolderPath back to Settings type, constants, and GeneralSettings UI - Update description to clarify it's a fallback when node type has no folder path set - Update node creation, conversion, and canvas rename to use node-type folder path first, then fall back to global setting - Folder path priority: node type folderPath > global nodesFolderPath > root/current folder - Update NodeTypeSettings description to indicate it overrides the default Resolves ENG-1513 * Revert relationsStore.ts to use nodesFolderPath for relations.json location - Restore original behavior where relations.json is saved in the same folder as nodes - Re-add folder creation logic before saving relations file * Format NodeTypeSettings.tsx - remove extra blank line --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com>
1 parent 43da018 commit 82055e1

5 files changed

Lines changed: 33 additions & 7 deletions

File tree

apps/obsidian/src/components/GeneralSettings.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -231,10 +231,13 @@ const GeneralSettings = () => {
231231

232232
<div className="setting-item">
233233
<div className="setting-item-info">
234-
<div className="setting-item-name">Discourse nodes folder path</div>
234+
<div className="setting-item-name">
235+
Default discourse nodes folder path
236+
</div>
235237
<div className="setting-item-description">
236-
Specify the folder where new discourse nodes should be created.
237-
Leave empty to create nodes in the root folder.
238+
Default folder where new discourse nodes will be created. This is
239+
used as a fallback when a node type does not have a specific folder
240+
path set. Leave empty to create nodes in the root folder.
238241
</div>
239242
</div>
240243
<div className="setting-item-control">

apps/obsidian/src/components/NodeTypeSettings.tsx

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
formatImportSource,
1212
getAndFormatImportSource,
1313
} from "~/utils/typeUtils";
14+
import { FolderSuggestInput } from "./GeneralSettings";
1415

1516
const generateTagPlaceholder = (format: string, nodeName?: string): string => {
1617
if (!format) return "Enter tag (e.g., clm-candidate)";
@@ -49,7 +50,7 @@ type BaseFieldConfig = {
4950
) => { isValid: boolean; error?: string };
5051
};
5152

52-
const FIELD_CONFIGS: Record<EditableFieldKey, BaseFieldConfig> = {
53+
const FIELD_CONFIGS: Partial<Record<EditableFieldKey, BaseFieldConfig>> = {
5354
name: {
5455
key: "name",
5556
label: "Name",
@@ -676,6 +677,24 @@ const NodeTypeSettings = () => {
676677
</h3>
677678
</div>
678679
{FIELD_CONFIG_ARRAY.map(renderField)}
680+
<div className="setting-item">
681+
<div className="setting-item-info">
682+
<div className="setting-item-name">Folder path</div>
683+
<div className="setting-item-description">
684+
Folder where new nodes of this type will be created. Leave empty
685+
to use the default discourse nodes folder path from general
686+
settings.
687+
</div>
688+
</div>
689+
<div className="setting-item-control">
690+
<FolderSuggestInput
691+
value={editingNodeType.folderPath || ""}
692+
onChange={(value) => handleNodeTypeChange("folderPath", value)}
693+
placeholder="Example: folder 1/folder"
694+
disabled={isEditingImported}
695+
/>
696+
</div>
697+
</div>
679698
{hasUnsavedChanges && !isEditingImported && (
680699
<div className="mt-4 flex justify-end gap-2">
681700
<button onClick={handleCancel} className="mod-muted">

apps/obsidian/src/components/canvas/shapes/DiscourseNodeShape.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ export class DiscourseNodeUtil extends BaseBoxShapeUtil<DiscourseNodeShape> {
164164
if (formattedName) {
165165
// Rename the file
166166
const folderPath =
167+
nodeType?.folderPath?.trim() ||
167168
this.options.plugin.settings.nodesFolderPath.trim();
168169
let newPath = "";
169170
if (folderPath) {

apps/obsidian/src/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export type DiscourseNode = {
1111
color?: string;
1212
tag?: string;
1313
keyImage?: boolean;
14+
folderPath?: string;
1415
created: number;
1516
modified: number;
1617
importedFromRid?: string;

apps/obsidian/src/utils/createNode.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ export const createDiscourseNodeFile = async ({
5050
return existingFile;
5151
}
5252

53-
const folderPath = settings.nodesFolderPath.trim();
53+
const folderPath =
54+
nodeType.folderPath?.trim() || settings.nodesFolderPath.trim();
5455
const fullPath = folderPath ? `${folderPath}/${fileName}` : fileName;
5556

5657
if (folderPath) {
@@ -169,7 +170,8 @@ export const convertPageToDiscourseNode = async ({
169170
});
170171

171172
let newPath = "";
172-
const folderPath = plugin.settings.nodesFolderPath.trim();
173+
const folderPath =
174+
nodeType.folderPath?.trim() || plugin.settings.nodesFolderPath.trim();
173175
if (folderPath) {
174176
const folderExists = plugin.app.vault.getAbstractFileByPath(folderPath);
175177
if (!folderExists) {
@@ -192,4 +194,4 @@ export const convertPageToDiscourseNode = async ({
192194
5000,
193195
);
194196
}
195-
};
197+
};

0 commit comments

Comments
 (0)