mirror of
https://github.com/amir20/dozzle.git
synced 2025-12-30 09:45:15 +01:00
Cleans up search by removing for loop (#1719)
* Cleans up search by removing for loop * Fixes tests
This commit is contained in:
10
assets/components.d.ts
vendored
10
assets/components.d.ts
vendored
@@ -5,8 +5,6 @@ import '@vue/runtime-core'
|
||||
|
||||
declare module '@vue/runtime-core' {
|
||||
export interface GlobalComponents {
|
||||
CarbonCaretDown: typeof import('~icons/carbon/caret-down')['default']
|
||||
CilColumns: typeof import('~icons/cil/columns')['default']
|
||||
CilFindInPage: typeof import('~icons/cil/find-in-page')['default']
|
||||
ContainerStat: typeof import('./components/ContainerStat.vue')['default']
|
||||
ContainerTitle: typeof import('./components/ContainerTitle.vue')['default']
|
||||
@@ -19,15 +17,7 @@ declare module '@vue/runtime-core' {
|
||||
LogViewer: typeof import('./components/LogViewer.vue')['default']
|
||||
LogViewerWithSource: typeof import('./components/LogViewerWithSource.vue')['default']
|
||||
MdiDotsVertical: typeof import('~icons/mdi/dots-vertical')['default']
|
||||
MdiLightChevronDoubleDown: typeof import('~icons/mdi-light/chevron-double-down')['default']
|
||||
MdiLightChevronLeft: typeof import('~icons/mdi-light/chevron-left')['default']
|
||||
MdiLightChevronRight: typeof import('~icons/mdi-light/chevron-right')['default']
|
||||
MdiLightCog: typeof import('~icons/mdi-light/cog')['default']
|
||||
MdiLightMagnify: typeof import('~icons/mdi-light/magnify')['default']
|
||||
MobileMenu: typeof import('./components/MobileMenu.vue')['default']
|
||||
OcticonContainer24: typeof import('~icons/octicon/container24')['default']
|
||||
OcticonDownload24: typeof import('~icons/octicon/download24')['default']
|
||||
OcticonTrash24: typeof import('~icons/octicon/trash24')['default']
|
||||
PastTime: typeof import('./components/PastTime.vue')['default']
|
||||
RelativeTime: typeof import('./components/RelativeTime.vue')['default']
|
||||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
|
||||
@@ -8,6 +8,7 @@ import { settings } from "../composables/settings";
|
||||
import { useSearchFilter } from "@/composables/search";
|
||||
import { vi, describe, expect, beforeEach, test, beforeAll, afterAll } from "vitest";
|
||||
import { computed, Ref } from "vue";
|
||||
import { createRouter, createWebHistory } from "vue-router";
|
||||
|
||||
vi.mock("lodash.debounce", () => ({
|
||||
__esModule: true,
|
||||
@@ -50,7 +51,7 @@ describe("<LogEventSource />", () => {
|
||||
|
||||
function createLogEventSource(
|
||||
{
|
||||
searchFilter = undefined,
|
||||
searchFilter = "",
|
||||
hourStyle = "auto",
|
||||
}: { searchFilter?: string | undefined; hourStyle?: "auto" | "24" | "12" } = {
|
||||
hourStyle: "auto",
|
||||
@@ -58,9 +59,22 @@ describe("<LogEventSource />", () => {
|
||||
) {
|
||||
settings.value.hourStyle = hourStyle;
|
||||
search.searchFilter.value = searchFilter;
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory("/"),
|
||||
routes: [
|
||||
{
|
||||
path: "/",
|
||||
component: {
|
||||
template: "Test from createLogEventSource",
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
return mount(LogEventSource, {
|
||||
global: {
|
||||
plugins: [createTestingPinia({ createSpy: vi.fn })],
|
||||
plugins: [router, createTestingPinia({ createSpy: vi.fn })],
|
||||
components: {
|
||||
LogViewer,
|
||||
},
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
<li
|
||||
v-for="(item, index) in filtered"
|
||||
:key="item.key"
|
||||
:data-event="item.event"
|
||||
:data-key="item.key"
|
||||
:class="item.selected ? 'selected' : ''"
|
||||
:data-event="item.event"
|
||||
:class="{ selected: item.selected }"
|
||||
>
|
||||
<div class="line-options" v-if="isSearching()">
|
||||
<div class="line-options" v-show="isSearching()">
|
||||
<dropdown-menu :class="{ 'is-last': index === filtered.length - 1 }" class="is-top minimal">
|
||||
<a class="dropdown-item" @click="handleJumpLineSelected">
|
||||
<a class="dropdown-item" @click="handleJumpLineSelected($event, item)" :href="`#${item.key}`">
|
||||
<div class="level is-justify-content-start">
|
||||
<div class="level-left">
|
||||
<div class="level-item">
|
||||
@@ -32,15 +32,13 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { PropType, ref, toRefs, watch, nextTick } from "vue";
|
||||
|
||||
import { PropType, ref, toRefs, watch } from "vue";
|
||||
import { useRouteHash } from "@vueuse/router";
|
||||
import { size, showTimestamp, softWrap } from "@/composables/settings";
|
||||
import RelativeTime from "./RelativeTime.vue";
|
||||
import AnsiConvertor from "ansi-to-html";
|
||||
import { LogEntry } from "@/types/LogEntry";
|
||||
import { useSearchFilter } from "@/composables/search";
|
||||
import { useContainerStore } from "@/stores/container";
|
||||
import { storeToRefs } from "pinia";
|
||||
|
||||
const props = defineProps({
|
||||
messages: {
|
||||
@@ -50,43 +48,29 @@ const props = defineProps({
|
||||
});
|
||||
|
||||
const ansiConvertor = new AnsiConvertor({ escapeXML: true });
|
||||
const colorize = (value: string) =>
|
||||
ansiConvertor.toHtml(value).replace("<mark>", "<mark>").replace("</mark>", "</mark>");
|
||||
const { filteredMessages, resetSearch, markSearch, isSearching } = useSearchFilter();
|
||||
const colorize = (value: string) => markSearch(ansiConvertor.toHtml(value));
|
||||
const { messages } = toRefs(props);
|
||||
const { filteredMessages, resetSearch, isSearching } = useSearchFilter();
|
||||
const store = useContainerStore();
|
||||
const { activeContainers } = storeToRefs(store);
|
||||
const filtered = filteredMessages(messages);
|
||||
const events = ref(null);
|
||||
let selectedLine: Element | null = null;
|
||||
const handleJumpLineSelected = async (e: Event) => {
|
||||
const line = e.target?.closest("li");
|
||||
if (line.tagName !== "LI") {
|
||||
return;
|
||||
const events = ref<HTMLElement>();
|
||||
let lastSelectedItem: LogEntry | undefined = undefined;
|
||||
function handleJumpLineSelected(e: Event, item: LogEntry) {
|
||||
if (lastSelectedItem) {
|
||||
lastSelectedItem.selected = false;
|
||||
}
|
||||
selectedLine = line;
|
||||
lastSelectedItem = item;
|
||||
item.selected = true;
|
||||
resetSearch();
|
||||
};
|
||||
watch(filtered, async (newVal, oldVal) => {
|
||||
if (selectedLine === null) {
|
||||
return;
|
||||
}
|
||||
await nextTick();
|
||||
for (const item of messages.value) {
|
||||
item.selected = false;
|
||||
if (item.key === selectedLine.dataset.key) {
|
||||
item.selected = true;
|
||||
}
|
||||
}
|
||||
// when in split pane mode - scroll the pane element, when not in split pane mode - scroll the window element
|
||||
const inSplitPane = activeContainers.value.length > 0;
|
||||
const elemToScroll = inSplitPane ? events.value.closest("main") : window;
|
||||
elemToScroll.scrollTo(0, 0);
|
||||
// wait 1s before jumping when in split pane mode to ensure the correct line is scrolled to, single pane mode does not have this issue thus only 10ms is needed
|
||||
await new Promise((resolve) => setTimeout(resolve, inSplitPane ? 1000 : 10));
|
||||
elemToScroll.scrollTo(0, selectedLine.offsetTop - 200);
|
||||
selectedLine = null;
|
||||
});
|
||||
}
|
||||
|
||||
const routeHash = useRouteHash();
|
||||
watch(
|
||||
routeHash,
|
||||
(hash) => {
|
||||
document.querySelector(`[data-key="${hash.substring(1)}"]`)?.scrollIntoView({ block: "center" });
|
||||
},
|
||||
{ immediate: true, flush: "post" }
|
||||
);
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.events {
|
||||
@@ -115,9 +99,10 @@ watch(filtered, async (newVal, oldVal) => {
|
||||
&[data-event="container-started"] {
|
||||
color: hsl(141, 53%, 53%);
|
||||
}
|
||||
&.selected {
|
||||
&.selected .date {
|
||||
background-color: var(--menu-item-active-background-color);
|
||||
color: black;
|
||||
|
||||
color: var(--text-color);
|
||||
}
|
||||
&.selected > .date {
|
||||
background-color: white;
|
||||
|
||||
@@ -3,7 +3,26 @@
|
||||
exports[`<LogEventSource /> > render html correctly > should render dates with 12 hour style 1`] = `
|
||||
"<ul class=\\"events medium\\" data-v-28f125ea=\\"\\">
|
||||
<li data-key=\\"2019-06-12T23:55:42.459034602Z\\" class=\\"\\" data-v-28f125ea=\\"\\">
|
||||
<!--v-if-->
|
||||
<div class=\\"line-options\\" data-v-28f125ea=\\"\\" style=\\"display: none;\\">
|
||||
<div class=\\"dropdown is-hoverable is-last is-top minimal\\" data-v-3af6a38b=\\"\\" data-v-28f125ea=\\"\\">
|
||||
<div class=\\"dropdown-trigger\\" data-v-3af6a38b=\\"\\"><button class=\\"button\\" aria-haspopup=\\"true\\" aria-controls=\\"dropdown-menu\\" data-v-3af6a38b=\\"\\"><span class=\\"icon\\" data-v-3af6a38b=\\"\\"><svg preserveAspectRatio=\\"xMidYMid meet\\" viewBox=\\"0 0 24 24\\" width=\\"1.2em\\" height=\\"1.2em\\" data-v-3af6a38b=\\"\\"><path fill=\\"currentColor\\" d=\\"M12 16a2 2 0 0 1 2 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2a2 2 0 0 1 2-2m0-6a2 2 0 0 1 2 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2a2 2 0 0 1 2-2m0-6a2 2 0 0 1 2 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2a2 2 0 0 1 2-2Z\\"></path></svg></span></button></div>
|
||||
<div class=\\"dropdown-menu\\" id=\\"dropdown-menu\\" role=\\"menu\\" data-v-3af6a38b=\\"\\">
|
||||
<div class=\\"dropdown-content\\" data-v-3af6a38b=\\"\\"><a class=\\"dropdown-item\\" href=\\"#2019-06-12T23:55:42.459034602Z\\" data-v-28f125ea=\\"\\">
|
||||
<div class=\\"level is-justify-content-start\\" data-v-28f125ea=\\"\\">
|
||||
<div class=\\"level-left\\" data-v-28f125ea=\\"\\">
|
||||
<div class=\\"level-item\\" data-v-28f125ea=\\"\\"><svg preserveAspectRatio=\\"xMidYMid meet\\" viewBox=\\"0 0 512 512\\" width=\\"1.2em\\" height=\\"1.2em\\" class=\\"mr-4\\" data-v-28f125ea=\\"\\">
|
||||
<path fill=\\"currentColor\\" d=\\"M334.627 16H48v480h424V153.373ZM440 464H80V48h241.373L440 166.627Z\\"></path>
|
||||
<path fill=\\"currentColor\\" d=\\"M239.861 152a95.861 95.861 0 1 0 53.624 175.284l68.03 68.029l22.627-22.626l-67.5-67.5A95.816 95.816 0 0 0 239.861 152ZM176 247.861a63.862 63.862 0 1 1 63.861 63.861A63.933 63.933 0 0 1 176 247.861Z\\"></path>
|
||||
</svg></div>
|
||||
</div>
|
||||
<div class=\\"level-right\\" data-v-28f125ea=\\"\\">
|
||||
<div class=\\"level-item\\" data-v-28f125ea=\\"\\">Jump to Context</div>
|
||||
</div>
|
||||
</div>
|
||||
</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class=\\"line\\" data-v-28f125ea=\\"\\"><span class=\\"date\\" data-v-28f125ea=\\"\\"><time datetime=\\"2019-06-12T23:55:42.459Z\\" data-v-28f125ea=\\"\\">today at 11:55:42 PM</time></span><span class=\\"text\\" data-v-28f125ea=\\"\\"><test>foo bar</test></span></div>
|
||||
</li>
|
||||
</ul>"
|
||||
@@ -12,7 +31,26 @@ exports[`<LogEventSource /> > render html correctly > should render dates with 1
|
||||
exports[`<LogEventSource /> > render html correctly > should render dates with 24 hour style 1`] = `
|
||||
"<ul class=\\"events medium\\" data-v-28f125ea=\\"\\">
|
||||
<li data-key=\\"2019-06-12T23:55:42.459034602Z\\" class=\\"\\" data-v-28f125ea=\\"\\">
|
||||
<!--v-if-->
|
||||
<div class=\\"line-options\\" data-v-28f125ea=\\"\\" style=\\"display: none;\\">
|
||||
<div class=\\"dropdown is-hoverable is-last is-top minimal\\" data-v-3af6a38b=\\"\\" data-v-28f125ea=\\"\\">
|
||||
<div class=\\"dropdown-trigger\\" data-v-3af6a38b=\\"\\"><button class=\\"button\\" aria-haspopup=\\"true\\" aria-controls=\\"dropdown-menu\\" data-v-3af6a38b=\\"\\"><span class=\\"icon\\" data-v-3af6a38b=\\"\\"><svg preserveAspectRatio=\\"xMidYMid meet\\" viewBox=\\"0 0 24 24\\" width=\\"1.2em\\" height=\\"1.2em\\" data-v-3af6a38b=\\"\\"><path fill=\\"currentColor\\" d=\\"M12 16a2 2 0 0 1 2 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2a2 2 0 0 1 2-2m0-6a2 2 0 0 1 2 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2a2 2 0 0 1 2-2m0-6a2 2 0 0 1 2 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2a2 2 0 0 1 2-2Z\\"></path></svg></span></button></div>
|
||||
<div class=\\"dropdown-menu\\" id=\\"dropdown-menu\\" role=\\"menu\\" data-v-3af6a38b=\\"\\">
|
||||
<div class=\\"dropdown-content\\" data-v-3af6a38b=\\"\\"><a class=\\"dropdown-item\\" href=\\"#2019-06-12T23:55:42.459034602Z\\" data-v-28f125ea=\\"\\">
|
||||
<div class=\\"level is-justify-content-start\\" data-v-28f125ea=\\"\\">
|
||||
<div class=\\"level-left\\" data-v-28f125ea=\\"\\">
|
||||
<div class=\\"level-item\\" data-v-28f125ea=\\"\\"><svg preserveAspectRatio=\\"xMidYMid meet\\" viewBox=\\"0 0 512 512\\" width=\\"1.2em\\" height=\\"1.2em\\" class=\\"mr-4\\" data-v-28f125ea=\\"\\">
|
||||
<path fill=\\"currentColor\\" d=\\"M334.627 16H48v480h424V153.373ZM440 464H80V48h241.373L440 166.627Z\\"></path>
|
||||
<path fill=\\"currentColor\\" d=\\"M239.861 152a95.861 95.861 0 1 0 53.624 175.284l68.03 68.029l22.627-22.626l-67.5-67.5A95.816 95.816 0 0 0 239.861 152ZM176 247.861a63.862 63.862 0 1 1 63.861 63.861A63.933 63.933 0 0 1 176 247.861Z\\"></path>
|
||||
</svg></div>
|
||||
</div>
|
||||
<div class=\\"level-right\\" data-v-28f125ea=\\"\\">
|
||||
<div class=\\"level-item\\" data-v-28f125ea=\\"\\">Jump to Context</div>
|
||||
</div>
|
||||
</div>
|
||||
</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class=\\"line\\" data-v-28f125ea=\\"\\"><span class=\\"date\\" data-v-28f125ea=\\"\\"><time datetime=\\"2019-06-12T23:55:42.459Z\\" data-v-28f125ea=\\"\\">today at 23:55:42</time></span><span class=\\"text\\" data-v-28f125ea=\\"\\"><test>foo bar</test></span></div>
|
||||
</li>
|
||||
</ul>"
|
||||
@@ -21,7 +59,26 @@ exports[`<LogEventSource /> > render html correctly > should render dates with 2
|
||||
exports[`<LogEventSource /> > render html correctly > should render messages 1`] = `
|
||||
"<ul class=\\"events medium\\" data-v-28f125ea=\\"\\">
|
||||
<li data-key=\\"2019-06-12T10:55:42.459034602Z\\" class=\\"\\" data-v-28f125ea=\\"\\">
|
||||
<!--v-if-->
|
||||
<div class=\\"line-options\\" data-v-28f125ea=\\"\\" style=\\"display: none;\\">
|
||||
<div class=\\"dropdown is-hoverable is-last is-top minimal\\" data-v-3af6a38b=\\"\\" data-v-28f125ea=\\"\\">
|
||||
<div class=\\"dropdown-trigger\\" data-v-3af6a38b=\\"\\"><button class=\\"button\\" aria-haspopup=\\"true\\" aria-controls=\\"dropdown-menu\\" data-v-3af6a38b=\\"\\"><span class=\\"icon\\" data-v-3af6a38b=\\"\\"><svg preserveAspectRatio=\\"xMidYMid meet\\" viewBox=\\"0 0 24 24\\" width=\\"1.2em\\" height=\\"1.2em\\" data-v-3af6a38b=\\"\\"><path fill=\\"currentColor\\" d=\\"M12 16a2 2 0 0 1 2 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2a2 2 0 0 1 2-2m0-6a2 2 0 0 1 2 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2a2 2 0 0 1 2-2m0-6a2 2 0 0 1 2 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2a2 2 0 0 1 2-2Z\\"></path></svg></span></button></div>
|
||||
<div class=\\"dropdown-menu\\" id=\\"dropdown-menu\\" role=\\"menu\\" data-v-3af6a38b=\\"\\">
|
||||
<div class=\\"dropdown-content\\" data-v-3af6a38b=\\"\\"><a class=\\"dropdown-item\\" href=\\"#2019-06-12T10:55:42.459034602Z\\" data-v-28f125ea=\\"\\">
|
||||
<div class=\\"level is-justify-content-start\\" data-v-28f125ea=\\"\\">
|
||||
<div class=\\"level-left\\" data-v-28f125ea=\\"\\">
|
||||
<div class=\\"level-item\\" data-v-28f125ea=\\"\\"><svg preserveAspectRatio=\\"xMidYMid meet\\" viewBox=\\"0 0 512 512\\" width=\\"1.2em\\" height=\\"1.2em\\" class=\\"mr-4\\" data-v-28f125ea=\\"\\">
|
||||
<path fill=\\"currentColor\\" d=\\"M334.627 16H48v480h424V153.373ZM440 464H80V48h241.373L440 166.627Z\\"></path>
|
||||
<path fill=\\"currentColor\\" d=\\"M239.861 152a95.861 95.861 0 1 0 53.624 175.284l68.03 68.029l22.627-22.626l-67.5-67.5A95.816 95.816 0 0 0 239.861 152ZM176 247.861a63.862 63.862 0 1 1 63.861 63.861A63.933 63.933 0 0 1 176 247.861Z\\"></path>
|
||||
</svg></div>
|
||||
</div>
|
||||
<div class=\\"level-right\\" data-v-28f125ea=\\"\\">
|
||||
<div class=\\"level-item\\" data-v-28f125ea=\\"\\">Jump to Context</div>
|
||||
</div>
|
||||
</div>
|
||||
</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class=\\"line\\" data-v-28f125ea=\\"\\"><span class=\\"date\\" data-v-28f125ea=\\"\\"><time datetime=\\"2019-06-12T10:55:42.459Z\\" data-v-28f125ea=\\"\\">today at 10:55:42 AM</time></span><span class=\\"text\\" data-v-28f125ea=\\"\\">\\"This is a message.\\"</span></div>
|
||||
</li>
|
||||
</ul>"
|
||||
@@ -30,7 +87,26 @@ exports[`<LogEventSource /> > render html correctly > should render messages 1`]
|
||||
exports[`<LogEventSource /> > render html correctly > should render messages with color 1`] = `
|
||||
"<ul class=\\"events medium\\" data-v-28f125ea=\\"\\">
|
||||
<li data-key=\\"2019-06-12T10:55:42.459034602Z\\" class=\\"\\" data-v-28f125ea=\\"\\">
|
||||
<!--v-if-->
|
||||
<div class=\\"line-options\\" data-v-28f125ea=\\"\\" style=\\"display: none;\\">
|
||||
<div class=\\"dropdown is-hoverable is-last is-top minimal\\" data-v-3af6a38b=\\"\\" data-v-28f125ea=\\"\\">
|
||||
<div class=\\"dropdown-trigger\\" data-v-3af6a38b=\\"\\"><button class=\\"button\\" aria-haspopup=\\"true\\" aria-controls=\\"dropdown-menu\\" data-v-3af6a38b=\\"\\"><span class=\\"icon\\" data-v-3af6a38b=\\"\\"><svg preserveAspectRatio=\\"xMidYMid meet\\" viewBox=\\"0 0 24 24\\" width=\\"1.2em\\" height=\\"1.2em\\" data-v-3af6a38b=\\"\\"><path fill=\\"currentColor\\" d=\\"M12 16a2 2 0 0 1 2 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2a2 2 0 0 1 2-2m0-6a2 2 0 0 1 2 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2a2 2 0 0 1 2-2m0-6a2 2 0 0 1 2 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2a2 2 0 0 1 2-2Z\\"></path></svg></span></button></div>
|
||||
<div class=\\"dropdown-menu\\" id=\\"dropdown-menu\\" role=\\"menu\\" data-v-3af6a38b=\\"\\">
|
||||
<div class=\\"dropdown-content\\" data-v-3af6a38b=\\"\\"><a class=\\"dropdown-item\\" href=\\"#2019-06-12T10:55:42.459034602Z\\" data-v-28f125ea=\\"\\">
|
||||
<div class=\\"level is-justify-content-start\\" data-v-28f125ea=\\"\\">
|
||||
<div class=\\"level-left\\" data-v-28f125ea=\\"\\">
|
||||
<div class=\\"level-item\\" data-v-28f125ea=\\"\\"><svg preserveAspectRatio=\\"xMidYMid meet\\" viewBox=\\"0 0 512 512\\" width=\\"1.2em\\" height=\\"1.2em\\" class=\\"mr-4\\" data-v-28f125ea=\\"\\">
|
||||
<path fill=\\"currentColor\\" d=\\"M334.627 16H48v480h424V153.373ZM440 464H80V48h241.373L440 166.627Z\\"></path>
|
||||
<path fill=\\"currentColor\\" d=\\"M239.861 152a95.861 95.861 0 1 0 53.624 175.284l68.03 68.029l22.627-22.626l-67.5-67.5A95.816 95.816 0 0 0 239.861 152ZM176 247.861a63.862 63.862 0 1 1 63.861 63.861A63.933 63.933 0 0 1 176 247.861Z\\"></path>
|
||||
</svg></div>
|
||||
</div>
|
||||
<div class=\\"level-right\\" data-v-28f125ea=\\"\\">
|
||||
<div class=\\"level-item\\" data-v-28f125ea=\\"\\">Jump to Context</div>
|
||||
</div>
|
||||
</div>
|
||||
</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class=\\"line\\" data-v-28f125ea=\\"\\"><span class=\\"date\\" data-v-28f125ea=\\"\\"><time datetime=\\"2019-06-12T10:55:42.459Z\\" data-v-28f125ea=\\"\\">today at 10:55:42 AM</time></span><span class=\\"text\\" data-v-28f125ea=\\"\\"><span style=\\"color:#000\\">black<span style=\\"color:#AAA\\">white</span></span></span></div>
|
||||
</li>
|
||||
</ul>"
|
||||
@@ -39,7 +115,26 @@ exports[`<LogEventSource /> > render html correctly > should render messages wit
|
||||
exports[`<LogEventSource /> > render html correctly > should render messages with filter 1`] = `
|
||||
"<ul class=\\"events medium\\" data-v-28f125ea=\\"\\">
|
||||
<li data-key=\\"2019-06-12T10:55:42.459034602Z\\" class=\\"\\" data-v-28f125ea=\\"\\">
|
||||
<!--v-if-->
|
||||
<div class=\\"line-options\\" data-v-28f125ea=\\"\\" style=\\"display: none;\\">
|
||||
<div class=\\"dropdown is-hoverable is-last is-top minimal\\" data-v-3af6a38b=\\"\\" data-v-28f125ea=\\"\\">
|
||||
<div class=\\"dropdown-trigger\\" data-v-3af6a38b=\\"\\"><button class=\\"button\\" aria-haspopup=\\"true\\" aria-controls=\\"dropdown-menu\\" data-v-3af6a38b=\\"\\"><span class=\\"icon\\" data-v-3af6a38b=\\"\\"><svg preserveAspectRatio=\\"xMidYMid meet\\" viewBox=\\"0 0 24 24\\" width=\\"1.2em\\" height=\\"1.2em\\" data-v-3af6a38b=\\"\\"><path fill=\\"currentColor\\" d=\\"M12 16a2 2 0 0 1 2 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2a2 2 0 0 1 2-2m0-6a2 2 0 0 1 2 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2a2 2 0 0 1 2-2m0-6a2 2 0 0 1 2 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2a2 2 0 0 1 2-2Z\\"></path></svg></span></button></div>
|
||||
<div class=\\"dropdown-menu\\" id=\\"dropdown-menu\\" role=\\"menu\\" data-v-3af6a38b=\\"\\">
|
||||
<div class=\\"dropdown-content\\" data-v-3af6a38b=\\"\\"><a class=\\"dropdown-item\\" href=\\"#2019-06-12T10:55:42.459034602Z\\" data-v-28f125ea=\\"\\">
|
||||
<div class=\\"level is-justify-content-start\\" data-v-28f125ea=\\"\\">
|
||||
<div class=\\"level-left\\" data-v-28f125ea=\\"\\">
|
||||
<div class=\\"level-item\\" data-v-28f125ea=\\"\\"><svg preserveAspectRatio=\\"xMidYMid meet\\" viewBox=\\"0 0 512 512\\" width=\\"1.2em\\" height=\\"1.2em\\" class=\\"mr-4\\" data-v-28f125ea=\\"\\">
|
||||
<path fill=\\"currentColor\\" d=\\"M334.627 16H48v480h424V153.373ZM440 464H80V48h241.373L440 166.627Z\\"></path>
|
||||
<path fill=\\"currentColor\\" d=\\"M239.861 152a95.861 95.861 0 1 0 53.624 175.284l68.03 68.029l22.627-22.626l-67.5-67.5A95.816 95.816 0 0 0 239.861 152ZM176 247.861a63.862 63.862 0 1 1 63.861 63.861A63.933 63.933 0 0 1 176 247.861Z\\"></path>
|
||||
</svg></div>
|
||||
</div>
|
||||
<div class=\\"level-right\\" data-v-28f125ea=\\"\\">
|
||||
<div class=\\"level-item\\" data-v-28f125ea=\\"\\">Jump to Context</div>
|
||||
</div>
|
||||
</div>
|
||||
</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class=\\"line\\" data-v-28f125ea=\\"\\"><span class=\\"date\\" data-v-28f125ea=\\"\\"><time datetime=\\"2019-06-12T10:55:42.459Z\\" data-v-28f125ea=\\"\\">today at 10:55:42 AM</time></span><span class=\\"text\\" data-v-28f125ea=\\"\\">This is a <mark>test</mark> <hi></hi></span></div>
|
||||
</li>
|
||||
</ul>"
|
||||
@@ -48,7 +143,26 @@ exports[`<LogEventSource /> > render html correctly > should render messages wit
|
||||
exports[`<LogEventSource /> > render html correctly > should render messages with html entities 1`] = `
|
||||
"<ul class=\\"events medium\\" data-v-28f125ea=\\"\\">
|
||||
<li data-key=\\"2019-06-12T10:55:42.459034602Z\\" class=\\"\\" data-v-28f125ea=\\"\\">
|
||||
<!--v-if-->
|
||||
<div class=\\"line-options\\" data-v-28f125ea=\\"\\" style=\\"display: none;\\">
|
||||
<div class=\\"dropdown is-hoverable is-last is-top minimal\\" data-v-3af6a38b=\\"\\" data-v-28f125ea=\\"\\">
|
||||
<div class=\\"dropdown-trigger\\" data-v-3af6a38b=\\"\\"><button class=\\"button\\" aria-haspopup=\\"true\\" aria-controls=\\"dropdown-menu\\" data-v-3af6a38b=\\"\\"><span class=\\"icon\\" data-v-3af6a38b=\\"\\"><svg preserveAspectRatio=\\"xMidYMid meet\\" viewBox=\\"0 0 24 24\\" width=\\"1.2em\\" height=\\"1.2em\\" data-v-3af6a38b=\\"\\"><path fill=\\"currentColor\\" d=\\"M12 16a2 2 0 0 1 2 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2a2 2 0 0 1 2-2m0-6a2 2 0 0 1 2 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2a2 2 0 0 1 2-2m0-6a2 2 0 0 1 2 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2a2 2 0 0 1 2-2Z\\"></path></svg></span></button></div>
|
||||
<div class=\\"dropdown-menu\\" id=\\"dropdown-menu\\" role=\\"menu\\" data-v-3af6a38b=\\"\\">
|
||||
<div class=\\"dropdown-content\\" data-v-3af6a38b=\\"\\"><a class=\\"dropdown-item\\" href=\\"#2019-06-12T10:55:42.459034602Z\\" data-v-28f125ea=\\"\\">
|
||||
<div class=\\"level is-justify-content-start\\" data-v-28f125ea=\\"\\">
|
||||
<div class=\\"level-left\\" data-v-28f125ea=\\"\\">
|
||||
<div class=\\"level-item\\" data-v-28f125ea=\\"\\"><svg preserveAspectRatio=\\"xMidYMid meet\\" viewBox=\\"0 0 512 512\\" width=\\"1.2em\\" height=\\"1.2em\\" class=\\"mr-4\\" data-v-28f125ea=\\"\\">
|
||||
<path fill=\\"currentColor\\" d=\\"M334.627 16H48v480h424V153.373ZM440 464H80V48h241.373L440 166.627Z\\"></path>
|
||||
<path fill=\\"currentColor\\" d=\\"M239.861 152a95.861 95.861 0 1 0 53.624 175.284l68.03 68.029l22.627-22.626l-67.5-67.5A95.816 95.816 0 0 0 239.861 152ZM176 247.861a63.862 63.862 0 1 1 63.861 63.861A63.933 63.933 0 0 1 176 247.861Z\\"></path>
|
||||
</svg></div>
|
||||
</div>
|
||||
<div class=\\"level-right\\" data-v-28f125ea=\\"\\">
|
||||
<div class=\\"level-item\\" data-v-28f125ea=\\"\\">Jump to Context</div>
|
||||
</div>
|
||||
</div>
|
||||
</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class=\\"line\\" data-v-28f125ea=\\"\\"><span class=\\"date\\" data-v-28f125ea=\\"\\"><time datetime=\\"2019-06-12T10:55:42.459Z\\" data-v-28f125ea=\\"\\">today at 10:55:42 AM</time></span><span class=\\"text\\" data-v-28f125ea=\\"\\"><test>foo bar</test></span></div>
|
||||
</li>
|
||||
</ul>"
|
||||
|
||||
@@ -1,26 +1,24 @@
|
||||
import { ref, computed, Ref } from "vue";
|
||||
|
||||
const searchFilter = ref<string>();
|
||||
const searchFilter = ref<string>("");
|
||||
const showSearch = ref(false);
|
||||
|
||||
import type { LogEntry } from "@/types/LogEntry";
|
||||
|
||||
export function useSearchFilter() {
|
||||
const regex = computed(() => {
|
||||
const isSmartCase = searchFilter.value === searchFilter.value.toLowerCase();
|
||||
return isSmartCase ? new RegExp(searchFilter.value, "i") : new RegExp(searchFilter.value);
|
||||
});
|
||||
|
||||
function filteredMessages(messages: Ref<LogEntry[]>) {
|
||||
return computed(() => {
|
||||
if (searchFilter && searchFilter.value) {
|
||||
const isSmartCase = searchFilter.value === searchFilter.value.toLowerCase();
|
||||
try {
|
||||
const regex = isSmartCase ? new RegExp(searchFilter.value, "i") : new RegExp(searchFilter.value);
|
||||
return messages.value
|
||||
.filter((d) => d.message.match(regex))
|
||||
.map((d) => ({
|
||||
...d,
|
||||
message: d.message.replace(regex, "<mark>$&</mark>"),
|
||||
}));
|
||||
return messages.value.filter((d) => d.message.match(regex.value));
|
||||
} catch (e) {
|
||||
if (e instanceof SyntaxError) {
|
||||
console.info(`Ignoring SytaxError from search.`, e);
|
||||
console.info(`Ignoring SyntaxError from search.`, e);
|
||||
return messages.value;
|
||||
}
|
||||
throw e;
|
||||
@@ -31,6 +29,13 @@ export function useSearchFilter() {
|
||||
});
|
||||
}
|
||||
|
||||
function markSearch(log: string) {
|
||||
if (searchFilter && searchFilter.value) {
|
||||
return log.replace(regex.value, `<mark>$&</mark>`);
|
||||
}
|
||||
return log;
|
||||
}
|
||||
|
||||
function resetSearch() {
|
||||
searchFilter.value = "";
|
||||
showSearch.value = false;
|
||||
@@ -44,6 +49,7 @@ export function useSearchFilter() {
|
||||
filteredMessages,
|
||||
searchFilter,
|
||||
showSearch,
|
||||
markSearch,
|
||||
resetSearch,
|
||||
isSearching,
|
||||
};
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
"@vitejs/plugin-vue": "^2.3.1",
|
||||
"@vue/compiler-sfc": "^3.2.33",
|
||||
"@vueuse/core": "^8.2.6",
|
||||
"@vueuse/router": "^8.2.6",
|
||||
"ansi-to-html": "^0.7.2",
|
||||
"bulma": "^0.9.3",
|
||||
"date-fns": "^2.28.0",
|
||||
|
||||
15
pnpm-lock.yaml
generated
15
pnpm-lock.yaml
generated
@@ -17,6 +17,7 @@ specifiers:
|
||||
'@vue/compiler-sfc': ^3.2.33
|
||||
'@vue/test-utils': ^2.0.0-rc.20
|
||||
'@vueuse/core': ^8.2.6
|
||||
'@vueuse/router': ^8.2.6
|
||||
ansi-to-html: ^0.7.2
|
||||
bulma: ^0.9.3
|
||||
c8: ^7.11.0
|
||||
@@ -57,6 +58,7 @@ dependencies:
|
||||
'@vitejs/plugin-vue': 2.3.1_vite@2.9.5+vue@3.2.33
|
||||
'@vue/compiler-sfc': 3.2.33
|
||||
'@vueuse/core': 8.2.6_vue@3.2.33
|
||||
'@vueuse/router': 8.2.6_vue-router@4.0.14+vue@3.2.33
|
||||
ansi-to-html: 0.7.2
|
||||
bulma: 0.9.3
|
||||
date-fns: 2.28.0
|
||||
@@ -580,6 +582,19 @@ packages:
|
||||
resolution: {integrity: sha512-OBKtafCt+4RcEJlYDCjp1vl65pBCL2g4TmipEtdZ8/qphKlW6nakJbkY7XRN5grPmjqU99/ahJGtyGk5NHS2hw==}
|
||||
dev: false
|
||||
|
||||
/@vueuse/router/8.2.6_vue-router@4.0.14+vue@3.2.33:
|
||||
resolution: {integrity: sha512-7HKFR7VNfqXVB/N6sIP6hq7zn+XgWWOPdpWlgcTbbzyiDwzHu2dHjUx1LMn7o1GbQAyMFlJdiXqvuvqjS8Xb8A==}
|
||||
peerDependencies:
|
||||
vue-router: '>=4.0.0-rc.1'
|
||||
dependencies:
|
||||
'@vueuse/shared': 8.2.6_vue@3.2.33
|
||||
vue-demi: 0.12.5_vue@3.2.33
|
||||
vue-router: 4.0.14_vue@3.2.33
|
||||
transitivePeerDependencies:
|
||||
- '@vue/composition-api'
|
||||
- vue
|
||||
dev: false
|
||||
|
||||
/@vueuse/shared/8.2.6_vue@3.2.33:
|
||||
resolution: {integrity: sha512-J/W4CMfdL8TahELuSOgtfVO4eQXTjhigp7dVWIBsLUVFCeY9d49gvHUcQN3y5xYLZ6iNP57TjTQjMMT/zhklkw==}
|
||||
peerDependencies:
|
||||
|
||||
Reference in New Issue
Block a user