mirror of
https://github.com/amir20/dozzle.git
synced 2026-06-23 04:10:12 +00:00
feat: adds shortcut for creating alerts (#4411)
This commit is contained in:
Vendored
+1
@@ -80,6 +80,7 @@ declare module 'vue' {
|
||||
'MaterialSymbols:eyeTracking': typeof import('~icons/material-symbols/eye-tracking')['default']
|
||||
'MaterialSymbols:link': typeof import('~icons/material-symbols/link')['default']
|
||||
'MaterialSymbols:logout': typeof import('~icons/material-symbols/logout')['default']
|
||||
'MaterialSymbols:notificationsAdd': typeof import('~icons/material-symbols/notifications-add')['default']
|
||||
'MaterialSymbols:person': typeof import('~icons/material-symbols/person')['default']
|
||||
'MaterialSymbols:terminal': typeof import('~icons/material-symbols/terminal')['default']
|
||||
'MaterialSymbolsLight:collapseAll': typeof import('~icons/material-symbols-light/collapse-all')['default']
|
||||
|
||||
@@ -73,6 +73,12 @@
|
||||
{{ $t("action.show-details") }}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a @click="createAlert()">
|
||||
<mdi:bell />
|
||||
{{ $t("action.create-alert") }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
@@ -82,6 +88,7 @@ import stripAnsi from "strip-ansi";
|
||||
import { Container } from "@/models/Container";
|
||||
import { LogEntry, SimpleLogEntry, ComplexLogEntry, GroupedLogEntry, JSONObject } from "@/models/LogEntry";
|
||||
import LogDetails from "./LogDetails.vue";
|
||||
import AlertForm from "@/components/Notification/AlertForm.vue";
|
||||
|
||||
const { logEntry, container } = defineProps<{
|
||||
logEntry: LogEntry<string | JSONObject>;
|
||||
@@ -147,6 +154,22 @@ async function copyPermalink() {
|
||||
}
|
||||
}
|
||||
|
||||
function createAlert() {
|
||||
const containerExpr = `name contains "${container.name}"`;
|
||||
let logExpr = "";
|
||||
if (logEntry.level && logEntry.level !== "unknown") {
|
||||
logExpr = `level == "${logEntry.level}"`;
|
||||
}
|
||||
|
||||
const nameParts = [container.name];
|
||||
if (logEntry.level && logEntry.level !== "unknown") {
|
||||
nameParts.push(logEntry.level);
|
||||
}
|
||||
const name = nameParts.join(" ");
|
||||
|
||||
showDrawer(AlertForm, { prefill: { name, containerExpression: containerExpr, logExpression: logExpr } }, "lg");
|
||||
}
|
||||
|
||||
function hideMenu(e: MouseEvent) {
|
||||
if (e.target instanceof HTMLAnchorElement) {
|
||||
setTimeout(() => {
|
||||
|
||||
@@ -21,6 +21,9 @@ exports[`<ContainerEventSource /> > render html correctly > should render dates
|
||||
<path fill="currentColor" d="M11 17H7q-2.075 0-3.537-1.463T2 12t1.463-3.537T7 7h4v2H7q-1.25 0-2.125.875T4 12t.875 2.125T7 15h4zm-3-4v-2h8v2zm5 4v-2h4q1.25 0 2.125-.875T20 12t-.875-2.125T17 9h-4V7h4q2.075 0 3.538 1.463T22 12t-1.463 3.538T17 17z"></path>
|
||||
</svg> action.copy-link</a></li>
|
||||
<!--v-if-->
|
||||
<li><a><svg viewBox="0 0 24 24" width="1.2em" height="1.2em">
|
||||
<path fill="currentColor" d="M21 19v1H3v-1l2-2v-6c0-3.1 2.03-5.83 5-6.71V4a2 2 0 0 1 2-2a2 2 0 0 1 2 2v.29c2.97.88 5 3.61 5 6.71v6zm-7 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2"></path>
|
||||
</svg> action.create-alert</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!--v-if-->
|
||||
@@ -59,6 +62,9 @@ exports[`<ContainerEventSource /> > render html correctly > should render dates
|
||||
<path fill="currentColor" d="M11 17H7q-2.075 0-3.537-1.463T2 12t1.463-3.537T7 7h4v2H7q-1.25 0-2.125.875T4 12t.875 2.125T7 15h4zm-3-4v-2h8v2zm5 4v-2h4q1.25 0 2.125-.875T20 12t-.875-2.125T17 9h-4V7h4q2.075 0 3.538 1.463T22 12t-1.463 3.538T17 17z"></path>
|
||||
</svg> action.copy-link</a></li>
|
||||
<!--v-if-->
|
||||
<li><a><svg viewBox="0 0 24 24" width="1.2em" height="1.2em">
|
||||
<path fill="currentColor" d="M21 19v1H3v-1l2-2v-6c0-3.1 2.03-5.83 5-6.71V4a2 2 0 0 1 2-2a2 2 0 0 1 2 2v.29c2.97.88 5 3.61 5 6.71v6zm-7 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2"></path>
|
||||
</svg> action.create-alert</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!--v-if-->
|
||||
@@ -97,6 +103,9 @@ exports[`<ContainerEventSource /> > render html correctly > should render messag
|
||||
<path fill="currentColor" d="M11 17H7q-2.075 0-3.537-1.463T2 12t1.463-3.537T7 7h4v2H7q-1.25 0-2.125.875T4 12t.875 2.125T7 15h4zm-3-4v-2h8v2zm5 4v-2h4q1.25 0 2.125-.875T20 12t-.875-2.125T17 9h-4V7h4q2.075 0 3.538 1.463T22 12t-1.463 3.538T17 17z"></path>
|
||||
</svg> action.copy-link</a></li>
|
||||
<!--v-if-->
|
||||
<li><a><svg viewBox="0 0 24 24" width="1.2em" height="1.2em">
|
||||
<path fill="currentColor" d="M21 19v1H3v-1l2-2v-6c0-3.1 2.03-5.83 5-6.71V4a2 2 0 0 1 2-2a2 2 0 0 1 2 2v.29c2.97.88 5 3.61 5 6.71v6zm-7 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2"></path>
|
||||
</svg> action.create-alert</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!--v-if-->
|
||||
|
||||
@@ -147,10 +147,11 @@ import { createExprEditor, createContainerHints, createLogHints } from "@/compos
|
||||
|
||||
import type { Dispatcher, NotificationRule, PreviewResult } from "@/types/notifications";
|
||||
|
||||
const { close, onCreated, alert } = defineProps<{
|
||||
const { close, onCreated, alert, prefill } = defineProps<{
|
||||
close?: () => void;
|
||||
onCreated?: () => void;
|
||||
alert?: NotificationRule;
|
||||
prefill?: { name?: string; containerExpression?: string; logExpression?: string };
|
||||
}>();
|
||||
|
||||
// Fetch dispatchers
|
||||
@@ -177,9 +178,9 @@ const destinationDropdown = ref<HTMLDetailsElement>();
|
||||
|
||||
// Form state
|
||||
const isEditing = computed(() => !!alert);
|
||||
const alertName = ref(alert?.name ?? "");
|
||||
const containerExpression = ref(alert?.containerExpression ?? "");
|
||||
const logExpression = ref(alert?.logExpression ?? "");
|
||||
const alertName = ref(alert?.name ?? prefill?.name ?? "");
|
||||
const containerExpression = ref(alert?.containerExpression ?? prefill?.containerExpression ?? "");
|
||||
const logExpression = ref(alert?.logExpression ?? prefill?.logExpression ?? "");
|
||||
const dispatcherId = ref(alert?.dispatcher?.id ?? 0);
|
||||
const selectedDestination = computed(() => destinations.value.find((d) => d.id === dispatcherId.value));
|
||||
useFocus(alertNameInput, { initialValue: true });
|
||||
@@ -301,10 +302,14 @@ async function validateExpressions() {
|
||||
|
||||
const debouncedValidate = useDebounceFn(validateExpressions, 500);
|
||||
|
||||
watch([containerExpression, logExpression], () => {
|
||||
isLoading.value = true;
|
||||
debouncedValidate();
|
||||
});
|
||||
watch(
|
||||
[containerExpression, logExpression],
|
||||
() => {
|
||||
isLoading.value = true;
|
||||
debouncedValidate();
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
let containerEditorView: Awaited<ReturnType<typeof createExprEditor>> | undefined;
|
||||
let logEditorView: Awaited<ReturnType<typeof createExprEditor>> | undefined;
|
||||
@@ -314,7 +319,7 @@ onMounted(async () => {
|
||||
containerEditorView = await createExprEditor({
|
||||
parent: containerEditorRef.value,
|
||||
placeholder: 'name contains "api"',
|
||||
initialValue: alert?.containerExpression ?? "",
|
||||
initialValue: alert?.containerExpression ?? prefill?.containerExpression ?? "",
|
||||
getHints: () => createContainerHints(containerNames.value, imageNames.value, hostNames.value),
|
||||
onChange: (v) => (containerExpression.value = v),
|
||||
});
|
||||
@@ -324,7 +329,7 @@ onMounted(async () => {
|
||||
logEditorView = await createExprEditor({
|
||||
parent: logEditorRef.value,
|
||||
placeholder: 'level == "error" && message contains "timeout"',
|
||||
initialValue: alert?.logExpression ?? "",
|
||||
initialValue: alert?.logExpression ?? prefill?.logExpression ?? "",
|
||||
getHints: createLogHints,
|
||||
onChange: (v) => (logExpression.value = v),
|
||||
});
|
||||
|
||||
@@ -491,7 +491,7 @@ func (h *handler) previewExpression(w http.ResponseWriter, r *http.Request) {
|
||||
continue
|
||||
}
|
||||
|
||||
from := time.Now().Add(-5 * time.Minute)
|
||||
from := time.Now().Add(-2 * time.Hour)
|
||||
to := time.Now()
|
||||
|
||||
logChan, err := containerService.LogsBetweenDates(ctx, from, to, container.STDALL)
|
||||
|
||||
@@ -17,6 +17,7 @@ action:
|
||||
copy-link: Kopier permalink
|
||||
see-in-context: Se i kontekst
|
||||
show-details: Vis detaljer
|
||||
create-alert: Opret advarsel
|
||||
label:
|
||||
containers: Containere
|
||||
container: Ingen containere | 1 container | {count} containere
|
||||
|
||||
@@ -17,6 +17,7 @@ action:
|
||||
copy-link: Permalink kopieren
|
||||
see-in-context: Im Kontext anzeigen
|
||||
show-details: Details anzeigen
|
||||
create-alert: Alarm erstellen
|
||||
label:
|
||||
containers: Container
|
||||
container: Keine Container | 1 Container | {count} Container
|
||||
|
||||
@@ -17,6 +17,7 @@ action:
|
||||
copy-link: Copy permalink
|
||||
see-in-context: See in context
|
||||
show-details: Show details
|
||||
create-alert: Create alert
|
||||
label:
|
||||
containers: Containers
|
||||
container: No containers | 1 container | {count} containers
|
||||
|
||||
@@ -17,6 +17,7 @@ action:
|
||||
copy-link: Copiar enlace permanente
|
||||
see-in-context: Ver en contexto
|
||||
show-details: Mostrar detalles
|
||||
create-alert: Crear alerta
|
||||
label:
|
||||
containers: Contenedores
|
||||
container: No contenedores | 1 contenedor | {count} contenedores
|
||||
|
||||
@@ -17,6 +17,7 @@ action:
|
||||
copy-link: Copier le permalien
|
||||
see-in-context: Voir dans le contexte
|
||||
show-details: Afficher les détails
|
||||
create-alert: Créer une alerte
|
||||
label:
|
||||
containers: Conteneurs
|
||||
container: Pas de conteneur | 1 conteneur | {count} conteneurs
|
||||
|
||||
@@ -17,6 +17,7 @@ action:
|
||||
copy-link: Salin permalink
|
||||
see-in-context: Lihat dalam konteks
|
||||
show-details: Tampilkan detail
|
||||
create-alert: Buat peringatan
|
||||
|
||||
label:
|
||||
containers: Kontainer
|
||||
|
||||
@@ -17,6 +17,7 @@ action:
|
||||
copy-link: Copia permalink
|
||||
see-in-context: Vedi nel contesto
|
||||
show-details: Mostra dettagli
|
||||
create-alert: Crea avviso
|
||||
label:
|
||||
containers: Container
|
||||
container: Nessun container | 1 container | {count} container
|
||||
|
||||
@@ -17,6 +17,7 @@ action:
|
||||
copy-link: 영구 링크 복사
|
||||
see-in-context: 컨텍스트에서 보기
|
||||
show-details: 세부 정보 표시
|
||||
create-alert: 알림 생성
|
||||
label:
|
||||
containers: 컨테이너
|
||||
container: 컨테이너가 없습니다 | 컨테이너 1개 | 컨테이너 {count}개
|
||||
|
||||
@@ -17,6 +17,7 @@ action:
|
||||
copy-link: Permalink kopiëren
|
||||
see-in-context: Bekijk in context
|
||||
show-details: Toon details
|
||||
create-alert: Waarschuwing aanmaken
|
||||
label:
|
||||
containers: Containers
|
||||
container: Geen containers | 1 container | {count} containers
|
||||
|
||||
@@ -17,6 +17,7 @@ action:
|
||||
copy-link: Skopiuj permalink
|
||||
see-in-context: Zobacz w kontekście
|
||||
show-details: Pokaż szczegóły
|
||||
create-alert: Utwórz alert
|
||||
label:
|
||||
service: Brak usług | 1 usługa | {count} usług
|
||||
host-count: Brak Hostów | 1 Host | {count} Hostów
|
||||
|
||||
@@ -17,6 +17,7 @@ action:
|
||||
copy-link: Copiar hiperligação permanente
|
||||
see-in-context: Ver no contexto
|
||||
show-details: Mostrar detalhes
|
||||
create-alert: Criar alerta
|
||||
label:
|
||||
containers: Contentores
|
||||
container: Nenhum contentor | 1 contentor | {count} contentores
|
||||
|
||||
@@ -17,6 +17,7 @@ action:
|
||||
copy-link: Copiar permalink
|
||||
see-in-context: Ver no contexto
|
||||
show-details: Mostrar detalhes
|
||||
create-alert: Criar alerta
|
||||
label:
|
||||
containers: Contêineres
|
||||
container: Nenhum container | 1 container | {count} containers
|
||||
|
||||
@@ -17,6 +17,7 @@ action:
|
||||
copy-link: Копировать постоянную ссылку
|
||||
see-in-context: Посмотреть в контексте
|
||||
show-details: Показать детали
|
||||
create-alert: Создать оповещение
|
||||
label:
|
||||
containers: Контейнеры
|
||||
container: Нет контейнеров | 1 контейнер | {count} контейнеров
|
||||
|
||||
@@ -17,6 +17,7 @@ action:
|
||||
copy-link: Kopiraj trajno povezavo
|
||||
see-in-context: Glej v kontekstu
|
||||
show-details: Prikaži podrobnosti
|
||||
create-alert: Ustvari opozorilo
|
||||
label:
|
||||
containers: Zabojniki
|
||||
host-count: Ni Gostiteljev | 1 Gostitelj | {count} Gostiteljev
|
||||
|
||||
@@ -17,6 +17,7 @@ action:
|
||||
copy-link: Kalıcı bağlantıyı kopyala
|
||||
see-in-context: Bağlamda gör
|
||||
show-details: Detayları göster
|
||||
create-alert: Uyarı oluştur
|
||||
label:
|
||||
containers: Konteynerlar
|
||||
container: Konteyner yok | 1 konteyner | {count} konteyner
|
||||
|
||||
@@ -17,6 +17,7 @@ action:
|
||||
copy-link: 複製永久連結
|
||||
see-in-context: 在內容中查看
|
||||
show-details: 顯示詳細資訊
|
||||
create-alert: 建立警報
|
||||
label:
|
||||
containers: 容器
|
||||
container: 無容器 | 1 個容器 | {count} 個容器
|
||||
|
||||
@@ -17,6 +17,7 @@ action:
|
||||
copy-link: 复制永久链接
|
||||
see-in-context: 在上下文中查看
|
||||
show-details: 显示详细信息
|
||||
create-alert: 创建告警
|
||||
label:
|
||||
containers: 容器
|
||||
container: 无容器 | 1 容器 | {count} 容器
|
||||
|
||||
Reference in New Issue
Block a user