refactor: enhance chat components and improve user interaction
- Refactored Sidebar, ChatList, ChatWindow, and NewConversationModal components for better readability and maintainability. - Updated user data handling to utilize the latest API responses, ensuring accurate display of user statuses and notifications. - Improved modal interactions and user feedback mechanisms across chat components. - Cleaned up unused code and optimized state management for a smoother user experience.
This commit is contained in:
@@ -1,502 +1,481 @@
|
||||
<script lang="ts">
|
||||
import { useQuery, useConvexClient } from "convex-svelte";
|
||||
import { api } from "@sgse-app/backend/convex/_generated/api";
|
||||
import type { Id } from "@sgse-app/backend/convex/_generated/dataModel";
|
||||
import { useQuery, useConvexClient } from 'convex-svelte';
|
||||
import { api } from '@sgse-app/backend/convex/_generated/api';
|
||||
import type { Id } from '@sgse-app/backend/convex/_generated/dataModel';
|
||||
|
||||
let { onClose }: { onClose: () => void } = $props();
|
||||
let { onClose }: { onClose: () => void } = $props();
|
||||
|
||||
const client = useConvexClient();
|
||||
const alertasQuery = useQuery(api.monitoramento.listarAlertas, {});
|
||||
const alertas = $derived.by(() => {
|
||||
if (!alertasQuery) return [];
|
||||
// O useQuery pode retornar o array diretamente ou em .data
|
||||
if (Array.isArray(alertasQuery)) return alertasQuery;
|
||||
return alertasQuery.data ?? [];
|
||||
});
|
||||
const client = useConvexClient();
|
||||
const alertas = useQuery(api.monitoramento.listarAlertas, {});
|
||||
|
||||
// Estado para novo alerta
|
||||
let editingAlertId = $state<Id<"alertConfigurations"> | null>(null);
|
||||
let metricName = $state("cpuUsage");
|
||||
let threshold = $state(80);
|
||||
let operator = $state<">" | "<" | ">=" | "<=" | "==">(">");
|
||||
let enabled = $state(true);
|
||||
let notifyByEmail = $state(false);
|
||||
let notifyByChat = $state(true);
|
||||
let saving = $state(false);
|
||||
let showForm = $state(false);
|
||||
$inspect(alertas);
|
||||
|
||||
const metricOptions = [
|
||||
{ value: "cpuUsage", label: "Uso de CPU (%)" },
|
||||
{ value: "memoryUsage", label: "Uso de Memória (%)" },
|
||||
{ value: "networkLatency", label: "Latência de Rede (ms)" },
|
||||
{ value: "storageUsed", label: "Armazenamento Usado (%)" },
|
||||
{ value: "usuariosOnline", label: "Usuários Online" },
|
||||
{ value: "mensagensPorMinuto", label: "Mensagens por Minuto" },
|
||||
{ value: "tempoRespostaMedio", label: "Tempo de Resposta (ms)" },
|
||||
{ value: "errosCount", label: "Contagem de Erros" },
|
||||
];
|
||||
// Estado para novo alerta
|
||||
let editingAlertId = $state<Id<'alertConfigurations'> | null>(null);
|
||||
let metricName = $state('cpuUsage');
|
||||
let threshold = $state(80);
|
||||
let operator = $state<'>' | '<' | '>=' | '<=' | '=='>('>');
|
||||
let enabled = $state(true);
|
||||
let notifyByEmail = $state(false);
|
||||
let notifyByChat = $state(true);
|
||||
let saving = $state(false);
|
||||
let showForm = $state(false);
|
||||
|
||||
const operatorOptions = [
|
||||
{ value: ">", label: "Maior que (>)" },
|
||||
{ value: ">=", label: "Maior ou igual (≥)" },
|
||||
{ value: "<", label: "Menor que (<)" },
|
||||
{ value: "<=", label: "Menor ou igual (≤)" },
|
||||
{ value: "==", label: "Igual a (=)" },
|
||||
];
|
||||
const metricOptions = [
|
||||
{ value: 'cpuUsage', label: 'Uso de CPU (%)' },
|
||||
{ value: 'memoryUsage', label: 'Uso de Memória (%)' },
|
||||
{ value: 'networkLatency', label: 'Latência de Rede (ms)' },
|
||||
{ value: 'storageUsed', label: 'Armazenamento Usado (%)' },
|
||||
{ value: 'usuariosOnline', label: 'Usuários Online' },
|
||||
{ value: 'mensagensPorMinuto', label: 'Mensagens por Minuto' },
|
||||
{ value: 'tempoRespostaMedio', label: 'Tempo de Resposta (ms)' },
|
||||
{ value: 'errosCount', label: 'Contagem de Erros' }
|
||||
];
|
||||
|
||||
function resetForm() {
|
||||
editingAlertId = null;
|
||||
metricName = "cpuUsage";
|
||||
threshold = 80;
|
||||
operator = ">";
|
||||
enabled = true;
|
||||
notifyByEmail = false;
|
||||
notifyByChat = true;
|
||||
showForm = false;
|
||||
}
|
||||
const operatorOptions = [
|
||||
{ value: '>', label: 'Maior que (>)' },
|
||||
{ value: '>=', label: 'Maior ou igual (≥)' },
|
||||
{ value: '<', label: 'Menor que (<)' },
|
||||
{ value: '<=', label: 'Menor ou igual (≤)' },
|
||||
{ value: '==', label: 'Igual a (=)' }
|
||||
];
|
||||
|
||||
function editAlert(alert: any) {
|
||||
editingAlertId = alert._id;
|
||||
metricName = alert.metricName;
|
||||
threshold = alert.threshold;
|
||||
operator = alert.operator;
|
||||
enabled = alert.enabled;
|
||||
notifyByEmail = alert.notifyByEmail;
|
||||
notifyByChat = alert.notifyByChat;
|
||||
showForm = true;
|
||||
}
|
||||
function resetForm() {
|
||||
editingAlertId = null;
|
||||
metricName = 'cpuUsage';
|
||||
threshold = 80;
|
||||
operator = '>';
|
||||
enabled = true;
|
||||
notifyByEmail = false;
|
||||
notifyByChat = true;
|
||||
showForm = false;
|
||||
}
|
||||
|
||||
async function saveAlert() {
|
||||
saving = true;
|
||||
try {
|
||||
await client.mutation(api.monitoramento.configurarAlerta, {
|
||||
alertId: editingAlertId || undefined,
|
||||
metricName,
|
||||
threshold,
|
||||
operator,
|
||||
enabled,
|
||||
notifyByEmail,
|
||||
notifyByChat,
|
||||
});
|
||||
function editAlert(alert: any) {
|
||||
editingAlertId = alert._id;
|
||||
metricName = alert.metricName;
|
||||
threshold = alert.threshold;
|
||||
operator = alert.operator;
|
||||
enabled = alert.enabled;
|
||||
notifyByEmail = alert.notifyByEmail;
|
||||
notifyByChat = alert.notifyByChat;
|
||||
showForm = true;
|
||||
}
|
||||
|
||||
resetForm();
|
||||
} catch (error) {
|
||||
console.error("Erro ao salvar alerta:", error);
|
||||
alert("Erro ao salvar alerta. Tente novamente.");
|
||||
} finally {
|
||||
saving = false;
|
||||
}
|
||||
}
|
||||
async function saveAlert() {
|
||||
saving = true;
|
||||
try {
|
||||
await client.mutation(api.monitoramento.configurarAlerta, {
|
||||
alertId: editingAlertId || undefined,
|
||||
metricName,
|
||||
threshold,
|
||||
operator,
|
||||
enabled,
|
||||
notifyByEmail,
|
||||
notifyByChat
|
||||
});
|
||||
|
||||
async function deleteAlert(alertId: Id<"alertConfigurations">) {
|
||||
if (!confirm("Tem certeza que deseja deletar este alerta?")) return;
|
||||
resetForm();
|
||||
} catch (error) {
|
||||
console.error('Erro ao salvar alerta:', error);
|
||||
alert('Erro ao salvar alerta. Tente novamente.');
|
||||
} finally {
|
||||
saving = false;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
await client.mutation(api.monitoramento.deletarAlerta, { alertId });
|
||||
} catch (error) {
|
||||
console.error("Erro ao deletar alerta:", error);
|
||||
alert("Erro ao deletar alerta. Tente novamente.");
|
||||
}
|
||||
}
|
||||
async function deleteAlert(alertId: Id<'alertConfigurations'>) {
|
||||
if (!confirm('Tem certeza que deseja deletar este alerta?')) return;
|
||||
|
||||
function getMetricLabel(metricName: string): string {
|
||||
return (
|
||||
metricOptions.find((m) => m.value === metricName)?.label || metricName
|
||||
);
|
||||
}
|
||||
try {
|
||||
await client.mutation(api.monitoramento.deletarAlerta, { alertId });
|
||||
} catch (error) {
|
||||
console.error('Erro ao deletar alerta:', error);
|
||||
alert('Erro ao deletar alerta. Tente novamente.');
|
||||
}
|
||||
}
|
||||
|
||||
function getOperatorLabel(op: string): string {
|
||||
return operatorOptions.find((o) => o.value === op)?.label || op;
|
||||
}
|
||||
function getMetricLabel(metricName: string): string {
|
||||
return metricOptions.find((m) => m.value === metricName)?.label || metricName;
|
||||
}
|
||||
|
||||
function getOperatorLabel(op: string): string {
|
||||
return operatorOptions.find((o) => o.value === op)?.label || op;
|
||||
}
|
||||
</script>
|
||||
|
||||
<dialog class="modal modal-open">
|
||||
<div class="modal-box max-w-4xl bg-linear-to-br from-base-100 to-base-200">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"
|
||||
onclick={onClose}
|
||||
>
|
||||
✕
|
||||
</button>
|
||||
<div class="modal-box from-base-100 to-base-200 max-w-4xl bg-linear-to-br">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm btn-circle btn-ghost absolute top-2 right-2"
|
||||
onclick={onClose}
|
||||
>
|
||||
✕
|
||||
</button>
|
||||
|
||||
<h3 class="font-bold text-3xl text-primary mb-2">
|
||||
⚙️ Configuração de Alertas
|
||||
</h3>
|
||||
<p class="text-base-content/60 mb-6">
|
||||
Configure alertas personalizados para monitoramento do sistema
|
||||
</p>
|
||||
<h3 class="text-primary mb-2 text-3xl font-bold">⚙️ Configuração de Alertas</h3>
|
||||
<p class="text-base-content/60 mb-6">
|
||||
Configure alertas personalizados para monitoramento do sistema
|
||||
</p>
|
||||
|
||||
<!-- Botão Novo Alerta -->
|
||||
{#if !showForm}
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-primary mb-6"
|
||||
onclick={() => (showForm = true)}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-5 w-5"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M12 4v16m8-8H4"
|
||||
/>
|
||||
</svg>
|
||||
Novo Alerta
|
||||
</button>
|
||||
{/if}
|
||||
<!-- Botão Novo Alerta -->
|
||||
{#if !showForm}
|
||||
<button type="button" class="btn btn-primary mb-6" onclick={() => (showForm = true)}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-5 w-5"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M12 4v16m8-8H4"
|
||||
/>
|
||||
</svg>
|
||||
Novo Alerta
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
<!-- Formulário de Alerta -->
|
||||
{#if showForm}
|
||||
<div class="card bg-base-100 shadow-xl mb-6 border-2 border-primary/20">
|
||||
<div class="card-body">
|
||||
<h4 class="card-title text-xl">
|
||||
{editingAlertId ? "Editar Alerta" : "Novo Alerta"}
|
||||
</h4>
|
||||
<!-- Formulário de Alerta -->
|
||||
{#if showForm}
|
||||
<div class="card bg-base-100 border-primary/20 mb-6 border-2 shadow-xl">
|
||||
<div class="card-body">
|
||||
<h4 class="card-title text-xl">
|
||||
{editingAlertId ? 'Editar Alerta' : 'Novo Alerta'}
|
||||
</h4>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mt-4">
|
||||
<!-- Métrica -->
|
||||
<div class="form-control">
|
||||
<label class="label" for="metric">
|
||||
<span class="label-text font-semibold">Métrica</span>
|
||||
</label>
|
||||
<select
|
||||
id="metric"
|
||||
class="select select-bordered select-primary"
|
||||
bind:value={metricName}
|
||||
>
|
||||
{#each metricOptions as option}
|
||||
<option value={option.value}>{option.label}</option>
|
||||
{/each}
|
||||
</select>
|
||||
</div>
|
||||
<div class="mt-4 grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||
<!-- Métrica -->
|
||||
<div class="form-control">
|
||||
<label class="label" for="metric">
|
||||
<span class="label-text font-semibold">Métrica</span>
|
||||
</label>
|
||||
<select
|
||||
id="metric"
|
||||
class="select select-bordered select-primary"
|
||||
bind:value={metricName}
|
||||
>
|
||||
{#each metricOptions as option (option.value)}
|
||||
<option value={option.value}>{option.label}</option>
|
||||
{/each}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Operador -->
|
||||
<div class="form-control">
|
||||
<label class="label" for="operator">
|
||||
<span class="label-text font-semibold">Condição</span>
|
||||
</label>
|
||||
<select
|
||||
id="operator"
|
||||
class="select select-bordered select-primary"
|
||||
bind:value={operator}
|
||||
>
|
||||
{#each operatorOptions as option}
|
||||
<option value={option.value}>{option.label}</option>
|
||||
{/each}
|
||||
</select>
|
||||
</div>
|
||||
<!-- Operador -->
|
||||
<div class="form-control">
|
||||
<label class="label" for="operator">
|
||||
<span class="label-text font-semibold">Condição</span>
|
||||
</label>
|
||||
<select
|
||||
id="operator"
|
||||
class="select select-bordered select-primary"
|
||||
bind:value={operator}
|
||||
>
|
||||
{#each operatorOptions as option (option.value)}
|
||||
<option value={option.value}>{option.label}</option>
|
||||
{/each}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Threshold -->
|
||||
<div class="form-control">
|
||||
<label class="label" for="threshold">
|
||||
<span class="label-text font-semibold">Valor Limite</span>
|
||||
</label>
|
||||
<input
|
||||
id="threshold"
|
||||
type="number"
|
||||
class="input input-bordered input-primary"
|
||||
bind:value={threshold}
|
||||
min="0"
|
||||
step="1"
|
||||
/>
|
||||
</div>
|
||||
<!-- Threshold -->
|
||||
<div class="form-control">
|
||||
<label class="label" for="threshold">
|
||||
<span class="label-text font-semibold">Valor Limite</span>
|
||||
</label>
|
||||
<input
|
||||
id="threshold"
|
||||
type="number"
|
||||
class="input input-bordered input-primary"
|
||||
bind:value={threshold}
|
||||
min="0"
|
||||
step="1"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Ativo -->
|
||||
<div class="form-control">
|
||||
<label class="label cursor-pointer justify-start gap-4">
|
||||
<span class="label-text font-semibold">Alerta Ativo</span>
|
||||
<input
|
||||
type="checkbox"
|
||||
class="toggle toggle-primary"
|
||||
bind:checked={enabled}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Ativo -->
|
||||
<div class="form-control">
|
||||
<label class="label cursor-pointer justify-start gap-4">
|
||||
<span class="label-text font-semibold">Alerta Ativo</span>
|
||||
<input type="checkbox" class="toggle toggle-primary" bind:checked={enabled} />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Notificações -->
|
||||
<div class="divider">Método de Notificação</div>
|
||||
<div class="flex gap-6">
|
||||
<label class="label cursor-pointer gap-3">
|
||||
<input
|
||||
type="checkbox"
|
||||
class="checkbox checkbox-primary"
|
||||
bind:checked={notifyByChat}
|
||||
/>
|
||||
<span class="label-text">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-5 w-5 inline mr-2"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M8 10h.01M12 10h.01M16 10h.01M9 16H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-5l-5 5v-5z"
|
||||
/>
|
||||
</svg>
|
||||
Notificar por Chat
|
||||
</span>
|
||||
</label>
|
||||
<!-- Notificações -->
|
||||
<div class="divider">Método de Notificação</div>
|
||||
<div class="flex gap-6">
|
||||
<label class="label cursor-pointer gap-3">
|
||||
<input
|
||||
type="checkbox"
|
||||
class="checkbox checkbox-primary"
|
||||
bind:checked={notifyByChat}
|
||||
/>
|
||||
<span class="label-text">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="mr-2 inline h-5 w-5"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M8 10h.01M12 10h.01M16 10h.01M9 16H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-5l-5 5v-5z"
|
||||
/>
|
||||
</svg>
|
||||
Notificar por Chat
|
||||
</span>
|
||||
</label>
|
||||
|
||||
<label class="label cursor-pointer gap-3">
|
||||
<input
|
||||
type="checkbox"
|
||||
class="checkbox checkbox-secondary"
|
||||
bind:checked={notifyByEmail}
|
||||
/>
|
||||
<span class="label-text">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-5 w-5 inline mr-2"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"
|
||||
/>
|
||||
</svg>
|
||||
Notificar por E-mail
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<label class="label cursor-pointer gap-3">
|
||||
<input
|
||||
type="checkbox"
|
||||
class="checkbox checkbox-secondary"
|
||||
bind:checked={notifyByEmail}
|
||||
/>
|
||||
<span class="label-text">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="mr-2 inline h-5 w-5"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"
|
||||
/>
|
||||
</svg>
|
||||
Notificar por E-mail
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!-- Preview -->
|
||||
<div class="alert alert-info mt-4">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
class="stroke-current shrink-0 w-6 h-6"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
></path>
|
||||
</svg>
|
||||
<div>
|
||||
<h4 class="font-bold">Preview do Alerta:</h4>
|
||||
<p class="text-sm">
|
||||
Alertar quando <strong>{getMetricLabel(metricName)}</strong> for
|
||||
<strong>{getOperatorLabel(operator)}</strong> a
|
||||
<strong>{threshold}</strong>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Preview -->
|
||||
<div class="alert alert-info mt-4">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
class="h-6 w-6 shrink-0 stroke-current"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
></path>
|
||||
</svg>
|
||||
<div>
|
||||
<h4 class="font-bold">Preview do Alerta:</h4>
|
||||
<p class="text-sm">
|
||||
Alertar quando <strong>{getMetricLabel(metricName)}</strong> for
|
||||
<strong>{getOperatorLabel(operator)}</strong> a
|
||||
<strong>{threshold}</strong>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Botões -->
|
||||
<div class="card-actions justify-end mt-4">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-ghost"
|
||||
onclick={resetForm}
|
||||
disabled={saving}
|
||||
>
|
||||
Cancelar
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-primary"
|
||||
onclick={saveAlert}
|
||||
disabled={saving || (!notifyByChat && !notifyByEmail)}
|
||||
>
|
||||
{#if saving}
|
||||
<span class="loading loading-spinner"></span>
|
||||
Salvando...
|
||||
{:else}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-5 w-5"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M5 13l4 4L19 7"
|
||||
/>
|
||||
</svg>
|
||||
Salvar Alerta
|
||||
{/if}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<!-- Botões -->
|
||||
<div class="card-actions mt-4 justify-end">
|
||||
<button type="button" class="btn btn-ghost" onclick={resetForm} disabled={saving}>
|
||||
Cancelar
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-primary"
|
||||
onclick={saveAlert}
|
||||
disabled={saving || (!notifyByChat && !notifyByEmail)}
|
||||
>
|
||||
{#if saving}
|
||||
<span class="loading loading-spinner"></span>
|
||||
Salvando...
|
||||
{:else}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-5 w-5"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M5 13l4 4L19 7"
|
||||
/>
|
||||
</svg>
|
||||
Salvar Alerta
|
||||
{/if}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- Lista de Alertas -->
|
||||
<div class="divider">Alertas Configurados</div>
|
||||
<!-- Lista de Alertas -->
|
||||
<div class="divider">Alertas Configurados</div>
|
||||
|
||||
{#if alertas.length > 0}
|
||||
<div class="overflow-x-auto">
|
||||
<table class="table table-zebra">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Métrica</th>
|
||||
<th>Condição</th>
|
||||
<th>Status</th>
|
||||
<th>Notificações</th>
|
||||
<th>Ações</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each alertas as alerta}
|
||||
<tr class={!alerta.enabled ? "opacity-50" : ""}>
|
||||
<td>
|
||||
<div class="font-semibold">
|
||||
{getMetricLabel(alerta.metricName)}
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="badge badge-outline">
|
||||
{getOperatorLabel(alerta.operator)}
|
||||
{alerta.threshold}
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
{#if alerta.enabled}
|
||||
<div class="badge badge-success gap-2">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-3 w-3"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
/>
|
||||
</svg>
|
||||
Ativo
|
||||
</div>
|
||||
{:else}
|
||||
<div class="badge badge-ghost gap-2">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-3 w-3"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<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>
|
||||
Inativo
|
||||
</div>
|
||||
{/if}
|
||||
</td>
|
||||
<td>
|
||||
<div class="flex gap-1">
|
||||
{#if alerta.notifyByChat}
|
||||
<div class="badge badge-primary badge-sm">Chat</div>
|
||||
{/if}
|
||||
{#if alerta.notifyByEmail}
|
||||
<div class="badge badge-secondary badge-sm">Email</div>
|
||||
{/if}
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="flex gap-2">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-ghost btn-xs"
|
||||
onclick={() => editAlert(alerta)}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-4 w-4"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<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>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-ghost btn-xs text-error"
|
||||
onclick={() => deleteAlert(alerta._id)}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-4 w-4"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="alert">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
class="stroke-info shrink-0 w-6 h-6"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
></path>
|
||||
</svg>
|
||||
<span
|
||||
>Nenhum alerta configurado. Clique em "Novo Alerta" para criar um.</span
|
||||
>
|
||||
</div>
|
||||
{/if}
|
||||
{#if alertas.data && alertas.data.length > 0}
|
||||
<div class="overflow-x-auto">
|
||||
<table class="table-zebra table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Métrica</th>
|
||||
<th>Condição</th>
|
||||
<th>Status</th>
|
||||
<th>Notificações</th>
|
||||
<th>Ações</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each alertas.data as alerta (alerta._id)}
|
||||
<tr class={!alerta.enabled ? 'opacity-50' : ''}>
|
||||
<td>
|
||||
<div class="font-semibold">
|
||||
{getMetricLabel(alerta.metricName)}
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="badge badge-outline">
|
||||
{getOperatorLabel(alerta.operator)}
|
||||
{alerta.threshold}
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
{#if alerta.enabled}
|
||||
<div class="badge badge-success gap-2">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-3 w-3"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
/>
|
||||
</svg>
|
||||
Ativo
|
||||
</div>
|
||||
{:else}
|
||||
<div class="badge badge-ghost gap-2">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-3 w-3"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<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>
|
||||
Inativo
|
||||
</div>
|
||||
{/if}
|
||||
</td>
|
||||
<td>
|
||||
<div class="flex gap-1">
|
||||
{#if alerta.notifyByChat}
|
||||
<div class="badge badge-primary badge-sm">Chat</div>
|
||||
{/if}
|
||||
{#if alerta.notifyByEmail}
|
||||
<div class="badge badge-secondary badge-sm">Email</div>
|
||||
{/if}
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="flex gap-2">
|
||||
<button
|
||||
title="Editar Alerta"
|
||||
type="button"
|
||||
class="btn btn-ghost btn-xs"
|
||||
onclick={() => editAlert(alerta)}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-4 w-4"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<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>
|
||||
</button>
|
||||
<button
|
||||
title="Deletar Alerta"
|
||||
type="button"
|
||||
class="btn btn-ghost btn-xs text-error"
|
||||
onclick={() => deleteAlert(alerta._id)}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-4 w-4"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="alert">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
class="stroke-info h-6 w-6 shrink-0"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
></path>
|
||||
</svg>
|
||||
<span>Nenhum alerta configurado. Clique em "Novo Alerta" para criar um.</span>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="modal-action">
|
||||
<button type="button" class="btn btn-lg" onclick={onClose}>Fechar</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
||||
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
|
||||
<form method="dialog" class="modal-backdrop" onclick={onClose}>
|
||||
<button type="button">close</button>
|
||||
</form>
|
||||
<div class="modal-action">
|
||||
<button type="button" class="btn btn-lg" onclick={onClose}>Fechar</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
||||
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
|
||||
<form method="dialog" class="modal-backdrop" onclick={onClose}>
|
||||
<button type="button">close</button>
|
||||
</form>
|
||||
</dialog>
|
||||
|
||||
Reference in New Issue
Block a user