Skip to content

Commit a24feaf

Browse files
authored
Merge pull request #26 from buggregator/issue/#17-add-virtualisation
Issue/#17 add virtualisation
2 parents 04682f9 + ced9254 commit a24feaf

File tree

4 files changed

+13506
-12862
lines changed

4 files changed

+13506
-12862
lines changed

components/PreviewCard/PreviewCard.vue

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,26 @@
1111
:event-type="event.type"
1212
:event-id="event.id"
1313
:tags="normalizedTags"
14-
:is-open="!isCollapsed"
15-
:is-visible-controls="isVisibleControls"
14+
:is-open="!isCollapsed && !isOptimized"
15+
:is-visible-controls="isVisibleControls && !isOptimized"
1616
@toggle-view="toggle"
1717
@delete="deleteEvent"
1818
@copy="copyCode"
1919
@download="downloadImage"
2020
/>
2121

22-
<div v-if="!isCollapsed" ref="event_body" class="preview-card__body">
22+
<div
23+
v-if="!isCollapsed && !isOptimized"
24+
ref="event_body"
25+
class="preview-card__body"
26+
>
2327
<slot />
2428
</div>
2529

2630
<PreviewCardFooter
27-
v-if="!isCollapsed && (normalizedOrigin || event.serverName)"
31+
v-if="
32+
!isCollapsed && !isOptimized && (normalizedOrigin || event.serverName)
33+
"
2834
class="preview-card__footer"
2935
:server-name="event.serverName"
3036
:origin-config="normalizedOrigin"
@@ -34,8 +40,9 @@
3440

3541
<script lang="ts">
3642
import { defineComponent, PropType } from "vue";
37-
import { toPng, toBlob } from "html-to-image";
43+
import { toBlob, toPng } from "html-to-image";
3844
import download from "downloadjs";
45+
import debounce from "lodash.debounce";
3946
import PreviewCardFooter from "~/components/PreviewCardFooter/PreviewCardFooter.vue";
4047
import PreviewCardHeader from "~/components/PreviewCardHeader/PreviewCardHeader.vue";
4148
import { NormalizedEvent } from "~/config/types";
@@ -50,7 +57,7 @@ export default defineComponent({
5057
},
5158
props: {
5259
event: {
53-
type: Object as PropType<NormalizedEvent<unknown>>,
60+
type: Object as PropType<NormalizedEvent>,
5461
required: true,
5562
},
5663
},
@@ -70,6 +77,7 @@ export default defineComponent({
7077
data() {
7178
return {
7279
isCollapsed: false,
80+
isOptimized: false,
7381
isVisibleControls: true,
7482
};
7583
},
@@ -93,6 +101,12 @@ export default defineComponent({
93101
return `${this.event.type}-${this.event.id}.png`;
94102
},
95103
},
104+
mounted() {
105+
window.addEventListener("scroll", this.optimiseRenderHidden());
106+
},
107+
beforeUnmount() {
108+
window.removeEventListener("scroll", this.optimiseRenderHidden());
109+
},
96110
methods: {
97111
toggle(): void {
98112
this.isCollapsed = !this.isCollapsed;
@@ -131,6 +145,26 @@ export default defineComponent({
131145
});
132146
}
133147
},
148+
optimiseRenderHidden() {
149+
return debounce(() => {
150+
if (this.$refs.event) {
151+
const eventNode = this.$refs.event as HTMLElement;
152+
const { top, height } = eventNode.getBoundingClientRect();
153+
const extraDelta = height;
154+
const isVisible =
155+
top - extraDelta <= window.innerHeight &&
156+
top + height + extraDelta * 2 >= 0;
157+
158+
if (!isVisible && !this.isOptimized) {
159+
this.isOptimized = true;
160+
eventNode.style.height = `${eventNode.clientHeight}px`;
161+
} else if (isVisible && this.isOptimized) {
162+
this.isOptimized = false;
163+
eventNode.style.height = "auto";
164+
}
165+
}
166+
}, 30);
167+
},
134168
},
135169
});
136170
</script>

components/PreviewEventMapper/PreviewEventMapper.stories.ts

