Enhance chain inspection functionality with editor content support
- Updated `inspectChains` to accept optional `editorContent`, allowing for real-time inspection without relying on potentially stale vault data. - Introduced `buildNoteIndexFromContent` to facilitate graph indexing directly from provided content. - Improved handling of template matching profiles in `ChainWorkbenchModal`, ensuring accurate context during chain inspections. - Added debug logging for better traceability of the chain inspection process.
This commit is contained in:
parent
dbd76b764d
commit
99c77ef616
|
|
@ -679,6 +679,8 @@ function computeFindings(
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inspect chains for current section context.
|
* Inspect chains for current section context.
|
||||||
|
* @param editorContent Optional: If provided, use this content instead of reading from vault.
|
||||||
|
* This is useful when the file was just modified and vault cache is stale.
|
||||||
*/
|
*/
|
||||||
export async function inspectChains(
|
export async function inspectChains(
|
||||||
app: App,
|
app: App,
|
||||||
|
|
@ -688,7 +690,8 @@ export async function inspectChains(
|
||||||
edgeVocabularyPath?: string,
|
edgeVocabularyPath?: string,
|
||||||
chainTemplates?: ChainTemplatesConfig | null,
|
chainTemplates?: ChainTemplatesConfig | null,
|
||||||
templatesLoadResult?: { path: string; status: string; loadedAt: number | null; templateCount: number },
|
templatesLoadResult?: { path: string; status: string; loadedAt: number | null; templateCount: number },
|
||||||
templateMatchingProfileName?: string
|
templateMatchingProfileName?: string,
|
||||||
|
editorContent?: string
|
||||||
): Promise<ChainInspectorReport> {
|
): Promise<ChainInspectorReport> {
|
||||||
// Build index for current note
|
// Build index for current note
|
||||||
const currentFile = app.vault.getAbstractFileByPath(context.file);
|
const currentFile = app.vault.getAbstractFileByPath(context.file);
|
||||||
|
|
@ -700,10 +703,11 @@ export async function inspectChains(
|
||||||
throw new Error(`File not found or not a markdown file: ${context.file}`);
|
throw new Error(`File not found or not a markdown file: ${context.file}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { edges: currentEdges, sections } = await buildNoteIndex(
|
// Use editor content if provided, otherwise read from vault
|
||||||
app,
|
const { buildNoteIndex, buildNoteIndexFromContent } = await import("./graphIndex");
|
||||||
currentFile as TFile
|
const { edges: currentEdges, sections } = editorContent
|
||||||
);
|
? await buildNoteIndexFromContent(app, currentFile as TFile, editorContent)
|
||||||
|
: await buildNoteIndex(app, currentFile as TFile);
|
||||||
|
|
||||||
// Collect all outgoing targets to load neighbor notes
|
// Collect all outgoing targets to load neighbor notes
|
||||||
// Respect includeNoteLinks and includeCandidates toggles
|
// Respect includeNoteLinks and includeCandidates toggles
|
||||||
|
|
@ -905,7 +909,8 @@ export async function inspectChains(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get section content for gap analysis
|
// Get section content for gap analysis
|
||||||
const content = await app.vault.read(currentFile as TFile);
|
// Use editor content if provided, otherwise read from vault
|
||||||
|
const content = editorContent || await app.vault.read(currentFile as TFile);
|
||||||
const sectionsWithContent = splitIntoSections(content);
|
const sectionsWithContent = splitIntoSections(content);
|
||||||
const currentSectionContent =
|
const currentSectionContent =
|
||||||
sectionsWithContent[context.sectionIndex]?.content || "";
|
sectionsWithContent[context.sectionIndex]?.content || "";
|
||||||
|
|
|
||||||
|
|
@ -83,13 +83,27 @@ function parseTarget(linkText: string, currentFilePath: string, sections: NoteSe
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build graph index for a single note.
|
* Build graph index for a single note from file content.
|
||||||
|
* Use buildNoteIndexFromContent if you have the content already (e.g., from editor).
|
||||||
*/
|
*/
|
||||||
export async function buildNoteIndex(
|
export async function buildNoteIndex(
|
||||||
app: App,
|
app: App,
|
||||||
file: TFile
|
file: TFile
|
||||||
): Promise<{ edges: IndexedEdge[]; sections: SectionNode[] }> {
|
): Promise<{ edges: IndexedEdge[]; sections: SectionNode[] }> {
|
||||||
const content = await app.vault.read(file);
|
const content = await app.vault.read(file);
|
||||||
|
return buildNoteIndexFromContent(app, file, content);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build graph index for a single note from provided content.
|
||||||
|
* This is useful when you have the content from an editor and want to avoid
|
||||||
|
* reading stale data from the vault cache.
|
||||||
|
*/
|
||||||
|
export async function buildNoteIndexFromContent(
|
||||||
|
app: App,
|
||||||
|
file: TFile,
|
||||||
|
content: string
|
||||||
|
): Promise<{ edges: IndexedEdge[]; sections: SectionNode[] }> {
|
||||||
const sections = splitIntoSections(content);
|
const sections = splitIntoSections(content);
|
||||||
const edges: IndexedEdge[] = [];
|
const edges: IndexedEdge[] = [];
|
||||||
const sectionNodes: SectionNode[] = [];
|
const sectionNodes: SectionNode[] = [];
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,8 @@ export async function executeChainWorkbench(
|
||||||
chainRoles,
|
chainRoles,
|
||||||
chainTemplates,
|
chainTemplates,
|
||||||
vocabulary,
|
vocabulary,
|
||||||
pluginInstance
|
pluginInstance,
|
||||||
|
templatesLoadResult
|
||||||
);
|
);
|
||||||
modal.open();
|
modal.open();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
||||||
|
|
@ -8,12 +8,15 @@ import type { WorkbenchModel, WorkbenchMatch, WorkbenchTodoUnion } from "../work
|
||||||
import type { MindnetSettings } from "../settings";
|
import type { MindnetSettings } from "../settings";
|
||||||
import type { ChainRolesConfig, ChainTemplatesConfig } from "../dictionary/types";
|
import type { ChainRolesConfig, ChainTemplatesConfig } from "../dictionary/types";
|
||||||
import type { Vocabulary } from "../vocab/Vocabulary";
|
import type { Vocabulary } from "../vocab/Vocabulary";
|
||||||
|
import type { IndexedEdge, SectionNode } from "../analysis/graphIndex";
|
||||||
|
import type { DictionaryLoadResult } from "../dictionary/types";
|
||||||
|
|
||||||
export class ChainWorkbenchModal extends Modal {
|
export class ChainWorkbenchModal extends Modal {
|
||||||
private model: WorkbenchModel;
|
private model: WorkbenchModel;
|
||||||
private settings: MindnetSettings;
|
private settings: MindnetSettings;
|
||||||
private chainRoles: ChainRolesConfig | null;
|
private chainRoles: ChainRolesConfig | null;
|
||||||
private chainTemplates: ChainTemplatesConfig | null;
|
private chainTemplates: ChainTemplatesConfig | null;
|
||||||
|
private templatesLoadResult: DictionaryLoadResult<ChainTemplatesConfig> | undefined;
|
||||||
private vocabulary: Vocabulary;
|
private vocabulary: Vocabulary;
|
||||||
private pluginInstance: any;
|
private pluginInstance: any;
|
||||||
|
|
||||||
|
|
@ -28,13 +31,15 @@ export class ChainWorkbenchModal extends Modal {
|
||||||
chainRoles: ChainRolesConfig | null,
|
chainRoles: ChainRolesConfig | null,
|
||||||
chainTemplates: ChainTemplatesConfig | null,
|
chainTemplates: ChainTemplatesConfig | null,
|
||||||
vocabulary: Vocabulary,
|
vocabulary: Vocabulary,
|
||||||
pluginInstance: any
|
pluginInstance: any,
|
||||||
|
templatesLoadResult?: DictionaryLoadResult<ChainTemplatesConfig>
|
||||||
) {
|
) {
|
||||||
super(app);
|
super(app);
|
||||||
this.model = model;
|
this.model = model;
|
||||||
this.settings = settings;
|
this.settings = settings;
|
||||||
this.chainRoles = chainRoles;
|
this.chainRoles = chainRoles;
|
||||||
this.chainTemplates = chainTemplates;
|
this.chainTemplates = chainTemplates;
|
||||||
|
this.templatesLoadResult = templatesLoadResult;
|
||||||
this.vocabulary = vocabulary;
|
this.vocabulary = vocabulary;
|
||||||
this.pluginInstance = pluginInstance;
|
this.pluginInstance = pluginInstance;
|
||||||
|
|
||||||
|
|
@ -94,22 +99,37 @@ export class ChainWorkbenchModal extends Modal {
|
||||||
private render(): void {
|
private render(): void {
|
||||||
const { contentEl } = this;
|
const { contentEl } = this;
|
||||||
|
|
||||||
|
// Debug: Log render state
|
||||||
|
console.log("[Chain Workbench] Render - model.matches.length:", this.model.matches.length);
|
||||||
|
console.log("[Chain Workbench] Render - filterStatus:", this.filterStatus, "searchQuery:", this.searchQuery);
|
||||||
|
|
||||||
// Filter matches
|
// Filter matches
|
||||||
let filteredMatches = this.model.matches;
|
let filteredMatches = this.model.matches;
|
||||||
if (this.filterStatus) {
|
if (this.filterStatus) {
|
||||||
filteredMatches = filteredMatches.filter((m) => m.status === this.filterStatus);
|
filteredMatches = filteredMatches.filter((m) => m.status === this.filterStatus);
|
||||||
|
console.log("[Chain Workbench] After status filter:", filteredMatches.length);
|
||||||
}
|
}
|
||||||
if (this.searchQuery) {
|
if (this.searchQuery) {
|
||||||
filteredMatches = filteredMatches.filter((m) =>
|
filteredMatches = filteredMatches.filter((m) =>
|
||||||
m.templateName.toLowerCase().includes(this.searchQuery)
|
m.templateName.toLowerCase().includes(this.searchQuery)
|
||||||
);
|
);
|
||||||
|
console.log("[Chain Workbench] After search filter:", filteredMatches.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log("[Chain Workbench] Final filtered matches:", filteredMatches.length);
|
||||||
|
|
||||||
// Sort: near_complete first (default), then by score descending
|
// Sort: near_complete first (default), then by score descending
|
||||||
|
// Use stable sort to preserve order within same status/score groups
|
||||||
filteredMatches.sort((a, b) => {
|
filteredMatches.sort((a, b) => {
|
||||||
if (a.status === "near_complete" && b.status !== "near_complete") return -1;
|
if (a.status === "near_complete" && b.status !== "near_complete") return -1;
|
||||||
if (a.status !== "near_complete" && b.status === "near_complete") return 1;
|
if (a.status !== "near_complete" && b.status === "near_complete") return 1;
|
||||||
return b.score - a.score;
|
const scoreDiff = b.score - a.score;
|
||||||
|
if (scoreDiff !== 0) return scoreDiff;
|
||||||
|
// Preserve original order for matches with same status and score
|
||||||
|
// Use templateName + slotAssignments as tiebreaker for stability
|
||||||
|
const aId = this.getMatchIdentifier(a);
|
||||||
|
const bId = this.getMatchIdentifier(b);
|
||||||
|
return aId.localeCompare(bId);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Render tree view (left column)
|
// Render tree view (left column)
|
||||||
|
|
@ -125,6 +145,19 @@ export class ChainWorkbenchModal extends Modal {
|
||||||
|
|
||||||
treeContainer.empty();
|
treeContainer.empty();
|
||||||
treeContainer.createEl("h3", { text: "Templates & Chains" });
|
treeContainer.createEl("h3", { text: "Templates & Chains" });
|
||||||
|
|
||||||
|
// Show message if no matches
|
||||||
|
if (matches.length === 0) {
|
||||||
|
const emptyMessage = treeContainer.createDiv({ cls: "workbench-empty-message" });
|
||||||
|
emptyMessage.createEl("p", { text: "Keine Chains gefunden." });
|
||||||
|
if (this.filterStatus || this.searchQuery) {
|
||||||
|
emptyMessage.createEl("p", {
|
||||||
|
cls: "workbench-empty-hint",
|
||||||
|
text: "Versuchen Sie, die Filter zu löschen, um alle Chains anzuzeigen."
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Group matches by template name
|
// Group matches by template name
|
||||||
const matchesByTemplate = new Map<string, WorkbenchMatch[]>();
|
const matchesByTemplate = new Map<string, WorkbenchMatch[]>();
|
||||||
|
|
@ -969,8 +1002,39 @@ export class ChainWorkbenchModal extends Modal {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a unique identifier for a match to restore selection after refresh.
|
||||||
|
*/
|
||||||
|
private getMatchIdentifier(match: WorkbenchMatch): string {
|
||||||
|
// Create a stable identifier based on template name and slot assignments
|
||||||
|
const slotKeys = Object.keys(match.slotAssignments).sort();
|
||||||
|
const slotValues = slotKeys.map(key => {
|
||||||
|
const assignment = match.slotAssignments[key];
|
||||||
|
if (!assignment) return `${key}:null`;
|
||||||
|
return `${key}:${assignment.file}#${assignment.heading || ''}`;
|
||||||
|
});
|
||||||
|
return `${match.templateName}|${slotValues.join('|')}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find a match in the new model that corresponds to the saved identifier.
|
||||||
|
*/
|
||||||
|
private findMatchByIdentifier(identifier: string, matches: WorkbenchMatch[]): WorkbenchMatch | null {
|
||||||
|
for (const match of matches) {
|
||||||
|
if (this.getMatchIdentifier(match) === identifier) {
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private async refreshWorkbench(): Promise<void> {
|
private async refreshWorkbench(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
|
// Save current state before refresh
|
||||||
|
const savedSelectedMatchId = this.selectedMatch ? this.getMatchIdentifier(this.selectedMatch) : null;
|
||||||
|
const savedFilterStatus = this.filterStatus;
|
||||||
|
const savedSearchQuery = this.searchQuery;
|
||||||
|
|
||||||
// Reload the workbench model without closing the modal
|
// Reload the workbench model without closing the modal
|
||||||
const activeFile = this.app.workspace.getActiveFile();
|
const activeFile = this.app.workspace.getActiveFile();
|
||||||
const activeEditor = this.app.workspace.activeEditor?.editor;
|
const activeEditor = this.app.workspace.activeEditor?.editor;
|
||||||
|
|
@ -1002,8 +1066,34 @@ export class ChainWorkbenchModal extends Modal {
|
||||||
const vocabText = await VocabularyLoader.loadText(this.app, this.settings.edgeVocabularyPath);
|
const vocabText = await VocabularyLoader.loadText(this.app, this.settings.edgeVocabularyPath);
|
||||||
const edgeVocabulary = parseEdgeVocabulary(vocabText);
|
const edgeVocabulary = parseEdgeVocabulary(vocabText);
|
||||||
|
|
||||||
// Inspect chains
|
// Prepare templates source info for inspectChains
|
||||||
|
// This is required for template matching to work!
|
||||||
|
let templatesSourceInfo: { path: string; status: string; loadedAt: number | null; templateCount: number } | undefined;
|
||||||
|
if (this.templatesLoadResult) {
|
||||||
|
templatesSourceInfo = {
|
||||||
|
path: this.templatesLoadResult.resolvedPath,
|
||||||
|
status: this.templatesLoadResult.status,
|
||||||
|
loadedAt: this.templatesLoadResult.loadedAt,
|
||||||
|
templateCount: this.chainTemplates?.templates?.length || 0,
|
||||||
|
};
|
||||||
|
} else if (this.chainTemplates) {
|
||||||
|
// Fallback: create a minimal templatesSourceInfo if templatesLoadResult is not available
|
||||||
|
templatesSourceInfo = {
|
||||||
|
path: this.settings.chainTemplatesPath || "unknown",
|
||||||
|
status: "loaded",
|
||||||
|
loadedAt: Date.now(),
|
||||||
|
templateCount: this.chainTemplates.templates?.length || 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inspect chains - pass editor content if available to avoid stale vault cache
|
||||||
const { inspectChains } = await import("../analysis/chainInspector");
|
const { inspectChains } = await import("../analysis/chainInspector");
|
||||||
|
const editorContent = activeEditor ? activeEditor.getValue() : undefined;
|
||||||
|
console.log("[Chain Workbench] Calling inspectChains with context:", context);
|
||||||
|
console.log("[Chain Workbench] Using editor content:", !!editorContent);
|
||||||
|
console.log("[Chain Workbench] chainTemplates:", this.chainTemplates ? "loaded" : "null");
|
||||||
|
console.log("[Chain Workbench] chainRoles:", this.chainRoles ? "loaded" : "null");
|
||||||
|
console.log("[Chain Workbench] templatesSourceInfo:", templatesSourceInfo ? "provided" : "null");
|
||||||
const report = await inspectChains(
|
const report = await inspectChains(
|
||||||
this.app,
|
this.app,
|
||||||
context,
|
context,
|
||||||
|
|
@ -1011,20 +1101,36 @@ export class ChainWorkbenchModal extends Modal {
|
||||||
this.chainRoles,
|
this.chainRoles,
|
||||||
this.settings.edgeVocabularyPath,
|
this.settings.edgeVocabularyPath,
|
||||||
this.chainTemplates,
|
this.chainTemplates,
|
||||||
undefined,
|
templatesSourceInfo,
|
||||||
this.settings.templateMatchingProfile
|
this.settings.templateMatchingProfile,
|
||||||
|
editorContent
|
||||||
);
|
);
|
||||||
|
console.log("[Chain Workbench] inspectChains returned - templateMatches:", report.templateMatches?.length || 0);
|
||||||
|
|
||||||
// Build all edges index
|
// Build all edges index for workbench model (using same editor content if available)
|
||||||
const { buildNoteIndex } = await import("../analysis/graphIndex");
|
const { buildNoteIndex, buildNoteIndexFromContent } = await import("../analysis/graphIndex");
|
||||||
const fileObj = this.app.vault.getAbstractFileByPath(activeFile.path);
|
const fileObj = this.app.vault.getAbstractFileByPath(activeFile.path);
|
||||||
if (!fileObj || !(fileObj instanceof TFile)) {
|
if (!fileObj || !(fileObj instanceof TFile)) {
|
||||||
throw new Error("Active file not found");
|
throw new Error("Active file not found");
|
||||||
}
|
}
|
||||||
const { edges: allEdges } = await buildNoteIndex(this.app, fileObj);
|
|
||||||
|
// Use editor content if available to ensure consistency with inspectChains
|
||||||
|
let allEdges: IndexedEdge[];
|
||||||
|
if (editorContent) {
|
||||||
|
const result = await buildNoteIndexFromContent(this.app, fileObj, editorContent);
|
||||||
|
allEdges = result.edges;
|
||||||
|
console.log("[Chain Workbench] Built index from editor content for workbench, edges:", allEdges.length);
|
||||||
|
} else {
|
||||||
|
const result = await buildNoteIndex(this.app, fileObj);
|
||||||
|
allEdges = result.edges;
|
||||||
|
console.log("[Chain Workbench] Built index from vault for workbench, edges:", allEdges.length);
|
||||||
|
}
|
||||||
|
|
||||||
// Build workbench model
|
// Build workbench model
|
||||||
const { buildWorkbenchModel } = await import("../workbench/workbenchBuilder");
|
const { buildWorkbenchModel } = await import("../workbench/workbenchBuilder");
|
||||||
|
console.log("[Chain Workbench] Building workbench model...");
|
||||||
|
console.log("[Chain Workbench] Report has templateMatches:", report.templateMatches?.length || 0);
|
||||||
|
console.log("[Chain Workbench] allEdges count:", allEdges.length);
|
||||||
const newModel = await buildWorkbenchModel(
|
const newModel = await buildWorkbenchModel(
|
||||||
this.app,
|
this.app,
|
||||||
report,
|
report,
|
||||||
|
|
@ -1035,11 +1141,48 @@ export class ChainWorkbenchModal extends Modal {
|
||||||
this.settings.debugLogging
|
this.settings.debugLogging
|
||||||
);
|
);
|
||||||
|
|
||||||
// Update model and re-render
|
// Update model
|
||||||
this.model = newModel;
|
this.model = newModel;
|
||||||
this.selectedMatch = null; // Reset selection
|
|
||||||
this.filterStatus = null; // Reset filters
|
// Debug: Log model state
|
||||||
this.searchQuery = ""; // Reset search
|
console.log("[Chain Workbench] Refresh complete - matches:", newModel.matches.length);
|
||||||
|
if (newModel.matches.length === 0) {
|
||||||
|
console.warn("[Chain Workbench] WARNING: No matches found after refresh!");
|
||||||
|
console.log("[Chain Workbench] Report templateMatches:", report.templateMatches?.length || 0);
|
||||||
|
console.log("[Chain Workbench] Context:", context);
|
||||||
|
console.log("[Chain Workbench] chainTemplates:", this.chainTemplates ? `loaded (${this.chainTemplates.templates?.length || 0} templates)` : "null");
|
||||||
|
console.log("[Chain Workbench] allEdges:", allEdges.length);
|
||||||
|
if (report.templateMatches && report.templateMatches.length > 0) {
|
||||||
|
console.warn("[Chain Workbench] Report HAS templateMatches but model.matches is empty!");
|
||||||
|
console.log("[Chain Workbench] First templateMatch:", report.templateMatches[0]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log("[Chain Workbench] Model has matches, first match:", newModel.matches[0]?.templateName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore selection if possible
|
||||||
|
if (savedSelectedMatchId && newModel.matches.length > 0) {
|
||||||
|
const restoredMatch = this.findMatchByIdentifier(savedSelectedMatchId, newModel.matches);
|
||||||
|
this.selectedMatch = restoredMatch;
|
||||||
|
// If exact match not found, try to find a similar match (same template)
|
||||||
|
if (!this.selectedMatch && savedSelectedMatchId) {
|
||||||
|
const templateName = savedSelectedMatchId.split('|')[0];
|
||||||
|
const templateMatches = newModel.matches.filter(m => m.templateName === templateName);
|
||||||
|
if (templateMatches.length > 0) {
|
||||||
|
// Select the first match of the same template as fallback
|
||||||
|
this.selectedMatch = templateMatches[0] || null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.selectedMatch = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore filters
|
||||||
|
this.filterStatus = savedFilterStatus;
|
||||||
|
this.searchQuery = savedSearchQuery;
|
||||||
|
|
||||||
|
// Debug: Log filter state
|
||||||
|
console.log("[Chain Workbench] Filter status:", this.filterStatus, "Search query:", this.searchQuery);
|
||||||
|
|
||||||
// Clear and re-render the entire UI
|
// Clear and re-render the entire UI
|
||||||
const { contentEl } = this;
|
const { contentEl } = this;
|
||||||
|
|
@ -1062,6 +1205,10 @@ export class ChainWorkbenchModal extends Modal {
|
||||||
statusSelect.createEl("option", { text: "Near Complete", value: "near_complete" });
|
statusSelect.createEl("option", { text: "Near Complete", value: "near_complete" });
|
||||||
statusSelect.createEl("option", { text: "Partial", value: "partial" });
|
statusSelect.createEl("option", { text: "Partial", value: "partial" });
|
||||||
statusSelect.createEl("option", { text: "Weak", value: "weak" });
|
statusSelect.createEl("option", { text: "Weak", value: "weak" });
|
||||||
|
// Restore filter value
|
||||||
|
if (this.filterStatus) {
|
||||||
|
statusSelect.value = this.filterStatus;
|
||||||
|
}
|
||||||
statusSelect.addEventListener("change", (e) => {
|
statusSelect.addEventListener("change", (e) => {
|
||||||
const target = e.target as HTMLSelectElement;
|
const target = e.target as HTMLSelectElement;
|
||||||
this.filterStatus = target.value || null;
|
this.filterStatus = target.value || null;
|
||||||
|
|
@ -1070,6 +1217,10 @@ export class ChainWorkbenchModal extends Modal {
|
||||||
|
|
||||||
filterContainer.createEl("label", { text: "Search:" });
|
filterContainer.createEl("label", { text: "Search:" });
|
||||||
const searchInput = filterContainer.createEl("input", { type: "text", placeholder: "Template name..." });
|
const searchInput = filterContainer.createEl("input", { type: "text", placeholder: "Template name..." });
|
||||||
|
// Restore search query
|
||||||
|
if (this.searchQuery) {
|
||||||
|
searchInput.value = this.searchQuery;
|
||||||
|
}
|
||||||
searchInput.addEventListener("input", (e) => {
|
searchInput.addEventListener("input", (e) => {
|
||||||
const target = e.target as HTMLInputElement;
|
const target = e.target as HTMLInputElement;
|
||||||
this.searchQuery = target.value.toLowerCase();
|
this.searchQuery = target.value.toLowerCase();
|
||||||
|
|
@ -1088,7 +1239,9 @@ export class ChainWorkbenchModal extends Modal {
|
||||||
detailsContainer.createEl("h3", { text: "Chain Details" });
|
detailsContainer.createEl("h3", { text: "Chain Details" });
|
||||||
|
|
||||||
// Now render the content
|
// Now render the content
|
||||||
|
console.log("[Chain Workbench] About to call render() - model.matches.length:", this.model.matches.length);
|
||||||
this.render();
|
this.render();
|
||||||
|
console.log("[Chain Workbench] render() completed");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("[Chain Workbench] Error refreshing workbench:", error);
|
console.error("[Chain Workbench] Error refreshing workbench:", error);
|
||||||
new Notice(`Error refreshing workbench: ${error instanceof Error ? error.message : String(error)}`);
|
new Notice(`Error refreshing workbench: ${error instanceof Error ? error.message : String(error)}`);
|
||||||
|
|
|
||||||
|
|
@ -26,12 +26,19 @@ export async function buildWorkbenchModel(
|
||||||
const matches: WorkbenchMatch[] = [];
|
const matches: WorkbenchMatch[] = [];
|
||||||
|
|
||||||
if (!report.templateMatches || !chainTemplates) {
|
if (!report.templateMatches || !chainTemplates) {
|
||||||
|
console.warn("[buildWorkbenchModel] No templateMatches or chainTemplates:", {
|
||||||
|
hasTemplateMatches: !!report.templateMatches,
|
||||||
|
templateMatchesCount: report.templateMatches?.length || 0,
|
||||||
|
hasChainTemplates: !!chainTemplates,
|
||||||
|
});
|
||||||
return {
|
return {
|
||||||
context: report.context,
|
context: report.context,
|
||||||
matches: [],
|
matches: [],
|
||||||
timestamp: Date.now(),
|
timestamp: Date.now(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log("[buildWorkbenchModel] Processing", report.templateMatches.length, "template matches");
|
||||||
|
|
||||||
// Get candidate edges from current note
|
// Get candidate edges from current note
|
||||||
// Also check for confirmed edges that would make candidates "not needed"
|
// Also check for confirmed edges that would make candidates "not needed"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user