1
0
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:
Amir Raminfar
2022-04-19 13:54:08 -07:00
committed by GitHub
parent 49448790ff
commit 011bc94e8c
7 changed files with 196 additions and 71 deletions

View File

@@ -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']

View File

@@ -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,
},

View File

@@ -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("&lt;mark&gt;", "<mark>").replace("&lt;/mark&gt;", "</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;

View File

@@ -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=\\"\\">&lt;test&gt;foo bar&lt;/test&gt;</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=\\"\\">&lt;test&gt;foo bar&lt;/test&gt;</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> &lt;hi&gt;&lt;/hi&gt;</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=\\"\\">&lt;test&gt;foo bar&lt;/test&gt;</span></div>
</li>
</ul>"

View File

@@ -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,
};

View File

@@ -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
View File

@@ -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: