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 { useState, useEffect } from "react";
|
||||||
import { Loader2, AlertCircle, ExternalLink } from "lucide-react";
|
import { Loader2, AlertCircle } from "lucide-react";
|
||||||
import { Button } from "@/components/ui/button";
|
|
||||||
import { Alert, AlertDescription } from "@/components/ui/alert";
|
import { Alert, AlertDescription } from "@/components/ui/alert";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
|
||||||
export default function Metaset() {
|
export default function Metaset() {
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
const [hasError, setHasError] = useState(false);
|
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 (
|
return (
|
||||||
<div className="h-[calc(100vh-40px)] w-full flex flex-col bg-background">
|
<div className="h-[calc(100vh-40px)] w-full flex items-center justify-center p-4">
|
||||||
{/* Header do módulo */}
|
<Alert variant="destructive" className="max-w-md">
|
||||||
<div className="h-10 border-b flex items-center px-4 justify-between bg-muted/30">
|
<AlertCircle className="h-4 w-4" />
|
||||||
<div className="flex items-center gap-2">
|
<AlertDescription>
|
||||||
<span className="font-semibold text-sm">Metaset BI</span>
|
{errorMessage}
|
||||||
</div>
|
<div className="mt-4">
|
||||||
<Button variant="ghost" size="sm" asChild>
|
<Button onClick={() => window.location.reload()}>
|
||||||
<a
|
Tentar novamente
|
||||||
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>
|
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
</AlertDescription>
|
||||||
|
</Alert>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
{/* Container do iframe */}
|
return (
|
||||||
<div className="flex-1 relative">
|
<div className="h-[calc(100vh-40px)] w-full relative">
|
||||||
{isLoading && (
|
{isLoading && (
|
||||||
<div className="absolute inset-0 flex items-center justify-center bg-background z-10">
|
<div className="absolute inset-0 flex items-center justify-center bg-background z-10">
|
||||||
<div className="flex flex-col items-center gap-2">
|
<div className="flex flex-col items-center gap-2">
|
||||||
|
|
@ -37,41 +55,12 @@ export default function Metaset() {
|
||||||
</div>
|
</div>
|
||||||
</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
|
<iframe
|
||||||
src="https://bi.onboardbi.com.br/"
|
src="/metaset"
|
||||||
className="w-full h-full border-0"
|
className="w-full h-full border-0"
|
||||||
onLoad={() => setIsLoading(false)}
|
onLoad={() => setIsLoading(false)}
|
||||||
onError={() => {
|
|
||||||
setIsLoading(false);
|
|
||||||
setHasError(true);
|
|
||||||
}}
|
|
||||||
sandbox="allow-scripts allow-same-origin allow-forms allow-popups"
|
|
||||||
title="Metaset BI"
|
title="Metaset BI"
|
||||||
/>
|
/>
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</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 { setupPlusProxy } from "./plus/proxy";
|
||||||
import { setupSupersetProxy } from "./superset/proxy";
|
import { setupSupersetProxy } from "./superset/proxy";
|
||||||
import { registerSupersetRoutes } from "./superset/routes";
|
import { registerSupersetRoutes } from "./superset/routes";
|
||||||
|
import { setupMetasetProxy } from "./bi/metaset-proxy";
|
||||||
import { setupErpNextProxy } from "./erpnext/proxy";
|
import { setupErpNextProxy } from "./erpnext/proxy";
|
||||||
import { importErpNextRulesForTenant } from "./soe/erpnext-rule-importer";
|
import { importErpNextRulesForTenant } from "./soe/erpnext-rule-importer";
|
||||||
import { registerEngineRoomRoutes } from "./engine-room/routes";
|
import { registerEngineRoomRoutes } from "./engine-room/routes";
|
||||||
|
|
@ -89,6 +90,9 @@ export async function registerRoutes(
|
||||||
setupSupersetProxy(app);
|
setupSupersetProxy(app);
|
||||||
registerSupersetRoutes(app);
|
registerSupersetRoutes(app);
|
||||||
|
|
||||||
|
// MetaSet - BI alternativo (porta 8100)
|
||||||
|
setupMetasetProxy(app);
|
||||||
|
|
||||||
// ERPNext container proxy (ativo apenas em DOCKER_MODE ou ERPNEXT_PROXY_ENABLED=true)
|
// ERPNext container proxy (ativo apenas em DOCKER_MODE ou ERPNEXT_PROXY_ENABLED=true)
|
||||||
setupErpNextProxy(app);
|
setupErpNextProxy(app);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue