mirror of
https://github.com/khoaliber/khoj.git
synced 2026-03-09 13:25:11 +00:00
Enhance Search Modal, Error State Handling in Khoj Obsidian Plugin
### Search Modal Enhancements -b52cd85Allow Reranking results using Keybinding from Khoj Search Modal -580f4acAdd hints to Modal for available Keybindings -da49ea2Add placeholder text to modal in Khoj Obsidian plugin ### Handle Failure to Connect to Khoj Backend Load plugin but warn on failure to connect to Khoj backend -f046a95Track connectedToBackend as a setting. Use it across obsidian plugin to: - Disable command if not connected to backend - Trigger warning notice on clicking Khoj ribbon if not connected to backend - Show warning at top of Khoj Obsidian plugin settings pane -768e874Load obsidian plugin even if fail to connect to backend but show warning - Allows user to see reason for failure to try resolve it - Allows user to update Khoj URL settings to point to URL of Khoj server ### Miscellaneous -7991ab7Add button in Obsidian plugin settings to force re-indexing your vault - Useful if index gets corrupted
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { Plugin } from 'obsidian';
|
import { Notice, Plugin } from 'obsidian';
|
||||||
import { KhojSetting, KhojSettingTab, DEFAULT_SETTINGS } from 'src/settings'
|
import { KhojSetting, KhojSettingTab, DEFAULT_SETTINGS } from 'src/settings'
|
||||||
import { KhojModal } from 'src/modal'
|
import { KhojModal } from 'src/modal'
|
||||||
import { configureKhojBackend } from './utils';
|
import { configureKhojBackend } from './utils';
|
||||||
@@ -14,18 +14,22 @@ export default class Khoj extends Plugin {
|
|||||||
this.addCommand({
|
this.addCommand({
|
||||||
id: 'search',
|
id: 'search',
|
||||||
name: 'Search',
|
name: 'Search',
|
||||||
callback: () => {
|
checkCallback: (checking) => {
|
||||||
new KhojModal(this.app, this.settings).open();
|
if (!checking && this.settings.connectedToBackend)
|
||||||
|
new KhojModal(this.app, this.settings).open();
|
||||||
|
return this.settings.connectedToBackend;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create an icon in the left ribbon.
|
// Create an icon in the left ribbon.
|
||||||
this.addRibbonIcon('search', 'Khoj', (_: MouseEvent) => {
|
this.addRibbonIcon('search', 'Khoj', (_: MouseEvent) => {
|
||||||
// Called when the user clicks the icon.
|
// Called when the user clicks the icon.
|
||||||
new KhojModal(this.app, this.settings).open();
|
this.settings.connectedToBackend
|
||||||
|
? new KhojModal(this.app, this.settings).open()
|
||||||
|
: new Notice(`❗️Ensure Khoj backend is running and Khoj URL is pointing to it in the plugin settings`);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add a settings tab so the user can configure various aspects of the plugin
|
// Add a settings tab so the user can configure khoj
|
||||||
this.addSettingTab(new KhojSettingTab(this.app, this));
|
this.addSettingTab(new KhojSettingTab(this.app, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,7 +45,7 @@ export default class Khoj extends Plugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async saveSettings() {
|
async saveSettings() {
|
||||||
await this.saveData(this.settings)
|
await configureKhojBackend(this.settings)
|
||||||
.then(() => configureKhojBackend(this.settings));
|
.then(() => this.saveData(this.settings));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { App, SuggestModal, Notice, request, MarkdownRenderer } from 'obsidian';
|
import { App, SuggestModal, Notice, request, MarkdownRenderer, Instruction, Platform } from 'obsidian';
|
||||||
import { KhojSetting } from 'src/settings';
|
import { KhojSetting } from 'src/settings';
|
||||||
import { getVaultAbsolutePath } from 'src/utils';
|
import { getVaultAbsolutePath } from 'src/utils';
|
||||||
|
|
||||||
@@ -9,16 +9,54 @@ export interface SearchResult {
|
|||||||
|
|
||||||
export class KhojModal extends SuggestModal<SearchResult> {
|
export class KhojModal extends SuggestModal<SearchResult> {
|
||||||
setting: KhojSetting;
|
setting: KhojSetting;
|
||||||
|
rerank: boolean;
|
||||||
|
|
||||||
constructor(app: App, setting: KhojSetting) {
|
constructor(app: App, setting: KhojSetting) {
|
||||||
super(app);
|
super(app);
|
||||||
this.setting = setting;
|
this.setting = setting;
|
||||||
|
this.rerank = false;
|
||||||
|
|
||||||
|
// Register Modal Keybindings to Rerank Results
|
||||||
|
this.scope.register(['Mod'], 'Enter', async () => {
|
||||||
|
this.rerank = true
|
||||||
|
let results = await this.getSuggestions(this.inputEl.value);
|
||||||
|
|
||||||
|
this.resultContainerEl.empty();
|
||||||
|
results.forEach((result) => {
|
||||||
|
this.renderSuggestion(result, this.resultContainerEl);
|
||||||
|
});
|
||||||
|
this.rerank = false
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add Hints to Modal for available Keybindings
|
||||||
|
const modalInstructions: Instruction[] = [
|
||||||
|
{
|
||||||
|
command: '↑↓',
|
||||||
|
purpose: 'to navigate',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
command: '↵',
|
||||||
|
purpose: 'to open',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
command: Platform.isMacOS ? 'cmd ↵': 'ctrl ↵',
|
||||||
|
purpose: 'to rerank',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
command: 'esc',
|
||||||
|
purpose: 'to dismiss',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
this.setInstructions(modalInstructions);
|
||||||
|
|
||||||
|
// Set Placeholder Text for Modal
|
||||||
|
this.setPlaceholder('Search with Khoj...');
|
||||||
}
|
}
|
||||||
|
|
||||||
async getSuggestions(query: string): Promise<SearchResult[]> {
|
async getSuggestions(query: string): Promise<SearchResult[]> {
|
||||||
// Query Khoj backend for search results
|
// Query Khoj backend for search results
|
||||||
var searchUrl = `${this.setting.khojUrl}/api/search?q=${query}&n=${this.setting.resultsCount}&t=markdown`
|
let searchUrl = `${this.setting.khojUrl}/api/search?q=${query}&n=${this.setting.resultsCount}&r=${this.rerank}&t=markdown`
|
||||||
var results = await request(searchUrl)
|
let results = await request(searchUrl)
|
||||||
.then(response => JSON.parse(response))
|
.then(response => JSON.parse(response))
|
||||||
.then(data => {
|
.then(data => {
|
||||||
return data.map((result: any) => {
|
return data.map((result: any) => {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { App, PluginSettingTab, Setting } from 'obsidian';
|
import { App, PluginSettingTab, request, Setting } from 'obsidian';
|
||||||
import Khoj from 'src/main';
|
import Khoj from 'src/main';
|
||||||
import { getVaultAbsolutePath } from 'src/utils';
|
import { getVaultAbsolutePath } from 'src/utils';
|
||||||
|
|
||||||
@@ -6,12 +6,14 @@ export interface KhojSetting {
|
|||||||
resultsCount: number;
|
resultsCount: number;
|
||||||
khojUrl: string;
|
khojUrl: string;
|
||||||
obsidianVaultPath: string;
|
obsidianVaultPath: string;
|
||||||
|
connectedToBackend: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DEFAULT_SETTINGS: KhojSetting = {
|
export const DEFAULT_SETTINGS: KhojSetting = {
|
||||||
resultsCount: 6,
|
resultsCount: 6,
|
||||||
khojUrl: 'http://localhost:8000',
|
khojUrl: 'http://localhost:8000',
|
||||||
obsidianVaultPath: getVaultAbsolutePath()
|
obsidianVaultPath: getVaultAbsolutePath(),
|
||||||
|
connectedToBackend: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
export class KhojSettingTab extends PluginSettingTab {
|
export class KhojSettingTab extends PluginSettingTab {
|
||||||
@@ -25,8 +27,15 @@ export class KhojSettingTab extends PluginSettingTab {
|
|||||||
display(): void {
|
display(): void {
|
||||||
const { containerEl } = this;
|
const { containerEl } = this;
|
||||||
containerEl.empty();
|
containerEl.empty();
|
||||||
|
|
||||||
|
// Add notice if unable to connect to khoj backend
|
||||||
|
if (!this.plugin.settings.connectedToBackend) {
|
||||||
|
containerEl.createEl('small', { text: '❗Ensure Khoj backend is running and Khoj URL is correctly set below' });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add khoj settings configurable from the plugin settings tab
|
||||||
new Setting(containerEl)
|
new Setting(containerEl)
|
||||||
.setName('Vault Paths')
|
.setName('Vault Path')
|
||||||
.setDesc('The Obsidian Vault to search with Khoj')
|
.setDesc('The Obsidian Vault to search with Khoj')
|
||||||
.addText(text => text
|
.addText(text => text
|
||||||
.setValue(`${this.plugin.settings.obsidianVaultPath}`)
|
.setValue(`${this.plugin.settings.obsidianVaultPath}`)
|
||||||
@@ -44,7 +53,7 @@ export class KhojSettingTab extends PluginSettingTab {
|
|||||||
await this.plugin.saveSettings();
|
await this.plugin.saveSettings();
|
||||||
}));
|
}));
|
||||||
new Setting(containerEl)
|
new Setting(containerEl)
|
||||||
.setName('Number of Results')
|
.setName('Results Count')
|
||||||
.setDesc('The number of search results to show')
|
.setDesc('The number of search results to show')
|
||||||
.addText(text => text
|
.addText(text => text
|
||||||
.setPlaceholder('6')
|
.setPlaceholder('6')
|
||||||
@@ -53,5 +62,14 @@ export class KhojSettingTab extends PluginSettingTab {
|
|||||||
this.plugin.settings.resultsCount = parseInt(value);
|
this.plugin.settings.resultsCount = parseInt(value);
|
||||||
await this.plugin.saveSettings();
|
await this.plugin.saveSettings();
|
||||||
}));
|
}));
|
||||||
|
new Setting(containerEl)
|
||||||
|
.setName('Index Vault')
|
||||||
|
.setDesc('Manually force Khoj to re-index your Obsidian Vault')
|
||||||
|
.addButton(button => button
|
||||||
|
.setButtonText('Update')
|
||||||
|
.onClick(async () => {
|
||||||
|
await request(`${this.plugin.settings.khojUrl}/api/update?t=markdown&force=true`);
|
||||||
|
}
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,16 +13,25 @@ export async function configureKhojBackend(setting: KhojSetting) {
|
|||||||
let mdInVault = `${setting.obsidianVaultPath}/**/*.md`;
|
let mdInVault = `${setting.obsidianVaultPath}/**/*.md`;
|
||||||
let khojConfigUrl = `${setting.khojUrl}/api/config/data`;
|
let khojConfigUrl = `${setting.khojUrl}/api/config/data`;
|
||||||
|
|
||||||
// Load khoj app config from backend API, Update Markdown config and save
|
// Check if khoj backend is configured, show error if backend is not running
|
||||||
let khoj_configured = await request(khojConfigUrl)
|
let khoj_already_configured = await request(khojConfigUrl)
|
||||||
.then(response => response !== "null");
|
.then(response => {
|
||||||
|
setting.connectedToBackend = true;
|
||||||
|
return response !== "null"
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
setting.connectedToBackend = false;
|
||||||
|
new Notice(`❗️Ensure Khoj backend is running and Khoj URL is pointing to it in the plugin settings.\n\n${error}`);
|
||||||
|
})
|
||||||
|
// Short-circuit configuring khoj if unable to connect to khoj backend
|
||||||
|
if (!setting.connectedToBackend) return;
|
||||||
|
|
||||||
// Get current config if khoj backend configured, else get default config from khoj backend
|
// Get current config if khoj backend configured, else get default config from khoj backend
|
||||||
await request(khoj_configured ? khojConfigUrl : `${khojConfigUrl}/default`)
|
await request(khoj_already_configured ? khojConfigUrl : `${khojConfigUrl}/default`)
|
||||||
.then(response => JSON.parse(response))
|
.then(response => JSON.parse(response))
|
||||||
.then(data => {
|
.then(data => {
|
||||||
// If khoj backend not configured yet
|
// If khoj backend not configured yet
|
||||||
if (!khoj_configured) {
|
if (!khoj_already_configured) {
|
||||||
// Create khoj content-type config with only markdown configured
|
// Create khoj content-type config with only markdown configured
|
||||||
let khojObsidianPluginPath = `${setting.obsidianVaultPath}/${this.app.vault.configDir}/plugins/khoj/`;
|
let khojObsidianPluginPath = `${setting.obsidianVaultPath}/${this.app.vault.configDir}/plugins/khoj/`;
|
||||||
data["content-type"] = {
|
data["content-type"] = {
|
||||||
@@ -70,9 +79,10 @@ export async function configureKhojBackend(setting: KhojSetting) {
|
|||||||
updateKhojBackend(setting.khojUrl, data);
|
updateKhojBackend(setting.khojUrl, data);
|
||||||
console.log(`Khoj: Updated markdown config in khoj backend config:\n${JSON.stringify(data["content-type"]["markdown"])}`)
|
console.log(`Khoj: Updated markdown config in khoj backend config:\n${JSON.stringify(data["content-type"]["markdown"])}`)
|
||||||
}
|
}
|
||||||
|
new Notice(`✅ Successfully Setup Khoj`);
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
new Notice(`Ensure Khoj backend is running and Khoj URL is correct in the Khoj plugin settings.\nError: ${error}`);
|
new Notice(`❗️Failed to configure Khoj backend. Contact developer on Github. \n\nError: ${error}`);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user