Lines changed: 49 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
import { Meta, Story } from "@storybook/vue3";
2-
import PreviewEventMapper from '~/components/PreviewEventMapper/PreviewEventMapper.vue';
3-
import monologEventMock from '~/mocks/monolog.json'
4-
import sentryEventMock from '~/mocks/sentry-spiral.json'
5-
import smtpEventMock from '~/mocks/smtp-welcome.json'
6-
import varDumpEventMock from '~/mocks/var-dump-object.json'
7-
import profilerEventMock from '~/mocks/profiler.json'
8-
import inspectorEventMock from '~/mocks/inspector.json'
9-
import httpDumpEventMock from '~/mocks/http-dump.json'
2+
import PreviewEventMapper from "~/components/PreviewEventMapper/PreviewEventMapper.vue";
3+
import monologEventMock from "~/mocks/monolog.json";
4+
import sentryEventMock from "~/mocks/sentry-spiral.json";
5+
import smtpEventMock from "~/mocks/smtp-welcome.json";
6+
import varDumpEventMock from "~/mocks/var-dump-object.json";
7+
import profilerEventMock from "~/mocks/profiler.json";
8+
import inspectorEventMock from "~/mocks/inspector.json";
9+
import httpDumpEventMock from "~/mocks/http-dump.json";
1010

1111
export default {
1212
title: "Preview/PreviewEventMapper",
13-
component: PreviewEventMapper
13+
component: PreviewEventMapper,
1414
} as Meta<typeof PreviewEventMapper>;
1515

1616
const Template: Story = (args) => ({
@@ -26,7 +26,7 @@ const Template: Story = (args) => ({
2626
export const Default = Template.bind({});
2727

2828
Default.args = {
29-
event: { ...smtpEventMock, type: 'unknown' },
29+
event: { ...smtpEventMock, type: "unknown" },
3030
};
3131

3232
export const Monolog = Template.bind({});
@@ -70,21 +70,57 @@ HttpDump.args = {
7070
event: httpDumpEventMock,
7171
};
7272

73+
const eventsList = [
74+
monologEventMock,
75+
sentryEventMock,
76+
smtpEventMock,
77+
varDumpEventMock,
78+
profilerEventMock,
79+
inspectorEventMock,
80+
httpDumpEventMock,
81+
];
82+
7383
const TemplateList: Story = (args) => ({
7484
components: { PreviewEventMapper },
7585
setup() {
76-
7786
return {
7887
args,
79-
eventsList: [monologEventMock,sentryEventMock,smtpEventMock,varDumpEventMock,profilerEventMock,inspectorEventMock,httpDumpEventMock]
88+
eventsList,
8089
};
8190
},
8291
template: `<PreviewEventMapper class="border-b" v-for="event in eventsList" :event="event" :key="event.uuid"/>`,
8392
});
8493

85-
8694
export const EventsList = TemplateList.bind({});
8795

8896
EventsList.args = {
8997
event: inspectorEventMock,
9098
};
99+
100+
const TemplateListVirtual: Story = (args) => ({
101+
components: { PreviewEventMapper },
102+
setup() {
103+
return {
104+
args,
105+
eventsList: eventsList
106+
.concat(eventsList)
107+
.concat(eventsList)
108+
.concat(eventsList)
109+
.concat(eventsList)
110+
.concat(eventsList)
111+
.map((item, index) => ({ ...item, uuid: String(index + 1) })) // make uniq ids
112+
.sort(() => Math.random() - 0.5), // shuffle
113+
};
114+
},
115+
template: `
116+
<template v-for="item in eventsList">
117+
<PreviewEventMapper class="border-b" :event="item" />
118+
</template>
119+
`,
120+
});
121+
122+
export const EventsListVirtual = TemplateListVirtual.bind({});
123+
124+
EventsListVirtual.args = {
125+
event: inspectorEventMock,
126+
};

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
"@storybook/addon-postcss": "^2.0.0",
3636
"@storybook/builder-vite": "^0.3.0",
3737
"@types/downloadjs": "^1.4.3",
38+
"@types/lodash.debounce": "^4.0.7",
3839
"@typescript-eslint/eslint-plugin": "^5.48.2",
3940
"@typescript-eslint/parser": "^5.48.2",
4041
"@vitejs/plugin-vue": "^4.0.0",
@@ -70,6 +71,7 @@
7071
"flame-chart-js": "^2.3.1",
7172
"highlight.js": "^11.7.0",
7273
"html-to-image": "^1.11.4",
74+
"lodash.debounce": "^4.0.8",
7375
"moment": "^2.29.4",
7476
"nuxt": "3.3.3",
7577
"pinia": "^2.0.30",

0 commit comments

Comments
 (0)