feat: integração Metaset BI via proxy interno
- Adiciona server/bi/metaset-proxy.ts para proxy do serviço Metaset - Registra proxy /metaset no servidor (setupMetasetProxy) - Atualiza página Metaset.tsx para usar proxy local /metaset - Remove referência externa bi.onboardbi.com.br - Agora usa serviço interno http://metaset:8100 - Mantém navegação suave com navbar sempre visível
This commit is contained in:
parent
bdb92c4135
commit
5554e9d613
|
|
@ -1,34 +1,52 @@
|
|||
import { useState } from "react";
|
||||
import { Loader2, AlertCircle, ExternalLink } from "lucide-react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { useState, useEffect } from "react";
|
||||
import { Loader2, AlertCircle } from "lucide-react";
|
||||
import { Alert, AlertDescription } from "@/components/ui/alert";
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
||||
export default function Metaset() {
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [hasError, setHasError] = useState(false);
|
||||
const [errorMessage, setErrorMessage] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
// Verificar se o Metaset está online
|
||||
fetch("/api/bi/metaset/health", { credentials: "include" })
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
if (!data.online) {
|
||||
setHasError(true);
|
||||
setErrorMessage("O Metaset está offline ou iniciando.");
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
setHasError(true);
|
||||
setErrorMessage("Não foi possível conectar ao Metaset.");
|
||||
})
|
||||
.finally(() => {
|
||||
setIsLoading(false);
|
||||
});
|
||||
}, []);
|
||||
|
||||
if (hasError) {
|
||||
return (
|
||||
<div className="h-[calc(100vh-40px)] w-full flex flex-col bg-background">
|
||||
{/* Header do módulo */}
|
||||
<div className="h-10 border-b flex items-center px-4 justify-between bg-muted/30">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="font-semibold text-sm">Metaset BI</span>
|
||||
</div>
|
||||
<Button variant="ghost" size="sm" asChild>
|
||||
<a
|
||||
href="https://bi.onboardbi.com.br/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="flex items-center gap-1"
|
||||
>
|
||||
<ExternalLink className="w-3 h-3" />
|
||||
Abrir em nova aba
|
||||
</a>
|
||||
<div className="h-[calc(100vh-40px)] w-full flex items-center justify-center p-4">
|
||||
<Alert variant="destructive" className="max-w-md">
|
||||
<AlertCircle className="h-4 w-4" />
|
||||
<AlertDescription>
|
||||
{errorMessage}
|
||||
<div className="mt-4">
|
||||
<Button onClick={() => window.location.reload()}>
|
||||
Tentar novamente
|
||||
</Button>
|
||||
</div>
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
{/* Container do iframe */}
|
||||
<div className="flex-1 relative">
|
||||
return (
|
||||
<div className="h-[calc(100vh-40px)] w-full relative">
|
||||
{isLoading && (
|
||||
<div className="absolute inset-0 flex items-center justify-center bg-background z-10">
|
||||
<div className="flex flex-col items-center gap-2">
|
||||
|
|
@ -37,41 +55,12 @@ export default function Metaset() {
|
|||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{hasError ? (
|
||||
<div className="absolute inset-0 flex items-center justify-center p-4">
|
||||
<Alert variant="destructive" className="max-w-md">
|
||||
<AlertCircle className="h-4 w-4" />
|
||||
<AlertDescription>
|
||||
Não foi possível carregar o Metaset. O site pode não permitir embed em iframe.
|
||||
<div className="mt-4">
|
||||
<Button asChild>
|
||||
<a
|
||||
href="https://bi.onboardbi.com.br/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Abrir Metaset em nova aba
|
||||
</a>
|
||||
</Button>
|
||||
</div>
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
</div>
|
||||
) : (
|
||||
<iframe
|
||||
src="https://bi.onboardbi.com.br/"
|
||||
src="/metaset"
|
||||
className="w-full h-full border-0"
|
||||
onLoad={() => setIsLoading(false)}
|
||||
onError={() => {
|
||||
setIsLoading(false);
|
||||
setHasError(true);
|
||||
}}
|
||||
sandbox="allow-scripts allow-same-origin allow-forms allow-popups"
|
||||
title="Metaset BI"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
import { Express, Response } from "express";
|
||||
import { createProxyMiddleware } from "http-proxy-middleware";
|
||||
|
||||
const METASET_HOST = process.env.METASET_HOST || "metaset";
|
||||
const METASET_PORT = parseInt(process.env.METASET_PORT || "8100", 10);
|
||||
const METASET_TIMEOUT = 60000;
|
||||
|
||||
export function setupMetasetProxy(app: Express): void {
|
||||
const target = `http://${METASET_HOST}:${METASET_PORT}`;
|
||||
|
||||
const metasetProxy = createProxyMiddleware({
|
||||
target,
|
||||
changeOrigin: true,
|
||||
timeout: METASET_TIMEOUT,
|
||||
proxyTimeout: METASET_TIMEOUT,
|
||||
pathRewrite: { "^/metaset": "" },
|
||||
on: {
|
||||
error: (err, _req, res) => {
|
||||
console.error("[Metaset Proxy] Error:", err.message);
|
||||
if (res && typeof (res as Response).status === "function") {
|
||||
(res as Response).status(502).json({
|
||||
error: "Metaset indisponível",
|
||||
message: "O Metaset BI está iniciando. Tente novamente em alguns segundos.",
|
||||
target,
|
||||
});
|
||||
}
|
||||
},
|
||||
proxyRes: (proxyRes) => {
|
||||
const location = proxyRes.headers["location"];
|
||||
if (location && typeof location === "string" && location.startsWith("/")) {
|
||||
proxyRes.headers["location"] = `/metaset${location}`;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
app.use("/metaset", metasetProxy);
|
||||
console.log(`[Metaset Proxy] Configurado -> /metaset/* => ${target}`);
|
||||
}
|
||||
|
|
@ -51,6 +51,7 @@ import governanceRoutes from "./governance/routes";
|
|||
import { setupPlusProxy } from "./plus/proxy";
|
||||
import { setupSupersetProxy } from "./superset/proxy";
|
||||
import { registerSupersetRoutes } from "./superset/routes";
|
||||
import { setupMetasetProxy } from "./bi/metaset-proxy";
|
||||
import { setupErpNextProxy } from "./erpnext/proxy";
|
||||
import { importErpNextRulesForTenant } from "./soe/erpnext-rule-importer";
|
||||
import { registerEngineRoomRoutes } from "./engine-room/routes";
|
||||
|
|
@ -89,6 +90,9 @@ export async function registerRoutes(
|
|||
setupSupersetProxy(app);
|
||||
registerSupersetRoutes(app);
|
||||
|
||||
// MetaSet - BI alternativo (porta 8100)
|
||||
setupMetasetProxy(app);
|
||||
|
||||
// ERPNext container proxy (ativo apenas em DOCKER_MODE ou ERPNEXT_PROXY_ENABLED=true)
|
||||
setupErpNextProxy(app);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue