From 011a867aac7d45e1060fd52ceaedf6e312ea0def Mon Sep 17 00:00:00 2001 From: killer-cf Date: Thu, 18 Dec 2025 15:52:57 -0300 Subject: [PATCH 1/3] refactor: update fluxo instance management by enhancing the creation modal and improving the sidebar navigation structure, ensuring better user experience and code maintainability --- apps/web/src/lib/components/Sidebar.svelte | 3 +- .../routes/(dashboard)/fluxos/+page.svelte | 532 ++++------ .../fluxos/[id]-fluxo/+page.svelte | 947 ------------------ .../fluxos/instancias/+page.svelte | 410 -------- .../[id]}/+page.server.ts | 0 .../instancias}/[id]/+page.svelte | 6 +- .../{instancias => templates}/+page.server.ts | 0 .../(dashboard)/fluxos/templates/+page.svelte | 514 ++++++++++ .../(dashboard)/licitacoes/+page.svelte | 4 +- .../licitacoes/fluxos/+page.svelte | 402 -------- .../licitacoes/fluxos/[id]/+page.server.ts | 3 - 11 files changed, 736 insertions(+), 2085 deletions(-) delete mode 100644 apps/web/src/routes/(dashboard)/fluxos/[id]-fluxo/+page.svelte delete mode 100644 apps/web/src/routes/(dashboard)/fluxos/instancias/+page.svelte rename apps/web/src/routes/(dashboard)/fluxos/{[id]-fluxo => instancias/[id]}/+page.server.ts (100%) rename apps/web/src/routes/(dashboard)/{licitacoes/fluxos => fluxos/instancias}/[id]/+page.svelte (99%) rename apps/web/src/routes/(dashboard)/fluxos/{instancias => templates}/+page.server.ts (100%) create mode 100644 apps/web/src/routes/(dashboard)/fluxos/templates/+page.svelte delete mode 100644 apps/web/src/routes/(dashboard)/licitacoes/fluxos/+page.svelte delete mode 100644 apps/web/src/routes/(dashboard)/licitacoes/fluxos/[id]/+page.server.ts diff --git a/apps/web/src/lib/components/Sidebar.svelte b/apps/web/src/lib/components/Sidebar.svelte index 45c0c96..573f7ac 100644 --- a/apps/web/src/lib/components/Sidebar.svelte +++ b/apps/web/src/lib/components/Sidebar.svelte @@ -174,7 +174,8 @@ { label: 'Meus Processos', link: '/fluxos', - permission: { recurso: 'fluxos_instancias', acao: 'listar' } + permission: { recurso: 'fluxos_instancias', acao: 'listar' }, + exact: true }, { label: 'Modelos de Fluxo', diff --git a/apps/web/src/routes/(dashboard)/fluxos/+page.svelte b/apps/web/src/routes/(dashboard)/fluxos/+page.svelte index 41b48a0..861c710 100644 --- a/apps/web/src/routes/(dashboard)/fluxos/+page.svelte +++ b/apps/web/src/routes/(dashboard)/fluxos/+page.svelte @@ -3,50 +3,52 @@ import type { Id } from '@sgse-app/backend/convex/_generated/dataModel'; import { useConvexClient, useQuery } from 'convex-svelte'; import { goto } from '$app/navigation'; + import { resolve } from '$app/paths'; const client = useConvexClient(); - // Estado do filtro - let statusFilter = $state<'draft' | 'published' | 'archived' | undefined>(undefined); + // Estado dos filtros + let statusFilter = $state<'active' | 'completed' | 'cancelled' | undefined>(undefined); - // Query de templates - const templatesQuery = useQuery(api.flows.listTemplates, () => + // Query de instâncias + const instancesQuery = useQuery(api.flows.listInstances, () => statusFilter ? { status: statusFilter } : {} ); + // Query de templates publicados (para o modal de criação) + const publishedTemplatesQuery = useQuery(api.flows.listTemplates, { + status: 'published' + }); + // Modal de criação let showCreateModal = $state(false); - let newTemplateName = $state(''); - let newTemplateDescription = $state(''); + let selectedTemplateId = $state | ''>(''); + let contratoId = $state | ''>(''); + let managerId = $state | ''>(''); let isCreating = $state(false); let createError = $state(null); - // Modal de confirmação de exclusão - let showDeleteModal = $state(false); - let templateToDelete = $state<{ - _id: Id<'flowTemplates'>; - name: string; - } | null>(null); - let isDeleting = $state(false); - let deleteError = $state(null); + // Query de usuários (para seleção de gerente) + const usuariosQuery = useQuery(api.usuarios.listar, {}); + + // Query de contratos (para seleção) + const contratosQuery = useQuery(api.contratos.listar, {}); function openCreateModal() { - newTemplateName = ''; - newTemplateDescription = ''; + selectedTemplateId = ''; + contratoId = ''; + managerId = ''; createError = null; showCreateModal = true; } function closeCreateModal() { showCreateModal = false; - newTemplateName = ''; - newTemplateDescription = ''; - createError = null; } async function handleCreate() { - if (!newTemplateName.trim()) { - createError = 'O nome é obrigatório'; + if (!selectedTemplateId || !managerId) { + createError = 'Template e gerente são obrigatórios'; return; } @@ -54,72 +56,28 @@ createError = null; try { - const templateId = await client.mutation(api.flows.createTemplate, { - name: newTemplateName.trim(), - description: newTemplateDescription.trim() || undefined + const instanceId = await client.mutation(api.flows.instantiateFlow, { + flowTemplateId: selectedTemplateId as Id<'flowTemplates'>, + contratoId: contratoId ? (contratoId as Id<'contratos'>) : undefined, + managerId: managerId as Id<'usuarios'> }); closeCreateModal(); - // Navegar para o editor - goto(`/fluxos/${templateId}/editor`); + goto(resolve(`/fluxos/instancias/${instanceId}`)); } catch (e) { - createError = e instanceof Error ? e.message : 'Erro ao criar template'; + createError = e instanceof Error ? e.message : 'Erro ao criar instância'; } finally { isCreating = false; } } - function openDeleteModal(template: { _id: Id<'flowTemplates'>; name: string }) { - templateToDelete = template; - deleteError = null; - showDeleteModal = true; - } - - function closeDeleteModal() { - showDeleteModal = false; - templateToDelete = null; - deleteError = null; - } - - async function handleDelete() { - if (!templateToDelete) return; - - isDeleting = true; - deleteError = null; - - try { - await client.mutation(api.flows.deleteTemplate, { - id: templateToDelete._id - }); - closeDeleteModal(); - } catch (e) { - deleteError = e instanceof Error ? e.message : 'Erro ao excluir template'; - } finally { - isDeleting = false; - } - } - - async function handleStatusChange( - templateId: Id<'flowTemplates'>, - newStatus: 'draft' | 'published' | 'archived' - ) { - try { - await client.mutation(api.flows.updateTemplate, { - id: templateId, - status: newStatus - }); - } catch (e) { - console.error('Erro ao atualizar status:', e); - } - } - - function getStatusBadge(status: 'draft' | 'published' | 'archived') { + function getStatusBadge(status: 'active' | 'completed' | 'cancelled') { switch (status) { - case 'draft': - return { class: 'badge-warning', label: 'Rascunho' }; - case 'published': - return { class: 'badge-success', label: 'Publicado' }; - case 'archived': - return { class: 'badge-neutral', label: 'Arquivado' }; + case 'active': + return { class: 'badge-info', label: 'Em Andamento' }; + case 'completed': + return { class: 'badge-success', label: 'Concluído' }; + case 'cancelled': + return { class: 'badge-error', label: 'Cancelado' }; } } @@ -127,43 +85,70 @@ return new Date(timestamp).toLocaleDateString('pt-BR', { day: '2-digit', month: '2-digit', - year: 'numeric' + year: 'numeric', + hour: '2-digit', + minute: '2-digit' }); } + + function getProgressPercentage(completed: number, total: number): number { + if (total === 0) return 0; + return Math.round((completed / total) * 100); + }
-
-
+
+
- - Gestão de Fluxos - +
+ + + Templates + + + Execução + +

- Templates de Fluxo + Instâncias de Fluxo

- Crie e gerencie templates de fluxo de trabalho. Templates definem os passos e - responsabilidades que serão instanciados para projetos ou contratos. + Acompanhe e gerencie as execuções de fluxos de trabalho. Visualize o progresso, documentos + e responsáveis de cada etapa.

-
- +
- {#if templatesQuery.isLoading} + {#if instancesQuery.isLoading}
- +
- {:else if !templatesQuery.data || templatesQuery.data.length === 0} + {:else if !instancesQuery.data || instancesQuery.data.length === 0}
-

Nenhum template encontrado

+

+ Nenhuma instância encontrada +

{statusFilter - ? 'Não há templates com este status.' - : 'Clique em "Novo Template" para criar o primeiro.'} + ? 'Não há instâncias com este status.' + : 'Clique em "Nova Instância" para iniciar um fluxo.'}

{:else} -
- {#each templatesQuery.data as template (template._id)} - {@const statusBadge = getStatusBadge(template.status)} -
-
-
-

{template.name}

- {statusBadge.label} -
- - {#if template.description} -

- {template.description} -

- {/if} - -
- - + + + + + + + + + + + + + {#each instancesQuery.data as instance (instance._id)} + {@const statusBadge = getStatusBadge(instance.status)} + {@const progressPercent = getProgressPercentage( + instance.progress.completed, + instance.progress.total + )} + + + + + + + + + + {/each} + +
TemplateContratoGerenteProgressoStatusIniciado emAções
+
{instance.templateName ?? 'Template desconhecido'}
+
+ {#if instance.contratoId} + {instance.contratoId} + {:else} + - + {/if} + {instance.managerName ?? '-'} +
+ + + {instance.progress.completed}/{instance.progress.total} + +
+
+ {statusBadge.label} + {formatDate(instance.startedAt)} + - - - {template.stepsCount} passos - - - - {formatDate(template.createdAt)} - - - - - - - {/each} + Ver + +
{/if}
- - -
- - - Ver Fluxos de Trabalho - -
{#if showCreateModal}