Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,868 changes: 1,088 additions & 780 deletions frontend/package-lock.json

Large diffs are not rendered by default.

37 changes: 29 additions & 8 deletions frontend/src/components/LogRecord.vue
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
<script setup lang="ts">
import JsonData from '@/components/json/JsonData.vue';
import type LogRecord from '@/models/LogRecord';
import {isEmptyJson, prettyFormatJson} from '@/services/JsonFormatter';
import {ref} from 'vue';

const expanded = ref(false);
defineProps<{
logRecord: LogRecord
}>()
const styled = ref(true);
defineProps<{ logRecord: LogRecord }>()
const emit = defineEmits(['search']);

function click(value: string) {
emit('search', value);
}
</script>

<template>
Expand All @@ -20,14 +25,21 @@ defineProps<{
<span :class="['pe-2', logRecord.level_class ]">{{ logRecord.level_name }}</span>
<span>{{ logRecord.text }}</span>
</div>
<div class="border-top pt-2 ps-4 mb-2" v-bind:class="{'d-block': expanded, 'd-none': !expanded}" v-if="expanded">
<div class="border-top pt-2 ps-2 mb-2 position-relative" v-bind:class="{'d-block': expanded, 'd-none': !expanded}" v-if="expanded">
<button class="btn btn-outline-secondary slv-btn-raw" @click="styled = !styled">{{ styled ? 'raw' : 'styled' }}</button>
<div v-if="!isEmptyJson(logRecord.context)">
<div class="fw-bold">Context</div>
<pre class="m-0"><code>{{ prettyFormatJson(logRecord.context) }}</code></pre>
<div class="fw-bold">Context:</div>
<json-data v-if="styled" path="context:" :data=logRecord.context @click="click"></json-data>
<div v-else>
<pre class="ms-0"><code>{{ prettyFormatJson(logRecord.context) }}</code></pre>
</div>
</div>
<div v-if="!isEmptyJson(logRecord.extra)">
<div class="fw-bold">Extra</div>
<pre class="m-0"><code>{{ prettyFormatJson(logRecord.extra) }}</code></pre>
<div class="fw-bold">Extra:</div>
<json-data v-if="styled" path="extra:" :data=logRecord.extra @click="click"></json-data>
<div v-else>
<pre class="ms-0"><code>{{ prettyFormatJson(logRecord.extra) }}</code></pre>
</div>
</div>
</div>
</div>
Expand All @@ -42,4 +54,13 @@ defineProps<{
.slv-list-link {
cursor: pointer;
}

.slv-btn-raw {
position: absolute;
top: 5px;
right: 5px;
--bs-btn-padding-y: .25rem;
--bs-btn-padding-x: .5rem;
--bs-btn-font-size: .75rem;
}
</style>
4 changes: 2 additions & 2 deletions frontend/src/components/datepicker/DatePicker.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ const emit = defineEmits(['change']);

const active = ref(false);
const dateExpanded = ref<'none' | 'startDate' | 'endDate'>('none');
let startDate = reactive<DateSelection>({
const startDate = reactive<DateSelection>({
date: getRelativeDate(15, 'i', true),
mode: 'relative',
value: '15i',
formatted: formatRelativeDate(15, 'i')
});
let endDate = reactive<DateSelection>({date: new Date(), mode: 'now', value: null, formatted: 'now'});
const endDate = reactive<DateSelection>({date: new Date(), mode: 'now', value: null, formatted: 'now'});
let currentValue: string | null = null;

onMounted(() => onBetweenChanged());
Expand Down
36 changes: 36 additions & 0 deletions frontend/src/components/json/JsonData.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<script setup lang="ts">
import JsonValue from '@/components/json/JsonValue.vue';
import Objects from '@/services/Objects.ts';

const props = defineProps<{ path: string, data: { [key: string]: unknown } | string }>();
const emit = defineEmits(['click']);

function click(value: string) {
emit('click', value);
}
</script>

<template>
<div v-if="Objects.isObject(props.data)">
<div v-for="(value, key) in props.data"
v-bind:key="key"
class="slv-indent"
:class="{'slv-key-value': Objects.isObject(value) === false && Array.isArray(value) === false }">
<div class="text-warning">{{ key }}:</div>
<json-value :path="props.path + key + '.'" :data=value @click=click></json-value>
</div>
</div>
<json-value v-else :path=props.path :data=props.data @click=click></json-value>
</template>

<style scoped>
.slv-key-value {
display: grid;
grid-column-gap: 10px;
grid-template-columns: auto 1fr;
}

.slv-indent {
padding-left: 15px;
}
</style>
33 changes: 33 additions & 0 deletions frontend/src/components/json/JsonScalarValue.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<script setup lang="ts">
import Numbers from '@/services/Numbers.ts';
import Strings from '@/services/Strings.ts';

const props = defineProps<{ path: string, data: unknown }>();
const emit = defineEmits(['click']);

function click(value: unknown) {
emit('click', `${Strings.trim(props.path, '.')}="${value}"`);
}
</script>

<template>
<div v-if="props.data === null">
<span class="slv-json-value text-info" title="type: null" @click="click(props.data)">null</span>
</div>
<div v-else-if="typeof props.data === 'boolean'">
<span class="slv-json-value text-info" title="type: boolean" @click="click(props.data)">{{ props.data ? 'true' : 'false' }}</span>
</div>
<div v-else-if="Numbers.numeric(data)">
<span class="slv-json-value text-info" :title="'type: ' + typeof props.data" @click="click(props.data)">{{ props.data }}</span>
</div>
<div v-else>
<span class="slv-json-value" :title="'type: ' + typeof props.data" @click="click(props.data)">{{ props.data }}</span>
</div>
</template>

<style scoped>
.slv-json-value:hover {
text-decoration: underline;
cursor: pointer;
}
</style>
32 changes: 32 additions & 0 deletions frontend/src/components/json/JsonValue.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<script setup lang="ts">
import JsonData from '@/components/json/JsonData.vue';
import JsonScalarValue from '@/components/json/JsonScalarValue.vue';
import JsonValue from '@/components/json/JsonValue.vue';
import Objects from '@/services/Objects.ts';

const props = defineProps<{ path: string, data: unknown }>();
const emit = defineEmits(['click']);

function click(value: string) {
emit('click', value);
}
</script>

<template>
<div v-if="Array.isArray(props.data)">
<ul class="m-0 slv-array-list">
<li v-for="(val, key) in props.data" :key=key>
<json-data v-if="Objects.isObject(val)" :path="props.path + key + '.'" :data=val @click=click></json-data>
<json-value v-else :path="props.path + key + '.'" :data=val @click=click></json-value>
</li>
</ul>
</div>
<json-data v-else-if="Objects.isObject(props.data)" :path=props.path :data="props.data" @click=click></json-data>
<json-scalar-value v-else :path=props.path :data=props.data @click=click></json-scalar-value>
</template>

<style scoped>
.slv-array-list {
list-style: square;
}
</style>
10 changes: 10 additions & 0 deletions frontend/src/services/Numbers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,14 @@ export default class Numbers {
}
return number;
}

public static numeric(value: unknown): boolean {
if (typeof value === 'number') {
return true;
}
if (typeof value === 'string') {
return isNaN(Number(value)) === false;
}
return false;
}
}
5 changes: 5 additions & 0 deletions frontend/src/services/Objects.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export default class Objects {
public static isObject(value: unknown): value is {[key: string]: unknown} {
return value !== null && typeof value === 'object' && Array.isArray(value) === false;
}
}
13 changes: 13 additions & 0 deletions frontend/src/services/Strings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export default class Strings {

public static trim(str: string, toRemove: string): string {
while (str.startsWith(toRemove)) {
str = str.substring(toRemove.length);
}
while (str.endsWith(toRemove)) {
str = str.substring(0, str.length - toRemove.length);
}

return str;
}
}
62 changes: 35 additions & 27 deletions frontend/src/views/LogView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -22,38 +22,38 @@ const badRequest = ref(false);
const navigate = () => {
const fileOffset = offset.value > 0 && logRecordStore.records.paginator?.direction !== searchStore.sort ? 0 : offset.value;
const params = new ParameterBag()
.set('host', hostsStore.selected, 'localhost')
.set('file', searchStore.files.join(','))
.set('query', searchStore.query, '')
.set('between', searchStore.between, '')
.set('per_page', searchStore.perPage, '100')
.set('sort', searchStore.sort, 'desc')
.set('offset', fileOffset, 0);
router.push({query: <Record<string, LocationQueryValueRaw>>params.all()});
}

const load = () => {
badRequest.value = false;
logRecordStore
.fetch(new ParameterBag()
.set('host', hostsStore.selected, 'localhost')
.set('file', searchStore.files.join(','))
.set('query', searchStore.query, '')
.set('between', searchStore.between, '')
.set('per_page', searchStore.perPage, '100')
.set('sort', searchStore.sort, 'desc')
.set('offset', offset.value, 0)
.set('time_zone', Intl.DateTimeFormat().resolvedOptions().timeZone))
.catch((error: Error) => {
if (error.message === 'bad-request') {
badRequest.value = true;
return;
}
router.push({name: error.message});
})
.finally(() => {
searchRef.value?.focus();
});
.set('offset', fileOffset, 0);
router.push({query: <Record<string, LocationQueryValueRaw>>params.all()});
}

const load = () => {
badRequest.value = false;
logRecordStore
.fetch(new ParameterBag()
.set('host', hostsStore.selected, 'localhost')
.set('file', searchStore.files.join(','))
.set('query', searchStore.query, '')
.set('between', searchStore.between, '')
.set('per_page', searchStore.perPage, '100')
.set('sort', searchStore.sort, 'desc')
.set('offset', offset.value, 0)
.set('time_zone', Intl.DateTimeFormat().resolvedOptions().timeZone))
.catch((error: Error) => {
if (error.message === 'bad-request') {
badRequest.value = true;
return;
}
router.push({name: error.message});
})
.finally(() => {
searchRef.value?.focus();
});
}

onMounted(() => {
Expand All @@ -66,6 +66,11 @@ onMounted(() => {
offset.value = parseInt(String(route.query.offset ?? '0'));
load();
});

function onSearchRequest(value: string) {
searchStore.query = value;
navigate();
}
</script>

<template>
Expand All @@ -87,7 +92,10 @@ onMounted(() => {

<main class="overflow-auto d-none d-md-block slv-loadable" v-bind:class="{ 'slv-loading': logRecordStore.loading }">
<div class="slv-entries list-group pt-1 pe-1 pb-3">
<log-record :logRecord="record" v-for="(record, index) in logRecordStore.records.logs ?? []" v-bind:key="index"></log-record>
<log-record :logRecord="record"
v-for="(record, index) in logRecordStore.records.logs ?? []"
v-bind:key="index"
@search="onSearchRequest"></log-record>
</div>
</main>

Expand Down
4 changes: 2 additions & 2 deletions src/Resources/public/.vite/manifest.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
{
"src/main.ts": {
"file": "assets/main-B_Df2OVf.js",
"file": "assets/main-BJo1MZqw.js",
"name": "main",
"src": "src/main.ts",
"isEntry": true
},
"style.css": {
"file": "assets/style-iL1b4RUl.css",
"file": "assets/style-Coso1hMk.css",
"src": "style.css"
}
}
Loading