refactor: update fluxo instance management by enhancing the creation modal and improving the sidebar navigation structure, ensuring better user experience and code maintainability
This commit is contained in:
@@ -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<Id<'flowTemplates'> | ''>('');
|
||||
let contratoId = $state<Id<'contratos'> | ''>('');
|
||||
let managerId = $state<Id<'usuarios'> | ''>('');
|
||||
let isCreating = $state(false);
|
||||
let createError = $state<string | null>(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<string | null>(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);
|
||||
}
|
||||
</script>
|
||||
|
||||
<main class="mx-auto w-full max-w-7xl space-y-8 px-4 py-10">
|
||||
<!-- Header -->
|
||||
<section
|
||||
class="border-secondary/25 from-secondary/10 via-base-100 to-primary/20 relative overflow-hidden rounded-3xl border bg-linear-to-br p-8 shadow-2xl"
|
||||
class="border-info/25 from-info/10 via-base-100 to-secondary/20 relative overflow-hidden rounded-3xl border bg-linear-to-br p-8 shadow-2xl"
|
||||
>
|
||||
<div class="bg-secondary/20 absolute top-10 -left-10 h-40 w-40 rounded-full blur-3xl"></div>
|
||||
<div class="bg-primary/20 absolute right-0 -bottom-16 h-56 w-56 rounded-full blur-3xl"></div>
|
||||
<div class="bg-info/20 absolute top-10 -left-10 h-40 w-40 rounded-full blur-3xl"></div>
|
||||
<div class="bg-secondary/20 absolute right-0 -bottom-16 h-56 w-56 rounded-full blur-3xl"></div>
|
||||
<div class="relative z-10 flex flex-col gap-6 lg:flex-row lg:items-center lg:justify-between">
|
||||
<div class="max-w-3xl space-y-4">
|
||||
<span
|
||||
class="border-secondary/40 bg-secondary/10 text-secondary inline-flex w-fit items-center gap-2 rounded-full border px-4 py-1 text-xs font-semibold tracking-[0.28em] uppercase"
|
||||
>
|
||||
Gestão de Fluxos
|
||||
</span>
|
||||
<div class="flex items-center gap-4">
|
||||
<a href={resolve('/fluxos/templates')} class="btn btn-ghost btn-sm">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-5 w-5"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M10 19l-7-7m0 0l7-7m-7 7h18"
|
||||
/>
|
||||
</svg>
|
||||
Templates
|
||||
</a>
|
||||
<span
|
||||
class="border-info/40 bg-info/10 text-info inline-flex w-fit items-center gap-2 rounded-full border px-4 py-1 text-xs font-semibold tracking-[0.28em] uppercase"
|
||||
>
|
||||
Execução
|
||||
</span>
|
||||
</div>
|
||||
<h1 class="text-base-content text-4xl leading-tight font-black sm:text-5xl">
|
||||
Templates de Fluxo
|
||||
Instâncias de Fluxo
|
||||
</h1>
|
||||
<p class="text-base-content/70 text-base leading-relaxed sm:text-lg">
|
||||
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.
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex flex-col gap-4 sm:flex-row sm:items-center">
|
||||
<!-- Filtro de status -->
|
||||
<select class="select select-bordered" bind:value={statusFilter}>
|
||||
<option value={undefined}>Todos os status</option>
|
||||
<option value="draft">Rascunho</option>
|
||||
<option value="published">Publicado</option>
|
||||
<option value="archived">Arquivado</option>
|
||||
<option value="active">Em Andamento</option>
|
||||
<option value="completed">Concluído</option>
|
||||
<option value="cancelled">Cancelado</option>
|
||||
</select>
|
||||
|
||||
<button class="btn btn-secondary shadow-lg" onclick={openCreateModal}>
|
||||
<button class="btn btn-info shadow-lg" onclick={openCreateModal}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-5 w-5"
|
||||
@@ -179,19 +164,19 @@
|
||||
d="M12 4v16m8-8H4"
|
||||
/>
|
||||
</svg>
|
||||
Novo Template
|
||||
Nova Instância
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Lista de Templates -->
|
||||
<!-- Lista de Instâncias -->
|
||||
<section class="bg-base-100 rounded-2xl border p-6 shadow-lg">
|
||||
{#if templatesQuery.isLoading}
|
||||
{#if instancesQuery.isLoading}
|
||||
<div class="flex items-center justify-center py-12">
|
||||
<span class="loading loading-spinner loading-lg text-secondary"></span>
|
||||
<span class="loading loading-spinner loading-lg text-info"></span>
|
||||
</div>
|
||||
{:else if !templatesQuery.data || templatesQuery.data.length === 0}
|
||||
{:else if !instancesQuery.data || instancesQuery.data.length === 0}
|
||||
<div class="flex flex-col items-center justify-center py-12 text-center">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@@ -205,77 +190,69 @@
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="1.5"
|
||||
d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-3 7h3m-3 4h3m-6-4h.01M9 16h.01"
|
||||
d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"
|
||||
/>
|
||||
</svg>
|
||||
<h3 class="text-base-content/70 mt-4 text-lg font-semibold">Nenhum template encontrado</h3>
|
||||
<h3 class="text-base-content/70 mt-4 text-lg font-semibold">
|
||||
Nenhuma instância encontrada
|
||||
</h3>
|
||||
<p class="text-base-content/50 mt-2">
|
||||
{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.'}
|
||||
</p>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
|
||||
{#each templatesQuery.data as template (template._id)}
|
||||
{@const statusBadge = getStatusBadge(template.status)}
|
||||
<article
|
||||
class="card bg-base-200/50 hover:bg-base-200 border transition-all duration-200 hover:shadow-md"
|
||||
>
|
||||
<div class="card-body">
|
||||
<div class="flex items-start justify-between gap-2">
|
||||
<h2 class="card-title text-lg">{template.name}</h2>
|
||||
<span class="badge {statusBadge.class}">{statusBadge.label}</span>
|
||||
</div>
|
||||
|
||||
{#if template.description}
|
||||
<p class="text-base-content/60 line-clamp-2 text-sm">
|
||||
{template.description}
|
||||
</p>
|
||||
{/if}
|
||||
|
||||
<div class="text-base-content/50 mt-2 flex flex-wrap gap-4 text-xs">
|
||||
<span class="flex items-center gap-1">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-4 w-4"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
aria-hidden="true"
|
||||
<div class="overflow-x-auto">
|
||||
<table class="table w-full">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Template</th>
|
||||
<th>Contrato</th>
|
||||
<th>Gerente</th>
|
||||
<th>Progresso</th>
|
||||
<th>Status</th>
|
||||
<th>Iniciado em</th>
|
||||
<th class="text-right">Ações</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each instancesQuery.data as instance (instance._id)}
|
||||
{@const statusBadge = getStatusBadge(instance.status)}
|
||||
{@const progressPercent = getProgressPercentage(
|
||||
instance.progress.completed,
|
||||
instance.progress.total
|
||||
)}
|
||||
<tr class="hover">
|
||||
<td>
|
||||
<div class="font-medium">{instance.templateName ?? 'Template desconhecido'}</div>
|
||||
</td>
|
||||
<td>
|
||||
{#if instance.contratoId}
|
||||
<span class="badge badge-outline badge-sm">{instance.contratoId}</span>
|
||||
{:else}
|
||||
<span class="text-base-content/40 text-sm">-</span>
|
||||
{/if}
|
||||
</td>
|
||||
<td class="text-base-content/70">{instance.managerName ?? '-'}</td>
|
||||
<td>
|
||||
<div class="flex items-center gap-2">
|
||||
<progress class="progress progress-info w-20" value={progressPercent} max="100"
|
||||
></progress>
|
||||
<span class="text-base-content/60 text-xs">
|
||||
{instance.progress.completed}/{instance.progress.total}
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge {statusBadge.class}">{statusBadge.label}</span>
|
||||
</td>
|
||||
<td class="text-base-content/60 text-sm">{formatDate(instance.startedAt)}</td>
|
||||
<td class="text-right">
|
||||
<a
|
||||
href={resolve(`/fluxos/instancias/${instance._id}`)}
|
||||
class="btn btn-ghost btn-sm"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"
|
||||
/>
|
||||
</svg>
|
||||
{template.stepsCount} passos
|
||||
</span>
|
||||
<span class="flex items-center gap-1">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-4 w-4"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"
|
||||
/>
|
||||
</svg>
|
||||
{formatDate(template.createdAt)}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="card-actions mt-4 justify-between">
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-ghost btn-sm" aria-label="Alterar status">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-4 w-4"
|
||||
@@ -288,97 +265,32 @@
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M12 5v.01M12 12v.01M12 19v.01M12 6a1 1 0 110-2 1 1 0 010 2zm0 7a1 1 0 110-2 1 1 0 010 2zm0 7a1 1 0 110-2 1 1 0 010 2z"
|
||||
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
|
||||
/>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
<ul
|
||||
class="dropdown-content menu bg-base-100 rounded-box z-10 w-52 p-2 shadow"
|
||||
role="menu"
|
||||
>
|
||||
{#if template.status !== 'draft'}
|
||||
<li>
|
||||
<button onclick={() => handleStatusChange(template._id, 'draft')}>
|
||||
Voltar para Rascunho
|
||||
</button>
|
||||
</li>
|
||||
{/if}
|
||||
{#if template.status !== 'published'}
|
||||
<li>
|
||||
<button onclick={() => handleStatusChange(template._id, 'published')}>
|
||||
Publicar
|
||||
</button>
|
||||
</li>
|
||||
{/if}
|
||||
{#if template.status !== 'archived'}
|
||||
<li>
|
||||
<button onclick={() => handleStatusChange(template._id, 'archived')}>
|
||||
Arquivar
|
||||
</button>
|
||||
</li>
|
||||
{/if}
|
||||
<li class="mt-2 border-t pt-2">
|
||||
<button class="text-error" onclick={() => openDeleteModal(template)}>
|
||||
Excluir
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<a href="/fluxos/{template._id}/editor" class="btn btn-secondary btn-sm">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-4 w-4"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"
|
||||
/>
|
||||
</svg>
|
||||
Editar
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
{/each}
|
||||
Ver
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{/if}
|
||||
</section>
|
||||
|
||||
<!-- Link para Instâncias -->
|
||||
<section class="flex justify-center">
|
||||
<a href="/licitacoes/fluxos" class="btn btn-outline btn-lg">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-5 w-5"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"
|
||||
/>
|
||||
</svg>
|
||||
Ver Fluxos de Trabalho
|
||||
</a>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<!-- Modal de Criação -->
|
||||
{#if showCreateModal}
|
||||
<div class="modal modal-open">
|
||||
<div class="modal-box">
|
||||
<h3 class="text-lg font-bold">Novo Template de Fluxo</h3>
|
||||
<div class="modal-box max-w-2xl">
|
||||
<h3 class="text-lg font-bold">Nova Instância de Fluxo</h3>
|
||||
|
||||
{#if createError}
|
||||
<div class="alert alert-error mt-4">
|
||||
@@ -408,41 +320,82 @@
|
||||
class="mt-4 space-y-4"
|
||||
>
|
||||
<div class="form-control">
|
||||
<label class="label" for="template-name">
|
||||
<span class="label-text">Nome do Template</span>
|
||||
<label class="label" for="template-select">
|
||||
<span class="label-text">Template de Fluxo</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="template-name"
|
||||
bind:value={newTemplateName}
|
||||
class="input input-bordered w-full"
|
||||
placeholder="Ex: Fluxo de Aprovação de Contrato"
|
||||
<select
|
||||
id="template-select"
|
||||
bind:value={selectedTemplateId}
|
||||
class="select select-bordered w-full"
|
||||
required
|
||||
/>
|
||||
>
|
||||
<option value="">Selecione um template</option>
|
||||
{#if publishedTemplatesQuery.data}
|
||||
{#each publishedTemplatesQuery.data as template (template._id)}
|
||||
<option value={template._id}>{template.name}</option>
|
||||
{/each}
|
||||
{/if}
|
||||
</select>
|
||||
<p class="label">
|
||||
<span class="label-text-alt text-base-content/60"
|
||||
>Apenas templates publicados podem ser instanciados</span
|
||||
>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="form-control">
|
||||
<label class="label" for="template-description">
|
||||
<span class="label-text">Descrição (opcional)</span>
|
||||
<label class="label" for="contrato-select">
|
||||
<span class="label-text">Contrato (Opcional)</span>
|
||||
</label>
|
||||
<textarea
|
||||
id="template-description"
|
||||
bind:value={newTemplateDescription}
|
||||
class="textarea textarea-bordered w-full"
|
||||
placeholder="Descreva o propósito deste fluxo..."
|
||||
rows="3"
|
||||
></textarea>
|
||||
<select
|
||||
id="contrato-select"
|
||||
bind:value={contratoId}
|
||||
class="select select-bordered w-full"
|
||||
>
|
||||
<option value="">Nenhum contrato</option>
|
||||
{#if contratosQuery.data}
|
||||
{#each contratosQuery.data as contrato (contrato._id)}
|
||||
<option value={contrato._id}>
|
||||
{contrato.numeroContrato}/{contrato.anoContrato}
|
||||
</option>
|
||||
{/each}
|
||||
{/if}
|
||||
</select>
|
||||
<p class="label">
|
||||
<span class="label-text-alt text-base-content/60"
|
||||
>Opcional: vincule este fluxo a um contrato específico</span
|
||||
>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="form-control">
|
||||
<label class="label" for="manager-select">
|
||||
<span class="label-text">Gerente Responsável</span>
|
||||
</label>
|
||||
<select
|
||||
id="manager-select"
|
||||
bind:value={managerId}
|
||||
class="select select-bordered w-full"
|
||||
required
|
||||
>
|
||||
<option value="">Selecione um gerente</option>
|
||||
{#if usuariosQuery.data}
|
||||
{#each usuariosQuery.data as usuario (usuario._id)}
|
||||
<option value={usuario._id}>{usuario.nome}</option>
|
||||
{/each}
|
||||
{/if}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="modal-action">
|
||||
<button type="button" class="btn" onclick={closeCreateModal} disabled={isCreating}>
|
||||
Cancelar
|
||||
</button>
|
||||
<button type="submit" class="btn btn-secondary" disabled={isCreating}>
|
||||
<button type="submit" class="btn btn-info" disabled={isCreating}>
|
||||
{#if isCreating}
|
||||
<span class="loading loading-spinner loading-sm"></span>
|
||||
{/if}
|
||||
Criar e Editar
|
||||
Iniciar Fluxo
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
@@ -455,56 +408,3 @@
|
||||
></button>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- Modal de Confirmação de Exclusão -->
|
||||
{#if showDeleteModal && templateToDelete}
|
||||
<div class="modal modal-open">
|
||||
<div class="modal-box">
|
||||
<h3 class="text-error text-lg font-bold">Confirmar Exclusão</h3>
|
||||
|
||||
{#if deleteError}
|
||||
<div class="alert alert-error mt-4">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-6 w-6 shrink-0 stroke-current"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
/>
|
||||
</svg>
|
||||
<span>{deleteError}</span>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<p class="py-4">
|
||||
Tem certeza que deseja excluir o template <strong>{templateToDelete.name}</strong>?
|
||||
</p>
|
||||
<p class="text-base-content/60 text-sm">
|
||||
Esta ação não pode ser desfeita. Templates com instâncias vinculadas não podem ser
|
||||
excluídos.
|
||||
</p>
|
||||
|
||||
<div class="modal-action">
|
||||
<button class="btn" onclick={closeDeleteModal} disabled={isDeleting}> Cancelar </button>
|
||||
<button class="btn btn-error" onclick={handleDelete} disabled={isDeleting}>
|
||||
{#if isDeleting}
|
||||
<span class="loading loading-spinner loading-sm"></span>
|
||||
{/if}
|
||||
Excluir
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
class="modal-backdrop"
|
||||
onclick={closeDeleteModal}
|
||||
aria-label="Fechar modal"
|
||||
></button>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
Reference in New Issue
Block a user