feat(makefile): update run command to exclude frontend and log files during reload
This commit is contained in:
48
frontend/.github/workflows/docker-image.yml
vendored
48
frontend/.github/workflows/docker-image.yml
vendored
@@ -1,48 +0,0 @@
|
||||
name: Build Docker image
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "*.*.*"
|
||||
|
||||
jobs:
|
||||
build_deploy:
|
||||
name: Build and Deploy
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: evoapicloud/evo-ai-frontend
|
||||
tags: type=semver,pattern=v{{version}}
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Build and push
|
||||
id: docker_build
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
|
||||
- name: Image digest
|
||||
run: echo ${{ steps.docker_build.outputs.digest }}
|
||||
@@ -1,48 +0,0 @@
|
||||
name: Build Docker image
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- develop
|
||||
|
||||
jobs:
|
||||
build_deploy:
|
||||
name: Build and Deploy
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: evoapicloud/evo-ai-frontend
|
||||
tags: homolog
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Build and push
|
||||
id: docker_build
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
|
||||
- name: Image digest
|
||||
run: echo ${{ steps.docker_build.outputs.digest }}
|
||||
@@ -1,48 +0,0 @@
|
||||
name: Build Docker image
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
build_deploy:
|
||||
name: Build and Deploy
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: evoapicloud/evo-ai-frontend
|
||||
tags: latest
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Build and push
|
||||
id: docker_build
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
|
||||
- name: Image digest
|
||||
run: echo ${{ steps.docker_build.outputs.digest }}
|
||||
@@ -215,7 +215,7 @@ export function AgentCard({
|
||||
return new Date(agent.created_at).toLocaleDateString();
|
||||
};
|
||||
|
||||
// Função para exportar o agente como JSON
|
||||
// Function to export the agent as JSON
|
||||
const handleExportAgent = () => {
|
||||
try {
|
||||
exportAsJson(
|
||||
@@ -231,18 +231,18 @@ export function AgentCard({
|
||||
}
|
||||
};
|
||||
|
||||
// Função para testar o agente A2A no laboratório
|
||||
// Function to test the A2A agent in the lab
|
||||
const handleTestA2A = () => {
|
||||
// Usar a URL do agent card como URL base para testes A2A
|
||||
// Use the agent card URL as base for A2A tests
|
||||
const agentUrl = agent.agent_card_url?.replace(
|
||||
"/.well-known/agent.json",
|
||||
""
|
||||
);
|
||||
|
||||
// Usar a API key diretamente do config do agente
|
||||
// Use the API key directly from the agent config
|
||||
const apiKey = agent.config?.api_key;
|
||||
|
||||
// Construir a URL com parâmetros para o laboratório de testes
|
||||
// Build the URL with parameters for the lab tests
|
||||
const params = new URLSearchParams();
|
||||
|
||||
if (agentUrl) {
|
||||
@@ -253,7 +253,7 @@ export function AgentCard({
|
||||
params.set("api_key", apiKey);
|
||||
}
|
||||
|
||||
// Redirecionar para o laboratório de testes na aba "lab"
|
||||
// Redirect to the lab tests in the "lab" tab
|
||||
const testUrl = `/documentation?${params.toString()}#lab`;
|
||||
|
||||
router.push(testUrl);
|
||||
|
||||
@@ -440,15 +440,15 @@ export default function AgentsPage() {
|
||||
setEditingAgent(null);
|
||||
};
|
||||
|
||||
// Função para exportar todos os agentes como JSON
|
||||
// Function to export all agents as JSON
|
||||
const handleExportAllAgents = () => {
|
||||
try {
|
||||
// Criar nome do arquivo com data atual
|
||||
// Create file name with current date
|
||||
const date = new Date();
|
||||
const formattedDate = `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')}`;
|
||||
const filename = `agents-export-${formattedDate}`;
|
||||
|
||||
// Usar a função utilitária para exportar
|
||||
// Use the utility function to export
|
||||
// Pass agents both as the data and as allAgents parameter to properly resolve references
|
||||
const result = exportAsJson({ agents: filteredAgents }, filename, true, agents);
|
||||
|
||||
|
||||
@@ -189,12 +189,12 @@ const Canva = forwardRef(({ agent }: { agent: Agent | null }, ref) => {
|
||||
setActiveExecutionNodeId,
|
||||
}));
|
||||
|
||||
// Effect para limpar o nó ativo após um timeout
|
||||
// Effect to clear the active node after a timeout
|
||||
useEffect(() => {
|
||||
if (activeExecutionNodeId) {
|
||||
const timer = setTimeout(() => {
|
||||
setActiveExecutionNodeId(null);
|
||||
}, 5000); // Aumentar para 5 segundos para dar mais tempo de visualização
|
||||
}, 5000); // Increase to 5 seconds to give more time to visualize
|
||||
|
||||
return () => clearTimeout(timer);
|
||||
}
|
||||
@@ -218,13 +218,13 @@ const Canva = forwardRef(({ agent }: { agent: Agent | null }, ref) => {
|
||||
}
|
||||
}, [agent, setNodes, setEdges]);
|
||||
|
||||
// Atualizar os nós quando o nó ativo muda para adicionar classe visual
|
||||
// Update nodes when the active node changes to add visual class
|
||||
useEffect(() => {
|
||||
if (nodes.length > 0) {
|
||||
setNodes((nds: any) =>
|
||||
nds.map((node: any) => {
|
||||
if (node.id === activeExecutionNodeId) {
|
||||
// Adiciona uma classe para destacar o nó ativo
|
||||
// Add a class to highlight the active node
|
||||
return {
|
||||
...node,
|
||||
className: "active-execution-node",
|
||||
@@ -234,7 +234,7 @@ const Canva = forwardRef(({ agent }: { agent: Agent | null }, ref) => {
|
||||
},
|
||||
};
|
||||
} else {
|
||||
// Remove a classe de destaque
|
||||
// Remove the highlight class
|
||||
const { isExecuting, ...restData } = node.data || {};
|
||||
return {
|
||||
...node,
|
||||
|
||||
@@ -108,15 +108,15 @@ export function AgentForm({ selectedNode, handleUpdateNode, setEdges, setIsOpen,
|
||||
const [isTestModalOpen, setIsTestModalOpen] = useState(false);
|
||||
const [isEditMode, setIsEditMode] = useState(false);
|
||||
|
||||
// Acessar a referência do canvas a partir do localStorage
|
||||
// Access the canvas reference from localStorage
|
||||
const canvasRef = useRef<any>(null);
|
||||
|
||||
useEffect(() => {
|
||||
// Quando o componente é montado, verifica se há uma referência de canvas no contexto global
|
||||
// When the component is mounted, check if there is a canvas reference in the global context
|
||||
if (typeof window !== "undefined") {
|
||||
const workflowsPage = document.querySelector('[data-workflow-page="true"]');
|
||||
if (workflowsPage) {
|
||||
// Se estamos na página de workflows, tentamos acessar a ref do canvas
|
||||
// If we are on the workflows page, try to access the canvas ref
|
||||
const canvasElement = workflowsPage.querySelector('[data-canvas-ref="true"]');
|
||||
if (canvasElement && (canvasElement as any).__reactRef) {
|
||||
canvasRef.current = (canvasElement as any).__reactRef.current;
|
||||
|
||||
@@ -89,8 +89,8 @@ export function AgentTestChatModal({ open, onOpenChange, agent, canvasRef }: Age
|
||||
const onEvent = useCallback((event: any) => {
|
||||
setMessages((prev) => [...prev, event]);
|
||||
|
||||
// Verificar se a mensagem vem de um nó de workflow e destacar o nó
|
||||
// somente se o canvasRef estiver disponível (chamado do Test Workflow na página principal)
|
||||
// Check if the message comes from a workflow node and highlight the node
|
||||
// only if the canvasRef is available (called from Test Workflow on the main page)
|
||||
if (event.author && event.author.startsWith('workflow-node:') && canvasRef?.current) {
|
||||
const nodeId = event.author.split(':')[1];
|
||||
canvasRef.current.setActiveExecutionNodeId(nodeId);
|
||||
@@ -139,7 +139,7 @@ export function AgentTestChatModal({ open, onOpenChange, agent, canvasRef }: Age
|
||||
setExternalId(generateExternalId());
|
||||
setIsInitializing(true);
|
||||
|
||||
// Breve delay para mostrar o status de inicialização
|
||||
// Short delay to show the initialization status
|
||||
const timer = setTimeout(() => {
|
||||
setIsInitializing(false);
|
||||
}, 1200);
|
||||
|
||||
@@ -223,7 +223,7 @@ function MessageForm({
|
||||
</SelectTrigger>
|
||||
<SelectContent className="bg-neutral-800 border-neutral-700 text-neutral-200">
|
||||
<SelectItem value="text">Text</SelectItem>
|
||||
{/* Outras opções podem ser habilitadas no futuro */}
|
||||
{/* Other options can be enabled in the future */}
|
||||
{/* <SelectItem value="image">Image</SelectItem>
|
||||
<SelectItem value="file">File</SelectItem>
|
||||
<SelectItem value="video">Video</SelectItem> */}
|
||||
|
||||
@@ -185,7 +185,7 @@ function WorkflowsContent() {
|
||||
open={isTestModalOpen}
|
||||
onOpenChange={setIsTestModalOpen}
|
||||
agent={agent}
|
||||
canvasRef={canvaRef} // Passamos a referência do canvas para permitir a visualização dos nós em execução
|
||||
canvasRef={canvaRef} // Pass the canvas reference to allow visualization of running nodes
|
||||
/>
|
||||
)}
|
||||
|
||||
|
||||
@@ -140,7 +140,7 @@ export function AgentInfoDialog({
|
||||
}
|
||||
};
|
||||
|
||||
// Função para exportar o agente como JSON
|
||||
// Function to export the agent as JSON
|
||||
const handleExportAgent = async () => {
|
||||
if (!agent) return;
|
||||
|
||||
|
||||
@@ -60,9 +60,9 @@ export function ChatInput({
|
||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
||||
|
||||
// Autofocus no textarea quando o componente for montado
|
||||
// Autofocus the textarea when the component is mounted
|
||||
React.useEffect(() => {
|
||||
// Pequeno timeout para garantir que o foco seja aplicado após a renderização completa
|
||||
// Small timeout to ensure focus is applied after the complete rendering
|
||||
if (autoFocus) {
|
||||
const timer = setTimeout(() => {
|
||||
if (textareaRef.current && !isLoading) {
|
||||
@@ -87,7 +87,7 @@ export function ChatInput({
|
||||
|
||||
setTimeout(() => {
|
||||
setResetFileUpload(false);
|
||||
// Mantém o foco no textarea após enviar a mensagem
|
||||
// Keep the focus on the textarea after sending the message
|
||||
if (autoFocus && textareaRef.current) {
|
||||
textareaRef.current.focus();
|
||||
}
|
||||
|
||||
@@ -49,6 +49,11 @@ interface LabSectionProps {
|
||||
setTaskId: (id: string) => void;
|
||||
callId: string;
|
||||
setCallId: (id: string) => void;
|
||||
a2aMethod: string;
|
||||
setA2aMethod: (method: string) => void;
|
||||
authMethod: string;
|
||||
setAuthMethod: (method: string) => void;
|
||||
generateNewIds: () => void;
|
||||
sendRequest: () => Promise<void>;
|
||||
sendStreamRequestWithEventSource: () => Promise<void>;
|
||||
isLoading: boolean;
|
||||
@@ -76,6 +81,11 @@ export function LabSection({
|
||||
setTaskId,
|
||||
callId,
|
||||
setCallId,
|
||||
a2aMethod,
|
||||
setA2aMethod,
|
||||
authMethod,
|
||||
setAuthMethod,
|
||||
generateNewIds,
|
||||
sendRequest,
|
||||
sendStreamRequestWithEventSource,
|
||||
isLoading,
|
||||
@@ -125,6 +135,11 @@ export function LabSection({
|
||||
setTaskId={setTaskId}
|
||||
callId={callId}
|
||||
setCallId={setCallId}
|
||||
a2aMethod={a2aMethod}
|
||||
setA2aMethod={setA2aMethod}
|
||||
authMethod={authMethod}
|
||||
setAuthMethod={setAuthMethod}
|
||||
generateNewIds={generateNewIds}
|
||||
sendRequest={sendRequest}
|
||||
isLoading={isLoading}
|
||||
/>
|
||||
@@ -144,6 +159,7 @@ export function LabSection({
|
||||
setTaskId={setTaskId}
|
||||
callId={callId}
|
||||
setCallId={setCallId}
|
||||
authMethod={authMethod}
|
||||
sendStreamRequest={sendStreamRequestWithEventSource}
|
||||
isStreaming={isStreaming}
|
||||
streamResponse={streamResponse}
|
||||
|
||||
@@ -851,12 +851,12 @@ function DocumentationContent() {
|
||||
body: JSON.stringify(streamRpcRequest),
|
||||
});
|
||||
|
||||
// Verificar o content-type da resposta
|
||||
// Verify the content-type of the response
|
||||
const contentType = initialResponse.headers.get("Content-Type");
|
||||
addDebugLog(`Response content type: ${contentType || "not specified"}`);
|
||||
|
||||
if (contentType && contentType.includes("text/event-stream")) {
|
||||
// É uma resposta SSE (Server-Sent Events)
|
||||
// It's an SSE (Server-Sent Events) response
|
||||
addDebugLog("Detected SSE response, processing stream directly");
|
||||
processEventStream(initialResponse);
|
||||
return;
|
||||
@@ -877,10 +877,10 @@ function DocumentationContent() {
|
||||
try {
|
||||
const responseText = await initialResponse.text();
|
||||
|
||||
// Verificar se a resposta começa com "data:", o que indica um SSE
|
||||
// Verify if the response starts with "data:", which indicates an SSE
|
||||
if (responseText.trim().startsWith("data:")) {
|
||||
addDebugLog("Response has SSE format but wrong content-type");
|
||||
// Criar uma resposta sintética para processar como stream
|
||||
// Create a synthetic response to process as stream
|
||||
const syntheticResponse = new Response(responseText, {
|
||||
headers: {
|
||||
"Content-Type": "text/event-stream",
|
||||
@@ -890,7 +890,7 @@ function DocumentationContent() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Tentar processar como JSON
|
||||
// Try to process as JSON
|
||||
const initialData = JSON.parse(responseText);
|
||||
addDebugLog("Initial stream response: " + JSON.stringify(initialData));
|
||||
|
||||
@@ -913,7 +913,7 @@ function DocumentationContent() {
|
||||
} catch (parseError) {
|
||||
addDebugLog(`Error parsing response: ${parseError}`);
|
||||
|
||||
// Se não conseguimos processar como JSON ou SSE, mostrar o erro
|
||||
// If we can't process as JSON or SSE, show the error
|
||||
setStreamResponse(
|
||||
`Error: Unable to process response: ${parseError instanceof Error ? parseError.message : String(parseError)}`
|
||||
);
|
||||
|
||||
@@ -71,7 +71,6 @@
|
||||
"cmdk": "1.0.4",
|
||||
"date-fns": "2.28.0",
|
||||
"embla-carousel-react": "8.5.1",
|
||||
"evo-ai-frontend": "file:",
|
||||
"input-otp": "1.4.1",
|
||||
"lucide-react": "^0.454.0",
|
||||
"next": "15.2.4",
|
||||
|
||||
Reference in New Issue
Block a user