From 6fd75355878d532765a6994ff659e139c2a15d94 Mon Sep 17 00:00:00 2001 From: liufree Date: Mon, 28 Apr 2025 23:59:50 +0800 Subject: [PATCH 1/4] feat: support kanbanview --- src/pages/QueryDashView.tsx | 3 + src/pages/kanbanview/KanbanView.tsx | 152 ++++++++++++++++++++++++++++ 2 files changed, 155 insertions(+) create mode 100644 src/pages/kanbanview/KanbanView.tsx diff --git a/src/pages/QueryDashView.tsx b/src/pages/QueryDashView.tsx index 1bab3a3..b79f93c 100644 --- a/src/pages/QueryDashView.tsx +++ b/src/pages/QueryDashView.tsx @@ -5,6 +5,7 @@ import ListView from "./listview/ListView"; import {ConfigProvider, ConfigProviderProps, Timeline} from "antd"; import enUS from 'antd/locale/en_US'; import TimeLineView from "./timelineview/TimeLineView"; +import KanbanView from "./kanbanview/KanbanView"; interface QueryDashViewDashs { @@ -31,6 +32,8 @@ const QueryDashView: React.FC = ({app, source}) => { return ; } else if (sourceType === "timeline") { return ; + } else if (sourceType === "task") { + return ; } } diff --git a/src/pages/kanbanview/KanbanView.tsx b/src/pages/kanbanview/KanbanView.tsx new file mode 100644 index 0000000..f107efe --- /dev/null +++ b/src/pages/kanbanview/KanbanView.tsx @@ -0,0 +1,152 @@ +import React, {useEffect, useState} from "react"; +import {ProCard} from "@ant-design/pro-components"; +import {Checkbox, CheckboxChangeEvent, CheckboxProps, Typography} from "antd"; +import {getAPI, STask} from "obsidian-dataview"; +import {ViewProps} from "../../models/ViewProps"; +import {TFile, Vault} from "obsidian"; + +const {Text, Link} = Typography; + +const KanbanView: React.FC = ({app, source}) => { + const [columns, setColumns] = useState([]); + const [refresh, setRefresh] = useState(false); + const dv = getAPI(app); + + const ellipsisLink = (display: string, path: string) => ( + { + const file = app.vault.getAbstractFileByPath(path); + if (file && file instanceof TFile) { + const leaf = app.workspace.getLeaf(); + leaf.openFile(file); + } + }} + > + {display} + + ); + + const parseTaskData = (value: any) => { + const tasks = value.values || []; + const groupedTasks: Record = { + done: [], + doing: [], + todo: [], + }; + + tasks.forEach((task: any) => { + const status = task.status === "x" ? "done" : task.status === "?" ? "doing" : "todo"; + groupedTasks[status].push({ + ...task, + type: "link", + }); + }); + + return Object.keys(groupedTasks).map((status) => ({ + title: status.toUpperCase(), + items: groupedTasks[status], + })); + }; + + const executeTaskQuery = async (dvApi: any, source: any) => { + const queryResult = await dvApi.query(source); + console.log("queryResult", queryResult); + if (queryResult.successful) { + return parseTaskData(queryResult.value); + } + return []; + }; + + const onChange: (e: CheckboxChangeEvent, item: STask) => void = async (e, item) => { + console.log("completed", e.target.checked); + console.log("item", item); + const completed = e.target.checked; + const status = completed ? "x" : " "; + console.log("status", status); + let updatedText: string = item.text; + await rewriteTask(app.vault, item, status, updatedText) + setRefresh(true) + }; + + + const LIST_ITEM_REGEX = /^[\s>]*(\d+\.|\d+\)|\*|-|\+)\s*(\[.{0,1}\])?\s*(.*)$/mu; + + /** Rewrite a task with the given completion status and new text. */ + async function rewriteTask(vault: Vault, task: STask, desiredStatus: string, desiredText?: string) { + if (desiredStatus == task.status && (desiredText == undefined || desiredText == task.text)) return; + desiredStatus = desiredStatus == "" ? " " : desiredStatus; + + let rawFiletext = await vault.adapter.read(task.path); + + console.log("rawFiletext", rawFiletext); + + let hasRN = rawFiletext.contains("\r"); + let filetext = rawFiletext.split(/\r?\n/u); + console.log("filetext", filetext); + + if (filetext.length < task.line) { + console.log("line", filetext); + return; + } + + let match = LIST_ITEM_REGEX.exec(filetext[task.line]); + if (!match || match[2].length == 0) { + console.log("match", match); + return; + } + + let taskTextParts = task.text.split("\n"); + if (taskTextParts[0].trim() != match[3].trim()) { + console.log("taskTextParts", taskTextParts); + return; + } + + // We have a positive match here at this point, so go ahead and do the rewrite of the status. + let initialSpacing = /^[\s>]*/u.exec(filetext[task.line])!![0]; + if (desiredText) { + let desiredParts = desiredText.split("\n"); + + let newTextLines: string[] = [`${initialSpacing}${task.symbol} [${desiredStatus}] ${desiredParts[0]}`].concat( + desiredParts.slice(1).map(l => initialSpacing + "\t" + l) + ); + + filetext.splice(task.line, task.lineCount, ...newTextLines); + } else { + filetext[task.line] = `${initialSpacing}${task.symbol} [${desiredStatus}] ${taskTextParts[0].trim()}`; + } + + let newText = filetext.join(hasRN ? "\r\n" : "\n"); + console.log("newText", newText); + console.log("taskPath", task.path); + await vault.adapter.write(task.path, newText); + } + + + useEffect(() => { + executeTaskQuery(dv, source) + .then((data) => setColumns(JSON.parse(JSON.stringify(data)))) + .catch((error) => console.error("Error executing query:", error)); + }, [app, source, refresh]); + + return ( + + {columns.map((column) => ( + + {column.items.map((item: any, index: number) => ( + <> + + onChange(e, item)} checked={item.checked}> + {item.type === "link" + ? ellipsisLink(item.text, item.path) + : {item.text}} + + + + ))} + + ))} + + ); +}; + +export default KanbanView; From ea83f94950bc441c71b3bd84c8a11da038ab90cb Mon Sep 17 00:00:00 2001 From: liufree Date: Sat, 26 Apr 2025 07:36:44 +0800 Subject: [PATCH 2/4] build: upgrade dependency --- package.json | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/package.json b/package.json index 46064bf..1edb8e6 100644 --- a/package.json +++ b/package.json @@ -11,25 +11,25 @@ "author": "", "license": "MIT", "dependencies": { - "@ant-design/icons": "^5.0.1", + "@ant-design/icons": "^6.0.0", "@ant-design/pro-components": "^2.8.7", "umi-request": "^1.4.0" }, "devDependencies": { - "@types/luxon": "^3.4.2", - "@types/node": "^22.13.8", - "@types/react": "^18.0.33", - "@types/react-dom": "^18.0.11", - "@typescript-eslint/eslint-plugin": "5.29.0", - "@typescript-eslint/parser": "5.29.0", - "@vitejs/plugin-react": "^4.3.4", - "builtin-modules": "3.3.0", + "@types/luxon": "^3.6.2", + "@types/node": "^22.15.2", + "@types/react": "^19.1.2", + "@types/react-dom": "^19.1.2", + "@typescript-eslint/eslint-plugin": "8.31.0", + "@typescript-eslint/parser": "8.31.0", + "@vitejs/plugin-react": "^4.4.1", + "builtin-modules": "5.0.0", "husky": "^9", - "lint-staged": "^13.2.0", + "lint-staged": "^15.5.1", "obsidian": "latest", - "obsidian-dataview": "^0.5.67", - "tslib": "2.4.0", - "vite": "^6.2.6", + "obsidian-dataview": "^0.5.68", + "tslib": "2.8.1", + "vite": "^6.3.3", "vite-plugin-css-injected-by-js": "^3.5.2" } } From b699440568180dd89aa424716d672ca8dad74c3b Mon Sep 17 00:00:00 2001 From: liufree Date: Tue, 6 May 2025 23:12:38 +0800 Subject: [PATCH 3/4] fix: fix npe bug --- manifest.json | 2 +- src/pages/tableview/TableView.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/manifest.json b/manifest.json index 70266ad..84f2e00 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "querydash", "name": "QueryDash", - "version": "1.0.4", + "version": "1.0.5", "minAppVersion": "1.8.0", "description": "Refer to Dataview and add search, sorting, and pagination functions, just like Notion.", "author": "lwx", diff --git a/src/pages/tableview/TableView.tsx b/src/pages/tableview/TableView.tsx index 99b249e..e0c6ce8 100644 --- a/src/pages/tableview/TableView.tsx +++ b/src/pages/tableview/TableView.tsx @@ -61,7 +61,7 @@ const TableView: React.FC = ({app, source}) => { return { title: header, dataIndex: header, - sorter: (a, b) => a[header].display.toString().localeCompare(b[header].display.toString()), + sorter: (a, b) => a[header]?.display?.toString()?.localeCompare(b[header]?.display?.toString()), render: (_, record) => { const {type, path, display} = record[header] || {}; if (type === "datetime") { From dca336562fc776e59e2aa3813c86dbb7bb85dd13 Mon Sep 17 00:00:00 2001 From: liufree Date: Tue, 6 May 2025 23:13:40 +0800 Subject: [PATCH 4/4] fix: fix npe bug --- src/pages/tableview/TableView.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/pages/tableview/TableView.tsx b/src/pages/tableview/TableView.tsx index e0c6ce8..f2aef0a 100644 --- a/src/pages/tableview/TableView.tsx +++ b/src/pages/tableview/TableView.tsx @@ -10,7 +10,6 @@ import {ViewProps} from "../../models/ViewProps"; const TableView: React.FC = ({app, source}) => { - const actionRef = useRef(); const [columns, setColumns] = React.useState[]>([]); const dv = getAPI(app); @@ -155,7 +154,6 @@ const TableView: React.FC = ({app, source}) => { return (