Merge pull request #20 from liufree/dev

feat: support task
This commit is contained in:
liufree 2025-05-20 23:25:50 +08:00 committed by GitHub
commit af5fb8f66b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 84 additions and 79 deletions

View file

@ -17,6 +17,7 @@ QueryDash的目标是开发一款类似Notion Database的Obsidian插件但不
- **过滤**:根据条件筛选数据。
- **合计**:支持数据汇总统计。
- **分页**:优化大数据量下的浏览体验。
- **任务**:支持任务管理,包括任务编辑。
**使用教程**

View file

@ -18,6 +18,7 @@ In the future, it will gradually expand with more practical features to help use
- **Filter**: Screen data based on conditions.
- **Aggregation**: Supports data summary statistics.
- **Pagination**: Optimizes browsing experience for large datasets.
- **Task**: Supports task management, including task editing.
**Tutorial**
@ -31,6 +32,9 @@ file.mtime as "mtime" ,file.tags as "tags" from #clippings
![demo.gif](docs/demo.gif)
**task**
![task.png](docs/task.png)
**timeline**
**simple mode**

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 MiB

After

Width:  |  Height:  |  Size: 3.7 MiB

BIN
docs/task.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

View file

@ -1,7 +1,7 @@
{
"id": "querydash",
"name": "QueryDash",
"version": "1.0.6",
"version": "1.0.7",
"minAppVersion": "1.8.0",
"description": "Refer to Dataview and add search, sorting, and pagination functions, just like Notion.",
"author": "lwx",

View file

@ -10,61 +10,36 @@ import EditableTable from "../../components/EditableTable";
const {Text, Link} = Typography;
const KanbanView: React.FC<ViewProps> = ({app, source}) => {
const [columns, setColumns] = useState<any[]>([]);
const [columns, setColumns] = useState<any>([]);
const [allData, setAllData] = useState<any>([]);
const [todoData, setTodoData] = useState<any>([]);
const [doneData, setDoneData] = useState<any>([]);
const [refresh, setRefresh] = useState(false);
const [tab, setTab] = useState('all');
const dv = getAPI(app);
const ellipsisLink = (display: string, path: string) => (
<Link
onClick={() => {
const file = app.vault.getAbstractFileByPath(path);
if (file && file instanceof TFile) {
const leaf = app.workspace.getLeaf();
leaf.openFile(file);
}
}}
>
<Text
style={display ? {maxWidth: 200, color: '#1890ff', cursor: 'pointer'} : {
color: '#1890ff',
cursor: 'pointer'
}}
ellipsis={{expanded: true}}
>
</Text>
</Link>
);
const parseTaskData = (value: any) => {
const tasks = value.values || [];
const groupedTasks: Record<string, any[]> = {
todo: [],
done: [],
};
tasks.forEach((task: any) => {
const status = task.status === "x" ? "done" : "todo";
groupedTasks[status].push({
...task,
type: "link",
});
});
return Object.keys(groupedTasks).map((status) => ({
title: status.toUpperCase(),
items: groupedTasks[status],
}));
return tasks;
};
const executeTaskQuery = (dvApi: any, source: any) => {
const executeTaskQuery = (dvApi: any, source: any, key: any) => {
dvApi.query(source).then((result: any) => {
console.log("queryResult", result);
console.log("key", key);
if (result.successful) {
const data = parseTaskData(result.value);
console.log("Data:", data); // 输出 data
setColumns([...data]);
let filteredDataList = [...data]
if (key == "todo") {
filteredDataList = data.filter((item: any) => item.status === " ");
setTodoData(filteredDataList)
} else if (key == "done") {
filteredDataList = data.filter((item: any) => item.status === "x");
setDoneData(filteredDataList)
} else {
setAllData(filteredDataList)
}
}
});
};
@ -72,6 +47,7 @@ const KanbanView: React.FC<ViewProps> = ({app, source}) => {
const onChange: (checked: boolean, updateText: string, item: STask) => void = async (checked, updateText, item) => {
console.log("completed", checked);
console.log("item", item);
console.log("updateText", updateText);
const completed = checked;
const status = completed ? "x" : " ";
console.log("status", status);
@ -85,7 +61,7 @@ const KanbanView: React.FC<ViewProps> = ({app, source}) => {
/** 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;
desiredStatus = desiredStatus == " " ? " " : desiredStatus;
let rawFiletext = await vault.adapter.read(task.path);
@ -136,7 +112,9 @@ const KanbanView: React.FC<ViewProps> = ({app, source}) => {
useEffect(() => {
executeTaskQuery(dv, source)
executeTaskQuery(dv, source, "all");
executeTaskQuery(dv, source, "todo");
executeTaskQuery(dv, source, "done");
}, [app, source, refresh]);
useEffect(() => {
@ -172,40 +150,62 @@ const KanbanView: React.FC<ViewProps> = ({app, source}) => {
};
}, [app]);
const cardDetails = (dataList: any) => {
return (
dataList.map((item: any) => (
<>
<ProCard bordered>
<Row>
<Col span={1}>
<Checkbox
onChange={(e) => onChange(e.target.checked, item.text, item)}
checked={item.checked}
/>
</Col>
<Col span={18}>
<EditableText
app={app}
item={item}
onSave={(newText) => {
console.log("保存的新文本:", newText);
onChange(item.checked, newText, item);
}}
/>
</Col>
</Row>
</ProCard>
</>
))
)
}
return (
<>
{/*<EditableTable></EditableTable>*/}
<ProCard ghost gutter={8}>
{columns.map((column) => (
<ProCard key={column.title} title={column.title} bordered>
{column.items.map((item: any, index: number) => (
<>
<ProCard key={index} bordered>
<Row>
<Col span={1}>
<Checkbox
onChange={(e) => onChange(e.target.checked, item.text, item)}
checked={item.checked}
/>
</Col>
<Col span={18}>
<EditableText
app={app}
item={item}
onSave={(newText) => {
console.log("保存的新文本:", newText);
onChange(item.checked, newText, item);
}}
/>
</Col>
</Row>
</ProCard>
</>
))}
</ProCard>
))}
</ProCard>
<ProCard
tabs={{
activeKey: tab,
items: [
{
label: `ALL`,
key: 'all',
children: cardDetails(allData),
},
{
label: `TODO`,
key: 'todo',
children: cardDetails(todoData),
},
{
label: `DONE`,
key: 'done',
children: cardDetails(doneData),
},
],
onChange: (key) => {
setTab(key);
},
}}
/>
</>
);
};