mirror of
https://github.com/amir20/dozzle.git
synced 2025-12-24 14:31:44 +01:00
feat: actions on log messages (#2572)
This commit is contained in:
4
assets/components.d.ts
vendored
4
assets/components.d.ts
vendored
@@ -10,10 +10,13 @@ declare module 'vue' {
|
||||
BarChart: typeof import('./components/BarChart.vue')['default']
|
||||
'Carbon:caretDown': typeof import('~icons/carbon/caret-down')['default']
|
||||
'Carbon:circleSolid': typeof import('~icons/carbon/circle-solid')['default']
|
||||
'Carbon:copyFile': typeof import('~icons/carbon/copy-file')['default']
|
||||
'Carbon:information': typeof import('~icons/carbon/information')['default']
|
||||
'Carbon:macShift': typeof import('~icons/carbon/mac-shift')['default']
|
||||
'Carbon:play': typeof import('~icons/carbon/play')['default']
|
||||
'Carbon:restart': typeof import('~icons/carbon/restart')['default']
|
||||
'Carbon:rowCollapse': typeof import('~icons/carbon/row-collapse')['default']
|
||||
'Carbon:rowExpand': typeof import('~icons/carbon/row-expand')['default']
|
||||
'Carbon:star': typeof import('~icons/carbon/star')['default']
|
||||
'Carbon:starFilled': typeof import('~icons/carbon/star-filled')['default']
|
||||
'Carbon:stopFilledAlt': typeof import('~icons/carbon/stop-filled-alt')['default']
|
||||
@@ -28,6 +31,7 @@ declare module 'vue' {
|
||||
ContainerStat: typeof import('./components/LogViewer/ContainerStat.vue')['default']
|
||||
ContainerTable: typeof import('./components/ContainerTable.vue')['default']
|
||||
ContainerTitle: typeof import('./components/LogViewer/ContainerTitle.vue')['default']
|
||||
CopyLogMessage: typeof import('./components/LogViewer/CopyLogMessage.vue')['default']
|
||||
DateTime: typeof import('./components/common/DateTime.vue')['default']
|
||||
DistanceTime: typeof import('./components/common/DistanceTime.vue')['default']
|
||||
DockerEventLogItem: typeof import('./components/LogViewer/DockerEventLogItem.vue')['default']
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="flex gap-x-2">
|
||||
<div class="relative flex gap-x-2">
|
||||
<div v-if="showStd">
|
||||
<log-std :std="logEntry.std"></log-std>
|
||||
</div>
|
||||
@@ -22,6 +22,10 @@
|
||||
</ul>
|
||||
<field-list :fields="logEntry.unfilteredMessage" :expanded="expanded" :visible-keys="visibleKeys"></field-list>
|
||||
</div>
|
||||
<copy-log-message
|
||||
class="duration-250 absolute -right-1 opacity-0 transition-opacity delay-150 group-hover/entry:opacity-100"
|
||||
:message="JSON.stringify(logEntry.message)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
@@ -45,6 +49,7 @@ const validValues = computed(() => {
|
||||
.text-light {
|
||||
@apply text-base-content/70;
|
||||
}
|
||||
|
||||
.fields {
|
||||
&:hover {
|
||||
&::after {
|
||||
|
||||
39
assets/components/LogViewer/CopyLogMessage.vue
Normal file
39
assets/components/LogViewer/CopyLogMessage.vue
Normal file
@@ -0,0 +1,39 @@
|
||||
<template>
|
||||
<div
|
||||
class="flex min-w-[0.98rem] items-start justify-end align-bottom hover:cursor-pointer"
|
||||
v-if="isSupported && message.trim() != ''"
|
||||
:title="t('copy_log.title')"
|
||||
>
|
||||
<span
|
||||
class="rounded bg-slate-800/60 px-1.5 py-1 text-primary hover:bg-slate-700"
|
||||
@click="copyLogMessageToClipBoard()"
|
||||
>
|
||||
<carbon:copy-file />
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
const { message } = defineProps<{
|
||||
message: string;
|
||||
}>();
|
||||
|
||||
const { showToast } = useToast();
|
||||
const { copy, isSupported, copied } = useClipboard();
|
||||
const { t } = useI18n();
|
||||
|
||||
async function copyLogMessageToClipBoard() {
|
||||
await copy(message);
|
||||
|
||||
if (copied.value) {
|
||||
showToast(
|
||||
{
|
||||
title: t("toasts.copied.title"),
|
||||
message: t("toasts.copied.message"),
|
||||
type: "info",
|
||||
},
|
||||
{ expire: 2000 },
|
||||
);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -10,6 +10,7 @@ import { vi, describe, expect, beforeEach, test, afterEach } from "vitest";
|
||||
import { computed, nextTick } from "vue";
|
||||
import { createRouter, createWebHistory } from "vue-router";
|
||||
import { containerContext } from "@/composable/containerContext";
|
||||
import { createI18n } from "vue-i18n";
|
||||
|
||||
vi.mock("@/stores/config", () => ({
|
||||
__esModule: true,
|
||||
@@ -68,7 +69,7 @@ describe("<LogEventSource />", () => {
|
||||
|
||||
return mount(LogEventSource, {
|
||||
global: {
|
||||
plugins: [router, createTestingPinia({ createSpy: vi.fn })],
|
||||
plugins: [router, createTestingPinia({ createSpy: vi.fn }), createI18n({})],
|
||||
components: {
|
||||
LogViewer,
|
||||
},
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
:key="item.id"
|
||||
:data-key="item.id"
|
||||
:class="{ 'border border-secondary': toRaw(item) === toRaw(lastSelectedItem) }"
|
||||
class="group/entry"
|
||||
>
|
||||
<a
|
||||
class="jump-context tooltip tooltip-right tooltip-primary"
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
<template>
|
||||
<div class="flex items-start gap-x-2">
|
||||
<div class="relative flex w-full items-start gap-x-2">
|
||||
<log-std :std="logEntry.std" v-if="showStd" />
|
||||
<log-date :date="logEntry.date" v-if="showTimestamp" />
|
||||
<log-level class="flex" :level="logEntry.level" :position="logEntry.position" />
|
||||
<div class="whitespace-pre-wrap group-[.disable-wrap]:whitespace-nowrap" v-html="colorize(logEntry.message)"></div>
|
||||
<copy-log-message
|
||||
class="duration-250 absolute -right-1 opacity-0 transition-opacity delay-150 group-hover/entry:opacity-100"
|
||||
:message="logEntry.message"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
|
||||
@@ -2,15 +2,16 @@
|
||||
|
||||
exports[`<LogEventSource /> > render html correctly > should render dates with 12 hour style 1`] = `
|
||||
"<ul data-v-2e92daca="" class="events group py-4 medium">
|
||||
<li data-v-2e92daca="" data-key="1" class="">
|
||||
<li data-v-2e92daca="" data-key="1" class="group/entry">
|
||||
<!--v-if-->
|
||||
<div data-v-2e92daca="" class="flex items-start gap-x-2" visible-keys="">
|
||||
<div data-v-2e92daca="" class="relative flex w-full items-start gap-x-2" visible-keys="">
|
||||
<!--v-if-->
|
||||
<div data-v-961504e7="" class="inline-flex items-center justify-center rounded bg-base-lighter px-2 py-[0.2em] text-sm" size="small">
|
||||
<div class="inline-flex gap-2 whitespace-nowrap text-blue"><time datetime="2019-06-12T10:55:42.459Z" class="mobile-hidden">06/12/2019</time><time datetime="2019-06-12T10:55:42.459Z">10:55:42 AM</time></div>
|
||||
</div>
|
||||
<div data-v-e625cddd="" class="mt-1.5 h-2.5 w-2.5 flex-none rounded-lg flex"></div>
|
||||
<div class="whitespace-pre-wrap group-[.disable-wrap]:whitespace-nowrap"><test>foo bar</test></div>
|
||||
<!--v-if-->
|
||||
</div>
|
||||
</li>
|
||||
</ul>"
|
||||
@@ -18,15 +19,16 @@ exports[`<LogEventSource /> > render html correctly > should render dates with 1
|
||||
|
||||
exports[`<LogEventSource /> > render html correctly > should render dates with 24 hour style 1`] = `
|
||||
"<ul data-v-2e92daca="" class="events group py-4 medium">
|
||||
<li data-v-2e92daca="" data-key="1" class="">
|
||||
<li data-v-2e92daca="" data-key="1" class="group/entry">
|
||||
<!--v-if-->
|
||||
<div data-v-2e92daca="" class="flex items-start gap-x-2" visible-keys="">
|
||||
<div data-v-2e92daca="" class="relative flex w-full items-start gap-x-2" visible-keys="">
|
||||
<!--v-if-->
|
||||
<div data-v-961504e7="" class="inline-flex items-center justify-center rounded bg-base-lighter px-2 py-[0.2em] text-sm" size="small">
|
||||
<div class="inline-flex gap-2 whitespace-nowrap text-blue"><time datetime="2019-06-12T10:55:42.459Z" class="mobile-hidden">06/12/2019</time><time datetime="2019-06-12T10:55:42.459Z">10:55:42</time></div>
|
||||
</div>
|
||||
<div data-v-e625cddd="" class="mt-1.5 h-2.5 w-2.5 flex-none rounded-lg flex"></div>
|
||||
<div class="whitespace-pre-wrap group-[.disable-wrap]:whitespace-nowrap"><test>foo bar</test></div>
|
||||
<!--v-if-->
|
||||
</div>
|
||||
</li>
|
||||
</ul>"
|
||||
@@ -34,15 +36,16 @@ exports[`<LogEventSource /> > render html correctly > should render dates with 2
|
||||
|
||||
exports[`<LogEventSource /> > render html correctly > should render messages 1`] = `
|
||||
"<ul data-v-2e92daca="" class="events group py-4 medium">
|
||||
<li data-v-2e92daca="" data-key="1" class="">
|
||||
<li data-v-2e92daca="" data-key="1" class="group/entry">
|
||||
<!--v-if-->
|
||||
<div data-v-2e92daca="" class="flex items-start gap-x-2" visible-keys="">
|
||||
<div data-v-2e92daca="" class="relative flex w-full items-start gap-x-2" visible-keys="">
|
||||
<!--v-if-->
|
||||
<div data-v-961504e7="" class="inline-flex items-center justify-center rounded bg-base-lighter px-2 py-[0.2em] text-sm" size="small">
|
||||
<div class="inline-flex gap-2 whitespace-nowrap text-blue"><time datetime="2019-06-12T10:55:42.459Z" class="mobile-hidden">06/12/2019</time><time datetime="2019-06-12T10:55:42.459Z">10:55:42 AM</time></div>
|
||||
</div>
|
||||
<div data-v-e625cddd="" class="mt-1.5 h-2.5 w-2.5 flex-none rounded-lg flex"></div>
|
||||
<div class="whitespace-pre-wrap group-[.disable-wrap]:whitespace-nowrap">This is a message.</div>
|
||||
<!--v-if-->
|
||||
</div>
|
||||
</li>
|
||||
</ul>"
|
||||
@@ -50,15 +53,16 @@ exports[`<LogEventSource /> > render html correctly > should render messages 1`]
|
||||
|
||||
exports[`<LogEventSource /> > render html correctly > should render messages with color 1`] = `
|
||||
"<ul data-v-2e92daca="" class="events group py-4 medium">
|
||||
<li data-v-2e92daca="" data-key="1" class="">
|
||||
<li data-v-2e92daca="" data-key="1" class="group/entry">
|
||||
<!--v-if-->
|
||||
<div data-v-2e92daca="" class="flex items-start gap-x-2" visible-keys="">
|
||||
<div data-v-2e92daca="" class="relative flex w-full items-start gap-x-2" visible-keys="">
|
||||
<!--v-if-->
|
||||
<div data-v-961504e7="" class="inline-flex items-center justify-center rounded bg-base-lighter px-2 py-[0.2em] text-sm" size="small">
|
||||
<div class="inline-flex gap-2 whitespace-nowrap text-blue"><time datetime="2019-06-12T10:55:42.459Z" class="mobile-hidden">06/12/2019</time><time datetime="2019-06-12T10:55:42.459Z">10:55:42 AM</time></div>
|
||||
</div>
|
||||
<div data-v-e625cddd="" class="mt-1.5 h-2.5 w-2.5 flex-none rounded-lg flex"></div>
|
||||
<div class="whitespace-pre-wrap group-[.disable-wrap]:whitespace-nowrap"><span style="color:#000">black<span style="color:#AAA">white</span></span></div>
|
||||
<!--v-if-->
|
||||
</div>
|
||||
</li>
|
||||
</ul>"
|
||||
@@ -66,16 +70,17 @@ exports[`<LogEventSource /> > render html correctly > should render messages wit
|
||||
|
||||
exports[`<LogEventSource /> > render html correctly > should render messages with filter 1`] = `
|
||||
"<ul data-v-2e92daca="" class="events group py-4 medium">
|
||||
<li data-v-2e92daca="" data-key="2" class=""><a data-v-2e92daca="" class="jump-context tooltip tooltip-right tooltip-primary" data-tip="Jump to Context" href="#2"><svg data-v-2e92daca="" viewBox="0 0 24 24" width="1.2em" height="1.2em">
|
||||
<li data-v-2e92daca="" data-key="2" class="group/entry"><a data-v-2e92daca="" class="jump-context tooltip tooltip-right tooltip-primary" data-tip="Jump to Context" href="#2"><svg data-v-2e92daca="" viewBox="0 0 24 24" width="1.2em" height="1.2em">
|
||||
<path fill="currentColor" d="M20 19.59V8l-6-6H4v20l15.57-.02l-4.81-4.81c-.8.52-1.74.83-2.76.83c-2.76 0-5-2.24-5-5s2.24-5 5-5s5 2.24 5 5c0 1.02-.31 1.96-.83 2.75L20 19.59zM9 13c0 1.66 1.34 3 3 3s3-1.34 3-3s-1.34-3-3-3s-3 1.34-3 3z"></path>
|
||||
</svg></a>
|
||||
<div data-v-2e92daca="" class="flex items-start gap-x-2" visible-keys="">
|
||||
<div data-v-2e92daca="" class="relative flex w-full items-start gap-x-2" visible-keys="">
|
||||
<!--v-if-->
|
||||
<div data-v-961504e7="" class="inline-flex items-center justify-center rounded bg-base-lighter px-2 py-[0.2em] text-sm" size="small">
|
||||
<div class="inline-flex gap-2 whitespace-nowrap text-blue"><time datetime="2019-06-12T10:55:42.459Z" class="mobile-hidden">06/12/2019</time><time datetime="2019-06-12T10:55:42.459Z">10:55:42 AM</time></div>
|
||||
</div>
|
||||
<div data-v-e625cddd="" class="mt-1.5 h-2.5 w-2.5 flex-none rounded-lg flex"></div>
|
||||
<div class="whitespace-pre-wrap group-[.disable-wrap]:whitespace-nowrap"><mark>test</mark> bar</div>
|
||||
<!--v-if-->
|
||||
</div>
|
||||
</li>
|
||||
</ul>"
|
||||
@@ -83,15 +88,16 @@ exports[`<LogEventSource /> > render html correctly > should render messages wit
|
||||
|
||||
exports[`<LogEventSource /> > render html correctly > should render messages with html entities 1`] = `
|
||||
"<ul data-v-2e92daca="" class="events group py-4 medium">
|
||||
<li data-v-2e92daca="" data-key="1" class="">
|
||||
<li data-v-2e92daca="" data-key="1" class="group/entry">
|
||||
<!--v-if-->
|
||||
<div data-v-2e92daca="" class="flex items-start gap-x-2" visible-keys="">
|
||||
<div data-v-2e92daca="" class="relative flex w-full items-start gap-x-2" visible-keys="">
|
||||
<!--v-if-->
|
||||
<div data-v-961504e7="" class="inline-flex items-center justify-center rounded bg-base-lighter px-2 py-[0.2em] text-sm" size="small">
|
||||
<div class="inline-flex gap-2 whitespace-nowrap text-blue"><time datetime="2019-06-12T10:55:42.459Z" class="mobile-hidden">06/12/2019</time><time datetime="2019-06-12T10:55:42.459Z">10:55:42 AM</time></div>
|
||||
</div>
|
||||
<div data-v-e625cddd="" class="mt-1.5 h-2.5 w-2.5 flex-none rounded-lg flex"></div>
|
||||
<div class="whitespace-pre-wrap group-[.disable-wrap]:whitespace-nowrap"><test>foo bar</test></div>
|
||||
<!--v-if-->
|
||||
</div>
|
||||
</li>
|
||||
</ul>"
|
||||
|
||||
@@ -91,3 +91,10 @@ releases:
|
||||
two_parts: "{first} with {second}"
|
||||
latest: Latest
|
||||
no_releases: You have the latest version
|
||||
copy_log:
|
||||
title: Copy log
|
||||
toasts:
|
||||
copied:
|
||||
title: Copied
|
||||
message: Log copied to clipboard
|
||||
|
||||
|
||||
Reference in New Issue
Block a user