Enhance edge type suggestions and UI in LinkPromptModal
- Added support for alternative edge types in the EdgeTypeSuggestion interface, improving user guidance during edge type selection. - Updated computeEdgeSuggestions function to compute and limit alternative edge types based on typical and prohibited types. - Enhanced LinkPromptModal to display recommended and alternative edge types, improving user experience with clearer selection options. - Introduced new action for setting typical edge types, allowing for more intuitive edge type management.
This commit is contained in:
parent
2fcf333e56
commit
7e256bd2e9
|
|
@ -8,6 +8,7 @@ import { getHints } from "./graphSchema";
|
||||||
|
|
||||||
export interface EdgeTypeSuggestion {
|
export interface EdgeTypeSuggestion {
|
||||||
typical: string[]; // Recommended edge types
|
typical: string[]; // Recommended edge types
|
||||||
|
alternatives: string[]; // Alternative edge types (not typical, not prohibited)
|
||||||
prohibited: string[]; // Prohibited edge types
|
prohibited: string[]; // Prohibited edge types
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -21,14 +22,36 @@ export function computeEdgeSuggestions(
|
||||||
targetType: string | null,
|
targetType: string | null,
|
||||||
graphSchema: GraphSchema | null = null
|
graphSchema: GraphSchema | null = null
|
||||||
): EdgeTypeSuggestion {
|
): EdgeTypeSuggestion {
|
||||||
|
let typical: string[] = [];
|
||||||
|
let prohibited: string[] = [];
|
||||||
|
|
||||||
if (graphSchema) {
|
if (graphSchema) {
|
||||||
return getHints(graphSchema, sourceType, targetType);
|
const hints = getHints(graphSchema, sourceType, targetType);
|
||||||
|
typical = hints.typical;
|
||||||
|
prohibited = hints.prohibited;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute alternatives: limit to a reasonable number of common edge types
|
||||||
|
// Only show alternatives if we have typical types (meaning schema is available)
|
||||||
|
// Otherwise, don't show alternatives to avoid overwhelming the user
|
||||||
|
let alternatives: string[] = [];
|
||||||
|
if (typical.length > 0) {
|
||||||
|
// Only show alternatives if we have schema-based recommendations
|
||||||
|
// Limit to first 6-8 most common edge types that aren't typical or prohibited
|
||||||
|
const allCanonicalTypes = Array.from(vocabulary.byCanonical.keys());
|
||||||
|
const filtered = allCanonicalTypes.filter(canonical => {
|
||||||
|
const isTypical = typical.includes(canonical);
|
||||||
|
const isProhibited = prohibited.includes(canonical);
|
||||||
|
return !isTypical && !isProhibited;
|
||||||
|
});
|
||||||
|
// Limit to 8 alternatives max
|
||||||
|
alternatives = filtered.slice(0, 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
// No schema available, return empty
|
|
||||||
return {
|
return {
|
||||||
typical: [],
|
typical,
|
||||||
prohibited: [],
|
alternatives,
|
||||||
|
prohibited,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -233,7 +233,7 @@ export async function buildSemanticMappings(
|
||||||
if (mappingState.existingMappings.has(item.link)) {
|
if (mappingState.existingMappings.has(item.link)) {
|
||||||
result.existingMappingsKept++;
|
result.existingMappingsKept++;
|
||||||
}
|
}
|
||||||
} else if (decision.action === "change") {
|
} else if (decision.action === "change" || decision.action === "setTypical") {
|
||||||
// Use alias if provided, otherwise use canonical type
|
// Use alias if provided, otherwise use canonical type
|
||||||
// This ensures selected aliases are written to the file, not just canonical types
|
// This ensures selected aliases are written to the file, not just canonical types
|
||||||
const finalEdgeType = decision.alias || decision.edgeType;
|
const finalEdgeType = decision.alias || decision.edgeType;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
/**
|
/**
|
||||||
* Modal for prompting edge type assignment for a single link.
|
* Modal for prompting edge type assignment for a single link.
|
||||||
|
* Enhanced with preselection similar to InlineEdgeTypeModal.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Modal } from "obsidian";
|
import { Modal } from "obsidian";
|
||||||
|
|
@ -12,6 +13,7 @@ import { computeEdgeSuggestions } from "../mapping/schemaHelper";
|
||||||
export type LinkPromptDecision =
|
export type LinkPromptDecision =
|
||||||
| { action: "keep"; edgeType: string } // edgeType is the actual type (alias or canonical) to keep
|
| { action: "keep"; edgeType: string } // edgeType is the actual type (alias or canonical) to keep
|
||||||
| { action: "change"; edgeType: string; alias?: string } // edgeType is canonical, alias is the selected alias (if any)
|
| { action: "change"; edgeType: string; alias?: string } // edgeType is canonical, alias is the selected alias (if any)
|
||||||
|
| { action: "setTypical"; edgeType: string; alias?: string } // Set to first typical type (canonical, alias optional)
|
||||||
| { action: "skip" };
|
| { action: "skip" };
|
||||||
|
|
||||||
export class LinkPromptModal extends Modal {
|
export class LinkPromptModal extends Modal {
|
||||||
|
|
@ -21,6 +23,8 @@ export class LinkPromptModal extends Modal {
|
||||||
private graphSchema: GraphSchema | null;
|
private graphSchema: GraphSchema | null;
|
||||||
private result: LinkPromptDecision | null = null;
|
private result: LinkPromptDecision | null = null;
|
||||||
private resolve: ((result: LinkPromptDecision) => void) | null = null;
|
private resolve: ((result: LinkPromptDecision) => void) | null = null;
|
||||||
|
private selectedEdgeType: string | null = null;
|
||||||
|
private selectedAlias: string | null = null;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
app: any,
|
app: any,
|
||||||
|
|
@ -37,10 +41,26 @@ export class LinkPromptModal extends Modal {
|
||||||
}
|
}
|
||||||
|
|
||||||
onOpen(): void {
|
onOpen(): void {
|
||||||
|
// Always show quick chooser as main view
|
||||||
|
this.showQuickChooser();
|
||||||
|
}
|
||||||
|
|
||||||
|
private showQuickChooser(): void {
|
||||||
const { contentEl } = this;
|
const { contentEl } = this;
|
||||||
contentEl.empty();
|
contentEl.empty();
|
||||||
contentEl.addClass("link-prompt-modal");
|
contentEl.addClass("link-prompt-modal");
|
||||||
|
|
||||||
|
// Get recommendations
|
||||||
|
const suggestions = computeEdgeSuggestions(
|
||||||
|
this.vocabulary,
|
||||||
|
this.sourceType,
|
||||||
|
this.item.targetType,
|
||||||
|
this.graphSchema
|
||||||
|
);
|
||||||
|
const typical = suggestions.typical;
|
||||||
|
const alternatives = suggestions.alternatives;
|
||||||
|
const prohibited = suggestions.prohibited;
|
||||||
|
|
||||||
// Link info
|
// Link info
|
||||||
const linkInfo = contentEl.createEl("div", { cls: "link-info" });
|
const linkInfo = contentEl.createEl("div", { cls: "link-info" });
|
||||||
linkInfo.createEl("h2", { text: `Link: [[${this.item.link}]]` });
|
linkInfo.createEl("h2", { text: `Link: [[${this.item.link}]]` });
|
||||||
|
|
@ -49,114 +69,210 @@ export class LinkPromptModal extends Modal {
|
||||||
linkInfo.createEl("p", { text: `Target type: ${this.item.targetType}` });
|
linkInfo.createEl("p", { text: `Target type: ${this.item.targetType}` });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Current mapping (if exists)
|
// Show current/selected edge type prominently
|
||||||
if (this.item.currentType) {
|
const selectedTypeDisplay = this.getSelectedTypeDisplay();
|
||||||
const currentInfo = linkInfo.createEl("p", { cls: "current-mapping" });
|
if (selectedTypeDisplay) {
|
||||||
currentInfo.textContent = `Current edge type: ${this.item.currentType}`;
|
const selectedInfo = contentEl.createEl("div", {
|
||||||
|
cls: "selected-edge-type",
|
||||||
// Check if current type is prohibited
|
|
||||||
if (this.graphSchema) {
|
|
||||||
const suggestions = computeEdgeSuggestions(
|
|
||||||
this.vocabulary,
|
|
||||||
this.sourceType,
|
|
||||||
this.item.targetType,
|
|
||||||
this.graphSchema
|
|
||||||
);
|
|
||||||
if (suggestions.prohibited.includes(this.item.currentType)) {
|
|
||||||
const warning = linkInfo.createEl("span", {
|
|
||||||
text: " ⚠️ Prohibited",
|
|
||||||
cls: "prohibited-warning",
|
|
||||||
});
|
});
|
||||||
warning.style.color = "var(--text-error)";
|
selectedInfo.style.marginTop = "1em";
|
||||||
warning.style.fontWeight = "bold";
|
selectedInfo.style.padding = "0.75em";
|
||||||
|
selectedInfo.style.backgroundColor = "var(--background-modifier-hover)";
|
||||||
|
selectedInfo.style.borderRadius = "4px";
|
||||||
|
selectedInfo.style.border = "2px solid var(--interactive-accent)";
|
||||||
|
|
||||||
|
const selectedLabel = selectedInfo.createEl("div", {
|
||||||
|
text: "Ausgewählte Beziehung:",
|
||||||
|
cls: "selected-label",
|
||||||
|
});
|
||||||
|
selectedLabel.style.fontSize = "0.9em";
|
||||||
|
selectedLabel.style.color = "var(--text-muted)";
|
||||||
|
selectedLabel.style.marginBottom = "0.25em";
|
||||||
|
|
||||||
|
const selectedValue = selectedInfo.createEl("div", {
|
||||||
|
text: selectedTypeDisplay,
|
||||||
|
cls: "selected-value",
|
||||||
|
});
|
||||||
|
selectedValue.style.fontSize = "1.1em";
|
||||||
|
selectedValue.style.fontWeight = "bold";
|
||||||
|
selectedValue.style.color = "var(--text-normal)";
|
||||||
|
} else if (this.item.currentType) {
|
||||||
|
// Show existing type if no new selection
|
||||||
|
const currentInfo = contentEl.createEl("div", {
|
||||||
|
cls: "current-edge-type",
|
||||||
|
});
|
||||||
|
currentInfo.style.marginTop = "1em";
|
||||||
|
currentInfo.style.padding = "0.75em";
|
||||||
|
currentInfo.style.backgroundColor = "var(--background-modifier-hover)";
|
||||||
|
currentInfo.style.borderRadius = "4px";
|
||||||
|
|
||||||
|
const currentLabel = currentInfo.createEl("div", {
|
||||||
|
text: "Aktuelle Beziehung:",
|
||||||
|
cls: "current-label",
|
||||||
|
});
|
||||||
|
currentLabel.style.fontSize = "0.9em";
|
||||||
|
currentLabel.style.color = "var(--text-muted)";
|
||||||
|
currentLabel.style.marginBottom = "0.25em";
|
||||||
|
|
||||||
|
const currentValue = currentInfo.createEl("div", {
|
||||||
|
text: this.item.currentType,
|
||||||
|
cls: "current-value",
|
||||||
|
});
|
||||||
|
currentValue.style.fontSize = "1.1em";
|
||||||
|
currentValue.style.fontWeight = "bold";
|
||||||
|
|
||||||
|
// Check if current type is typical, alternative, or prohibited
|
||||||
|
const currentTypeLower = this.item.currentType.toLowerCase();
|
||||||
|
const currentCanonical = this.vocabulary.aliasToCanonical.get(currentTypeLower) || this.item.currentType;
|
||||||
|
const isTypical = typical.includes(currentCanonical);
|
||||||
|
const isProhibited = prohibited.includes(currentCanonical);
|
||||||
|
|
||||||
|
if (isTypical) {
|
||||||
|
currentValue.style.color = "var(--text-success)";
|
||||||
|
currentValue.textContent = `${this.item.currentType} ⭐`;
|
||||||
|
} else if (isProhibited) {
|
||||||
|
currentValue.style.color = "var(--text-error)";
|
||||||
|
currentValue.textContent = `${this.item.currentType} ⚠️`;
|
||||||
|
} else {
|
||||||
|
currentValue.style.color = "var(--text-warning)";
|
||||||
|
currentValue.textContent = `${this.item.currentType} ⚠️`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Quick-Chooser: Recommended and Alternatives
|
||||||
|
if (typical.length > 0 || alternatives.length > 0) {
|
||||||
|
// Recommended chips (typical)
|
||||||
|
if (typical.length > 0) {
|
||||||
|
const typicalContainer = contentEl.createEl("div", {
|
||||||
|
cls: "link-prompt-modal__section",
|
||||||
|
});
|
||||||
|
typicalContainer.createEl("div", {
|
||||||
|
cls: "link-prompt-modal__section-label",
|
||||||
|
text: "⭐ Recommended:",
|
||||||
|
});
|
||||||
|
const chipsContainer = typicalContainer.createEl("div", {
|
||||||
|
cls: "link-prompt-modal__chips",
|
||||||
|
});
|
||||||
|
chipsContainer.style.display = "flex";
|
||||||
|
chipsContainer.style.flexWrap = "wrap";
|
||||||
|
chipsContainer.style.gap = "0.5em";
|
||||||
|
chipsContainer.style.marginTop = "0.5em";
|
||||||
|
|
||||||
|
for (const canonical of typical) {
|
||||||
|
const entry = this.vocabulary.byCanonical.get(canonical);
|
||||||
|
if (!entry) continue;
|
||||||
|
|
||||||
|
const chip = chipsContainer.createEl("button", {
|
||||||
|
cls: "link-prompt-modal__chip",
|
||||||
|
text: canonical,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (entry.description) {
|
||||||
|
chip.title = entry.description;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark as selected if this is the currently selected type
|
||||||
|
const isSelected = this.isSelectedType(canonical);
|
||||||
|
if (isSelected) {
|
||||||
|
chip.addClass("mod-cta");
|
||||||
|
}
|
||||||
|
|
||||||
|
chip.onclick = async () => {
|
||||||
|
await this.handleChipSelection(canonical, entry.aliases);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alternatives chips
|
||||||
|
if (alternatives.length > 0) {
|
||||||
|
const altContainer = contentEl.createEl("div", {
|
||||||
|
cls: "link-prompt-modal__section",
|
||||||
|
});
|
||||||
|
altContainer.createEl("div", {
|
||||||
|
cls: "link-prompt-modal__section-label",
|
||||||
|
text: "Alternatives:",
|
||||||
|
});
|
||||||
|
const chipsContainer = altContainer.createEl("div", {
|
||||||
|
cls: "link-prompt-modal__chips",
|
||||||
|
});
|
||||||
|
chipsContainer.style.display = "flex";
|
||||||
|
chipsContainer.style.flexWrap = "wrap";
|
||||||
|
chipsContainer.style.gap = "0.5em";
|
||||||
|
chipsContainer.style.marginTop = "0.5em";
|
||||||
|
|
||||||
|
for (const canonical of alternatives) {
|
||||||
|
const entry = this.vocabulary.byCanonical.get(canonical);
|
||||||
|
if (!entry) continue;
|
||||||
|
|
||||||
|
const chip = chipsContainer.createEl("button", {
|
||||||
|
cls: "link-prompt-modal__chip",
|
||||||
|
text: canonical,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (entry.description) {
|
||||||
|
chip.title = entry.description;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark as selected if this is the currently selected type
|
||||||
|
const isSelected = this.isSelectedType(canonical);
|
||||||
|
if (isSelected) {
|
||||||
|
chip.addClass("mod-cta");
|
||||||
|
}
|
||||||
|
|
||||||
|
chip.onclick = async () => {
|
||||||
|
await this.handleChipSelection(canonical, entry.aliases);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Link to full Edge-Chooser
|
||||||
|
const chooserLink = contentEl.createEl("button", {
|
||||||
|
text: "Alle Kanten anzeigen...",
|
||||||
|
cls: "link-prompt-modal__chooser-link",
|
||||||
|
});
|
||||||
|
chooserLink.style.marginTop = "1em";
|
||||||
|
chooserLink.style.width = "100%";
|
||||||
|
chooserLink.onclick = async () => {
|
||||||
|
await this.showFullChooser();
|
||||||
|
};
|
||||||
|
|
||||||
// Action buttons
|
// Action buttons
|
||||||
const buttonContainer = contentEl.createEl("div", { cls: "action-buttons" });
|
const buttonContainer = contentEl.createEl("div", { cls: "action-buttons" });
|
||||||
buttonContainer.style.display = "flex";
|
buttonContainer.style.display = "flex";
|
||||||
buttonContainer.style.flexDirection = "column";
|
buttonContainer.style.flexDirection = "row";
|
||||||
buttonContainer.style.gap = "0.5em";
|
buttonContainer.style.gap = "0.5em";
|
||||||
buttonContainer.style.marginTop = "1em";
|
buttonContainer.style.marginTop = "1.5em";
|
||||||
|
buttonContainer.style.justifyContent = "flex-end";
|
||||||
|
|
||||||
if (this.item.currentType) {
|
// OK/Save button - confirms selection
|
||||||
// Keep current
|
const okBtn = buttonContainer.createEl("button", {
|
||||||
const keepBtn = buttonContainer.createEl("button", {
|
text: this.item.currentType ? "Speichern" : "OK",
|
||||||
text: `✅ Keep (${this.item.currentType})`,
|
|
||||||
cls: "mod-cta",
|
cls: "mod-cta",
|
||||||
});
|
});
|
||||||
|
okBtn.onclick = () => {
|
||||||
|
this.confirmSelection();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Keep current button (only if current type exists and no new selection)
|
||||||
|
if (this.item.currentType && !this.selectedEdgeType) {
|
||||||
|
const keepBtn = buttonContainer.createEl("button", {
|
||||||
|
text: `Behalten (${this.item.currentType})`,
|
||||||
|
});
|
||||||
keepBtn.onclick = () => {
|
keepBtn.onclick = () => {
|
||||||
this.result = { action: "keep", edgeType: this.item.currentType! };
|
this.result = { action: "keep", edgeType: this.item.currentType! };
|
||||||
this.close();
|
this.close();
|
||||||
};
|
};
|
||||||
|
|
||||||
// Change type
|
|
||||||
const changeBtn = buttonContainer.createEl("button", {
|
|
||||||
text: "Change type...",
|
|
||||||
});
|
|
||||||
changeBtn.onclick = async () => {
|
|
||||||
const chooser = new EdgeTypeChooserModal(
|
|
||||||
this.app,
|
|
||||||
this.vocabulary,
|
|
||||||
this.sourceType,
|
|
||||||
this.item.targetType,
|
|
||||||
this.graphSchema
|
|
||||||
);
|
|
||||||
const choice = await chooser.show();
|
|
||||||
if (choice) {
|
|
||||||
this.result = {
|
|
||||||
action: "change",
|
|
||||||
edgeType: choice.edgeType,
|
|
||||||
alias: choice.alias,
|
|
||||||
};
|
|
||||||
this.close();
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
// Skip
|
// Skip button
|
||||||
const skipBtn = buttonContainer.createEl("button", {
|
const skipBtn = buttonContainer.createEl("button", {
|
||||||
text: "Skip link",
|
text: "Überspringen",
|
||||||
});
|
});
|
||||||
skipBtn.onclick = () => {
|
skipBtn.onclick = () => {
|
||||||
this.result = { action: "skip" };
|
this.result = { action: "skip" };
|
||||||
this.close();
|
this.close();
|
||||||
};
|
};
|
||||||
} else {
|
|
||||||
// No current mapping
|
|
||||||
// Skip
|
|
||||||
const skipBtn = buttonContainer.createEl("button", {
|
|
||||||
text: "⏩ Skip link",
|
|
||||||
});
|
|
||||||
skipBtn.onclick = () => {
|
|
||||||
this.result = { action: "skip" };
|
|
||||||
this.close();
|
|
||||||
};
|
|
||||||
|
|
||||||
// Choose type
|
|
||||||
const chooseBtn = buttonContainer.createEl("button", {
|
|
||||||
text: "Choose type...",
|
|
||||||
cls: "mod-cta",
|
|
||||||
});
|
|
||||||
chooseBtn.onclick = async () => {
|
|
||||||
const chooser = new EdgeTypeChooserModal(
|
|
||||||
this.app,
|
|
||||||
this.vocabulary,
|
|
||||||
this.sourceType,
|
|
||||||
this.item.targetType,
|
|
||||||
this.graphSchema
|
|
||||||
);
|
|
||||||
const choice = await chooser.show();
|
|
||||||
if (choice) {
|
|
||||||
this.result = {
|
|
||||||
action: "change",
|
|
||||||
edgeType: choice.edgeType,
|
|
||||||
alias: choice.alias,
|
|
||||||
};
|
|
||||||
this.close();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onClose(): void {
|
onClose(): void {
|
||||||
|
|
@ -180,4 +296,126 @@ export class LinkPromptModal extends Modal {
|
||||||
this.open();
|
this.open();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private selectEdgeType(edgeType: string, alias?: string | null): void {
|
||||||
|
this.selectedEdgeType = edgeType;
|
||||||
|
this.selectedAlias = alias || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private isSelectedType(canonical: string): boolean {
|
||||||
|
if (!this.selectedEdgeType) return false;
|
||||||
|
// Check if selected canonical matches
|
||||||
|
if (this.selectedEdgeType === canonical) return true;
|
||||||
|
// Check if selected alias belongs to this canonical
|
||||||
|
if (this.selectedAlias) {
|
||||||
|
const entry = this.vocabulary.byCanonical.get(canonical);
|
||||||
|
if (entry && entry.aliases.includes(this.selectedAlias)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getSelectedTypeDisplay(): string | null {
|
||||||
|
if (this.selectedEdgeType) {
|
||||||
|
// Show alias if selected, otherwise canonical
|
||||||
|
return this.selectedAlias || this.selectedEdgeType;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async handleChipSelection(canonical: string, aliases: string[]): Promise<void> {
|
||||||
|
if (aliases.length > 0) {
|
||||||
|
// Show alias chooser
|
||||||
|
const alias = await this.showAliasChooser(canonical, aliases);
|
||||||
|
if (alias !== null && alias !== undefined) {
|
||||||
|
this.selectEdgeType(canonical, alias);
|
||||||
|
// Return to quick chooser to show selection
|
||||||
|
this.showQuickChooser();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// No aliases, select canonical directly
|
||||||
|
this.selectEdgeType(canonical);
|
||||||
|
// Return to quick chooser to show selection
|
||||||
|
this.showQuickChooser();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async showFullChooser(): Promise<void> {
|
||||||
|
const chooser = new EdgeTypeChooserModal(
|
||||||
|
this.app,
|
||||||
|
this.vocabulary,
|
||||||
|
this.sourceType,
|
||||||
|
this.item.targetType,
|
||||||
|
this.graphSchema
|
||||||
|
);
|
||||||
|
const choice = await chooser.show();
|
||||||
|
if (choice) {
|
||||||
|
// Store selection and return to quick chooser
|
||||||
|
this.selectEdgeType(choice.edgeType, choice.alias);
|
||||||
|
this.showQuickChooser();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private confirmSelection(): void {
|
||||||
|
if (this.selectedEdgeType) {
|
||||||
|
// New selection made
|
||||||
|
this.result = {
|
||||||
|
action: "change",
|
||||||
|
edgeType: this.selectedEdgeType,
|
||||||
|
alias: this.selectedAlias || undefined,
|
||||||
|
};
|
||||||
|
this.close();
|
||||||
|
} else if (this.item.currentType) {
|
||||||
|
// No new selection, keep current
|
||||||
|
this.result = { action: "keep", edgeType: this.item.currentType };
|
||||||
|
this.close();
|
||||||
|
} else {
|
||||||
|
// No selection and no current type, skip
|
||||||
|
this.result = { action: "skip" };
|
||||||
|
this.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async showAliasChooser(canonical: string, aliases: string[]): Promise<string | null> {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const { contentEl } = this;
|
||||||
|
|
||||||
|
contentEl.empty();
|
||||||
|
contentEl.createEl("h2", { text: "Alias auswählen" });
|
||||||
|
contentEl.createEl("p", { text: `Verfügbare Aliase für ${canonical}:` });
|
||||||
|
|
||||||
|
const container = contentEl.createEl("div");
|
||||||
|
container.style.display = "flex";
|
||||||
|
container.style.flexDirection = "column";
|
||||||
|
container.style.gap = "0.5em";
|
||||||
|
container.style.marginTop = "1em";
|
||||||
|
|
||||||
|
// Canonical option
|
||||||
|
const canonicalBtn = container.createEl("button", {
|
||||||
|
text: `${canonical} (canonical)`,
|
||||||
|
cls: "mod-cta",
|
||||||
|
});
|
||||||
|
canonicalBtn.style.width = "100%";
|
||||||
|
canonicalBtn.style.padding = "0.75em";
|
||||||
|
canonicalBtn.onclick = () => {
|
||||||
|
resolve(canonical);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Alias options
|
||||||
|
for (const alias of aliases) {
|
||||||
|
const btn = container.createEl("button", { text: alias });
|
||||||
|
btn.style.width = "100%";
|
||||||
|
btn.style.padding = "0.75em";
|
||||||
|
btn.onclick = () => {
|
||||||
|
resolve(alias);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const backBtn = container.createEl("button", { text: "← Zurück" });
|
||||||
|
backBtn.style.width = "100%";
|
||||||
|
backBtn.style.marginTop = "1em";
|
||||||
|
backBtn.onclick = () => {
|
||||||
|
resolve(null);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user