+
+
+
{t("view-id")}
+
{t("view-id-info")}
+
+
+
{view.viewId}
+
{
+ try {
+ void navigator.clipboard.writeText(view.viewId);
+ new Notice(t("copy-view-id-successful"));
+ } catch (error) {
+ bugReporterManagerInsatance.addToLogs(
+ 221,
+ String(error),
+ "BoardConfigModal.tsx/renderViewSettings/copy-view-id",
+ );
+ new Notice(t("copy-task-title-unsuccessful"));
+ }
+ }} />
+
+
{t("view-name")}
@@ -1282,7 +1308,7 @@ const ConfigModalContent: React.FC
= ({
-
+
@@ -1350,7 +1376,14 @@ const ConfigModalContent: React.FC = ({
-
+
@@ -1365,7 +1398,14 @@ const ConfigModalContent: React.FC
= ({
)}
-
+
>
);
};
diff --git a/src/modals/BoardsExplorer.ts b/src/modals/BoardsExplorer.ts
index 18449ed9..33a1b33c 100644
--- a/src/modals/BoardsExplorer.ts
+++ b/src/modals/BoardsExplorer.ts
@@ -58,9 +58,9 @@ export class BoardsExplorerModal extends Modal {
text: t("refresh-boards"),
cls: "boardsExplorerScanButton",
});
- scanButton.addEventListener("click", async () => {
+ scanButton.addEventListener("click", () => {
if (!this.isScanning) {
- await this.handleScanBoards(
+ void this.handleScanBoards(
mainContent,
headerSection,
scanButton,
@@ -121,8 +121,8 @@ export class BoardsExplorerModal extends Modal {
cls: "boardsExplorerCard",
});
- card.addEventListener("click", async () => {
- await this.openBoard(boardId, board.filePath);
+ card.addEventListener("click", () => {
+ void this.openBoard(boardId, board.filePath);
this.close();
});
@@ -170,7 +170,7 @@ export class BoardsExplorerModal extends Modal {
});
pathRow.createEl("span", {
- text: "File Path:",
+ text: t("file-path") + " : ",
cls: "boardsExplorerCardRowLabel",
});
@@ -231,57 +231,10 @@ export class BoardsExplorerModal extends Modal {
}
private createLoadingBar(): HTMLElement {
- const container = document.createElement("div");
- container.className = "boardsExplorerLoadingBarContainer";
-
- const style = document.createElement("style");
- style.textContent = `
- .boardsExplorerLoadingBarContainer {
- width: calc(100% + 40px);
- margin: 0 -20px 12px -20px;
- padding: 0 20px;
- overflow: hidden;
- }
-
- .boardsExplorerLoadingBar {
- width: 100%;
- height: 4px;
- background: linear-gradient(
- 90deg,
- #0066cc 0%,
- #0066cc 20%,
- transparent 20%,
- transparent 40%,
- #0066cc 40%,
- #0066cc 60%,
- transparent 60%,
- transparent 80%,
- #0066cc 80%,
- #0066cc 100%
- );
- background-size: 100px 4px;
- animation: boardsExplorerLoadingPendulum 2s ease-in-out infinite;
- border-radius: 2px;
- }
-
- @keyframes boardsExplorerLoadingPendulum {
- 0% {
- background-position: -100px 0;
- }
- 50% {
- background-position: calc(100% + 100px) 0;
- }
- 100% {
- background-position: -100px 0;
- }
- }
- `;
-
- container.appendChild(style);
-
- const bar = document.createElement("div");
- bar.className = "boardsExplorerLoadingBar";
-
+ const container = activeDocument.createElement("div");
+ container.addClass("boardsExplorerLoadingBarContainer");
+ const bar = activeDocument.createElement("div");
+ bar.addClass("boardsExplorerLoadingBar");
container.appendChild(bar);
return container;
diff --git a/src/modals/BugReporterModal.ts b/src/modals/BugReporterModal.ts
index d00dc232..67c85a46 100644
--- a/src/modals/BugReporterModal.ts
+++ b/src/modals/BugReporterModal.ts
@@ -120,9 +120,9 @@ export class BugReporterModal extends Modal {
}
async sanitizeBugReportContent(
- message: String,
- bugContent: String,
- context: String,
+ message: string,
+ bugContent: string,
+ context: string,
) {
// Sanitize the bug report content to prevent XSS attacks
let sanitizedErrorContent = bugContent;
@@ -189,7 +189,7 @@ export class BugReporterModal extends Modal {
handleCopyBtnEvent(bugReportContent: string) {
// Copy the bug report content to clipboard
- navigator.clipboard.writeText(bugReportContent).then(() => {
+ void navigator.clipboard.writeText(bugReportContent).then(() => {
new Notice(t("copied-to-clipboard"));
});
}
diff --git a/src/modals/ConfigureColumnSortingModal.ts b/src/modals/ConfigureColumnSortingModal.ts
index 6789aa0f..7899df8b 100644
--- a/src/modals/ConfigureColumnSortingModal.ts
+++ b/src/modals/ConfigureColumnSortingModal.ts
@@ -31,9 +31,10 @@ export class ConfigureColumnSortingModal extends Modal {
// Deep-copy columnConfiguration to avoid mutating caller's object (avoid stale/unsaved changes)
// This ensures that edits in the modal don't affect the original object until Save is clicked
try {
- this.columnConfiguration = JSON.parse(
+ const parsedData: unknown = JSON.parse(
JSON.stringify(columnConfiguration),
);
+ this.columnConfiguration = parsedData as ColumnData;
} catch (e) {
// Fallback to shallow copy if stringify fails
this.columnConfiguration = { ...columnConfiguration };
@@ -95,7 +96,7 @@ export class ConfigureColumnSortingModal extends Modal {
forceFallback: true,
fallbackClass: "task-board-sortable-fallback",
easing: "cubic-bezier(1, 0, 0, 1)",
- onSort: async () => {
+ onSort: () => {
// Use stable uid attributes on DOM rows to determine new order
const uidsInDom = Array.from(sortingCriteriaList.children).map(
(child) => child.getAttribute("data-uid"),
@@ -104,7 +105,7 @@ export class ConfigureColumnSortingModal extends Modal {
const newOrder: ColumnData["sortCriteria"] = [];
uidsInDom.forEach((uid, idx) => {
if (!uid) return;
- const found = existing.find((c) => (c as any).uid === uid);
+ const found = existing.find((c) => c.uid === uid);
if (found) {
found.priority = idx + 1;
newOrder.push(found);
@@ -129,7 +130,7 @@ export class ConfigureColumnSortingModal extends Modal {
cls: "configureColumnSortingModalHomeSortingCriteriaListItemRow",
attr: {
"data-criteria-name": sortCriteria.criteria,
- "data-uid": (sortCriteria as any).uid,
+ "data-uid": sortCriteria.uid,
},
});
@@ -257,7 +258,7 @@ export class ConfigureColumnSortingModal extends Modal {
})
.addButton((del) =>
del
- .setButtonText("delete")
+ .setButtonText(t("delete"))
.setIcon("trash")
.setClass(
"configureColumnSortingModalHomeSortingCriteriaListItemDeleteCriterion",
@@ -301,7 +302,7 @@ export class ConfigureColumnSortingModal extends Modal {
text: t("add-new-sorting-criterion"),
cls: "configureColumnSortingModalHomeAddSortingBtn",
});
- addNewSortingButton.addEventListener("click", async () => {
+ addNewSortingButton.addEventListener("click", () => {
if (
this.columnConfiguration.sortCriteria?.some(
(c) => c.criteria === "manualOrder",
diff --git a/src/modals/CustomStatusConfigurator.ts b/src/modals/CustomStatusConfigurator.ts
index 51b93409..e9d46241 100644
--- a/src/modals/CustomStatusConfigurator.ts
+++ b/src/modals/CustomStatusConfigurator.ts
@@ -3,14 +3,14 @@ import { Modal, Setting, TextComponent } from "obsidian";
import type { Plugin } from "obsidian";
import { statusTypeNames } from "../interfaces/Enums.js";
import { CustomStatus } from "../interfaces/GlobalSettings.js";
-import { StatusType, StatusConfiguration } from "../interfaces/StatusConfiguration.js";
+import { StatusConfiguration } from "../interfaces/StatusConfiguration.js";
export class CustomStatusModal extends Modal {
statusSymbol: string;
statusName: string;
statusNextSymbol: string;
statusAvailableAsCommand: boolean;
- type: StatusType;
+ type: statusTypeNames;
saved: boolean = false;
error: boolean = false;
@@ -21,14 +21,14 @@ export class CustomStatusModal extends Modal {
isCoreStatus: boolean,
) {
super(plugin.app);
- const status = statusType as any;
+ let status = statusType;
this.statusSymbol = status.symbol;
this.statusName = status.name;
this.statusNextSymbol = status.nextStatusSymbol;
this.statusAvailableAsCommand = status.availableAsCommand;
- // Ensure type is a valid StatusType enum value
+ // Ensure type is a valid statusTypeNames enum value
if (typeof status.type === "string") {
- this.type = status.type as StatusType;
+ this.type = status.type;
} else {
this.type = status.type;
}
@@ -57,12 +57,10 @@ export class CustomStatusModal extends Modal {
const settingDiv = contentEl.createDiv();
//const title = this.title ?? '...';
- let statusSymbolText: TextComponent;
new Setting(settingDiv)
.setName(t("task-status-symbol"))
.setDesc(t("task-status-symbol-info"))
.addText((text) => {
- statusSymbolText = text;
text.setValue(this.statusSymbol).onChange((v) => {
this.statusSymbol = v;
});
@@ -72,12 +70,10 @@ export class CustomStatusModal extends Modal {
// Show any error if the initial value loaded is incorrect.
});
- let statusNameText: TextComponent;
new Setting(settingDiv)
.setName(t("task-status-name"))
.setDesc(t("task-status-name-info"))
.addText((text) => {
- statusNameText = text;
text.setValue(this.statusName).onChange((v) => {
this.statusName = v;
});
@@ -100,17 +96,15 @@ export class CustomStatusModal extends Modal {
dropdown.addOption(s, s);
});
dropdown.setValue(this.type).onChange((v) => {
- this.type = v as StatusType;
+ this.type = v as statusTypeNames;
});
});
- let statusNextSymbolText: TextComponent;
new Setting(settingDiv)
.setName(t("cycle-to-following-status"))
.setDesc(t("cycle-to-following-status-info"))
.addText((text) => {
- text.setPlaceholder("eg.: /");
- statusNextSymbolText = text;
+ text.setPlaceholder("Eg.: /");
text.setValue(this.statusNextSymbol).onChange((v) => {
this.statusNextSymbol = v;
});
@@ -145,7 +139,7 @@ export class CustomStatusModal extends Modal {
// titleSpan.prepend(iconEl);
// }
onOpen() {
- this.display();
+ void this.display();
}
static setValidationError(textInput: TextComponent) {
diff --git a/src/modals/DiffContentCompareModal.ts b/src/modals/DiffContentCompareModal.ts
index d8a56ca5..3e2ab307 100644
--- a/src/modals/DiffContentCompareModal.ts
+++ b/src/modals/DiffContentCompareModal.ts
@@ -2,6 +2,7 @@
import { Modal, ButtonComponent } from "obsidian";
import TaskBoard from "../../main.js";
+import { t } from "i18next";
export type DiffSelection = "old" | "new";
@@ -33,13 +34,13 @@ export class DiffContentCompareModal extends Modal {
"data-type",
"task-board-diff-content-compare",
);
- this.setTitle("Task Board Safe Guard");
+ this.setTitle(t("task-board-safe-guard"));
contentEl.classList.add("taskboard-diff-content-compare-modal");
contentEl.createEl("h2", { text: "Content mismatch detected" });
contentEl.createEl("p", {
- text: "Looks like the task content in your file is a little different from the content you just edited through Task Board. Choose which version of content you would like to keep:",
+ text: "Looks like the task content in your file is a little different from the content you just edited through task board. Choose which version of content you would like to keep:",
});
const comparisonContainer = contentEl.createDiv({
@@ -53,13 +54,18 @@ export class DiffContentCompareModal extends Modal {
const newContentDiv = rightDiv.createDiv({
cls: "taskboard-diff-content-compare-modal-content",
});
- newContentDiv.insertAdjacentHTML(
- "beforeend",
- this.getHighlightedDiff(
- this.cachedTaskContent,
- this.taskContentFromFile,
- "left",
- ),
+ // newContentDiv.insertAdjacentHTML(
+ // "beforeend",
+ // this.getHighlightedDiff(
+ // this.cachedTaskContent,
+ // this.taskContentFromFile,
+ // "left",
+ // ),
+ // );
+ newContentDiv.textContent = this.getHighlightedDiff(
+ this.cachedTaskContent,
+ this.taskContentFromFile,
+ "left",
);
new ButtonComponent(rightDiv)
.setButtonText("Keep this as it is")
@@ -76,13 +82,18 @@ export class DiffContentCompareModal extends Modal {
const oldContentDiv = leftDiv.createDiv({
cls: "taskboard-diff-content-compare-modal-content",
});
- oldContentDiv.insertAdjacentHTML(
- "beforeend",
- this.getHighlightedDiff(
- this.cachedTaskContent,
- this.EditedTaskContent,
- "right",
- ),
+ // oldContentDiv.insertAdjacentHTML(
+ // "beforeend",
+ // this.getHighlightedDiff(
+ // this.cachedTaskContent,
+ // this.EditedTaskContent,
+ // "right",
+ // ),
+ // );
+ oldContentDiv.textContent = this.getHighlightedDiff(
+ this.cachedTaskContent,
+ this.EditedTaskContent,
+ "right",
);
new ButtonComponent(leftDiv)
.setButtonText("Use this")
@@ -93,9 +104,10 @@ export class DiffContentCompareModal extends Modal {
});
const noteOnSetting = contentEl.createEl("p", {
+ // eslint-disable-next-line obsidianmd/ui/sentence-case
text: "NOTE : If you think this safe guard modal shown is irrelevant and its also popping-up too many times, you can by-pass it and disable this from the settings under the 'general' tab.",
});
- noteOnSetting.style.color = "red";
+ noteOnSetting.addClass("tb_color_white");
const infoDiv = contentEl.createDiv({
cls: "taskboard-diff-content-compare-modal-info",
@@ -108,10 +120,10 @@ export class DiffContentCompareModal extends Modal {
text: "Green highlighted content indicates the characters which are different by comparing the content you just now edited and the content from the task-board-cache..",
});
ul.createEl("li", {
- text: "Select the version of content you want Task Board to write in your note.",
+ text: "Select the version of content you want task board to write in your note.",
});
ul.createEl("li", {
- text: "If the content shown on left-side is completely different from the content of the task you just edited. This probably means that, Task Board couldnt able to find the task you just edited through its cache inside the current file at the particular line. Either some other plugin updated the content or during sync the content was tempered. Use the abort button below to close this modal, to avoid updating any data. And scan the file using file-menu option or update the task manually.",
+ text: "If the content shown on left-side is completely different from the content of the task you just edited. This probably means that, task board couldnt able to find the task you just edited through its cache inside the current file at the particular line. Either some other plugin updated the content or during sync the content was tempered. Use the abort button below to close this modal, to avoid updating any data. And scan the file using file-menu option or update the task manually.",
});
});
@@ -127,7 +139,7 @@ export class DiffContentCompareModal extends Modal {
contentEl.createEl("hr");
- contentEl.createEl("h2", { text: "Debug Info" });
+ contentEl.createEl("h2", { text: "Debug info" });
contentEl.createEl("p", {
text: "Here is why this modal was shown in the first place. If you think this modal shown was unnecessary and if possible kindly share this information with the developer to improve the plugin.",
});
@@ -146,37 +158,48 @@ export class DiffContentCompareModal extends Modal {
debuInfoComparisonContainerLefttDiv.createDiv({
cls: "taskboard-diff-content-compare-modal-content",
});
- debuInfoComparisonContainerLefttDivContent.insertAdjacentHTML(
- "beforeend",
+ // debuInfoComparisonContainerLefttDivContent.insertAdjacentHTML(
+ // "beforeend",
+ // this.getHighlightedDiff(
+ // this.cachedTaskContent,
+ // this.taskContentFromFile,
+ // "left",
+ // ),
+ // );
+ debuInfoComparisonContainerLefttDivContent.textContent =
this.getHighlightedDiff(
this.cachedTaskContent,
this.taskContentFromFile,
"left",
- ),
- );
-
+ );
const debuInfoComparisonContainerRightDiv =
debuInfoComparisonContainer.createDiv({
cls: "taskboard-diff-content-compare-modal-side",
});
debuInfoComparisonContainerRightDiv.createEl("h3", {
- text: "Task Board Cache",
+ text: t("task-board-cache"),
});
const debuInfoComparisonContainerRightDivContent =
debuInfoComparisonContainerRightDiv.createDiv({
cls: "taskboard-diff-content-compare-modal-content",
});
- debuInfoComparisonContainerRightDivContent.insertAdjacentHTML(
- "beforeend",
+ // debuInfoComparisonContainerRightDivContent.insertAdjacentHTML(
+ // "beforeend",
+ // this.getHighlightedDiff(
+ // this.taskContentFromFile,
+ // this.cachedTaskContent,
+ // "right",
+ // ),
+ // );
+ debuInfoComparisonContainerRightDivContent.textContent =
this.getHighlightedDiff(
this.taskContentFromFile,
this.cachedTaskContent,
"right",
- ),
- );
+ );
contentEl.createEl("p", {
- text: "This 'Debug info' section is just provided to find out whether the Safe Guard genuinely captured the difference correctly or whether this was a false alarm. Will remove this section in the future, if this safe guard feature is working as expected.",
+ text: "This 'debug info' section is just provided to find out whether the safe guard genuinely captured the difference correctly or whether this was a false alarm. Will remove this section in the future, if this safe guard feature is working as expected.",
});
}
@@ -264,7 +287,7 @@ export class DiffContentCompareModal extends Modal {
.replace(/&/g, "&")
.replace(//g, ">")
- .replace(/\"/g, """)
+ .replace(/"/g, """)
.replace(/'/g, "'");
}
}
diff --git a/src/modals/EditTagsModal.ts b/src/modals/EditTagsModal.ts
index 96519682..fc761a3c 100644
--- a/src/modals/EditTagsModal.ts
+++ b/src/modals/EditTagsModal.ts
@@ -1,93 +1,112 @@
-import { Modal } from 'obsidian';
-import TaskBoard from '../../main.js';
+import { Modal } from "obsidian";
+import TaskBoard from "../../main.js";
+import { MultiSuggest } from "../services/MultiSuggest.js";
export default class EditTagsModal extends Modal {
- plugin: TaskBoard;
- initialTags: string[];
- onSave: (tags: string[]) => void;
-
- private tagsContainer: HTMLElement | null = null;
- private inputEl: HTMLInputElement | null = null;
-
- constructor(plugin: TaskBoard, initialTags: string[], onSave: (tags: string[]) => void) {
- super(plugin.app);
- this.plugin = plugin;
- this.initialTags = initialTags || [];
- this.onSave = onSave;
- }
-
- onOpen() {
- const { contentEl } = this;
- contentEl.empty();
- contentEl.addClass('task-board-edit-tags-modal');
-
- const title = contentEl.createEl('h3', { text: 'Edit tags' });
- this.tagsContainer = contentEl.createDiv({ cls: 'tags-container' });
-
- const inputWrap = contentEl.createDiv({ cls: 'tag-input-wrap' });
- this.inputEl = inputWrap.createEl('input', { type: 'text' }) as HTMLInputElement;
- this.inputEl.placeholder = 'Type to add tag and press Enter (use #prefix optional)';
-
- const info = contentEl.createEl('div', { text: 'Existing tags:' });
-
- // Render initial tags as capsules
- this.initialTags.forEach(t => this.addTagPill(t));
-
- // MultiSuggest for tag suggestions (best-effort)
- try {
- // @ts-ignore - MultiSuggest is available globally in project
- const suggestionContent = this.plugin.settings.data.tagColors?.map(tc => tc.name) || [];
- // @ts-ignore
- new (window as any).MultiSuggest(this.inputEl, new Set(suggestionContent), (choice: string) => {
- this.handleAddTag(choice);
- }, this.plugin.app);
- } catch (error) {
- // ignore if MultiSuggest not available in this scope
- }
-
- this.inputEl.addEventListener('keydown', (ev) => {
- if (ev.key === 'Enter') {
- ev.preventDefault();
- const v = this.inputEl!.value.trim();
- if (v) this.handleAddTag(v);
- this.inputEl!.value = '';
- }
- });
-
- const footer = contentEl.createDiv({ cls: 'modal-footer' });
- const saveBtn = footer.createEl('button', { text: 'Save' });
- saveBtn.addEventListener('click', () => {
- const tags = Array.from(this.tagsContainer!.querySelectorAll('.tag-pill')).map((el: any) => el.getAttribute('data-tag'));
- this.onSave(tags);
- this.close();
- });
-
- const cancelBtn = footer.createEl('button', { text: 'Cancel' });
- cancelBtn.addEventListener('click', () => this.close());
- }
-
- addTagPill(tag: string) {
- if (!this.tagsContainer) return;
- const normalized = tag.startsWith('#') ? tag : `#${tag}`;
- // avoid duplicates
- const exists = Array.from(this.tagsContainer.querySelectorAll('.tag-pill')).some((el: any) => el.getAttribute('data-tag') === normalized);
- if (exists) return;
- const pill = this.tagsContainer.createDiv({ cls: 'tag-pill' });
- pill.setAttr('data-tag', normalized);
- pill.createSpan({ text: normalized });
- const removeBtn = pill.createEl('button', { text: '✕' });
- removeBtn.addEventListener('click', () => pill.remove());
- }
-
- handleAddTag(tag: string) {
- if (!this.tagsContainer) return;
- const t = tag.trim();
- if (!t) return;
- this.addTagPill(t);
- }
-
- onClose() {
- const { contentEl } = this;
- contentEl.empty();
- }
+ plugin: TaskBoard;
+ initialTags: string[];
+ onSave: (tags: string[]) => void;
+
+ private tagsContainer: HTMLElement | null = null;
+ private inputEl: HTMLInputElement | null = null;
+
+ constructor(
+ plugin: TaskBoard,
+ initialTags: string[],
+ onSave: (tags: string[]) => void,
+ ) {
+ super(plugin.app);
+ this.plugin = plugin;
+ this.initialTags = initialTags || [];
+ this.onSave = onSave;
+ }
+
+ onOpen() {
+ const { contentEl } = this;
+ contentEl.empty();
+ contentEl.addClass("task-board-edit-tags-modal");
+
+ const title = contentEl.createEl("h3", { text: "Edit tags" });
+ this.tagsContainer = contentEl.createDiv({ cls: "tags-container" });
+
+ const inputWrap = contentEl.createDiv({ cls: "tag-input-wrap" });
+ this.inputEl = inputWrap.createEl("input", { type: "text" });
+ this.inputEl.placeholder = "Hit enter key after typing the tag";
+
+ const info = contentEl.createEl("div", { text: "Existing tags:" });
+
+ // Render initial tags as capsules
+ this.initialTags.forEach((t) => this.addTagPill(t));
+
+ // MultiSuggest for tag suggestions (best-effort)
+ try {
+ // @ts-ignore - MultiSuggest is available globally in project
+ const suggestionContent =
+ this.plugin.settings.data.tagColors?.map((tc) => tc.name) || [];
+ // @ts-ignore
+ new MultiSuggest(
+ this.inputEl,
+ new Set(suggestionContent),
+ (choice: string) => {
+ this.handleAddTag(choice);
+ },
+ this.plugin.app,
+ );
+ } catch (error) {
+ // ignore if MultiSuggest not available in this scope
+ }
+
+ this.inputEl.addEventListener("keydown", (ev) => {
+ if (ev.key === "Enter") {
+ ev.preventDefault();
+ const v = this.inputEl!.value.trim();
+ if (v) this.handleAddTag(v);
+ this.inputEl!.value = "";
+ }
+ });
+
+ const footer = contentEl.createDiv({ cls: "modal-footer" });
+ const saveBtn = footer.createEl("button", { text: "Save" });
+ saveBtn.addEventListener("click", () => {
+ const tags = Array.from(
+ this.tagsContainer!.querySelectorAll(".tag-pill"),
+ ).map((el: Element) => el.getAttribute("data-tag"));
+
+ const validTags = tags.filter(
+ (tag: unknown) => typeof tag === "string",
+ );
+ this.onSave(validTags);
+ this.close();
+ });
+
+ const cancelBtn = footer.createEl("button", { text: "Cancel" });
+ cancelBtn.addEventListener("click", () => this.close());
+ }
+
+ addTagPill(tag: string) {
+ if (!this.tagsContainer) return;
+ const normalized = tag.startsWith("#") ? tag : `#${tag}`;
+ // avoid duplicates
+ const exists = Array.from(
+ this.tagsContainer.querySelectorAll(".tag-pill"),
+ ).some((el: Element) => el.getAttribute("data-tag") === normalized);
+ if (exists) return;
+ const pill = this.tagsContainer.createDiv({ cls: "tag-pill" });
+ pill.setAttr("data-tag", normalized);
+ pill.createSpan({ text: normalized });
+ const removeBtn = pill.createEl("button", { text: "✕" });
+ removeBtn.addEventListener("click", () => pill.remove());
+ }
+
+ handleAddTag(tag: string) {
+ if (!this.tagsContainer) return;
+ const t = tag.trim();
+ if (!t) return;
+ this.addTagPill(t);
+ }
+
+ onClose() {
+ const { contentEl } = this;
+ contentEl.empty();
+ }
}
diff --git a/src/modals/MergeBoardsModal.ts b/src/modals/MergeBoardsModal.ts
index c4692819..c4861648 100644
--- a/src/modals/MergeBoardsModal.ts
+++ b/src/modals/MergeBoardsModal.ts
@@ -1,6 +1,6 @@
import { App, Modal, Setting, Notice, TFile, setIcon } from "obsidian";
import TaskBoard from "../../main.js";
-import { Board } from "../interfaces/BoardConfigs.js";
+import { AdvancedFilter, Board } from "../interfaces/BoardConfigs.js";
import TaskBoardFileManager from "../managers/TaskBoardFileManager.js";
import { MultiSuggest } from "../services/MultiSuggest.js";
import { generateRandomStringId } from "../utils/TaskItemUtils.js";
@@ -141,9 +141,11 @@ export class MergeBoardsModal extends Modal {
const actions = modalContent.createDiv({
cls: "mergeBoardsModalActions",
});
- this.mergeButton = actions.createEl("button", { text: "Merge Boards" });
+ this.mergeButton = actions.createEl("button", {
+ text: t("merge-boards"),
+ });
this.mergeButton.addEventListener("click", () => {
- this.handleMerge();
+ void this.handleMerge();
});
// Cancel Button
@@ -227,7 +229,7 @@ export class MergeBoardsModal extends Modal {
// Re-enable button
if (this.mergeButton) {
this.mergeButton.disabled = false;
- this.mergeButton.textContent = "Merge Boards";
+ this.mergeButton.textContent = t("merge-boards");
}
}
}
@@ -236,18 +238,6 @@ export class MergeBoardsModal extends Modal {
// Generate new ID
const newId = generateRandomStringId("board");
- // Combine filterConfig
- const combinedFilterConfig = {
- enableSavedFilters:
- board1.filterConfig?.enableSavedFilters ||
- board2.filterConfig?.enableSavedFilters ||
- false,
- savedConfigs: [
- ...(board1.filterConfig?.savedConfigs || []),
- ...(board2.filterConfig?.savedConfigs || []),
- ],
- };
-
// Combine views
const combinedViews = [...board1.views, ...board2.views];
@@ -257,7 +247,6 @@ export class MergeBoardsModal extends Modal {
revision: board1?.revision ?? CURRENT_REVISION,
name: this.newBoardName,
description: board1.description,
- filterConfig: combinedFilterConfig,
views: combinedViews,
// lastViewId: board1.lastViewId, // Use from first board
lastViewIndex: 0,
diff --git a/src/modals/ModifiedFilesModal.ts b/src/modals/ModifiedFilesModal.ts
index 5c3de16b..0fcf4c21 100644
--- a/src/modals/ModifiedFilesModal.ts
+++ b/src/modals/ModifiedFilesModal.ts
@@ -109,6 +109,7 @@ export class ModifiedFilesModal extends Modal {
cls: "deletedFilesSectionHeader",
});
sectionContainer.createEl("p", {
+ // eslint-disable-next-line obsidianmd/ui/sentence-case
text: "NOTE : Renamed files are little difficult to find. So if you see a lot of files here, it will be good idea to run the vault scan to re-build the cache.",
});
diff --git a/src/modals/ScanFilterModal.ts b/src/modals/ScanFilterModal.ts
index 84feebd3..3938bc3f 100644
--- a/src/modals/ScanFilterModal.ts
+++ b/src/modals/ScanFilterModal.ts
@@ -115,7 +115,7 @@ export class ScanFilterModal extends Modal {
}
this.selectedValues.forEach((value) => {
- const itemEl = listEl!.createDiv("scan-filter-item");
+ const itemEl = listEl.createDiv("scan-filter-item");
itemEl.setText(value);
const removeBtn = itemEl.createEl("button", {
text: "Remove",
diff --git a/src/modals/ScanVaultModal.tsx b/src/modals/ScanVaultModal.tsx
index 8884037b..e859abb6 100644
--- a/src/modals/ScanVaultModal.tsx
+++ b/src/modals/ScanVaultModal.tsx
@@ -21,7 +21,7 @@ export const findMaxIdCounterAndUpdateSettings = (plugin: TaskBoard) => {
// Check Pending tasks
Object.values(plugin.vaultScanner.tasksCache.Pending).forEach((tasks) => {
tasks.forEach((task) => {
- const taskIdNum = task.legacyId ? parseInt(task.legacyId as unknown as string, 10) : 0;
+ const taskIdNum = task.legacyId ? parseInt(task.legacyId, 10) : 0;
if (!isNaN(taskIdNum) && taskIdNum > maxId) {
maxId = taskIdNum;
}
@@ -31,7 +31,7 @@ export const findMaxIdCounterAndUpdateSettings = (plugin: TaskBoard) => {
// Check Completed tasks
Object.values(plugin.vaultScanner.tasksCache.Completed).forEach((tasks) => {
tasks.forEach((task) => {
- const taskIdNum = task.legacyId ? parseInt(task.legacyId as unknown as string, 10) : 0;
+ const taskIdNum = task.legacyId ? parseInt(task.legacyId, 10) : 0;
if (!isNaN(taskIdNum) && taskIdNum > maxId) {
maxId = taskIdNum;
}
@@ -40,7 +40,7 @@ export const findMaxIdCounterAndUpdateSettings = (plugin: TaskBoard) => {
// Update the uniqueIdCounter in settings to be one more than the max found ID
plugin.settings.data.uniqueIdCounter = maxId + 1;
- plugin.saveSettings();
+ void plugin.saveSettings();
}
const ScanVaultModalContent: React.FC<{ app: App, plugin: TaskBoard, vaultScanner: VaultScanner }> = ({ app, plugin, vaultScanner }) => {
@@ -97,8 +97,8 @@ const ScanVaultModalContent: React.FC<{ app: App, plugin: TaskBoard, vaultScanne
findMaxIdCounterAndUpdateSettings(plugin);
// If mandatory scan, close all existing Task Board views to force re-opening with the newly scanned data. Else, just emit REFRESH_BOARD event to update the existing board(s) with the newly scanned data.
- if (localStorage.getItem(MANDATORY_SCAN_KEY) === "true") {
- localStorage.setItem(MANDATORY_SCAN_KEY, "false");
+ if (plugin.app.loadLocalStorage(MANDATORY_SCAN_KEY) === "true") {
+ plugin.app.saveLocalStorage(MANDATORY_SCAN_KEY, "false");
plugin.app.workspace.getLeavesOfType(VIEW_TYPE_TASKBOARD).forEach((leaf) => {
leaf.detach();
});
@@ -115,7 +115,8 @@ const ScanVaultModalContent: React.FC<{ app: App, plugin: TaskBoard, vaultScanne
const componentRef = useRef
(null);
useEffect(() => {
// Initialize Obsidian Component on mount
- componentRef.current = plugin.view;
+ // componentRef.current = plugin.view;
+ componentRef.current = new Component();
}, []);
const taskRendererRef = useRef<{ [key: string]: HTMLDivElement | null }>({});
@@ -135,7 +136,7 @@ const ScanVaultModalContent: React.FC<{ app: App, plugin: TaskBoard, vaultScanne
priority: task.priority,
};
- getFormattedTaskContent(newTaskContent).then((formatedContent) => {
+ void getFormattedTaskContent(newTaskContent).then((formatedContent) => {
const uniqueKey = `${filePath}-task-${taskIndex}`;
const descElement = taskRendererRef.current[uniqueKey];
@@ -143,7 +144,7 @@ const ScanVaultModalContent: React.FC<{ app: App, plugin: TaskBoard, vaultScanne
if (descElement && formatedContent !== "") {
descElement.empty();
// Render task description using MarkdownUIRenderer
- MarkdownUIRenderer.renderTaskDisc(
+ void MarkdownUIRenderer.strictRender(
app,
formatedContent,
descElement,
@@ -160,7 +161,7 @@ const ScanVaultModalContent: React.FC<{ app: App, plugin: TaskBoard, vaultScanne
return (
{t("vault-scanner")}
- {localStorage.getItem(MANDATORY_SCAN_KEY) === "true" ?
+ {plugin.app.loadLocalStorage(MANDATORY_SCAN_KEY) === "true" ?
(<>
{t("scan-vault-from-the-vault-upgrade-message-1")} {CURRENT_PLUGIN_VERSION}
{t("scan-vault-from-the-vault-upgrade-message-2")}
@@ -178,7 +179,7 @@ const ScanVaultModalContent: React.FC<{ app: App, plugin: TaskBoard, vaultScanne
-
@@ -200,7 +201,7 @@ const ScanVaultModalContent: React.FC<{ app: App, plugin: TaskBoard, vaultScanne
{filePath}
- {collectedTasks.Pending[filePath].map((task: any, taskIndex: number) => {
+ {collectedTasks.Pending[filePath].map((task: unknown, taskIndex: number) => {
const uniqueKey = `${filePath}-task-${taskIndex}`;
return (
diff --git a/src/modals/SwimlanesConfigModal.tsx b/src/modals/SwimlanesConfigModal.tsx
index beae984a..2f651f1d 100644
--- a/src/modals/SwimlanesConfigModal.tsx
+++ b/src/modals/SwimlanesConfigModal.tsx
@@ -32,7 +32,7 @@ export class SwimlanesConfigModal extends Modal {
private customSortOrder: { value: string; index: number }[];
private maxHeight: string;
private groupAllRest: boolean;
- private headerUIType: string;
+ private headerUIType: HeaderUITypeOptions;
private sortableInstance: Sortable | null = null;
private sortableListEl: HTMLElement | null = null;
@@ -498,7 +498,7 @@ export class SwimlanesConfigModal extends Modal {
.addToggle((toggle) =>
toggle
.setValue(this.hideEmptySwimlanes)
- .onChange(async (value) => {
+ .onChange((value) => {
this.hideEmptySwimlanes = value;
this.edited = true;
}),)
@@ -519,9 +519,9 @@ export class SwimlanesConfigModal extends Modal {
});
dropdown
.setValue(this.headerUIType)
- .onChange(async (value) => {
+ .onChange((value) => {
this.headerUIType =
- value;
+ value as HeaderUITypeOptions;
this.edited = true;
})
});
diff --git a/src/modals/TaskBoardActionsModal.ts b/src/modals/TaskBoardActionsModal.ts
index 19b073ff..3b692b69 100644
--- a/src/modals/TaskBoardActionsModal.ts
+++ b/src/modals/TaskBoardActionsModal.ts
@@ -18,7 +18,7 @@ export class TaskBoardActionsModal extends Modal {
super(plugin.app);
this.plugin = plugin;
this.columns = columns;
- this.setTitle("Task Board Actions");
+ this.setTitle("Task board actions");
}
onOpen() {
@@ -30,7 +30,7 @@ export class TaskBoardActionsModal extends Modal {
// Header
const header = contentEl.createDiv({ cls: "taskboard-actions-header" });
- header.createEl("h2", { text: "Active Actions" });
+ header.createEl("h2", { text: "Active actions" });
const addBtn = header.createEl("button", {
text: "Add action",
@@ -44,7 +44,7 @@ export class TaskBoardActionsModal extends Modal {
targetColumn: this.columns[0].name || "",
};
this.plugin.settings.data.actions.push(newAction);
- this.plugin.saveSettings();
+ void this.plugin.saveSettings();
this.refresh();
};
@@ -54,7 +54,7 @@ export class TaskBoardActionsModal extends Modal {
});
const inactiveSection = contentEl.createDiv();
inactiveSection.createEl("h2", {
- text: "Inactive Actions",
+ text: "Inactive actions",
cls: "taskboard-inactive-actions-section",
});
@@ -62,8 +62,7 @@ export class TaskBoardActionsModal extends Modal {
cls: "taskboard-actions-modal-list",
});
- const actions: TaskBoardAction[] =
- this.plugin.settings.data.actions;
+ const actions: TaskBoardAction[] = this.plugin.settings.data.actions;
for (let i = 0; i < actions.length; i++) {
const action = actions[i];
@@ -79,7 +78,7 @@ export class TaskBoardActionsModal extends Modal {
toggle.setValue(action.enabled);
toggle.onChange((val) => {
action.enabled = val;
- this.plugin.saveSettings();
+ void this.plugin.saveSettings();
this.refresh();
});
@@ -90,7 +89,7 @@ export class TaskBoardActionsModal extends Modal {
.setValue(action.trigger)
.onChange((val) => {
action.trigger = val as "Complete" | "Incomplete";
- this.plugin.saveSettings();
+ void this.plugin.saveSettings();
});
new DropdownComponent(container)
@@ -98,7 +97,7 @@ export class TaskBoardActionsModal extends Modal {
.setValue(action.type)
.onChange((val) => {
action.type = val as "move" | "copy";
- this.plugin.saveSettings();
+ void this.plugin.saveSettings();
});
container.createSpan({ text: "the card to" });
@@ -106,24 +105,21 @@ export class TaskBoardActionsModal extends Modal {
new DropdownComponent(container)
.addOptions(
Object.fromEntries(
- this.columns.map((c) => [c.index, c.name || ""])
- )
+ this.columns.map((c) => [c.index, c.name || ""]),
+ ),
)
.setValue(action.targetColumn)
.onChange((val) => {
action.targetColumn = val;
- this.plugin.saveSettings();
+ void this.plugin.saveSettings();
});
new ButtonComponent(container)
.setIcon("trash")
- .setTooltip("Delete Action")
+ .setTooltip("Delete action")
.onClick(() => {
- this.plugin.settings.data.actions.splice(
- i,
- 1
- );
- this.plugin.saveSettings();
+ this.plugin.settings.data.actions.splice(i, 1);
+ void this.plugin.saveSettings();
this.refresh();
});
}
diff --git a/src/modals/TaskEditorModal.tsx b/src/modals/TaskEditorModal.tsx
index 34709d41..44ae2fa1 100644
--- a/src/modals/TaskEditorModal.tsx
+++ b/src/modals/TaskEditorModal.tsx
@@ -25,13 +25,13 @@ export class TaskEditorModal extends Modal {
isEdited: boolean;
isTaskNote: boolean;
activeNote: boolean;
- saveTask: (updatedTask: taskItem, quickAddPluginChoice: string, updatedNoteContent?: string) => void;
+ saveTask: (updatedTask: taskItem, quickAddPluginChoice: string, updatedNoteContent?: string) => Promise
;
public waitForClose: Promise;
private resolvePromise: (input: string) => void = (input: string) => { };
private rejectPromise: (reason?: unknown) => void = (reason?: unknown) => { };
- constructor(plugin: TaskBoard, saveTask: (updatedTask: taskItem, quickAddPluginChoice: string, updatedNoteContent?: string) => void, isTaskNote: boolean, activeNote: boolean, taskExists: boolean, task?: taskItem, filePath?: string) {
+ constructor(plugin: TaskBoard, saveTask: (updatedTask: taskItem, quickAddPluginChoice: string, updatedNoteContent?: string) => Promise, isTaskNote: boolean, activeNote: boolean, taskExists: boolean, task?: taskItem, filePath?: string) {
super(plugin.app);
this.plugin = plugin;
this.filePath = filePath ? filePath : "";
@@ -106,7 +106,7 @@ export class TaskEditorModal extends Modal {
this.isEdited = false;
const formattedContent = await getFormattedTaskContent(updatedTask);
this.resolvePromise(formattedContent);
- this.saveTask(updatedTask, quickAddPluginChoice, updatedNoteContent);
+ void this.saveTask(updatedTask, quickAddPluginChoice, updatedNoteContent);
this.close();
}}
onClose={() => this.close()}
@@ -142,7 +142,6 @@ export class TaskEditorModal extends Modal {
this.handleCloseAttempt();
} else {
this.modalEl.addClass("slide-out");
- sleep(300);
this.resolvePromise("");
this.onClose();
super.close();
diff --git a/src/modals/TextInputModal.ts b/src/modals/TextInputModal.ts
index d8edc03d..81041024 100644
--- a/src/modals/TextInputModal.ts
+++ b/src/modals/TextInputModal.ts
@@ -47,7 +47,7 @@ export class TextInputModal extends Modal {
});
// Focus the input
- setTimeout(() => {
+ window.setTimeout(() => {
this.inputEl.focus();
this.inputEl.select();
}, 100);
diff --git a/src/modals/date_picker/DatePickerComponent.ts b/src/modals/date_picker/DatePickerComponent.ts
index 1649ae4c..93d5092e 100644
--- a/src/modals/date_picker/DatePickerComponent.ts
+++ b/src/modals/date_picker/DatePickerComponent.ts
@@ -221,7 +221,7 @@ export class DatePickerComponent extends Component {
});
// Month/Year display
- const monthYear = header.createDiv({
+ header.createDiv({
cls: "calendar-month-year",
text: format(currentDate, "MMMM yyyy"),
});
diff --git a/src/obsidian_views/Archived_TaskBoardView_TextFileView.tsx b/src/obsidian_views/Archived_TaskBoardView_TextFileView.tsx
deleted file mode 100644
index 933cb12d..00000000
--- a/src/obsidian_views/Archived_TaskBoardView_TextFileView.tsx
+++ /dev/null
@@ -1,421 +0,0 @@
-// src/views/TaskBoardView.tsx
-
-import { TextFileView, Platform, WorkspaceLeaf, ViewStateResult, Notice, Menu } from "obsidian";
-import { Root, createRoot } from "react-dom/client";
-import { StrictMode } from "react";
-import { t } from "i18next";
-import TaskBoard from "../../main.js";
-import TaskBoardViewContainer from "../components/TaskBoardViewContainer.js";
-import { Board, DEFAULT_BOARD } from "../interfaces/BoardConfigs.js";
-import { VIEW_TYPE_TASKBOARD, PENDING_SCAN_FILE_STACK, MANDATORY_SCAN_KEY } from "../interfaces/Constants.js";
-import { TaskBoardIcon, funnelIcon, ScanVaultIcon, RefreshIcon } from "../interfaces/Icons.js";
-import { bugReporterManagerInsatance } from "../managers/BugReporter.js";
-import { eventEmitter } from "../services/EventEmitter.js";
-import { openScanVaultModal, openBoardsExplorerModal } from "../services/OpenModals.js";
-import { generateRandomStringId } from "../utils/TaskItemUtils.js";
-
-export class TaskBoardView extends TextFileView {
- plugin: TaskBoard;
- leaf: WorkspaceLeaf;
- root: Root | null = null;
- private currentFilePath: string = "";
- boardName: string = "No Board Loaded";
- private currentBoard: Board | null = null;
-
- constructor(plugin: TaskBoard, leaf: WorkspaceLeaf) {
- super(leaf);
- this.leaf = leaf;
- this.app = plugin.app;
- this.plugin = plugin;
- // this.boards = [];
- this.icon = TaskBoardIcon;
- }
-
- getViewType() {
- return VIEW_TYPE_TASKBOARD;
- }
-
- getDisplayText() {
- return this.boardName;
- }
-
- setViewData(data: string): void {
- try {
- const board = JSON.parse(data) as Board;
- this.boardName = board.name || "Unnamed Board";
- this.currentBoard = board;
- if (this.file) {
- this.currentFilePath = this.file.path;
- }
- this.renderBoard(board);
- } catch (error) {
- bugReporterManagerInsatance.showNotice(
- 183,
- `Failed to load board from file: ${this.file?.path}`,
- String(error),
- "TaskBoardView.tsx/setViewData"
- );
- this.renderNoBoard();
- }
- }
-
- getViewData(): string {
- return this.currentBoard ? JSON.stringify(this.currentBoard, null, "\t") : "{}";
- }
-
- clear(): void {
- this.root?.unmount();
- this.root = null;
- const container = this.containerEl.children[1] as HTMLElement;
- if (container) {
- container.empty();
- }
- this.currentBoard = null;
- this.boardName = "No Board Loaded";
- }
-
- onPaneMenu(menu: Menu, source: "more-options" | "tab-header" | string): void {
- if (source === "more-options") {
- menu.addItem((item) => {
- item.setTitle(t("quick-actions"));
- item.setIsLabel(true);
- });
- menu.addItem((item) => {
- item.setTitle(t("refresh-the-board"));
- item.setIcon("rotate-cw");
- item.onClick(async () => {
- // refreshBoardButton();
- });
- });
- menu.addItem((item) => {
- item.setTitle(t("show-hide-properties"));
- item.setIcon("list");
- item.onClick(async () => {
- // handlePropertiesBtnClick(event);
- });
- });
- menu.addItem((item) => {
- item.setTitle(t("open-board-filters-modal"));
- item.setIcon(funnelIcon);
- item.onClick(async () => {
- // handleFilterButtonClick(event);
- });
- });
- menu.addItem((item) => {
- item.setTitle(t("open-board-configuration-modal"));
- item.setIcon("settings");
- item.onClick(async () => {
- // openBoardConfigModal(plugin, currentBoardData, (updatedBoard: Board) => {
- // // handleUpdateBoards(plugin, updatedBoards, setCurrentBoardData)
- // // setCurrentBoardData(updatedBoard);
- // this.plugin.taskBoardFileManager.saveBoard(updatedBoard);
- // })
- });
- });
- menu.addItem((item) => {
- item.setTitle(t("scan-vault-modal"));
- item.setIcon(ScanVaultIcon);
- item.onClick(async () => {
- openScanVaultModal(this.plugin);
- });
- });
-
-
- // DEPRECATED : As we are moving the view switching options to the ribbon menu, we will remove these options from the pane menu to avoid confusion for users.
- // menu.addItem((item) => {
- // item.setTitle(t("view-type"));
- // item.setIsLabel(true);
- // });
- // menu.addItem((item) => {
- // item.setTitle(t("kanban-view"));
- // item.setIcon("square-kanban");
- // item.onClick(async () => {
- // eventEmitter.emit("SWITCH_VIEW", 'kanban');
- // });
- // });
- // menu.addItem((item) => {
- // item.setTitle(t("map-view"));
- // item.setIcon("network");
- // item.onClick(async () => {
- // eventEmitter.emit("SWITCH_VIEW", 'map');
- // });
- // });
- }
- }
-
- /**
- * This is called by Obsidian when Obsidian is about to save its state/layout.
- *
- * @returns The state data to be stored inside the workspace.json file inside the
- * Obsidian's config folder. (.obsidian/workspace.json)
- */
- getState() {
- // console.log("Value of currentFilePath : ", this.currentFilePath);
- // Save the current filePath to the workspace state
- return {
- ...super.getState(),
- filePath: this.currentFilePath ?? "",
- };
- }
-
- /**
- * This setState is always called after the onOpen function has finished its work by Obsidian.
- * If the leaf was saved by Obsidian in its workspace.json file previosly,
- * we can get the data in this function through the state param.
- * @param state
- * @param result
- */
- async setState(state: any, result: ViewStateResult): Promise {
- const { filePath } = state;
-
- // Check if a specific .taskboard file was clicked from File Navigator
- const clickedFilePath = (this.leaf as any).taskboardFilePath as string | undefined;
- if (clickedFilePath && typeof clickedFilePath === 'string' && clickedFilePath.endsWith('.taskboard')) {
- // Load and render the clicked file
- const clickedFileData = await this.plugin.taskBoardFileManager.loadBoardUsingPath(clickedFilePath);
- if (clickedFileData) {
- this.currentFilePath = clickedFilePath;
- state = {
- ...state,
- filePath: this.currentFilePath
- };
- this.renderBoard(clickedFileData);
- } else {
- bugReporterManagerInsatance.showNotice(183, `There was an issue with opening the task board file : ${clickedFilePath}`, "clickedFileData is undefined", "TaskBoardView.tsx/onOpen");
- }
- } else {
- if (filePath && typeof filePath === "string") {
- // This will run when an in-active (deffered) leaf will come in focus. Specially happen when Obsidian is opened again and the Task Board leaf was brought in focus.
- const boardData = await this.plugin.taskBoardFileManager.loadBoardUsingPath(
- filePath
- );
- if (boardData) {
- this.currentFilePath = filePath;
- state = {
- ...state,
- filePath: this.currentFilePath
- };
- this.renderBoard(boardData);
- } else {
- bugReporterManagerInsatance.showNotice(
- 183,
- `There was an issue with opening the task board file : ${filePath}`,
- "boardData is undefined",
- "TaskBoardView.tsx/setState"
- );
- }
- }
- else {
- // This will run when user has clicked on the Ribbon icon or running the "Open task board" command.
- // We need to get the last opened board.
- const lastViewedBoardData = await this.plugin.taskBoardFileManager.getLastOpenedBoard();
- if (lastViewedBoardData) {
- // Get the filePath from the registry
- const taskBoardFilesRegistry = this.plugin.settings.data.taskBoardFilesRegistry || {};
- const registryEntries = Object.values(taskBoardFilesRegistry);
-
- if (registryEntries.length > 0) {
- const firstItemFromRegistry = registryEntries[0];
- if (firstItemFromRegistry.filePath) {
- this.currentFilePath = firstItemFromRegistry.filePath;
- state = {
- ...state,
- filePath: this.currentFilePath,
- };
- }
- }
-
- this.renderBoard(lastViewedBoardData);
- } else {
- this.renderNoBoard();
- bugReporterManagerInsatance.addToLogs(185, "There was an issue with opening the last viewed board. lastViewedBoardData is undefined", "TaskBoardView.tsx/onOpen");
- }
-
- }
- }
-
- await super.setState(state, result);
- }
-
- /**
- * This function is ran by Obsidian, whenever a new leaf is created or
- * an in-active leaf is brough to life.
- */
- async onOpen() {
- if (Platform.isMobile) {
- this.addAction(RefreshIcon, t("refresh-board-button"), async () => {
- const fileStackString = localStorage.getItem(PENDING_SCAN_FILE_STACK);
- const fileStack = fileStackString ? JSON.parse(fileStackString) : null;
-
- if (fileStack && fileStack.length > 0) {
- await this.plugin.realTimeScanner.processAllUpdatedFiles();
- }
- eventEmitter.emit("REFRESH_BOARD");
- }).addClass("taskboardRefreshBtn");
- }
-
- const mandatoryScanSignal = localStorage.getItem(MANDATORY_SCAN_KEY) === "true";
-
- if (!Platform.isMobile || mandatoryScanSignal) {
- this.addAction(ScanVaultIcon, t("scan-vault-modal"), () => {
- openScanVaultModal(this.plugin);
- }).addClass("taskboardScanVaultBtn");
- }
-
- if (mandatoryScanSignal) this.highlighgtScanvaultIcon();
- }
-
- async highlighgtScanvaultIcon() {
- const scanVaultIcon = this.containerEl.querySelector(
- ".taskboardScanVaultBtn"
- ) as HTMLElement;
- if (scanVaultIcon) {
- scanVaultIcon.classList.add("highlight");
- setInterval(() => {
- scanVaultIcon.classList.toggle("highlight");
- }, 800); // Toggle highlight class every 500ms for blinking effect
- }
- }
-
- // private async loadBoards() {
- // try {
- // this.boards = await loadBoardsData(this.plugin);
- // } catch (err) {
- // bugReporterManagerInsatance.showNotice(
- // 89,
- // "Failed to load board configurations from data.json",
- // String(err),
- // "TaskBoardView.tsx/loadBoards"
- // );
- // }
- // }
-
- private renderBoard(currentBoardData: Board) {
- this.boardName = currentBoardData.name || "Unnamed Board";
- this.currentBoard = currentBoardData;
- this.root = createRoot(this.containerEl.children[1]);
- this.root.render(
-
-
-
- );
-
- // Signal the workspace to save the updated layout state
- this.app.workspace.requestSaveLayout();
- }
-
- /**
- * This function will render a message to the user when there is no board to show in the view. This can happen when user opens the view for the first time and there is no board created, or when there is an issue with loading the board data.
- * Will show a button to create a new board and to scan the vault when there is no board found.
- **/
- private renderNoBoard() {
- const container = this.containerEl.children[1] as HTMLElement;
- container.empty(); // Clear any previous content
-
- const wrapper = container.createDiv({ cls: "taskboard-no-board-wrapper" });
-
- const content = wrapper.createDiv({ cls: "taskboard-no-board-container" });
-
- // Main message
- content.createEl("h2", {
- text: t("no-board-found"),
- cls: "taskboard-no-board-title",
- });
-
- // Detailed description
- const description = content.createEl("p", {
- cls: "taskboard-no-board-description",
- text: t("no-boards-found-description")
- });
-
- // Action buttons
- const buttonContainer = content.createDiv({
- cls: "taskboard-no-board-buttons",
- });
-
- // Create template board button
- const createBtn = buttonContainer.createEl("button", {
- text: t("create-template-board") || "Create Template Board",
- cls: "taskboard-no-board-create-btn",
- attr: {
- "aria-label": t("create-template-board"),
- },
- });
- createBtn.addEventListener("click", () => {
- this.handleCreateTemplateBoard();
- });
-
- // Scan vault button
- const scanBtn = buttonContainer.createEl("button", {
- text: t("scan-vault-modal") || "Scan Vault",
- cls: "taskboard-no-board-scan-btn",
- attr: {
- "aria-label": t("scan-vault-modal"),
- },
- });
- scanBtn.addEventListener("click", () => {
- openBoardsExplorerModal(this.plugin);
- });
- }
-
- /**
- * Creates a new template board from DEFAULT_BOARD, saves it to disk, and renders it in the current view.
- * Generates a unique ID and file path for the new board.
- */
- private async handleCreateTemplateBoard() {
- try {
- // Generate unique ID and filename for the new template board
- const boardId = generateRandomStringId('board');
- const timestamp = new Date().getTime();
- const filePath = `TaskBoard-Template-${timestamp}.taskboard`;
-
- // Create a deep copy of DEFAULT_BOARD and update its properties
- const newBoard: Board = JSON.parse(JSON.stringify(DEFAULT_BOARD));
- newBoard.id = boardId;
-
- // Save the board to disk
- const saveSuccess = await this.plugin.taskBoardFileManager.createNewBoardFile(
- filePath,
- newBoard,
- );
-
- if (!saveSuccess) {
- bugReporterManagerInsatance.showNotice(
- 187,
- "Failed to create template board",
- "saveBoardToDisk returned false",
- "TaskBoardView.tsx/handleCreateTemplateBoard",
- );
- return;
- }
-
- // Update current file path
- this.currentFilePath = filePath;
-
- // Show success notice
- new Notice(t("board-created-successfully"));
-
- // Render the newly created board
- this.renderBoard(newBoard);
-
- } catch (error) {
- bugReporterManagerInsatance.showNotice(
- 187,
- "Error creating template board",
- String(error),
- "TaskBoardView.tsx/handleCreateTemplateBoard",
- );
- }
- }
-
- async onClose() {
- // Clean up when view is closed
- this.root?.unmount();
- this.plugin.leafIsActive = false;
- // onUnloadSave(this.plugin);
- }
-}
diff --git a/src/obsidian_views/TaskBoardView.tsx b/src/obsidian_views/TaskBoardView.tsx
index b4a6afde..ac9dcb82 100644
--- a/src/obsidian_views/TaskBoardView.tsx
+++ b/src/obsidian_views/TaskBoardView.tsx
@@ -40,7 +40,7 @@ export class TaskBoardView extends ItemView {
return this.boardName;
}
- onPaneMenu(menu: Menu, source: "more-options" | "tab-header" | string): void {
+ onPaneMenu(menu: Menu, source: "more-options" | "tab-header"): void {
if (source === "more-options") {
menu.addItem((item) => {
item.setTitle(t("quick-actions"));
@@ -130,18 +130,18 @@ export class TaskBoardView extends ItemView {
* @param state
* @param result
*/
- async setState(state: any, result: ViewStateResult): Promise {
- const { filePath } = state;
+ async setState(state: unknown, result: ViewStateResult): Promise {
+ const filePath = (state as Record).filePath as string | undefined;
// Check if a specific .taskboard file was clicked from File Navigator
- const clickedFilePath = (this.leaf as any).taskboardFilePath as string | undefined;
+ const clickedFilePath = this.leaf.taskboardFilePath as string | undefined;
if (clickedFilePath && typeof clickedFilePath === 'string' && clickedFilePath.endsWith('.taskboard')) {
// Load and render the clicked file
const clickedFileData = await this.plugin.taskBoardFileManager.loadBoardUsingPath(clickedFilePath);
if (clickedFileData) {
this.currentFilePath = clickedFilePath;
state = {
- ...state,
+ ...(state as Record),
filePath: this.currentFilePath
};
this.renderBoard(clickedFileData);
@@ -157,7 +157,7 @@ export class TaskBoardView extends ItemView {
if (boardData) {
this.currentFilePath = filePath;
state = {
- ...state,
+ ...(state as Record),
filePath: this.currentFilePath
};
this.renderBoard(boardData);
@@ -184,7 +184,7 @@ export class TaskBoardView extends ItemView {
if (firstItemFromRegistry.filePath) {
this.currentFilePath = firstItemFromRegistry.filePath;
state = {
- ...state,
+ ...(state as Record),
filePath: this.currentFilePath,
};
}
@@ -209,8 +209,9 @@ export class TaskBoardView extends ItemView {
async onOpen() {
if (Platform.isMobile) {
this.addAction(RefreshIcon, t("refresh-board-button"), async () => {
- const fileStackString = localStorage.getItem(PENDING_SCAN_FILE_STACK);
- const fileStack = fileStackString ? JSON.parse(fileStackString) : null;
+ const fileStackString = this.app.loadLocalStorage(PENDING_SCAN_FILE_STACK);
+ const parsedData: unknown = JSON.parse(fileStackString as string);
+ const fileStack = fileStackString ? parsedData as string[] : null;
if (fileStack && fileStack.length > 0) {
await this.plugin.realTimeScanner.processAllUpdatedFiles();
@@ -219,7 +220,7 @@ export class TaskBoardView extends ItemView {
}).addClass("taskboardRefreshBtn");
}
- const mandatoryScanSignal = localStorage.getItem(MANDATORY_SCAN_KEY) === "true";
+ const mandatoryScanSignal = this.app.loadLocalStorage(MANDATORY_SCAN_KEY) === "true";
if (!Platform.isMobile || mandatoryScanSignal) {
this.addAction(ScanVaultIcon, t("scan-vault-modal"), () => {
@@ -227,7 +228,7 @@ export class TaskBoardView extends ItemView {
}).addClass("taskboardScanVaultBtn");
}
- if (mandatoryScanSignal) this.highlighgtScanvaultIcon();
+ if (mandatoryScanSignal) void this.highlighgtScanvaultIcon();
}
async highlighgtScanvaultIcon() {
@@ -236,7 +237,7 @@ export class TaskBoardView extends ItemView {
) as HTMLElement;
if (scanVaultIcon) {
scanVaultIcon.classList.add("highlight");
- setInterval(() => {
+ window.setInterval(() => {
scanVaultIcon.classList.toggle("highlight");
}, 800); // Toggle highlight class every 500ms for blinking effect
}
@@ -264,6 +265,7 @@ export class TaskBoardView extends ItemView {
plugin={this.plugin}
currentBoardData={currentBoardData}
currentLeaf={this.leaf}
+ viewId=""
/>
);
@@ -306,26 +308,29 @@ export class TaskBoardView extends ItemView {
// Create path elements
let currentPath = '';
- // Add folder parts
- folderParts.forEach((part, index) => {
- if (part) {
- currentPath += part;
- const folderPath = currentPath;
- const folderSpan = titleContainer.createSpan({ text: part, cls: 'taskboard-path-folder' });
- folderSpan.addEventListener('click', () => {
- const folder = this.app.vault.getAbstractFileByPath(folderPath);
- if (folder instanceof TFolder) {
- revealFileFolderInExplorer(this.plugin, folder);
- }
- });
+ // Add folder parts - Only show if the screen width is sufficiently large
+ // Else will only show the fileName
+ if (this.leaf.width > 500) {
+ folderParts.forEach((part, index) => {
+ if (part) {
+ currentPath += part;
+ const folderPath = currentPath;
+ const folderSpan = titleContainer.createSpan({ text: part, cls: 'taskboard-path-folder' });
+ folderSpan.addEventListener('click', () => {
+ const folder = this.app.vault.getAbstractFileByPath(folderPath);
+ if (folder instanceof TFolder) {
+ revealFileFolderInExplorer(this.plugin, folder);
+ }
+ });
- // Add separator
- if (index < folderParts.length - 1 || fileName) {
- titleContainer.createSpan({ text: '/', cls: 'taskboard-path-separator' });
+ // Add separator
+ if (index < folderParts.length - 1 || fileName) {
+ titleContainer.createSpan({ text: '/', cls: 'taskboard-path-separator' });
+ }
+ currentPath += '/';
}
- currentPath += '/';
- }
- });
+ });
+ }
// Add file name
if (fileName) {
@@ -381,7 +386,7 @@ export class TaskBoardView extends ItemView {
},
});
createBtn.addEventListener("click", () => {
- this.handleCreateTemplateBoard();
+ void this.handleCreateTemplateBoard();
});
// Scan vault button
@@ -409,7 +414,7 @@ export class TaskBoardView extends ItemView {
const filePath = `TaskBoard-Template-${timestamp}.taskboard`;
// Create a deep copy of DEFAULT_BOARD and update its properties
- const newBoard: Board = JSON.parse(JSON.stringify(DEFAULT_BOARD));
+ let newBoard: Board = DEFAULT_BOARD;
newBoard.id = boardId;
// Save the board to disk
@@ -447,6 +452,10 @@ export class TaskBoardView extends ItemView {
}
}
+ onResize(): void {
+ this.renderCustomViewHeader();
+ }
+
async onClose() {
// Clean up when view is closed
this.root?.unmount();
diff --git a/src/obsidian_views/TaskEditorView.tsx b/src/obsidian_views/TaskEditorView.tsx
index 4c1ae452..69c46def 100644
--- a/src/obsidian_views/TaskEditorView.tsx
+++ b/src/obsidian_views/TaskEditorView.tsx
@@ -13,7 +13,6 @@ import { allowedFileExtensionsRegEx } from "../regularExpressions/MiscelleneousR
import { getCurrentLocalDateTimeString } from "../utils/DateTimeCalculations.js";
import { readDataOfVaultFile } from "../utils/MarkdownFileOperations.js";
import { generateTaskId } from "../utils/TaskItemUtils.js";
-import { getFormattedTaskContent } from "../utils/taskLine/TaskContentFormatter.js";
export class TaskEditorView extends ItemView {
@@ -26,13 +25,13 @@ export class TaskEditorView extends ItemView {
isEdited: boolean;
isTaskNote: boolean;
activeNote: boolean;
- saveTask: (updatedTask: taskItem, quickAddPluginChoice: string, updatedNoteContent?: string) => void;
+ saveTask: (updatedTask: taskItem, quickAddPluginChoice: string, updatedNoteContent?: string) => Promise;
constructor(
plugin: TaskBoard,
leaf: WorkspaceLeaf,
viewTypeId: string,
- saveTask: (updatedTask: taskItem, quickAddPluginChoice: string, updatedNoteContent?: string) => void,
+ saveTask: (updatedTask: taskItem, quickAddPluginChoice: string, updatedNoteContent?: string) => Promise,
isTaskNote: boolean,
activeNote: boolean,
taskExists: boolean,
@@ -78,7 +77,7 @@ export class TaskEditorView extends ItemView {
if (this.taskExists) {
const data = await readDataOfVaultFile(this.plugin, this.filePath, true);
- if (data == null) this.onClose();
+ if (data == null) await this.onClose();
else noteContent = data;
if (!this.task.title) this.task.title = this.filePath.split('/').pop()?.replace(allowedFileExtensionsRegEx, "") ?? "";
@@ -112,8 +111,8 @@ export class TaskEditorView extends ItemView {
filePath={this.filePath}
onSave={async (updatedTask: taskItem, quickAddPluginChoice: string, updatedNoteContent?: string) => {
this.isEdited = false;
- const formattedContent = await getFormattedTaskContent(updatedTask);
- this.saveTask(updatedTask, quickAddPluginChoice, updatedNoteContent);
+ // const formattedContent = await getFormattedTaskContent(updatedTask);
+ await this.saveTask(updatedTask, quickAddPluginChoice, updatedNoteContent);
// Close the view leaf
this.app.workspace.detachLeavesOfType(this.viewTypeId);
}}
diff --git a/src/services/CommunityPlugins.ts b/src/services/CommunityPlugins.ts
index e152fa81..7a6d79a4 100644
--- a/src/services/CommunityPlugins.ts
+++ b/src/services/CommunityPlugins.ts
@@ -1,7 +1,17 @@
-import { TFile, TFolder } from "obsidian";
+import { App, Plugin, TFile, TFolder } from "obsidian";
import { TaskBoardSubmodule } from "./subModules.js";
import type TaskBoard from "../../main.js";
+export interface QuickAddPlugin extends Plugin {
+ app: App;
+ api: {
+ executeChoice(
+ choiceName: string,
+ variables?: { [key: string]: unknown },
+ ): Promise;
+ };
+}
+
export class CommunityPlugins extends TaskBoardSubmodule {
get fileExplorerPlugin() {
return this.app.internalPlugins.getEnabledPluginById("file-explorer");
@@ -19,8 +29,8 @@ export class CommunityPlugins extends TaskBoardSubmodule {
return !!this.reminderPlugin;
}
- get quickAddPlugin() {
- return this.app.plugins.plugins["quickadd"] ?? null;
+ get quickAddPlugin(): QuickAddPlugin {
+ return (this.app.plugins.plugins.quickAdd as QuickAddPlugin) ?? null;
}
isQuickAddPluginEnabled() {
@@ -48,10 +58,13 @@ export function isReminderPluginInstalled(plugin: TaskBoard) {
reminderPlugin.isReminderPluginEnabled();
}
-export function revealFileFolderInExplorer(plugin: TaskBoard, abstractFile: TFile | TFolder) {
+export function revealFileFolderInExplorer(
+ plugin: TaskBoard,
+ abstractFile: TFile | TFolder,
+) {
const communityPlugins = new CommunityPlugins(plugin);
- if(communityPlugins.isFileExplorerPluginEnabled()) {
+ if (communityPlugins.isFileExplorerPluginEnabled()) {
communityPlugins.fileExplorerPlugin?.revealInFolder(abstractFile);
}
}
diff --git a/src/services/EventEmitter.ts b/src/services/EventEmitter.ts
index 9041d865..39fe2e0f 100644
--- a/src/services/EventEmitter.ts
+++ b/src/services/EventEmitter.ts
@@ -1,15 +1,19 @@
// /src/services/ EventEmitter.ts
+type EventListener = (data: T) => void;
+
class EventEmitter {
- private events: { [key: string]: Function[] } = Object.create(null);
+ private events: Record>> = {};
private readonly blockedEvents = new Set([
"__proto__",
"constructor",
"prototype",
]);
- // Add an event listener
- on(event: string, listener: Function) {
+ // Keep the listener payload generic at the call site, but store the handler
+ // internally as `unknown` so the event bus remains compatible with the
+ // existing callback signatures used across the plugin.
+ on(event: string, listener: EventListener) {
if (this.blockedEvents.has(event)) {
console.warn(
"[Task Board] [Event Emitter] : Blocked event is registered : ",
@@ -20,11 +24,11 @@ class EventEmitter {
if (!this.events[event]) {
this.events[event] = [];
}
- this.events[event].push(listener);
+ this.events[event].push(listener as EventListener);
}
// Emit an event, calling all listeners
- emit(event: string, data?: any) {
+ emit(event: string, data?: T) {
if (this.blockedEvents.has(event)) {
console.warn(
"[Task Board] [Event Emitter] : Blocked event is emitted : ",
@@ -38,7 +42,7 @@ class EventEmitter {
}
// Remove an event listener
- off(event: string, listener: Function) {
+ off(event: string, listener: EventListener) {
if (this.blockedEvents.has(event)) {
console.warn(
"[Task Board] [Event Emitter] : Blocked event is un-registered : ",
@@ -48,7 +52,8 @@ class EventEmitter {
}
if (this.events[event]) {
this.events[event] = this.events[event].filter(
- (registeredListener) => registeredListener !== listener,
+ (registeredListener) =>
+ registeredListener !== (listener as EventListener),
);
}
}
diff --git a/src/services/FileSystem.ts b/src/services/FileSystem.ts
index c83fdf52..f66774f3 100644
--- a/src/services/FileSystem.ts
+++ b/src/services/FileSystem.ts
@@ -1,13 +1,14 @@
+/* eslint-disable @typescript-eslint/no-unsafe-assignment */
+/* eslint-disable import/no-nodejs-modules */
// import { BlobReader, configure, Reader, ZipReader } from '@zip.js/zip.js';
import type * as NodeFS from "node:fs";
import type * as NodeOS from "node:os";
import type * as NodePath from "node:path";
import type * as NodeUrl from "node:url";
import type * as NodeZlib from "node:zlib";
-import { App, Platform } from "obsidian";
+import { App, Platform, TFile } from "obsidian";
+import { Buffer } from "node:buffer";
-
-import TaskBoard from "../../main.js";
import { bugReporterManagerInsatance } from "../managers/BugReporter.js";
// import { configureWebWorker } from './z-worker-inline';
@@ -73,7 +74,7 @@ export function nodeBufferToArrayBuffer(
}
export class NodePickedFile implements PickedFile {
- readonly type: "file" = "file";
+ readonly type = "file";
readonly filepath: string;
readonly fullpath: string;
@@ -124,7 +125,7 @@ export class NodePickedFile implements PickedFile {
}
export class NodePickedFolder implements PickedFolder {
- readonly type: "folder" = "folder";
+ readonly type = "folder";
readonly filepath: string;
readonly name: string;
@@ -162,7 +163,7 @@ export class NodePickedFolder implements PickedFolder {
}
export class WebPickedFile implements PickedFile {
- readonly type: "file" = "file";
+ readonly type = "file";
readonly file: File;
readonly fullpath: string;
@@ -215,8 +216,9 @@ export class WebPickedFile implements PickedFile {
// return callback(new ZipReader(new BlobReader(this.file)));
// }
+ // Use file.name instead of this.file.toString() to avoid [object Object] default stringification
toString(): string {
- return this.file.toString();
+ return this.file.name;
}
}
@@ -302,7 +304,7 @@ export function splitext(name: string) {
/**
* Checks and creates folders if they are not present.
* Recursively checks each child folder if it exists of not.
- *
+ *
* @param plugin - The plugin's app instance
* @param folderPath - Only the folder path. (Filename should not be present)
* @returns - Void
@@ -328,7 +330,7 @@ export async function createFolderRecursively(
// If a file exists where a folder is expected, report and abort
// (this is unlikely but safer to surface)
// existing.type may not be available in all builds, so just check truthiness and skip create
- if ((existing as any).path && !(existing as any).children) {
+ if (existing.path && existing instanceof TFile) {
bugReporterManagerInsatance.showNotice(
58,
`A file exists where a folder is expected: ${currentPath}`,
diff --git a/src/services/FrontmatterRenderer.ts b/src/services/FrontmatterRenderer.ts
index 4ee4b111..0df2fb30 100644
--- a/src/services/FrontmatterRenderer.ts
+++ b/src/services/FrontmatterRenderer.ts
@@ -10,7 +10,7 @@
* In the current version, this FrontmatterRenderer is using a simple custom styling method to render the properties.
*/
-import { App, Component, Notice, TFile } from "obsidian";
+import { App, Component, Notice, setIcon, TFile } from "obsidian";
import TaskBoard from "../../main.js";
import { extractFrontmatterFromContent } from "../utils/taskNote/FrontmatterOperations.js";
@@ -148,9 +148,17 @@ export class FrontmatterRenderer {
const collapseIcon = header.createSpan({
cls: "taskboard-frontmatter-collapse-icon",
});
- collapseIcon.replaceChildren();
- const collapseIconSVG = ``;
- collapseIcon.insertAdjacentHTML("beforeend", collapseIconSVG);
+ // collapseIcon.replaceChildren();
+ // const collapseIconSVG = ``;
+ // // collapseIcon.insertAdjacentHTML("beforeend", collapseIconSVG);
+ // collapseIcon.appendChild(
+ // createSvg("svg", {
+ // cls: "taskboard-frontmatter-collapse-icon",
+
+ // }),
+ // );
+
+ setIcon(collapseIcon, "chevron-down"); // or 'chevron-up' for expanded state
// Add "Properties" text
header.createSpan({
@@ -174,8 +182,10 @@ export class FrontmatterRenderer {
if (this.isFrontmatterContainerCollapsed) {
propertiesContainer.hide();
collapseIcon.replaceChildren();
- const collapseIconSVG = ``;
- collapseIcon.insertAdjacentHTML("beforeend", collapseIconSVG);
+ // const collapseIconSVG = ``;
+ // // collapseIcon.insertAdjacentHTML("beforeend", collapseIconSVG);
+ // collapseIcon.textContent = collapseIconSVG;
+ setIcon(collapseIcon, "chevron-right");
}
// Render each property using PropertyWidget
@@ -188,14 +198,18 @@ export class FrontmatterRenderer {
if (this.isFrontmatterContainerCollapsed) {
propertiesContainer.hide();
- collapseIcon.replaceChildren();
- const collapseIconSVG = ``;
- collapseIcon.insertAdjacentHTML("beforeend", collapseIconSVG);
+ // collapseIcon.replaceChildren();
+ // const collapseIconSVG = ``;
+ // // collapseIcon.insertAdjacentHTML("beforeend", collapseIconSVG);
+ // collapseIcon.textContent = collapseIconSVG;
+ setIcon(collapseIcon, "chevron-down");
} else {
propertiesContainer.show();
- collapseIcon.replaceChildren();
- const collapseIconSVG = ``;
- collapseIcon.insertAdjacentHTML("beforeend", collapseIconSVG);
+ // collapseIcon.replaceChildren();
+ // const collapseIconSVG = ``;
+ // // collapseIcon.insertAdjacentHTML("beforeend", collapseIconSVG);
+ // collapseIcon.textContent = collapseIconSVG;
+ setIcon(collapseIcon, "chevron-down");
}
frontmatterSection.toggleClass(
@@ -218,7 +232,7 @@ export class FrontmatterRenderer {
*/
private renderProperties(
containerEl: HTMLElement,
- frontmatter: Record,
+ frontmatter: Record,
file?: TFile,
): void {
this.renderPropertiesSimple(containerEl, frontmatter);
@@ -336,7 +350,7 @@ export class FrontmatterRenderer {
*/
private renderPropertiesSimple(
containerEl: HTMLElement,
- frontmatter: Record,
+ frontmatter: Record,
): void {
const propertiesToRender = Object.entries(frontmatter).filter(
([key]) => key !== "position",
@@ -373,7 +387,7 @@ export class FrontmatterRenderer {
*/
private renderPropertyValueSimple(
containerEl: HTMLElement,
- value: any,
+ value: unknown,
): void {
if (Array.isArray(value)) {
const list = containerEl.createEl("ul", {
diff --git a/src/services/MarkdownEditor.ts b/src/services/MarkdownEditor.ts
index 877303e6..00594686 100644
--- a/src/services/MarkdownEditor.ts
+++ b/src/services/MarkdownEditor.ts
@@ -8,14 +8,15 @@
import {
App,
Editor,
+ MarkdownFileInfo,
MarkdownScrollableEditView,
Scope,
TFile,
- WidgetEditorView,
+ Workspace,
WorkspaceLeaf,
} from "obsidian";
-import { EditorSelection, Prec } from "@codemirror/state";
+import { EditorSelection, Prec, Range } from "@codemirror/state";
import {
EditorView,
keymap,
@@ -40,7 +41,7 @@ import { FrontmatterRenderer } from "./FrontmatterRenderer.js";
export function createEmbeddableMarkdownEditor(
plugin: TaskBoard,
container: HTMLElement,
- options: Partial
+ options: Partial,
): EmbeddableMarkdownEditor {
// Get the editor class
const EditorClass = resolveEditorPrototype(plugin.app);
@@ -51,32 +52,35 @@ export function createEmbeddableMarkdownEditor(
plugin.app,
EditorClass,
container,
- options
+ options,
);
}
/**
* Resolves the markdown editor prototype from the app
*/
-function resolveEditorPrototype(app: App): any {
+function resolveEditorPrototype(app: App): unknown {
// Create a temporary editor to resolve the prototype of ScrollableMarkdownEditor
const widgetEditorView = app.embedRegistry.embedByExtension.md(
{ app, containerEl: createDiv() },
+ // eslint-disable-next-line obsidianmd/no-tfile-tfolder-cast -- null TFile needed for API
null as unknown as TFile,
- ""
- ) as WidgetEditorView;
+ "",
+ );
// Mark as editable to instantiate the editor
widgetEditorView.editable = true;
widgetEditorView.showEditor();
+ // Navigate prototype chain to resolve the ScrollableMarkdownEditor constructor
+ const editMode = widgetEditorView.editMode as object;
const MarkdownEditor = Object.getPrototypeOf(
- Object.getPrototypeOf(widgetEditorView.editMode!)
- );
+ Object.getPrototypeOf(editMode),
+ ) as { constructor: unknown };
// Unload to remove the temporary editor
widgetEditorView.unload();
- // Return the constructor, using 'any' type to bypass the abstract class check
+ // Return the constructor, bypassing the abstract class check
return MarkdownEditor.constructor;
}
@@ -87,13 +91,14 @@ interface MarkdownEditorProps {
placeholder?: string;
enableFrontmatterUI?: boolean; // Enable enhanced frontmatter UI
file?: TFile; // Optional file for context in property rendering
+ singleLine?: boolean;
onEnter: (
editor: EmbeddableMarkdownEditor,
mod: boolean,
- shift: boolean
+ shift: boolean,
) => boolean;
- // onEscape: (editor: EmbeddableMarkdownEditor) => void;
+ onEscape?: (editor: EmbeddableMarkdownEditor) => void;
onSubmit: (editor: EmbeddableMarkdownEditor) => void;
onBlur: (editor: EmbeddableMarkdownEditor) => void;
onPaste: (e: ClipboardEvent, editor: EmbeddableMarkdownEditor) => void;
@@ -145,7 +150,7 @@ export class EmbeddableMarkdownEditor {
get app(): App {
return this.editor.app;
}
- get owner(): any {
+ get owner(): unknown {
return this.editor.owner;
}
get _loaded(): boolean {
@@ -162,13 +167,135 @@ export class EmbeddableMarkdownEditor {
constructor(
plugin: TaskBoard,
app: App,
- EditorClass: any,
+ EditorClass: unknown,
container: HTMLElement,
- options: Partial
+ options: Partial,
) {
this.plugin = plugin;
+
+ // Store user options first
+ this.options = { ...defaultProperties, ...options };
+ this.initial_value = this.options.value!;
+ this.scope = new Scope(app.scope);
+
+ // Prevent Mod+Enter default behavior
+ this.scope.register(["Mod"], "Enter", () => true);
+
+ // Store reference to self for the patched method BEFORE using it
+ // eslint-disable-next-line @typescript-eslint/no-this-alias -- needed for monkey-patching context
+ const self = this;
+
+ // Use monkey-around to safely patch the method
+ const uninstaller = around(
+ (EditorClass as { prototype: object }).prototype,
+ {
+ buildLocalExtensions: (originalMethod: unknown) =>
+ function (this: object) {
+ const extensions = (
+ originalMethod as (this: object) => unknown[]
+ ).call(this);
+
+ // Only add our custom extensions if this is our editor instance
+ if (this === self.editor) {
+ // Add placeholder if configured
+ if (self.options.placeholder) {
+ extensions.push(
+ placeholder(self.options.placeholder),
+ );
+ }
+
+ // Add paste, blur, and focus event handlers
+ extensions.push(
+ EditorView.domEventHandlers({
+ paste: (event) => {
+ self.options.onPaste(event, self);
+ },
+ blur: () => {
+ // Always trigger blur callback and let it handle the logic
+ app.keymap.popScope(self.scope);
+ if (self.options.onBlur) {
+ self.options.onBlur(self);
+ }
+ },
+ focusin: () => {
+ app.keymap.pushScope(self.scope);
+ app.workspace.activeEditor =
+ self.owner as MarkdownFileInfo | null;
+ },
+ }),
+ );
+
+ // Add keyboard handlers
+ const keyBindings = [
+ {
+ key: "Enter",
+ run: () => {
+ return self.options.onEnter(
+ self,
+ false,
+ false,
+ );
+ },
+ shift: () =>
+ self.options.onEnter(self, false, true),
+ },
+ {
+ key: "Mod-Enter",
+ run: () =>
+ self.options.onEnter(self, true, false),
+ shift: () =>
+ self.options.onEnter(self, true, true),
+ },
+ {
+ key: "Escape",
+ run: () => {
+ self.options.onEscape?.(self);
+ return true;
+ },
+ preventDefault: true,
+ },
+ ];
+
+ // For single line mode, prevent Enter key from creating new lines
+ if (self.options.singleLine) {
+ keyBindings[0] = {
+ key: "Enter",
+ run: () => {
+ // In single line mode, Enter should trigger onEnter
+ return self.options.onEnter(
+ self,
+ false,
+ false,
+ );
+ },
+ shift: () => {
+ // Even with shift, still call onEnter in single line mode
+ return self.options.onEnter(
+ self,
+ false,
+ true,
+ );
+ },
+ };
+ }
+
+ extensions.push(
+ Prec.highest(keymap.of(keyBindings)),
+ );
+ }
+
+ return extensions;
+ },
+ },
+ );
+ plugin.register(uninstaller);
+
// Create the editor with the app instance
- this.editor = new EditorClass(app, container, {
+ this.editor = new (EditorClass as new (
+ app: App,
+ container: HTMLElement,
+ opts: Record,
+ ) => MarkdownScrollableEditView)(app, container, {
app,
// This mocks the MarkdownView functions, required for proper scrolling
onMarkdownScroll: () => {},
@@ -177,18 +304,14 @@ export class EmbeddableMarkdownEditor {
this.frontmatterRenderer = new FrontmatterRenderer(plugin, this.editor);
- // Store user options
- this.options = { ...defaultProperties, ...options };
- this.initial_value = this.options.value!;
- this.scope = new Scope(app.scope);
-
// Prevent Mod+Enter default behavior
this.scope.register(["Mod"], "Enter", () => true);
// Set up the editor relationship for commands to work
- if (this.owner) {
- this.owner.editMode = this;
- this.owner.editor = this.editor.editor;
+ const ownerRecord = this.owner as Record | undefined;
+ if (ownerRecord) {
+ ownerRecord.editMode = this;
+ ownerRecord.editor = this.editor.editor;
}
// Set initial content
@@ -198,32 +321,48 @@ export class EmbeddableMarkdownEditor {
this.register(
around(app.workspace, {
setActiveLeaf:
- (oldMethod: any) =>
- (leaf: WorkspaceLeaf, ...args: any[]) => {
+ (oldMethod: unknown) =>
+ (leaf: WorkspaceLeaf, ...args: unknown[]) => {
if (!this.activeCM?.hasFocus) {
- oldMethod.call(app.workspace, leaf, ...args);
+ (
+ oldMethod as (
+ this: Workspace,
+ leaf: WorkspaceLeaf,
+ ...args: unknown[]
+ ) => void
+ ).call(app.workspace, leaf, ...args);
}
},
- })
+ }),
);
// Set up blur event handler
+ const contentDOM = (
+ this.editor.editor as unknown as Record
+ )?.cm as Record | undefined;
if (
this.options.onBlur !== defaultProperties.onBlur &&
- this.editor.editor?.cm?.contentDOM
+ contentDOM?.contentDOM
) {
- this.editor.editor.cm.contentDOM.addEventListener("blur", () => {
- app.keymap.popScope(this.scope);
- if (this._loaded) this.options.onBlur(this);
- });
+ (contentDOM.contentDOM as HTMLElement).addEventListener(
+ "blur",
+ () => {
+ app.keymap.popScope(this.scope);
+ if (this._loaded) this.options.onBlur(this);
+ },
+ );
}
// Set up focus event handler
- if (this.editor.editor?.cm?.contentDOM) {
- this.editor.editor.cm.contentDOM.addEventListener("focusin", () => {
- app.keymap.pushScope(this.scope);
- app.workspace.activeEditor = this.owner;
- });
+ if (contentDOM?.contentDOM) {
+ (contentDOM.contentDOM as HTMLElement).addEventListener(
+ "focusin",
+ () => {
+ app.keymap.pushScope(this.scope);
+ app.workspace.activeEditor = this
+ .owner as MarkdownFileInfo | null;
+ },
+ );
}
// Apply custom class if provided
@@ -236,7 +375,7 @@ export class EmbeddableMarkdownEditor {
this.editor.editor.cm.dispatch({
selection: EditorSelection.range(
options.cursorLocation.anchor,
- options.cursorLocation.head
+ options.cursorLocation.head,
),
});
}
@@ -261,7 +400,7 @@ export class EmbeddableMarkdownEditor {
paste: (event) => {
this.options.onPaste(event, this);
},
- })
+ }),
);
// Add keyboard handlers
@@ -287,8 +426,8 @@ export class EmbeddableMarkdownEditor {
// },
// preventDefault: true,
// },
- ])
- )
+ ]),
+ ),
);
return extensions;
@@ -311,15 +450,16 @@ export class EmbeddableMarkdownEditor {
*/
private createFrontmatterHidingExtension() {
// Helper function to build decorations for frontmatter
- const buildDecorations = (state: any): DecorationSet => {
- const decorations: any[] = [];
- const doc = state.doc;
+ const buildDecorations = (state: unknown): DecorationSet => {
+ const decorations: Range[] = [];
+ const editorState = state as { doc: { toString: () => string } };
+ const doc = editorState.doc;
const text = doc.toString();
// Regular expression to match frontmatter blocks
// Matches content that starts with '---' and ends with '---'
const frontmatterRegex = /^---\s*\n([\s\S]*?)\n---\s*$/gm;
- let match;
+ let match: RegExpExecArray | null;
while ((match = frontmatterRegex.exec(text)) !== null) {
const start = match.index;
@@ -332,7 +472,7 @@ export class EmbeddableMarkdownEditor {
attributes: {
style: "display: none;",
},
- }).range(start, end)
+ }).range(start, end),
);
}
@@ -368,7 +508,7 @@ export class EmbeddableMarkdownEditor {
const contentWithoutFrontmatter =
this.frontmatterRenderer.extractContentWithoutFrontmatter(
content,
- frontmatterContent
+ frontmatterContent,
);
this.editor.set(contentWithoutFrontmatter, focus);
@@ -399,7 +539,7 @@ export class EmbeddableMarkdownEditor {
// Find or create a wrapper in the container
// We'll prepend the frontmatter UI to the container
const wrapper = this.containerEl.querySelector(
- ".taskboard-frontmatter-wrapper"
+ ".taskboard-frontmatter-wrapper",
) as HTMLElement;
if (!wrapper) {
@@ -411,7 +551,7 @@ export class EmbeddableMarkdownEditor {
// Insert at the beginning of the container
this.containerEl.insertBefore(
this.frontmatterUIContainer,
- this.containerEl.firstChild
+ this.containerEl.firstChild,
);
} else {
this.frontmatterUIContainer = wrapper;
@@ -422,7 +562,7 @@ export class EmbeddableMarkdownEditor {
const result = this.frontmatterRenderer.renderCollapsibleFrontmatter(
this.frontmatterUIContainer,
content,
- this.options.file
+ this.options.file,
);
// If no frontmatter was rendered, remove the container
@@ -433,8 +573,8 @@ export class EmbeddableMarkdownEditor {
}
// Register cleanup callback
- register(cb: any): void {
- this.editor.register(cb);
+ register(cb: unknown): void {
+ this.editor.register(cb as () => unknown);
}
// Clean up method that ensures proper destruction
diff --git a/src/services/MarkdownHoverPreview.ts b/src/services/MarkdownHoverPreview.ts
index 2cbbf33f..a4b7aad5 100644
--- a/src/services/MarkdownHoverPreview.ts
+++ b/src/services/MarkdownHoverPreview.ts
@@ -8,7 +8,7 @@ export function hookMarkdownLinkMouseEventHandlers(
plugin: TaskBoard,
containerEl: HTMLElement,
sourcePath: string,
- filePath: string
+ filePath: string,
) {
containerEl
.querySelectorAll("a.internal-link")
@@ -18,10 +18,10 @@ export function hookMarkdownLinkMouseEventHandlers(
evt.preventDefault();
const linktext = el.getAttribute("href");
if (linktext) {
- app.workspace.openLinkText(
+ void app.workspace.openLinkText(
linktext,
sourcePath,
- Keymap.isModEvent(evt)
+ Keymap.isModEvent(evt),
);
}
});
@@ -47,7 +47,7 @@ export function hookMarkdownLinkMouseEventHandlers(
export function markdownButtonHoverPreviewEvent(
app: App,
event: React.MouseEvent,
- filePath: string
+ filePath: string,
) {
app.workspace.trigger("hover-link", {
event,
diff --git a/src/services/MarkdownUIRenderer.ts b/src/services/MarkdownUIRenderer.ts
index 0a1610fe..a526c8bb 100644
--- a/src/services/MarkdownUIRenderer.ts
+++ b/src/services/MarkdownUIRenderer.ts
@@ -33,13 +33,12 @@ export function createAndAppendElement(
// so had to convert all of these to the equivalent but more elaborate document.createElement() and
// appendChild() calls.
- const el: HTMLElementTagNameMap[K] = document.createElement(tagName);
+ const el: HTMLElementTagNameMap[K] = activeDocument.createElement(tagName);
parentElement.appendChild(el);
return el;
}
export class MarkdownUIRenderer {
- private readonly textRenderer: TextRenderer;
private readonly obsidianComponent: Component | null;
private readonly parentUlElement: HTMLElement;
// private readonly taskLayoutOptions: TaskLayoutOptions;
@@ -55,6 +54,7 @@ export class MarkdownUIRenderer {
if (!obsidianComponent) {
return;
}
+
await MarkdownRenderer.render(
app,
text,
@@ -76,7 +76,6 @@ export class MarkdownUIRenderer {
* @param parentUlElement HTML element where the task shall be rendered.
*/
constructor({
- textRenderer = MarkdownUIRenderer.obsidianMarkdownRenderer,
obsidianComponent,
parentUlElement,
}: {
@@ -84,12 +83,11 @@ export class MarkdownUIRenderer {
obsidianComponent: Component | null;
parentUlElement: HTMLElement;
}) {
- this.textRenderer = textRenderer;
this.obsidianComponent = obsidianComponent;
this.parentUlElement = parentUlElement;
}
- public static async renderTaskDisc(
+ public static async strictRender(
app: App,
taskDescText: string,
element: HTMLDivElement,
@@ -111,7 +109,7 @@ export class MarkdownUIRenderer {
);
}
- static async renderSubtaskText(
+ public static async safeRender(
app: App,
subtaskText: string,
el: HTMLElement,
@@ -119,11 +117,11 @@ export class MarkdownUIRenderer {
taskItemComponent: Component | null,
) {
try {
- // console.log("renderSubtaskText : Received following text : ", subtaskText);
+ // console.log("safeRender : Received following text : ", subtaskText);
let componentEl = taskItemComponent ?? new Component();
- if (!componentEl) {
- return;
- }
+ // if (!componentEl) {
+ // return;
+ // }
el.replaceChildren();
@@ -139,7 +137,7 @@ export class MarkdownUIRenderer {
bugReporterManagerInsatance.addToLogs(
102,
String(error),
- "MarkdownUIRenderer.ts/MarkdownUIRenderer.renderSubtaskText",
+ "MarkdownUIRenderer.ts/MarkdownUIRenderer.safeRender",
);
}
}
diff --git a/src/services/MultiSuggest.ts b/src/services/MultiSuggest.ts
index 708a67ed..31a448de 100644
--- a/src/services/MultiSuggest.ts
+++ b/src/services/MultiSuggest.ts
@@ -85,9 +85,15 @@ export function getTagSuggestions(app: App): string[] {
return tagsArray;
}
+// Define expected shape of QuickAdd plugin choices for type safety
+interface QuickAddChoice {
+ type: string;
+ name: string;
+}
+
export function getQuickAddPluginChoices(
app: App,
- quickAddPluginObj: any,
+ quickAddPluginObj: unknown,
): string[] {
try {
if (!quickAddPluginObj) {
@@ -96,7 +102,8 @@ export function getQuickAddPluginChoices(
const quickAddPlugin = app.plugins.getPlugin("quickadd");
if (!quickAddPlugin) return [];
- const choices = quickAddPluginObj.settings.choices;
+ const settings = (quickAddPluginObj as Record).settings as Record;
+ const choices = settings.choices as Record;
return Object.keys(choices)
.filter((key) => choices[key].type === "Capture")
@@ -141,18 +148,15 @@ export function getYAMLPropertySuggestions(app: App): string[] {
const metadata = app.metadataCache.getFileCache(file);
if (metadata && metadata.frontmatter) {
// console.log("Frontmatter:", metadata.frontmatter, "\nFile:", file.path);
- Object.keys(metadata.frontmatter).forEach((key) => {
- const value = metadata.frontmatter
- ? metadata.frontmatter[key]
- : null;
- if (Array.isArray(value)) {
- value.forEach((val) => {
- yamlPropertiesSet.add(`["${key}": ${val}]`);
- });
- } else {
- yamlPropertiesSet.add(`["${key}": ${value}]`);
- }
+ // metadata.frontmatter values are unknown; cast safely for template literals
+ Object.keys(metadata.frontmatter).forEach((key) => {
+ // Cast frontmatter to avoid any-typed access from Obsidian's API
+ const raw = (metadata.frontmatter as Record)?.[key];
+ const values = Array.isArray(raw) ? raw : [raw];
+ values.forEach((val) => {
+ yamlPropertiesSet.add(`["${key}": ${String(val)}]`);
});
+ });
}
}
});
diff --git a/src/services/ObsidianDebugInfo.ts b/src/services/ObsidianDebugInfo.ts
index a9f71cc0..1b8e82f6 100644
--- a/src/services/ObsidianDebugInfo.ts
+++ b/src/services/ObsidianDebugInfo.ts
@@ -16,8 +16,8 @@ export async function getObsidianDebugInfo(app: App) {
// This is an empty string if it's the default theme
const themeName = app.customCss.theme;
const themeManifest = app.customCss.themes[themeName];
- const numSnippets = app.customCss.snippets.filter((snippet: any) =>
- app.customCss.enabledSnippets.has(snippet)
+ const numSnippets = app.customCss.snippets.filter((snippet: unknown) =>
+ app.customCss.enabledSnippets.has(String(snippet)),
).length;
const plugins = app.plugins.plugins;
@@ -27,7 +27,7 @@ export async function getObsidianDebugInfo(app: App) {
"Use [[Wikilinks]]": !app.vault.getConfig("useMarkdownLinks"),
// This entry is not in Obsidian's built-in "Show debug info" command.
// It replaces the "Base theme" entry for identifying the color scheme even if it's set to be "adapt to system"
- "Base color scheme": document.body.hasClass("theme-dark")
+ "Base color scheme": activeDocument.body.hasClass("theme-dark")
? "dark"
: "light",
// This entry is not in Obsidian's built-in "Show debug info" command
@@ -38,39 +38,66 @@ export async function getObsidianDebugInfo(app: App) {
"Snippets enabled": numSnippets,
"Plugins installed": Object.keys(app.plugins.manifests).length,
"Plugins enabled": Object.values(plugins).map(
- (plugin) => `${plugin!.manifest.name} v${plugin!.manifest.version}`
+ (plugin) => `${plugin.manifest.name} v${plugin.manifest.version}`,
),
};
}
-export async function getWebViewVersion() {
+// Capacitor plugins return untyped results; use a concise interface for the shape we access
+interface CapacitorDeviceInfo {
+ webViewVersion?: string;
+ platform?: string;
+ osVersion?: string;
+ manufacturer?: string;
+ model?: string;
+}
+interface CapacitorAppInfo {
+ version?: string;
+ build?: string;
+}
+
+export async function getWebViewVersion(): Promise {
if (!Platform.isMobileApp) {
return null;
}
- const deviceInfo = await window.Capacitor.Plugins.Device.getInfo();
- return deviceInfo.webViewVersion;
+ const plugins = (window.Capacitor as Record)
+ .Plugins as Record;
+ const deviceInfo = await (
+ plugins.Device as { getInfo: () => Promise }
+ ).getInfo();
+ return deviceInfo.webViewVersion ?? null;
}
/**
* Get the information about the Obsidian app and the system.
* This is the same as the "SYSTEM INFO" section in the result of the "Show debug info" command.
*/
-export async function getSystemInfo(): Promise {
+export async function getSystemInfo(): Promise> {
if (window.electron) {
- // eslint-disable-next-line @typescript-eslint/no-require-imports
+ // eslint-disable-next-line @typescript-eslint/no-require-imports, import/no-nodejs-modules, no-undef
const os = require("os") as typeof import("os");
+ const electron = window.electron;
+ const ipcRenderer = electron.ipcRenderer as {
+ sendSync: (channel: string) => string;
+ };
+ const remote = electron.remote as { app: { getVersion: () => string } };
return {
- "Obsidian version": window.electron.ipcRenderer.sendSync("version"),
- // @ts-ignore
- "Installer version": window.electron.remote.app.getVersion(),
+ "Obsidian version": ipcRenderer.sendSync("version"),
+ "Installer version": remote.app.getVersion(),
"Operating system": os.version() + " " + os.release(),
};
}
- const appInfo = await window.Capacitor.Plugins.App.getInfo();
- const deviceInfo = await window.Capacitor.Plugins.Device.getInfo();
- const info: any = {
+ const apps = (window.Capacitor as Record)
+ .Plugins as Record;
+ const appInfo = await (
+ apps.App as { getInfo: () => Promise }
+ ).getInfo();
+ const deviceInfo = await (
+ apps.Device as { getInfo: () => Promise }
+ ).getInfo();
+ const info: Record = {
"Obsidian version": `${appInfo.version} (${appInfo.build})`,
"API version": apiVersion,
"Operating system": `${deviceInfo.platform} ${deviceInfo.osVersion} (${deviceInfo.manufacturer} ${deviceInfo.model})`,
diff --git a/src/services/OpenModals.ts b/src/services/OpenModals.ts
index 2a1d658a..6b301273 100644
--- a/src/services/OpenModals.ts
+++ b/src/services/OpenModals.ts
@@ -71,16 +71,22 @@ export const openAddNewTaskInCurrentFileModal = (
app: App,
plugin: TaskBoard,
activeFile: TFile,
- cursorPosition?: { line: number; ch: number } | undefined,
+ cursorPosition?: { line: number; ch: number },
) => {
const AddTaskModal = new TaskEditorModal(
plugin,
- (newTask: taskItem, quickAddPluginChoice: string) => {
- addTaskInNote(plugin, newTask, true, cursorPosition).then(
+ async (newTask: taskItem, quickAddPluginChoice: string) => {
+ void addTaskInNote(plugin, newTask, true, cursorPosition).then(
(newId) => {
- plugin.realTimeScanner.processAllUpdatedFiles(
- newTask.filePath,
- );
+ plugin.realTimeScanner
+ .processAllUpdatedFiles(newTask.filePath)
+ .catch((error) => {
+ bugReporterManagerInsatance.addToLogs(
+ 217,
+ String(error),
+ "OpenModals.ts/openAddNewTaskInCurrentFileModal",
+ );
+ });
},
);
@@ -96,7 +102,6 @@ export const openAddNewTaskInCurrentFileModal = (
// @todo - I dont think I need to emit this here, since the processAllUpdatedFiles function will refresh the file and then it will emit this same signal anyways. And, until that, we dont have to refresh the view at all.
eventEmitter.emit("SOFT_REFRESH");
cursorPosition = undefined;
- return true;
},
false,
true,
@@ -120,11 +125,13 @@ export const openAddNewTaskModal = (plugin: TaskBoard, activeFile?: TFile) => {
if (communityPlugins.isQuickAddPluginIntegrationEnabled()) {
// Call the API of QuickAdd plugin and pass the formatted content.
let completeTask = await getFormattedTaskContent(newTask);
- const { formattedTaskContent, newId } =
- await addIdToTaskContent(plugin, completeTask);
+ const { formattedTaskContent } = await addIdToTaskContent(
+ plugin,
+ completeTask,
+ );
completeTask = formattedTaskContent;
- (communityPlugins.quickAddPlugin as any)?.api.executeChoice(
+ await communityPlugins.quickAddPlugin?.api.executeChoice(
quickAddPluginChoice,
{
value: completeTask + "\n",
@@ -132,9 +139,15 @@ export const openAddNewTaskModal = (plugin: TaskBoard, activeFile?: TFile) => {
);
} else {
await addTaskInNote(plugin, newTask, false).then((newId) => {
- plugin.realTimeScanner.processAllUpdatedFiles(
- newTask.filePath,
- );
+ plugin.realTimeScanner
+ .processAllUpdatedFiles(newTask.filePath)
+ .catch((error) => {
+ bugReporterManagerInsatance.addToLogs(
+ 217,
+ String(error),
+ "OpenModals.ts/openAddNewTaskModal",
+ );
+ });
});
}
@@ -167,7 +180,7 @@ export const openAddNewTaskNoteModal = (app: App, plugin: TaskBoard) => {
async (
newTask: taskItem,
quickAddPluginChoice: string,
- noteContent: string | undefined,
+ noteContent?: string,
) => {
if (!noteContent) {
bugReporterManagerInsatance.showNotice(
@@ -201,7 +214,7 @@ export const openAddNewTaskNoteModal = (app: App, plugin: TaskBoard) => {
}
// Required for Obsidian to create the folder and index it.
- sleep(200);
+ await sleep(200);
}
await plugin.app.vault
@@ -211,10 +224,18 @@ export const openAddNewTaskNoteModal = (app: App, plugin: TaskBoard) => {
plugin.realTimeScanner.onFileModified(
newTask.filePath,
);
- sleep(1000).then(() => {
+ window.setTimeout(() => {
// TODO : Is 1 seconds really required ?
- plugin.realTimeScanner.processAllUpdatedFiles();
- });
+ plugin.realTimeScanner
+ .processAllUpdatedFiles()
+ .catch((error) => {
+ bugReporterManagerInsatance.addToLogs(
+ 217,
+ String(error),
+ "OpenModals.ts/openAddNewTaskNoteModal",
+ );
+ });
+ }, 1000);
});
} else {
const newName = getCurrentLocalDateTimeString();
@@ -238,9 +259,18 @@ export const openAddNewTaskNoteModal = (app: App, plugin: TaskBoard) => {
plugin.realTimeScanner.onFileModified(
`Copy-${newTask.filePath}`,
);
- sleep(1000).then(() => {
- plugin.realTimeScanner.processAllUpdatedFiles();
- });
+
+ window.setTimeout(() => {
+ plugin.realTimeScanner
+ .processAllUpdatedFiles()
+ .catch((error) => {
+ bugReporterManagerInsatance.addToLogs(
+ 217,
+ String(error),
+ "OpenModals.ts/openAddNewTaskNoteModal",
+ );
+ });
+ }, 1000);
});
}
} catch (error) {
@@ -250,7 +280,6 @@ export const openAddNewTaskNoteModal = (app: App, plugin: TaskBoard) => {
"OpenModals.ts/openAddNewTaskNoteModal/callback()",
);
new Notice(t("error-creating-task-note"), 5000);
- return false;
}
}
@@ -266,13 +295,13 @@ export const openAddNewTaskNoteModal = (app: App, plugin: TaskBoard) => {
AddTaskModal.open();
};
-export const openEditTaskModal = async (
+export const openEditTaskModal = (
plugin: TaskBoard,
existingTask: taskItem,
) => {
const EditTaskModal = new TaskEditorModal(
plugin,
- (updatedTask: taskItem) => {
+ async (updatedTask: taskItem) => {
let eventData: UpdateTaskEventData = {
taskID: existingTask.id,
state: true,
@@ -281,14 +310,24 @@ export const openEditTaskModal = async (
updatedTask.filePath = existingTask.filePath;
// Update the task in the file and JSON
- updateTaskInFile(plugin, updatedTask, existingTask).then(
- (newId) => {
- plugin.realTimeScanner.processAllUpdatedFiles(
- updatedTask.filePath,
- existingTask.id,
- );
- },
- );
+ updateTaskInFile(plugin, updatedTask, existingTask)
+ .then((newId) => {
+ plugin.realTimeScanner
+ .processAllUpdatedFiles(
+ updatedTask.filePath,
+ existingTask.id,
+ )
+ .catch((error) => {
+ bugReporterManagerInsatance.addToLogs(
+ 217,
+ String(error),
+ "OpenModals.ts/openEditTaskModal",
+ );
+ });
+ })
+ .catch((error) => {
+ // No need to handle here, the function already handles this.
+ });
// DEPRECATED : See notes from //src/utils/TaskItemCacheOperations.ts file
// updateTaskInJson(plugin, updatedTask);
@@ -332,29 +371,45 @@ export const openEditTaskNoteModal = (
plugin,
updatedTask,
).then(() => {
- sleep(1000).then(() => {
+ window.setTimeout(() => {
// TODO : Is 1 sec really required ?
// This is required to rescan the updated file and refresh the board.
- plugin.realTimeScanner.processAllUpdatedFiles(
- updatedTask.filePath,
- existingTask.id,
- );
- });
+ plugin.realTimeScanner
+ .processAllUpdatedFiles(
+ updatedTask.filePath,
+ existingTask.id,
+ )
+ .catch((error) => {
+ bugReporterManagerInsatance.addToLogs(
+ 217,
+ String(error),
+ "OpenModals.ts/openEditTaskNoteModal",
+ );
+ });
+ }, 1000);
});
} else {
- writeDataToVaultFile(
+ await writeDataToVaultFile(
plugin,
updatedTask.filePath,
newTaskContent,
).then(() => {
- sleep(1000).then(() => {
+ window.setTimeout(() => {
// TODO : Is 1 sec really required ?
// This is required to rescan the updated file and refresh the board.
- plugin.realTimeScanner.processAllUpdatedFiles(
- updatedTask.filePath,
- existingTask.id,
- );
- });
+ plugin.realTimeScanner
+ .processAllUpdatedFiles(
+ updatedTask.filePath,
+ existingTask.id,
+ )
+ .catch((error) => {
+ bugReporterManagerInsatance.addToLogs(
+ 217,
+ String(error),
+ "OpenModals.ts/openEditTaskNoteModal",
+ );
+ });
+ }, 1000);
});
}
@@ -561,7 +616,7 @@ export const openScanFiltersModal = (
filterType: keyof ScanFilters,
onSave: (scanFilters: string[]) => void,
) => {
- new ScanFilterModal(plugin, filterType, async (newValues) => {
+ new ScanFilterModal(plugin, filterType, (newValues) => {
onSave(newValues);
}).open();
};
@@ -654,7 +709,7 @@ export const openEditTaskView = async (
matchLeaf.setEphemeralState({ viewTaskId: taskId });
// Reveal the leaf
- workspace.revealLeaf(matchLeaf);
+ await workspace.revealLeaf(matchLeaf);
return leaves[0];
} else {
@@ -695,14 +750,22 @@ export const openEditTaskView = async (
) => {
if (!isTaskNote) {
// Update the task in the file and JSON
- updateTaskInFile(
+ await updateTaskInFile(
plugin,
updatedTask,
task,
).then((newId) => {
- plugin.realTimeScanner.processAllUpdatedFiles(
- updatedTask.filePath,
- );
+ plugin.realTimeScanner
+ .processAllUpdatedFiles(
+ updatedTask.filePath,
+ )
+ .catch((error) => {
+ bugReporterManagerInsatance.addToLogs(
+ 217,
+ String(error),
+ "OpenModals.ts/openEditTaskView",
+ );
+ });
});
} else {
if (!updatedNoteContent) {
@@ -711,28 +774,43 @@ export const openEditTaskView = async (
plugin,
updatedTask,
).then(() => {
- // This is required to rescan the updated file and refresh the board.
- sleep(1000).then(() => {
+ window.setTimeout(() => {
// TODO : Is 1 sec really required ?
// This is required to rescan the updated file and refresh the board.
- plugin.realTimeScanner.processAllUpdatedFiles(
- updatedTask.filePath,
- );
- });
+ plugin.realTimeScanner
+ .processAllUpdatedFiles(
+ updatedTask.filePath,
+ )
+ .catch((error) => {
+ bugReporterManagerInsatance.addToLogs(
+ 217,
+ String(error),
+ "OpenModals.ts/openEditTaskView",
+ );
+ });
+ }, 1000);
});
} else {
- writeDataToVaultFile(
+ await writeDataToVaultFile(
plugin,
updatedTask.filePath,
updatedNoteContent,
).then(() => {
- sleep(1000).then(() => {
+ window.setTimeout(() => {
// TODO : Is 1 sec really required ?
// This is required to rescan the updated file and refresh the board.
- plugin.realTimeScanner.processAllUpdatedFiles(
- updatedTask.filePath,
- );
- });
+ plugin.realTimeScanner
+ .processAllUpdatedFiles(
+ updatedTask.filePath,
+ )
+ .catch((error) => {
+ bugReporterManagerInsatance.addToLogs(
+ 217,
+ String(error),
+ "OpenModals.ts/openEditTaskView",
+ );
+ });
+ }, 1000);
});
}
}
@@ -756,13 +834,23 @@ export const openEditTaskView = async (
) => {
if (!isTaskNote) {
// Update the task in the file and JSON
- updateTaskInFile(plugin, updatedTask, task).then(
- (newId) => {
- plugin.realTimeScanner.processAllUpdatedFiles(
+ void updateTaskInFile(
+ plugin,
+ updatedTask,
+ task,
+ ).then((newId) => {
+ plugin.realTimeScanner
+ .processAllUpdatedFiles(
updatedTask.filePath,
- );
- },
- );
+ )
+ .catch((error) => {
+ bugReporterManagerInsatance.addToLogs(
+ 217,
+ String(error),
+ "OpenModals.ts/openEditTaskView",
+ );
+ });
+ });
} else {
if (!updatedNoteContent) {
// Update frontmatter with task properties
@@ -770,27 +858,41 @@ export const openEditTaskView = async (
plugin,
updatedTask,
).then(() => {
- // This is required to rescan the updated file and refresh the board.
- sleep(1000).then(() => {
- // This is required to rescan the updated file and refresh the board.
- plugin.realTimeScanner.processAllUpdatedFiles(
- updatedTask.filePath,
- );
- });
+ window.setTimeout(() => {
+ // This delay is required to rescan the updated file and refresh the board.
+ plugin.realTimeScanner
+ .processAllUpdatedFiles(
+ updatedTask.filePath,
+ )
+ .catch((error) => {
+ bugReporterManagerInsatance.addToLogs(
+ 217,
+ String(error),
+ "OpenModals.ts/openEditTaskView",
+ );
+ });
+ }, 1000);
});
} else {
- writeDataToVaultFile(
+ void writeDataToVaultFile(
plugin,
updatedTask.filePath,
updatedNoteContent,
).then(() => {
- sleep(1000).then(() => {
- // TODO : Is 1 sec really required ?
- // This is required to rescan the updated file and refresh the board.
- plugin.realTimeScanner.processAllUpdatedFiles(
- updatedTask.filePath,
- );
- });
+ window.setTimeout(() => {
+ // This delay is required to rescan the updated file and refresh the board.
+ plugin.realTimeScanner
+ .processAllUpdatedFiles(
+ updatedTask.filePath,
+ )
+ .catch((error) => {
+ bugReporterManagerInsatance.addToLogs(
+ 217,
+ String(error),
+ "OpenModals.ts/openEditTaskView",
+ );
+ });
+ }, 1000);
});
}
}
@@ -818,7 +920,7 @@ export const openEditTaskView = async (
});
// Reveal the leaf
- workspace.revealLeaf(leaf);
+ await workspace.revealLeaf(leaf);
}
return leaf;
}
@@ -831,7 +933,7 @@ export const openDateInputModal = async (
initialValue?: string,
) => {
const datePicker = new DatePickerModal(plugin, dateName, initialValue);
- datePicker.onDateSelected = async (date: string) => {
+ datePicker.onDateSelected = (date: string) => {
// newTask[dateType] = date;
// updateTaskItemDate(plugin, newTask, dateType, date);
onSelect(date);
diff --git a/src/services/TaskSelectorWithCreateModal.ts b/src/services/TaskSelectorWithCreateModal.ts
index bbb4778a..e171fb52 100644
--- a/src/services/TaskSelectorWithCreateModal.ts
+++ b/src/services/TaskSelectorWithCreateModal.ts
@@ -212,7 +212,7 @@ export class TaskSelectorWithCreateModal extends SuggestModal {
taskData["id"] = generateRandomStringId();
let completeTask: taskItem = taskData as taskItem;
// Create the task
- const result = await createNewInlineTask(this.plugin, completeTask);
+ await createNewInlineTask(this.plugin, completeTask);
new Notice(
t("A new task created successfully : ", {
diff --git a/src/services/editor_extensions/GutterMarker.ts b/src/services/editor_extensions/GutterMarker.ts
index 4b93aee3..6a2a07d1 100644
--- a/src/services/editor_extensions/GutterMarker.ts
+++ b/src/services/editor_extensions/GutterMarker.ts
@@ -10,6 +10,7 @@ import { syntaxTree, tokenClassNodeProp } from "@codemirror/language";
import TaskBoard from "../../../main.js";
import { TaskEditorModal } from "../../modals/TaskEditorModal.js";
import { isTaskLine } from "../../utils/CheckBoxUtils.js";
+import { t } from "i18next";
// Task icon marker
class TaskGutterMarker extends GutterMarker {
@@ -22,7 +23,7 @@ class TaskGutterMarker extends GutterMarker {
text: string,
lineNum: number,
view: EditorView,
- plugin: TaskBoard
+ plugin: TaskBoard,
) {
super();
this.text = text;
@@ -37,12 +38,12 @@ class TaskGutterMarker extends GutterMarker {
// ".cm-scroller"
// ) as HTMLDivElement;
const scroller = this.view.scrollDOM;
- if (scroller) scroller.style.paddingLeft = "0";
+ if (scroller) scroller.addClass("tb_padding_left_0");
const markerEl = createEl("div");
const button = new ExtraButtonComponent(markerEl)
.setIcon("edit")
- .setTooltip("Edit Task")
+ .setTooltip(t("edit-task"))
.onClick(() => {
const lineText = this.view.state.doc.line(this.lineNum).text;
const file = this.plugin.app.workspace.getActiveFile();
@@ -52,7 +53,7 @@ class TaskGutterMarker extends GutterMarker {
// Check if the line is in a codeblock or frontmatter
const line = this.view.state.doc.line(this.lineNum);
const syntaxNode = syntaxTree(this.view.state).resolveInner(
- line.from + 1
+ line.from + 1,
);
const nodeProps = syntaxNode.type.prop(tokenClassNodeProp);
@@ -67,9 +68,9 @@ class TaskGutterMarker extends GutterMarker {
}
// Create a save callback for the modal
- const saveTask = (
- updatedTask: any,
- quickAddPluginChoice: string
+ const saveTask = async (
+ updatedTask: unknown,
+ quickAddPluginChoice: string,
) => {
// This will be handled by the existing task saving logic
// The modal will update the file content automatically
@@ -84,7 +85,7 @@ class TaskGutterMarker extends GutterMarker {
true, // activeNote
true, // taskExists (we're editing an existing task)
undefined, // task - let the modal parse it from the line
- file.path // filePath
+ file.path, // filePath
);
modal.open();
return true;
@@ -114,7 +115,7 @@ export function taskGutterExtension(app: App, plugin: TaskBoard): Extension {
// Check if the line is in a codeblock or frontmatter
const syntaxNode = syntaxTree(view.state).resolveInner(
- line.from + 1
+ line.from + 1,
);
const nodeProps = syntaxNode.type.prop(tokenClassNodeProp);
diff --git a/src/services/editor_extensions/PropertiesHiding.ts b/src/services/editor_extensions/PropertiesHiding.ts
index 018e3494..eaeaf852 100644
--- a/src/services/editor_extensions/PropertiesHiding.ts
+++ b/src/services/editor_extensions/PropertiesHiding.ts
@@ -32,7 +32,7 @@ class HiddenPropertyWidget extends WidgetType {
}
toDOM() {
- const span = document.createElement("span");
+ const span = activeDocument.createElement("span");
span.className = "taskboard-hidden-property-placeholder";
span.textContent = "...";
span.title = `Hidden: ${this.content}`;
@@ -101,7 +101,7 @@ export function getTaskPropertyRegexPatterns(
.TaskFormatRegularExpWithGlobal.dependsOnRegex;
case taskPropertiesNames.Reminder:
- return /\(\@(\d{4}-\d{2}-\d{2}( \d{2}:\d{2})?)\)/g;
+ return /\(@(\d{4}-\d{2}-\d{2}( \d{2}:\d{2})?)\)/g;
default:
return /(?:)/g;
diff --git a/src/services/subModules.ts b/src/services/subModules.ts
index 3b553edb..c29b1711 100644
--- a/src/services/subModules.ts
+++ b/src/services/subModules.ts
@@ -14,4 +14,6 @@ export class TaskBoardSubmodule {
get settings(): PluginDataJson {
return this.plugin.settings;
}
+
+ api: unknown;
}
diff --git a/src/services/tasks-plugin/helpers.ts b/src/services/tasks-plugin/helpers.ts
index 3cad0c40..2f7a92f5 100644
--- a/src/services/tasks-plugin/helpers.ts
+++ b/src/services/tasks-plugin/helpers.ts
@@ -4,11 +4,21 @@ import TaskBoard from "../../../main.js";
import { CustomStatus } from "../../interfaces/GlobalSettings.js";
import { taskItem } from "../../interfaces/TaskItem.js";
import { bugReporterManagerInsatance } from "../../managers/BugReporter.js";
-import { getFormattedTaskContent, addIdToTaskContent } from "../../utils/taskLine/TaskContentFormatter.js";
+import {
+ getFormattedTaskContent,
+ addIdToTaskContent,
+} from "../../utils/taskLine/TaskContentFormatter.js";
import { replaceOldTaskWithNewTask } from "../../utils/taskLine/TaskLineUtils.js";
import { eventEmitter } from "../EventEmitter.js";
import { TasksPluginApi } from "./api.js";
+type TasksPluginStatusSettings = {
+ statusSettings?: {
+ coreStatuses?: CustomStatus[];
+ customStatuses?: CustomStatus[];
+ };
+};
+
export async function isTasksPluginEnabled(plugin: TaskBoard) {
try {
const tasksPluginO = new TasksPluginApi(plugin);
@@ -37,17 +47,21 @@ export async function fetchTasksPluginCustomStatuses(
// Read the file content
const data: string = await plugin.app.vault.adapter.read(path);
- const parsedData = JSON.parse(data);
+ // Treat the plugin data as an explicit structure instead of relying on
+ // the implicit `any` that JSON.parse() introduces.
+ const parsedData = JSON.parse(data) as unknown;
+ const statusSettings = (parsedData as Partial)
+ .statusSettings;
// Extract coreStatuses from the JSON
const coreStatuses: CustomStatus[] =
- parsedData?.statusSettings?.coreStatuses || [];
+ statusSettings?.coreStatuses ?? [];
// Extract customStatuses from the JSON
const customStatuses: CustomStatus[] =
- parsedData?.statusSettings?.customStatuses || [];
+ statusSettings?.customStatuses ?? [];
- const statusMap = new Map();
+ const statusMap = new Map();
coreStatuses.forEach((status: CustomStatus) =>
statusMap.set(status.symbol, status),
);
@@ -99,7 +113,7 @@ export async function openTasksPluginEditModal(
// Prepare the updated task block
const completeOldTaskContent = await getFormattedTaskContent(oldTask);
if (completeOldTaskContent === "")
- throw "getSanitizedTaskContent returned empty string";
+ throw new Error("getSanitizedTaskContent returned empty string");
if (tasksPlugin.isTasksPluginEnabled()) {
const tasksPluginApiOutput = await tasksPlugin.editTaskLineModal(
@@ -135,7 +149,7 @@ export async function openTasksPluginEditModal(
completeOldTaskContent,
newContent,
);
- } else if ((twoTaskTitles.length = 1)) {
+ } else if (twoTaskTitles.length === 1) {
const { formattedTaskContent, newId } =
await addIdToTaskContent(plugin, tasksPluginApiOutput);
const tasksPluginApiOutputWithId = formattedTaskContent;
@@ -150,7 +164,7 @@ export async function openTasksPluginEditModal(
completeOldTaskContent,
newContent,
);
- } else if ((twoTaskTitles.length = 2)) {
+ } else if (twoTaskTitles.length === 2) {
newContent = `${twoTaskTitles[0]}${
oldTask.body.length > 0
? `\n${oldTask.body.join("\n")}`
@@ -177,8 +191,16 @@ export async function openTasksPluginEditModal(
return;
}
- plugin.realTimeScanner.processAllUpdatedFiles(oldTask.filePath);
- setTimeout(() => {
+ plugin.realTimeScanner
+ .processAllUpdatedFiles(oldTask.filePath)
+ .catch((error) => {
+ bugReporterManagerInsatance.addToLogs(
+ 217,
+ String(error),
+ "helpers.ts/openTasksPluginEditModal",
+ );
+ });
+ window.setTimeout(() => {
// This event emmitter will stop any loading animation of ongoing task-card.
eventEmitter.emit("UPDATE_TASK", {
taskID: oldTask.id,
diff --git a/src/settings/2_x_x_Migrations/LegacyInterfacesAndTypings.ts b/src/settings/2_x_x_Migrations/LegacyInterfacesAndTypings.ts
index be6b87f8..9d988f19 100644
--- a/src/settings/2_x_x_Migrations/LegacyInterfacesAndTypings.ts
+++ b/src/settings/2_x_x_Migrations/LegacyInterfacesAndTypings.ts
@@ -1,3 +1,4 @@
+/* eslint-disable @typescript-eslint/no-deprecated */
import {
ColumnData,
Filter,
@@ -12,6 +13,14 @@ import {
mapViewArrowDirection,
mapViewScrollAction,
mapViewEdgeType,
+ RibbonIconActions,
+ taskPropertyFormatOptions,
+ scanModeOptions,
+ taskCardStyleNames,
+ mapViewBackgrounVariantTypes,
+ mapViewNodeMapOrientation,
+ NotificationService,
+ UniversalDateOptions,
} from "../../interfaces/Enums.js";
import {
ScanFilters,
@@ -19,6 +28,7 @@ import {
CustomStatus,
FrontmatterFormattingInterface,
TaskBoardAction,
+ taskBoardFilesRegistryType,
} from "../../interfaces/GlobalSettings.js";
export type BoardLegacy = {
@@ -49,7 +59,7 @@ export interface globalSettingsDataLegacy {
scanFilters: ScanFilters;
firstDayOfWeek?: string;
ignoreFileNameDates: boolean;
- taskPropertyFormat: string;
+ taskPropertyFormat: taskPropertyFormatOptions;
dateFormat: string;
dateTimeFormat: string;
dailyNotesPluginComp: boolean;
@@ -62,16 +72,16 @@ export interface globalSettingsDataLegacy {
autoAddCancelledDate: boolean;
// scanVaultAtStartup: boolean; -- @deprecated v1.9.0 - A better approach has been used using showModifiedFilesNotice feature.
showModifiedFilesNotice: boolean;
- scanMode: string;
+ scanMode: scanModeOptions;
columnWidth: string;
visiblePropertiesList: string[];
- taskCardStyle: string;
+ taskCardStyle: taskCardStyleNames;
showVerticalScroll: boolean;
dragAutoScrollEdgePercent: number;
tagColors: TagColor[];
editButtonAction: EditButtonMode;
doubleClickCardToEdit: EditButtonMode;
- universalDate: string;
+ universalDate: UniversalDateOptions;
customStatuses: CustomStatus[];
showTaskWithoutMetadata: boolean;
tagColorsType: TagColorType;
@@ -91,7 +101,7 @@ export interface globalSettingsDataLegacy {
frontmatterFormatting: FrontmatterFormattingInterface[];
showFrontmatterTagsOnCards: boolean;
tasksCacheFilePath: string;
- notificationService: string;
+ notificationService: NotificationService;
actions: TaskBoardAction[];
searchQuery?: string;
hiddenTaskProperties: taskPropertiesNames[];
@@ -100,15 +110,17 @@ export interface globalSettingsDataLegacy {
experimentalFeatures: boolean;
safeGuardFeature: boolean;
lastViewHistory: {
- viewedType: string;
- boardIndex: number;
+ viewedType?: string;
+ boardIndex?: number;
settingTab: number;
taskId?: string;
+ // New setting introduced in 2.x.x series
+ boardFilePath: string;
};
boundTaskCompletionToChildTasks: boolean;
mapView: {
- background: string;
- mapOrientation: string;
+ background: mapViewBackgrounVariantTypes;
+ mapOrientation: mapViewNodeMapOrientation;
optimizedRender: boolean;
arrowDirection: mapViewArrowDirection;
animatedEdges: boolean;
@@ -117,6 +129,12 @@ export interface globalSettingsDataLegacy {
renderVisibleNodes: boolean;
edgeType: mapViewEdgeType;
};
+
+ // These are new settings introduced in v2.x.x, hence adding here for the setting synchronization utility to work properly.
+ taskBoardFilesRegistry: taskBoardFilesRegistryType;
+ enableDragnDropTouch: boolean;
+ filtersWarehouse: Filter[];
+ ribbonIconAction: RibbonIconActions;
}
export interface PluginDataJsonLegacy {
diff --git a/src/settings/2_x_x_Migrations/MigrationModal.tsx b/src/settings/2_x_x_Migrations/MigrationModal.tsx
index cf529809..67a04c10 100644
--- a/src/settings/2_x_x_Migrations/MigrationModal.tsx
+++ b/src/settings/2_x_x_Migrations/MigrationModal.tsx
@@ -40,7 +40,7 @@ const MigrationModalContent: React.FC<{
setLogs((prev) => [...prev, logEntry]);
// Auto-scroll to bottom
- setTimeout(() => {
+ window.setTimeout(() => {
if (terminalRef.current) {
terminalRef.current.scrollTop = terminalRef.current.scrollHeight;
}
@@ -130,7 +130,7 @@ const MigrationModalContent: React.FC<{
}
// Show Notice to reload Obsidian and make the "Reload Obsidian" button visible
- showReloadObsidianNotice(plugin);
+ void showReloadObsidianNotice(plugin);
// Capture all logs after migration completes and all logs are added
result.logs = [...logsRef.current];
@@ -213,7 +213,7 @@ const MigrationModalContent: React.FC<{
{ void handleStartMigration(); }}
disabled={isRunning}
>
{isRunning ? "Running..." : "Run migrations"}
diff --git a/src/settings/2_x_x_Migrations/MigrationUtils.ts b/src/settings/2_x_x_Migrations/MigrationUtils.ts
index b3cc5793..b482c9e1 100644
--- a/src/settings/2_x_x_Migrations/MigrationUtils.ts
+++ b/src/settings/2_x_x_Migrations/MigrationUtils.ts
@@ -5,6 +5,8 @@ import {
Board,
DEFAULT_BOARD,
MapView,
+ nodeDataType,
+ TaskBoardViewType,
} from "../../interfaces/BoardConfigs.js";
import {
CURRENT_PLUGIN_VERSION,
@@ -12,7 +14,10 @@ import {
NODE_POSITIONS_STORAGE_KEY,
} from "../../interfaces/Constants.js";
import { viewTypeNames } from "../../interfaces/Enums.js";
-import { DEFAULT_SETTINGS } from "../../interfaces/GlobalSettings.js";
+import {
+ DEFAULT_SETTINGS,
+ PluginDataJson,
+} from "../../interfaces/GlobalSettings.js";
import { bugReporterManagerInsatance } from "../../managers/BugReporter.js";
import { createFolderRecursively } from "../../services/FileSystem.js";
import { getCurrentLocalDateTimeString } from "../../utils/DateTimeCalculations.js";
@@ -22,6 +27,7 @@ import {
PluginDataJsonLegacy,
BoardLegacy,
} from "./LegacyInterfacesAndTypings.js";
+import { MigrationModal } from "./MigrationModal.js";
export interface MigrationStepResult {
stepName: string;
@@ -64,7 +70,7 @@ export async function readDataFile(
}
const dataContent = await app.vault.adapter.read(normalizedPath);
- const data: PluginDataJsonLegacy = JSON.parse(dataContent);
+ const data = JSON.parse(dataContent) as PluginDataJsonLegacy;
return data;
}
@@ -170,7 +176,7 @@ export async function checkForV1Data(
} catch (error) {
bugReporterManagerInsatance.addToLogs(
200,
- `Error checking for v1 data: ${error}`,
+ `Error checking for v1 data: ${String(error)}`,
"2_x_x_Migrations/MigrationUtils.ts/checkForV1Data",
);
return { hasV1Data: false };
@@ -180,12 +186,10 @@ export async function checkForV1Data(
// Function to open the MigrationModal
export const openMigrationModal = (
plugin: TaskBoard,
- onMigrationComplete?: (result: any) => void,
+ onMigrationComplete?: (result: unknown) => void,
) => {
// Dynamic import to avoid circular dependencies
- import("./MigrationModal.js").then(({ MigrationModal }) => {
- new MigrationModal(plugin, onMigrationComplete).open();
- });
+ new MigrationModal(plugin, onMigrationComplete).open();
};
/**
@@ -204,7 +208,7 @@ export async function checkAndNotifyV2MigrationsRequired(
createFragment((f) => {
f.createDiv("bugReportNotice", (el) => {
el.createEl("h4", {
- text: `⚠ Task Board migration required`,
+ text: `⚠ Task board migration required`,
});
el.createEl("p", {
text: `Task Board has been updated from version ${v1Check.version} (v1.x.x series) to version ${CURRENT_PLUGIN_VERSION} (v2.x.x series). You are required to run the migrations for this new version to work.`,
@@ -341,7 +345,9 @@ export async function createBoardFiles(
);
if (result) onProgress?.(`✓ Created directory: ${boardsDir}`);
else
- throw "There was an error while creating the default directory for storing the board files.";
+ throw new Error(
+ "There was an error while creating the default directory for storing the board files.",
+ );
} catch (folderError) {
const errorMsg =
folderError instanceof Error
@@ -455,7 +461,7 @@ export async function createBoardFiles(
message: `Board file created successfully`,
});
} else {
- throw `Failed to create the board.`;
+ throw new Error(`Failed to create the board.`);
}
} catch (boardError) {
const errorMsg =
@@ -504,12 +510,15 @@ export async function migrateMapViewData(
// Query localStorage for map view data using board name as key
// Note: localStorage in Obsidian is scoped per workspace
- let mapViewData;
- const mapViewPostionsDataStr = localStorage.getItem(
+ let mapViewData: Record = {};
+ const mapViewPostionsDataStr = plugin.app.loadLocalStorage(
NODE_POSITIONS_STORAGE_KEY,
);
if (mapViewPostionsDataStr) {
- mapViewData = JSON.parse(mapViewPostionsDataStr);
+ const parsedData: unknown = JSON.parse(
+ mapViewPostionsDataStr as string,
+ );
+ mapViewData = parsedData as Record;
} else {
onProgress?.(
`⚠ No map view data found in the LocalStorge. Safely moving for the next operation.`,
@@ -545,7 +554,7 @@ export async function migrateMapViewData(
await sleep(500);
continue;
}
- const boardIndexKey = String(board.boardIndex);
+ const boardIndexKey = Number(board.boardIndex);
if (
mapViewData &&
@@ -566,12 +575,14 @@ export async function migrateMapViewData(
y: 0,
zoom: 0.5,
},
- nodesData: mapViewData[boardIndexKey], // ✅ Safely accessed now
+ // Runtime safety checks above ensure mapViewData is a non-null object with boardIndexKey
+ nodesData: mapViewData[boardIndexKey],
};
const viewsLength = boardData.views.length;
const mapViewExists = boardData.views.some(
- (v: any) => v.type === "map",
+ (v: TaskBoardViewType) =>
+ v.viewType === viewTypeNames.map,
);
if (!mapViewExists) {
boardData.views.push({
@@ -641,17 +652,17 @@ export async function migrateMapViewData(
*/
export async function updateRegistryAndSettings(
plugin: TaskBoard,
- oldPluginSettings: any,
+ oldPluginSettings: PluginDataJson,
onProgress?: (message: string) => void,
): Promise<{ success: boolean; error?: string }> {
try {
onProgress?.("Updating plugin settings...");
await sleep(500);
- const migratedSettings = migrateSettings(
- DEFAULT_SETTINGS,
- oldPluginSettings,
- );
+ const migratedSettings = migrateSettings(DEFAULT_SETTINGS, {
+ version: oldPluginSettings.version,
+ data: oldPluginSettings.data,
+ });
if (migratedSettings.version === "") {
// There was an error while migrating the settings. => ABORT
@@ -763,7 +774,7 @@ export async function migrateVersion1_to_Version2(
// Step 4: Update the main settings file (data.json) and the registry inside it.
onStepStart?.(4, 4, "Finalizing migration...");
- const modifiedOldPluginSettings = {
+ const modifiedOldPluginSettings: PluginDataJson = {
version: oldPluginSettings.version,
data: oldPluginSettings.data.globalSettings,
};
diff --git a/src/settings/SettingConstructUI.ts b/src/settings/SettingConstructUI.ts
index 503ff47c..0ebf4fe5 100644
--- a/src/settings/SettingConstructUI.ts
+++ b/src/settings/SettingConstructUI.ts
@@ -8,7 +8,18 @@ import {
normalizePath,
setIcon,
} from "obsidian";
-import Pickr from "@simonwep/pickr";
+import PickrImport from "@simonwep/pickr";
+
+interface PickrColor {
+ toRGBA(): number[];
+}
+interface PickrInstance {
+ on(event: string, cb: (...args: unknown[]) => void): this;
+ destroy(): void;
+ hide(): void;
+}
+type PickrConstructor = new (options: Record) => PickrInstance;
+const Pickr = PickrImport as unknown as PickrConstructor;
import Sortable from "sortablejs";
import { isValid, parse, format, differenceInHours } from "date-fns";
import { t } from "i18next";
@@ -36,7 +47,6 @@ import {
FrontmatterFormattingInterface,
} from "../interfaces/GlobalSettings.js";
import { buyMeCoffeeSVGIcon, kofiSVGIcon } from "../interfaces/Icons.js";
-import { StatusType } from "../interfaces/StatusConfiguration.js";
import { bugReporterManagerInsatance } from "../managers/BugReporter.js";
import { CustomStatusModal } from "../modals/CustomStatusConfigurator.js";
import { TASKS_PLUGIN_DEFAULT_SYMBOLS } from "../regularExpressions/TasksPluginRegularExpr.js";
@@ -64,7 +74,7 @@ export class SettingsManager {
app: App;
plugin: TaskBoard;
globalSettings: globalSettingsData;
- allPickrs: any[] = [];
+ allPickrs: unknown[] = [];
reloadNoticeAlreadyShown: boolean = false;
constructor(plugin: TaskBoard) {
@@ -125,13 +135,11 @@ export class SettingsManager {
*/
private openReloadNoticeIfNeeded() {
if (!this.reloadNoticeAlreadyShown) {
- sleep(100).then(() => {
- showReloadObsidianNotice(this.plugin);
+ window.setTimeout(() => {
+ void showReloadObsidianNotice(this.plugin);
this.reloadNoticeAlreadyShown = true;
- });
- return;
+ }, 500);
}
- return;
}
// Function to load the settings from data.json
@@ -155,7 +163,7 @@ export class SettingsManager {
try {
this.plugin.settings.data = this.globalSettings;
- this.plugin.saveSettings();
+ await this.plugin.saveSettings();
} catch (err) {
bugReporterManagerInsatance.showNotice(
43,
@@ -230,7 +238,7 @@ export class SettingsManager {
cls: "taskBoard-settings-tab-button",
});
- tabButton.addEventListener("click", async () => {
+ tabButton.addEventListener("click", () => {
// Highlight selected tab
Array.from(tabBar.children).forEach((child) =>
child.toggleClass(
@@ -249,7 +257,7 @@ export class SettingsManager {
if (this.globalSettings) {
this.globalSettings.lastViewHistory.settingTab = tabIndex;
// saveSettings is async; call without awaiting inside this non-async handler
- await this.saveSettings();
+ void this.saveSettings();
}
});
@@ -287,7 +295,7 @@ export class SettingsManager {
this.reloadNoticeAlreadyShown = false;
//Destroy all Pickr instances
- this.allPickrs.forEach((pickr) => pickr.destroy());
+ this.allPickrs.forEach((pickr) => (pickr as PickrInstance).destroy());
//find all the div with calls picr-app using query-selector and remove them from the main window
const pickrApps = this.win.document.querySelectorAll(".pcr-app ");
@@ -315,7 +323,7 @@ export class SettingsManager {
experimentalFeatures,
safeGuardFeature,
ribbonIconAction,
- } = this.globalSettings!;
+ } = this.globalSettings;
new Setting(contentEl)
.setName(t("filters-for-scanning"))
@@ -361,7 +369,7 @@ export class SettingsManager {
openScanFiltersModal(this.plugin, filterType, (newValues) => {
this.plugin.settings.data.scanFilters[filterType].values =
newValues;
- this.plugin.saveSettings();
+ void this.plugin.saveSettings();
refreshTagList(); // Refresh the tag list after updating values
});
});
@@ -392,7 +400,7 @@ export class SettingsManager {
// Polarity dropdown
const polarityDropdown = rowBody.createEl("select", {
- attr: { "aria-label": "Select Filter Polarity" },
+ attr: { "aria-label": "Select filter polarity" },
cls: "taskBoard-filter-dropdown",
});
[
@@ -414,7 +422,7 @@ export class SettingsManager {
);
this.plugin.settings.data.scanFilters[filterType].polarity =
newPolarity;
- this.plugin.saveSettings();
+ void this.plugin.saveSettings();
});
});
@@ -458,10 +466,9 @@ export class SettingsManager {
[scanModeOptions.MANUAL]: t("manual"),
})
.setValue(scanMode)
- .onChange(async (value) => {
- this.globalSettings!.scanMode =
- value as scanModeOptions;
- await this.saveSettings();
+ .onChange((value) => {
+ this.globalSettings.scanMode = value as scanModeOptions;
+ void this.saveSettings();
this.openReloadNoticeIfNeeded();
}),
@@ -488,9 +495,9 @@ export class SettingsManager {
),
)
.addToggle((toggle) =>
- toggle.setValue(autoAddUniqueID).onChange(async (value) => {
+ toggle.setValue(autoAddUniqueID).onChange((value) => {
this.globalSettings.autoAddUniqueID = value;
- await this.saveSettings();
+ void this.saveSettings();
this.openReloadNoticeIfNeeded();
}),
@@ -501,9 +508,9 @@ export class SettingsManager {
.setName(t("open-board-on-obsidian-startup"))
.setDesc(t("open-board-on-obsidian-startup-info"))
.addToggle((toggle) =>
- toggle.setValue(openOnStartup).onChange(async (value) => {
- this.globalSettings!.openOnStartup = value;
- await this.saveSettings();
+ toggle.setValue(openOnStartup).onChange((value) => {
+ this.globalSettings.openOnStartup = value;
+ void this.saveSettings();
}),
);
@@ -512,12 +519,10 @@ export class SettingsManager {
.setName(t("show-modified-files-message-on-startup"))
.setDesc(t("show-modified-files-message-on-startup-info"))
.addToggle((toggle) =>
- toggle
- .setValue(showModifiedFilesNotice)
- .onChange(async (value) => {
- this.globalSettings!.showModifiedFilesNotice = value;
- await this.saveSettings();
- }),
+ toggle.setValue(showModifiedFilesNotice).onChange((value) => {
+ this.globalSettings.showModifiedFilesNotice = value;
+ void this.saveSettings();
+ }),
);
new Setting(contentEl)
@@ -532,10 +537,10 @@ export class SettingsManager {
t("boards-explorer"),
})
.setValue(ribbonIconAction)
- .onChange(async (value) => {
- this.globalSettings!.ribbonIconAction =
+ .onChange((value) => {
+ this.globalSettings.ribbonIconAction =
value as RibbonIconActions;
- await this.saveSettings();
+ void this.saveSettings();
}),
);
@@ -607,7 +612,7 @@ export class SettingsManager {
// }
// }
// renderTasksCachePathSetting();
- // await this.saveSettings();
+ // void this.saveSettings();
// };
// new MultiSuggest(
@@ -626,7 +631,7 @@ export class SettingsManager {
);
if (result) {
this.globalSettings.tasksCacheFilePath = newPath;
- this.saveSettings();
+ void this.saveSettings();
renderTasksCachePathSetting();
new Notice(
@@ -634,10 +639,10 @@ export class SettingsManager {
);
} else {
new Notice(
- "Task Board : Failed to change the path. Check logs for more info.",
+ "Task board : Failed to change the path. Check logs for more info.",
);
this.globalSettings.tasksCacheFilePath = `${this.app.vault.configDir}/plugins/task-board/tasks.json`;
- this.saveSettings();
+ void this.saveSettings();
renderTasksCachePathSetting();
}
@@ -655,18 +660,18 @@ export class SettingsManager {
if (result) {
this.globalSettings.tasksCacheFilePath = newPath;
- this.saveSettings();
+ void this.saveSettings();
renderTasksCachePathSetting();
new Notice(
- `Task Board cache file path reset was succussfully.`,
+ `Task board cache file path reset was succussfully.`,
);
} else {
new Notice(
- "Task Board : Failed to change the path. Check logs for more info.",
+ "Task board : Failed to change the path. Check logs for more info.",
);
this.globalSettings.tasksCacheFilePath = `${this.app.vault.configDir}/plugins/task-board/tasks.json`;
- this.saveSettings();
+ void this.saveSettings();
renderTasksCachePathSetting();
}
@@ -682,16 +687,17 @@ export class SettingsManager {
.setName(t("import-export-configurations"))
.setDesc(t("import-export-configurations-info"))
.addButton((button) =>
- button.setButtonText(t("import")).onClick(async () => {
- const result = await importConfigurations(this.plugin);
- if (result) {
- this.openReloadNoticeIfNeeded();
- }
+ button.setButtonText(t("import")).onClick(() => {
+ void importConfigurations(this.plugin).then((result) => {
+ if (result) {
+ this.openReloadNoticeIfNeeded();
+ }
+ });
}),
)
.addButton((button) =>
- button.setButtonText(t("export")).onClick(async () => {
- await exportConfigurations(this.plugin);
+ button.setButtonText(t("export")).onClick(() => {
+ void exportConfigurations(this.plugin);
}),
);
@@ -699,8 +705,8 @@ export class SettingsManager {
.setName(t("export-logs"))
.setDesc(t("export-logs-info"))
.addButton((button) =>
- button.setButtonText(t("export")).onClick(async () => {
- await bugReporterManagerInsatance.exportLogFile();
+ button.setButtonText(t("export")).onClick(() => {
+ void bugReporterManagerInsatance.exportLogFile();
}),
);
@@ -720,9 +726,9 @@ export class SettingsManager {
),
)
.addToggle((toggle) =>
- toggle.setValue(safeGuardFeature).onChange(async (value) => {
- this.globalSettings!.safeGuardFeature = value;
- await this.saveSettings();
+ toggle.setValue(safeGuardFeature).onChange((value) => {
+ this.globalSettings.safeGuardFeature = value;
+ void this.saveSettings();
this.openReloadNoticeIfNeeded();
}),
@@ -751,14 +757,12 @@ export class SettingsManager {
),
)
.addToggle((toggle) =>
- toggle
- .setValue(experimentalFeatures)
- .onChange(async (value) => {
- this.globalSettings!.experimentalFeatures = value;
- await this.saveSettings();
+ toggle.setValue(experimentalFeatures).onChange((value) => {
+ this.globalSettings.experimentalFeatures = value;
+ void this.saveSettings();
- this.openReloadNoticeIfNeeded();
- }),
+ this.openReloadNoticeIfNeeded();
+ }),
);
// // Helper to add filter rows
@@ -788,7 +792,7 @@ export class SettingsManager {
// input.addEventListener("change", async () => {
// this.globalSettings!.scanFilters[filterType].values =
// input.value.split(",").map((v) => normalizePath(v.trim()));
- // await this.saveSettings();
+ // void this.saveSettings();
// });
// input.placeholder = placeholder;
@@ -808,7 +812,7 @@ export class SettingsManager {
// dropdown.addEventListener("change", async () => {
// this.globalSettings!.scanFilters[filterType].polarity =
// parseInt(dropdown.value, 10);
- // await this.saveSettings();
+ // void this.saveSettings();
// });
// };
@@ -850,7 +854,7 @@ export class SettingsManager {
text: t("this-plugin-is-created-by"),
})
.createEl("a", {
- text: "Atmanand Gauns",
+ text: t("author-name"),
href: "https://www.github.com/tu2-atmanand",
});
@@ -905,9 +909,9 @@ export class SettingsManager {
// dropdown.setValue(lang as string);
// // On dropdown value change, update the global settings
- // dropdown.onChange(async (value) => {
+ // dropdown.onChange((value) => {
// this.globalSettings!.lang = value;
- // await this.saveSettings();
+ // void this.saveSettings();
// });
// });
@@ -919,7 +923,7 @@ export class SettingsManager {
showTaskWithoutMetadata,
taskCardStyle,
enableDragnDropTouch,
- } = this.globalSettings!;
+ } = this.globalSettings;
new Setting(contentEl)
.setName(t("task-card-style"))
@@ -933,10 +937,10 @@ export class SettingsManager {
// [taskCardStyleNames.DATAVIEW]: t("dataview-style"),
})
.setValue(taskCardStyle)
- .onChange(async (value) => {
- this.globalSettings!.taskCardStyle =
+ .onChange((value) => {
+ this.globalSettings.taskCardStyle =
value as taskCardStyleNames;
- await this.saveSettings();
+ void this.saveSettings();
}),
);
@@ -945,12 +949,10 @@ export class SettingsManager {
.setName(t("show-task-without-metadata"))
.setDesc(t("show-task-without-metadata-info"))
.addToggle((toggle) =>
- toggle
- .setValue(showTaskWithoutMetadata)
- .onChange(async (value) => {
- this.globalSettings!.showTaskWithoutMetadata = value;
- await this.saveSettings();
- }),
+ toggle.setValue(showTaskWithoutMetadata).onChange((value) => {
+ this.globalSettings.showTaskWithoutMetadata = value;
+ void this.saveSettings();
+ }),
);
// Setting to take the width of each Column in px.
@@ -960,11 +962,11 @@ export class SettingsManager {
.addText((text) =>
text
.setValue(columnWidth)
- .onChange(async (value) => {
- this.globalSettings!.columnWidth = value;
- await this.saveSettings();
+ .onChange((value) => {
+ this.globalSettings.columnWidth = value;
+ void this.saveSettings();
})
- .setPlaceholder("300px"),
+ .setPlaceholder("300"),
);
// Setting to show/Hide the Vertical ScrollBar of each Column
@@ -972,9 +974,9 @@ export class SettingsManager {
.setName(t("show-column-scroll-bar"))
.setDesc(t("enable-to-see-a-scrollbar-for-each-column"))
.addToggle((toggle) =>
- toggle.setValue(showVerticalScroll).onChange(async (value) => {
- this.globalSettings!.showVerticalScroll = value;
- await this.saveSettings();
+ toggle.setValue(showVerticalScroll).onChange((value) => {
+ this.globalSettings.showVerticalScroll = value;
+ void this.saveSettings();
}),
);
@@ -991,7 +993,7 @@ export class SettingsManager {
// this.globalSettings!.kanbanView?.lazyLoadingEnabled ??
// false,
// )
- // .onChange(async (value) => {
+ // .onChange((value) => {
// if (!this.globalSettings!.kanbanView) {
// this.globalSettings!.kanbanView = {
// lazyLoadingEnabled: false,
@@ -1002,7 +1004,7 @@ export class SettingsManager {
// }
// this.globalSettings!.kanbanView.lazyLoadingEnabled =
// value;
- // await this.saveSettings();
+ // void this.saveSettings();
// }),
// );
@@ -1031,11 +1033,11 @@ export class SettingsManager {
"open-note-in-hover-preview",
),
})
- .setValue(this.globalSettings!.editButtonAction)
- .onChange(async (value) => {
- this.globalSettings!.editButtonAction =
+ .setValue(this.globalSettings.editButtonAction)
+ .onChange((value) => {
+ this.globalSettings.editButtonAction =
value as EditButtonMode;
- await this.saveSettings();
+ void this.saveSettings();
}),
);
@@ -1060,11 +1062,11 @@ export class SettingsManager {
"open-note-in-hover-preview",
),
})
- .setValue(this.globalSettings!.doubleClickCardToEdit)
- .onChange(async (value) => {
- this.globalSettings!.doubleClickCardToEdit =
+ .setValue(this.globalSettings.doubleClickCardToEdit)
+ .onChange((value) => {
+ this.globalSettings.doubleClickCardToEdit =
value as EditButtonMode;
- await this.saveSettings();
+ void this.saveSettings();
}),
);
@@ -1089,14 +1091,12 @@ export class SettingsManager {
),
)
.addToggle((toggle) =>
- toggle
- .setValue(enableDragnDropTouch)
- .onChange(async (value) => {
- this.globalSettings!.enableDragnDropTouch = value;
- await this.saveSettings();
+ toggle.setValue(enableDragnDropTouch).onChange((value) => {
+ this.globalSettings.enableDragnDropTouch = value;
+ void this.saveSettings();
- this.openReloadNoticeIfNeeded();
- }),
+ this.openReloadNoticeIfNeeded();
+ }),
);
// .setVisibility(Platform.isMobile);
}
@@ -1114,10 +1114,10 @@ export class SettingsManager {
[TagColorType.CardBg]: t("background-of-the-card"),
})
.setValue(tagColorsType)
- .onChange(async (value) => {
- this.globalSettings!.tagColorsType =
+ .onChange((value) => {
+ this.globalSettings.tagColorsType =
value as TagColorType;
- await this.saveSettings();
+ void this.saveSettings();
renderTagColors();
}),
);
@@ -1137,7 +1137,7 @@ export class SettingsManager {
forceFallback: true,
fallbackClass: "task-board-sortable-fallback",
easing: "cubic-bezier(1, 0, 0, 1)",
- onSort: async () => {
+ onSort: () => {
const newOrder = Array.from(tagColorsContainer.children)
.map((child, index) => {
const tagName = child.getAttribute("data-tag-name");
@@ -1158,188 +1158,200 @@ export class SettingsManager {
} => tag !== null,
);
- this.globalSettings!.tagColors = newOrder;
- await this.saveSettings();
+ this.globalSettings.tagColors = newOrder;
+ void this.saveSettings();
},
});
const renderTagColors = () => {
tagColorsContainer.empty(); // Clear existing rendered rows
- this.globalSettings!.tagColors.sort(
- (a, b) => a.priority - b.priority,
- ).forEach((tag, index) => {
- const row = tagColorsContainer.createDiv({
- cls: "tag-color-row",
- attr: { "data-tag-name": tag.name },
- });
- let colorInputRef: any;
-
- new Setting(row)
- .setClass("tag-color-row-element")
- .addButton((drag) =>
- drag
- .setTooltip("Hold and drag")
- .setIcon("grip-horizontal")
- .setClass(
- "taskboard-setting-tag-color-row-element-drag-handle",
- )
- .buttonEl.setCssStyles({
- cursor: "grab",
- backgroundColor:
- this.globalSettings!.tagColorsType !==
- TagColorType.TagText
- ? tag.color
- : "",
- color:
- this.globalSettings!.tagColorsType ===
- TagColorType.TagText
- ? tag.color
- : "",
- border:
- this.globalSettings!.tagColorsType ===
- TagColorType.TagText
- ? `1px solid ${tag.color}`
- : "",
- maxWidth: "max-content !important",
- }),
- )
- .addText((text) =>
- text
- .setPlaceholder(t("enter-tag-name"))
- .setValue(tag.name)
- .onChange(async (value) => {
- tag.name = value.trim().replace("#", "");
- row.setAttribute("data-tag-name", tag.name);
- await this.saveSettings();
- })
- .inputEl.setCssStyles({
- backgroundColor:
- this.globalSettings!.tagColorsType !==
- TagColorType.TagText
- ? tag.color
- : "",
- color:
- this.globalSettings!.tagColorsType ===
- TagColorType.TagText
- ? tag.color
- : "",
- border:
- this.globalSettings!.tagColorsType ===
- TagColorType.TagText
- ? `1px solid ${tag.color}`
- : "",
- minWidth: "23vw !important",
- }),
- )
- .addButton((btn) => {
- btn.setTooltip(t("pick-color-for-tag"))
- .setIcon("palette")
- .setClass(
- "taskboard-setting-tag-color-row-element-color-picker",
- )
- .then(() => {
- const colorMap =
- this.plugin.settings.data.tagColors.map(
- (tagColor) => ({
- color:
- this.plugin.settings.data
- .tagColors[
- tagColor.priority - 1
- ]?.color || "#ff0000",
- }),
- );
- const pickr = new (Pickr as any)({
- el: btn.buttonEl,
- theme: "nano",
- swatches: colorMap.map(
- (item) => item.color,
- ),
- defaultRepresentation: "HEXA",
- default: tag.color || "#ff0000",
- comparison: false,
- components: {
- preview: true,
- opacity: true,
- hue: true,
- interaction: {
- hex: true,
- rgba: true,
- hsla: false,
- hsva: false,
- cmyk: false,
- input: true,
- clear: true,
- cancel: true,
- save: false,
+ this.globalSettings.tagColors
+ .sort((a, b) => a.priority - b.priority)
+ .forEach((tag, index) => {
+ const row = tagColorsContainer.createDiv({
+ cls: "tag-color-row",
+ attr: { "data-tag-name": tag.name },
+ });
+ let colorInputRef: unknown;
+
+ new Setting(row)
+ .setClass("tag-color-row-element")
+ .addButton((drag) =>
+ drag
+ .setTooltip("Hold and drag")
+ .setIcon("grip-horizontal")
+ .setClass(
+ "taskboard-setting-tag-color-row-element-drag-handle",
+ )
+ .buttonEl.setCssStyles({
+ cursor: "grab",
+ backgroundColor:
+ this.globalSettings.tagColorsType !==
+ TagColorType.TagText
+ ? tag.color
+ : "",
+ color:
+ this.globalSettings.tagColorsType ===
+ TagColorType.TagText
+ ? tag.color
+ : "",
+ border:
+ this.globalSettings.tagColorsType ===
+ TagColorType.TagText
+ ? `1px solid ${tag.color}`
+ : "",
+ maxWidth: "max-content !important",
+ }),
+ )
+ .addText((text) =>
+ text
+ .setPlaceholder(t("enter-tag-name"))
+ .setValue(tag.name)
+ .onChange((value) => {
+ tag.name = value.trim().replace("#", "");
+ row.setAttribute("data-tag-name", tag.name);
+ void this.saveSettings();
+ })
+ .inputEl.setCssStyles({
+ backgroundColor:
+ this.globalSettings.tagColorsType !==
+ TagColorType.TagText
+ ? tag.color
+ : "",
+ color:
+ this.globalSettings.tagColorsType ===
+ TagColorType.TagText
+ ? tag.color
+ : "",
+ border:
+ this.globalSettings.tagColorsType ===
+ TagColorType.TagText
+ ? `1px solid ${tag.color}`
+ : "",
+ minWidth: "23vw !important",
+ }),
+ )
+ .addButton((btn) => {
+ btn.setTooltip(t("pick-color-for-tag"))
+ .setIcon("palette")
+ .setClass(
+ "taskboard-setting-tag-color-row-element-color-picker",
+ )
+ .then(() => {
+ const colorMap =
+ this.plugin.settings.data.tagColors.map(
+ (tagColor) => ({
+ color:
+ this.plugin.settings.data
+ .tagColors[
+ tagColor.priority - 1
+ ]?.color || "#ff0000",
+ }),
+ );
+
+ const pickr = new Pickr({
+ el: btn.buttonEl,
+ theme: "nano",
+ swatches: colorMap.map(
+ (item) => item.color,
+ ),
+ defaultRepresentation: "HEXA",
+ default: tag.color || "#ff0000",
+ comparison: false,
+ components: {
+ preview: true,
+ opacity: true,
+ hue: true,
+ interaction: {
+ hex: true,
+ rgba: true,
+ hsla: false,
+ hsva: false,
+ cmyk: false,
+ input: true,
+ clear: true,
+ cancel: true,
+ save: false,
+ },
},
- },
- });
+ });
- this.allPickrs.push(pickr);
+ this.allPickrs.push(pickr);
- pickr
- .on("change", (color: any) => {
- const rgbaColor = `rgba(${color
- .toRGBA()
- .map((v: number, i: number) =>
- i < 3 ? Math.round(v) : v,
+ pickr
+ .on("change", (color: unknown) => {
+ const rgbaColor = `rgba(${(
+ color as PickrColor
)
- .join(", ")})`;
- tag.color = rgbaColor;
- colorInputRef.setValue(rgbaColor);
- })
- .on("hide", () => {
- renderTagColors();
- this.saveSettings();
- })
- .on("cancel", () => pickr.destroy())
- .on("clear", () => pickr.hide());
- });
- })
- .addText((colorInput) => {
- colorInputRef = colorInput;
- colorInput
- .setPlaceholder("Color Value")
- .setValue(tag.color)
- .onChange(async (newColor) => {
- tag.color = newColor;
- await this.saveSettings();
- })
- .inputEl.setCssStyles({
- backgroundColor:
- this.globalSettings!.tagColorsType !==
- TagColorType.TagText
- ? tag.color
- : "",
- color:
- this.globalSettings!.tagColorsType ===
- TagColorType.TagText
- ? tag.color
- : "",
- border:
- this.globalSettings!.tagColorsType ===
- TagColorType.TagText
- ? `1px solid ${tag.color}`
- : "",
- minWidth: "23vw !important",
- });
- })
- .addButton((del) =>
- del
- .setButtonText("Delete")
- .setIcon("trash")
- .setClass(
- "taskboard-setting-tag-color-row-element-delete",
- )
- .setTooltip(t("delete-tag-color"))
- .onClick(async () => {
- this.globalSettings!.tagColors.splice(index, 1);
- await this.saveSettings();
- renderTagColors(); // Re-render after delete
- }),
- );
- });
+ .toRGBA()
+ .map((v: number, i: number) =>
+ i < 3 ? Math.round(v) : v,
+ )
+ .join(", ")})`;
+ tag.color = rgbaColor;
+ (
+ colorInputRef as {
+ setValue: (
+ val: string,
+ ) => void;
+ }
+ ).setValue(rgbaColor);
+ })
+ .on("hide", () => {
+ renderTagColors();
+ void this.saveSettings();
+ })
+ .on("cancel", () => pickr.destroy())
+ .on("clear", () => pickr.hide());
+ });
+ })
+ .addText((colorInput) => {
+ colorInputRef = colorInput;
+ colorInput
+ .setPlaceholder("Color value")
+ .setValue(tag.color)
+ .onChange(async (newColor) => {
+ tag.color = newColor;
+ void this.saveSettings();
+ })
+ .inputEl.setCssStyles({
+ backgroundColor:
+ this.globalSettings.tagColorsType !==
+ TagColorType.TagText
+ ? tag.color
+ : "",
+ color:
+ this.globalSettings.tagColorsType ===
+ TagColorType.TagText
+ ? tag.color
+ : "",
+ border:
+ this.globalSettings.tagColorsType ===
+ TagColorType.TagText
+ ? `1px solid ${tag.color}`
+ : "",
+ minWidth: "23vw !important",
+ });
+ })
+ .addButton((del) =>
+ del
+ .setButtonText("Delete")
+ .setIcon("trash")
+ .setClass(
+ "taskboard-setting-tag-color-row-element-delete",
+ )
+ .setTooltip(t("delete-tag-color"))
+ .onClick(async () => {
+ this.globalSettings.tagColors.splice(
+ index,
+ 1,
+ );
+ void this.saveSettings();
+ renderTagColors(); // Re-render after delete
+ }),
+ );
+ });
};
// Initial render
@@ -1355,10 +1367,10 @@ export class SettingsManager {
const newTag = {
name: "",
color: "rgba(255, 0, 0, 1)",
- priority: this.globalSettings!.tagColors.length + 1,
+ priority: this.globalSettings.tagColors.length + 1,
};
- this.globalSettings!.tagColors.push(newTag);
- await this.saveSettings();
+ this.globalSettings.tagColors.push(newTag);
+ void this.saveSettings();
renderTagColors();
}),
)
@@ -1392,9 +1404,9 @@ export class SettingsManager {
// dropdown.setValue(lang as string);
// // On dropdown value change, update the global settings
- // dropdown.onChange(async (value) => {
+ // dropdown.onChange((value) => {
// this.globalSettings!.lang = value;
- // await this.saveSettings();
+ // void this.saveSettings();
// });
// });
@@ -1506,7 +1518,7 @@ export class SettingsManager {
status,
false,
);
- modal.onClose = async () => {
+ modal.onClose = () => {
if (modal.saved) {
const updatedStatus = modal.statusConfiguration();
const customStatus: CustomStatus = {
@@ -1520,9 +1532,9 @@ export class SettingsManager {
updatedStatus.availableAsCommand,
type: updatedStatus.type,
};
- this.plugin.settings.data!.customStatuses[index] =
+ this.plugin.settings.data.customStatuses[index] =
customStatus;
- await this.saveSettings();
+ void this.saveSettings();
renderCustomStatuses();
this.openReloadNoticeIfNeeded();
}
@@ -1538,8 +1550,8 @@ export class SettingsManager {
});
setIcon(deleteButton, "trash");
deleteButton.onclick = async () => {
- this.globalSettings!.customStatuses.splice(index, 1);
- await this.saveSettings();
+ this.globalSettings.customStatuses.splice(index, 1);
+ void this.saveSettings();
renderCustomStatuses();
this.openReloadNoticeIfNeeded();
};
@@ -1579,14 +1591,14 @@ export class SettingsManager {
name: "",
nextStatusSymbol: "",
availableAsCommand: false,
- type: StatusType.TODO,
+ type: statusTypeNames.TODO,
};
const modal = new CustomStatusModal(
this.plugin,
newStatus,
false,
);
- modal.onClose = async () => {
+ modal.onClose = () => {
if (modal.saved) {
const statusConfig =
modal.statusConfiguration();
@@ -1599,13 +1611,13 @@ export class SettingsManager {
statusConfig.availableAsCommand,
type: statusConfig.type,
};
- if (!this.globalSettings!.customStatuses) {
- this.globalSettings!.customStatuses = [];
+ if (!this.globalSettings.customStatuses) {
+ this.globalSettings.customStatuses = [];
}
- this.globalSettings!.customStatuses.push(
+ this.globalSettings.customStatuses.push(
customStatus,
);
- await this.saveSettings();
+ void this.saveSettings();
renderCustomStatuses();
this.openReloadNoticeIfNeeded();
}
@@ -1629,7 +1641,7 @@ export class SettingsManager {
archivedTasksFilePath,
showFrontmatterTagsOnCards,
hiddenTaskProperties,
- } = this.globalSettings!;
+ } = this.globalSettings;
// Create the live preview element
const previewEl = contentEl.createDiv({
@@ -1659,12 +1671,20 @@ export class SettingsManager {
markdownPreviewEl.empty();
// Use Obsidian's MarkdownUIRenderer to render markdown
// @ts-ignore
- MarkdownUIRenderer.renderSubtaskText(
+ // MarkdownUIRenderer.safeRender(
+ // this.app,
+ // markdown,
+ // markdownPreviewEl,
+ // "",
+ // this.plugin.view,
+ // );
+
+ void MarkdownUIRenderer.strictRender(
this.app,
markdown,
markdownPreviewEl,
"",
- this.plugin.view,
+ null, // @todo - Need to pass the window of the settings modal.
);
};
const updatePreview = () => {
@@ -1699,11 +1719,11 @@ export class SettingsManager {
let completionDate = "2024-09-21/12:20:33";
let preview = "";
- switch (this.globalSettings!.taskPropertyFormat) {
+ switch (this.globalSettings.taskPropertyFormat) {
// Default
- case "1": {
+ case taskPropertyFormatOptions.default: {
if (
- this.globalSettings!.compatiblePlugins.dayPlannerPlugin
+ this.globalSettings.compatiblePlugins.dayPlannerPlugin
) {
preview = `- [>] ${time} ${taskTitle} ${priority} ${universalDateEmoji}${date} ${tags} ✅${completionDate}`;
} else {
@@ -1712,9 +1732,9 @@ export class SettingsManager {
break;
}
// Tasks Plugin
- case "2": {
+ case taskPropertyFormatOptions.tasksPlugin: {
if (
- this.globalSettings!.compatiblePlugins.dayPlannerPlugin
+ this.globalSettings.compatiblePlugins.dayPlannerPlugin
) {
preview = `- [>] ${time} ${taskTitle} ${priority} ${universalDateEmoji} ${date} ${tags} ✅ ${
completionDate.split("/")[0]
@@ -1727,9 +1747,9 @@ export class SettingsManager {
break;
}
// Dataview Plugin
- case "3": {
+ case taskPropertyFormatOptions.dataviewPlugin: {
if (
- this.globalSettings!.compatiblePlugins.dayPlannerPlugin
+ this.globalSettings.compatiblePlugins.dayPlannerPlugin
) {
preview = `- [>] ${time} ${taskTitle} [priority:: 2] [${universalDateString}:: ${date}] ${tags} [completion:: ${completionDate}]`;
} else {
@@ -1738,9 +1758,9 @@ export class SettingsManager {
break;
}
// Obsidian Native
- case "4": {
+ case taskPropertyFormatOptions.obsidianNative: {
if (
- this.globalSettings!.compatiblePlugins.dayPlannerPlugin
+ this.globalSettings.compatiblePlugins.dayPlannerPlugin
) {
preview = `- [>] ${time} ${taskTitle} @priority(2) @${universalDateString}(${date}) ${tags} @completion(${completionDate})`;
} else {
@@ -1775,10 +1795,11 @@ export class SettingsManager {
"Obsidian " + t("native"),
);
- dropdown.setValue(taskPropertyFormat as string);
- dropdown.onChange(async (value) => {
- this.globalSettings!.taskPropertyFormat = value;
- await this.saveSettings();
+ dropdown.setValue(taskPropertyFormat);
+ dropdown.onChange((value) => {
+ this.globalSettings.taskPropertyFormat =
+ value as taskPropertyFormatOptions;
+ void this.saveSettings();
updatePreview();
this.openReloadNoticeIfNeeded();
@@ -1801,12 +1822,12 @@ export class SettingsManager {
const inputEl = text.inputEl;
const suggestionContent = getFileSuggestions(this.app);
- const onSelectCallback = async (selectedPath: string) => {
+ const onSelectCallback = (selectedPath: string) => {
if (this.globalSettings) {
this.globalSettings.preDefinedNote = selectedPath;
}
text.setValue(selectedPath);
- await this.saveSettings();
+ void this.saveSettings();
};
new MultiSuggest(
@@ -1831,13 +1852,13 @@ export class SettingsManager {
const inputEl = text.inputEl;
const suggestionContent = getFileSuggestions(this.app);
- const onSelectCallback = async (selectedPath: string) => {
+ const onSelectCallback = (selectedPath: string) => {
if (this.globalSettings) {
this.globalSettings.archivedTasksFilePath =
selectedPath;
}
text.setValue(selectedPath);
- await this.saveSettings();
+ void this.saveSettings();
};
new MultiSuggest(
@@ -1855,9 +1876,9 @@ export class SettingsManager {
.addToggle((toggle) =>
toggle
.setValue(showFrontmatterTagsOnCards)
- .onChange(async (value) => {
- this.globalSettings!.showFrontmatterTagsOnCards = value;
- await this.saveSettings();
+ .onChange((value) => {
+ this.globalSettings.showFrontmatterTagsOnCards = value;
+ void this.saveSettings();
}),
);
@@ -1883,26 +1904,26 @@ export class SettingsManager {
.addToggle((toggle) => {
const isSelected =
hiddenTaskProperties.includes(property);
- toggle.setValue(isSelected).onChange(async (value) => {
+ toggle.setValue(isSelected).onChange((value) => {
if (value) {
// Add property if not already included
if (
- !this.globalSettings!.hiddenTaskProperties.includes(
+ !this.globalSettings.hiddenTaskProperties.includes(
property,
)
) {
- this.globalSettings!.hiddenTaskProperties.push(
+ this.globalSettings.hiddenTaskProperties.push(
property,
);
}
} else {
// Remove property
- this.globalSettings!.hiddenTaskProperties =
- this.globalSettings!.hiddenTaskProperties.filter(
+ this.globalSettings.hiddenTaskProperties =
+ this.globalSettings.hiddenTaskProperties.filter(
(p) => p !== property,
);
}
- await this.saveSettings();
+ void this.saveSettings();
this.openReloadNoticeIfNeeded();
});
@@ -1920,7 +1941,7 @@ export class SettingsManager {
taskNoteDefaultLocation,
archivedTBNotesFolderPath,
frontmatterFormatting,
- } = this.globalSettings!;
+ } = this.globalSettings;
new Setting(contentEl)
.setName(t("task-note-vs-tbnote"))
@@ -1955,7 +1976,8 @@ export class SettingsManager {
});
const inputEl = text.inputEl;
- inputEl.placeholder = "e.g., taskNote";
+ // eslint-disable-next-line obsidianmd/ui/sentence-case
+ inputEl.placeholder = "E.g., taskNote";
});
const folderSuggestions = getFolderSuggestions(this.app);
@@ -1974,14 +1996,15 @@ export class SettingsManager {
});
const inputEl = text.inputEl;
- inputEl.placeholder = "e.g., Task Notes/";
- const onSelectCallback = async (selectedPath: string) => {
+ // eslint-disable-next-line obsidianmd/ui/sentence-case
+ inputEl.placeholder = "E.g., Task Notes/";
+ const onSelectCallback = (selectedPath: string) => {
if (this.globalSettings) {
this.globalSettings.taskNoteDefaultLocation =
selectedPath;
}
text.setValue(selectedPath);
- await this.saveSettings();
+ void this.saveSettings();
};
new MultiSuggest(
@@ -2006,14 +2029,15 @@ export class SettingsManager {
});
const inputEl = text.inputEl;
+ // eslint-disable-next-line obsidianmd/ui/sentence-case
inputEl.placeholder = "e.g., TaskBoard/TaskNotes";
- const onSelectCallback = async (selectedPath: string) => {
+ const onSelectCallback = (selectedPath: string) => {
if (this.globalSettings) {
this.globalSettings.archivedTBNotesFolderPath =
selectedPath;
}
text.setValue(selectedPath);
- await this.saveSettings();
+ void this.saveSettings();
};
new MultiSuggest(
@@ -2043,7 +2067,7 @@ export class SettingsManager {
forceFallback: true,
fallbackClass: "task-board-sortable-fallback",
easing: "cubic-bezier(1, 0, 0, 1)",
- onSort: async () => {
+ onSort: () => {
const newOrder = Array.from(
frontmatterFormattingContainer.children,
)
@@ -2128,7 +2152,7 @@ export class SettingsManager {
// index,
// 1
// );
- // this.saveSettings();
+ // void this.saveSettings();
// renderFrontmatterFormattingItems(); // Re-render after delete
// }
// })
@@ -2177,7 +2201,7 @@ export class SettingsManager {
showMinimap,
renderVisibleNodes,
edgeType,
- } = this.globalSettings?.mapView!;
+ } = this.globalSettings.mapView;
new Setting(contentEl)
.setName(
@@ -2210,9 +2234,9 @@ export class SettingsManager {
),
)
.addToggle((toggle) =>
- toggle.setValue(renderVisibleNodes).onChange(async (value) => {
- this.globalSettings!.mapView.renderVisibleNodes = value;
- await this.saveSettings();
+ toggle.setValue(renderVisibleNodes).onChange((value) => {
+ this.globalSettings.mapView.renderVisibleNodes = value;
+ void this.saveSettings();
}),
);
@@ -2228,10 +2252,10 @@ export class SettingsManager {
[mapViewScrollAction.pan]: t("pan"),
})
.setValue(scrollAction)
- .onChange(async (value) => {
- this.globalSettings!.mapView.scrollAction =
+ .onChange((value) => {
+ this.globalSettings.mapView.scrollAction =
value as mapViewScrollAction;
- await this.saveSettings();
+ void this.saveSettings();
}),
);
@@ -2251,10 +2275,10 @@ export class SettingsManager {
[mapViewBackgrounVariantTypes.cross]: t("cross"),
})
.setValue(background)
- .onChange(async (value) => {
- this.globalSettings!.mapView.background =
+ .onChange((value) => {
+ this.globalSettings.mapView.background =
value as mapViewBackgrounVariantTypes;
- await this.saveSettings();
+ void this.saveSettings();
}),
);
@@ -2268,10 +2292,10 @@ export class SettingsManager {
[mapViewNodeMapOrientation.vertical]: t("vertical"),
})
.setValue(mapOrientation)
- .onChange(async (value) => {
- this.globalSettings!.mapView.mapOrientation =
+ .onChange((value) => {
+ this.globalSettings.mapView.mapOrientation =
value as mapViewNodeMapOrientation;
- await this.saveSettings();
+ void this.saveSettings();
}),
);
@@ -2288,10 +2312,10 @@ export class SettingsManager {
[mapViewArrowDirection.bothWay]: t("both-way"),
})
.setValue(arrowDirection)
- .onChange(async (value) => {
- this.globalSettings!.mapView.arrowDirection =
+ .onChange((value) => {
+ this.globalSettings.mapView.arrowDirection =
value as mapViewArrowDirection;
- await this.saveSettings();
+ void this.saveSettings();
}),
);
@@ -2307,10 +2331,10 @@ export class SettingsManager {
[mapViewEdgeType.bezier]: t("curved"),
})
.setValue(edgeType)
- .onChange(async (value) => {
- this.globalSettings!.mapView.edgeType =
+ .onChange((value) => {
+ this.globalSettings.mapView.edgeType =
value as mapViewEdgeType;
- await this.saveSettings();
+ void this.saveSettings();
}),
);
@@ -2318,9 +2342,9 @@ export class SettingsManager {
.setName(t("animate-links"))
.setDesc(t("animate-links-description"))
.addToggle((toggle) =>
- toggle.setValue(animatedEdges).onChange(async (value) => {
- this.globalSettings!.mapView.animatedEdges = value;
- await this.saveSettings();
+ toggle.setValue(animatedEdges).onChange((value) => {
+ this.globalSettings.mapView.animatedEdges = value;
+ void this.saveSettings();
}),
);
@@ -2328,9 +2352,9 @@ export class SettingsManager {
.setName(t("show-minimap"))
.setDesc(t("show-minimap-description"))
.addToggle((toggle) =>
- toggle.setValue(showMinimap).onChange(async (value) => {
- this.globalSettings!.mapView.showMinimap = value;
- await this.saveSettings();
+ toggle.setValue(showMinimap).onChange((value) => {
+ this.globalSettings.mapView.showMinimap = value;
+ void this.saveSettings();
}),
);
}
@@ -2352,7 +2376,7 @@ export class SettingsManager {
boundTaskCompletionToChildTasks,
autoAddCancelledDate,
autoAddCompletedDate,
- } = this.globalSettings!;
+ } = this.globalSettings;
new Setting(contentEl)
.setName(t("restrict-task-completion-to-child-tasks-and-sub-tasks"))
@@ -2360,10 +2384,10 @@ export class SettingsManager {
.addToggle((toggle) =>
toggle
.setValue(boundTaskCompletionToChildTasks)
- .onChange(async (value) => {
- this.globalSettings!.boundTaskCompletionToChildTasks =
+ .onChange((value) => {
+ this.globalSettings.boundTaskCompletionToChildTasks =
value;
- await this.saveSettings();
+ void this.saveSettings();
}),
);
@@ -2372,12 +2396,10 @@ export class SettingsManager {
.setName(t("auto-add-universal-date-to-tasks"))
.setDesc(t("auto-add-universal-date-to-tasks-info"))
.addToggle((toggle) =>
- toggle
- .setValue(autoAddUniversalDate)
- .onChange(async (value) => {
- this.globalSettings!.autoAddUniversalDate = value;
- await this.saveSettings();
- }),
+ toggle.setValue(autoAddUniversalDate).onChange((value) => {
+ this.globalSettings.autoAddUniversalDate = value;
+ void this.saveSettings();
+ }),
);
// Setting for Auto Adding Created Date while creating new Tasks through AddTaskModal
@@ -2385,9 +2407,9 @@ export class SettingsManager {
.setName(t("auto-add-created-date"))
.setDesc(t("auto-add-created-date-desc"))
.addToggle((toggle) =>
- toggle.setValue(autoAddCreatedDate).onChange(async (value) => {
- this.globalSettings!.autoAddCreatedDate = value;
- await this.saveSettings();
+ toggle.setValue(autoAddCreatedDate).onChange((value) => {
+ this.globalSettings.autoAddCreatedDate = value;
+ void this.saveSettings();
}),
);
@@ -2396,12 +2418,10 @@ export class SettingsManager {
.setName(t("auto-add-completed-date"))
.setDesc(t("auto-add-completed-date-desc"))
.addToggle((toggle) =>
- toggle
- .setValue(autoAddCompletedDate)
- .onChange(async (value) => {
- this.globalSettings!.autoAddCompletedDate = value;
- await this.saveSettings();
- }),
+ toggle.setValue(autoAddCompletedDate).onChange((value) => {
+ this.globalSettings.autoAddCompletedDate = value;
+ void this.saveSettings();
+ }),
);
// Setting for Auto Adding Created Date while creating new Tasks through AddTaskModal
@@ -2409,12 +2429,10 @@ export class SettingsManager {
.setName(t("auto-add-cancelled-date"))
.setDesc(t("auto-add-cancelled-date-desc"))
.addToggle((toggle) =>
- toggle
- .setValue(autoAddCancelledDate)
- .onChange(async (value) => {
- this.globalSettings!.autoAddCancelledDate = value;
- await this.saveSettings();
- }),
+ toggle.setValue(autoAddCancelledDate).onChange((value) => {
+ this.globalSettings.autoAddCancelledDate = value;
+ void this.saveSettings();
+ }),
);
// contentEl.createEl("h4", { text: t("compatible-plugins") });
@@ -2425,12 +2443,10 @@ export class SettingsManager {
.setName(t("daily-notes") + t("plugin-compatibility"))
.setDesc(t("daily-notes-plugin-compatibility"))
.addToggle((toggle) =>
- toggle
- .setValue(dailyNotesPluginComp)
- .onChange(async (value) => {
- this.globalSettings!.dailyNotesPluginComp = value;
- await this.saveSettings();
- }),
+ toggle.setValue(dailyNotesPluginComp).onChange((value) => {
+ this.globalSettings.dailyNotesPluginComp = value;
+ void this.saveSettings();
+ }),
);
// Setting for Auto Adding Due Date while creating new Tasks through AddTaskModal
@@ -2440,24 +2456,24 @@ export class SettingsManager {
.addToggle((toggle) =>
toggle
.setValue(compatiblePlugins.dayPlannerPlugin)
- .onChange(async (value) => {
- this.globalSettings!.compatiblePlugins.dayPlannerPlugin =
+ .onChange((value) => {
+ this.globalSettings.compatiblePlugins.dayPlannerPlugin =
value;
- await this.saveSettings();
+ void this.saveSettings();
}),
);
// Setting for choosing the default QuickAdd plugin run command
const communityPlugins = new CommunityPlugins(this.plugin);
if (!communityPlugins.isQuickAddPluginEnabled()) {
- this.globalSettings!.compatiblePlugins.quickAddPlugin = false;
- this.saveSettings();
+ this.globalSettings.compatiblePlugins.quickAddPlugin = false;
+ void this.saveSettings();
}
new Setting(contentEl)
.setName("QuickAdd " + t("plugin-compatibility"))
.setDesc(t("quickadd-plugin-compatibility-description"))
.addToggle((toggle) => {
- toggle.onChange(async (value) => {
+ toggle.onChange((value) => {
if (
this.globalSettings &&
!communityPlugins.isQuickAddPluginEnabled()
@@ -2471,7 +2487,7 @@ export class SettingsManager {
this.openReloadNoticeIfNeeded();
}
- await this.saveSettings();
+ void this.saveSettings();
});
// toggle.onClick();
})
@@ -2496,15 +2512,13 @@ export class SettingsManager {
this.app,
communityPlugins.quickAddPlugin,
);
- const onSelectCallback = async (
- selectedChoiceName: string,
- ) => {
+ const onSelectCallback = (selectedChoiceName: string) => {
if (this.globalSettings) {
this.globalSettings.quickAddPluginDefaultChoice =
selectedChoiceName;
}
text.setValue(selectedChoiceName);
- await this.saveSettings();
+ void this.saveSettings();
};
new MultiSuggest(
@@ -2515,7 +2529,7 @@ export class SettingsManager {
);
})
.setDisabled(
- !this.globalSettings!.compatiblePlugins.quickAddPlugin,
+ !this.globalSettings.compatiblePlugins.quickAddPlugin,
);
}
@@ -2537,10 +2551,11 @@ export class SettingsManager {
"Obsi " + t("app"),
);
- dropdown.setValue(notificationService as string);
- dropdown.onChange(async (value) => {
- this.globalSettings!.notificationService = value;
- await this.saveSettings();
+ dropdown.setValue(notificationService);
+ dropdown.onChange((value) => {
+ this.globalSettings.notificationService =
+ value as NotificationService;
+ void this.saveSettings();
});
});
}
@@ -2559,7 +2574,7 @@ export class SettingsManager {
firstDayOfWeek,
taskCompletionInLocalTime,
taskCompletionShowUtcOffset,
- } = this.globalSettings!;
+ } = this.globalSettings;
new Setting(contentEl)
.setName(t("universal-date"))
@@ -2572,11 +2587,11 @@ export class SettingsManager {
t("scheduled-date"),
[UniversalDateOptions.dueDate]: t("due-date"),
})
- .setValue(this.globalSettings!.universalDate)
- .onChange(async (value) => {
- this.globalSettings!.universalDate =
+ .setValue(this.globalSettings.universalDate)
+ .onChange((value) => {
+ this.globalSettings.universalDate =
value as UniversalDateOptions;
- await this.saveSettings();
+ void this.saveSettings();
}),
);
@@ -2607,10 +2622,11 @@ export class SettingsManager {
.addText((text) =>
text
.setValue(dateFormat)
- .onChange(async (value) => {
- this.globalSettings!.dateFormat = value;
- await this.saveSettings();
+ .onChange((value) => {
+ this.globalSettings.dateFormat = value;
+ void this.saveSettings();
})
+ // eslint-disable-next-line obsidianmd/ui/sentence-case
.setPlaceholder("yyyy-MM-dd"),
)
.addButton((btn) => {
@@ -2699,10 +2715,11 @@ export class SettingsManager {
.addText((text) =>
text
.setValue(dateTimeFormat)
- .onChange(async (value) => {
- this.globalSettings!.dateTimeFormat = value;
- await this.saveSettings();
+ .onChange((value) => {
+ this.globalSettings.dateTimeFormat = value;
+ void this.saveSettings();
})
+ // eslint-disable-next-line obsidianmd/ui/sentence-case
.setPlaceholder("yyyy-MM-dd/HH:mm"),
)
.addButton((btn) => {
@@ -2777,11 +2794,11 @@ export class SettingsManager {
.addText((text) =>
text
.setValue(defaultStartTime)
- .onChange(async (value) => {
- this.globalSettings!.defaultStartTime = value;
- await this.saveSettings();
+ .onChange((value) => {
+ this.globalSettings.defaultStartTime = value;
+ void this.saveSettings();
})
- .setPlaceholder("eg.: 00:00 or 23:59"),
+ .setPlaceholder("Eg.: 00:00 or 23:59"),
);
// Text input for the taskCompletionDateTimePattern
@@ -2791,10 +2808,10 @@ export class SettingsManager {
// .addText((text) =>
// text
// .setValue(taskCompletionDateTimePattern)
- // .onChange(async (value) => {
+ // .onChange((value) => {
// this.globalSettings!.taskCompletionDateTimePattern =
// value;
- // await this.saveSettings();
+ // void this.saveSettings();
// updatePreview();
// })
// .setPlaceholder("yyyy-MM-dd/HH:mm")
@@ -2805,9 +2822,9 @@ export class SettingsManager {
.setName(t("first-day-of-the-week"))
.setDesc(t("first-day-of-the-week-info"))
// .addText((text) =>
- // text.setValue(firstDayOfWeek).onChange(async (value) => {
+ // text.setValue(firstDayOfWeek).onChange((value) => {
// this.globalSettings!.firstDayOfWeek = value;
- // await this.saveSettings();
+ // void this.saveSettings();
// })
// );
.addDropdown((dropdown) => {
@@ -2820,9 +2837,9 @@ export class SettingsManager {
dropdown.addOption("7", t("saturday"));
dropdown.setValue(firstDayOfWeek as string);
- dropdown.onChange(async (value) => {
- this.globalSettings!.firstDayOfWeek = value;
- await this.saveSettings();
+ dropdown.onChange((value) => {
+ this.globalSettings.firstDayOfWeek = value;
+ void this.saveSettings();
});
});
@@ -2833,9 +2850,9 @@ export class SettingsManager {
// .addToggle((toggle) =>
// toggle
// .setValue(taskCompletionInLocalTime)
- // .onChange(async (value) => {
+ // .onChange((value) => {
// this.globalSettings!.taskCompletionInLocalTime = value;
- // await this.saveSettings();
+ // void this.saveSettings();
// }),
// );
@@ -2846,10 +2863,10 @@ export class SettingsManager {
// .addToggle((toggle) =>
// toggle
// .setValue(taskCompletionShowUtcOffset)
- // .onChange(async (value) => {
+ // .onChange((value) => {
// this.globalSettings!.taskCompletionShowUtcOffset =
// value;
- // await this.saveSettings();
+ // void this.saveSettings();
// }),
// );
}
@@ -2936,7 +2953,7 @@ const paypalButton = (link: string): HTMLElement => {
// };
const buyMeACoffeeButton = (link: string, img: HTMLElement): HTMLElement => {
- const a = document.createElement("a");
+ const a = activeDocument.createElement("a");
a.setAttribute("href", link);
a.addClass("buymeacoffee-tu2-atmanand-img");
a.appendChild(img);
@@ -2959,7 +2976,7 @@ const buyMeACoffeeButton = (link: string, img: HTMLElement): HTMLElement => {
// };
const kofiButton = (link: string, img: HTMLElement): HTMLElement => {
- const a = document.createElement("a");
+ const a = activeDocument.createElement("a");
a.setAttribute("href", link);
a.addClass("buymeacoffee-tu2-atmanand-img");
a.appendChild(img);
diff --git a/src/settings/SettingSynchronizer.ts b/src/settings/SettingSynchronizer.ts
index 0d889b29..bbb3aeaf 100644
--- a/src/settings/SettingSynchronizer.ts
+++ b/src/settings/SettingSynchronizer.ts
@@ -3,11 +3,12 @@ import { Notice } from "obsidian";
import TaskBoard from "../../main.js";
import { CURRENT_PLUGIN_VERSION } from "../interfaces/Constants.js";
import {
- PluginDataJson,
+ type PluginDataJson,
DEFAULT_SETTINGS,
} from "../interfaces/GlobalSettings.js";
import { bugReporterManagerInsatance } from "../managers/BugReporter.js";
import { fsPromises, NodePickedFile } from "../services/FileSystem.js";
+import { type ElectronOpenDialogReturnValue } from "obsidian-typings";
/**
* Recursively migrates settings by adding missing fields from defaults to settings.
@@ -16,22 +17,29 @@ import { fsPromises, NodePickedFile } from "../services/FileSystem.js";
* @param settings - The current settings object to migrate. Values from this object should be to the new objects.
* @returns The migrated settings object
*/
-export function migrateSettings(defaults: any, settings: any): PluginDataJson {
+export function migrateSettings(
+ defaults: Partial,
+ settings: Partial,
+): PluginDataJson {
try {
- if (settings == undefined) return defaults;
+ if (settings == undefined) return defaults as PluginDataJson;
+
+ const s = settings as Record;
+ const d = defaults as Record;
for (const key in defaults) {
if (!(key in settings)) {
// This is a cumpulsory migration which will be required in every new version update, since a new field should be added into the users settings.
- settings[key] = defaults[key];
+ s[key] = d[key];
}
if (key === "scanFilters") {
- if (settings[key]?.tags && settings[key].tags.length > 0) {
- const cleanedTags: string[] = settings[key].tags.map(
+ const scanFilter = s[key] as { tags: string[] };
+ if (scanFilter?.tags && scanFilter.tags.length > 0) {
+ const cleanedTags: string[] = scanFilter.tags.map(
(tag: string) => tag.trim().replace("#", ""),
);
- settings[key].tags = cleanedTags;
+ scanFilter.tags = cleanedTags;
}
}
@@ -44,7 +52,7 @@ export function migrateSettings(defaults: any, settings: any): PluginDataJson {
* This is migration is only applied to replace the older settings available in users configs with the new settings as per the new Settinsg section added in the global settings.
*/
if (key === "customStatuses") {
- settings[key] = DEFAULT_SETTINGS.data.customStatuses;
+ s[key] = DEFAULT_SETTINGS.data.customStatuses;
}
// -----------------------------------
@@ -55,9 +63,9 @@ export function migrateSettings(defaults: any, settings: any): PluginDataJson {
*
* Because of the name change, we had to do this migration.
*/
- if (key === "frontmatter" && settings["frontMatter"]) {
- settings[key] = settings["frontMatter"];
- delete settings["frontMatter"];
+ if (key === "frontmatter" && s["frontMatter"]) {
+ s[key] = s["frontMatter"];
+ delete s["frontMatter"];
}
// -------------------------------------
@@ -67,14 +75,14 @@ export function migrateSettings(defaults: any, settings: any): PluginDataJson {
* This is a cumpulsory case, which will recursively iterate all the object type settings.
*/
if (
- typeof defaults[key] === "object" &&
- defaults[key] !== null &&
- !Array.isArray(defaults[key])
+ typeof d[key] === "object" &&
+ d[key] !== null &&
+ !Array.isArray(d[key])
) {
- migrateSettings(defaults[key], settings[key]);
+ migrateSettings(d[key], s[key] as Partial);
}
}
- return settings;
+ return s as unknown as PluginDataJson;
} catch (error) {
bugReporterManagerInsatance.showNotice(
181,
@@ -82,8 +90,8 @@ export function migrateSettings(defaults: any, settings: any): PluginDataJson {
JSON.stringify(error),
"SettingSynchronizer.ts",
);
- if (settings != undefined) return settings;
- else return defaults;
+ if (settings != undefined) return settings as PluginDataJson;
+ else return defaults as PluginDataJson;
}
}
@@ -98,21 +106,25 @@ export async function exportConfigurations(plugin: TaskBoard): Promise {
// Desktop folder picker
if (
- (window as any).electron &&
- (window as any).electron.remote &&
- (window as any).electron.remote.dialog
+ window?.electron &&
+ window.electron?.remote &&
+ window.electron.dialog
) {
- let folderPaths: string[] = (
- window as any
- ).electron.remote.dialog.showOpenDialogSync({
- title: "Pick folder to export settings",
- properties: ["openDirectory", "dontAddToRecent"],
- });
- if (!folderPaths || folderPaths.length === 0) {
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
+ let pickFolderDialogReturn: ElectronOpenDialogReturnValue =
+ await window.electron.dialog.showOpenDialog({
+ title: "Pick folder to export settings",
+ properties: ["openDirectory", "dontAddToRecent"],
+ });
+ if (
+ pickFolderDialogReturn.canceled ||
+ !pickFolderDialogReturn?.filePaths ||
+ pickFolderDialogReturn.filePaths.length === 0
+ ) {
new Notice("Export cancelled or folder not selected.");
return;
}
- const folderPath = folderPaths[0];
+ const folderPath = pickFolderDialogReturn.filePaths[0];
const exportPath =
folderPath.endsWith("/") || folderPath.endsWith("\\")
? folderPath + exportFileName
@@ -123,20 +135,18 @@ export async function exportConfigurations(plugin: TaskBoard): Promise {
new Notice(`Settings exported to ${exportPath}`);
} else {
// Web: use file save dialog
- let a = document.createElement("a");
+ let a = activeDocument.createElement("a");
a.href = URL.createObjectURL(
new Blob([fileContent], { type: "application/json" }),
);
a.download = exportFileName;
- document.body.appendChild(a);
+ activeDocument.body.appendChild(a);
a.click();
- setTimeout(() => {
- document.body.removeChild(a);
+ window.setTimeout(() => {
+ activeDocument.body.removeChild(a);
URL.revokeObjectURL(a.href);
}, 1000);
- new Notice(
- "Settings exported. Check the folder where you downloaded the file.",
- );
+ new Notice(`Settings exported to ${exportFileName}. Check the folder where you saved the file.`);
}
} catch (err) {
new Notice("Failed to export settings.");
@@ -160,41 +170,46 @@ export async function importConfigurations(
let extensions = ["json"];
let name = "JSON Files";
- // Desktop file picker
+ // Desktop folder picker
if (
- (window as any).electron &&
- (window as any).electron.remote &&
- (window as any).electron.remote.dialog
+ window?.electron &&
+ window.electron?.remote &&
+ window.electron.dialog
) {
- let filePaths: string[] = (
- window as any
- ).electron.remote.dialog.showOpenDialogSync({
- title: "Pick settings file to import",
- properties: ["openFile", "dontAddToRecent"],
- filters: [{ name, extensions }],
- });
- if (!filePaths || filePaths.length === 0) {
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
+ let pickFileDialogReturn: ElectronOpenDialogReturnValue =
+ await window.electron.dialog.showOpenDialog({
+ title: "Pick settings file to import",
+ properties: ["openDirectory", "dontAddToRecent"],
+ });
+ if (
+ pickFileDialogReturn.canceled ||
+ !pickFileDialogReturn?.filePaths ||
+ pickFileDialogReturn.filePaths.length === 0
+ ) {
new Notice("Import cancelled or file not selected.");
return false;
}
- const pickedFile = new NodePickedFile(filePaths[0]);
+ const pickedFile = new NodePickedFile(
+ pickFileDialogReturn.filePaths[0],
+ );
importedContent = await pickedFile.readText();
} else {
// Web file picker
await new Promise((resolve) => {
- let inputEl = document.createElement("input");
+ let inputEl = activeDocument.createElement("input");
inputEl.type = "file";
inputEl.accept = extensions
.map((e) => "." + e.toLowerCase())
.join(",");
- inputEl.addEventListener("change", async () => {
+ inputEl.addEventListener("change", () => {
if (!inputEl.files || inputEl.files.length === 0) {
new Notice("Import cancelled or file not selected.");
resolve();
return;
}
const file = inputEl.files[0];
- importedContent = await file.text();
+ importedContent = void file.text();
resolve();
});
inputEl.click();
@@ -205,7 +220,8 @@ export async function importConfigurations(
}
}
- const importedData: PluginDataJson = JSON.parse(importedContent);
+ const parsedData: unknown = JSON.parse(importedContent);
+ const importedData = parsedData as PluginDataJson;
// Get current settings and defaults
// const currentData = plugin.settings; // No use, current settings will be overwritten, hence will use the DEFAULT_SETTINGS
diff --git a/src/settings/TaskBoardSettingTab.ts b/src/settings/TaskBoardSettingTab.ts
index 9458753c..497dab9e 100644
--- a/src/settings/TaskBoardSettingTab.ts
+++ b/src/settings/TaskBoardSettingTab.ts
@@ -20,12 +20,12 @@ export class TaskBoardSettingTab extends PluginSettingTab {
}
// Display the settings in the settings tab
- async display(): Promise {
+ display(): void {
const { containerEl } = this;
containerEl.empty();
containerEl.addClass("TaskBoardSettingTab");
- this.settingsManager.constructUI(containerEl, t("task-board"));
+ void this.settingsManager.constructUI(containerEl, t("task-board"));
}
hide(): void {
diff --git a/src/taskboardAPIs.ts b/src/taskboardAPIs.ts
index 1efb347f..ad64fe7e 100644
--- a/src/taskboardAPIs.ts
+++ b/src/taskboardAPIs.ts
@@ -5,7 +5,6 @@ import TaskBoard from "../main.js";
import { bugReporterManagerInsatance } from "./managers/BugReporter.js";
import { TaskEditorModal } from "./modals/TaskEditorModal.js";
-
/**
* TaskBoardApi provides external plugins with a public API to interact with Task Board functionality.
* This class exposes methods that allow other Obsidian plugins to integrate with Task Board features.
@@ -103,7 +102,7 @@ export class TaskBoardApi {
try {
const AddTaskModal = new TaskEditorModal(
plugin,
- (newTask, quickAddPluginChoice) => {
+ async () => {
// Task save callback - handled by modal's onSave event
},
isTaskNote,
diff --git a/src/types/obsidian-ex.d.ts b/src/typings/obsidian-ex.d.ts
similarity index 86%
rename from src/types/obsidian-ex.d.ts
rename to src/typings/obsidian-ex.d.ts
index 9f7a678d..21b5de6b 100644
--- a/src/types/obsidian-ex.d.ts
+++ b/src/typings/obsidian-ex.d.ts
@@ -1,18 +1,39 @@
import "obsidian";
import { EditorView, ViewUpdate } from "@codemirror/view";
import { Extension } from "@codemirror/state";
-import { App as obsidianApp, FoldInfo, Vault as obsidianVault } from "obsidian";
import {
+ App as obsidianApp,
+ FoldInfo,
+ Vault as obsidianVault,
+ MetadataCache,
+ Workspace,
+ Events,
+} from "obsidian";
+import {
+ // App,
Editor,
EditorRange,
EditorSuggest,
MarkdownFileInfo,
TFile,
+ Menu,
+ TAbstractFile,
+ Component,
+ UserEvent,
+ MarkdownView,
Setting,
- Vault,
+ CachedMetadata,
+ Tasks,
} from "obsidian";
-import { InternalPlugins, Plugins } from "obsidian-typings";
-import { Component } from "obsidian";
+import {
+ InternalPlugins,
+ Plugins,
+ Keymap,
+ EventRef,
+ WorkspaceWindow,
+ FileManager,
+ Scope,
+} from "obsidian-typings";
interface Token extends EditorRange {
/** @todo Documentation incomplete. */
@@ -80,7 +101,7 @@ interface MarkdownBaseView extends Component {
/**
* Reference to the app.
*/
- app: App;
+ app: obsidianApp;
/**
* Callback to clear all elements.
@@ -302,6 +323,12 @@ interface MarkdownBaseView extends Component {
updateOptions(): void;
}
+export class ExtendedMetadataCache extends MetadataCache {}
+
+export class ExtendedWorkspace extends Workspace {}
+
+export class CustomWorkspaceEvents extends Events {}
+
declare module "obsidian" {
interface App extends obsidianApp {
title: string;
@@ -316,7 +343,7 @@ declare module "obsidian" {
/** @public */
scope: Scope;
/** @public */
- vault: ExtendedVault;
+ vault: Vault;
/** @public */
fileManager: FileManager;
/**
@@ -329,10 +356,9 @@ declare module "obsidian" {
plugins: Plugins;
- customCss: any;
+ customCss: unknown;
- viewRegistry: any;
- embedRegistry: EmbedRegistry;
+ viewRegistry: unknown;
/** @public */
metadataCache: ExtendedMetadataCache;
@@ -342,7 +368,7 @@ declare module "obsidian" {
name: K,
callback: (
...args: Parameters
- ) => void
+ ) => void,
): EventRef;
trigger(
name: K,
@@ -352,41 +378,53 @@ declare module "obsidian" {
// Inbuilt
on(
name: "quick-preview",
- callback: (file: TFile, data: string) => any,
- ctx?: any
+ callback: (file: TFile, data: string) => unknown,
+ ctx?: unknown,
+ ): EventRef;
+ on(
+ name: "resize",
+ callback: () => unknown,
+ ctx?: unknown,
): EventRef;
- on(name: "resize", callback: () => any, ctx?: any): EventRef;
on(
name: "active-leaf-change",
- callback: (leaf: WorkspaceLeaf | null) => any,
- ctx?: any
+ callback: (leaf: WorkspaceLeaf | null) => unknown,
+ ctx?: unknown,
): EventRef;
on(
name: "file-open",
- callback: (file: TFile | null) => any,
- ctx?: any
+ callback: (file: TFile | null) => unknown,
+ ctx?: unknown,
+ ): EventRef;
+ on(
+ name: "layout-change",
+ callback: () => unknown,
+ ctx?: unknown,
): EventRef;
- on(name: "layout-change", callback: () => any, ctx?: any): EventRef;
on(
name: "window-open",
- callback: (win: WorkspaceWindow, window: Window) => any,
- ctx?: any
+ callback: (win: WorkspaceWindow, window: Window) => unknown,
+ ctx?: unknown,
): EventRef;
on(
name: "window-close",
- callback: (win: WorkspaceWindow, window: Window) => any,
- ctx?: any
+ callback: (win: WorkspaceWindow, window: Window) => unknown,
+ ctx?: unknown,
+ ): EventRef;
+ on(
+ name: "css-change",
+ callback: () => unknown,
+ ctx?: unknown,
): EventRef;
- on(name: "css-change", callback: () => any, ctx?: any): EventRef;
on(
name: "file-menu",
callback: (
menu: Menu,
file: TAbstractFile,
source: string,
- leaf?: WorkspaceLeaf
- ) => any,
- ctx?: any
+ leaf?: WorkspaceLeaf,
+ ) => unknown,
+ ctx?: unknown,
): EventRef;
on(
name: "files-menu",
@@ -394,71 +432,71 @@ declare module "obsidian" {
menu: Menu,
files: TAbstractFile[],
source: string,
- leaf?: WorkspaceLeaf
- ) => any,
- ctx?: any
+ leaf?: WorkspaceLeaf,
+ ) => unknown,
+ ctx?: unknown,
): EventRef;
on(
name: "url-menu",
- callback: (menu: Menu, url: string) => any,
- ctx?: any
+ callback: (menu: Menu, url: string) => unknown,
+ ctx?: unknown,
): EventRef;
on(
name: "editor-menu",
callback: (
menu: Menu,
editor: Editor,
- info: MarkdownView | MarkdownFileInfo
- ) => any,
- ctx?: any
+ info: MarkdownView | MarkdownFileInfo,
+ ) => unknown,
+ ctx?: unknown,
): EventRef;
on(
name: "editor-change",
callback: (
editor: Editor,
- info: MarkdownView | MarkdownFileInfo
- ) => any,
- ctx?: any
+ info: MarkdownView | MarkdownFileInfo,
+ ) => unknown,
+ ctx?: unknown,
): EventRef;
on(
name: "editor-paste",
callback: (
evt: ClipboardEvent,
editor: Editor,
- info: MarkdownView | MarkdownFileInfo
- ) => any,
- ctx?: any
+ info: MarkdownView | MarkdownFileInfo,
+ ) => unknown,
+ ctx?: unknown,
): EventRef;
on(
name: "editor-drop",
callback: (
evt: DragEvent,
editor: Editor,
- info: MarkdownView | MarkdownFileInfo
- ) => any,
- ctx?: any
+ info: MarkdownView | MarkdownFileInfo,
+ ) => unknown,
+ ctx?: unknown,
): EventRef;
on(
name: "quit",
- callback: (tasks: Tasks) => any,
- ctx?: any
+ callback: (tasks: Tasks) => unknown,
+ ctx?: unknown,
): EventRef;
};
}
interface DropdownComponent {
type: string;
- style: any;
+ style: unknown;
value: string;
}
interface ExternalPlugins {
app: App;
- enabledPlugins: any;
- loadingPluginId: any;
- manifests: any;
- plugins: any;
- updates: any;
+ enabledPlugins: unknown;
+ loadingPluginId: unknown;
+ manifests: unknown;
+ plugins: unknown;
+ updates: unknown;
}
interface Editor {
@@ -466,26 +504,30 @@ declare module "obsidian" {
}
interface MetadataTypeManager {
- properties: Record;
+ properties: Record;
}
interface EmbedRegistry {
embedByExtension: {
- md: (args: any, file: TFile, subpath: string) => WidgetEditorView;
+ md: (
+ args: unknown,
+ file: TFile,
+ subpath: string,
+ ) => WidgetEditorView;
};
}
export interface Vault extends obsidianVault {
- config: any;
+ config: unknown;
getMarkdownFiles: () => TFile[];
- getConfig(key: string): any;
+ getConfig(key: string): unknown;
// Custom
recurseChildrenAC: (
origin: TAbstractFile,
- traverse: (file: TAbstractFile) => void
+ traverse: (file: TAbstractFile) => void,
) => void;
}
@@ -504,18 +546,14 @@ declare module "obsidian" {
setWarning(warning: boolean): this;
}
- interface ExtendedSetting extends Settings {
+ interface ExtendedSetting extends Setting {
open(): void;
openTabById(tabId: string): void;
}
interface Commands {
executeCommandById(commandId: string): void;
- executeCommandById(commandId: string, ...args: any[]): void;
- }
-
- interface Component {
- _loaded: boolean;
+ executeCommandById(commandId: string, ...args: unknown[]): void;
}
interface WorkspaceLeaf {
@@ -526,6 +564,7 @@ declare module "obsidian" {
tabHeaderInnerIconEl: HTMLElement;
tabHeaderInnerTitleEl: HTMLElement;
id: string;
+ taskboardFilePath: string; // Custom field for this plugin
}
interface MarkdownScrollableEditView extends MarkdownBaseView {
diff --git a/src/types/react-beautiful-dnd.d.ts b/src/typings/react-beautiful-dnd.d.ts
similarity index 100%
rename from src/types/react-beautiful-dnd.d.ts
rename to src/typings/react-beautiful-dnd.d.ts
diff --git a/src/utils/CheckBoxUtils.ts b/src/utils/CheckBoxUtils.ts
index bdf43f21..89f5c39a 100644
--- a/src/utils/CheckBoxUtils.ts
+++ b/src/utils/CheckBoxUtils.ts
@@ -16,7 +16,7 @@ import { TaskRegularExpressions } from "../regularExpressions/TasksPluginRegular
export function checkboxStateSwitcher(
customStatuses: CustomStatus[],
symbol: string,
-): { newSymbol: string; newSymbolType: string } {
+): { newSymbol: string; newSymbolType: statusTypeNames } {
// Check if customStatuses is available and has entries
if (customStatuses?.length > 0) {
const oldStatus = customStatuses.find(
@@ -36,7 +36,7 @@ export function checkboxStateSwitcher(
}
new Notice(
- "customStatuses are not available or empty. Please check your settings. Falling back to default behavior.",
+ "Custom statuses are not available or empty. Please check your settings. Falling back to default behavior.",
);
// Default fallback behavior
return symbol === "x" || symbol === "X"
@@ -92,8 +92,8 @@ export function isTaskCompleted(
// console.log("customStatus :", customStatus, "\nsymbol :", symbol);
if (
customStatus.symbol === symbol &&
- (customStatus.type === "DONE" ||
- customStatus.type === "CANCELLED")
+ (customStatus.type === statusTypeNames.DONE ||
+ customStatus.type === statusTypeNames.CANCELLED)
) {
flag = true;
return true;
@@ -106,8 +106,8 @@ export function isTaskCompleted(
tasksPluginStatusConfigs.some((customStatus: CustomStatus) => {
if (
customStatus.symbol === titleOrSymbol &&
- (customStatus.type === "DONE" ||
- customStatus.type === "CANCELLED")
+ (customStatus.type === statusTypeNames.DONE ||
+ customStatus.type === statusTypeNames.CANCELLED)
) {
flag = true;
return true;
@@ -142,7 +142,7 @@ export function extractCheckboxSymbol(task: string): string {
const match = task.match(/\[(.)\]/); // Extract the symbol inside [ ]
if (!match || match.length < 2) return " ";
- return match[1]!;
+ return match[1];
}
/**
@@ -169,16 +169,17 @@ export function getObsidianIndentationSetting(plugin: TaskBoard): string {
// Fallback: try to read the vault's .obsidian/app.json to get tabSize / useTab
try {
const path = `${plugin.app.vault.configDir}/app.json`;
- plugin.app.vault.adapter.read(path).then((content: string) => {
- const parsed = JSON.parse(content || "{}");
- if (parsed?.useTab === undefined) {
+ // Cast JSON.parse result to avoid unsafe any access
+ void plugin.app.vault.adapter.read(path).then((content: string) => {
+ const parsed = JSON.parse(content || "{}") as Record;
+ if (parsed.useTab === undefined) {
// Obsidian has not initialized any settings, hence they will be undefined
// So return the following default settings of Obsidian.
return `\t`;
} else {
- if (typeof parsed?.tabSize === "number") {
- const tabSize = parsed.tabSize;
- return parsed?.useTab ? `\t` : " ".repeat(tabSize);
+ if (typeof parsed.tabSize === "number") {
+ const tabSize: number = parsed.tabSize;
+ return parsed.useTab ? `\t` : " ".repeat(tabSize);
}
return `\t`;
@@ -215,10 +216,11 @@ export async function getObsidianIndentationSettingAsync(
try {
const path = `${plugin.app.vault.configDir}/app.json`;
const content: string = await plugin.app.vault.adapter.read(path);
- const parsed = JSON.parse(content || "{}");
+ // Cast JSON.parse result to avoid unsafe any access
+ const parsed = JSON.parse(content) as Record;
const tabSize =
- typeof parsed?.tabSize === "number" ? parsed.tabSize : 4;
- const useTab = !!parsed?.useTab;
+ typeof parsed.tabSize === "number" ? parsed.tabSize : 4;
+ const useTab = !!parsed.useTab;
return useTab ? `\t` : " ".repeat(tabSize);
} catch (err) {
bugReporterManagerInsatance.addToLogs(
diff --git a/src/utils/DateTimeCalculations.ts b/src/utils/DateTimeCalculations.ts
index 17db112c..41230061 100644
--- a/src/utils/DateTimeCalculations.ts
+++ b/src/utils/DateTimeCalculations.ts
@@ -7,7 +7,10 @@ import {
} from "date-fns";
import { moment as _moment } from "obsidian";
import { bugReporterManagerInsatance } from "../managers/BugReporter.js";
-import { DEFAULT_DATE_FORMAT, DEFAULT_DATE_TIME_FORMAT } from "../interfaces/Constants.js";
+import {
+ DEFAULT_DATE_FORMAT,
+ DEFAULT_DATE_TIME_FORMAT,
+} from "../interfaces/Constants.js";
import { UniversalDateOptions } from "../interfaces/Enums.js";
import { taskItem } from "../interfaces/TaskItem.js";
@@ -306,7 +309,7 @@ export function getAllDatesInRelativeRange(
* @returns The universal date of the task as a string, or an empty string if not set. */
export const getUniversalDateFromTask = (
task: taskItem,
- universalDateType: string,
+ universalDateType: UniversalDateOptions,
): string => {
// Method 1 - Comparing
if (universalDateType === UniversalDateOptions.dueDate) {
@@ -338,7 +341,9 @@ export const getUniversalDateFromTask = (
* @param plugin - The TaskBoard plugin object.
* @returns An emoji representing the universal date type, or an empty string if not set.
*/
-export const getUniversalDateEmoji = (universalDateSetting: string): string => {
+export const getUniversalDateEmoji = (
+ universalDateSetting: UniversalDateOptions,
+): string => {
if (universalDateSetting === UniversalDateOptions.dueDate) {
return "📅";
} else if (universalDateSetting === UniversalDateOptions.scheduledDate) {
diff --git a/src/utils/JsonFileOperations.ts b/src/utils/JsonFileOperations.ts
index 5af757b2..a4fa359d 100644
--- a/src/utils/JsonFileOperations.ts
+++ b/src/utils/JsonFileOperations.ts
@@ -121,7 +121,10 @@ export const loadJsonCacheDataFromDisk = async (
path = plugin.settings.data.tasksCacheFilePath;
}
const data: string = await plugin.app.vault.adapter.read(path);
- const cacheData: jsonCacheData = JSON.parse(data);
+ // JSON.parse() is untyped by default, so we narrow it to `unknown`
+ // before we cast to the known cache structure used by the plugin.
+ const parsedData: unknown = JSON.parse(data);
+ const cacheData = parsedData as jsonCacheData;
// const allTasks = {
// Pending: cacheData.Pending,
// Completed: cacheData.Completed,
@@ -202,7 +205,7 @@ const writeFileWithRetry = async (
`File write timeout due to following error: ${String(error)}....retrying again...`,
"TaskItemEventHandlers.ts/writeFileWithRetry",
);
- await new Promise((resolve) => setTimeout(resolve, delay));
+ await new Promise((resolve) => window.setTimeout(resolve, delay));
}
}
};
@@ -258,55 +261,43 @@ export const writeJsonCacheDataToDisk = async (
};
// Function to move the file from old path to new path
-export const moveTasksCacheFileToNewPath = (
+export const moveTasksCacheFileToNewPath = async (
app: App,
oldPath: string,
newPath: string,
-) => {
- return new Promise(async (resolve, reject) => {
- if (
- oldPath === newPath ||
- (newPath !== "" && newPath.endsWith(".json") === false) ||
- (oldPath !== "" && oldPath.endsWith(".json") === false)
- ) {
- resolve(true);
- return true;
- }
+): Promise => {
+ if (
+ oldPath === newPath ||
+ (newPath !== "" && newPath.endsWith(".json") === false) ||
+ (oldPath !== "" && oldPath.endsWith(".json") === false)
+ ) {
+ return true;
+ }
- // Check if the directory exists, create if not
- const parts = newPath.split("/");
- if (parts.length > 1) {
- const dirPath = parts.slice(0, -1).join("/").trim();
- if (!(await app.vault.adapter.exists(dirPath))) {
- await createFolderRecursively(app, dirPath);
- }
+ // Check if the directory exists, create if not
+ const parts = newPath.split("/");
+ if (parts.length > 1) {
+ const dirPath = parts.slice(0, -1).join("/").trim();
+ if (!(await app.vault.adapter.exists(dirPath))) {
+ await createFolderRecursively(app, dirPath);
}
+ }
- if (newPath === "")
- newPath = `${app.vault.configDir}/plugins/task-board/tasks.json`;
- if (oldPath === "")
- oldPath = `${app.vault.configDir}/plugins/task-board/tasks.json`;
- app.vault.adapter
- .rename(oldPath, newPath)
- // .then(() => {
- // // Update the tasksCacheFilePath in globalSettings
- // plugin.settings.data.tasksCacheFilePath =
- // newPath;
- // // Save the updated settings
- // return plugin.saveSettings();
- // })
- .then(() => resolve(true))
- .catch((error) => {
- bugReporterManagerInsatance.showNotice(
- 73,
- "Failed to move tasks.json file to new path",
- String(error),
- "JsonFileOperations.ts/moveTasksCacheFileToNewPath",
- );
- reject(error);
- return false;
- });
+ if (newPath === "")
+ newPath = `${app.vault.configDir}/plugins/task-board/tasks.json`;
+ if (oldPath === "")
+ oldPath = `${app.vault.configDir}/plugins/task-board/tasks.json`;
+ await app.vault.adapter.rename(oldPath, newPath).catch((error) => {
+ bugReporterManagerInsatance.showNotice(
+ 73,
+ "Failed to move tasks.json file to new path",
+ String(error),
+ "JsonFileOperations.ts/moveTasksCacheFileToNewPath",
+ );
+ return false;
});
+
+ return true;
};
// Helper function to load tasks from tasks.json and merge them
@@ -319,6 +310,7 @@ export const loadTasksAndMerge = async (
if (hardRefresh) {
allTasks = await loadJsonCacheDataFromDisk(plugin);
} else {
+ // eslint-disable-next-line @typescript-eslint/no-deprecated
allTasks = await loadJsonCacheData(plugin);
}
// const pendingTasks: taskItem[] = [];
diff --git a/src/utils/MarkdownFileOperations.ts b/src/utils/MarkdownFileOperations.ts
index 58ecc1ba..ba8e7821 100644
--- a/src/utils/MarkdownFileOperations.ts
+++ b/src/utils/MarkdownFileOperations.ts
@@ -30,7 +30,9 @@ export const readDataOfVaultFile = async (
// `File not found at path: ${filePath}`,
// "MarkdownFileOperations.ts/readDataOfVaultFile",
// );
- throw `File not found at path: ${filePath}, file object : ${JSON.stringify(file)}`;
+ throw new Error(
+ `File not found at path: ${filePath}, file object : ${JSON.stringify(file)}`,
+ );
}
} catch (error) {
if (showBugNotice) {
@@ -76,7 +78,7 @@ export const writeDataToVaultFile = async (
// `File not found at path.\nPath: ${filePath}`,
// "MarkdownFileOperations.ts/writeDataToVaultFile",
// );
- throw `File not found at path: ${filePath}`;
+ throw new Error(`File not found at path: ${filePath}`);
}
return;
} catch (error) {
diff --git a/src/utils/TaskItemCacheOperations.ts b/src/utils/TaskItemCacheOperations.ts
index 2cb0405d..eccd7e34 100644
--- a/src/utils/TaskItemCacheOperations.ts
+++ b/src/utils/TaskItemCacheOperations.ts
@@ -43,7 +43,7 @@ export const moveFromPendingToCompleted = async (
if (!allTasks.Completed[task.filePath]) {
allTasks.Completed[task.filePath] = [];
}
- allTasks.Completed[task.filePath]!.push(task);
+ allTasks.Completed[task.filePath].push(task);
}
// Write the updated data back to the JSON file
@@ -82,7 +82,7 @@ export const moveFromCompletedToPending = async (
if (!allTasks.Pending[task.filePath]) {
allTasks.Pending[task.filePath] = [];
}
- allTasks.Pending[task.filePath]!.push(task);
+ allTasks.Pending[task.filePath].push(task);
}
// Write the updated data back to the JSON file
@@ -201,12 +201,12 @@ export const deleteTaskFromJson = async (plugin: TaskBoard, task: taskItem) => {
if (allTasks.Pending[task.filePath]) {
allTasks.Pending[task.filePath] = allTasks.Pending[
task.filePath
- ].filter((t: any) => t.id !== task.id);
+ ].filter((t: taskItem) => t.id !== task.id);
}
if (allTasks.Completed[task.filePath]) {
allTasks.Completed[task.filePath] = allTasks.Completed[
task.filePath
- ].filter((t: any) => t.id !== task.id);
+ ].filter((t: taskItem) => t.id !== task.id);
}
await writeJsonCacheDataToDisk(plugin, allTasks);
diff --git a/src/utils/TaskItemUtils.ts b/src/utils/TaskItemUtils.ts
index d1bb6719..45d8cba9 100644
--- a/src/utils/TaskItemUtils.ts
+++ b/src/utils/TaskItemUtils.ts
@@ -113,7 +113,7 @@ export function generateTaskId(plugin: TaskBoard): string {
plugin.settings.data.uniqueIdCounter + 1 || 0;
// Save the updated uniqueIdCounter back to settings
- plugin.saveSettings();
+ void plugin.saveSettings();
// Return the current counter value and then increment it for the next ID
return String(plugin.settings.data.uniqueIdCounter);
}
@@ -145,7 +145,7 @@ export const applyIdToTaskItem = async (
newId = generateTaskId(plugin);
task.legacyId = newId;
}
- updateFrontmatterInMarkdownFile(plugin, task, true);
+ void updateFrontmatterInMarkdownFile(plugin, task, true);
return newId;
}
diff --git a/src/utils/UserTaskEvents.ts b/src/utils/UserTaskEvents.ts
index 377256df..7a91b01f 100644
--- a/src/utils/UserTaskEvents.ts
+++ b/src/utils/UserTaskEvents.ts
@@ -4,17 +4,36 @@ import { WorkspaceLeaf, TFile, Notice } from "obsidian";
import { t } from "i18next";
import TaskBoard from "../../main.js";
-import { EditButtonMode, statusTypeNames, UniversalDateOptions } from "../interfaces/Enums.js";
+import {
+ EditButtonMode,
+ statusTypeNames,
+ UniversalDateOptions,
+} from "../interfaces/Enums.js";
import { globalSettingsData } from "../interfaces/GlobalSettings.js";
import { taskItem, UpdateTaskEventData } from "../interfaces/TaskItem.js";
import { bugReporterManagerInsatance } from "../managers/BugReporter.js";
import { eventEmitter } from "../services/EventEmitter.js";
-import { openEditTaskNoteModal, openEditTaskModal, openEditTaskView } from "../services/OpenModals.js";
+import {
+ openEditTaskNoteModal,
+ openEditTaskModal,
+ openEditTaskView,
+} from "../services/OpenModals.js";
import { openTasksPluginEditModal } from "../services/tasks-plugin/helpers.js";
import { verifySubtasksAndChildtasksAreComplete } from "./algorithms/ScanningFilterer.js";
-import { sanitizeStatus, sanitizePriority, sanitizeStartDate, sanitizeScheduledDate, sanitizeDueDate, sanitizeReminder, sanitizeTags } from "./taskLine/TaskContentFormatter.js";
+import {
+ sanitizeStatus,
+ sanitizePriority,
+ sanitizeStartDate,
+ sanitizeScheduledDate,
+ sanitizeDueDate,
+ sanitizeReminder,
+ sanitizeTags,
+} from "./taskLine/TaskContentFormatter.js";
import { updateTaskInFile } from "./taskLine/TaskLineUtils.js";
-import { isTaskNotePresentInTags, updateFrontmatterInMarkdownFile } from "./taskNote/TaskNoteUtils.js";
+import {
+ isTaskNotePresentInTags,
+ updateFrontmatterInMarkdownFile,
+} from "./taskNote/TaskNoteUtils.js";
/**
* Handle edit task event when user click on the edit task button. Depends on the configurations, it will either open the edit task modal, edit task view, directly open the inline-task in note and highlight the task or also open the edit task modal of tasks plugin.
@@ -25,7 +44,7 @@ import { isTaskNotePresentInTags, updateFrontmatterInMarkdownFile } from "./task
export const handleEditTask = (
plugin: TaskBoard,
task: taskItem,
- settingOption: string,
+ settingOption: EditButtonMode,
) => {
const taskNoteIdentifierTag = plugin.settings.data.taskNoteIdentifierTag;
const isThisATaskNote = isTaskNotePresentInTags(
@@ -41,7 +60,7 @@ export const handleEditTask = (
}
break;
case EditButtonMode.ViewInSplitTab:
- openEditTaskView(
+ void openEditTaskView(
plugin,
isThisATaskNote,
false,
@@ -52,7 +71,7 @@ export const handleEditTask = (
);
break;
case EditButtonMode.ViewInWindow:
- openEditTaskView(
+ void openEditTaskView(
plugin,
isThisATaskNote,
false,
@@ -66,19 +85,19 @@ export const handleEditTask = (
if (isThisATaskNote) {
openEditTaskNoteModal(plugin, task);
} else {
- openTasksPluginEditModal(plugin, task);
+ void openTasksPluginEditModal(plugin, task);
}
break;
case EditButtonMode.NoteInTab: {
- openFileAndHighlightTask(plugin, task, settingOption);
+ void openFileAndHighlightTask(plugin, task, settingOption);
break;
}
case EditButtonMode.NoteInSplit: {
- openFileAndHighlightTask(plugin, task, settingOption);
+ void openFileAndHighlightTask(plugin, task, settingOption);
break;
}
case EditButtonMode.NoteInWindow: {
- openFileAndHighlightTask(plugin, task, settingOption);
+ void openFileAndHighlightTask(plugin, task, settingOption);
break;
}
default:
@@ -105,7 +124,7 @@ export const handleEditTask = (
export const openFileAndHighlightTask = async (
plugin: TaskBoard,
task: taskItem,
- mode: string,
+ mode: EditButtonMode,
) => {
const file = plugin.app.vault.getAbstractFileByPath(task.filePath);
let leaf: WorkspaceLeaf | null = null;
@@ -229,16 +248,23 @@ export const updateTaskItemStatus = async (
taskOld.tags,
);
if (isThisTaskNote) {
- updateFrontmatterInMarkdownFile(plugin, newTask).then(() => {
- sleep(1000).then(() => {
- // TODO : Is 1 sec really required ?
- // This is required to rescan the updated file and refresh the board.
- plugin.realTimeScanner.processAllUpdatedFiles(
- taskOld.filePath,
- taskOld.id,
- );
- });
- });
+ updateFrontmatterInMarkdownFile(plugin, newTask)
+ .then(() => {
+ window.setTimeout(() => {
+ // TODO : Is 1 sec really required ?
+ // This is required to rescan the updated file and refresh the board.
+ plugin.realTimeScanner
+ .processAllUpdatedFiles(taskOld.filePath, taskOld.id)
+ .catch((error) => {
+ bugReporterManagerInsatance.addToLogs(
+ 217,
+ String(error),
+ "UserTaskEvents.ts/udateTaskItemStatus",
+ );
+ });
+ }, 1000);
+ })
+ .catch((error) => {});
} else {
newTask.title = sanitizeStatus(
plugin.settings.data,
@@ -246,11 +272,16 @@ export const updateTaskItemStatus = async (
newStatus,
statusType,
);
- updateTaskInFile(plugin, newTask, taskOld).then((newId) => {
- plugin.realTimeScanner.processAllUpdatedFiles(
- taskOld.filePath,
- taskOld.id,
- );
+ void updateTaskInFile(plugin, newTask, taskOld).then((newId) => {
+ plugin.realTimeScanner
+ .processAllUpdatedFiles(taskOld.filePath, taskOld.id)
+ .catch((error) => {
+ bugReporterManagerInsatance.addToLogs(
+ 217,
+ String(error),
+ "UserTaskEvents.ts/udateTaskItemStatus",
+ );
+ });
});
}
};
@@ -272,7 +303,7 @@ export const updateTaskItemPriority = (
taskUpdated: taskItem,
newPriority: number,
) => {
- let newTask = { ...taskUpdated } as taskItem;
+ let newTask = { ...taskUpdated };
newTask.priority = newPriority;
let eventData = {
@@ -287,13 +318,18 @@ export const updateTaskItemPriority = (
);
if (isThisTaskNote) {
- updateFrontmatterInMarkdownFile(plugin, newTask).then(() => {
- sleep(1000).then(() => {
- plugin.realTimeScanner.processAllUpdatedFiles(
- taskOld.filePath,
- taskOld.id,
- );
- });
+ void updateFrontmatterInMarkdownFile(plugin, newTask).then(() => {
+ window.setTimeout(() => {
+ plugin.realTimeScanner
+ .processAllUpdatedFiles(taskOld.filePath, taskOld.id)
+ .catch((error) => {
+ bugReporterManagerInsatance.addToLogs(
+ 217,
+ String(error),
+ "UserTaskEvents.ts/updateTaskItemTags",
+ );
+ });
+ }, 1000);
});
} else {
newTask.title = sanitizePriority(
@@ -301,11 +337,16 @@ export const updateTaskItemPriority = (
newTask.title,
newPriority,
);
- updateTaskInFile(plugin, newTask, taskOld).then(() => {
- plugin.realTimeScanner.processAllUpdatedFiles(
- taskOld.filePath,
- taskOld.id,
- );
+ void updateTaskInFile(plugin, newTask, taskOld).then(() => {
+ plugin.realTimeScanner
+ .processAllUpdatedFiles(taskOld.filePath, taskOld.id)
+ .catch((error) => {
+ bugReporterManagerInsatance.addToLogs(
+ 217,
+ String(error),
+ "UserTaskEvents.ts/updateTaskItemTags",
+ );
+ });
});
}
};
@@ -326,10 +367,10 @@ export const updateTaskItemDate = (
plugin: TaskBoard,
taskOld: taskItem,
taskUpdated: taskItem,
- dateType: string,
+ dateType: UniversalDateOptions,
newDate: string,
): void => {
- let newTask = { ...taskUpdated } as taskItem;
+ let newTask = { ...taskUpdated };
switch (dateType) {
case UniversalDateOptions.startDate:
newTask.startDate = newDate;
@@ -344,7 +385,7 @@ export const updateTaskItemDate = (
bugReporterManagerInsatance.addToLogs(
166,
"error while updating the date value. Date type unknown.",
- `dateType = ${dateType}`,
+ `dateType = ${String(dateType)}`,
);
}
@@ -356,13 +397,18 @@ export const updateTaskItemDate = (
);
if (isThisTaskNote) {
- updateFrontmatterInMarkdownFile(plugin, newTask).then(() => {
- sleep(1000).then(() => {
- plugin.realTimeScanner.processAllUpdatedFiles(
- taskOld.filePath,
- taskOld.id,
- );
- });
+ void updateFrontmatterInMarkdownFile(plugin, newTask).then(() => {
+ window.setTimeout(() => {
+ plugin.realTimeScanner
+ .processAllUpdatedFiles(taskOld.filePath, taskOld.id)
+ .catch((error) => {
+ bugReporterManagerInsatance.addToLogs(
+ 217,
+ String(error),
+ "UserTaskEvents.ts/updateTaskItemTags",
+ );
+ });
+ }, 1000);
});
} else {
switch (dateType) {
@@ -391,15 +437,20 @@ export const updateTaskItemDate = (
bugReporterManagerInsatance.addToLogs(
167,
"error while updating the date value. Date type unknown.",
- `dateType = ${dateType}`,
+ `dateType = ${String(dateType)}`,
);
}
- updateTaskInFile(plugin, newTask, taskOld).then(() => {
- plugin.realTimeScanner.processAllUpdatedFiles(
- taskOld.filePath,
- taskOld.id,
- );
+ void updateTaskInFile(plugin, newTask, taskOld).then(() => {
+ plugin.realTimeScanner
+ .processAllUpdatedFiles(taskOld.filePath, taskOld.id)
+ .catch((error) => {
+ bugReporterManagerInsatance.addToLogs(
+ 217,
+ String(error),
+ "UserTaskEvents.ts/updateTaskItemTags",
+ );
+ });
});
}
};
@@ -421,7 +472,7 @@ export const updateTaskItemReminder = (
taskUpdated: taskItem,
newReminder: string,
) => {
- const newTask = { ...taskUpdated } as taskItem;
+ const newTask = { ...taskUpdated };
newTask.reminder = newReminder;
eventEmitter.emit("UPDATE_TASK", { taskID: taskOld.id, state: true });
@@ -432,13 +483,18 @@ export const updateTaskItemReminder = (
);
if (isThisTaskNote) {
- updateFrontmatterInMarkdownFile(plugin, newTask).then(() => {
- sleep(1000).then(() => {
- plugin.realTimeScanner.processAllUpdatedFiles(
- taskOld.filePath,
- taskOld.id,
- );
- });
+ void updateFrontmatterInMarkdownFile(plugin, newTask).then(() => {
+ window.setTimeout(() => {
+ plugin.realTimeScanner
+ .processAllUpdatedFiles(taskOld.filePath, taskOld.id)
+ .catch((error) => {
+ bugReporterManagerInsatance.addToLogs(
+ 217,
+ String(error),
+ "UserTaskEvents.ts/updateTaskItemTags",
+ );
+ });
+ }, 1000);
});
} else {
newTask.title = sanitizeReminder(
@@ -446,11 +502,16 @@ export const updateTaskItemReminder = (
taskOld.title,
newReminder,
);
- updateTaskInFile(plugin, newTask, taskOld).then(() => {
- plugin.realTimeScanner.processAllUpdatedFiles(
- taskOld.filePath,
- taskOld.id,
- );
+ void updateTaskInFile(plugin, newTask, taskOld).then(() => {
+ plugin.realTimeScanner
+ .processAllUpdatedFiles(taskOld.filePath, taskOld.id)
+ .catch((error) => {
+ bugReporterManagerInsatance.addToLogs(
+ 217,
+ String(error),
+ "UserTaskEvents.ts/updateTaskItemTags",
+ );
+ });
});
}
};
@@ -482,21 +543,31 @@ export const updateTaskItemTags = (
);
if (isThisTaskNote) {
- updateFrontmatterInMarkdownFile(plugin, newTask).then(() => {
- sleep(1000).then(() => {
- plugin.realTimeScanner.processAllUpdatedFiles(
- taskOld.filePath,
- taskOld.id,
- );
- });
+ void updateFrontmatterInMarkdownFile(plugin, newTask).then(() => {
+ window.setTimeout(() => {
+ plugin.realTimeScanner
+ .processAllUpdatedFiles(taskOld.filePath, taskOld.id)
+ .catch((error) => {
+ bugReporterManagerInsatance.addToLogs(
+ 217,
+ String(error),
+ "UserTaskEvents.ts/updateTaskItemTags",
+ );
+ });
+ }, 1000);
});
} else {
newTask.title = sanitizeTags(newTask.title, newTags);
- updateTaskInFile(plugin, newTask, taskOld).then(() => {
- plugin.realTimeScanner.processAllUpdatedFiles(
- taskOld.filePath,
- taskOld.id,
- );
+ void updateTaskInFile(plugin, newTask, taskOld).then(() => {
+ plugin.realTimeScanner
+ .processAllUpdatedFiles(taskOld.filePath, taskOld.id)
+ .catch((error) => {
+ bugReporterManagerInsatance.addToLogs(
+ 217,
+ String(error),
+ "UserTaskEvents.ts/updateTaskItemTags",
+ );
+ });
});
}
};
diff --git a/src/utils/ViewUtils.ts b/src/utils/ViewUtils.ts
index 67b2ac01..f1a197b8 100644
--- a/src/utils/ViewUtils.ts
+++ b/src/utils/ViewUtils.ts
@@ -46,7 +46,7 @@ export function getViewById(
*/
export function getViewByType(
board: Board,
- viewType: string,
+ viewType: viewTypeNames,
): TaskBoardViewType | undefined {
return board.views.find((v) => v.viewType === viewType);
}
@@ -59,7 +59,7 @@ export function getViewByType(
*/
export function getViewsByType(
board: Board,
- viewType: string,
+ viewType: viewTypeNames,
): TaskBoardViewType[] {
return board.views.filter((v) => v.viewType === viewType);
}
@@ -73,7 +73,7 @@ export function getViewsByType(
*/
export function addViewToBoard(
board: Board,
- viewType: string,
+ viewType: viewTypeNames,
viewName: string,
): Board {
const newViewId = generateRandomStringId("view");
@@ -156,7 +156,8 @@ export function duplicateViewInBoard(board: Board, viewIndex: number): boolean {
}
const originalView = board.views[viewIndex];
- const newView: TaskBoardViewType = JSON.parse(JSON.stringify(originalView));
+ const parsedData: unknown = JSON.parse(JSON.stringify(originalView));
+ const newView= parsedData as TaskBoardViewType;
// Generate new view ID
newView.viewId = generateRandomStringId("view");
@@ -260,6 +261,9 @@ export function getTotalViewCount(board: Board): number {
* @param viewType The view type to check for
* @returns true if board has at least one view of the specified type
*/
-export function boardHasViewType(board: Board, viewType: string): boolean {
+export function boardHasViewType(
+ board: Board,
+ viewType: viewTypeNames,
+): boolean {
return board.views.some((v) => v.viewType === viewType);
}
diff --git a/src/utils/algorithms/AdvancedFilterer.ts b/src/utils/algorithms/AdvancedFilterer.ts
index 16ca5ce7..b8687036 100644
--- a/src/utils/algorithms/AdvancedFilterer.ts
+++ b/src/utils/algorithms/AdvancedFilterer.ts
@@ -13,7 +13,6 @@ import { robustDateParser } from "../DateTimeCalculations.js";
import { getAllTaskTags } from "../TaskItemUtils.js";
import { getFormattedTaskContentSync } from "../taskLine/TaskContentFormatter.js";
import { matchTagsWithWildcards } from "./ScanningFilterer.js";
-import { normalizePath } from "obsidian";
/**
* Filters tasks based on the board's filter configuration
@@ -167,7 +166,7 @@ function evaluateFilterCriterion(
// Evaluate based on condition
switch (condition) {
case "isNotEmpty":
- if (Array.isArray(taskValue && taskValue.length > 0)) return true;
+ if (Array.isArray(taskValue) && taskValue.length > 0) return true;
else if (taskValue && taskValue !== "") return true;
else if (taskValue) return true;
else return false;
@@ -187,10 +186,10 @@ function evaluateFilterCriterion(
);
case "equals":
case "is":
- return taskValue === value;
+ return taskValue == value;
case "notEquals":
case "isNot":
- return taskValue !== value;
+ return taskValue != value;
case "contains":
if (typeof taskValue === "string") {
return taskValue
@@ -199,7 +198,7 @@ function evaluateFilterCriterion(
}
if (Array.isArray(taskValue)) {
return taskValue.some((item) =>
- matchTagsWithWildcards(value, item),
+ matchTagsWithWildcards(String(value), item),
);
}
return false;
@@ -211,7 +210,7 @@ function evaluateFilterCriterion(
}
if (Array.isArray(taskValue)) {
return !taskValue.some((item) =>
- matchTagsWithWildcards(value, item),
+ matchTagsWithWildcards(String(value), item),
);
}
return true;
@@ -242,12 +241,20 @@ function evaluateFilterCriterion(
case "<=":
return Number(taskValue) <= Number(value);
case "before":
+ if (typeof taskValue !== "string" || typeof value !== "string")
+ return false;
return compareDates(taskValue, value, dateFormat) < 0;
case "after":
+ if (typeof taskValue !== "string" || typeof value !== "string")
+ return false;
return compareDates(taskValue, value, dateFormat) > 0;
case "onOrBefore":
+ if (typeof taskValue !== "string" || typeof value !== "string")
+ return false;
return compareDates(taskValue, value, dateFormat) <= 0;
case "onOrAfter":
+ if (typeof taskValue !== "string" || typeof value !== "string")
+ return false;
return compareDates(taskValue, value, dateFormat) >= 0;
case "hasTag":
if (Array.isArray(taskValue)) {
@@ -275,7 +282,10 @@ function evaluateFilterCriterion(
/**
* Gets the property value from a task based on property name
*/
-function getTaskPropertyValue(task: taskItem, property: string): any {
+function getTaskPropertyValue(
+ task: taskItem,
+ property: string,
+): string | string[] | number | boolean | undefined {
switch (property) {
case "content":
return getFormattedTaskContentSync(task);
@@ -314,10 +324,11 @@ function getTaskPropertyValue(task: taskItem, property: string): any {
case "filePath":
case "path":
return task.filePath || "";
- case "folderPath":
+ case "folderPath": {
const parts = task.filePath.split("/");
const folderPath = parts.slice(0, -1).join("/");
return folderPath + "/" || "";
+ }
case "startTime":
return task.time ? task.time.split("-")[0].trim() : "";
case "reminder":
@@ -342,7 +353,11 @@ function getTaskPropertyValue(task: taskItem, property: string): any {
* Handles multiple date formats automatically
* @returns -1 if date1 < date2, 0 if equal, 1 if date1 > date2
*/
-function compareDates(date1: any, date2: any, dateFormat: string): number {
+function compareDates(
+ date1: string | Date,
+ date2: string | Date,
+ dateFormat: string,
+): number {
if (!date1 || !date2) {
return 0;
}
@@ -365,6 +380,8 @@ function compareDates(date1: any, date2: any, dateFormat: string): number {
* Checks if the root filter state is empty (no filter groups or filters)
* @param filterState - The root filter state to check
* @returns true if empty, false otherwise
+ *
+ * @deprecated We are no longer using the older Advanced Filter. Use {@link isAdvancedFilterEmpty} instead
*/
export function isRootFilterStateEmpty(
filterState: Filter | undefined,
@@ -381,3 +398,27 @@ export function isRootFilterStateEmpty(
return true;
}
+
+/**
+ * Checks if the {@link AdvancedFilter} is empty (no "active" {@link Filter} are present)
+ * @param advancedFilter - The complete advanced filter
+ *
+ * @returns true if empty, false otherwise
+ */
+export function isAdvancedFilterEmpty(
+ advancedFilter: AdvancedFilter | undefined,
+): boolean {
+ if (!advancedFilter) return true;
+
+ if (!advancedFilter?.filters || advancedFilter.filters.length === 0)
+ return true;
+
+ if (
+ advancedFilter.filters.some(
+ (filter: Filter) => filter.status && filter.filterGroups.length > 0,
+ )
+ )
+ return false;
+
+ return true;
+}
diff --git a/src/utils/algorithms/ColumnSegregator.ts b/src/utils/algorithms/ColumnSegregator.ts
index e9eec61f..ab77bf65 100644
--- a/src/utils/algorithms/ColumnSegregator.ts
+++ b/src/utils/algorithms/ColumnSegregator.ts
@@ -67,7 +67,7 @@ export const columnSegregator = (
}
});
break;
- case colTypeNames.dated:
+ case colTypeNames.dated: {
const { dateType, from, to } = columnData.datedBasedColumn || {
dateType: "due",
from: 0,
@@ -187,6 +187,7 @@ export const columnSegregator = (
return diffDays >= from && diffDays <= to;
});
break;
+ }
case colTypeNames.untagged:
tasksToDisplay = pendingTasks.filter(
(task) => getAllTaskTags(task).length === 0,
@@ -238,7 +239,7 @@ export const columnSegregator = (
tasksToDisplay = [];
}
break;
- case colTypeNames.otherTags:
+ case colTypeNames.otherTags: {
const TaggedColumns = activeViewData.kanbanView.columns.filter(
(col: ColumnData) =>
col.colType === colTypeNames.namedTag && col.coltag,
@@ -261,6 +262,7 @@ export const columnSegregator = (
});
});
break;
+ }
case colTypeNames.completed:
// NOTE : to apply the sorting algorithm properly, we have to take all the completed tasks.
// Here we are taking around 1000 which should be enough.
@@ -274,12 +276,13 @@ export const columnSegregator = (
(task) => task.priority === columnData.taskPriority,
);
break;
- case colTypeNames.taskStatus:
+ case colTypeNames.taskStatus: {
const allTasks = [...pendingTasks, ...completedTasks];
tasksToDisplay = allTasks.filter(
(task) => task.status === columnData.taskStatus,
);
break;
+ }
case colTypeNames.allPending:
tasksToDisplay = pendingTasks;
break;
@@ -331,7 +334,7 @@ export const columnSegregator = (
// Prepend missing ids so newest appear on top
columnData.tasksIdManualOrder = [
...missingIds,
- ...columnData.tasksIdManualOrder!,
+ ...columnData.tasksIdManualOrder,
];
}
diff --git a/src/utils/algorithms/ColumnSortingAlgorithm.ts b/src/utils/algorithms/ColumnSortingAlgorithm.ts
index e3a3ff24..6c5db5f3 100644
--- a/src/utils/algorithms/ColumnSortingAlgorithm.ts
+++ b/src/utils/algorithms/ColumnSortingAlgorithm.ts
@@ -10,7 +10,7 @@ function getTaskPropertyValue(
task: taskItem,
criteria: string,
startTimeConfig: string,
-): any {
+): string | string[] | number | undefined {
switch (criteria) {
case "content":
return task.title;
@@ -69,7 +69,11 @@ function getTaskPropertyValue(
* Returns: -1 if date1 < date2, 0 if equal, 1 if date1 > date2
* Handles empty/null dates by placing them at the end for ascending order
*/
-function compareDates(date1: any, date2: any, order: "asc" | "desc"): number {
+function compareDates(
+ date1: string,
+ date2: string,
+ order: "asc" | "desc",
+): number {
// Handle empty/null values
const hasDate1 = date1 && date1 !== "";
const hasDate2 = date2 && date2 !== "";
@@ -94,7 +98,11 @@ function compareDates(date1: any, date2: any, order: "asc" | "desc"): number {
* Compares two time strings (e.g., "09:00", "9:00", or "09:00-10:00")
* Returns: -1 if time1 < time2, 0 if equal, 1 if time1 > time2
*/
-function compareTimes(time1: any, time2: any, order: "asc" | "desc"): number {
+function compareTimes(
+ time1: string,
+ time2: string,
+ order: "asc" | "desc",
+): number {
// Handle empty/null values
const hasTime1 = time1 && time1 !== "";
const hasTime2 = time2 && time2 !== "";
@@ -142,12 +150,12 @@ function compareTimes(time1: any, time2: any, order: "asc" | "desc"): number {
* Compares two values based on their type
*/
function compareValues(
- value1: any,
- value2: any,
+ value1: string | string[] | number,
+ value2: string | string[] | number,
criteria: string,
order: "asc" | "desc",
): number {
- // Handle date criteria
+ // Handle date/date-time type properties
if (
[
"dueDate",
@@ -156,41 +164,28 @@ function compareValues(
"createdDate",
"completedDate",
"completed",
- ].includes(criteria)
+ ].includes(criteria) &&
+ typeof value1 === "string" &&
+ typeof value2 === "string"
) {
return compareDates(value1, value2, order);
}
- // Handle time criteria
- if (criteria === "time") {
+ // Handle time properties
+ if (
+ criteria === "time" &&
+ typeof value1 === "string" &&
+ typeof value2 === "string"
+ ) {
return compareTimes(value1, value2, order);
}
- // Handle priority - special case where lower numbers are higher priority
- // Priority scale: 1 (highest) -> 5 (lowest) -> 0 (none)
- // if (criteria === "priority") {
- // const hasValue1 = value1 !== undefined && value1 !== null;
- // const hasValue2 = value2 !== undefined && value2 !== null;
-
- // if (!hasValue1 && !hasValue2) return 0;
-
- // const isNone1 = value1 === 0;
- // const isNone2 = value2 === 0;
-
- // if (isNone1 && isNone2) return 0;
- // // Place none (0) at the bottom always for both orders
- // if (isNone1) return 1;
- // if (isNone2) return -1;
-
- // // if (order === "asc") {
- // // return value1 - value2; // lower number higher priority first
- // // } else {
- // // return value2 - value1; // higher number lower priority first
- // // }
- // return value2 - value1; // lower number higher priority first
- // }
-
- if (criteria === "priority") {
+ // Handle numeric properties - Specifically for task.priority property.
+ if (
+ criteria === "priority" &&
+ typeof value1 === "number" &&
+ typeof value2 === "number"
+ ) {
const hasValue1 = value1 !== undefined && value1 !== null;
const hasValue2 = value2 !== undefined && value2 !== null;
@@ -216,12 +211,8 @@ function compareValues(
}
}
- // Handle numeric criteria
- if (
- criteria === "lineNumber" ||
- criteria === "id" ||
- typeof value1 === "number"
- ) {
+ // Handle numeric properties
+ if (typeof value1 === "number" && typeof value2 === "number") {
const num1 = Number(value1);
const num2 = Number(value2);
@@ -237,9 +228,9 @@ function compareValues(
const arr1 = Array.isArray(value1) ? value1 : [];
const arr2 = Array.isArray(value2) ? value2 : [];
- // Compare arrays by their first element (or length if you prefer)
- const str1 = arr1.length > 0 ? arr1[0].toLowerCase() : "";
- const str2 = arr2.length > 0 ? arr2[0].toLowerCase() : "";
+ // Convert first element to string for safe comparison
+ const str1 = arr1.length > 0 ? String(arr1[0]).toLowerCase() : "";
+ const str2 = arr2.length > 0 ? String(arr2[0]).toLowerCase() : "";
if (str1 === "" && str2 === "") return 0;
if (str1 === "") return 1;
@@ -248,9 +239,21 @@ function compareValues(
return str1.localeCompare(str2);
}
- // Handle string criteria
- const str1 = String(value1 || "").toLowerCase();
- const str2 = String(value2 || "").toLowerCase();
+ // Handle string criteria — narrow type to primitives before stringifying
+ const str1 = (
+ value1 == null
+ ? ""
+ : typeof value1 === "string" || typeof value1 === "number"
+ ? String(value1)
+ : ""
+ ).toLowerCase();
+ const str2 = (
+ value2 == null
+ ? ""
+ : typeof value2 === "string" || typeof value2 === "number"
+ ? String(value2)
+ : ""
+ ).toLowerCase();
if (str1 === "" && str2 === "") return 0;
if (str1 === "") return 1;
@@ -261,7 +264,8 @@ function compareValues(
/**
* Sorts tasks based on multiple sorting criteria.
- * Criteria are applied in reverse priority order (lowest priority first, highest priority last)
+ *
+ * For {@link taskItem.priority} - Criteria are applied in reverse priority order (lowest priority first, highest priority last)
* to ensure that the highest priority criteria has the final say in the sort order.
*
* @param tasksToDisplay - Array of tasks to sort
@@ -294,7 +298,7 @@ export function columnSortingAlgorithm(
// Apply sorting criteria in reverse order (lowest priority first)
// This ensures that the highest priority criteria has the final say
for (let i = orderedCriteria.length - 1; i >= 0; i--) {
- const criterion = orderedCriteria[i]!;
+ const criterion = orderedCriteria[i];
if (!criterion) continue;
sortedTasks = sortedTasks.sort((taskA, taskB) => {
@@ -309,6 +313,8 @@ export function columnSortingAlgorithm(
startTimeConfig,
);
+ if (!valueA || !valueB) return 0;
+
// if (criterion.criteria === "time") {
// console.log("valueA :", valueA, "\nvalueB :", valueB);
// }
diff --git a/src/utils/algorithms/ScanningFilterer.ts b/src/utils/algorithms/ScanningFilterer.ts
index a0e16ebe..dea101a2 100644
--- a/src/utils/algorithms/ScanningFilterer.ts
+++ b/src/utils/algorithms/ScanningFilterer.ts
@@ -74,7 +74,7 @@ export function checkFrontMatterFilters(
const valueMatch = filterString.match(/"[^"]+":\s*([^,\]]+)/);
if (valueMatch) {
const filterValue = valueMatch[1]?.trim() || "";
- const frontmatterValue = frontmatter[key];
+ const frontmatterValue = frontmatter[key] as unknown;
if (Array.isArray(frontmatterValue)) {
return frontmatterValue.includes(filterValue); // Check if the filterValue is in the list
} else {
@@ -322,7 +322,7 @@ export async function verifySubtasksAndChildtasksAreComplete(
* @param settingsTags - Tags from settings which may include wildcards
* @param userInputTags - Tags from user input to match against settings tags
* @returns An array of matching tags or null if no match is found
- *
+ *
* @todo Will be storing all the tags without the '#' suffix, so we dont have to do the extra replace("#", "") operation. Deprecate that operation in future version such as 2.1.0.
*/
export function matchTagsWithWildcards(
@@ -379,7 +379,7 @@ export function matchTagsWithWildcards(
* @param tag2 - The second tag
*
* @returns - TRUE if both the tags are same based on the above rule. Else it will return FALSE.
- *
+ *
* @todo - Will be storing all the tags without the '#' suffix, so we dont have to do the extra replace("#", "") operation. Deprecate that operation in future version such as 2.1.0.
*/
export function compareTwoTags(tag1: string, tag2: string): boolean {
diff --git a/src/utils/lang/helper.ts b/src/utils/lang/helper.ts
index 678e6b6d..b1c37333 100644
--- a/src/utils/lang/helper.ts
+++ b/src/utils/lang/helper.ts
@@ -1,9 +1,14 @@
// /src/utils/lang/helper.ts
-import { Notice, normalizePath, requestUrl, getLanguage } from "obsidian";
+import { Notice, normalizePath, requestUrl, getLanguage, App } from "obsidian";
import i18next from "i18next";
import TaskBoard from "../../../main.js";
-import { NODE_POSITIONS_STORAGE_KEY, NODE_SIZE_STORAGE_KEY, VIEWPORT_STORAGE_KEY, PENDING_SCAN_FILE_STACK } from "../../interfaces/Constants.js";
+import {
+ NODE_POSITIONS_STORAGE_KEY,
+ NODE_SIZE_STORAGE_KEY,
+ VIEWPORT_STORAGE_KEY,
+ PENDING_SCAN_FILE_STACK,
+} from "../../interfaces/Constants.js";
import { langCodes } from "../../interfaces/GlobalSettings.js";
import { bugReporterManagerInsatance } from "../../managers/BugReporter.js";
import en from "./locale/en.js";
@@ -38,7 +43,7 @@ export const loadTranslationsOnStartup = async (plugin: TaskBoard) => {
`${pluginFolder}/locales/${lang}.json`,
);
const file = await plugin.app.vault.adapter.read(filePath);
- const parsed = JSON.parse(file);
+ const parsed = JSON.parse(file) as unknown;
// Add the loaded translations to i18next
i18next.addResourceBundle(lang, "translation", parsed, true, true);
@@ -142,10 +147,17 @@ export async function downloadAndApplyLanguageFile(
}
}
-export const deleteAllLocalStorageKeys = () => {
+/**
+ * This function removes all the keys and data from the localStorage.
+ *
+ * @note Dont use this anymore, since any localStorage created using the `plugin.app.saveLocalStorage` will be automatically removed, when plugin will be unloaded.
+ *
+ * @param app - The app instance
+ */
+export const deleteAllLocalStorageKeys = (app: App) => {
// No longer need to remove LOCAL_STORAGE_TRANSLATIONS as we're using i18next
- localStorage.removeItem(NODE_POSITIONS_STORAGE_KEY);
- localStorage.removeItem(NODE_SIZE_STORAGE_KEY);
- localStorage.removeItem(VIEWPORT_STORAGE_KEY);
- localStorage.removeItem(PENDING_SCAN_FILE_STACK);
+ // localStorage.removeItem(NODE_POSITIONS_STORAGE_KEY);
+ // localStorage.removeItem(NODE_SIZE_STORAGE_KEY);
+ // localStorage.removeItem(VIEWPORT_STORAGE_KEY);
+ // localStorage.removeItem(PENDING_SCAN_FILE_STACK);
};
diff --git a/src/utils/lang/locale/en.ts b/src/utils/lang/locale/en.ts
index d00fd0ea..c7a201c8 100644
--- a/src/utils/lang/locale/en.ts
+++ b/src/utils/lang/locale/en.ts
@@ -689,7 +689,15 @@ const en: Lang = {
"boards-explorer": "Boards explorer",
"refresh-boards": "Refresh boards",
"ribbon-icon-action": "Ribbon icon action",
- "ribbon-icon-action-info": "Choose what does the ribbon icon of this plugin should do from the ribbon bar."
+ "ribbon-icon-action-info": "Choose what does the ribbon icon of this plugin should do from the ribbon bar.",
+ "author-name": "Atmanand Gauns",
+ "task-board-filters-warehouse": "Task board filters warehouse",
+ "task-board-safe-guard": "Task board safe guard",
+ "task-board-cache": "Task board cache",
+ "view-id": "View id",
+ "view-id-info": "Click on the copy icon to copy the ID of this view. The ID can be used while while embedding boards inside notes and set a default view which should be rendered by default inside the embed. As this id is unique, you will be free to change the name or position of this view inside the board and the embed link will not break.",
+ "copy-view-id-successful": "Succesfully copied the view id to clipboard.",
+ "copy-view-id-unsuccessful": "There was an issue while copying the view id. Check the logs for more details."
};
export default en;
diff --git a/src/utils/taskLine/TaskContentFormatter.ts b/src/utils/taskLine/TaskContentFormatter.ts
index 75b30d9e..5bd2b5ce 100644
--- a/src/utils/taskLine/TaskContentFormatter.ts
+++ b/src/utils/taskLine/TaskContentFormatter.ts
@@ -277,7 +277,7 @@ export const sanitizeStatus = (
globalSettings: globalSettingsData,
oldTitle: string,
newStatusSymbol: string,
- newStatusType: string,
+ newStatusType: statusTypeNames,
): string => {
const oldStatusValuematch = oldTitle.match(/\[(.)\]/); // Extract the symbol inside [ ]
let newTitle = oldTitle;
@@ -355,11 +355,20 @@ export const sanitizeCreatedDate = (
globalSettings.dateFormat,
);
if (formattedCreatedDate) {
- if (globalSettings?.taskPropertyFormat === "1") {
+ if (
+ globalSettings?.taskPropertyFormat ===
+ taskPropertyFormatOptions.default
+ ) {
createdDateWithFormat = `➕${formattedCreatedDate}`;
- } else if (globalSettings?.taskPropertyFormat === "2") {
+ } else if (
+ globalSettings?.taskPropertyFormat ===
+ taskPropertyFormatOptions.tasksPlugin
+ ) {
createdDateWithFormat = `➕ ${formattedCreatedDate}`;
- } else if (globalSettings?.taskPropertyFormat === "3") {
+ } else if (
+ globalSettings?.taskPropertyFormat ===
+ taskPropertyFormatOptions.dataviewPlugin
+ ) {
createdDateWithFormat = `[created:: ${formattedCreatedDate}]`;
} else {
createdDateWithFormat = `@created(${formattedCreatedDate})`;
@@ -422,11 +431,20 @@ export const sanitizeStartDate = (
globalSettings.dateFormat,
);
if (formattedStartDate) {
- if (globalSettings?.taskPropertyFormat === "1") {
+ if (
+ globalSettings?.taskPropertyFormat ===
+ taskPropertyFormatOptions.default
+ ) {
startDateWithFormat = `🛫${formattedStartDate}`;
- } else if (globalSettings?.taskPropertyFormat === "2") {
+ } else if (
+ globalSettings?.taskPropertyFormat ===
+ taskPropertyFormatOptions.tasksPlugin
+ ) {
startDateWithFormat = `🛫 ${formattedStartDate}`;
- } else if (globalSettings?.taskPropertyFormat === "3") {
+ } else if (
+ globalSettings?.taskPropertyFormat ===
+ taskPropertyFormatOptions.dataviewPlugin
+ ) {
startDateWithFormat = `[start:: ${formattedStartDate}]`;
} else {
startDateWithFormat = `@start(${formattedStartDate})`;
@@ -491,11 +509,20 @@ export const sanitizeScheduledDate = (
globalSettings.dateFormat,
);
if (formattedScheduledDate) {
- if (globalSettings?.taskPropertyFormat === "1") {
+ if (
+ globalSettings?.taskPropertyFormat ===
+ taskPropertyFormatOptions.default
+ ) {
scheduledDateWithFormat = `⏳${formattedScheduledDate}`;
- } else if (globalSettings?.taskPropertyFormat === "2") {
+ } else if (
+ globalSettings?.taskPropertyFormat ===
+ taskPropertyFormatOptions.tasksPlugin
+ ) {
scheduledDateWithFormat = `⏳ ${formattedScheduledDate}`;
- } else if (globalSettings?.taskPropertyFormat === "3") {
+ } else if (
+ globalSettings?.taskPropertyFormat ===
+ taskPropertyFormatOptions.dataviewPlugin
+ ) {
scheduledDateWithFormat = `[scheduled:: ${formattedScheduledDate}]`;
} else {
scheduledDateWithFormat = `@scheduled(${formattedScheduledDate})`;
@@ -561,11 +588,20 @@ export const sanitizeDueDate = (
globalSettings.dateFormat,
);
if (formattedDueDate) {
- if (globalSettings?.taskPropertyFormat === "1") {
+ if (
+ globalSettings?.taskPropertyFormat ===
+ taskPropertyFormatOptions.default
+ ) {
dueDateWithFormat = `📅${formattedDueDate}`;
- } else if (globalSettings?.taskPropertyFormat === "2") {
+ } else if (
+ globalSettings?.taskPropertyFormat ===
+ taskPropertyFormatOptions.tasksPlugin
+ ) {
dueDateWithFormat = `📅 ${formattedDueDate}`;
- } else if (globalSettings?.taskPropertyFormat === "3") {
+ } else if (
+ globalSettings?.taskPropertyFormat ===
+ taskPropertyFormatOptions.dataviewPlugin
+ ) {
dueDateWithFormat = `[due:: ${formattedDueDate}]`;
} else {
dueDateWithFormat = `@due(${formattedDueDate})`;
@@ -609,7 +645,7 @@ export const sanitizeCompletionDate = (
cursorLocation?: cursorLocationInterface,
): string => {
const completionDateRegex =
- /\[completion::[^\]]+\]|\@completion\(.*?\)|✅\s*.*?(?=\s|$)/;
+ /\[completion::[^\]]+\]|@completion\(.*?\)|✅\s*.*?(?=\s|$)/;
const extractedCompletionDateMatch = title.match(completionDateRegex);
if (!completionDate) {
@@ -626,11 +662,20 @@ export const sanitizeCompletionDate = (
globalSettings.dateTimeFormat,
);
if (formattedCompletionDate) {
- if (globalSettings?.taskPropertyFormat === "1") {
+ if (
+ globalSettings?.taskPropertyFormat ===
+ taskPropertyFormatOptions.default
+ ) {
completedWitFormat = `✅${formattedCompletionDate} `;
- } else if (globalSettings?.taskPropertyFormat === "2") {
+ } else if (
+ globalSettings?.taskPropertyFormat ===
+ taskPropertyFormatOptions.tasksPlugin
+ ) {
completedWitFormat = `✅ ${formattedCompletionDate} `;
- } else if (globalSettings?.taskPropertyFormat === "3") {
+ } else if (
+ globalSettings?.taskPropertyFormat ===
+ taskPropertyFormatOptions.dataviewPlugin
+ ) {
completedWitFormat = `[completion:: ${formattedCompletionDate}] `;
} else {
completedWitFormat = `@completion(${formattedCompletionDate}) `;
@@ -696,11 +741,20 @@ export const sanitizeCancelledDate = (
globalSettings.dateTimeFormat,
);
if (formattedCancelledDate) {
- if (globalSettings?.taskPropertyFormat === "1") {
+ if (
+ globalSettings?.taskPropertyFormat ===
+ taskPropertyFormatOptions.default
+ ) {
cancelledWithFormat = `❌${formattedCancelledDate}`;
- } else if (globalSettings?.taskPropertyFormat === "2") {
+ } else if (
+ globalSettings?.taskPropertyFormat ===
+ taskPropertyFormatOptions.tasksPlugin
+ ) {
cancelledWithFormat = `❌ ${formattedCancelledDate}`;
- } else if (globalSettings?.taskPropertyFormat === "3") {
+ } else if (
+ globalSettings?.taskPropertyFormat ===
+ taskPropertyFormatOptions.dataviewPlugin
+ ) {
cancelledWithFormat = `[cancelled:: ${formattedCancelledDate}]`;
} else {
cancelledWithFormat = `@cancelled(${formattedCancelledDate})`;
@@ -794,11 +848,20 @@ export const sanitizeTime = (
return newTitle;
} else {
let newTimeWithFormat: string = "";
- if (globalSettings.taskPropertyFormat === "1") {
+ if (
+ globalSettings.taskPropertyFormat ===
+ taskPropertyFormatOptions.default
+ ) {
newTimeWithFormat = `⏰[${newTime}]`;
- } else if (globalSettings.taskPropertyFormat === "2") {
+ } else if (
+ globalSettings.taskPropertyFormat ===
+ taskPropertyFormatOptions.tasksPlugin
+ ) {
newTimeWithFormat = `⏰ ${newTime}`;
- } else if (globalSettings.taskPropertyFormat === "3") {
+ } else if (
+ globalSettings.taskPropertyFormat ===
+ taskPropertyFormatOptions.dataviewPlugin
+ ) {
newTimeWithFormat = `[time:: ${newTime}]`;
} else {
newTimeWithFormat = `@time(${newTime})`;
@@ -911,9 +974,15 @@ export const sanitizePriority = (
if (extractedPriorityMatch.value === 0) {
if (newPriority > 0) {
let priorityWithFormat: string = "";
- if (globalSettings?.taskPropertyFormat === "3") {
+ if (
+ globalSettings?.taskPropertyFormat ===
+ taskPropertyFormatOptions.dataviewPlugin
+ ) {
priorityWithFormat = `[priority:: ${newPriority}]`;
- } else if (globalSettings?.taskPropertyFormat === "4") {
+ } else if (
+ globalSettings?.taskPropertyFormat ===
+ taskPropertyFormatOptions.tasksPlugin
+ ) {
priorityWithFormat = `@priority(${newPriority})`;
} else {
priorityWithFormat = priorityEmojis[newPriority];
@@ -1105,8 +1174,8 @@ export const sanitizeReminder = (
const reminderRegex =
globalSettings.notificationService === NotificationService.ObsidApp
- ? /\(\@\d{2}:\d{2}\)/
- : /\(\@\d{4}-\d{2}-\d{2} \d{2}:\d{2}\)/;
+ ? /\(@\d{2}:\d{2}\)/
+ : /\(@\d{4}-\d{2}-\d{2} \d{2}:\d{2}\)/;
if (!newReminder) {
return title.replace(reminderRegex, "").trimEnd();
@@ -1157,15 +1226,24 @@ export const sanitizeDependsOn = (
return title;
} else {
let dependsOnFormat: string = "";
- if (globalSettings?.taskPropertyFormat === "1") {
+ if (
+ globalSettings?.taskPropertyFormat ===
+ taskPropertyFormatOptions.default
+ ) {
dependsOnFormat =
dependesOnIds.length > 0 ? `⛔${dependesOnIds.join(", ")}` : "";
- } else if (globalSettings?.taskPropertyFormat === "2") {
+ } else if (
+ globalSettings?.taskPropertyFormat ===
+ taskPropertyFormatOptions.tasksPlugin
+ ) {
dependsOnFormat =
dependesOnIds.length > 0
? `⛔ ${dependesOnIds.join(", ")}`
: "";
- } else if (globalSettings?.taskPropertyFormat === "3") {
+ } else if (
+ globalSettings?.taskPropertyFormat ===
+ taskPropertyFormatOptions.dataviewPlugin
+ ) {
dependsOnFormat =
dependesOnIds.length > 0
? `[dependsOn:: ${dependesOnIds.join(", ")}]`
@@ -1210,17 +1288,17 @@ export const sanitizeDependsOn = (
// let dueDateWithFormat: string = "";
// let completedWitFormat: string = "";
// if (updatedTask.due || updatedTask.completion) {
-// if (globalSettings?.taskPropertyFormat === "1") {
+// if (globalSettings?.taskPropertyFormat === taskPropertyFormatOptions.default) {
// dueDateWithFormat = updatedTask.due ? ` 📅${updatedTask.due}` : "";
// completedWitFormat = updatedTask.completion
// ? ` ✅${updatedTask.completion} `
// : "";
-// } else if (globalSettings?.taskPropertyFormat === "2") {
+// } else if (globalSettings?.taskPropertyFormat === taskPropertyFormatOptions.tasksPlugin) {
// dueDateWithFormat = updatedTask.due ? ` 📅 ${updatedTask.due}` : "";
// completedWitFormat = updatedTask.completion
// ? ` ✅ ${updatedTask.completion} `
// : "";
-// } else if (globalSettings?.taskPropertyFormat === "3") {
+// } else if (globalSettings?.taskPropertyFormat === taskPropertyFormatOptions.dataviewPlugin) {
// dueDateWithFormat = updatedTask.due
// ? ` [due:: ${updatedTask.due}]`
// : "";
@@ -1346,7 +1424,7 @@ export const cleanTaskTitle = (plugin: TaskBoard, task: taskItem): string => {
// Remove time (handles both formats)
if (task.time) {
const timeRegex =
- /\s*(⏰\s*\[\d{2}:\d{2}\s*-\s*\d{2}:\d{2}\]|\b\d{2}:\d{2}\s*-\s*\d{2}:\d{2}\b|⏰\s*(\d{2}:\d{2}\s*-\s*\d{2}:\d{2})|\[time::.*?\]|\@time\(.*?\))/g;
+ /\s*(⏰\s*\[\d{2}:\d{2}\s*-\s*\d{2}:\d{2}\]|\b\d{2}:\d{2}\s*-\s*\d{2}:\d{2}\b|⏰\s*(\d{2}:\d{2}\s*-\s*\d{2}:\d{2})|\[time::.*?\]|@time\(.*?\))/g;
const timeMatch = cleanedTitle.match(timeRegex);
if (timeMatch) {
cleanedTitle = cleanedTitle.replace(timeMatch[0], "");
@@ -1446,7 +1524,7 @@ export const cleanTaskTitle = (plugin: TaskBoard, task: taskItem): string => {
plugin.settings.data.showTaskWithoutMetadata
) {
const reminderRegex =
- /\(\@(\d{4}-\d{2}-\d{2}( \d{2}:\d{2})?|\d{2}:\d{2})\)/;
+ /\(@(\d{4}-\d{2}-\d{2}( \d{2}:\d{2})?|\d{2}:\d{2})\)/;
const reminderMatch = cleanedTitle.match(reminderRegex);
if (reminderMatch) {
cleanedTitle = cleanedTitle.replace(reminderMatch[0], "").trim();
@@ -1503,7 +1581,7 @@ export const cleanTaskTitleLegacy = (task: taskItem): string => {
// Remove time (handles both formats)
if (task.time) {
const timeRegex =
- /\s*(⏰\s*\[.*?\]|\b\d{2}:\d{2}\s*-\s*\d{2}:\d{2}\b|⏰\s*(.*?)|\[time::.*?\]|\@time\(.*?\))/g;
+ /\s*(⏰\s*\[.*?\]|\b\d{2}:\d{2}\s*-\s*\d{2}:\d{2}\b|⏰\s*(.*?)|\[time::.*?\]|@time\(.*?\))/g;
const timeMatch = cleanedTitle.match(timeRegex);
if (timeMatch) {
cleanedTitle = cleanedTitle.replace(timeMatch[0], "");
@@ -1596,7 +1674,7 @@ export const cleanTaskTitleLegacy = (task: taskItem): string => {
// Remove reminder if it exists
if (task.reminder) {
const reminderRegex =
- /\(\@(\d{4}-\d{2}-\d{2}( \d{2}:\d{2})?|\d{2}:\d{2})\)/;
+ /\(@(\d{4}-\d{2}-\d{2}( \d{2}:\d{2})?|\d{2}:\d{2})\)/;
const reminderMatch = cleanedTitle.match(reminderRegex);
if (reminderMatch) {
cleanedTitle = cleanedTitle.replace(reminderMatch[0], "").trim();
diff --git a/src/utils/taskLine/TaskItemEventHandlers.ts b/src/utils/taskLine/TaskItemEventHandlers.ts
index 671004e1..b16a9255 100644
--- a/src/utils/taskLine/TaskItemEventHandlers.ts
+++ b/src/utils/taskLine/TaskItemEventHandlers.ts
@@ -53,15 +53,22 @@ export const handleCheckboxChange = (plugin: TaskBoard, task: taskItem) => {
status: newStatus.newSymbol,
};
- updateTaskInFile(plugin, taskWithUpdatedStatus, task).then((newId) => {
- plugin.realTimeScanner.processAllUpdatedFiles(
- task.filePath,
- task.legacyId,
- );
+ void updateTaskInFile(plugin, taskWithUpdatedStatus, task).then(
+ (newId) => {
+ plugin.realTimeScanner
+ .processAllUpdatedFiles(task.filePath, task.legacyId)
+ .catch((error) => {
+ bugReporterManagerInsatance.addToLogs(
+ 217,
+ String(error),
+ "TaskItemEventHandlers.ts/handleCheckboxChange/updateTaskInFile",
+ );
+ });
- // DEPRECATED : See notes from //src/utils/TaskItemCacheOperations.ts file
- // moveFromCompletedToPending(plugin, taskWithUpdatedStatus);
- });
+ // DEPRECATED : See notes from //src/utils/TaskItemCacheOperations.ts file
+ // moveFromCompletedToPending(plugin, taskWithUpdatedStatus);
+ },
+ );
// if (isTaskCompleted(`- [${task.status}]`, false, plugin.settings)) {
// const newStatusType =
@@ -130,10 +137,15 @@ export const handleCheckboxChange = (plugin: TaskBoard, task: taskItem) => {
if (tasksPlugin.isTasksPluginEnabled()) {
useTasksPluginToUpdateInFile(plugin, tasksPlugin, task)
.then(() => {
- plugin.realTimeScanner.processAllUpdatedFiles(
- task.filePath,
- task.legacyId,
- );
+ plugin.realTimeScanner
+ .processAllUpdatedFiles(task.filePath, task.legacyId)
+ .catch((error) => {
+ bugReporterManagerInsatance.addToLogs(
+ 217,
+ String(error),
+ "TaskItemEventHandlers.ts/handleCheckboxChange/useTasksPluginToUpdateInFile",
+ );
+ });
// NOTE : This is not necessary any more as I am scanning the file after it has been updated.
// // Move from Pending to Completed
@@ -171,11 +183,16 @@ export const handleSubTasksChange = (
// DEPRECATED : See notes from //src/utils/TaskItemCacheOperations.ts file
// updateTaskInJson(plugin, updatedTask);
- updateTaskInFile(plugin, updatedTask, oldTask).then((newId) => {
- plugin.realTimeScanner.processAllUpdatedFiles(
- updatedTask.filePath,
- oldTask.id,
- );
+ void updateTaskInFile(plugin, updatedTask, oldTask).then((newId) => {
+ plugin.realTimeScanner
+ .processAllUpdatedFiles(updatedTask.filePath, oldTask.id)
+ .catch((error) => {
+ bugReporterManagerInsatance.addToLogs(
+ 217,
+ String(error),
+ "TaskItemEventHandlers.ts/handleCheckboxChange/updateTaskInFile",
+ );
+ });
});
};
@@ -197,12 +214,18 @@ export const handleDeleteTask = (
mssg,
onConfirm: () => {
if (isTaskNote) {
- deleteTaskNote(plugin, task.filePath);
+ void deleteTaskNote(plugin, task.filePath);
} else {
- deleteTaskFromFile(plugin, task).then(() => {
- plugin.realTimeScanner.processAllUpdatedFiles(
- task.filePath,
- );
+ void deleteTaskFromFile(plugin, task).then(() => {
+ plugin.realTimeScanner
+ .processAllUpdatedFiles(task.filePath)
+ .catch((error) => {
+ bugReporterManagerInsatance.addToLogs(
+ 217,
+ String(error),
+ "TaskItemEventHandlers.ts/handleDeleteTask/deleteTaskFromFile",
+ );
+ });
});
// DEPRECATED : See notes from //src/utils/TaskItemCacheOperations.ts file
@@ -216,11 +239,11 @@ export const handleDeleteTask = (
},
onArchive: () => {
if (isTaskNote) {
- archiveTaskNote(plugin, task.filePath).then(() => {
+ void archiveTaskNote(plugin, task.filePath).then(() => {
eventEmitter.emit("SOFT_REFRESH");
});
} else {
- archiveTask(plugin, task);
+ void archiveTask(plugin, task);
}
},
});
@@ -241,7 +264,7 @@ export const createNewInlineTask = async (
);
completeTask = formattedTaskContent;
- (communityPlugins.quickAddPlugin as any)?.api.executeChoice(
+ communityPlugins.quickAddPlugin?.api.executeChoice(
plugin.settings.data.quickAddPluginDefaultChoice,
{
value: completeTask + "\n",
@@ -249,7 +272,7 @@ export const createNewInlineTask = async (
);
} else {
await addTaskInNote(plugin, task, false).then((newId) => {
- plugin.realTimeScanner.processAllUpdatedFiles(task.filePath);
+ void plugin.realTimeScanner.processAllUpdatedFiles(task.filePath);
});
}
};
diff --git a/src/utils/taskLine/TaskLineUtils.ts b/src/utils/taskLine/TaskLineUtils.ts
index 83fe3f66..8d271622 100644
--- a/src/utils/taskLine/TaskLineUtils.ts
+++ b/src/utils/taskLine/TaskLineUtils.ts
@@ -48,7 +48,7 @@ export const addTaskInNote = async (
plugin: TaskBoard,
newTask: taskItem,
editorActive: boolean,
- cursorPosition?: { line: number; ch: number } | undefined,
+ cursorPosition?: { line: number; ch: number },
): Promise => {
const filePath = newTask.filePath.endsWith("md")
? newTask.filePath
@@ -84,7 +84,7 @@ export const addTaskInNote = async (
);
completeTask = formattedTaskContent;
if (completeTask === "")
- throw "getSanitizedTaskContent returned empty string";
+ throw new Error("getSanitizedTaskContent returned empty string");
const file = plugin.app.vault.getAbstractFileByPath(filePath);
if (file === null || !(file instanceof TFile)) return;
@@ -286,7 +286,7 @@ export const useTasksPluginToUpdateInFile = async (
// Prepare the updated task block
const completeOldTaskContent = await getFormattedTaskContent(oldTask);
if (completeOldTaskContent === "")
- throw "getSanitizedTaskContent returned empty string";
+ throw new Error("getSanitizedTaskContent returned empty string");
if (tasksPlugin.isTasksPluginEnabled()) {
const { formattedTaskContent, newId } = await addIdToTaskContent(
@@ -329,7 +329,7 @@ export const useTasksPluginToUpdateInFile = async (
completeOldTaskContent,
newContent,
);
- } else if ((twoTaskTitles.length = 1)) {
+ } else if (twoTaskTitles.length === 1) {
const { formattedTaskContent, newId } =
await addIdToTaskContent(plugin, tasksPluginApiOutput);
const tasksPluginApiOutputWithId = formattedTaskContent;
@@ -344,7 +344,7 @@ export const useTasksPluginToUpdateInFile = async (
completeOldTaskContent,
newContent,
);
- } else if ((twoTaskTitles.length = 2)) {
+ } else if (twoTaskTitles.length === 2) {
// if (twoTaskTitles[1].trim().startsWith("- [x]")) {
newContent = `${twoTaskTitles[0]}${
oldTask.body.length > 0
@@ -536,7 +536,7 @@ export const archiveTask = async (
// Prepare the task content to be archived
const oldTaskContent = await getFormattedTaskContent(task);
if (oldTaskContent === "")
- throw "getSanitizedTaskContent returned empty string";
+ throw new Error("getSanitizedTaskContent returned empty string");
if (archivedFilePath) {
try {
@@ -597,26 +597,28 @@ export const archiveTask = async (
plugin.app.vault.getAbstractFileByPath(archivedFilePath);
if (file === null || !(file instanceof TFile)) return;
- // Archive the task to the specified file
- await plugin.app.vault.process(file, (archivedFileContent) => {
- // Add the task to the top of the archived file content
- const newArchivedContent = `> ${t("archived-on")} ${new Date().toLocaleString()}\n${oldTaskContent}\n\n${archivedFileContent}`;
- return newArchivedContent;
- });
-
- // Now delete the task from its original file only if archiving succeeded
- const deletionSuccess = await deleteTaskFromFile(plugin, task);
- if (deletionSuccess) {
- plugin.realTimeScanner.processAllUpdatedFiles(task.filePath);
- } else {
- // Archiving succeeded but deletion failed
- bugReporterManagerInsatance.showNotice(
- 64,
- "Task was archived successfully but failed to delete from the original file. Please manually verify and delete the task from the source file if needed.",
- "Archive succeeded but deletion failed",
- "TaskItemUtils.ts/archiveTask",
- );
- }
+ // Archive the task to the specified file
+ await plugin.app.vault.process(file, (archivedFileContent) => {
+ // Add the task to the top of the archived file content
+ const newArchivedContent = `> ${t("archived-on")} ${new Date().toLocaleString()}\n${oldTaskContent}\n\n${archivedFileContent}`;
+ return newArchivedContent;
+ });
+
+ // Now delete the task from its original file only if archiving succeeded
+ const deletionSuccess = await deleteTaskFromFile(plugin, task);
+ if (deletionSuccess) {
+ void plugin.realTimeScanner.processAllUpdatedFiles(
+ task.filePath,
+ );
+ } else {
+ // Archiving succeeded but deletion failed
+ bugReporterManagerInsatance.showNotice(
+ 64,
+ "Task was archived successfully but failed to delete from the original file. Please manually verify and delete the task from the source file if needed.",
+ "Archive succeeded but deletion failed",
+ "TaskItemUtils.ts/archiveTask",
+ );
+ }
// archivedFilePath,
// true,
// );
@@ -631,7 +633,7 @@ export const archiveTask = async (
// newArchivedContent,
// );
- // // Now delete the task from its original file
+ // // Now delete the task from its original file
// await deleteTaskFromFile(plugin, task).then(() => {
// plugin.realTimeScanner.processAllUpdatedFiles(task.filePath);
// });
@@ -655,9 +657,11 @@ export const archiveTask = async (
oldTaskContent,
`%%${oldTaskContent}%%`,
);
-
+
if (markSuccess) {
- plugin.realTimeScanner.processAllUpdatedFiles(task.filePath);
+ void plugin.realTimeScanner.processAllUpdatedFiles(
+ task.filePath,
+ );
} else {
bugReporterManagerInsatance.showNotice(
65,
@@ -731,7 +735,9 @@ export const replaceOldTaskWithNewTask = async (
const file = plugin.app.vault.getAbstractFileByPath(filePath);
if (file === null || !(file instanceof TFile))
- throw `The file was either not found at the path or its not an instance of TFile.`;
+ throw new Error(
+ `The file was either not found at the path or its not an instance of TFile.`,
+ );
await plugin.app.vault.process(file, (fileContent: string): string => {
const lines = fileContent.split("\n");
@@ -847,7 +853,7 @@ export const replaceOldTaskWithNewTask = async (
oldTaskContent,
newTaskContent,
oldTaskContentFromFile,
- async (userChoice) => {
+ (userChoice) => {
if (userChoice === "old") {
const before = linesBefore.join("\n");
const after = lines
@@ -860,7 +866,7 @@ export const replaceOldTaskWithNewTask = async (
after,
);
// Replace the old task block with the updated content
- await writeDataToVaultFile(
+ void writeDataToVaultFile(
plugin,
filePath,
newContent,
diff --git a/src/utils/taskNote/FrontmatterOperations.ts b/src/utils/taskNote/FrontmatterOperations.ts
index 89b94592..67365a30 100644
--- a/src/utils/taskNote/FrontmatterOperations.ts
+++ b/src/utils/taskNote/FrontmatterOperations.ts
@@ -14,7 +14,7 @@ import {
getPriorityNameForTaskNote,
} from "./TaskNoteUtils.js";
import { FrontmatterFormattingInterface } from "../../interfaces/GlobalSettings.js";
-import { compareTwoTags} from "../algorithms/ScanningFilterer.js";
+import { compareTwoTags } from "../algorithms/ScanningFilterer.js";
/**
* Extract frontmatter from file content
@@ -67,11 +67,11 @@ export function extractFrontmatterFromFile(
return frontmatterAsObject;
} catch (error) {
- // bugReporterManagerInsatance.addToLogs(
- // 176,
- // `Failed to parse frontmatter: ${String(error)}`,
- // "FrontmatterOperations.ts/extractFrontmatterFromFile",
- // );
+ bugReporterManagerInsatance.addToLogs(
+ 176,
+ `Failed to parse frontmatter: ${String(error)}`,
+ "FrontmatterOperations.ts/extractFrontmatterFromFile",
+ );
return undefined;
}
}
@@ -133,7 +133,7 @@ export function extractFrontmatterTags(
if (frontmatter.tags) {
if (Array.isArray(frontmatter.tags)) {
// If tags is an array, process each tag
- tags = frontmatter.tags.map((tag: any) => {
+ tags = frontmatter.tags.map((tag: unknown) => {
const tagStr = String(tag).trim();
// Ensure tags start with # if they don't already
return tagStr.replace("#", "");
@@ -181,14 +181,14 @@ function orderFrontmatterProperties(
const key = format.key;
// If the key exists in the frontmatter object, add it to the ordered object
if (key in frontmatterObj) {
- orderedFrontmatter[key] = frontmatterObj[key];
+ orderedFrontmatter[key] = frontmatterObj[key] as unknown;
}
}
// Add any additional properties from the frontmatter object that aren't in the formatted list
for (const [key, value] of Object.entries(frontmatterObj)) {
if (!(key in orderedFrontmatter) && !customKeys.has(key)) {
- orderedFrontmatter[key] = value;
+ orderedFrontmatter[key] = value as unknown;
}
}
@@ -199,7 +199,7 @@ function orderFrontmatterProperties(
if (key === "index__") continue;
// Skip keys that are already in the ordered frontmatter
if (!(key in orderedFrontmatter)) {
- orderedFrontmatter[key] = value;
+ orderedFrontmatter[key] = value as unknown;
}
}
}
@@ -309,7 +309,7 @@ export function updateFrontmatterProperties(
const oldFrontmatter = existingFrontmatter;
// Step 1: Build a temporary object with all the updated values
- const tempUpdates: Record = {};
+ const tempUpdates: Record = {};
if (task.title) {
tempUpdates[getCustomFrontmatterKey("title", frontmatterFormatting)] =
@@ -321,12 +321,12 @@ export function updateFrontmatterProperties(
// Ensure taskNote tag exists and respect removed tags (task.tags is source of truth)
const tagsKey = getCustomFrontmatterKey("tags", frontmatterFormatting);
- const existingTagsRaw = existingFrontmatter?.[tagsKey];
+ const existingTagsRaw = existingFrontmatter?.[tagsKey as keyof customFrontmatterCache] as unknown;
// Normalize existing tags to array of strings
let existingTags: string[] = [];
if (Array.isArray(existingTagsRaw)) {
- existingTags = existingTagsRaw.filter(Boolean);
+ existingTags = existingTagsRaw.filter(Boolean) as string[];
} else if (typeof existingTagsRaw === "string" && existingTagsRaw.length) {
existingTags = existingTagsRaw
.split(",")
diff --git a/src/utils/taskNote/TaskNoteEventHandlers.ts b/src/utils/taskNote/TaskNoteEventHandlers.ts
index 27b498e1..da73b236 100644
--- a/src/utils/taskNote/TaskNoteEventHandlers.ts
+++ b/src/utils/taskNote/TaskNoteEventHandlers.ts
@@ -61,14 +61,18 @@ export const handleTaskNoteStatusChange = async (
// Update frontmatter with new status
await updateFrontmatterInMarkdownFile(plugin, updatedTask).then(() => {
- // This is required to rescan the updated file and refresh the board.
- sleep(1000).then(() => {
- // This is required to rescan the updated file and refresh the board.
- plugin.realTimeScanner.processAllUpdatedFiles(
- updatedTask.filePath,
- task.legacyId,
- );
- });
+ // This delay is required to rescan the updated file and refresh the board.
+ window.setTimeout(() => {
+ plugin.realTimeScanner
+ .processAllUpdatedFiles(updatedTask.filePath, task.legacyId)
+ .catch((error) => {
+ bugReporterManagerInsatance.addToLogs(
+ 217,
+ String(error),
+ "TaskNoteEventHandlers.ts/handleTaskNoteStatusChange/updateFrontmatterInMarkdownFile",
+ );
+ });
+ }, 1000);
});
new Notice(`Task note status updated to ${newStatusName}`);
@@ -96,13 +100,18 @@ export const handleTaskNotePropertyUpdate = async (
try {
// Update frontmatter with all updated properties
await updateFrontmatterInMarkdownFile(plugin, updatedTask).then(() => {
- // This is required to rescan the updated file and refresh the board.
- sleep(1000).then(() => {
- // This is required to rescan the updated file and refresh the board.
- plugin.realTimeScanner.processAllUpdatedFiles(
- updatedTask.filePath,
- );
- });
+ // This delay is required to rescan the updated file and refresh the board.
+ window.setTimeout(() => {
+ plugin.realTimeScanner
+ .processAllUpdatedFiles(updatedTask.filePath)
+ .catch((error) => {
+ bugReporterManagerInsatance.addToLogs(
+ 217,
+ String(error),
+ "TaskNoteEventHandlers.ts/handleTaskNoteStatusChange/handleTaskNotePropertyUpdate",
+ );
+ });
+ }, 1000);
});
new Notice("Task note properties updated");
@@ -136,13 +145,12 @@ export const handleTaskNote2NormalNote = async (
plugin.app.metadataCache.getFileCache(file)?.frontmatter;
if (frontmatter && frontmatter.tags) {
// Remove taskNote tag from frontmatter
- let tags = Array.isArray(frontmatter.tags)
- ? [...frontmatter.tags]
- : [frontmatter.tags];
- tags = tags.filter(
- (tag: string) =>
- tag.includes(plugin.settings.data.taskNoteIdentifierTag) ===
- false,
+ const rawTags = frontmatter.tags as unknown;
+ let tagsArray = Array.isArray(rawTags)
+ ? [...(rawTags as string[])]
+ : [rawTags as string];
+ tagsArray = tagsArray.filter((tag: string) =>
+ tag.includes(plugin.settings.data.taskNoteIdentifierTag),
);
// If no other tags remain, we could remove the tags property entirely
@@ -209,11 +217,23 @@ export const handleTaskNoteBodyChange = async (
return updatedLines.join("\n");
})
- .finally(() => {
- plugin.realTimeScanner.processAllUpdatedFiles(
- updatedTask.filePath,
- oldTask.id,
+ .catch((error) => {
+ bugReporterManagerInsatance.addToLogs(
+ 219,
+ String(error),
+ "TaskNoteEventHandlers.ts/handleTaskNoteBodyChange/process",
);
+ })
+ .finally(() => {
+ plugin.realTimeScanner
+ .processAllUpdatedFiles(updatedTask.filePath, oldTask.id)
+ .catch((error) => {
+ bugReporterManagerInsatance.addToLogs(
+ 217,
+ String(error),
+ "TaskNoteEventHandlers.ts/handleTaskNoteBodyChange/process",
+ );
+ });
});
// const fileContent = await readDataOfVaultFile(
diff --git a/src/utils/taskNote/TaskNoteUtils.ts b/src/utils/taskNote/TaskNoteUtils.ts
index b921d15c..4dc66f1c 100644
--- a/src/utils/taskNote/TaskNoteUtils.ts
+++ b/src/utils/taskNote/TaskNoteUtils.ts
@@ -6,7 +6,6 @@ import { defaultTaskStatuses } from "../../interfaces/Enums.js";
import {
PluginDataJson,
CustomStatus,
- globalSettingsData,
FrontmatterFormattingInterface,
} from "../../interfaces/GlobalSettings.js";
import { customFrontmatterCache, taskItem } from "../../interfaces/TaskItem.js";
@@ -34,7 +33,7 @@ export function isTaskNotePresentInFrontmatter(
let tags: string[] = [];
if (Array.isArray(frontmatter.tags)) {
- tags = frontmatter.tags.map((tag: any) => String(tag).trim());
+ tags = frontmatter.tags.map((tag: unknown) => String(tag).trim());
} else if (typeof frontmatter.tags === "string") {
tags = frontmatter.tags.split(",").map((tag: string) => tag.trim());
}
@@ -64,11 +63,12 @@ export function validateFrontmatterValue(
customKey: string,
valueType: "string" | "number" | "array",
): string | number | string[] | undefined {
- const value = frontmatter[customKey];
+ const value = frontmatter[customKey] as unknown ?? "";
if (value && typeof value === valueType) {
- return value;
+ return value as string | number | string[];
}
+ return undefined;
}
/**
@@ -196,7 +196,7 @@ export function extractTaskNoteProperties(
getCustomFrontmatterKey("priority", frontmatterFormatting),
"string",
);
- if (value) {
+ if (value && typeof value === "string") {
const priorityNumber = getPriorityNumberForTaskNote(value);
taskItemData["priority"] = priorityNumber;
}
@@ -239,7 +239,7 @@ export function extractTaskNoteProperties(
* @param priorityValue - Priority value from frontmatter
* @returns number - Priority number (0-5)
*/
-export function getPriorityNumberForTaskNote(priorityValue: any): number {
+export function getPriorityNumberForTaskNote(priorityValue: string): number {
if (!priorityValue) return 0;
if (priorityValue.length === 1 && Number(priorityValue))
@@ -418,6 +418,8 @@ export function formatTaskNoteContent(
* @param task - Task item with updated properties
* @param forceId (Optional) - Whether to forcefully add ID property in frontmatter
* @returns Promise
+ *
+ * @error_code 158
*/
export async function updateFrontmatterInMarkdownFile(
plugin: TaskBoard,
@@ -441,7 +443,7 @@ export async function updateFrontmatterInMarkdownFile(
forceId,
);
for (const key of Object.keys(updated)) {
- existing[key] = updated[key];
+ existing[key] = updated[key] as unknown;
}
},
);
@@ -510,7 +512,7 @@ export async function deleteTaskNote(
return;
}
- await plugin.app.vault.trash(file, true);
+ await plugin.app.fileManager.trashFile(file);
new Notice(`Task note deleted: ${file.name}`);
} catch (error) {
bugReporterManagerInsatance.showNotice(
diff --git a/styles.css b/styles.css
index 283b4369..09410ccf 100644
--- a/styles.css
+++ b/styles.css
@@ -494,6 +494,7 @@ button.clickable-icon.view-action.taskboardScanVaultBtn.highlight {
display: flex;
transition: flex 0.3s cubic-bezier(0.4, 0, 0.2, 1);
overflow: hidden;
+ max-height: inherit;
}
.taskBoardViewSectionWrapper--shifted {
@@ -506,12 +507,13 @@ button.clickable-icon.view-action.taskboardScanVaultBtn.highlight {
/* margin-block-end: 20px; */
/* padding-block-end: 3.4rem; */
width: 100%;
+ max-height: -webkit-fill-available;
flex: 1;
}
.taskBoardViewSection-mobile {
/* height: 100%; */
- max-height: 92%;
+ /* max-height: 92%; */
/* margin-block-end: 20px; */
padding-block-end: 4.2rem;
width: 100%;
@@ -535,14 +537,38 @@ button.clickable-icon.view-action.taskboardScanVaultBtn.highlight {
/* Task Board Embed Styles */
.task-board-embed {
- max-height: 600px;
- overflow: auto;
+ /* heith will be set dynamically using the dimensions mentioned by the user in the embed link. */
+ /* max-height: 600px; */
+ overflow-x: auto;
+ /* overflow-y: hidden; */
border: 1px solid var(--background-modifier-border);
border-radius: 4px;
- padding: 8px;
- background-color: var(--background-primary);
+ background-color: transparent;
+ max-height: var(--task-board-embed-wdith);
+}
+
+.task-board-embed .taskBoardView {
+ margin: 6px;
+}
+
+.task-board-embed .taskBoardView .taskBoardMainContent {
+ max-height: calc(var(--task-board-embed-wdith) - 15px);
}
+.task-board-embed .taskBoardView .taskBoardMainContent .taskBoardViewSectionWrapper .taskBoardViewSection .kanbanBoard {
+ max-height: calc(var(--task-board-embed-wdith) - 60px);
+}
+
+.task-board-embed .taskBoardView .taskBoardMainContent .taskBoardViewSectionWrapper .taskBoardViewSection .taskBoardMapViewWrapper {
+ max-height: calc(var(--task-board-embed-wdith) - 60px);
+}
+
+.task-board-embed .taskBoardView .taskBoardMainContent .taskBoardViewSectionWrapper .taskBoardViewSection .taskBoardMapViewWrapper .taskBoardMapView{
+ max-height: inherit;
+}
+
+
+
/* Custom view header path elements */
.taskboard-path-folder,
.taskboard-path-file {
@@ -574,6 +600,7 @@ button.clickable-icon.view-action.taskboardScanVaultBtn.highlight {
.kanbanBoard {
height: 100%;
/* max-height: 90%; */
+ max-height: inherit;
}
.columnsContainer {
@@ -581,6 +608,7 @@ button.clickable-icon.view-action.taskboardScanVaultBtn.highlight {
overflow-x: auto;
/* padding-block: 4px; */
height: 100%;
+ max-height: inherit;
}
.loadingContainer {
@@ -1296,26 +1324,24 @@ button.clickable-icon.view-action.taskboardScanVaultBtn.highlight {
}
.taskItemTag {
- /* Custom tag styling */
font-size: 0.7rem;
/* font-weight: 500; */
/* line-height: 1; */
margin-right: 2px;
- display: inline-block;
+ display: flex;
white-space: nowrap;
-
- /* Default tag styling */
background-color: var(--tag-background);
border: var(--tag-border-width) solid var(--tag-border-color);
border-radius: var(--tag-radius);
color: var(--tag-color);
font-weight: var(--tag-weight);
text-decoration: var(--tag-decoration);
- padding-top: 0.15em;
- padding-right: 0.65em;
- padding-bottom: 0.25em;
- padding-left: 0.65em;
+ /* padding-top: 0.15em; */
+ /* padding-right: 0.65em; */
+ padding-block: 0.25em;
+ padding-inline: 0.65em;
line-height: 1;
+ align-items: center;
}
.taskItemTagFrontmatter {
@@ -1595,12 +1621,13 @@ button.clickable-icon.view-action.taskboardScanVaultBtn.highlight {
flex-direction: row;
gap: 1em;
align-items: center;
- font-size: var(--font-ui-smaller);
max-width: 100%;
}
.taskItemFooterPropertyContainerLabel {
color: var(--text-muted);
+ font-size: 0.65rem;
+ color: var(--canvas-card-label-color);
}
.taskItemFooterPropertyContainerValue {
@@ -1608,6 +1635,7 @@ button.clickable-icon.view-action.taskboardScanVaultBtn.highlight {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
+ font-size: 0.75rem;
/* max-width: calc(var(--task-board-column-width) - 5rem); */
}
@@ -1697,6 +1725,7 @@ body.taskboard-touch-dragging {
.taskBoardMapViewContainer {
width: 100%;
height: 80vh;
+ max-height: inherit;
display: flex;
flex-direction: column;
align-items: center;
@@ -3089,11 +3118,15 @@ body.taskboard-touch-dragging {
/* Hidden Properties in Live Editor and Reading Mode */
.taskboard-hidden-property {
+ display: inline-block;
+ overflow: hidden;
+ white-space: nowrap;
+ vertical-align: middle;
opacity: 0;
transform: scaleX(0);
width: 0;
/* Smooth transition for both properties */
- transition: opacity 0.2s ease-in, width 0.2s ease-in;
+ transition: opacity 0.2s ease-in, width 0.2s ease-in, transform 0.2s ease-in;
}
/* Show hidden properties on line hover for easier editing */
@@ -5417,6 +5450,19 @@ svg.react-flow__connectionline {
transition: max-height 0.3s ease, opacity 0.3s ease, padding 0.3s ease;
}
+.advanced-filter-expandable-area.expand {
+ max-height: 2000px;
+ opacity: 1;
+ padding-block: var(--size-2-2);
+}
+
+.advanced-filter-expandable-area.collapse {
+ max-height: 0;
+ opacity: 0;
+ padding-top: 0;
+ padding-bottom: 0;
+}
+
.filter-name-setting {
display: flex;
flex-direction: row;
@@ -8866,6 +8912,46 @@ li[data-task=b]>p>input:checked {
transform: scale(0.98);
}
+.boardsExplorerLoadingBarContainer {
+ width: calc(100% + 40px);
+ margin: 0 -20px 12px -20px;
+ padding: 0 20px;
+ overflow: hidden;
+}
+
+.boardsExplorerLoadingBar {
+ width: 100%;
+ height: 4px;
+ background: linear-gradient(90deg,
+ #0066cc 0%,
+ #0066cc 20%,
+ transparent 20%,
+ transparent 40%,
+ #0066cc 40%,
+ #0066cc 60%,
+ transparent 60%,
+ transparent 80%,
+ #0066cc 80%,
+ #0066cc 100%);
+ background-size: 100px 4px;
+ animation: boardsExplorerLoadingPendulum 2s ease-in-out infinite;
+ border-radius: 2px;
+}
+
+@keyframes boardsExplorerLoadingPendulum {
+ 0% {
+ background-position: -100px 0;
+ }
+
+ 50% {
+ background-position: calc(100% + 100px) 0;
+ }
+
+ 100% {
+ background-position: -100px 0;
+ }
+}
+
/* Responsive design */
@media (max-width: 1024px) {
@@ -9616,4 +9702,30 @@ li[data-task=b]>p>input:checked {
align-items: center;
justify-content: flex-end;
margin-top: 2rem;
-}
\ No newline at end of file
+}
+
+
+/* ---------------------------------------------------- */
+/* SOME COMMON STYLES */
+/* ---------------------------------------------------- */
+
+.tb_opacity_1 {
+ opacity: 1;
+}
+
+.tb_opacity_0 {
+ opacity: 0;
+}
+
+.tb_padding_left_0 {
+ padding-left: 0;
+ padding-inline-start: 0;
+}
+
+.tb_color_white {
+ color: white;
+}
+
+.tb_color_white {
+ color: red;
+}
diff --git a/task-board-logs.log b/task-board-logs.log
new file mode 100644
index 00000000..a7d2b5b7
--- /dev/null
+++ b/task-board-logs.log
@@ -0,0 +1,279 @@
+# Task Board Logs
+
+## System Information
+
+- **Obsidian version**: 1.12.7
+- **Installer version**: 1.12.7
+- **Operating system**: Windows 10 Home Single Language 10.0.19045
+- **Use [[Wikilinks]]**: true
+- **Base color scheme**: dark
+- **Community theme**: none
+- **Snippets enabled**: 0
+- **Plugins installed**: 56
+- **Plugins enabled**:
+ - Task Board v2.0.0-beta-5
+ - Advanced Debug Mode v1.9.1
+ - Plugin Reloader v0.0.3
+ - Tasks v7.22.0
+
+## Recent Bug Reports
+
+Timestamp : 2026-06-14T10:18:57
+ID : 197
+Message :
+Context : Mapping.ts/getCustomStatusOptionsForDropdown
+Version : 2.0.0-beta-4
+
+#### Bug Content
+```log
+No valid statuses after filtering
+```
+
+-------------
+
+Timestamp : 2026-06-14T10:49:30
+ID : 197
+Message :
+Context : Mapping.ts/getCustomStatusOptionsForDropdown
+Version : 2.0.0-beta-4
+
+#### Bug Content
+```log
+No valid statuses after filtering
+```
+
+-------------
+
+Timestamp : 2026-06-14T11:25:37
+ID : 197
+Message :
+Context : Mapping.ts/getCustomStatusOptionsForDropdown
+Version : 2.0.0-beta-4
+
+#### Bug Content
+```log
+No valid statuses after filtering
+```
+
+-------------
+
+Timestamp : 2026-06-14T11:29:27
+ID : 197
+Message :
+Context : Mapping.ts/getCustomStatusOptionsForDropdown
+Version : 2.0.0-beta-4
+
+#### Bug Content
+```log
+No valid statuses after filtering
+```
+
+-------------
+
+Timestamp : 2026-06-14T11:30:27
+ID : 197
+Message :
+Context : Mapping.ts/getCustomStatusOptionsForDropdown
+Version : 2.0.0-beta-4
+
+#### Bug Content
+```log
+No valid statuses after filtering
+```
+
+-------------
+
+Timestamp : 2026-06-14T11:34:48
+ID : 17
+Message : Following duplicate IDs has been found for tasks with IDs: "2". This may cause unexpected behavior. Please consider changing the IDs of these tasks.
+Context : MapView.tsx/initialNodes
+Version : 2.0.0-beta-4
+
+#### Bug Content
+```log
+ERROR: Same id is present on two tasks
+```
+
+-------------
+
+Timestamp : 2026-06-14T11:43:03
+ID : 197
+Message :
+Context : Mapping.ts/getCustomStatusOptionsForDropdown
+Version : 2.0.0-beta-4
+
+#### Bug Content
+```log
+No valid statuses after filtering
+```
+
+-------------
+
+Timestamp : 2026-06-14T22:37:24
+ID : 141
+Message :
+Context : DragDropTasksManager.ts/handleColumnDragOverEvent
+Version : 2.0.0-beta-4
+
+#### Bug Content
+```log
+No source column data available for dragover.
+SourceColumn=null
+```
+
+-------------
+
+Timestamp : 2026-06-14T22:37:25
+ID : 142
+Message :
+Context : DragDropTasksManager.ts/handleDropEvent
+Version : 2.0.0-beta-4
+
+#### Bug Content
+```log
+No current drag data available for drop operation.
+currentDragData=null
+```
+
+-------------
+
+Timestamp : 2026-06-15T00:03:36
+ID : 196
+Message :
+Context : TaskBoardEmbedComponent.tsx/loadFile
+Version : 2.0.0-beta-5
+
+#### Bug Content
+```log
+Error loading task board for embed: TypeError: Cannot read properties of undefined (reading 'contains')
+```
+
+-------------
+
+Timestamp : 2026-06-15T00:04:23
+ID : 196
+Message :
+Context : TaskBoardEmbedComponent.tsx/loadFile
+Version : 2.0.0-beta-5
+
+#### Bug Content
+```log
+Error loading task board for embed: TypeError: Cannot read properties of undefined (reading 'contains')
+```
+
+-------------
+
+Timestamp : 2026-06-15T00:06:35
+ID : 196
+Message :
+Context : TaskBoardEmbedComponent.tsx/loadFile
+Version : 2.0.0-beta-5
+
+#### Bug Content
+```log
+Error loading task board for embed: TypeError: Cannot read properties of undefined (reading 'contains')
+```
+
+-------------
+
+Timestamp : 2026-06-15T00:08:04
+ID : 196
+Message :
+Context : TaskBoardEmbedComponent.tsx/loadFile
+Version : 2.0.0-beta-5
+
+#### Bug Content
+```log
+Error loading task board for embed: TypeError: Cannot read properties of undefined (reading 'contains')
+```
+
+-------------
+
+Timestamp : 2026-06-15T00:34:29
+ID : 17
+Message : Following duplicate IDs has been found for tasks with IDs: "2". This may cause unexpected behavior. Please consider changing the IDs of these tasks.
+Context : MapView.tsx/initialNodes
+Version : 2.0.0-beta-5
+
+#### Bug Content
+```log
+ERROR: Same id is present on two tasks
+```
+
+-------------
+
+Timestamp : 2026-06-15T09:45:16
+ID : 17
+Message : Following duplicate IDs has been found for tasks with IDs: "2". This may cause unexpected behavior. Please consider changing the IDs of these tasks.
+Context : MapView.tsx/initialNodes
+Version : 2.0.0-beta-5
+
+#### Bug Content
+```log
+ERROR: Same id is present on two tasks
+```
+
+-------------
+
+Timestamp : 2026-06-15T10:12:58
+ID : 17
+Message : Following duplicate IDs has been found for tasks with IDs: "2". This may cause unexpected behavior. Please consider changing the IDs of these tasks.
+Context : MapView.tsx/initialNodes
+Version : 2.0.0-beta-5
+
+#### Bug Content
+```log
+ERROR: Same id is present on two tasks
+```
+
+-------------
+
+Timestamp : 2026-06-15T10:19:59
+ID : 17
+Message : Following duplicate IDs has been found for tasks with IDs: "2". This may cause unexpected behavior. Please consider changing the IDs of these tasks.
+Context : MapView.tsx/initialNodes
+Version : 2.0.0-beta-5
+
+#### Bug Content
+```log
+ERROR: Same id is present on two tasks
+```
+
+-------------
+
+Timestamp : 2026-06-15T10:48:42
+ID : 197
+Message :
+Context : Mapping.ts/getCustomStatusOptionsForDropdown
+Version : 2.0.0-beta-5
+
+#### Bug Content
+```log
+No valid statuses after filtering
+```
+
+-------------
+
+Timestamp : 2026-06-15T11:07:44
+ID : 197
+Message :
+Context : Mapping.ts/getCustomStatusOptionsForDropdown
+Version : 2.0.0-beta-5
+
+#### Bug Content
+```log
+No valid statuses after filtering
+```
+
+-------------
+
+Timestamp : 2026-06-15T11:13:28
+ID : 17
+Message : Following duplicate IDs has been found for tasks with IDs: "2". This may cause unexpected behavior. Please consider changing the IDs of these tasks.
+Context : MapView.tsx/initialNodes
+Version : 2.0.0-beta-5
+
+#### Bug Content
+```log
+ERROR: Same id is present on two tasks
+```
diff --git a/tsconfig.json b/tsconfig.json
index 0a592179..f23f4041 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -43,6 +43,7 @@
// "noEmit": true,
},
"include": [
- "src"
+ "src",
+ "main.ts"
]
}
diff --git a/versions.json b/versions.json
index fa6f2103..31cdc62a 100644
--- a/versions.json
+++ b/versions.json
@@ -52,5 +52,6 @@
"2.0.0-beta-1": "1.10.0",
"2.0.0-beta-2": "1.10.0",
"2.0.0-beta-3": "1.10.0",
- "2.0.0-beta-4": "1.10.0"
+ "2.0.0-beta-4": "1.10.0",
+ "2.0.0-beta-5": "1.10.0"
}