diff --git a/src/app/(dashboard)/settings/page.tsx b/src/app/(dashboard)/settings/page.tsx index 280c436..e288523 100644 --- a/src/app/(dashboard)/settings/page.tsx +++ b/src/app/(dashboard)/settings/page.tsx @@ -5,7 +5,7 @@ import { Save, Eye, EyeOff, CheckCircle, AlertCircle, Loader2, RefreshCw, Sun, M import { useTheme } from "next-themes"; import { useGridStore } from "@/features/grid/store/use-grid-store"; import { useDbSettingsStore } from "@/features/settings/store/use-db-settings-store"; -import { testDatabaseConnection, saveDatabaseSettings, getSavedDatabaseConfig } from "@/features/settings/actions"; +import { testDatabaseConnection, saveDatabaseSettings, getSavedDatabaseConfig, saveQlikSettings, testQlikConnection } from "@/features/settings/actions"; import { useEffect } from "react"; import { UserManagement } from "@/features/admin/components/user-management"; @@ -106,6 +106,82 @@ function FfApiStatusSection() { ); } +function QlikSettingsSection() { + const [host, setHost] = useState(""); + const [user, setUser] = useState(""); + const [password, setPassword] = useState(""); + const [showPwd, setShowPwd] = useState(false); + const [saving, setSaving] = useState(false); + const [testing, setTesting] = useState(false); + const [status, setStatus] = useState<{ type: "ok" | "err"; msg: string } | null>(null); + + useEffect(() => { + getSavedDatabaseConfig().then((c) => { + if (!c) return; + setHost(c.qlikHost ?? ""); + setUser(c.qlikUser ?? ""); + setPassword(c.qlikPassword ?? ""); + }); + }, []); + + const handleSave = async () => { + setSaving(true); + setStatus(null); + const res = await saveQlikSettings(host.trim(), user.trim(), password); + setSaving(false); + setStatus(res.success ? { type: "ok", msg: "Réglages Qlik enregistrés" } : { type: "err", msg: res.error || "Erreur" }); + }; + + const handleTest = async () => { + setTesting(true); + setStatus(null); + const res = await testQlikConnection(host.trim(), user.trim(), password); + setTesting(false); + setStatus(res.success ? { type: "ok", msg: "Connexion Qlik OK" } : { type: "err", msg: res.error || "Échec connexion" }); + }; + + return ( +
+ + setHost(e.target.value)} className="apple-input font-mono" /> + + + setUser(e.target.value)} className="apple-input font-mono" /> + + +
+ setPassword(e.target.value)} className="apple-input font-mono pr-10" /> + +
+
+ {status && ( +
+ {status.type === "ok" ? : } + {status.msg} +
+ )} +
+ + +
+
+ ); +} + export default function SettingsPage() { const { resolvedTheme, setTheme } = useTheme(); const isDark = resolvedTheme === "dark"; @@ -336,6 +412,8 @@ export default function SettingsPage() { {/* API FF Nancy */} + + {/* AI Provider selector */}
diff --git a/src/features/settings/actions.ts b/src/features/settings/actions.ts index e530a8f..3fa513b 100644 --- a/src/features/settings/actions.ts +++ b/src/features/settings/actions.ts @@ -14,6 +14,20 @@ export interface DbConfig { aiProvider?: "openrouter" | "google"; googleAiKey?: string; googleAiModel?: string; + /** Qlik Sense — données réseau */ + qlikHost?: string; + qlikUser?: string; + qlikPassword?: string; +} + +/** Lit la config existante (ou {} si absente). */ +async function readConfig(): Promise> { + try { + const data = await fs.readFile(CONFIG_FILE, "utf-8"); + return JSON.parse(data); + } catch { + return {}; + } } export async function testDatabaseConnection(url: string) { @@ -46,7 +60,9 @@ export async function saveDatabaseSettings( googleAiModel?: string, ) { try { - const config: DbConfig = { url, openRouterKey, openRouterModel, aiProvider, googleAiKey, googleAiModel }; + // Merge avec l'existant pour préserver les autres réglages (ex: Qlik) + const existing = await readConfig(); + const config: DbConfig = { ...existing, url, openRouterKey, openRouterModel, aiProvider, googleAiKey, googleAiModel }; // S'assurer que le dossier data existe await fs.mkdir(DATA_DIR, { recursive: true }); @@ -67,6 +83,34 @@ export async function saveDatabaseSettings( } } +export async function saveQlikSettings(qlikHost: string, qlikUser: string, qlikPassword: string) { + try { + const existing = await readConfig(); + const config = { ...existing, qlikHost, qlikUser, qlikPassword } as DbConfig; + await fs.mkdir(DATA_DIR, { recursive: true }); + await fs.writeFile(CONFIG_FILE, JSON.stringify(config, null, 2)); + console.log("[Settings] Qlik configuration saved."); + return { success: true }; + } catch (error: unknown) { + const msg = error instanceof Error ? error.message : String(error); + console.error("[Settings] Failed to save Qlik config:", msg); + return { success: false, error: msg }; + } +} + +export async function testQlikConnection(qlikHost: string, qlikUser: string, qlikPassword: string) { + try { + const { getQlikConfig, qlikNtlmSession } = await import("@/lib/qlik-client"); + const cfg = { ...getQlikConfig(), user: qlikUser, password: qlikPassword }; + if (qlikHost) cfg.host = qlikHost; + await qlikNtlmSession(cfg); + return { success: true }; + } catch (error: unknown) { + const msg = error instanceof Error ? error.message : String(error); + return { success: false, error: msg }; + } +} + export async function getSavedDatabaseConfig(): Promise { try { if (!(await fs.stat(CONFIG_FILE).catch(() => null))) { diff --git a/src/lib/qlik-client.ts b/src/lib/qlik-client.ts index e099dfc..fd74333 100644 --- a/src/lib/qlik-client.ts +++ b/src/lib/qlik-client.ts @@ -19,6 +19,19 @@ import httpntlm from "httpntlm"; import { WebSocket } from "ws"; import { randomBytes } from "node:crypto"; +import { readFileSync } from "node:fs"; +import { join } from "node:path"; + +/** Lit les réglages Qlik depuis data/.db-config.json (configurés dans Paramètres). */ +function readQlikFileConfig(): { qlikHost?: string; qlikUser?: string; qlikPassword?: string } { + try { + const raw = readFileSync(join(process.cwd(), "data", ".db-config.json"), "utf-8"); + const c = JSON.parse(raw); + return { qlikHost: c.qlikHost, qlikUser: c.qlikUser, qlikPassword: c.qlikPassword }; + } catch { + return {}; + } +} // --------------------------------------------------------------------------- // Config (env) — defauts issus de la discovery @@ -40,10 +53,12 @@ export interface QlikConfig { } export function getQlikConfig(): QlikConfig { + // Priorité : réglages UI (data/.db-config.json) > env > défaut + const f = readQlikFileConfig(); return { - host: process.env.QLIK_HOST ?? "reporting-magasins.lafoirfouille.fr", - user: process.env.QLIK_USER ?? "FFSCH", - password: process.env.QLIK_PWD ?? "", + host: f.qlikHost || process.env.QLIK_HOST || "reporting-magasins.lafoirfouille.fr", + user: f.qlikUser || process.env.QLIK_USER || "FFSCH", + password: f.qlikPassword || process.env.QLIK_PWD || "", domain: process.env.QLIK_DOMAIN ?? "", workstation: process.env.QLIK_WORKSTATION ?? "", appNetwork: process.env.QLIK_APP_NETWORK ?? "9872ee6e-d64a-4b43-984a-076bf1f7f647",