Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | 39x 39x 39x 39x 39x 39x 39x 39x 39x 39x 39x 33x 33x 33x 33x 33x 33x 5x 5x 33x 33x 33x 33x 33x 45x 17x 33x 33x 5x 5x 44x 43x 43x 43x 62x 60x 13x 13x 11x 11x 11x 11x 10x 10x 7x 7x 7x 3x 3x | import { App, Modal, Notice } from "obsidian";
import type LilbeePlugin from "../main";
import { ConfirmModal } from "./confirm-modal";
import { DocumentList } from "../components/document-list";
import { MESSAGES } from "../locales/en";
import { bindEscapeToClose, debounce, DEBOUNCE_MS, extractServerErrorDetail } from "../utils";
export class DocumentsModal extends Modal {
private plugin: LilbeePlugin;
private list: DocumentList | null = null;
private unbindScroll: (() => void) | null = null;
private resultsEl: HTMLElement | null = null;
private removeBtn: HTMLElement | null = null;
private searchQuery = "";
private debouncedSearch: () => void;
private cancelDebouncedSearch: () => void;
constructor(app: App, plugin: LilbeePlugin) {
super(app);
this.plugin = plugin;
const searchDebounced = debounce(() => this.resetAndFetch(), DEBOUNCE_MS);
this.debouncedSearch = searchDebounced.run;
this.cancelDebouncedSearch = searchDebounced.cancel;
bindEscapeToClose(this);
}
onOpen(): void {
const { contentEl } = this;
contentEl.empty();
contentEl.addClass("lilbee-documents-modal");
contentEl.createEl("h2", { text: MESSAGES.TITLE_DOCUMENTS });
const searchInput = contentEl.createEl("input", {
cls: "lilbee-documents-search",
placeholder: MESSAGES.PLACEHOLDER_SEARCH_DOCUMENTS,
attr: { type: "text" },
});
searchInput.addEventListener("input", () => {
this.searchQuery = searchInput.value;
this.debouncedSearch();
});
this.removeBtn = contentEl.createEl("button", {
text: MESSAGES.BUTTON_DELETE_SELECTED,
cls: "lilbee-documents-remove",
});
(this.removeBtn as HTMLButtonElement).disabled = true;
this.removeBtn.addEventListener("click", () => void this.removeSelected());
this.resultsEl = contentEl.createDiv({ cls: "lilbee-documents-results" });
this.list = new DocumentList(
this.resultsEl,
(limit, offset) => this.plugin.api.listDocuments(this.searchQuery || undefined, limit, offset),
{ selectable: true, onSelectionChange: () => this.updateRemoveBtn() },
);
this.unbindScroll = this.list.bindScroll(this.resultsEl);
this.resetAndFetch();
}
onClose(): void {
this.cancelDebouncedSearch();
this.unbindScroll?.();
}
private resetAndFetch(): void {
if (!this.list) return;
this.list.reset();
this.updateRemoveBtn();
void this.list.loadMore();
}
private updateRemoveBtn(): void {
if (!this.removeBtn || !this.list) return;
(this.removeBtn as HTMLButtonElement).disabled = this.list.selected.length === 0;
}
private async removeSelected(): Promise<void> {
const names = this.list?.selected ?? [];
if (names.length === 0) return;
const confirm = new ConfirmModal(this.app, MESSAGES.NOTICE_CONFIRM_DELETE_DOCS(names.length));
confirm.open();
const confirmed = await confirm.result;
if (!confirmed) return;
try {
const result = await this.plugin.api.removeDocuments(names);
new Notice(MESSAGES.NOTICE_DELETED(result.removed.length));
if (result.not_found.length > 0) new Notice(MESSAGES.NOTICE_DELETE_NOT_FOUND(result.not_found.length));
this.resetAndFetch();
} catch (err) {
const reason = err instanceof Error ? extractServerErrorDetail(err.message) : null;
new Notice(reason ? MESSAGES.ERROR_DELETE_DOCUMENTS_REASON(reason) : MESSAGES.ERROR_DELETE_DOCUMENTS);
}
}
}
|