mirror of
https://github.com/core-hn/pseudobsidian-ization.git
synced 2026-07-22 06:57:06 +00:00
feat: dictionaries tab — list, entry count, import, delete
This commit is contained in:
parent
446c867e17
commit
631803f8f4
3 changed files with 187 additions and 16 deletions
91
main.js
91
main.js
|
|
@ -32598,7 +32598,7 @@ var PseudonymizationView = class extends import_obsidian7.ItemView {
|
|||
else if (tab === "mappings")
|
||||
await this.renderMappingsTab(pane);
|
||||
else if (tab === "dictionaries")
|
||||
this.renderDictionariesTab(pane);
|
||||
await this.renderDictionariesTab(pane);
|
||||
else if (tab === "ner")
|
||||
await this.renderNerTab(pane);
|
||||
else
|
||||
|
|
@ -32893,15 +32893,90 @@ var PseudonymizationView = class extends import_obsidian7.ItemView {
|
|||
}
|
||||
}
|
||||
// ---- Onglet Dictionnaires --------------------------------------
|
||||
renderDictionariesTab(el) {
|
||||
el.createEl("p", {
|
||||
text: "La gestion avanc\xE9e des dictionnaires (d\xE9tection NER, listes de lieux et d'institutions) sera disponible en Phase 9.",
|
||||
cls: "pseudobs-view-hint"
|
||||
async renderDictionariesTab(el) {
|
||||
const toolbar = el.createDiv("pseudobs-view-toolbar");
|
||||
const importBtn = toolbar.createEl("button", {
|
||||
text: "Importer un dictionnaire (.dict.json)",
|
||||
cls: "pseudobs-view-add-btn"
|
||||
});
|
||||
el.createEl("p", {
|
||||
text: "Utilisez l'outil Coulmont via le menu contextuel (clic droit sur un pr\xE9nom dans la transcription).",
|
||||
cls: "pseudobs-view-hint"
|
||||
const statusEl = toolbar.createSpan({ cls: "pseudobs-view-dict-status" });
|
||||
importBtn.addEventListener("click", () => {
|
||||
const input = activeDocument.createElement("input");
|
||||
input.type = "file";
|
||||
input.accept = ".json";
|
||||
input.multiple = true;
|
||||
input.classList.add("pseudobs-hidden-input");
|
||||
activeDocument.body.appendChild(input);
|
||||
input.addEventListener("change", () => {
|
||||
void (async () => {
|
||||
const files2 = Array.from(input.files ?? []);
|
||||
input.remove();
|
||||
if (files2.length === 0)
|
||||
return;
|
||||
await this.plugin.ensureFolder(this.plugin.settings.dictionariesFolder);
|
||||
let ok = 0;
|
||||
for (const f of files2) {
|
||||
try {
|
||||
const text = await f.text();
|
||||
const parsed = JSON.parse(text);
|
||||
if (!parsed.entries || !Array.isArray(parsed.entries))
|
||||
throw new Error("Format invalide");
|
||||
const dest = `${this.plugin.settings.dictionariesFolder}/${f.name}`;
|
||||
const existing = this.app.vault.getAbstractFileByPath(dest);
|
||||
if (existing instanceof import_obsidian7.TFile) {
|
||||
await this.app.vault.modify(existing, text);
|
||||
} else {
|
||||
await this.app.vault.create(dest, text);
|
||||
}
|
||||
ok++;
|
||||
} catch {
|
||||
new import_obsidian7.Notice(`Format invalide : ${f.name}`);
|
||||
}
|
||||
}
|
||||
if (ok > 0)
|
||||
new import_obsidian7.Notice(`\u2713 ${ok} dictionnaire${ok > 1 ? "s" : ""} import\xE9${ok > 1 ? "s" : ""}`);
|
||||
await this.renderTab("dictionaries");
|
||||
})();
|
||||
});
|
||||
input.click();
|
||||
});
|
||||
const folder = this.app.vault.getAbstractFileByPath(this.plugin.settings.dictionariesFolder);
|
||||
const files = [];
|
||||
if (folder && "children" in folder) {
|
||||
for (const child of folder.children) {
|
||||
if (child instanceof import_obsidian7.TFile && child.name.endsWith(".json"))
|
||||
files.push(child);
|
||||
}
|
||||
}
|
||||
if (files.length === 0) {
|
||||
el.createEl("p", { text: "Aucun dictionnaire import\xE9.", cls: "pseudobs-view-hint" });
|
||||
return;
|
||||
}
|
||||
el.createEl("p", {
|
||||
text: `${files.length} dictionnaire${files.length > 1 ? "s" : ""} charg\xE9${files.length > 1 ? "s" : ""} :`,
|
||||
cls: "pseudobs-view-count"
|
||||
});
|
||||
const list = el.createEl("ul", { cls: "pseudobs-dict-list" });
|
||||
for (const f of files) {
|
||||
let entryCount = "?";
|
||||
try {
|
||||
const raw = await this.app.vault.read(f);
|
||||
const parsed = JSON.parse(raw);
|
||||
entryCount = String(parsed.entries?.length ?? 0);
|
||||
} catch {
|
||||
}
|
||||
const li = list.createEl("li", { cls: "pseudobs-dict-item" });
|
||||
li.createSpan({ text: f.basename, cls: "pseudobs-dict-name" });
|
||||
li.createSpan({ text: `${entryCount} entr\xE9es`, cls: "pseudobs-dict-count" });
|
||||
const removeBtn = li.createEl("button", { text: "\u2715", cls: "pseudobs-dict-remove" });
|
||||
removeBtn.title = "Supprimer ce dictionnaire";
|
||||
removeBtn.addEventListener("click", () => {
|
||||
void (async () => {
|
||||
await this.app.fileManager.trashFile(f);
|
||||
await this.renderTab("dictionaries");
|
||||
})();
|
||||
});
|
||||
}
|
||||
}
|
||||
// ---- Onglet Exports --------------------------------------------
|
||||
renderExportsTab(el) {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { ItemView, Notice, Setting, TFile, WorkspaceLeaf } from 'obsidian';
|
||||
import type { DictionaryFile } from '../types';
|
||||
import type PseudObsPlugin from '../main';
|
||||
import type { MappingRule, Occurrence } from '../types';
|
||||
import { scanOccurrences } from '../scanner/OccurrenceScanner';
|
||||
|
|
@ -124,7 +125,7 @@ export class PseudonymizationView extends ItemView {
|
|||
pane.empty();
|
||||
if (tab === 'occurrences') await this.renderOccurrencesTab(pane);
|
||||
else if (tab === 'mappings') await this.renderMappingsTab(pane);
|
||||
else if (tab === 'dictionaries') this.renderDictionariesTab(pane);
|
||||
else if (tab === 'dictionaries') await this.renderDictionariesTab(pane);
|
||||
else if (tab === 'ner') await this.renderNerTab(pane);
|
||||
else this.renderExportsTab(pane);
|
||||
}
|
||||
|
|
@ -457,15 +458,91 @@ export class PseudonymizationView extends ItemView {
|
|||
|
||||
// ---- Onglet Dictionnaires --------------------------------------
|
||||
|
||||
private renderDictionariesTab(el: HTMLElement): void {
|
||||
el.createEl('p', {
|
||||
text: 'La gestion avancée des dictionnaires (détection NER, listes de lieux et d\'institutions) sera disponible en Phase 9.',
|
||||
cls: 'pseudobs-view-hint',
|
||||
private async renderDictionariesTab(el: HTMLElement): Promise<void> {
|
||||
const toolbar = el.createDiv('pseudobs-view-toolbar');
|
||||
const importBtn = toolbar.createEl('button', {
|
||||
text: 'Importer un dictionnaire (.dict.json)',
|
||||
cls: 'pseudobs-view-add-btn',
|
||||
});
|
||||
el.createEl('p', {
|
||||
text: 'Utilisez l\'outil Coulmont via le menu contextuel (clic droit sur un prénom dans la transcription).',
|
||||
cls: 'pseudobs-view-hint',
|
||||
const statusEl = toolbar.createSpan({ cls: 'pseudobs-view-dict-status' });
|
||||
|
||||
importBtn.addEventListener('click', () => {
|
||||
const input = activeDocument.createElement('input');
|
||||
input.type = 'file';
|
||||
input.accept = '.json';
|
||||
input.multiple = true;
|
||||
input.classList.add('pseudobs-hidden-input');
|
||||
activeDocument.body.appendChild(input);
|
||||
input.addEventListener('change', () => { void (async () => {
|
||||
const files = Array.from(input.files ?? []);
|
||||
input.remove();
|
||||
if (files.length === 0) return;
|
||||
|
||||
await this.plugin.ensureFolder(this.plugin.settings.dictionariesFolder);
|
||||
let ok = 0;
|
||||
for (const f of files) {
|
||||
try {
|
||||
const text = await f.text();
|
||||
const parsed = JSON.parse(text) as DictionaryFile;
|
||||
if (!parsed.entries || !Array.isArray(parsed.entries)) throw new Error('Format invalide');
|
||||
const dest = `${this.plugin.settings.dictionariesFolder}/${f.name}`;
|
||||
const existing = this.app.vault.getAbstractFileByPath(dest);
|
||||
if (existing instanceof TFile) {
|
||||
await this.app.vault.modify(existing, text);
|
||||
} else {
|
||||
await this.app.vault.create(dest, text);
|
||||
}
|
||||
ok++;
|
||||
} catch {
|
||||
new Notice(`Format invalide : ${f.name}`);
|
||||
}
|
||||
}
|
||||
if (ok > 0) new Notice(`✓ ${ok} dictionnaire${ok > 1 ? 's' : ''} importé${ok > 1 ? 's' : ''}`);
|
||||
await this.renderTab('dictionaries');
|
||||
})(); });
|
||||
input.click();
|
||||
});
|
||||
|
||||
// Liste des dictionnaires présents dans le vault
|
||||
const folder = this.app.vault.getAbstractFileByPath(this.plugin.settings.dictionariesFolder);
|
||||
const files: TFile[] = [];
|
||||
if (folder && 'children' in folder) {
|
||||
for (const child of (folder as { children: unknown[] }).children) {
|
||||
if (child instanceof TFile && child.name.endsWith('.json')) files.push(child);
|
||||
}
|
||||
}
|
||||
|
||||
if (files.length === 0) {
|
||||
el.createEl('p', { text: 'Aucun dictionnaire importé.', cls: 'pseudobs-view-hint' });
|
||||
return;
|
||||
}
|
||||
|
||||
el.createEl('p', {
|
||||
text: `${files.length} dictionnaire${files.length > 1 ? 's' : ''} chargé${files.length > 1 ? 's' : ''} :`,
|
||||
cls: 'pseudobs-view-count',
|
||||
});
|
||||
|
||||
const list = el.createEl('ul', { cls: 'pseudobs-dict-list' });
|
||||
for (const f of files) {
|
||||
let entryCount = '?';
|
||||
try {
|
||||
const raw = await this.app.vault.read(f);
|
||||
const parsed = JSON.parse(raw) as DictionaryFile;
|
||||
entryCount = String(parsed.entries?.length ?? 0);
|
||||
} catch { /* fichier malformé */ }
|
||||
|
||||
const li = list.createEl('li', { cls: 'pseudobs-dict-item' });
|
||||
li.createSpan({ text: f.basename, cls: 'pseudobs-dict-name' });
|
||||
li.createSpan({ text: `${entryCount} entrées`, cls: 'pseudobs-dict-count' });
|
||||
const removeBtn = li.createEl('button', { text: '✕', cls: 'pseudobs-dict-remove' });
|
||||
removeBtn.title = 'Supprimer ce dictionnaire';
|
||||
removeBtn.addEventListener('click', () => { void (async () => {
|
||||
await this.app.fileManager.trashFile(f);
|
||||
await this.renderTab('dictionaries');
|
||||
})(); });
|
||||
}
|
||||
|
||||
void statusEl;
|
||||
}
|
||||
|
||||
// ---- Onglet Exports --------------------------------------------
|
||||
|
|
|
|||
19
styles.css
19
styles.css
|
|
@ -580,3 +580,22 @@
|
|||
.pseudobs-view-add-btn::before { content: '+ '; }
|
||||
.pseudobs-btn-saved::before { content: '✓ '; color: var(--color-green); }
|
||||
.pseudobs-ner-reset-btn { margin-left: 8px; }
|
||||
|
||||
/* Onglet Dictionnaires — panneau latéral */
|
||||
.pseudobs-dict-list { list-style: none; padding: 0; margin: 6px 0; }
|
||||
.pseudobs-dict-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 5px 6px;
|
||||
border-radius: 4px;
|
||||
font-size: 0.85em;
|
||||
}
|
||||
.pseudobs-dict-item:hover { background: var(--background-secondary); }
|
||||
.pseudobs-dict-name { flex: 1; font-family: var(--font-monospace); }
|
||||
.pseudobs-dict-count { color: var(--text-muted); font-size: 0.8em; white-space: nowrap; }
|
||||
.pseudobs-dict-remove {
|
||||
background: none; border: none; cursor: pointer;
|
||||
color: var(--text-faint); padding: 0 4px;
|
||||
}
|
||||
.pseudobs-dict-remove:hover { color: var(--color-red); }
|
||||
|
|
|
|||
Loading…
Reference in a new issue