mirror of
https://github.com/taskgenius/taskgenius-plugin.git
synced 2026-07-22 06:40:25 +00:00
feat: support auto complete parent tasks
This commit is contained in:
parent
1c3df1fc12
commit
44c8de4915
9 changed files with 2584 additions and 802 deletions
40
README.md
40
README.md
|
|
@ -1,6 +1,6 @@
|
|||
# Obsidian Task Progress Bar
|
||||
|
||||
A plugin for showing task progress bar near the tasks bullet or headings. Only works in Live Preview mode in Obsidian.
|
||||
A plugin for showing task progress bar near the tasks bullet or headings.
|
||||
|
||||

|
||||
|
||||
|
|
@ -22,9 +22,37 @@ When you finished the task2,
|
|||
|
||||
## Settings
|
||||
|
||||
1. Add progress bar to Heading: Make the Heading showing the task progress bars.
|
||||
2. Add number to progress bar: You can see the total/completed number of tasks.
|
||||
3. Set alternative marks: You can set which marks means the completed tasks.
|
||||
### Basic Settings
|
||||
|
||||
1. **Add progress bar to Heading**: Make the Heading showing the task progress bars.
|
||||
2. **Enable heading progress bars**: Add progress bars to headings to show progress of all tasks under that heading.
|
||||
3. **Add number to progress bar**: You can see the total/completed number of tasks.
|
||||
4. **Show percentage**: Display the completion percentage in the progress bar.
|
||||
5. **Count sub children level of current Task**: Allow the plugin to count sub-tasks in the progress calculation.
|
||||
|
||||
### Task Status Settings
|
||||
|
||||
You can customize which characters represent different task statuses, or choose from predefined collections.
|
||||
|
||||
1. **Completed task markers**: Characters that represent completed tasks (default: `x|X`).
|
||||
2. **Planned task markers**: Characters that represent planned tasks (default: `?`).
|
||||
3. **In progress task markers**: Characters that represent tasks in progress (default: `>|/`).
|
||||
4. **Abandoned task markers**: Characters that represent abandoned tasks (default: `-`).
|
||||
5. **Not started task markers**: Characters that represent not started tasks (default: space ` `).
|
||||
6. **Count other statuses as**: Choose which category to count other statuses as.
|
||||
|
||||
### Task Counting Settings
|
||||
|
||||
1. **Exclude specific task markers**: Specify task markers to exclude from counting (e.g., `?|/`).
|
||||
2. **Only count specific task markers**: Toggle to only count specific task markers.
|
||||
3. **Specific task markers to count**: If the above option is enabled, specify which task markers to count.
|
||||
|
||||
### Conditional Progress Bar Display
|
||||
|
||||
1. **Hide progress bars based on conditions**: Enable hiding progress bars based on tags, folders, or metadata.
|
||||
2. **Hide by tags**: Specify tags that will hide progress bars (comma-separated, without #).
|
||||
3. **Hide by folders**: Specify folder paths that will hide progress bars.
|
||||
4. **Hide by metadata**: Specify frontmatter metadata that will hide progress bars.
|
||||
|
||||
## How to Install
|
||||
|
||||
|
|
@ -32,10 +60,6 @@ When you finished the task2,
|
|||
|
||||
💜: Directly install from Obsidian Market.
|
||||
|
||||
### From BRAT
|
||||
|
||||
🚗: Add `Quorafind/Obsidian-Task-Progress-Bar` to BRAT.
|
||||
|
||||
### Download Manually
|
||||
|
||||
🚚: Download the latest release. Extract and put the three files (main.js, manifest.json, styles.css) to
|
||||
|
|
|
|||
14
package.json
14
package.json
|
|
@ -14,25 +14,23 @@
|
|||
"devDependencies": {
|
||||
"@codemirror/autocomplete": "^6.0.0",
|
||||
"@codemirror/commands": "^6.0.0",
|
||||
"@codemirror/lang-html": "^6.0.0",
|
||||
"@codemirror/basic-setup": "^0.20.0",
|
||||
"@codemirror/lang-css": "^6.0.0",
|
||||
"@codemirror/lang-html": "^6.0.0",
|
||||
"@codemirror/language": "https://github.com/lishid/cm-language",
|
||||
"@codemirror/rangeset": "^0.19.1",
|
||||
"@codemirror/lint": "^6.0.0",
|
||||
"@codemirror/search": "^6.0.0",
|
||||
"@codemirror/state": "^6.0.0",
|
||||
"@codemirror/view": "^6.0.0",
|
||||
"@codemirror/stream-parser": "https://github.com/lishid/stream-parser",
|
||||
"codemirror": "^6.0.0",
|
||||
"@codemirror/view": "^6.0.0",
|
||||
"@types/node": "^16.11.6",
|
||||
"@typescript-eslint/eslint-plugin": "^5.2.0",
|
||||
"@typescript-eslint/parser": "^5.2.0",
|
||||
"builtin-modules": "^3.2.0",
|
||||
"codemirror": "^6.0.0",
|
||||
"esbuild": "0.13.12",
|
||||
"obsidian": "latest",
|
||||
"obsidian": "^1.8.7",
|
||||
"regexp-match-indices": "^1.0.2",
|
||||
"tslib": "2.4.0",
|
||||
"typescript": "4.7.3",
|
||||
"regexp-match-indices": "^1.0.2"
|
||||
"typescript": "4.7.3"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
2047
pnpm-lock.yaml
2047
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
284
src/autoCompleteParent.ts
Normal file
284
src/autoCompleteParent.ts
Normal file
|
|
@ -0,0 +1,284 @@
|
|||
import { App, Editor } from "obsidian";
|
||||
import {
|
||||
EditorState,
|
||||
Text,
|
||||
Transaction,
|
||||
TransactionSpec,
|
||||
} from "@codemirror/state";
|
||||
import { getTabSize } from "./utils";
|
||||
|
||||
/**
|
||||
* Creates an editor extension that automatically completes parent tasks when all child tasks are completed
|
||||
* @param app The Obsidian app instance
|
||||
* @param plugin The plugin instance
|
||||
* @returns An editor extension that can be registered with the plugin
|
||||
*/
|
||||
export function autoCompleteParentExtension(app: App) {
|
||||
return EditorState.transactionFilter.of((tr) => {
|
||||
return handleAutoCompleteParentTransaction(tr, app);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles transactions to detect task completion and process parent task updates
|
||||
* @param tr The transaction to handle
|
||||
* @param app The Obsidian app instance
|
||||
* @param plugin The plugin instance
|
||||
* @returns The original transaction or a modified transaction
|
||||
*/
|
||||
export function handleAutoCompleteParentTransaction(
|
||||
tr: Transaction,
|
||||
app: App
|
||||
): TransactionSpec {
|
||||
// Only process transactions that change the document and are user input events
|
||||
if (!tr.docChanged) {
|
||||
return tr;
|
||||
}
|
||||
|
||||
// Check if a task was completed in this transaction
|
||||
const taskCompletionInfo = findTaskCompletion(tr);
|
||||
if (!taskCompletionInfo) {
|
||||
return tr;
|
||||
}
|
||||
|
||||
// Check if the completed task has a parent task
|
||||
const { doc, lineNumber } = taskCompletionInfo;
|
||||
const parentInfo = findParentTask(doc, lineNumber);
|
||||
if (!parentInfo) {
|
||||
return tr;
|
||||
}
|
||||
|
||||
// Check if all siblings are completed
|
||||
const allSiblingsCompleted = areAllSiblingsCompleted(
|
||||
doc,
|
||||
parentInfo.lineNumber,
|
||||
parentInfo.indentationLevel,
|
||||
app
|
||||
);
|
||||
|
||||
// If all siblings are completed, update the parent task
|
||||
if (allSiblingsCompleted) {
|
||||
return completeParentTask(tr, parentInfo.lineNumber, doc);
|
||||
}
|
||||
|
||||
return tr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a task completion event in the transaction
|
||||
* @param tr The transaction to check
|
||||
* @returns Information about the completed task or null if no task was completed
|
||||
*/
|
||||
function findTaskCompletion(tr: Transaction): {
|
||||
doc: Text;
|
||||
lineNumber: number;
|
||||
} | null {
|
||||
let taskCompletedLine: number | null = null;
|
||||
|
||||
// Check each change in the transaction
|
||||
tr.changes.iterChanges(
|
||||
(
|
||||
fromA: number,
|
||||
toA: number,
|
||||
fromB: number,
|
||||
toB: number,
|
||||
inserted: Text
|
||||
) => {
|
||||
// If a change involves inserting an 'x' character
|
||||
const insertedText = inserted.toString();
|
||||
if (insertedText === "x" || insertedText === "X") {
|
||||
// Get the position context
|
||||
const pos = fromB;
|
||||
const line = tr.newDoc.lineAt(pos);
|
||||
const lineText = line.text;
|
||||
console.log(lineText);
|
||||
|
||||
// Check if this is a task being completed ([ ] to [x])
|
||||
// Matches the pattern where the cursor is between [ and ]
|
||||
const taskRegex = /^[\s|\t]*([-*+]|\d+\.)\s\[[x|X]\]/i;
|
||||
if (taskRegex.test(lineText)) {
|
||||
taskCompletedLine = line.number;
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if (taskCompletedLine === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
doc: tr.newDoc,
|
||||
lineNumber: taskCompletedLine,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the parent task of a given task line
|
||||
* @param doc The document to search in
|
||||
* @param lineNumber The line number of the task
|
||||
* @returns Information about the parent task or null if no parent was found
|
||||
*/
|
||||
function findParentTask(
|
||||
doc: Text,
|
||||
lineNumber: number
|
||||
): {
|
||||
lineNumber: number;
|
||||
indentationLevel: number;
|
||||
} | null {
|
||||
// Get the current line and its indentation level
|
||||
const currentLine = doc.line(lineNumber);
|
||||
const currentLineText = currentLine.text;
|
||||
const currentIndentMatch = currentLineText.match(/^[\s|\t]*/);
|
||||
const currentIndentLevel = currentIndentMatch
|
||||
? currentIndentMatch[0].length
|
||||
: 0;
|
||||
|
||||
// If we're at the top level, there's no parent
|
||||
if (currentIndentLevel === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Look backwards for a line with less indentation that contains a task
|
||||
for (let i = lineNumber - 1; i >= 1; i--) {
|
||||
const line = doc.line(i);
|
||||
const lineText = line.text;
|
||||
|
||||
// Skip empty lines
|
||||
if (lineText.trim() === "") {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the indentation level of this line
|
||||
const indentMatch = lineText.match(/^[\s|\t]*/);
|
||||
const indentLevel = indentMatch ? indentMatch[0].length : 0;
|
||||
|
||||
// If this line has less indentation than the current line
|
||||
if (indentLevel < currentIndentLevel) {
|
||||
// Check if it's a task
|
||||
const taskRegex = /^[\s|\t]*([-*+]|\d+\.)\s\[([ |x|X])\]/i;
|
||||
if (taskRegex.test(lineText)) {
|
||||
return {
|
||||
lineNumber: i,
|
||||
indentationLevel: indentLevel,
|
||||
};
|
||||
}
|
||||
|
||||
// If it's not a task, it can't be a parent task
|
||||
// If it's a heading or other structural element, we keep looking
|
||||
if (!lineText.startsWith("#") && !lineText.startsWith(">")) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Checks if all sibling tasks at the same indentation level as the parent's children are completed
|
||||
* @param doc The document to check
|
||||
* @param parentLineNumber The line number of the parent task
|
||||
* @param parentIndentLevel The indentation level of the parent task
|
||||
* @returns True if all siblings are completed, false otherwise
|
||||
*/
|
||||
function areAllSiblingsCompleted(
|
||||
doc: Text,
|
||||
parentLineNumber: number,
|
||||
parentIndentLevel: number,
|
||||
app: App
|
||||
): boolean {
|
||||
const tabSize = getTabSize(app);
|
||||
|
||||
// The expected indentation level for child tasks
|
||||
const childIndentLevel = parentIndentLevel + tabSize;
|
||||
|
||||
// Track if we found at least one child
|
||||
let foundChild = false;
|
||||
|
||||
// Search forward from the parent line
|
||||
for (let i = parentLineNumber + 1; i <= doc.lines; i++) {
|
||||
const line = doc.line(i);
|
||||
const lineText = line.text;
|
||||
|
||||
// Skip empty lines
|
||||
if (lineText.trim() === "") {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the indentation of this line
|
||||
const indentMatch = lineText.match(/^[\s|\t]*/);
|
||||
const indentLevel = indentMatch ? indentMatch[0].length : 0;
|
||||
|
||||
// If we encounter a line with less or equal indentation to the parent,
|
||||
// we've moved out of the parent's children scope
|
||||
if (indentLevel <= parentIndentLevel) {
|
||||
break;
|
||||
}
|
||||
|
||||
// If this is a direct child of the parent (exactly one level deeper)
|
||||
if (indentLevel === childIndentLevel) {
|
||||
// Create a regex to match tasks based on the indentation level
|
||||
const taskRegex = new RegExp(
|
||||
`^[\\s|\\t]{${childIndentLevel}}([-*+]|\\d+\\.)\\s\\[(.)\\]`
|
||||
);
|
||||
|
||||
const taskMatch = lineText.match(taskRegex);
|
||||
if (taskMatch) {
|
||||
foundChild = true;
|
||||
|
||||
// If we find an incomplete task, return false
|
||||
const taskStatus = taskMatch[2];
|
||||
if (taskStatus !== "x" && taskStatus !== "X") {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we found at least one child and all were completed, return true
|
||||
return foundChild;
|
||||
}
|
||||
|
||||
/**
|
||||
* Completes a parent task by modifying the transaction
|
||||
* @param tr The transaction to modify
|
||||
* @param parentLineNumber The line number of the parent task
|
||||
* @param doc The document
|
||||
* @returns The modified transaction
|
||||
*/
|
||||
function completeParentTask(
|
||||
tr: Transaction,
|
||||
parentLineNumber: number,
|
||||
doc: Text
|
||||
): TransactionSpec {
|
||||
const parentLine = doc.line(parentLineNumber);
|
||||
const parentLineText = parentLine.text;
|
||||
|
||||
// Find the task marker position
|
||||
const taskMarkerMatch = parentLineText.match(
|
||||
/^[\s|\t]*([-*+]|\d+\.)\s\[( )\]/
|
||||
);
|
||||
if (!taskMarkerMatch) {
|
||||
return tr;
|
||||
}
|
||||
|
||||
// Calculate the position where we need to insert 'x'
|
||||
const markerStart =
|
||||
parentLine.from +
|
||||
taskMarkerMatch.index! +
|
||||
taskMarkerMatch[0].indexOf("[ ]") +
|
||||
1;
|
||||
|
||||
// Create a new transaction that adds the completion marker 'x' to the parent task
|
||||
return {
|
||||
changes: [
|
||||
tr.changes,
|
||||
{
|
||||
from: markerStart,
|
||||
to: markerStart + 1,
|
||||
insert: "x",
|
||||
},
|
||||
],
|
||||
selection: tr.selection,
|
||||
};
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -19,6 +19,7 @@ import {
|
|||
TaskProgressBarSettingTab,
|
||||
} from "./taskProgressBarSetting";
|
||||
import { EditorView } from "@codemirror/view";
|
||||
import { autoCompleteParentExtension } from "./autoCompleteParent";
|
||||
|
||||
class TaskProgressBarPopover extends HoverPopover {
|
||||
plugin: TaskProgressBarPlugin;
|
||||
|
|
@ -103,7 +104,10 @@ export default class TaskProgressBarPlugin extends Plugin {
|
|||
await this.loadSettings();
|
||||
|
||||
this.addSettingTab(new TaskProgressBarSettingTab(this.app, this));
|
||||
this.registerEditorExtension(taskProgressBarExtension(this.app, this));
|
||||
this.registerEditorExtension([
|
||||
taskProgressBarExtension(this.app, this),
|
||||
|
||||
]);
|
||||
this.registerMarkdownPostProcessor((el, ctx) => {
|
||||
updateProgressBarInElement({
|
||||
plugin: this,
|
||||
|
|
@ -111,6 +115,14 @@ export default class TaskProgressBarPlugin extends Plugin {
|
|||
ctx: ctx,
|
||||
});
|
||||
});
|
||||
|
||||
this.app.workspace.onLayoutReady(() => {
|
||||
if (this.settings.autoCompleteParent) {
|
||||
this.registerEditorExtension([
|
||||
autoCompleteParentExtension(this.app),
|
||||
]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onunload() {}
|
||||
|
|
|
|||
|
|
@ -4,8 +4,10 @@ import { allStatusCollections } from "./task-status";
|
|||
|
||||
export interface TaskProgressBarSettings {
|
||||
addTaskProgressBarToHeading: boolean;
|
||||
enableHeadingProgressBar: boolean;
|
||||
addNumberToProgressBar: boolean;
|
||||
showPercentage: boolean;
|
||||
autoCompleteParent: boolean;
|
||||
countSubLevel: boolean;
|
||||
hideProgressBarBasedOnConditions: boolean;
|
||||
hideProgressBarTags: string;
|
||||
|
|
@ -31,7 +33,9 @@ export interface TaskProgressBarSettings {
|
|||
|
||||
export const DEFAULT_SETTINGS: TaskProgressBarSettings = {
|
||||
addTaskProgressBarToHeading: false,
|
||||
enableHeadingProgressBar: false,
|
||||
addNumberToProgressBar: false,
|
||||
autoCompleteParent: false,
|
||||
showPercentage: false,
|
||||
countSubLevel: true,
|
||||
hideProgressBarBasedOnConditions: false,
|
||||
|
|
@ -95,6 +99,34 @@ export class TaskProgressBarSettingTab extends PluginSettingTab {
|
|||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Enable heading progress bars")
|
||||
.setDesc(
|
||||
"Add progress bars to headings to show progress of all tasks under that heading."
|
||||
)
|
||||
.addToggle((toggle) =>
|
||||
toggle
|
||||
.setValue(this.plugin.settings.enableHeadingProgressBar)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.enableHeadingProgressBar = value;
|
||||
this.applySettingsUpdate();
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Auto complete parent task")
|
||||
.setDesc(
|
||||
"Toggle this to allow this plugin to auto complete parent task when all child tasks are completed."
|
||||
)
|
||||
.addToggle((toggle) =>
|
||||
toggle
|
||||
.setValue(this.plugin.settings.autoCompleteParent)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.autoCompleteParent = value;
|
||||
this.applySettingsUpdate();
|
||||
})
|
||||
);
|
||||
|
||||
this.showNumberToProgressbar();
|
||||
|
||||
new Setting(containerEl)
|
||||
|
|
@ -240,6 +272,22 @@ export class TaskProgressBarSettingTab extends PluginSettingTab {
|
|||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Planned task markers")
|
||||
.setDesc(
|
||||
'Characters in square brackets that represent planned tasks. Example: "?"'
|
||||
)
|
||||
.addText((text) =>
|
||||
text
|
||||
.setPlaceholder(DEFAULT_SETTINGS.taskStatuses.planned)
|
||||
.setValue(this.plugin.settings.taskStatuses.planned)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.taskStatuses.planned =
|
||||
value || DEFAULT_SETTINGS.taskStatuses.planned;
|
||||
this.applySettingsUpdate();
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("In progress task markers")
|
||||
.setDesc(
|
||||
|
|
|
|||
28
src/utils.ts
28
src/utils.ts
|
|
@ -1,8 +1,12 @@
|
|||
import { EditorView } from "@codemirror/view";
|
||||
|
||||
import TaskProgressBarPlugin from "./taskProgressBarIndex";
|
||||
import { editorInfoField, MarkdownPostProcessorContext, TFile } from "obsidian";
|
||||
|
||||
import {
|
||||
App,
|
||||
editorInfoField,
|
||||
MarkdownPostProcessorContext,
|
||||
TFile,
|
||||
} from "obsidian";
|
||||
|
||||
// Helper function to check if progress bars should be hidden
|
||||
export function shouldHideProgressBarInPreview(
|
||||
|
|
@ -14,7 +18,7 @@ export function shouldHideProgressBarInPreview(
|
|||
}
|
||||
|
||||
const abstractFile = ctx.sourcePath
|
||||
? plugin.app.vault.getAbstractFileByPath(ctx.sourcePath)
|
||||
? plugin.app.vault.getFileByPath(ctx.sourcePath)
|
||||
: null;
|
||||
if (!abstractFile) {
|
||||
return false;
|
||||
|
|
@ -139,3 +143,21 @@ export function shouldHideProgressBarInLivePriview(
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get tab size from vault configuration
|
||||
*/
|
||||
export function getTabSize(app: App): number {
|
||||
try {
|
||||
const vaultConfig = app.vault as any;
|
||||
const useTab =
|
||||
vaultConfig.getConfig?.("useTab") === undefined ||
|
||||
vaultConfig.getConfig?.("useTab") === true;
|
||||
return useTab
|
||||
? (vaultConfig.getConfig?.("tabSize") || 4) / 4
|
||||
: vaultConfig.getConfig?.("tabSize") || 4;
|
||||
} catch (e) {
|
||||
console.error("Error getting tab size:", e);
|
||||
return 4; // Default tab size
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -773,7 +773,6 @@ export function taskProgressBarExtension(
|
|||
| "notStarted"
|
||||
| "planned" {
|
||||
const markMatch = text.match(/\[(.)]/);
|
||||
console.log(markMatch, text);
|
||||
if (!markMatch || !markMatch[1]) {
|
||||
return "notStarted";
|
||||
}
|
||||
|
|
@ -997,17 +996,7 @@ export function taskProgressBarExtension(
|
|||
tabSize
|
||||
);
|
||||
|
||||
const bulletCompleteRegex = this.createCompletedTaskRegex(
|
||||
plugin,
|
||||
false,
|
||||
level,
|
||||
tabSize
|
||||
);
|
||||
const headingTotalRegex = this.createTotalTaskRegex(true);
|
||||
const headingCompleteRegex = this.createCompletedTaskRegex(
|
||||
plugin,
|
||||
true
|
||||
);
|
||||
|
||||
// Count tasks
|
||||
for (let i = 0; i < textArray.length; i++) {
|
||||
|
|
@ -1116,29 +1105,6 @@ export function taskProgressBarExtension(
|
|||
}
|
||||
}
|
||||
|
||||
// Log debug information
|
||||
if (taskDebug.length > 0) {
|
||||
console.log("Task counting debug:", {
|
||||
taskDebug,
|
||||
completedCount: completed,
|
||||
inProgressCount: inProgress,
|
||||
abandonedCount: abandoned,
|
||||
notStartedCount: notStarted,
|
||||
plannedCount: planned,
|
||||
totalCount: total,
|
||||
settings: {
|
||||
useOnlyCountMarks:
|
||||
plugin?.settings.useOnlyCountMarks,
|
||||
onlyCountTaskMarks:
|
||||
plugin?.settings.onlyCountTaskMarks,
|
||||
excludeTaskMarks: plugin?.settings.excludeTaskMarks,
|
||||
taskStatuses: plugin?.settings.taskStatuses,
|
||||
countOtherStatusesAs:
|
||||
plugin?.settings.countOtherStatusesAs,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// Ensure counts don't exceed total
|
||||
completed = Math.min(completed, total);
|
||||
inProgress = Math.min(inProgress, total - completed);
|
||||
|
|
|
|||
Loading…
Reference in a new issue