From d794db91498acd48acc445f9893614a4228f1187 Mon Sep 17 00:00:00 2001 From: Ross Keenan Date: Fri, 8 Oct 2021 17:50:54 +0200 Subject: [PATCH] feat(CSV Crumbs): :sparkles: Use a CSV file to add Breadcrumbs --- .vscode/settings.json | 3 +- main.js | 65 +++++++++++++++++++++++++++++++----- package.json | 5 +++ src/BreadcrumbsSettingTab.ts | 11 ++++++ src/interfaces.ts | 1 + src/main.ts | 64 ++++++++++++++++++++++++++++++----- 6 files changed, 130 insertions(+), 19 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 752c0776..d48e0ba7 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -10,6 +10,7 @@ "Path View", "Hierarchy Note", "WriteBCToFile", - "LimitTrailFields" + "LimitTrailFields", + "CSV Crumbs" ] } \ No newline at end of file diff --git a/main.js b/main.js index 978c0697..1e6967ac 100644 --- a/main.js +++ b/main.js @@ -2,6 +2,7 @@ var obsidian = require('obsidian'); require('path'); +require('fs'); var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; @@ -24491,6 +24492,16 @@ class BreadcrumbsSettingTab extends obsidian.PluginSettingTab { }); const generalDetails = containerEl.createEl("details"); generalDetails.createEl("summary", { text: "General Options" }); + new obsidian.Setting(generalDetails) + .setName('CSV Breadcrumb Paths') + .setDesc('The file path of a csv files with breadcrumbs information.') + .addText(text => { + text.setValue(settings.CSVPaths); + text.inputEl.onblur = async () => { + settings.CSVPaths = text.inputEl.value; + await plugin.saveSettings(); + }; + }); new obsidian.Setting(generalDetails) .setName("Refresh Index on Note Change") .setDesc("Refresh the Breadcrumbs index data everytime you change notes. This is how Breadcrumbs used to work, making it responsive to changes immediately after changing notes. However, this can be very slow on large vaults, so it is off by default.") @@ -37245,9 +37256,13 @@ class TrailPath extends SvelteComponent { } } +// import csv from 'csv-parse'; +// import csv2json from 'csv2json' +// import { csvParse } from "d3-dsv"; const DEFAULT_SETTINGS = { userHierarchies: [], indexNote: [""], + CSVPaths: '', hierarchyNotes: [""], hierarchyNoteDownFieldName: "", hierarchyNoteUpFieldName: "", @@ -37609,6 +37624,33 @@ class BreadcrumbsPlugin extends obsidian.Plugin { g.setEdge(currFileName, field, { dir, fieldName }); }); } + async getCSVRows(basePath) { + const { CSVPaths } = this.settings; + if (CSVPaths[0] === '') + return; + const fullPath = obsidian.normalizePath(CSVPaths[0]); + const content = await this.app.vault.adapter.read(fullPath); + const lines = content.split('\n'); + const headers = lines[0].split(',').map(head => head.trim()); + const CSVRows = []; + lines.slice(1).forEach(row => { + const rowObj = {}; + row.split(',').map(head => head.trim()).forEach((item, i) => { + rowObj[headers[i]] = item; + }); + CSVRows.push(rowObj); + }); + console.log({ CSVRows }); + return CSVRows; + } + addCSVCrumbs(g, CSVRows, dir, fieldName) { + CSVRows.forEach(row => { + g.setNode(row.file, { dir, fieldName }); + if (fieldName === "" || !row[fieldName]) + return; + g.setEdge(row.file, row[fieldName], { dir, fieldName }); + }); + } async initGraphs() { var _a; const settings = this.settings; @@ -37655,18 +37697,23 @@ class BreadcrumbsPlugin extends obsidian.Plugin { }); graphs.hierGs.push(newGraphs); }); - relObjArr.forEach((relObj) => { - const currFileName = relObj.current.basename || relObj.current.name; - relObj.hierarchies.forEach((hier, i) => { - DIRECTIONS.forEach((dir) => { - Object.keys(hier[dir]).forEach((fieldName) => { - const g = graphs.hierGs[i][dir][fieldName]; - const fieldValues = hier[dir][fieldName]; - this.populateGraph(g, currFileName, fieldValues, dir, fieldName); + if (settings.CSVPaths !== '') { + const { basePath } = this.app.vault.adapter; + const CSVRows = await this.getCSVRows(basePath); + relObjArr.forEach((relObj) => { + const currFileName = relObj.current.basename || relObj.current.name; + relObj.hierarchies.forEach((hier, i) => { + DIRECTIONS.forEach((dir) => { + Object.keys(hier[dir]).forEach((fieldName) => { + const g = graphs.hierGs[i][dir][fieldName]; + const fieldValues = hier[dir][fieldName]; + this.populateGraph(g, currFileName, fieldValues, dir, fieldName); + this.addCSVCrumbs(g, CSVRows, dir, fieldName); + }); }); }); }); - }); + } if (hierarchyNotesArr.length) { const { hierarchyNoteUpFieldName, hierarchyNoteDownFieldName } = settings; if (hierarchyNoteUpFieldName !== "") { diff --git a/package.json b/package.json index ee45481f..0c18e13e 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "@rollup/plugin-commonjs": "^18.1.0", "@rollup/plugin-node-resolve": "^11.2.1", "@rollup/plugin-typescript": "^8.2.1", + "@types/csv2json": "^1.4.2", "@types/graphlib": "^2.1.7", "@types/lodash": "^4.14.171", "@types/node": "^14.14.37", @@ -36,7 +37,11 @@ }, "dependencies": { "@tsconfig/svelte": "^2.0.1", + "csv-parse": "^4.16.3", + "csv2json": "^2.0.2", + "csvjson-csv2json": "^5.0.6", "d3": "^6.7.0", + "fs": "0.0.1-security", "graphlib": "^2.1.8", "hierarchy-js": "^1.0.4", "juggl-api": "git+https://github.com/HEmile/juggl-api.git", diff --git a/src/BreadcrumbsSettingTab.ts b/src/BreadcrumbsSettingTab.ts index 393f3766..fe27275b 100644 --- a/src/BreadcrumbsSettingTab.ts +++ b/src/BreadcrumbsSettingTab.ts @@ -349,6 +349,17 @@ export class BreadcrumbsSettingTab extends PluginSettingTab { const generalDetails: HTMLDetailsElement = containerEl.createEl("details"); generalDetails.createEl("summary", { text: "General Options" }); + new Setting(generalDetails) + .setName('CSV Breadcrumb Paths') + .setDesc('The file path of a csv files with breadcrumbs information.') + .addText(text => { + text.setValue(settings.CSVPaths) + text.inputEl.onblur = async () => { + settings.CSVPaths = text.inputEl.value + await plugin.saveSettings() + } + }) + new Setting(generalDetails) .setName("Refresh Index on Note Change") .setDesc( diff --git a/src/interfaces.ts b/src/interfaces.ts index 57a760cf..15b58f72 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -4,6 +4,7 @@ import type { FrontMatterCache, Pos, TFile } from "obsidian"; export interface BreadcrumbsSettings { userHierarchies: userHierarchy[]; indexNote: string[]; + CSVPaths: string; hierarchyNotes: string[]; hierarchyNoteDownFieldName: string; hierarchyNoteUpFieldName: string; diff --git a/src/main.ts b/src/main.ts index 2585274e..99e9a442 100644 --- a/src/main.ts +++ b/src/main.ts @@ -3,6 +3,7 @@ import { addIcon, EventRef, MarkdownView, + normalizePath, Notice, Plugin, TFile, WorkspaceLeaf @@ -35,17 +36,27 @@ import { getObsMetadataCache, mergeGs, oppFields, removeDuplicates, + splitAndTrim, writeBCToFile } from "src/sharedFunctions"; import StatsView from "src/StatsView"; import { VisModal } from "src/VisModal"; import TrailGrid from "./Components/TrailGrid.svelte"; import TrailPath from "./Components/TrailPath.svelte"; +import * as fs from 'fs' +import { promises as fsp } from 'fs'; +// import csv2json from "csv2json"; +import { csvParse } from "d3-dsv"; +import { head } from "lodash"; +// import csv from 'csv-parse'; +// import csv2json from 'csv2json' +// import { csvParse } from "d3-dsv"; const DEFAULT_SETTINGS: BreadcrumbsSettings = { userHierarchies: [], indexNote: [""], + CSVPaths: '', hierarchyNotes: [""], hierarchyNoteDownFieldName: "", hierarchyNoteUpFieldName: "", @@ -485,6 +496,36 @@ export default class BreadcrumbsPlugin extends Plugin { }); } + async getCSVRows(basePath: string) { + const { CSVPaths } = this.settings + if (CSVPaths[0] === '') return + const fullPath = normalizePath(CSVPaths[0]) + + const content = await this.app.vault.adapter.read(fullPath) + const lines = content.split('\n') + + const headers = lines[0].split(',').map(head => head.trim()) + const CSVRows: { [key: string]: string }[] = [] + lines.slice(1).forEach(row => { + const rowObj = {} + row.split(',').map(head => head.trim()).forEach((item, i) => { + rowObj[headers[i]] = item + }) + CSVRows.push(rowObj) + }) + + console.log({ CSVRows }) + return CSVRows + + } + addCSVCrumbs(g: Graph, CSVRows: { [key: string]: string }[], dir: Directions, fieldName: string) { + CSVRows.forEach(row => { + g.setNode(row.file, { dir, fieldName }); + if (fieldName === "" || !row[fieldName]) return; + g.setEdge(row.file, row[fieldName], { dir, fieldName }) + }) + } + async initGraphs(): Promise { const settings = this.settings; debugGroupStart(settings, "debugMode", "Initialise Graphs"); @@ -551,20 +592,25 @@ export default class BreadcrumbsPlugin extends Plugin { graphs.hierGs.push(newGraphs); }); - relObjArr.forEach((relObj) => { - const currFileName = relObj.current.basename || relObj.current.name; + if (settings.CSVPaths !== '') { + const { basePath } = this.app.vault.adapter + const CSVRows = await this.getCSVRows(basePath) + relObjArr.forEach((relObj) => { + const currFileName = relObj.current.basename || relObj.current.name; - relObj.hierarchies.forEach((hier, i) => { - DIRECTIONS.forEach((dir: Directions) => { - Object.keys(hier[dir]).forEach((fieldName) => { - const g = graphs.hierGs[i][dir][fieldName]; - const fieldValues = hier[dir][fieldName]; + relObj.hierarchies.forEach((hier, i) => { + DIRECTIONS.forEach((dir: Directions) => { + Object.keys(hier[dir]).forEach((fieldName) => { + const g = graphs.hierGs[i][dir][fieldName]; + const fieldValues = hier[dir][fieldName]; - this.populateGraph(g, currFileName, fieldValues, dir, fieldName); + this.populateGraph(g, currFileName, fieldValues, dir, fieldName); + this.addCSVCrumbs(g, CSVRows, dir, fieldName); + }); }); }); }); - }); + } if (hierarchyNotesArr.length) { const { hierarchyNoteUpFieldName, hierarchyNoteDownFieldName } = settings;