Skip to content

Commit 7ee2603

Browse files
authored
feat: improves the loader for logs (#3404)
1 parent 011294d commit 7ee2603

File tree

6 files changed

+81
-30
lines changed

6 files changed

+81
-30
lines changed

assets/components.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ declare module 'vue' {
4242
HostList: typeof import('./components/HostList.vue')['default']
4343
HostMenu: typeof import('./components/HostMenu.vue')['default']
4444
'Ic:sharpKeyboardReturn': typeof import('~icons/ic/sharp-keyboard-return')['default']
45+
IndeterminateBar: typeof import('./components/common/IndeterminateBar.vue')['default']
4546
InfiniteLoader: typeof import('./components/InfiniteLoader.vue')['default']
4647
KeyShortcut: typeof import('./components/common/KeyShortcut.vue')['default']
4748
LabeledInput: typeof import('./components/common/LabeledInput.vue')['default']
Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
<template>
22
<InfiniteLoader :onLoadMore="fetchMore" :enabled="!loadingMore && messages.length > 10" />
3-
<div v-if="!opened" class="m-4 text-center">
4-
<span class="loading loading-ring loading-md text-primary"></span>
5-
</div>
6-
<slot :messages="messages"></slot>
3+
<ul role="status" class="flex animate-pulse flex-col gap-4 p-4" v-if="loading || noLogs">
4+
<div class="flex flex-row gap-2" v-for="size in ['w-3/5', 'w-2/3', 'w-9/12', 'w-1/2']">
5+
<div class="h-3 w-40 shrink-0 rounded-full bg-base-content/50 opacity-50"></div>
6+
<div class="h-3 rounded-full bg-base-content/50 opacity-50" :class="size"></div>
7+
</div>
8+
<span class="sr-only">Loading...</span>
9+
</ul>
10+
<slot :messages="messages" v-else></slot>
11+
<IndeterminateBar :color />
712
</template>
813

914
<script lang="ts" setup generic="T">
@@ -14,10 +19,16 @@ const { entity, streamSource } = $defineProps<{
1419
entity: T;
1520
}>();
1621
17-
const { messages, loadOlderLogs, isLoadingMore, opened } = streamSource($$(entity));
22+
const { messages, loadOlderLogs, isLoadingMore, opened, loading, error } = streamSource($$(entity));
1823
const { loadingMore } = useLoggingContext();
24+
const color = computed(() => {
25+
if (error.value) return "error";
26+
if (loading.value) return "secondary";
27+
if (opened.value) return "primary";
28+
return "error";
29+
});
1930
20-
const enabled = ref(true);
31+
const noLogs = computed(() => messages.value.length === 0);
2132
2233
defineExpose({
2334
clear: () => (messages.value = []),
@@ -26,10 +37,8 @@ defineExpose({
2637
const fetchMore = async () => {
2738
if (!isLoadingMore.value) {
2839
loadingMore.value = true;
29-
enabled.value = false;
3040
await loadOlderLogs();
3141
loadingMore.value = false;
32-
enabled.value = true;
3342
}
3443
};
3544
</script>

assets/components/LogViewer/__snapshots__/EventSource.spec.ts.snap

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,25 @@ exports[`<ContainerEventSource /> > render html correctly > should render messag
5959

6060
exports[`<ContainerEventSource /> > renders loading correctly 1`] = `
6161
"<div class="flex min-h-[1px] justify-center"><span class="loading loading-bars loading-md mt-4 text-primary" style="display: none;"></span></div>
62-
<div class="m-4 text-center"><span class="loading loading-ring loading-md text-primary"></span></div>
63-
<ul data-v-cf9ff940="" class="events group pt-4 medium"></ul>"
62+
<ul role="status" class="flex animate-pulse flex-col gap-4 p-4">
63+
<div class="flex flex-row gap-2">
64+
<div class="h-3 w-40 shrink-0 rounded-full bg-base-content/50 opacity-50"></div>
65+
<div class="h-3 rounded-full bg-base-content/50 opacity-50 w-3/5"></div>
66+
</div>
67+
<div class="flex flex-row gap-2">
68+
<div class="h-3 w-40 shrink-0 rounded-full bg-base-content/50 opacity-50"></div>
69+
<div class="h-3 rounded-full bg-base-content/50 opacity-50 w-2/3"></div>
70+
</div>
71+
<div class="flex flex-row gap-2">
72+
<div class="h-3 w-40 shrink-0 rounded-full bg-base-content/50 opacity-50"></div>
73+
<div class="h-3 rounded-full bg-base-content/50 opacity-50 w-9/12"></div>
74+
</div>
75+
<div class="flex flex-row gap-2">
76+
<div class="h-3 w-40 shrink-0 rounded-full bg-base-content/50 opacity-50"></div>
77+
<div class="h-3 rounded-full bg-base-content/50 opacity-50 w-1/2"></div>
78+
</div><span class="sr-only">Loading...</span>
79+
</ul>
80+
<div data-v-2dbf2928="" class="animate-background h-1 w-1/2 bg-gradient-radial to-transparent to-75% from-secondary"></div>"
6481
`;
6582

6683
exports[`<ContainerEventSource /> > should parse messages 1`] = `

assets/components/ScrollableView.vue

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,7 @@
2121
<div ref="scrollableContent">
2222
<slot></slot>
2323
</div>
24-
<div
25-
class="animate-background h-1 w-1/2 bg-gradient-radial from-primary to-transparent to-75%"
26-
v-show="!scrollContext.paused"
27-
></div>
24+
2825
<div ref="scrollObserver" class="h-px"></div>
2926
</main>
3027

@@ -90,20 +87,6 @@ function scrollToBottom(behavior: "auto" | "smooth" = "auto") {
9087
.fade-leave-to {
9188
@apply opacity-0;
9289
}
93-
94-
.animate-background {
95-
animation: gradient-animation 3s ease-out infinite;
96-
}
97-
98-
@keyframes gradient-animation {
99-
0%,
100-
100% {
101-
transform: translateX(0%);
102-
}
103-
50% {
104-
transform: translateX(100%);
105-
}
106-
}
10790
</style>
10891

10992
<style>
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<template>
2+
<div class="animate-background h-1 w-1/2 bg-gradient-radial to-transparent to-75%" :class="colorClass"></div>
3+
</template>
4+
<script setup lang="ts">
5+
const { color = "primary" } = defineProps<{ color: "primary" | "error" | "secondary" }>();
6+
7+
const colorClass = computed(() => {
8+
switch (color) {
9+
case "primary":
10+
return "from-primary";
11+
case "error":
12+
return "from-error";
13+
case "secondary":
14+
return "from-secondary";
15+
}
16+
});
17+
</script>
18+
19+
<style scoped lang="postcss">
20+
.animate-background {
21+
animation: gradient-animation 3s ease-out infinite;
22+
}
23+
24+
@keyframes gradient-animation {
25+
0%,
26+
100% {
27+
transform: translateX(0%);
28+
}
29+
50% {
30+
transform: translateX(100%);
31+
}
32+
}
33+
</style>

assets/composable/eventStreams.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ function useLogStream(url: Ref<string>, loadMoreUrl?: Ref<string>) {
5353
const messages: ShallowRef<LogEntry<string | JSONObject>[]> = shallowRef([]);
5454
const buffer: ShallowRef<LogEntry<string | JSONObject>[]> = shallowRef([]);
5555
const opened = ref(false);
56+
const loading = ref(true);
57+
const error = ref(false);
5658
const { paused: scrollingPaused } = useScrollContext();
5759

5860
function flushNow() {
@@ -124,6 +126,8 @@ function useLogStream(url: Ref<string>, loadMoreUrl?: Ref<string>) {
124126
close();
125127
if (clear) clearMessages();
126128
opened.value = false;
129+
loading.value = true;
130+
error.value = false;
127131
es = new EventSource(urlWithParams.value);
128132
es.addEventListener("container-event", (e) => {
129133
const event = JSON.parse((e as MessageEvent).data) as { actorId: string; name: string };
@@ -151,9 +155,13 @@ function useLogStream(url: Ref<string>, loadMoreUrl?: Ref<string>) {
151155
flushBuffer();
152156
}
153157
};
154-
es.onerror = () => clearMessages();
158+
es.onerror = () => {
159+
error.value = true;
160+
};
155161
es.onopen = () => {
162+
loading.value = false;
156163
opened.value = true;
164+
error.value = false;
157165
};
158166
}
159167

@@ -210,5 +218,5 @@ function useLogStream(url: Ref<string>, loadMoreUrl?: Ref<string>) {
210218
}
211219
});
212220

213-
return { messages, loadOlderLogs, isLoadingMore, hasComplexLogs, opened };
221+
return { messages, loadOlderLogs, isLoadingMore, hasComplexLogs, opened, error, loading };
214222
}

0 commit comments

Comments
 (0)