feat: chat — boutons discrets sous l'image, image en onglet d'app, point de non-lus, notification OS, suppression annulable BUG-110
CI / lint (push) Successful in 2m50s
CI / security (push) Successful in 1m36s
CI / test (push) Successful in 4m28s
CI / build (push) Successful in 1m31s
CI / e2e (push) Successful in 17m30s

This commit is contained in:
2026-10-09 11:53:26 -04:00
parent 54caa48d1f
commit 4fb7c43e06
17 changed files with 420 additions and 46 deletions
+42 -1
View File
@@ -1,7 +1,7 @@
/* ObsiGate — UI module */
import { api, AuthManager, initLoginForm } from './auth.js';
import { state } from './state.js';
import { openFile, showWelcome, renderFile, el } from './viewer.js';
import { openFile, showWelcome, renderFile, renderImageViewer, el } from './viewer.js';
import { safeCreateIcons, getFileIcon, escapeHtml, detachInlineEditor } from './utils.js';
import { syncActiveFileTreeItem, refreshSidebarTreePreservingState } from './sidebar.js';
import { GraphViewManager } from './graph.js';
@@ -2122,6 +2122,28 @@ export const TabManager = {
this.activate(tabId);
},
/** #110 — ouvre une image jointe au chat dans un onglet, avec le même
* visualiseur que pour une image de vault (zoom/pan/plein écran). La pièce
* jointe est servie par ``/api/chat/attachment/`` : pas de couple
* (vault, path) derrière, donc onglet dédié qui rend le viewer directement
* depuis l'URL (aucun fetch de l'API fichiers).
* ponytail: l'onglet reste sur le TabManager singleton (les PaneTabManager
* n'ont pas cette branche) — suffisant pour un cas limite du mode split. */
async openChatImage(att) {
if (!att || !att.url) return;
const tabId = `chatimg::${att.url}`;
const name = att.name || "image";
const existing = this._tabs.find(t => t.id === tabId);
if (existing) {
this.activate(tabId);
return;
}
this._tabs.push({ id: tabId, vault: null, path: name, name, icon: "image", chatImage: true });
this._tabCache[tabId] = { chatImage: true, url: att.url, mime: att.mime, name, title: name };
this._renderTabs();
this.activate(tabId);
},
/** Open (or retarget) the navigation tab for a vault directory (#158).
* One navigation tab per vault: clicking another directory reuses it and
* updates its directory, so open file tabs are never displaced. */
@@ -2229,6 +2251,25 @@ export const TabManager = {
return;
}
// #110 — onglet image de chat : rendu direct depuis l'URL de la pièce
// jointe, sans passer par l'API fichiers (l'image n'est pas dans un vault).
if (cache.chatImage) {
state.currentVault = null;
state.currentPath = null;
const chatArea = document.getElementById("content-area");
if (!chatArea) return;
renderImageViewer(chatArea, {
vault: null,
path: cache.name,
title: cache.name,
url: cache.url,
image_mime: cache.mime,
});
const dash = document.getElementById("dashboard-home");
if (dash) dash.style.display = "none";
return;
}
// Update global state
state.currentVault = cache.vault;
state.currentPath = cache.path;