mirror of
https://github.com/taskgenius/taskgenius-plugin.git
synced 2026-07-22 06:40:25 +00:00
style: format code with prettier
Applied consistent code formatting across multiple components including trailing commas, quote style normalization, and proper indentation. No functional changes. Files updated: - FluentComponentManager: Consistent trailing commas - KanbanComponent: Code formatting improvements - MarkdownRenderer: Quote and comma consistency - StatusCycler: Formatting cleanup - FluentTaskView: Trailing comma fixes - Calendar/Task components: Minor formatting - CSS files: Formatting improvements
This commit is contained in:
parent
77f58747fd
commit
bc3a1d31d4
10 changed files with 396 additions and 382 deletions
|
|
@ -93,7 +93,7 @@ export class FluentComponentManager extends Component {
|
|||
onTaskContextMenu: (event: MouseEvent, task: Task) => void;
|
||||
onKanbanTaskStatusUpdate: (
|
||||
taskId: string,
|
||||
newStatusMark: string
|
||||
newStatusMark: string,
|
||||
) => void;
|
||||
};
|
||||
|
||||
|
|
@ -107,15 +107,15 @@ export class FluentComponentManager extends Component {
|
|||
onTaskCompleted: (task: Task) => void;
|
||||
onTaskUpdate: (
|
||||
originalTask: Task,
|
||||
updatedTask: Task
|
||||
updatedTask: Task,
|
||||
) => Promise<void>;
|
||||
onTaskContextMenu: (event: MouseEvent, task: Task) => void;
|
||||
onKanbanTaskStatusUpdate: (
|
||||
taskId: string,
|
||||
newStatusMark: string
|
||||
newStatusMark: string,
|
||||
) => void;
|
||||
},
|
||||
private selectionManager?: TaskSelectionManager
|
||||
private selectionManager?: TaskSelectionManager,
|
||||
) {
|
||||
super();
|
||||
this.viewHandlers = viewHandlers;
|
||||
|
|
@ -145,7 +145,7 @@ export class FluentComponentManager extends Component {
|
|||
this.app,
|
||||
this.plugin,
|
||||
this.contentArea,
|
||||
viewHandlers
|
||||
viewHandlers,
|
||||
);
|
||||
this.parentView.addChild(this.viewComponentManager);
|
||||
|
||||
|
|
@ -166,7 +166,7 @@ export class FluentComponentManager extends Component {
|
|||
if (task) this.viewHandlers.onTaskContextMenu(event, task);
|
||||
},
|
||||
selectionManager: this.selectionManager,
|
||||
}
|
||||
},
|
||||
);
|
||||
this.parentView.addChild(this.contentComponent);
|
||||
this.contentComponent.load();
|
||||
|
|
@ -187,14 +187,14 @@ export class FluentComponentManager extends Component {
|
|||
if (originalTask && updatedTask) {
|
||||
await this.viewHandlers.onTaskUpdate(
|
||||
originalTask,
|
||||
updatedTask
|
||||
updatedTask,
|
||||
);
|
||||
}
|
||||
},
|
||||
onTaskContextMenu: (event, task) => {
|
||||
if (task) this.viewHandlers.onTaskContextMenu(event, task);
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
this.parentView.addChild(this.forecastComponent);
|
||||
this.forecastComponent.load();
|
||||
|
|
@ -215,14 +215,14 @@ export class FluentComponentManager extends Component {
|
|||
if (originalTask && updatedTask) {
|
||||
await this.viewHandlers.onTaskUpdate(
|
||||
originalTask,
|
||||
updatedTask
|
||||
updatedTask,
|
||||
);
|
||||
}
|
||||
},
|
||||
onTaskContextMenu: (event, task) => {
|
||||
if (task) this.viewHandlers.onTaskContextMenu(event, task);
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
this.parentView.addChild(this.tagsComponent);
|
||||
this.tagsComponent.load();
|
||||
|
|
@ -243,14 +243,14 @@ export class FluentComponentManager extends Component {
|
|||
if (originalTask && updatedTask) {
|
||||
await this.viewHandlers.onTaskUpdate(
|
||||
originalTask,
|
||||
updatedTask
|
||||
updatedTask,
|
||||
);
|
||||
}
|
||||
},
|
||||
onTaskContextMenu: (event, task) => {
|
||||
if (task) this.viewHandlers.onTaskContextMenu(event, task);
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
this.parentView.addChild(this.projectsComponent);
|
||||
this.projectsComponent.load();
|
||||
|
|
@ -271,14 +271,14 @@ export class FluentComponentManager extends Component {
|
|||
if (originalTask && updatedTask) {
|
||||
await this.viewHandlers.onTaskUpdate(
|
||||
originalTask,
|
||||
updatedTask
|
||||
updatedTask,
|
||||
);
|
||||
}
|
||||
},
|
||||
onTaskContextMenu: (event, task) => {
|
||||
if (task) this.viewHandlers.onTaskContextMenu(event, task);
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
this.parentView.addChild(this.reviewComponent);
|
||||
this.reviewComponent.load();
|
||||
|
|
@ -304,7 +304,7 @@ export class FluentComponentManager extends Component {
|
|||
onEventContextMenu: (ev: MouseEvent, event: Task) => {
|
||||
if (event) this.viewHandlers.onTaskContextMenu(ev, event);
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
this.parentView.addChild(this.calendarComponent);
|
||||
|
||||
|
|
@ -318,7 +318,7 @@ export class FluentComponentManager extends Component {
|
|||
onTaskStatusUpdate: async (taskId, newStatusMark) => {
|
||||
this.viewHandlers.onKanbanTaskStatusUpdate(
|
||||
taskId,
|
||||
newStatusMark
|
||||
newStatusMark,
|
||||
);
|
||||
},
|
||||
onTaskSelected: (task) => {
|
||||
|
|
@ -330,7 +330,7 @@ export class FluentComponentManager extends Component {
|
|||
onTaskContextMenu: (event, task) => {
|
||||
if (task) this.viewHandlers.onTaskContextMenu(event, task);
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
this.parentView.addChild(this.kanbanComponent);
|
||||
|
||||
|
|
@ -345,7 +345,7 @@ export class FluentComponentManager extends Component {
|
|||
this.viewHandlers.onTaskCompleted(task),
|
||||
onTaskContextMenu: (event: MouseEvent, task: Task) =>
|
||||
this.viewHandlers.onTaskContextMenu(event, task),
|
||||
}
|
||||
},
|
||||
);
|
||||
this.parentView.addChild(this.ganttComponent);
|
||||
this.ganttComponent.load();
|
||||
|
|
@ -376,7 +376,7 @@ export class FluentComponentManager extends Component {
|
|||
// Smart hiding - only hide currently visible component (unless initial hide)
|
||||
if (!isInitialHide && this.currentVisibleComponent) {
|
||||
console.log(
|
||||
"[FluentComponent] Smart hide - only hiding current visible component"
|
||||
"[FluentComponent] Smart hide - only hiding current visible component",
|
||||
);
|
||||
this.currentVisibleComponent.containerEl?.hide();
|
||||
this.currentVisibleComponent = null;
|
||||
|
|
@ -384,7 +384,7 @@ export class FluentComponentManager extends Component {
|
|||
// Hide all components
|
||||
console.log(
|
||||
"[FluentComponent] Hiding all components",
|
||||
isInitialHide ? "(initial hide)" : ""
|
||||
isInitialHide ? "(initial hide)" : "",
|
||||
);
|
||||
this.contentComponent?.containerEl.hide();
|
||||
this.forecastComponent?.containerEl.hide();
|
||||
|
|
@ -417,20 +417,20 @@ export class FluentComponentManager extends Component {
|
|||
filteredTasks: Task[],
|
||||
currentFilterState: RootFilterState | null,
|
||||
viewMode: ViewMode,
|
||||
project?: string | null
|
||||
project?: string | null,
|
||||
): void {
|
||||
console.log(
|
||||
"[FluentComponent] switchView called with:",
|
||||
viewId,
|
||||
"viewMode:",
|
||||
viewMode
|
||||
viewMode,
|
||||
);
|
||||
|
||||
// Remove transient overlays (loading/error/empty) before showing components
|
||||
if (this.contentArea) {
|
||||
this.contentArea
|
||||
.querySelectorAll(
|
||||
".tg-fluent-loading, .tg-fluent-error-state, .tg-fluent-empty-state"
|
||||
".tg-fluent-loading, .tg-fluent-error-state, .tg-fluent-empty-state",
|
||||
)
|
||||
.forEach((el) => el.remove());
|
||||
}
|
||||
|
|
@ -457,7 +457,7 @@ export class FluentComponentManager extends Component {
|
|||
viewId,
|
||||
tasks,
|
||||
filteredTasks,
|
||||
viewMode
|
||||
viewMode,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
|
@ -478,7 +478,7 @@ export class FluentComponentManager extends Component {
|
|||
this.app,
|
||||
this.plugin,
|
||||
twoColumnConfig,
|
||||
viewId
|
||||
viewId,
|
||||
);
|
||||
this.parentView.addChild(twoColumnComponent);
|
||||
|
||||
|
|
@ -496,7 +496,7 @@ export class FluentComponentManager extends Component {
|
|||
const twoColumnComponent = this.twoColumnViewComponents.get(viewId);
|
||||
if (!twoColumnComponent) {
|
||||
console.warn(
|
||||
`[FluentComponent] Missing two column component for view ${viewId}`
|
||||
`[FluentComponent] Missing two column component for view ${viewId}`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
|
@ -508,7 +508,7 @@ export class FluentComponentManager extends Component {
|
|||
// Check if it's a special view managed by ViewComponentManager
|
||||
if (this.viewComponentManager.isSpecialView(viewId)) {
|
||||
targetComponent = this.viewComponentManager.showComponent(
|
||||
viewId
|
||||
viewId,
|
||||
) as ManagedViewComponent | null;
|
||||
} else if (
|
||||
specificViewType === "forecast" ||
|
||||
|
|
@ -530,13 +530,13 @@ export class FluentComponentManager extends Component {
|
|||
// 2. Without project selection (from view navigation) → use ProjectsComponent for overview
|
||||
if (project) {
|
||||
console.log(
|
||||
"[FluentComponent] Projects view with selected project - using ContentComponent"
|
||||
"[FluentComponent] Projects view with selected project - using ContentComponent",
|
||||
);
|
||||
targetComponent = this.contentComponent;
|
||||
modeForComponent = viewId;
|
||||
} else {
|
||||
console.log(
|
||||
"[FluentComponent] Projects view without selection - using ProjectsComponent"
|
||||
"[FluentComponent] Projects view without selection - using ProjectsComponent",
|
||||
);
|
||||
targetComponent = this.projectsComponent;
|
||||
modeForComponent = viewId;
|
||||
|
|
@ -569,13 +569,13 @@ export class FluentComponentManager extends Component {
|
|||
|
||||
console.log(
|
||||
"[FluentComponent] Target component determined:",
|
||||
targetComponent?.constructor?.name
|
||||
targetComponent?.constructor?.name,
|
||||
);
|
||||
|
||||
if (targetComponent) {
|
||||
console.log(
|
||||
`[FluentComponent] Activating component for view ${viewId}:`,
|
||||
targetComponent.constructor.name
|
||||
targetComponent.constructor.name,
|
||||
);
|
||||
targetComponent.containerEl.show();
|
||||
this.currentVisibleComponent = targetComponent;
|
||||
|
|
@ -583,7 +583,7 @@ export class FluentComponentManager extends Component {
|
|||
// Set view mode first for ContentComponent
|
||||
if (typeof targetComponent.setViewMode === "function") {
|
||||
console.log(
|
||||
`[FluentComponent] Setting view mode for ${viewId} to ${modeForComponent}`
|
||||
`[FluentComponent] Setting view mode for ${viewId} to ${modeForComponent}`,
|
||||
);
|
||||
targetComponent.setViewMode(modeForComponent as any, project);
|
||||
}
|
||||
|
|
@ -595,7 +595,7 @@ export class FluentComponentManager extends Component {
|
|||
if (viewId === "review" || viewId === "tags") {
|
||||
console.log(
|
||||
`[FluentComponent] Calling setTasks for ${viewId} with ALL tasks:`,
|
||||
tasks.length
|
||||
tasks.length,
|
||||
);
|
||||
targetComponent.setTasks(tasks);
|
||||
} else if (viewId === "projects" && !project) {
|
||||
|
|
@ -603,7 +603,7 @@ export class FluentComponentManager extends Component {
|
|||
// and FILTERED tasks to apply filter to project task lists
|
||||
// This ensures: left sidebar shows all projects, right panel shows filtered tasks
|
||||
console.log(
|
||||
`[FluentComponent] Calling setTasks for projects with ALL tasks (${tasks.length}) and FILTERED tasks (${filteredTasks.length})`
|
||||
`[FluentComponent] Calling setTasks for projects with ALL tasks (${tasks.length}) and FILTERED tasks (${filteredTasks.length})`,
|
||||
);
|
||||
targetComponent.setTasks(tasks, filteredTasks);
|
||||
} else {
|
||||
|
|
@ -612,14 +612,14 @@ export class FluentComponentManager extends Component {
|
|||
// Forecast view: remove badge-only items
|
||||
if (viewId === "forecast") {
|
||||
filteredTasksLocal = filteredTasksLocal.filter(
|
||||
(task) => !(task as any).badge
|
||||
(task) => !(task as any).badge,
|
||||
);
|
||||
}
|
||||
console.log(
|
||||
"[FluentComponent] Calling setTasks with filtered:",
|
||||
filteredTasksLocal.length,
|
||||
"all:",
|
||||
tasks.length
|
||||
tasks.length,
|
||||
);
|
||||
targetComponent.setTasks(filteredTasksLocal, tasks);
|
||||
}
|
||||
|
|
@ -641,8 +641,8 @@ export class FluentComponentManager extends Component {
|
|||
tasks,
|
||||
viewId as any,
|
||||
this.plugin,
|
||||
filterOptions
|
||||
)
|
||||
filterOptions,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -655,7 +655,7 @@ export class FluentComponentManager extends Component {
|
|||
}
|
||||
} else {
|
||||
console.warn(
|
||||
`[FluentComponent] No target component found for viewId: ${viewId}`
|
||||
`[FluentComponent] No target component found for viewId: ${viewId}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -667,11 +667,11 @@ export class FluentComponentManager extends Component {
|
|||
viewId: string,
|
||||
tasks: Task[],
|
||||
filteredTasks: Task[],
|
||||
viewMode: ViewMode
|
||||
viewMode: ViewMode,
|
||||
): void {
|
||||
console.log(
|
||||
"[FluentComponent] renderContentWithViewMode called, viewMode:",
|
||||
viewMode
|
||||
viewMode,
|
||||
);
|
||||
|
||||
// Hide current component
|
||||
|
|
@ -690,7 +690,7 @@ export class FluentComponentManager extends Component {
|
|||
|
||||
console.log(
|
||||
"[FluentComponent] Setting tasks to ContentComponent, filtered:",
|
||||
filteredTasks.length
|
||||
filteredTasks.length,
|
||||
);
|
||||
this.contentComponent.setTasks(filteredTasks, tasks);
|
||||
this.currentVisibleComponent = this.contentComponent;
|
||||
|
|
@ -705,7 +705,7 @@ export class FluentComponentManager extends Component {
|
|||
console.log(
|
||||
"[FluentComponent] Setting",
|
||||
filteredTasks.length,
|
||||
"tasks to kanban"
|
||||
"tasks to kanban",
|
||||
);
|
||||
this.kanbanComponent.setTasks(filteredTasks);
|
||||
this.currentVisibleComponent = this.kanbanComponent;
|
||||
|
|
@ -714,11 +714,11 @@ export class FluentComponentManager extends Component {
|
|||
case "calendar":
|
||||
// Use CalendarComponent
|
||||
console.log(
|
||||
"[FluentComponent] Calendar mode in renderContentWithViewMode"
|
||||
"[FluentComponent] Calendar mode in renderContentWithViewMode",
|
||||
);
|
||||
if (!this.calendarComponent) {
|
||||
console.log(
|
||||
"[FluentComponent] No calendar component available!"
|
||||
"[FluentComponent] No calendar component available!",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
|
@ -729,7 +729,7 @@ export class FluentComponentManager extends Component {
|
|||
console.log(
|
||||
"[FluentComponent] Setting",
|
||||
filteredTasks.length,
|
||||
"tasks to calendar"
|
||||
"tasks to calendar",
|
||||
);
|
||||
this.calendarComponent.setTasks(filteredTasks);
|
||||
this.currentVisibleComponent = this.calendarComponent;
|
||||
|
|
@ -745,7 +745,7 @@ export class FluentComponentManager extends Component {
|
|||
viewId: string,
|
||||
tasks: Task[],
|
||||
filteredTasks: Task[],
|
||||
viewMode: ViewMode
|
||||
viewMode: ViewMode,
|
||||
): void {
|
||||
// Content-based views (list/tree/kanban/calendar)
|
||||
if (this.isContentBasedView(viewId)) {
|
||||
|
|
@ -762,7 +762,7 @@ export class FluentComponentManager extends Component {
|
|||
this.contentComponent?.setTasks?.(
|
||||
filteredTasks,
|
||||
tasks,
|
||||
true
|
||||
true,
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
|
@ -891,7 +891,7 @@ export class FluentComponentManager extends Component {
|
|||
emptyEl.createDiv({
|
||||
cls: "tg-fluent-empty-description",
|
||||
text: t(
|
||||
"Create your first task to get started with Task Genius"
|
||||
"Create your first task to get started with Task Genius",
|
||||
),
|
||||
});
|
||||
|
||||
|
|
@ -925,12 +925,12 @@ export class FluentComponentManager extends Component {
|
|||
*/
|
||||
getAvailableModesForView(
|
||||
viewId: string,
|
||||
selectedProject?: string | null
|
||||
selectedProject?: string | null,
|
||||
): ViewMode[] {
|
||||
// Check for special two-column views
|
||||
const viewConfig = getViewSettingOrDefault(
|
||||
this.plugin,
|
||||
viewId as ViewMode
|
||||
viewId as ViewMode,
|
||||
);
|
||||
if (viewConfig?.specificConfig?.viewType === "twocolumn") {
|
||||
return [];
|
||||
|
|
|
|||
|
|
@ -27,12 +27,6 @@ import {
|
|||
isProjectReadonly,
|
||||
} from "@/utils/task/task-operations";
|
||||
|
||||
// CSS classes for drop indicators
|
||||
const DROP_INDICATOR_BEFORE_CLASS = "tg-kanban-card--drop-indicator-before";
|
||||
const DROP_INDICATOR_AFTER_CLASS = "tg-kanban-card--drop-indicator-after";
|
||||
const DROP_INDICATOR_EMPTY_CLASS =
|
||||
"tg-kanban-column-content--drop-indicator-empty";
|
||||
|
||||
export interface KanbanSortOption {
|
||||
field:
|
||||
| "priority"
|
||||
|
|
@ -60,7 +54,7 @@ export class KanbanComponent extends Component {
|
|||
private params: {
|
||||
onTaskStatusUpdate?: (
|
||||
taskId: string,
|
||||
newStatusMark: string
|
||||
newStatusMark: string,
|
||||
) => Promise<void>;
|
||||
onTaskSelected?: (task: Task) => void;
|
||||
onTaskCompleted?: (task: Task) => void;
|
||||
|
|
@ -85,13 +79,13 @@ export class KanbanComponent extends Component {
|
|||
params: {
|
||||
onTaskStatusUpdate?: (
|
||||
taskId: string,
|
||||
newStatusMark: string
|
||||
newStatusMark: string,
|
||||
) => Promise<void>;
|
||||
onTaskSelected?: (task: Task) => void;
|
||||
onTaskCompleted?: (task: Task) => void;
|
||||
onTaskContextMenu?: (ev: MouseEvent, task: Task) => void;
|
||||
} = {},
|
||||
viewId = "kanban" // 新增:视图ID参数
|
||||
viewId = "kanban", // 新增:视图ID参数
|
||||
) {
|
||||
super();
|
||||
this.app = app;
|
||||
|
|
@ -105,16 +99,18 @@ export class KanbanComponent extends Component {
|
|||
/**
|
||||
* Set configuration override from Bases view config
|
||||
*/
|
||||
public setConfigOverride(config: Partial<KanbanSpecificConfig> | null): void {
|
||||
public setConfigOverride(
|
||||
config: Partial<KanbanSpecificConfig> | null,
|
||||
): void {
|
||||
const isChanged = this.hasConfigOverrideChanged(config);
|
||||
this.configOverride = config;
|
||||
console.log('[Kanban] setConfigOverride received', config);
|
||||
console.log("[Kanban] setConfigOverride received", config);
|
||||
|
||||
if (isChanged) {
|
||||
// Refresh derived state from effective config (sort/hide/column order)
|
||||
this.loadKanbanConfig();
|
||||
const eff = this.getEffectiveKanbanConfig();
|
||||
console.log('[Kanban] effective config after override', eff);
|
||||
console.log("[Kanban] effective config after override", eff);
|
||||
if (this.columnContainerEl) {
|
||||
// Rebuild columns with the new configuration so changes like groupBy
|
||||
// take effect immediately without requiring a data refresh.
|
||||
|
|
@ -125,9 +121,11 @@ export class KanbanComponent extends Component {
|
|||
|
||||
private getEffectiveKanbanConfig(): KanbanSpecificConfig | undefined {
|
||||
const pluginConfig = this.plugin.settings.viewConfiguration.find(
|
||||
(v) => v.id === this.currentViewId
|
||||
(v) => v.id === this.currentViewId,
|
||||
)?.specificConfig as KanbanSpecificConfig;
|
||||
return this.configOverride ? {...(pluginConfig ?? {}), ...this.configOverride} : pluginConfig;
|
||||
return this.configOverride
|
||||
? { ...(pluginConfig ?? {}), ...this.configOverride }
|
||||
: pluginConfig;
|
||||
}
|
||||
|
||||
override onload() {
|
||||
|
|
@ -173,7 +171,7 @@ export class KanbanComponent extends Component {
|
|||
}
|
||||
|
||||
private hasConfigOverrideChanged(
|
||||
nextConfig: Partial<KanbanSpecificConfig> | null
|
||||
nextConfig: Partial<KanbanSpecificConfig> | null,
|
||||
): boolean {
|
||||
if (!this.configOverride && !nextConfig) {
|
||||
return false;
|
||||
|
|
@ -185,7 +183,8 @@ export class KanbanComponent extends Component {
|
|||
|
||||
try {
|
||||
return (
|
||||
JSON.stringify(this.configOverride) !== JSON.stringify(nextConfig)
|
||||
JSON.stringify(this.configOverride) !==
|
||||
JSON.stringify(nextConfig)
|
||||
);
|
||||
} catch (error) {
|
||||
console.warn("Failed to compare kanban config overrides:", error);
|
||||
|
|
@ -211,7 +210,7 @@ export class KanbanComponent extends Component {
|
|||
},
|
||||
(el) => {
|
||||
setIcon(el, "arrow-up-down");
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
this.registerDomEvent(sortButton, "click", (event) => {
|
||||
|
|
@ -265,7 +264,7 @@ export class KanbanComponent extends Component {
|
|||
item.setTitle(option.label)
|
||||
.setChecked(
|
||||
option.field === this.sortOption.field &&
|
||||
option.order === this.sortOption.order
|
||||
option.order === this.sortOption.order,
|
||||
)
|
||||
.onClick(() => {
|
||||
this.sortOption = option;
|
||||
|
|
@ -296,7 +295,7 @@ export class KanbanComponent extends Component {
|
|||
this.applyFiltersAndRender(); // Re-render when filters change
|
||||
},
|
||||
},
|
||||
this.plugin // Pass plugin instance
|
||||
this.plugin, // Pass plugin instance
|
||||
);
|
||||
|
||||
this.addChild(this.filterComponent); // Register as child component
|
||||
|
|
@ -312,7 +311,7 @@ export class KanbanComponent extends Component {
|
|||
this.filterComponent.updateFilterOptions(this.allTasks);
|
||||
} else {
|
||||
console.warn(
|
||||
"Filter component not initialized when setting tasks."
|
||||
"Filter component not initialized when setting tasks.",
|
||||
);
|
||||
// Options will be built when renderFilterControls is called if it hasn't been yet.
|
||||
// If renderFilterControls already ran, this might indicate an issue.
|
||||
|
|
@ -375,7 +374,7 @@ export class KanbanComponent extends Component {
|
|||
return task.filePath === filter.value;
|
||||
default:
|
||||
console.warn(
|
||||
`Unknown filter category in Kanban: ${filter.category}`
|
||||
`Unknown filter category in Kanban: ${filter.category}`,
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -417,7 +416,7 @@ export class KanbanComponent extends Component {
|
|||
|
||||
// Allow multiple symbols to represent the same logical status (e.g., In Progress: "/" and ">")
|
||||
private getAllowedMarksForStatusName(
|
||||
statusName: string
|
||||
statusName: string,
|
||||
): Set<string> | null {
|
||||
if (!statusName) return null;
|
||||
const s = statusName.trim().toLowerCase();
|
||||
|
|
@ -444,7 +443,7 @@ export class KanbanComponent extends Component {
|
|||
raw
|
||||
.split("|")
|
||||
.map((ch: string) => ch.trim())
|
||||
.filter((ch: string) => ch.length === 1)
|
||||
.filter((ch: string) => ch.length === 1),
|
||||
);
|
||||
return set.size > 0 ? set : null;
|
||||
}
|
||||
|
|
@ -452,7 +451,7 @@ export class KanbanComponent extends Component {
|
|||
// Handle filter application from clickable metadata
|
||||
private handleFilterApply = (
|
||||
filterType: string,
|
||||
value: string | number | string[]
|
||||
value: string | number | string[],
|
||||
) => {
|
||||
// Convert value to string for consistent handling
|
||||
let stringValue = Array.isArray(value) ? value[0] : value.toString();
|
||||
|
|
@ -474,7 +473,7 @@ export class KanbanComponent extends Component {
|
|||
|
||||
// Check if filter already exists
|
||||
const existingFilterIndex = this.activeFilters.findIndex(
|
||||
(f) => f.category === filterType && f.value === stringValue
|
||||
(f) => f.category === filterType && f.value === stringValue,
|
||||
);
|
||||
|
||||
if (existingFilterIndex === -1) {
|
||||
|
|
@ -491,7 +490,7 @@ export class KanbanComponent extends Component {
|
|||
this.activeFilters.map((f) => ({
|
||||
category: f.category,
|
||||
value: f.value,
|
||||
}))
|
||||
})),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -534,7 +533,7 @@ export class KanbanComponent extends Component {
|
|||
|
||||
// Resolve effective config (Bases override wins over plugin settings)
|
||||
const kanbanConfig = this.getEffectiveKanbanConfig();
|
||||
console.log('[Kanban] renderColumns effective config', kanbanConfig);
|
||||
console.log("[Kanban] renderColumns effective config", kanbanConfig);
|
||||
|
||||
const groupBy = kanbanConfig?.groupBy || "status";
|
||||
|
||||
|
|
@ -588,7 +587,7 @@ export class KanbanComponent extends Component {
|
|||
statusNames = [...spaceStatus, ...otherStatuses, ...xStatus];
|
||||
|
||||
// Apply saved column order to status names
|
||||
const statusColumns = statusNames.map((name) => ({title: name}));
|
||||
const statusColumns = statusNames.map((name) => ({ title: name }));
|
||||
const orderedStatusColumns = this.applyColumnOrder(statusColumns);
|
||||
const orderedStatusNames = orderedStatusColumns.map((col) => col.title);
|
||||
|
||||
|
|
@ -605,10 +604,10 @@ export class KanbanComponent extends Component {
|
|||
...this.params,
|
||||
onTaskStatusUpdate: (
|
||||
taskId: string,
|
||||
newStatusMark: string
|
||||
newStatusMark: string,
|
||||
) => this.handleStatusUpdate(taskId, newStatusMark),
|
||||
onFilterApply: this.handleFilterApply,
|
||||
}
|
||||
},
|
||||
);
|
||||
this.addChild(column);
|
||||
this.columns.push(column);
|
||||
|
|
@ -617,7 +616,7 @@ export class KanbanComponent extends Component {
|
|||
|
||||
private renderCustomColumns(
|
||||
groupBy: string,
|
||||
customColumns?: KanbanColumnConfig[]
|
||||
customColumns?: KanbanColumnConfig[],
|
||||
) {
|
||||
let columnConfigs: { title: string; value: any; id: string }[] = [];
|
||||
|
||||
|
|
@ -641,7 +640,7 @@ export class KanbanComponent extends Component {
|
|||
orderedColumnConfigs.forEach((config) => {
|
||||
const tasksForColumn = this.getTasksForProperty(
|
||||
groupBy,
|
||||
config.value
|
||||
config.value,
|
||||
);
|
||||
|
||||
const column = new KanbanColumnComponent(
|
||||
|
|
@ -657,10 +656,10 @@ export class KanbanComponent extends Component {
|
|||
taskId,
|
||||
groupBy,
|
||||
config.value,
|
||||
newValue
|
||||
newValue,
|
||||
),
|
||||
onFilterApply: this.handleFilterApply,
|
||||
}
|
||||
},
|
||||
);
|
||||
this.addChild(column);
|
||||
this.columns.push(column);
|
||||
|
|
@ -668,17 +667,17 @@ export class KanbanComponent extends Component {
|
|||
}
|
||||
|
||||
private generateDefaultColumns(
|
||||
groupBy: string
|
||||
groupBy: string,
|
||||
): { title: string; value: any; id: string }[] {
|
||||
switch (groupBy) {
|
||||
case "priority":
|
||||
return [
|
||||
{title: "🔺 Highest", value: 5, id: "priority-5"},
|
||||
{title: "⏫ High", value: 4, id: "priority-4"},
|
||||
{title: "🔼 Medium", value: 3, id: "priority-3"},
|
||||
{title: "🔽 Low", value: 2, id: "priority-2"},
|
||||
{title: "⏬ Lowest", value: 1, id: "priority-1"},
|
||||
{title: "No Priority", value: null, id: "priority-none"},
|
||||
{ title: "🔺 Highest", value: 5, id: "priority-5" },
|
||||
{ title: "⏫ High", value: 4, id: "priority-4" },
|
||||
{ title: "🔼 Medium", value: 3, id: "priority-3" },
|
||||
{ title: "🔽 Low", value: 2, id: "priority-2" },
|
||||
{ title: "⏬ Lowest", value: 1, id: "priority-1" },
|
||||
{ title: "No Priority", value: null, id: "priority-none" },
|
||||
];
|
||||
case "tags":
|
||||
// Get unique tags from all tasks
|
||||
|
|
@ -719,7 +718,7 @@ export class KanbanComponent extends Component {
|
|||
title: project,
|
||||
value: project,
|
||||
id: `project-${project}`,
|
||||
})
|
||||
}),
|
||||
);
|
||||
projectColumns.push({
|
||||
title: "No Project",
|
||||
|
|
@ -741,7 +740,7 @@ export class KanbanComponent extends Component {
|
|||
title: `@${context}`,
|
||||
value: context,
|
||||
id: `context-${context}`,
|
||||
})
|
||||
}),
|
||||
);
|
||||
contextColumns.push({
|
||||
title: "No Context",
|
||||
|
|
@ -758,7 +757,7 @@ export class KanbanComponent extends Component {
|
|||
value: "overdue",
|
||||
id: `${groupBy}-overdue`,
|
||||
},
|
||||
{title: "Today", value: "today", id: `${groupBy}-today`},
|
||||
{ title: "Today", value: "today", id: `${groupBy}-today` },
|
||||
{
|
||||
title: "Tomorrow",
|
||||
value: "tomorrow",
|
||||
|
|
@ -774,8 +773,8 @@ export class KanbanComponent extends Component {
|
|||
value: "nextWeek",
|
||||
id: `${groupBy}-nextWeek`,
|
||||
},
|
||||
{title: "Later", value: "later", id: `${groupBy}-later`},
|
||||
{title: "No Date", value: null, id: `${groupBy}-none`},
|
||||
{ title: "Later", value: "later", id: `${groupBy}-later` },
|
||||
{ title: "No Date", value: null, id: `${groupBy}-none` },
|
||||
];
|
||||
case "filePath":
|
||||
// Get unique file paths from all tasks
|
||||
|
|
@ -791,7 +790,7 @@ export class KanbanComponent extends Component {
|
|||
id: `path-${path.replace(/[^a-zA-Z0-9]/g, "-")}`,
|
||||
}));
|
||||
default:
|
||||
return [{title: "All Tasks", value: null, id: "all"}];
|
||||
return [{ title: "All Tasks", value: null, id: "all" }];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -826,9 +825,9 @@ export class KanbanComponent extends Component {
|
|||
private compareTasks(
|
||||
a: Task,
|
||||
b: Task,
|
||||
sortOption: KanbanSortOption
|
||||
sortOption: KanbanSortOption,
|
||||
): number {
|
||||
const {field, order} = sortOption;
|
||||
const { field, order } = sortOption;
|
||||
let comparison = 0;
|
||||
|
||||
// Ensure both tasks have metadata property
|
||||
|
|
@ -918,8 +917,8 @@ export class KanbanComponent extends Component {
|
|||
dropTargetColumnContent.closest(".tg-kanban-column");
|
||||
const targetColumnTitle = targetColumnEl
|
||||
? (targetColumnEl as HTMLElement).querySelector(
|
||||
".tg-kanban-column-title"
|
||||
)?.textContent
|
||||
".tg-kanban-column-title",
|
||||
)?.textContent
|
||||
: null;
|
||||
|
||||
// Get source column information
|
||||
|
|
@ -927,66 +926,67 @@ export class KanbanComponent extends Component {
|
|||
sourceColumnContent.closest(".tg-kanban-column");
|
||||
const sourceColumnTitle = sourceColumnEl
|
||||
? (sourceColumnEl as HTMLElement).querySelector(
|
||||
".tg-kanban-column-title"
|
||||
)?.textContent
|
||||
".tg-kanban-column-title",
|
||||
)?.textContent
|
||||
: null;
|
||||
|
||||
if (targetColumnTitle && sourceColumnTitle) {
|
||||
const kanbanConfig =
|
||||
this.plugin.settings.viewConfiguration.find(
|
||||
(v) => v.id === this.currentViewId
|
||||
(v) => v.id === this.currentViewId,
|
||||
)?.specificConfig as KanbanSpecificConfig;
|
||||
|
||||
const groupByPlugin = kanbanConfig?.groupBy || "status";
|
||||
const groupBy = (this.getEffectiveKanbanConfig()?.groupBy) || groupByPlugin;
|
||||
const groupBy =
|
||||
this.getEffectiveKanbanConfig()?.groupBy || groupByPlugin;
|
||||
|
||||
if (groupBy === "status") {
|
||||
// Handle status-based grouping (original logic)
|
||||
const targetStatusMark = this.resolveStatusMark(
|
||||
(targetColumnTitle || "").trim()
|
||||
(targetColumnTitle || "").trim(),
|
||||
);
|
||||
if (targetStatusMark !== undefined) {
|
||||
console.log(
|
||||
`Kanban requesting status update for task ${taskId} to status ${targetColumnTitle} (mark: ${targetStatusMark})`
|
||||
`Kanban requesting status update for task ${taskId} to status ${targetColumnTitle} (mark: ${targetStatusMark})`,
|
||||
);
|
||||
await this.handleStatusUpdate(taskId, targetStatusMark);
|
||||
} else {
|
||||
console.warn(
|
||||
`Could not find status mark for status name: ${targetColumnTitle}`
|
||||
`Could not find status mark for status name: ${targetColumnTitle}`,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
const effectiveCustomColumns = (this.getEffectiveKanbanConfig()?.customColumns) || kanbanConfig?.customColumns;
|
||||
const effectiveCustomColumns =
|
||||
this.getEffectiveKanbanConfig()?.customColumns ||
|
||||
kanbanConfig?.customColumns;
|
||||
|
||||
// Handle property-based grouping
|
||||
const targetValue = this.getColumnValueFromTitle(
|
||||
targetColumnTitle,
|
||||
groupBy,
|
||||
effectiveCustomColumns
|
||||
effectiveCustomColumns,
|
||||
);
|
||||
const sourceValue = this.getColumnValueFromTitle(
|
||||
sourceColumnTitle,
|
||||
groupBy,
|
||||
effectiveCustomColumns
|
||||
effectiveCustomColumns,
|
||||
);
|
||||
console.log(
|
||||
`Kanban requesting ${groupBy} update for task ${taskId} from ${sourceValue} to value: ${targetValue}`
|
||||
`Kanban requesting ${groupBy} update for task ${taskId} from ${sourceValue} to value: ${targetValue}`,
|
||||
);
|
||||
await this.handlePropertyUpdate(
|
||||
taskId,
|
||||
groupBy,
|
||||
sourceValue,
|
||||
targetValue
|
||||
targetValue,
|
||||
);
|
||||
}
|
||||
|
||||
// After update, select the moved task so the status panel (details) reflects changes
|
||||
const movedTask =
|
||||
this.allTasks.find((t) => t.id === taskId) ||
|
||||
this.tasks.find((t) => t.id === taskId);
|
||||
if (movedTask && this.params?.onTaskSelected) {
|
||||
this.params.onTaskSelected(movedTask);
|
||||
}
|
||||
// Don't auto-select task after drag to avoid unwanted detail panel opening
|
||||
// Users can manually click the card if they want to see details
|
||||
//
|
||||
// Previously: Auto-selected moved task so status panel reflects changes
|
||||
// Issue: This opens detail panel after every drag operation, disrupting workflow
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1001,10 +1001,10 @@ export class KanbanComponent extends Component {
|
|||
order: kanbanConfig.defaultSortOrder || "desc",
|
||||
label: this.getSortOptionLabel(
|
||||
kanbanConfig.defaultSortField || "priority",
|
||||
kanbanConfig.defaultSortOrder || "desc"
|
||||
kanbanConfig.defaultSortOrder || "desc",
|
||||
),
|
||||
};
|
||||
console.log('[Kanban] loadKanbanConfig applied', {
|
||||
console.log("[Kanban] loadKanbanConfig applied", {
|
||||
hideEmptyColumns: this.hideEmptyColumns,
|
||||
defaultSortField: this.sortOption.field,
|
||||
defaultSortOrder: this.sortOption.order,
|
||||
|
|
@ -1044,7 +1044,7 @@ export class KanbanComponent extends Component {
|
|||
if (typeof exact === "string") return exact;
|
||||
// Try case-insensitive match
|
||||
for (const [name, mark] of Object.entries(
|
||||
this.plugin.settings.taskStatusMarks
|
||||
this.plugin.settings.taskStatusMarks,
|
||||
)) {
|
||||
if (name.toLowerCase() === trimmed.toLowerCase()) {
|
||||
return mark as string;
|
||||
|
|
@ -1059,14 +1059,23 @@ export class KanbanComponent extends Component {
|
|||
|
||||
private async handleStatusUpdate(
|
||||
taskId: string,
|
||||
newStatusMark: string
|
||||
newStatusMark: string,
|
||||
): Promise<void> {
|
||||
console.log(`[Kanban] handleStatusUpdate called: taskId=${taskId}, mark=${newStatusMark}`);
|
||||
console.log('[Kanban] onTaskStatusUpdate callback exists:', !!this.params.onTaskStatusUpdate);
|
||||
|
||||
if (this.params.onTaskStatusUpdate) {
|
||||
try {
|
||||
console.log('[Kanban] Calling onTaskStatusUpdate callback...');
|
||||
await this.params.onTaskStatusUpdate(taskId, newStatusMark);
|
||||
console.log('[Kanban] onTaskStatusUpdate callback completed successfully');
|
||||
} catch (error) {
|
||||
console.error("Failed to update task status:", error);
|
||||
console.error("[Kanban] Failed to update task status:", error);
|
||||
console.error("[Kanban] Error details:", error.stack);
|
||||
}
|
||||
} else {
|
||||
console.error('[Kanban] CRITICAL: onTaskStatusUpdate callback is not defined!');
|
||||
console.error('[Kanban] this.params:', this.params);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1074,7 +1083,7 @@ export class KanbanComponent extends Component {
|
|||
taskId: string,
|
||||
groupBy: string,
|
||||
oldValue: any,
|
||||
newValue: string
|
||||
newValue: string,
|
||||
): Promise<void> {
|
||||
// This method will handle updating task properties when dragged between columns
|
||||
if (groupBy === "status") {
|
||||
|
|
@ -1086,7 +1095,7 @@ export class KanbanComponent extends Component {
|
|||
const taskToUpdate = this.allTasks.find((task) => task.id === taskId);
|
||||
if (!taskToUpdate) {
|
||||
console.warn(
|
||||
`Task with ID ${taskId} not found for property update`
|
||||
`Task with ID ${taskId} not found for property update`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
|
@ -1094,7 +1103,7 @@ export class KanbanComponent extends Component {
|
|||
taskToUpdate.metadata = taskToUpdate.metadata || {};
|
||||
|
||||
// Create updated task object
|
||||
const updatedTask = {...taskToUpdate};
|
||||
const updatedTask = { ...taskToUpdate };
|
||||
|
||||
// Update the specific property based on groupBy type
|
||||
switch (groupBy) {
|
||||
|
|
@ -1130,7 +1139,7 @@ export class KanbanComponent extends Component {
|
|||
];
|
||||
|
||||
currentTags = currentTags.filter(
|
||||
(tag) => !oldTagVariants.includes(tag)
|
||||
(tag) => !oldTagVariants.includes(tag),
|
||||
);
|
||||
console.log("Tags after removing old:", currentTags);
|
||||
}
|
||||
|
|
@ -1146,7 +1155,7 @@ export class KanbanComponent extends Component {
|
|||
];
|
||||
|
||||
const hasNewTag = currentTags.some((tag) =>
|
||||
newTagVariants.includes(tag)
|
||||
newTagVariants.includes(tag),
|
||||
);
|
||||
if (!hasNewTag) {
|
||||
// Add the tag in the same format as existing tags, or without # if no existing tags
|
||||
|
|
@ -1194,7 +1203,7 @@ export class KanbanComponent extends Component {
|
|||
break;
|
||||
default:
|
||||
console.warn(
|
||||
`Unsupported property type for update: ${groupBy}`
|
||||
`Unsupported property type for update: ${groupBy}`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
|
@ -1205,7 +1214,7 @@ export class KanbanComponent extends Component {
|
|||
`Updating task ${taskId} ${groupBy} from:`,
|
||||
oldValue,
|
||||
"to:",
|
||||
newValue
|
||||
newValue,
|
||||
);
|
||||
if (this.plugin.writeAPI) {
|
||||
const result = await this.plugin.writeAPI.updateTask({
|
||||
|
|
@ -1215,7 +1224,7 @@ export class KanbanComponent extends Component {
|
|||
if (!result.success) {
|
||||
console.error(
|
||||
`Failed to update task ${taskId} property ${groupBy}:`,
|
||||
result.error
|
||||
result.error,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
|
|
@ -1224,7 +1233,7 @@ export class KanbanComponent extends Component {
|
|||
} catch (error) {
|
||||
console.error(
|
||||
`Failed to update task ${taskId} property ${groupBy}:`,
|
||||
error
|
||||
error,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1246,7 +1255,7 @@ export class KanbanComponent extends Component {
|
|||
return (
|
||||
metadata.tags &&
|
||||
metadata.tags.some(
|
||||
(tag) => typeof tag === "string" && tag === value
|
||||
(tag) => typeof tag === "string" && tag === value,
|
||||
)
|
||||
);
|
||||
case "project":
|
||||
|
|
@ -1281,18 +1290,18 @@ export class KanbanComponent extends Component {
|
|||
private matchesDateCategory(
|
||||
task: Task,
|
||||
dateField: string,
|
||||
category: string
|
||||
category: string,
|
||||
): boolean {
|
||||
const now = new Date();
|
||||
const today = new Date(
|
||||
now.getFullYear(),
|
||||
now.getMonth(),
|
||||
now.getDate()
|
||||
now.getDate(),
|
||||
);
|
||||
const tomorrow = new Date(today.getTime() + 24 * 60 * 60 * 1000);
|
||||
const weekFromNow = new Date(today.getTime() + 7 * 24 * 60 * 60 * 1000);
|
||||
const twoWeeksFromNow = new Date(
|
||||
today.getTime() + 14 * 24 * 60 * 60 * 1000
|
||||
today.getTime() + 14 * 24 * 60 * 60 * 1000,
|
||||
);
|
||||
|
||||
const metadata = task.metadata || {};
|
||||
|
|
@ -1324,7 +1333,7 @@ export class KanbanComponent extends Component {
|
|||
return (
|
||||
taskDateObj >= tomorrow &&
|
||||
taskDateObj <
|
||||
new Date(tomorrow.getTime() + 24 * 60 * 60 * 1000)
|
||||
new Date(tomorrow.getTime() + 24 * 60 * 60 * 1000)
|
||||
);
|
||||
case "thisWeek":
|
||||
return taskDateObj >= tomorrow && taskDateObj < weekFromNow;
|
||||
|
|
@ -1346,7 +1355,7 @@ export class KanbanComponent extends Component {
|
|||
private getColumnValueFromTitle(
|
||||
title: string,
|
||||
groupBy: string,
|
||||
customColumns?: KanbanColumnConfig[]
|
||||
customColumns?: KanbanColumnConfig[],
|
||||
): any {
|
||||
console.log("customColumns", customColumns);
|
||||
if (customColumns && customColumns.length > 0) {
|
||||
|
|
@ -1393,7 +1402,7 @@ export class KanbanComponent extends Component {
|
|||
}
|
||||
|
||||
private convertDateCategoryToTimestamp(
|
||||
category: string
|
||||
category: string,
|
||||
): number | undefined {
|
||||
if (category === null || category === "" || category === "none") {
|
||||
return undefined;
|
||||
|
|
@ -1403,7 +1412,7 @@ export class KanbanComponent extends Component {
|
|||
const today = new Date(
|
||||
now.getFullYear(),
|
||||
now.getMonth(),
|
||||
now.getDate()
|
||||
now.getDate(),
|
||||
);
|
||||
|
||||
switch (category) {
|
||||
|
|
@ -1415,19 +1424,19 @@ export class KanbanComponent extends Component {
|
|||
return today.getTime();
|
||||
case "tomorrow":
|
||||
return new Date(
|
||||
today.getTime() + 24 * 60 * 60 * 1000
|
||||
today.getTime() + 24 * 60 * 60 * 1000,
|
||||
).getTime();
|
||||
case "thisWeek":
|
||||
// Set to end of this week (Sunday)
|
||||
const daysUntilSunday = 7 - today.getDay();
|
||||
return new Date(
|
||||
today.getTime() + daysUntilSunday * 24 * 60 * 60 * 1000
|
||||
today.getTime() + daysUntilSunday * 24 * 60 * 60 * 1000,
|
||||
).getTime();
|
||||
case "nextWeek":
|
||||
// Set to end of next week
|
||||
const daysUntilNextSunday = 14 - today.getDay();
|
||||
return new Date(
|
||||
today.getTime() + daysUntilNextSunday * 24 * 60 * 60 * 1000
|
||||
today.getTime() + daysUntilNextSunday * 24 * 60 * 60 * 1000,
|
||||
).getTime();
|
||||
case "later":
|
||||
// Set to one month from now
|
||||
|
|
@ -1448,7 +1457,7 @@ export class KanbanComponent extends Component {
|
|||
// We need to check against the current column configuration
|
||||
const kanbanConfig =
|
||||
this.plugin.settings.viewConfiguration.find(
|
||||
(v) => v.id === this.currentViewId
|
||||
(v) => v.id === this.currentViewId,
|
||||
)?.specificConfig as KanbanSpecificConfig;
|
||||
|
||||
if (
|
||||
|
|
@ -1469,7 +1478,7 @@ export class KanbanComponent extends Component {
|
|||
metadata.tags.some(
|
||||
(tag) =>
|
||||
typeof tag === "string" &&
|
||||
tag === column.value
|
||||
tag === column.value,
|
||||
)
|
||||
) {
|
||||
return column.value;
|
||||
|
|
@ -1483,7 +1492,7 @@ export class KanbanComponent extends Component {
|
|||
}
|
||||
// Return the first string tag (for simplicity, as we need to determine which column it came from)
|
||||
const firstStringTag = metadata.tags.find(
|
||||
(tag) => typeof tag === "string"
|
||||
(tag) => typeof tag === "string",
|
||||
);
|
||||
return firstStringTag || "";
|
||||
}
|
||||
|
|
@ -1516,12 +1525,12 @@ export class KanbanComponent extends Component {
|
|||
const today = new Date(
|
||||
now.getFullYear(),
|
||||
now.getMonth(),
|
||||
now.getDate()
|
||||
now.getDate(),
|
||||
);
|
||||
const tomorrow = new Date(today.getTime() + 24 * 60 * 60 * 1000);
|
||||
const weekFromNow = new Date(today.getTime() + 7 * 24 * 60 * 60 * 1000);
|
||||
const twoWeeksFromNow = new Date(
|
||||
today.getTime() + 14 * 24 * 60 * 60 * 1000
|
||||
today.getTime() + 14 * 24 * 60 * 60 * 1000,
|
||||
);
|
||||
|
||||
const taskDate = new Date(timestamp);
|
||||
|
|
@ -1563,7 +1572,7 @@ export class KanbanComponent extends Component {
|
|||
} catch (error) {
|
||||
console.warn(
|
||||
"Failed to load column order from localStorage:",
|
||||
error
|
||||
error,
|
||||
);
|
||||
this.columnOrder = [];
|
||||
}
|
||||
|
|
@ -1580,7 +1589,7 @@ export class KanbanComponent extends Component {
|
|||
}
|
||||
|
||||
private applyColumnOrder<T extends { title: string; id?: string }>(
|
||||
columns: T[]
|
||||
columns: T[],
|
||||
): T[] {
|
||||
try {
|
||||
if (this.columnOrder.length === 0) {
|
||||
|
|
@ -1589,7 +1598,7 @@ export class KanbanComponent extends Component {
|
|||
|
||||
if (!Array.isArray(columns)) {
|
||||
console.warn(
|
||||
"Invalid columns array provided to applyColumnOrder"
|
||||
"Invalid columns array provided to applyColumnOrder",
|
||||
);
|
||||
return [];
|
||||
}
|
||||
|
|
@ -1603,11 +1612,11 @@ export class KanbanComponent extends Component {
|
|||
const columnIndex = remainingColumns.findIndex(
|
||||
(col) =>
|
||||
(col.id && col.id === orderedId) ||
|
||||
col.title === orderedId
|
||||
col.title === orderedId,
|
||||
);
|
||||
if (columnIndex !== -1) {
|
||||
orderedColumns.push(
|
||||
remainingColumns.splice(columnIndex, 1)[0]
|
||||
remainingColumns.splice(columnIndex, 1)[0],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1667,12 +1676,12 @@ export class KanbanComponent extends Component {
|
|||
|
||||
columnElements.forEach((columnEl) => {
|
||||
const columnTitle = (columnEl as HTMLElement).querySelector(
|
||||
".tg-kanban-column-title"
|
||||
".tg-kanban-column-title",
|
||||
)?.textContent;
|
||||
if (columnTitle) {
|
||||
// Use the data-status-name attribute if available, otherwise use title
|
||||
const statusName = (columnEl as HTMLElement).getAttribute(
|
||||
"data-status-name"
|
||||
"data-status-name",
|
||||
);
|
||||
const columnId = statusName || columnTitle;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import { App, Component } from "obsidian";
|
|||
import { Task } from "@/types/task";
|
||||
import { TaskListItemComponent } from "./listItem";
|
||||
import { TaskTreeItemComponent } from "./treeItem";
|
||||
import { tasksToTree } from "@/utils/ui/tree-view-utils";
|
||||
import { t } from "@/translations/helper";
|
||||
import TaskProgressBarPlugin from "@/index";
|
||||
|
||||
|
|
@ -22,7 +21,7 @@ export class TaskListRendererComponent extends Component {
|
|||
private containerEl: HTMLElement, // The HTML element to render tasks into
|
||||
private plugin: TaskProgressBarPlugin,
|
||||
private app: App,
|
||||
private context: string // Context identifier (e.g., "projects", "review")
|
||||
private context: string, // Context identifier (e.g., "projects", "review")
|
||||
) {
|
||||
super();
|
||||
// Add this renderer as a child of the parent component
|
||||
|
|
@ -43,7 +42,7 @@ export class TaskListRendererComponent extends Component {
|
|||
isTreeView: boolean,
|
||||
allTasksMap: Map<string, Task>, // Make it optional but required for tree view
|
||||
emptyMessage: string = t("No tasks found."),
|
||||
append: boolean = false
|
||||
append: boolean = false,
|
||||
) {
|
||||
if (!append) {
|
||||
this.cleanupComponents();
|
||||
|
|
@ -62,7 +61,7 @@ export class TaskListRendererComponent extends Component {
|
|||
// Fallback: if tree view is requested but no map provided, build it from section tasks
|
||||
// This might lead to incomplete trees if parents are outside the section.
|
||||
console.warn(
|
||||
"TaskListRendererComponent: allTasksMap not provided for tree view. Tree may be incomplete."
|
||||
"TaskListRendererComponent: allTasksMap not provided for tree view. Tree may be incomplete.",
|
||||
);
|
||||
this.allTasksMap = new Map(tasks.map((task) => [task.id, task]));
|
||||
}
|
||||
|
|
@ -70,10 +69,10 @@ export class TaskListRendererComponent extends Component {
|
|||
if (isTreeView) {
|
||||
if (!this.allTasksMap || this.allTasksMap.size === 0) {
|
||||
console.error(
|
||||
"TaskListRendererComponent: Cannot render tree view without allTasksMap."
|
||||
"TaskListRendererComponent: Cannot render tree view without allTasksMap.",
|
||||
);
|
||||
this.renderEmptyState(
|
||||
"Error: Task data unavailable for tree view."
|
||||
"Error: Task data unavailable for tree view.",
|
||||
); // Show error
|
||||
return;
|
||||
}
|
||||
|
|
@ -90,7 +89,7 @@ export class TaskListRendererComponent extends Component {
|
|||
task,
|
||||
this.context,
|
||||
this.app,
|
||||
this.plugin
|
||||
this.plugin,
|
||||
);
|
||||
|
||||
// Set up event handlers
|
||||
|
|
@ -109,13 +108,13 @@ export class TaskListRendererComponent extends Component {
|
|||
"TaskListRendererComponent onTaskUpdate",
|
||||
this.onTaskUpdate,
|
||||
originalTask.content,
|
||||
updatedTask.content
|
||||
updatedTask.content,
|
||||
);
|
||||
if (this.onTaskUpdate) {
|
||||
console.log(
|
||||
"TaskListRendererComponent onTaskUpdate",
|
||||
originalTask.content,
|
||||
updatedTask.content
|
||||
updatedTask.content,
|
||||
);
|
||||
await this.onTaskUpdate(originalTask, updatedTask);
|
||||
}
|
||||
|
|
@ -141,7 +140,7 @@ export class TaskListRendererComponent extends Component {
|
|||
|
||||
private renderTreeView(
|
||||
sectionTasks: Task[],
|
||||
allTasksMap: Map<string, Task>
|
||||
allTasksMap: Map<string, Task>,
|
||||
) {
|
||||
const fragment = document.createDocumentFragment();
|
||||
const sectionTaskIds = new Set(sectionTasks.map((t) => t.id)); // IDs of tasks belonging to this section
|
||||
|
|
@ -151,7 +150,7 @@ export class TaskListRendererComponent extends Component {
|
|||
const markSubtreeAsProcessed = (
|
||||
rootTask: Task,
|
||||
sectionTaskIds: Set<string>,
|
||||
processedTaskIds: Set<string>
|
||||
processedTaskIds: Set<string>,
|
||||
) => {
|
||||
if (sectionTaskIds.has(rootTask.id)) {
|
||||
processedTaskIds.add(rootTask.id);
|
||||
|
|
@ -164,7 +163,7 @@ export class TaskListRendererComponent extends Component {
|
|||
markSubtreeAsProcessed(
|
||||
childTask,
|
||||
sectionTaskIds,
|
||||
processedTaskIds
|
||||
processedTaskIds,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
|
@ -197,11 +196,11 @@ export class TaskListRendererComponent extends Component {
|
|||
!sectionTaskIds.has(currentTask.metadata.parent)
|
||||
) {
|
||||
const parentTask = allTasksMap.get(
|
||||
currentTask.metadata.parent
|
||||
currentTask.metadata.parent,
|
||||
);
|
||||
if (!parentTask) {
|
||||
console.warn(
|
||||
`Parent task ${currentTask.metadata.parent} not found in allTasksMap.`
|
||||
`Parent task ${currentTask.metadata.parent} not found in allTasksMap.`,
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
|
@ -219,7 +218,7 @@ export class TaskListRendererComponent extends Component {
|
|||
markSubtreeAsProcessed(
|
||||
actualRoot,
|
||||
sectionTaskIds,
|
||||
processedTaskIds
|
||||
processedTaskIds,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -238,7 +237,7 @@ export class TaskListRendererComponent extends Component {
|
|||
directChildren.push(childTask);
|
||||
} else {
|
||||
console.warn(
|
||||
`Child task ${childId} (parent: ${rootTask.id}) not found in allTasksMap.`
|
||||
`Child task ${childId} (parent: ${rootTask.id}) not found in allTasksMap.`,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
|
@ -253,7 +252,7 @@ export class TaskListRendererComponent extends Component {
|
|||
0, // Root level is 0
|
||||
directChildren, // Pass the actual children from the full map
|
||||
allTasksMap, // Pass the full map for recursive building
|
||||
this.plugin
|
||||
this.plugin,
|
||||
);
|
||||
|
||||
// Set up event handlers
|
||||
|
|
@ -302,7 +301,7 @@ export class TaskListRendererComponent extends Component {
|
|||
|
||||
// Try updating in list view components
|
||||
const listItemComponent = this.taskComponents.find(
|
||||
(c) => c.getTask().id === updatedTask.id
|
||||
(c) => c.getTask().id === updatedTask.id,
|
||||
);
|
||||
if (listItemComponent) {
|
||||
listItemComponent.updateTask(updatedTask);
|
||||
|
|
|
|||
|
|
@ -177,6 +177,8 @@ export class ContentComponent extends Component {
|
|||
if (viewToggleBtn) {
|
||||
setIcon(viewToggleBtn, this.isTreeView ? "git-branch" : "list");
|
||||
}
|
||||
|
||||
console.log("toggle view mode");
|
||||
// Save the new view mode state
|
||||
saveViewMode(this.app, this.currentViewId, this.isTreeView);
|
||||
this.refreshTaskList(); // Refresh list completely on view mode change
|
||||
|
|
@ -258,11 +260,6 @@ export class ContentComponent extends Component {
|
|||
const viewConfig = getViewSettingOrDefault(this.plugin, viewId);
|
||||
let title = t(viewConfig.name);
|
||||
|
||||
// Special handling for project view title (if needed, maybe handled by component itself)
|
||||
// if (viewId === "projects" && this.selectedProjectForView) {
|
||||
// const projectName = this.selectedProjectForView.split("/").pop();
|
||||
// title = projectName || t("Project");
|
||||
// }
|
||||
this.titleEl.setText(title);
|
||||
|
||||
// Re-initialize view mode for the new view
|
||||
|
|
@ -374,6 +371,7 @@ export class ContentComponent extends Component {
|
|||
}
|
||||
|
||||
private refreshTaskList() {
|
||||
console.log("refreshing");
|
||||
// Defer rendering if container is not visible yet (e.g., view hidden during init)
|
||||
if (!this.isContainerVisible()) {
|
||||
this.pendingForceRefresh = true;
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ export function clearAllMarks(markdown: string): string {
|
|||
const escapedSymbol = symbol.replace(/[.*+?^${}()|[\\\]]/g, "\\$&");
|
||||
const regex = new RegExp(
|
||||
`${escapedSymbol}\\uFE0F? *\\d{4}-\\d{2}-\\d{2}`, // Use escaped symbol
|
||||
"gu"
|
||||
"gu",
|
||||
);
|
||||
cleanedMarkdown = cleanedMarkdown.replace(regex, "");
|
||||
});
|
||||
|
|
@ -119,7 +119,7 @@ export function clearAllMarks(markdown: string): string {
|
|||
// First remove priority emojis anywhere in the text (with optional variation selector)
|
||||
cleanedMarkdown = cleanedMarkdown.replace(
|
||||
/(?:🔺|⏫|🔼|🔽|⏬️?|\[#[A-E]\])/gu,
|
||||
""
|
||||
"",
|
||||
);
|
||||
|
||||
// Remove standalone exclamation marks (priority indicators)
|
||||
|
|
@ -138,7 +138,7 @@ export function clearAllMarks(markdown: string): string {
|
|||
const escapedRecurrenceSymbol =
|
||||
DEFAULT_SYMBOLS.recurrenceSymbol.replace(
|
||||
/[.*+?^${}()|[\\\]]/g,
|
||||
"\\$&"
|
||||
"\\$&",
|
||||
);
|
||||
// Create a string of escaped date/completion symbols for the lookahead
|
||||
const escapedOtherSymbols = symbolsToRemove
|
||||
|
|
@ -152,9 +152,9 @@ export function clearAllMarks(markdown: string): string {
|
|||
|
||||
const recurrenceRegex = new RegExp(
|
||||
`${escapedRecurrenceSymbol}\\uFE0F? *.*?` +
|
||||
// Lookahead for: space followed by (any date/completion/recurrence symbol OR non-date symbols OR @ OR #) OR end of string
|
||||
`(?=\s(?:[${escapedOtherSymbols}${escapedNonDateSymbols}${escapedRecurrenceSymbol}]|@|#)|$)`,
|
||||
"gu"
|
||||
// Lookahead for: space followed by (any date/completion/recurrence symbol OR non-date symbols OR @ OR #) OR end of string
|
||||
`(?=\s(?:[${escapedOtherSymbols}${escapedNonDateSymbols}${escapedRecurrenceSymbol}]|@|#)|$)`,
|
||||
"gu",
|
||||
);
|
||||
cleanedMarkdown = cleanedMarkdown.replace(recurrenceRegex, "");
|
||||
}
|
||||
|
|
@ -163,7 +163,7 @@ export function clearAllMarks(markdown: string): string {
|
|||
cleanedMarkdown = cleanedMarkdown.replace(
|
||||
/\[(?:due|📅|completion|✅|created|➕|start|🛫|scheduled|⏳|cancelled|❌|id|🆔|dependsOn|⛔|onCompletion|🏁|priority|repeat|recurrence|🔁|project|context)::\s*[^\]]+\]/gi,
|
||||
// Corrected the emoji in the previous attempt
|
||||
""
|
||||
"",
|
||||
);
|
||||
|
||||
// --- General Cleaning ---
|
||||
|
|
@ -202,7 +202,7 @@ export function clearAllMarks(markdown: string): string {
|
|||
const overlaps = preservedSegments.some(
|
||||
(ps) =>
|
||||
Math.max(ps.index, currentStart) <
|
||||
Math.min(ps.index + ps.length, currentEnd)
|
||||
Math.min(ps.index + ps.length, currentEnd),
|
||||
);
|
||||
if (!overlaps) {
|
||||
preservedSegments.push({
|
||||
|
|
@ -222,7 +222,7 @@ export function clearAllMarks(markdown: string): string {
|
|||
const overlaps = preservedSegments.some(
|
||||
(ps) =>
|
||||
Math.max(ps.index, currentStart) <
|
||||
Math.min(ps.index + ps.length, currentEnd)
|
||||
Math.min(ps.index + ps.length, currentEnd),
|
||||
);
|
||||
if (!overlaps) {
|
||||
preservedSegments.push({
|
||||
|
|
@ -268,7 +268,7 @@ export function clearAllMarks(markdown: string): string {
|
|||
// Remove any remaining simple tags but preserve special tags like #123-123-123
|
||||
// Also ignore escaped \# (do not treat as tag)
|
||||
tempMarkdown = (function removeSimpleTagsIgnoringEscapes(
|
||||
input: string
|
||||
input: string,
|
||||
): string {
|
||||
let out = "";
|
||||
let i = 0;
|
||||
|
|
@ -326,7 +326,7 @@ export function clearAllMarks(markdown: string): string {
|
|||
// Task marker and final cleaning (applied to the string with links/code restored)
|
||||
tempMarkdown = tempMarkdown.replace(
|
||||
/^([\s>]*)?(-|\d+\.|\*|\+)\s\[([^\[\]]{1})\]\s*/,
|
||||
""
|
||||
"",
|
||||
);
|
||||
tempMarkdown = tempMarkdown.replace(/^# /, "");
|
||||
tempMarkdown = tempMarkdown.replace(/\s+/g, " ").trim();
|
||||
|
|
@ -343,15 +343,15 @@ export class MarkdownRendererComponent extends Component {
|
|||
private container: HTMLElement;
|
||||
private sourcePath: string;
|
||||
private currentFile: TFile | null = null;
|
||||
private renderQueue: Array<{ markdown: string; blockId?: string }> = [];
|
||||
private isRendering: boolean = false;
|
||||
private renderQueue: Array<{ markdown: string; contentId?: string }> = [];
|
||||
private isRendering = false;
|
||||
private blockElements: Map<string, HTMLElement> = new Map();
|
||||
|
||||
constructor(
|
||||
private app: App,
|
||||
container: HTMLElement,
|
||||
sourcePath: string = "",
|
||||
private hideMarks: boolean = true
|
||||
sourcePath = "",
|
||||
private hideMarks: boolean = true,
|
||||
) {
|
||||
super();
|
||||
this.container = container;
|
||||
|
|
@ -381,7 +381,7 @@ export class MarkdownRendererComponent extends Component {
|
|||
*/
|
||||
public async render(
|
||||
markdown: string,
|
||||
clearContainer: boolean = true
|
||||
clearContainer = true,
|
||||
): Promise<void> {
|
||||
if (clearContainer) {
|
||||
this.clear();
|
||||
|
|
@ -392,15 +392,15 @@ export class MarkdownRendererComponent extends Component {
|
|||
|
||||
// Create block elements for each content block
|
||||
for (let i = 0; i < blocks.length; i++) {
|
||||
const blockId = `block-${Date.now()}-${i}`;
|
||||
const contentId = `content-${Date.now()}-${i}`;
|
||||
const blockEl = this.container.createEl("div", {
|
||||
cls: ["markdown-block", "markdown-renderer"],
|
||||
});
|
||||
blockEl.dataset.blockId = blockId;
|
||||
this.blockElements.set(blockId, blockEl);
|
||||
blockEl.dataset.contentId = contentId;
|
||||
this.blockElements.set(contentId, blockEl);
|
||||
|
||||
// Queue this block for rendering
|
||||
this.queueRender(blocks[i], blockId);
|
||||
this.queueRender(blocks[i], contentId);
|
||||
}
|
||||
|
||||
// Start processing the queue
|
||||
|
|
@ -425,8 +425,8 @@ export class MarkdownRendererComponent extends Component {
|
|||
/**
|
||||
* Queue a markdown block for rendering
|
||||
*/
|
||||
private queueRender(markdown: string, blockId?: string): void {
|
||||
this.renderQueue.push({markdown, blockId});
|
||||
private queueRender(markdown: string, contentId?: string): void {
|
||||
this.renderQueue.push({ markdown, contentId });
|
||||
this.processRenderQueue();
|
||||
}
|
||||
|
||||
|
|
@ -445,11 +445,11 @@ export class MarkdownRendererComponent extends Component {
|
|||
const item = this.renderQueue.shift();
|
||||
if (!item) continue;
|
||||
|
||||
const {markdown, blockId} = item;
|
||||
const { markdown, contentId } = item;
|
||||
|
||||
if (blockId) {
|
||||
if (contentId) {
|
||||
// Render to a specific block
|
||||
const blockEl = this.blockElements.get(blockId);
|
||||
const blockEl = this.blockElements.get(contentId);
|
||||
if (blockEl) {
|
||||
blockEl.empty();
|
||||
await ObsidianMarkdownRenderer.render(
|
||||
|
|
@ -457,7 +457,7 @@ export class MarkdownRendererComponent extends Component {
|
|||
markdown,
|
||||
blockEl,
|
||||
this.sourcePath,
|
||||
this
|
||||
this,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
|
|
@ -467,7 +467,7 @@ export class MarkdownRendererComponent extends Component {
|
|||
markdown,
|
||||
this.container,
|
||||
this.sourcePath,
|
||||
this
|
||||
this,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -481,12 +481,12 @@ export class MarkdownRendererComponent extends Component {
|
|||
|
||||
/**
|
||||
* Update a specific block with new content
|
||||
* @param blockId The ID of the block to update
|
||||
* @param contentId The ID of the block to update
|
||||
* @param markdown The new markdown content
|
||||
*/
|
||||
public updateBlock(blockId: string, markdown: string): void {
|
||||
if (this.blockElements.has(blockId)) {
|
||||
this.queueRender(markdown, blockId);
|
||||
public updateBlock(contentId: string, markdown: string): void {
|
||||
if (this.blockElements.has(contentId)) {
|
||||
this.queueRender(markdown, contentId);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -507,26 +507,26 @@ export class MarkdownRendererComponent extends Component {
|
|||
* @returns The ID of the new block
|
||||
*/
|
||||
public addBlock(markdown: string): string {
|
||||
const blockId = `block-${Date.now()}-${this.blockElements.size}`;
|
||||
const contentId = `content-${Date.now()}-${this.blockElements.size}`;
|
||||
const blockEl = this.container.createEl("div", {
|
||||
cls: "markdown-block",
|
||||
});
|
||||
blockEl.dataset.blockId = blockId;
|
||||
this.blockElements.set(blockId, blockEl);
|
||||
blockEl.dataset.contentId = contentId;
|
||||
this.blockElements.set(contentId, blockEl);
|
||||
|
||||
this.queueRender(markdown, blockId);
|
||||
return blockId;
|
||||
this.queueRender(markdown, contentId);
|
||||
return contentId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a specific block
|
||||
* @param blockId The ID of the block to remove
|
||||
* @param contentId The ID of the block to remove
|
||||
*/
|
||||
public removeBlock(blockId: string): void {
|
||||
const blockEl = this.blockElements.get(blockId);
|
||||
public removeBlock(contentId: string): void {
|
||||
const blockEl = this.blockElements.get(contentId);
|
||||
if (blockEl) {
|
||||
blockEl.remove();
|
||||
this.blockElements.delete(blockId);
|
||||
this.blockElements.delete(contentId);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ import { parseTaskLine } from "@/utils/task/task-operations";
|
|||
*/
|
||||
export function cycleCompleteStatusExtension(
|
||||
app: App,
|
||||
plugin: TaskProgressBarPlugin
|
||||
plugin: TaskProgressBarPlugin,
|
||||
) {
|
||||
return EditorState.transactionFilter.of((tr) => {
|
||||
return handleCycleCompleteStatusTransaction(tr, app, plugin);
|
||||
|
|
@ -59,7 +59,7 @@ function isValidTaskMarkerReplacement(
|
|||
originalText: string,
|
||||
pos: number,
|
||||
newLineText: string,
|
||||
plugin: TaskProgressBarPlugin
|
||||
plugin: TaskProgressBarPlugin,
|
||||
): boolean {
|
||||
// Only single character replacements are considered valid task marker operations
|
||||
if (toA - fromA !== 1 || insertedText.length !== 1) {
|
||||
|
|
@ -102,7 +102,7 @@ function isValidTaskMarkerReplacement(
|
|||
|
||||
// Log successful validation for debugging
|
||||
console.log(
|
||||
`Valid task marker replacement detected. No user selection or selection doesn't cover replacement range. Original: '${originalText}' -> New: '${insertedText}' at position ${fromA}-${toA}`
|
||||
`Valid task marker replacement detected. No user selection or selection doesn't cover replacement range. Original: '${originalText}' -> New: '${insertedText}' at position ${fromA}-${toA}`,
|
||||
);
|
||||
|
||||
return true;
|
||||
|
|
@ -118,7 +118,7 @@ function isValidTaskMarkerReplacement(
|
|||
export function findTaskStatusChanges(
|
||||
tr: Transaction,
|
||||
tasksPluginLoaded: boolean,
|
||||
plugin?: TaskProgressBarPlugin
|
||||
plugin?: TaskProgressBarPlugin,
|
||||
): {
|
||||
position: number;
|
||||
currentMark: string;
|
||||
|
|
@ -176,12 +176,12 @@ export function findTaskStatusChanges(
|
|||
(change.text === "" &&
|
||||
(tr.startState.doc.sliceString(
|
||||
change.fromA,
|
||||
change.toA
|
||||
change.toA,
|
||||
) === "\t" ||
|
||||
tr.startState.doc.sliceString(
|
||||
change.fromA,
|
||||
change.toA
|
||||
) === " "))
|
||||
change.toA,
|
||||
) === " ")),
|
||||
);
|
||||
|
||||
if (allIndentChanges) {
|
||||
|
|
@ -203,14 +203,14 @@ export function findTaskStatusChanges(
|
|||
toA: number,
|
||||
fromB: number,
|
||||
toB: number,
|
||||
inserted: Text
|
||||
inserted: Text,
|
||||
) => {
|
||||
// Check for deletion operation (inserted text is empty)
|
||||
if (inserted.toString() === "" && toA > fromA) {
|
||||
// Get the deleted content
|
||||
const deletedContent = tr.startState.doc.sliceString(
|
||||
fromA,
|
||||
toA
|
||||
toA,
|
||||
);
|
||||
// Check if the deleted content is a dash character
|
||||
if (deletedContent === "-") {
|
||||
|
|
@ -218,14 +218,14 @@ export function findTaskStatusChanges(
|
|||
const line = tr.startState.doc.lineAt(fromA);
|
||||
const textBeforeDash = line.text.substring(
|
||||
0,
|
||||
fromA - line.from
|
||||
fromA - line.from,
|
||||
);
|
||||
if (textBeforeDash.trim() === "") {
|
||||
isDeletingTaskMarker = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
if (isDeletingTaskMarker) {
|
||||
|
|
@ -239,7 +239,7 @@ export function findTaskStatusChanges(
|
|||
toA: number,
|
||||
fromB: number,
|
||||
toB: number,
|
||||
inserted: Text
|
||||
inserted: Text,
|
||||
) => {
|
||||
// Get the inserted text
|
||||
const insertedText = inserted.toString();
|
||||
|
|
@ -247,7 +247,7 @@ export function findTaskStatusChanges(
|
|||
// Check if this is a new task creation with a newline
|
||||
if (insertedText.includes("\n")) {
|
||||
console.log(
|
||||
"New task creation detected with newline, skipping"
|
||||
"New task creation detected with newline, skipping",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
|
@ -334,8 +334,8 @@ export function findTaskStatusChanges(
|
|||
/[a-zA-Z]/.test(insertedText) &&
|
||||
(plugin
|
||||
? !Object.values(
|
||||
getTaskStatusConfig(plugin).marks
|
||||
).includes(insertedText)
|
||||
getTaskStatusConfig(plugin).marks,
|
||||
).includes(insertedText)
|
||||
: true)
|
||||
)
|
||||
) {
|
||||
|
|
@ -343,7 +343,7 @@ export function findTaskStatusChanges(
|
|||
if (fromA !== toA) {
|
||||
const originalText = tr.startState.doc.sliceString(
|
||||
fromA,
|
||||
toA
|
||||
toA,
|
||||
);
|
||||
|
||||
// Only perform validation if plugin is provided
|
||||
|
|
@ -357,23 +357,23 @@ export function findTaskStatusChanges(
|
|||
originalText,
|
||||
pos,
|
||||
newLineText,
|
||||
plugin
|
||||
plugin,
|
||||
);
|
||||
|
||||
if (!isValidReplacement) {
|
||||
console.log(
|
||||
`Detected invalid task marker replacement (fromA=${fromA}, toA=${toA}). User manually input '${insertedText}' (original: '${originalText}'), skipping automatic cycling.`
|
||||
`Detected invalid task marker replacement (fromA=${fromA}, toA=${toA}). User manually input '${insertedText}' (original: '${originalText}'), skipping automatic cycling.`,
|
||||
);
|
||||
return; // Skip this change, don't add to taskChanges
|
||||
}
|
||||
|
||||
console.log(
|
||||
`Detected valid task marker replacement (fromA=${fromA}, toA=${toA}). Original: '${originalText}' -> New: '${insertedText}', proceeding with automatic cycling.`
|
||||
`Detected valid task marker replacement (fromA=${fromA}, toA=${toA}). Original: '${originalText}' -> New: '${insertedText}', proceeding with automatic cycling.`,
|
||||
);
|
||||
} else {
|
||||
// Fallback to original logic for backwards compatibility
|
||||
console.log(
|
||||
`Detected replacement operation (fromA=${fromA}, toA=${toA}). User manually input '${insertedText}', skipping automatic cycling.`
|
||||
`Detected replacement operation (fromA=${fromA}, toA=${toA}). User manually input '${insertedText}', skipping automatic cycling.`,
|
||||
);
|
||||
return; // Skip this change, don't add to taskChanges
|
||||
}
|
||||
|
|
@ -434,12 +434,12 @@ export function findTaskStatusChanges(
|
|||
originalFromB: fromB,
|
||||
originalToB: toB,
|
||||
originalInsertedText: insertedText,
|
||||
}
|
||||
}
|
||||
: null,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
return taskChanges;
|
||||
|
|
@ -455,7 +455,7 @@ export function findTaskStatusChanges(
|
|||
export function handleCycleCompleteStatusTransaction(
|
||||
tr: Transaction,
|
||||
app: App,
|
||||
plugin: TaskProgressBarPlugin
|
||||
plugin: TaskProgressBarPlugin,
|
||||
): TransactionSpec {
|
||||
// Only process transactions that change the document and are user input events
|
||||
if (!tr.docChanged) {
|
||||
|
|
@ -477,8 +477,6 @@ export function handleCycleCompleteStatusTransaction(
|
|||
return tr;
|
||||
}
|
||||
|
||||
console.log(tr.changes, "changes");
|
||||
|
||||
// Check for markdown link insertion (cmd+k)
|
||||
if (tr.isUserEvent("input.autocomplete")) {
|
||||
// Look for typical markdown link pattern [text]() in the changes
|
||||
|
|
@ -509,7 +507,7 @@ export function handleCycleCompleteStatusTransaction(
|
|||
toA: number,
|
||||
fromB: number,
|
||||
toB: number,
|
||||
inserted: Text
|
||||
inserted: Text,
|
||||
) => {
|
||||
// Check if this removes a dash character and somehow modifies a task marker elsewhere
|
||||
const insertedText = inserted.toString();
|
||||
|
|
@ -522,13 +520,13 @@ export function handleCycleCompleteStatusTransaction(
|
|||
tr.newDoc
|
||||
.sliceString(
|
||||
Math.max(0, fromB - 5),
|
||||
Math.min(fromB + 5, tr.newDoc.length)
|
||||
Math.min(fromB + 5, tr.newDoc.length),
|
||||
)
|
||||
.includes("[")
|
||||
) {
|
||||
hasInvalidTaskChange = true;
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
if (hasInvalidTaskChange) {
|
||||
|
|
@ -539,7 +537,7 @@ export function handleCycleCompleteStatusTransaction(
|
|||
const taskStatusChanges = findTaskStatusChanges(
|
||||
tr,
|
||||
!!getTasksAPI(plugin),
|
||||
plugin
|
||||
plugin,
|
||||
);
|
||||
if (taskStatusChanges.length === 0) {
|
||||
return tr;
|
||||
|
|
@ -548,7 +546,7 @@ export function handleCycleCompleteStatusTransaction(
|
|||
// Get the task cycle and marks from plugin settings
|
||||
const { cycle, marks, excludeMarksFromCycle } = getTaskStatusConfig(plugin);
|
||||
const remainingCycle = cycle.filter(
|
||||
(state) => !excludeMarksFromCycle.includes(state)
|
||||
(state) => !excludeMarksFromCycle.includes(state),
|
||||
);
|
||||
|
||||
// If no cycle is defined, don't do anything
|
||||
|
|
@ -579,7 +577,7 @@ export function handleCycleCompleteStatusTransaction(
|
|||
|
||||
// Check for deletions and task changes in the same transaction
|
||||
const hasDeletion = changes.some(
|
||||
(change) => change.text === "" && change.toA > change.fromA
|
||||
(change) => change.text === "" && change.toA > change.fromA,
|
||||
);
|
||||
const hasTaskMarkerChange = changes.some((change) => {
|
||||
// Check if this change affects a task marker position [x]
|
||||
|
|
@ -709,11 +707,16 @@ export function handleCycleCompleteStatusTransaction(
|
|||
const nextStatus = remainingCycle[nextStatusIndex];
|
||||
const nextMark = marks[nextStatus] || " ";
|
||||
|
||||
// Log the cycle calculation for debugging
|
||||
console.log(
|
||||
`[Status Cycler] Calculated cycle: '${currentMark}' (${remainingCycle[currentStatusIndex]}) → '${nextMark}' (${nextStatus})`,
|
||||
);
|
||||
|
||||
// Check if the current mark is the same as what would be the next mark in the cycle
|
||||
// If they are the same, we don't need to process this further
|
||||
if (currentMark === nextMark) {
|
||||
console.log(
|
||||
`Current mark '${currentMark}' is already the next mark in the cycle. Skipping processing.`
|
||||
`Current mark '${currentMark}' is already the next mark in the cycle. Skipping processing.`,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
|
@ -732,7 +735,7 @@ export function handleCycleCompleteStatusTransaction(
|
|||
// If user's input already matches the next mark, don't cycle
|
||||
if (userInputMark === nextMark) {
|
||||
console.log(
|
||||
`User input '${userInputMark}' already matches the next mark '${nextMark}' in the cycle. Skipping processing.`
|
||||
`User input '${userInputMark}' already matches the next mark '${nextMark}' in the cycle. Skipping processing.`,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
|
@ -741,7 +744,7 @@ export function handleCycleCompleteStatusTransaction(
|
|||
const posLine = tr.newDoc.lineAt(position);
|
||||
const newLineText = posLine.text;
|
||||
const originalPosLine = tr.startState.doc.lineAt(
|
||||
Math.min(position, tr.startState.doc.length)
|
||||
Math.min(position, tr.startState.doc.length),
|
||||
);
|
||||
const originalLineText = originalPosLine.text;
|
||||
|
||||
|
|
@ -782,7 +785,7 @@ export function handleCycleCompleteStatusTransaction(
|
|||
// This prevents unexpected data loss when creating a task
|
||||
if (isNewEmptyTask || isManualTaskCreation) {
|
||||
console.log(
|
||||
`New empty task detected with mark ' ', leaving as is regardless of alwaysCycleNewTasks setting`
|
||||
`New empty task detected with mark ' ', leaving as is regardless of alwaysCycleNewTasks setting`,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
|
@ -801,7 +804,7 @@ export function handleCycleCompleteStatusTransaction(
|
|||
// Check if the mark position is within the current line and valid
|
||||
if (markPosition < lineAtMark.from || markPosition >= lineEnd) {
|
||||
console.log(
|
||||
`Mark position ${markPosition} is beyond the current line range ${lineAtMark.from}-${lineEnd}, skipping processing`
|
||||
`Mark position ${markPosition} is beyond the current line range ${lineAtMark.from}-${lineEnd}, skipping processing`,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
|
@ -810,7 +813,7 @@ export function handleCycleCompleteStatusTransaction(
|
|||
const validTo = Math.min(markPosition + 1, lineEnd);
|
||||
if (validTo <= markPosition) {
|
||||
console.log(
|
||||
`Invalid modification range ${markPosition}-${validTo}, skipping processing`
|
||||
`Invalid modification range ${markPosition}-${validTo}, skipping processing`,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
|
@ -819,45 +822,17 @@ export function handleCycleCompleteStatusTransaction(
|
|||
completingTask = true;
|
||||
}
|
||||
|
||||
// If nextMark is 'x', 'X', or space and we have Tasks plugin info, use the original insertion
|
||||
if (
|
||||
(nextMark === "x" || nextMark === "X" || nextMark === " ") &&
|
||||
tasksInfo !== null
|
||||
) {
|
||||
// Verify if the Tasks plugin's modification range is within the same line
|
||||
const origLineAtFromA = tr.startState.doc.lineAt(
|
||||
tasksInfo.originalFromA
|
||||
);
|
||||
const origLineAtToA = tr.startState.doc.lineAt(
|
||||
Math.min(tasksInfo.originalToA, tr.startState.doc.length)
|
||||
);
|
||||
// Log the status cycle for debugging
|
||||
console.log(
|
||||
`[Status Cycler] Cycling at position ${markPosition}: '${currentMark}' → '${nextMark}'`,
|
||||
);
|
||||
|
||||
if (origLineAtFromA.number !== origLineAtToA.number) {
|
||||
console.log(
|
||||
`Tasks plugin modification range spans multiple lines ${origLineAtFromA.number}-${origLineAtToA.number}, using safe modification range`
|
||||
);
|
||||
// Use the safe modification range
|
||||
newChanges.push({
|
||||
from: markPosition,
|
||||
to: validTo,
|
||||
insert: nextMark,
|
||||
});
|
||||
} else {
|
||||
// Use the original insertion from Tasks plugin
|
||||
newChanges.push({
|
||||
from: tasksInfo.originalFromA,
|
||||
to: tasksInfo.originalToA,
|
||||
insert: tasksInfo.originalInsertedText,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// Add a change to replace the current mark with the next one
|
||||
newChanges.push({
|
||||
from: markPosition,
|
||||
to: validTo,
|
||||
insert: nextMark,
|
||||
});
|
||||
}
|
||||
// Always use the calculated nextMark for consistent cycling behavior
|
||||
newChanges.push({
|
||||
from: markPosition,
|
||||
to: validTo,
|
||||
insert: nextMark,
|
||||
});
|
||||
}
|
||||
|
||||
// If we found any changes to make, create a new transaction
|
||||
|
|
@ -870,7 +845,7 @@ export function handleCycleCompleteStatusTransaction(
|
|||
line.text,
|
||||
line.number,
|
||||
plugin.settings.preferMetadataFormat,
|
||||
plugin // Pass plugin for configurable prefix support
|
||||
plugin, // Pass plugin for configurable prefix support
|
||||
);
|
||||
// if (completingTask && task) {
|
||||
// app.workspace.trigger("task-genius:task-completed", task);
|
||||
|
|
|
|||
|
|
@ -140,7 +140,7 @@ export class FluentTaskView extends ItemView {
|
|||
updateWorkspaceLeafWidth = debounce(() => {
|
||||
this.app.workspace.trigger(
|
||||
"task-genius:leaf-width-updated",
|
||||
this.leaf.width
|
||||
this.leaf.width,
|
||||
);
|
||||
}, 200);
|
||||
|
||||
|
|
@ -190,7 +190,7 @@ export class FluentTaskView extends ItemView {
|
|||
} catch (e) {
|
||||
console.warn(
|
||||
"[TG] Failed to sync selectedProject from filter state",
|
||||
e
|
||||
e,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -202,7 +202,7 @@ export class FluentTaskView extends ItemView {
|
|||
this.filteredTasks = this.dataManager.applyFilters(this.tasks);
|
||||
this.updateView();
|
||||
},
|
||||
150
|
||||
150,
|
||||
);
|
||||
|
||||
onResize(): void {
|
||||
|
|
@ -213,7 +213,7 @@ export class FluentTaskView extends ItemView {
|
|||
const availableModes =
|
||||
this.componentManager?.getAvailableModesForView(
|
||||
viewId,
|
||||
this.viewState.selectedProject
|
||||
this.viewState.selectedProject,
|
||||
) ?? [];
|
||||
const storedMode = this.viewState.viewModeByViewId?.[viewId];
|
||||
|
||||
|
|
@ -243,7 +243,7 @@ export class FluentTaskView extends ItemView {
|
|||
const prefersTree = getInitialViewMode(
|
||||
this.app,
|
||||
this.plugin,
|
||||
viewId
|
||||
viewId,
|
||||
);
|
||||
if (prefersTree && availableModes.includes("tree")) {
|
||||
return "tree";
|
||||
|
|
@ -263,7 +263,7 @@ export class FluentTaskView extends ItemView {
|
|||
|
||||
const availableModes = this.componentManager?.getAvailableModesForView(
|
||||
viewId,
|
||||
this.viewState.selectedProject
|
||||
this.viewState.selectedProject,
|
||||
);
|
||||
if (
|
||||
availableModes &&
|
||||
|
|
@ -289,14 +289,14 @@ export class FluentTaskView extends ItemView {
|
|||
// ====================
|
||||
if (this.DEBUG_MODE) {
|
||||
console.log(
|
||||
"[TG] Initializing UI, managers, structure, and events..."
|
||||
"[TG] Initializing UI, managers, structure, and events...",
|
||||
);
|
||||
}
|
||||
|
||||
this.contentEl.empty();
|
||||
this.contentEl.toggleClass(
|
||||
["task-genius-fluent-view", "task-genius-view"],
|
||||
true
|
||||
true,
|
||||
);
|
||||
|
||||
// Create root container (use exact same class as original)
|
||||
|
|
@ -320,7 +320,7 @@ export class FluentTaskView extends ItemView {
|
|||
|
||||
if (this.DEBUG_MODE) {
|
||||
console.log(
|
||||
"[TG] ✅ UI, managers, structure, and events initialized"
|
||||
"[TG] ✅ UI, managers, structure, and events initialized",
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -338,7 +338,7 @@ export class FluentTaskView extends ItemView {
|
|||
this.viewState.currentWorkspace = savedWorkspaceId;
|
||||
if (this.DEBUG_MODE) {
|
||||
console.log(
|
||||
`[TG] Restored workspace ID: ${savedWorkspaceId}`
|
||||
`[TG] Restored workspace ID: ${savedWorkspaceId}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -355,7 +355,7 @@ export class FluentTaskView extends ItemView {
|
|||
this.liveFilterState = state;
|
||||
this.app.saveLocalStorage(
|
||||
"task-genius-view-filter",
|
||||
state || null
|
||||
state || null,
|
||||
);
|
||||
},
|
||||
setCurrentFilterState: (state) => {
|
||||
|
|
@ -373,14 +373,14 @@ export class FluentTaskView extends ItemView {
|
|||
const availableModes =
|
||||
this.componentManager?.getAvailableModesForView(
|
||||
this.currentViewId,
|
||||
selectedProject
|
||||
selectedProject,
|
||||
) ?? [];
|
||||
if (
|
||||
availableModes.length > 0 &&
|
||||
!availableModes.includes(viewMode)
|
||||
) {
|
||||
return this.ensureViewModeForView(
|
||||
this.currentViewId
|
||||
this.currentViewId,
|
||||
);
|
||||
}
|
||||
return viewMode;
|
||||
|
|
@ -388,7 +388,7 @@ export class FluentTaskView extends ItemView {
|
|||
this.viewState.viewMode = normalizedMode;
|
||||
this.recordViewModeForView(
|
||||
this.currentViewId,
|
||||
normalizedMode
|
||||
normalizedMode,
|
||||
);
|
||||
this.topNavigation?.setViewMode(normalizedMode);
|
||||
if (clearSearch) {
|
||||
|
|
@ -408,7 +408,7 @@ export class FluentTaskView extends ItemView {
|
|||
await this.dataManager.loadTasks(false); // Will trigger onTasksLoaded callback
|
||||
await this.dataManager.registerDataflowListeners();
|
||||
console.log(
|
||||
`[TG] ✅ Loaded ${this.tasks.length} tasks, ${this.filteredTasks.length} after filters`
|
||||
`[TG] ✅ Loaded ${this.tasks.length} tasks, ${this.filteredTasks.length} after filters`,
|
||||
);
|
||||
|
||||
// ====================
|
||||
|
|
@ -433,7 +433,7 @@ export class FluentTaskView extends ItemView {
|
|||
// ====================
|
||||
if (this.DEBUG_MODE) {
|
||||
console.log(
|
||||
`[TG] Finalizing (isInitializing was ${this.isInitializing})`
|
||||
`[TG] Finalizing (isInitializing was ${this.isInitializing})`,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -463,7 +463,7 @@ export class FluentTaskView extends ItemView {
|
|||
searchQuery: this.viewState.searchQuery || "",
|
||||
filterInputValue: this.viewState.filterInputValue || "",
|
||||
}),
|
||||
() => this.isInitializing
|
||||
() => this.isInitializing,
|
||||
);
|
||||
this.dataManager.setCallbacks({
|
||||
onTasksLoaded: (tasks, error) => {
|
||||
|
|
@ -479,7 +479,7 @@ export class FluentTaskView extends ItemView {
|
|||
this.isLoading = false;
|
||||
// Apply filters immediately after loading
|
||||
this.filteredTasks = this.dataManager.applyFilters(
|
||||
this.tasks
|
||||
this.tasks,
|
||||
);
|
||||
this.updateView();
|
||||
}
|
||||
|
|
@ -504,7 +504,7 @@ export class FluentTaskView extends ItemView {
|
|||
this.app,
|
||||
this.plugin,
|
||||
() => this.workspaceId,
|
||||
() => this.useSideLeaves()
|
||||
() => this.useSideLeaves(),
|
||||
);
|
||||
this.actionHandlers.setCallbacks({
|
||||
onTaskSelectionChanged: (task) => {
|
||||
|
|
@ -520,7 +520,7 @@ export class FluentTaskView extends ItemView {
|
|||
this.tasks[index] = updatedTask;
|
||||
// Re-apply filters
|
||||
this.filteredTasks = this.dataManager.applyFilters(
|
||||
this.tasks
|
||||
this.tasks,
|
||||
);
|
||||
this.updateView();
|
||||
}
|
||||
|
|
@ -551,7 +551,7 @@ export class FluentTaskView extends ItemView {
|
|||
onNavigateToView: (viewId) => {
|
||||
this.recordViewModeForView(
|
||||
this.currentViewId,
|
||||
this.viewState.viewMode
|
||||
this.viewState.viewMode,
|
||||
);
|
||||
this.currentViewId = viewId;
|
||||
|
||||
|
|
@ -559,7 +559,7 @@ export class FluentTaskView extends ItemView {
|
|||
// This enables the full project overview mode
|
||||
if (viewId === "projects") {
|
||||
console.log(
|
||||
"[TG] Navigating to projects overview - clearing project selection"
|
||||
"[TG] Navigating to projects overview - clearing project selection",
|
||||
);
|
||||
this.viewState.selectedProject = undefined;
|
||||
|
||||
|
|
@ -573,25 +573,25 @@ export class FluentTaskView extends ItemView {
|
|||
.map((g: any) => ({
|
||||
...g,
|
||||
filters: (g.filters || []).filter(
|
||||
(f: any) => f.property !== "project"
|
||||
(f: any) => f.property !== "project",
|
||||
),
|
||||
}))
|
||||
.filter(
|
||||
(g: any) =>
|
||||
g.filters && g.filters.length > 0
|
||||
g.filters && g.filters.length > 0,
|
||||
);
|
||||
|
||||
this.liveFilterState = nextState as any;
|
||||
this.currentFilterState = nextState as any;
|
||||
this.app.saveLocalStorage(
|
||||
"task-genius-view-filter",
|
||||
nextState
|
||||
nextState,
|
||||
);
|
||||
|
||||
// Broadcast filter change
|
||||
this.app.workspace.trigger(
|
||||
"task-genius:filter-changed",
|
||||
nextState
|
||||
nextState,
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
|
|
@ -607,6 +607,7 @@ export class FluentTaskView extends ItemView {
|
|||
this.recordViewModeForView(viewId, nextMode);
|
||||
this.topNavigation?.setViewMode(nextMode);
|
||||
this.updateView();
|
||||
this.workspaceStateManager.saveFilterStateToWorkspace();
|
||||
},
|
||||
onSearchQueryChanged: (query) => {
|
||||
this.viewState.searchQuery = query;
|
||||
|
|
@ -622,17 +623,17 @@ export class FluentTaskView extends ItemView {
|
|||
// Switch to projects view
|
||||
this.recordViewModeForView(
|
||||
this.currentViewId,
|
||||
this.viewState.viewMode
|
||||
this.viewState.viewMode,
|
||||
);
|
||||
this.currentViewId = "projects";
|
||||
this.filteredTasks = this.dataManager.applyFilters(this.tasks);
|
||||
const projectsViewMode = this.ensureViewModeForView(
|
||||
this.currentViewId
|
||||
this.currentViewId,
|
||||
);
|
||||
this.viewState.viewMode = projectsViewMode;
|
||||
this.recordViewModeForView(
|
||||
this.currentViewId,
|
||||
projectsViewMode
|
||||
projectsViewMode,
|
||||
);
|
||||
this.topNavigation?.setViewMode(projectsViewMode);
|
||||
|
||||
|
|
@ -649,7 +650,7 @@ export class FluentTaskView extends ItemView {
|
|||
.map((g: any) => ({
|
||||
...g,
|
||||
filters: (g.filters || []).filter(
|
||||
(f: any) => f.property !== "project"
|
||||
(f: any) => f.property !== "project",
|
||||
),
|
||||
}))
|
||||
.filter((g: any) => g.filters && g.filters.length > 0); // Remove empty groups
|
||||
|
|
@ -675,26 +676,27 @@ export class FluentTaskView extends ItemView {
|
|||
this.currentFilterState = nextState as any;
|
||||
this.app.saveLocalStorage(
|
||||
"task-genius-view-filter",
|
||||
nextState
|
||||
nextState,
|
||||
);
|
||||
|
||||
// Broadcast so any open filter UI reacts and header button shows reset
|
||||
// The filter-changed event listener will handle applyFilters and updateView
|
||||
this.app.workspace.trigger(
|
||||
"task-genius:filter-changed",
|
||||
nextState
|
||||
nextState,
|
||||
);
|
||||
} catch (e) {
|
||||
console.warn(
|
||||
"[TG] Failed to project-sync filter UI state",
|
||||
e
|
||||
e,
|
||||
);
|
||||
// If filter sync fails, still update the view
|
||||
this.filteredTasks = this.dataManager.applyFilters(
|
||||
this.tasks
|
||||
this.tasks,
|
||||
);
|
||||
this.updateView();
|
||||
}
|
||||
this.workspaceStateManager.saveFilterStateToWorkspace();
|
||||
},
|
||||
onViewModeChanged: (mode) => {
|
||||
this.viewState.viewMode = mode;
|
||||
|
|
@ -729,7 +731,7 @@ export class FluentTaskView extends ItemView {
|
|||
viewMode: this.viewState.viewMode,
|
||||
}),
|
||||
() => this.currentFilterState,
|
||||
() => this.liveFilterState
|
||||
() => this.liveFilterState,
|
||||
);
|
||||
this.addChild(this.workspaceStateManager);
|
||||
|
||||
|
|
@ -737,7 +739,7 @@ export class FluentTaskView extends ItemView {
|
|||
this.selectionManager = new TaskSelectionManager(
|
||||
this.app,
|
||||
this.plugin,
|
||||
this
|
||||
this,
|
||||
);
|
||||
this.addChild(this.selectionManager);
|
||||
|
||||
|
|
@ -805,7 +807,7 @@ export class FluentTaskView extends ItemView {
|
|||
this.rootContainerEl,
|
||||
this.headerEl, // Obsidian's view header
|
||||
this.titleEl, // Obsidian's view title element
|
||||
() => this.filteredTasks.length
|
||||
() => this.filteredTasks.length,
|
||||
);
|
||||
this.layoutManager.setOnSidebarNavigate((viewId) => {
|
||||
this.actionHandlers.handleNavigate(viewId);
|
||||
|
|
@ -823,7 +825,7 @@ export class FluentTaskView extends ItemView {
|
|||
onTaskUpdate: async (originalTask, updatedTask) => {
|
||||
await this.actionHandlers.handleTaskUpdate(
|
||||
originalTask,
|
||||
updatedTask
|
||||
updatedTask,
|
||||
);
|
||||
},
|
||||
});
|
||||
|
|
@ -843,7 +845,7 @@ export class FluentTaskView extends ItemView {
|
|||
} else {
|
||||
sidebarEl.hide();
|
||||
console.log(
|
||||
"[TG] Using workspace side leaves: skip in-view sidebar"
|
||||
"[TG] Using workspace side leaves: skip in-view sidebar",
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -861,7 +863,7 @@ export class FluentTaskView extends ItemView {
|
|||
// Sort click callback (future extension point)
|
||||
},
|
||||
() => this.actionHandlers.handleSettingsClick(),
|
||||
[] // Start with empty modes, will be set by updateView
|
||||
[], // Start with empty modes, will be set by updateView
|
||||
);
|
||||
this.addChild(this.topNavigation);
|
||||
|
||||
|
|
@ -882,23 +884,31 @@ export class FluentTaskView extends ItemView {
|
|||
onTaskUpdate: async (originalTask, updatedTask) => {
|
||||
await this.actionHandlers.handleTaskUpdate(
|
||||
originalTask,
|
||||
updatedTask
|
||||
updatedTask,
|
||||
);
|
||||
},
|
||||
onTaskContextMenu: (event, task) => {
|
||||
this.actionHandlers.handleTaskContextMenu(event, task);
|
||||
},
|
||||
onKanbanTaskStatusUpdate: (taskId, newStatusMark) => {
|
||||
console.log(`[FluentTaskView] Kanban status update callback received: taskId=${taskId}, mark=${newStatusMark}`);
|
||||
console.log(`[FluentTaskView] Current task list size: ${this.tasks.length}`);
|
||||
|
||||
const task = this.tasks.find((t) => t.id === taskId);
|
||||
if (task) {
|
||||
console.log('[FluentTaskView] Task found, delegating to action handler');
|
||||
this.actionHandlers.handleKanbanTaskStatusUpdate(
|
||||
task,
|
||||
newStatusMark
|
||||
newStatusMark,
|
||||
);
|
||||
} else {
|
||||
console.error(`[FluentTaskView] CRITICAL: Task ${taskId} not found in local task list`);
|
||||
console.error('[FluentTaskView] Available task IDs:', this.tasks.slice(0, 5).map(t => t.id));
|
||||
console.error('[FluentTaskView] This indicates a synchronization issue between kanban and main view');
|
||||
}
|
||||
},
|
||||
},
|
||||
this.selectionManager
|
||||
this.selectionManager,
|
||||
);
|
||||
this.addChild(this.componentManager);
|
||||
this.componentManager.initializeViewComponents();
|
||||
|
|
@ -947,7 +957,7 @@ export class FluentTaskView extends ItemView {
|
|||
this.workspaceStateManager.captureFilterStateSnapshot();
|
||||
if (snapshot) {
|
||||
await this.workspaceStateManager.saveFilterStateImmediately(
|
||||
snapshot
|
||||
snapshot,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -969,7 +979,7 @@ export class FluentTaskView extends ItemView {
|
|||
this.liveFilterState = state;
|
||||
this.app.saveLocalStorage(
|
||||
"task-genius-view-filter",
|
||||
state || null
|
||||
state || null,
|
||||
);
|
||||
},
|
||||
setCurrentFilterState: (state) => {
|
||||
|
|
@ -988,14 +998,14 @@ export class FluentTaskView extends ItemView {
|
|||
const availableModes =
|
||||
this.componentManager?.getAvailableModesForView(
|
||||
this.currentViewId,
|
||||
selectedProject
|
||||
selectedProject,
|
||||
) ?? [];
|
||||
if (
|
||||
availableModes.length > 0 &&
|
||||
!availableModes.includes(viewMode)
|
||||
) {
|
||||
return this.ensureViewModeForView(
|
||||
this.currentViewId
|
||||
this.currentViewId,
|
||||
);
|
||||
}
|
||||
return viewMode;
|
||||
|
|
@ -1003,7 +1013,7 @@ export class FluentTaskView extends ItemView {
|
|||
this.viewState.viewMode = normalizedMode;
|
||||
this.recordViewModeForView(
|
||||
this.currentViewId,
|
||||
normalizedMode
|
||||
normalizedMode,
|
||||
);
|
||||
this.topNavigation?.setViewMode(normalizedMode);
|
||||
if (clearSearch) {
|
||||
|
|
@ -1019,7 +1029,7 @@ export class FluentTaskView extends ItemView {
|
|||
// Reload tasks
|
||||
await this.dataManager.loadTasks();
|
||||
}
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
// Workspace overrides saved event
|
||||
|
|
@ -1029,7 +1039,7 @@ export class FluentTaskView extends ItemView {
|
|||
await this.workspaceStateManager.applyWorkspaceSettings();
|
||||
await this.dataManager.loadTasks();
|
||||
}
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
// Settings changed event (skip for filter state changes)
|
||||
|
|
@ -1037,7 +1047,7 @@ export class FluentTaskView extends ItemView {
|
|||
on(this.app, Events.SETTINGS_CHANGED, async () => {
|
||||
// Reload on settings change (unless caused by filter state save)
|
||||
await this.dataManager.loadTasks();
|
||||
})
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -1047,8 +1057,8 @@ export class FluentTaskView extends ItemView {
|
|||
"task-genius:filter-changed",
|
||||
(filterState: RootFilterState, leafId?: string) => {
|
||||
this.handleFilterChanged(filterState, leafId);
|
||||
}
|
||||
)
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
// Sidebar selection changed (when using side leaves)
|
||||
|
|
@ -1062,9 +1072,10 @@ export class FluentTaskView extends ItemView {
|
|||
) {
|
||||
this.currentViewId = payload.selectionId;
|
||||
this.filteredTasks = this.dataManager.applyFilters(
|
||||
this.tasks
|
||||
this.tasks,
|
||||
);
|
||||
this.updateView();
|
||||
this.workspaceStateManager.saveFilterStateToWorkspace();
|
||||
}
|
||||
if (
|
||||
payload.selectionType === "project" &&
|
||||
|
|
@ -1072,11 +1083,11 @@ export class FluentTaskView extends ItemView {
|
|||
) {
|
||||
// Use the full project selection logic via actionHandlers
|
||||
this.actionHandlers.handleProjectSelect(
|
||||
payload.selectionId || ""
|
||||
payload.selectionId || "",
|
||||
);
|
||||
}
|
||||
}
|
||||
})
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -1098,31 +1109,20 @@ export class FluentTaskView extends ItemView {
|
|||
* Update view with current state
|
||||
*/
|
||||
private updateView() {
|
||||
// Enhanced logging with all critical state
|
||||
console.log(
|
||||
`[TG] updateView called: ` +
|
||||
`isInitializing=${this.isInitializing}, ` +
|
||||
`viewId=${this.currentViewId}, ` +
|
||||
`tasks=${this.tasks.length}, ` +
|
||||
`filtered=${this.filteredTasks.length}, ` +
|
||||
`isLoading=${this.isLoading}, ` +
|
||||
`hasError=${!!this.loadError}`
|
||||
);
|
||||
|
||||
if (this.isInitializing) {
|
||||
console.log("[TG] ⏭️ Skip update during initialization");
|
||||
console.log("[TG] Skip update during initialization");
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(
|
||||
`[TG] ▶️ Proceeding with view update for ${this.currentViewId}`
|
||||
`[TG] Proceeding with view update for ${this.currentViewId}`,
|
||||
);
|
||||
|
||||
// Update top navigation available modes based on current view
|
||||
const availableModes =
|
||||
this.componentManager?.getAvailableModesForView(
|
||||
this.currentViewId,
|
||||
this.viewState.selectedProject
|
||||
this.viewState.selectedProject,
|
||||
) ?? [];
|
||||
this.topNavigation?.updateAvailableModes(availableModes);
|
||||
|
||||
|
|
@ -1178,7 +1178,7 @@ export class FluentTaskView extends ItemView {
|
|||
this.filteredTasks,
|
||||
this.currentFilterState,
|
||||
this.viewState.viewMode,
|
||||
this.viewState.selectedProject
|
||||
this.viewState.selectedProject,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -179,6 +179,7 @@
|
|||
.full-calendar-container .calendar-event {
|
||||
/* Example style for an event */
|
||||
background-color: var(--interactive-accent);
|
||||
--bold-color: var(--text-on-accent);
|
||||
color: var(--text-on-accent);
|
||||
border-radius: var(--radius-s);
|
||||
padding: 2px 4px;
|
||||
|
|
@ -300,7 +301,9 @@
|
|||
/* margin-bottom: var(--size-4-2); */
|
||||
width: 100%; /* Ensure it takes full width */
|
||||
border-radius: var(--radius-s);
|
||||
transition: transform 0.15s ease, box-shadow 0.15s ease;
|
||||
transition:
|
||||
transform 0.15s ease,
|
||||
box-shadow 0.15s ease;
|
||||
}
|
||||
|
||||
.full-calendar-container .calendar-event-timed:hover {
|
||||
|
|
@ -445,24 +448,49 @@
|
|||
}
|
||||
|
||||
/* Adjust grid layouts when weekends are hidden */
|
||||
.full-calendar-container .calendar-view-container.hide-weekends .calendar-weekday-header {
|
||||
grid-template-columns: repeat(5, 1fr) !important; /* 5 columns instead of 7 when weekends hidden */
|
||||
.full-calendar-container
|
||||
.calendar-view-container.hide-weekends
|
||||
.calendar-weekday-header {
|
||||
grid-template-columns: repeat(
|
||||
5,
|
||||
1fr
|
||||
) !important; /* 5 columns instead of 7 when weekends hidden */
|
||||
}
|
||||
|
||||
.full-calendar-container .calendar-view-container.hide-weekends .calendar-month-grid {
|
||||
grid-template-columns: repeat(5, 1fr) !important; /* 5 columns instead of 7 when weekends hidden */
|
||||
.full-calendar-container
|
||||
.calendar-view-container.hide-weekends
|
||||
.calendar-month-grid {
|
||||
grid-template-columns: repeat(
|
||||
5,
|
||||
1fr
|
||||
) !important; /* 5 columns instead of 7 when weekends hidden */
|
||||
}
|
||||
|
||||
.full-calendar-container .calendar-view-container.hide-weekends .calendar-week-header {
|
||||
grid-template-columns: repeat(5, 1fr) !important; /* 5 columns instead of 7 when weekends hidden */
|
||||
.full-calendar-container
|
||||
.calendar-view-container.hide-weekends
|
||||
.calendar-week-header {
|
||||
grid-template-columns: repeat(
|
||||
5,
|
||||
1fr
|
||||
) !important; /* 5 columns instead of 7 when weekends hidden */
|
||||
}
|
||||
|
||||
.full-calendar-container .calendar-view-container.hide-weekends .calendar-week-grid {
|
||||
grid-template-columns: repeat(5, 1fr) !important; /* 5 columns instead of 7 when weekends hidden */
|
||||
.full-calendar-container
|
||||
.calendar-view-container.hide-weekends
|
||||
.calendar-week-grid {
|
||||
grid-template-columns: repeat(
|
||||
5,
|
||||
1fr
|
||||
) !important; /* 5 columns instead of 7 when weekends hidden */
|
||||
}
|
||||
|
||||
.full-calendar-container .calendar-view-container.hide-weekends .mini-month-grid {
|
||||
grid-template-columns: repeat(5, 1fr) !important; /* 5 columns instead of 7 when weekends hidden */
|
||||
.full-calendar-container
|
||||
.calendar-view-container.hide-weekends
|
||||
.mini-month-grid {
|
||||
grid-template-columns: repeat(
|
||||
5,
|
||||
1fr
|
||||
) !important; /* 5 columns instead of 7 when weekends hidden */
|
||||
}
|
||||
|
||||
/* Note: Weekend elements are not created when hideWeekends is enabled,
|
||||
|
|
@ -637,7 +665,9 @@
|
|||
/* Make calendar events draggable */
|
||||
.calendar-events-container .calendar-event {
|
||||
cursor: grab;
|
||||
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||
transition:
|
||||
transform 0.2s ease,
|
||||
box-shadow 0.2s ease;
|
||||
}
|
||||
|
||||
.calendar-events-container .calendar-event:hover {
|
||||
|
|
|
|||
|
|
@ -530,7 +530,9 @@ export function filterTasks(
|
|||
// --- 基本筛选:隐藏已完成和空白任务 ---
|
||||
// 注意:这些是基础过滤条件,始终应用
|
||||
if (viewConfig.hideCompletedAndAbandonedTasks) {
|
||||
filtered = filtered.filter((task) => !task.completed);
|
||||
filtered = filtered.filter((task) =>
|
||||
isNotCompleted(plugin, task, viewId),
|
||||
);
|
||||
}
|
||||
|
||||
if (viewConfig.filterBlanks) {
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue