Commit e4420940 authored by Andrew Fontaine's avatar Andrew Fontaine

Merge branch 'ph/fixExtensionVirtualScroller' into 'master'

Fixes a rendering bug in the widget extensions virtual scroller

See merge request gitlab-org/gitlab!78286
parents d77932f3 288af487
...@@ -8,9 +8,9 @@ import { ...@@ -8,9 +8,9 @@ import {
} from '@gitlab/ui'; } from '@gitlab/ui';
import { once } from 'lodash'; import { once } from 'lodash';
import * as Sentry from '@sentry/browser'; import * as Sentry from '@sentry/browser';
import { DynamicScroller, DynamicScrollerItem } from 'vendor/vue-virtual-scroller';
import api from '~/api'; import api from '~/api';
import { sprintf, s__, __ } from '~/locale'; import { sprintf, s__, __ } from '~/locale';
import SmartVirtualList from '~/vue_shared/components/smart_virtual_list.vue';
import Poll from '~/lib/utils/poll'; import Poll from '~/lib/utils/poll';
import { EXTENSION_ICON_CLASS, EXTENSION_ICONS } from '../../constants'; import { EXTENSION_ICON_CLASS, EXTENSION_ICONS } from '../../constants';
import StatusIcon from './status_icon.vue'; import StatusIcon from './status_icon.vue';
...@@ -30,10 +30,11 @@ export default { ...@@ -30,10 +30,11 @@ export default {
GlButton, GlButton,
GlLoadingIcon, GlLoadingIcon,
GlIntersectionObserver, GlIntersectionObserver,
SmartVirtualList,
StatusIcon, StatusIcon,
Actions, Actions,
ChildContent, ChildContent,
DynamicScroller,
DynamicScrollerItem,
}, },
directives: { directives: {
SafeHtml: GlSafeHtmlDirective, SafeHtml: GlSafeHtmlDirective,
...@@ -186,7 +187,7 @@ export default { ...@@ -186,7 +187,7 @@ export default {
this.fetchFullData(this.$props) this.fetchFullData(this.$props)
.then((data) => { .then((data) => {
this.loadingState = null; this.loadingState = null;
this.fullData = data; this.fullData = data.map((x, i) => ({ id: i, ...x }));
}) })
.catch((e) => { .catch((e) => {
this.loadingState = LOADING_STATES.expandedError; this.loadingState = LOADING_STATES.expandedError;
...@@ -276,34 +277,33 @@ export default { ...@@ -276,34 +277,33 @@ export default {
<div v-if="isLoadingExpanded" class="report-block-container"> <div v-if="isLoadingExpanded" class="report-block-container">
<gl-loading-icon size="sm" inline /> {{ __('Loading...') }} <gl-loading-icon size="sm" inline /> {{ __('Loading...') }}
</div> </div>
<smart-virtual-list <dynamic-scroller
v-else-if="hasFullData" v-else-if="hasFullData"
:length="fullData.length" :items="fullData"
:remain="20" :min-item-size="32"
:size="32"
wtag="ul"
wclass="report-block-list"
class="report-block-container gl-px-5 gl-py-0" class="report-block-container gl-px-5 gl-py-0"
> >
<li <template #default="{ item, index, active }">
v-for="(data, index) in fullData" <dynamic-scroller-item :item="item" :active="active" :class="{ active }">
:key="data.id" <div
:class="{ :class="{
'gl-border-b-solid gl-border-b-1 gl-border-gray-100': index !== fullData.length - 1, 'gl-border-b-solid gl-border-b-1 gl-border-gray-100': index !== fullData.length - 1,
}" }"
class="gl-py-3 gl-pl-7" class="gl-py-3 gl-pl-7"
data-testid="extension-list-item" data-testid="extension-list-item"
> >
<gl-intersection-observer <gl-intersection-observer
:options="{ rootMargin: '100px', thresholds: 0.1 }" :options="{ rootMargin: '100px', thresholds: 0.1 }"
class="gl-w-full" class="gl-w-full"
@appear="appear(index)" @appear="appear(index)"
@disappear="disappear(index)" @disappear="disappear(index)"
> >
<child-content :data="data" :widget-label="widgetLabel" :level="2" /> <child-content :data="item" :widget-label="widgetLabel" :level="2" />
</gl-intersection-observer> </gl-intersection-observer>
</li> </div>
</smart-virtual-list> </dynamic-scroller-item>
</template>
</dynamic-scroller>
<div <div
:class="{ show: showFade }" :class="{ show: showFade }"
class="fade mr-extenson-scrim gl-absolute gl-left-0 gl-bottom-0 gl-w-full gl-h-7 gl-pointer-events-none" class="fade mr-extenson-scrim gl-absolute gl-left-0 gl-bottom-0 gl-w-full gl-h-7 gl-pointer-events-none"
......
...@@ -745,6 +745,10 @@ $tabs-holder-z-index: 250; ...@@ -745,6 +745,10 @@ $tabs-holder-z-index: 250;
} }
} }
.mr-section-container .resize-observer > object {
height: 0;
}
// TODO: Move to GitLab UI // TODO: Move to GitLab UI
.mr-extenson-scrim { .mr-extenson-scrim {
background: linear-gradient(to bottom, rgba($gray-light, 0), rgba($gray-light, 1)); background: linear-gradient(to bottom, rgba($gray-light, 0), rgba($gray-light, 1));
......
...@@ -100,15 +100,15 @@ describe('Accessibility extension', () => { ...@@ -100,15 +100,15 @@ describe('Accessibility extension', () => {
await waitForPromises(); await waitForPromises();
}); });
it('displays all report list items', async () => { it('displays all report list items in viewport', async () => {
expect(findAllExtensionListItems()).toHaveLength(10); expect(findAllExtensionListItems()).toHaveLength(7);
}); });
it('displays report list item formatted', () => { it('displays report list item formatted', () => {
const text = { const text = {
newError: trimText(findAllExtensionListItems().at(0).text()), newError: trimText(findAllExtensionListItems().at(0).text()),
resolvedError: findAllExtensionListItems().at(3).text(), resolvedError: findAllExtensionListItems().at(3).text(),
existingError: trimText(findAllExtensionListItems().at(8).text()), existingError: trimText(findAllExtensionListItems().at(6).text()),
}; };
expect(text.newError).toBe( expect(text.newError).toBe(
...@@ -118,7 +118,7 @@ describe('Accessibility extension', () => { ...@@ -118,7 +118,7 @@ describe('Accessibility extension', () => {
'The accessibility scanning found an error of the following type: WCAG2AA.Principle1.Guideline1_1.1_1_1.H30.2 Learn more Message: Img element is the only content of the link, but is missing alt text. The alt text should describe the purpose of the link.', 'The accessibility scanning found an error of the following type: WCAG2AA.Principle1.Guideline1_1.1_1_1.H30.2 Learn more Message: Img element is the only content of the link, but is missing alt text. The alt text should describe the purpose of the link.',
); );
expect(text.existingError).toBe( expect(text.existingError).toBe(
'The accessibility scanning found an error of the following type: WCAG2AA.Principle2.Guideline2_4.2_4_1.H64.1 Learn more Message: Iframe element requires a non-empty title attribute that identifies the frame.', 'The accessibility scanning found an error of the following type: WCAG2AA.Principle1.Guideline1_1.1_1_1.H37 Learn more Message: Img element missing an alt attribute. Use the alt attribute to specify a short text alternative.',
); );
}); });
}); });
......
...@@ -947,6 +947,8 @@ describe('MrWidgetOptions', () => { ...@@ -947,6 +947,8 @@ describe('MrWidgetOptions', () => {
wrapper.find('[data-testid="widget-extension-top-level"]').find(GlDropdown).exists(), wrapper.find('[data-testid="widget-extension-top-level"]').find(GlDropdown).exists(),
).toBe(false); ).toBe(false);
await nextTick();
const collapsedSection = wrapper.find('[data-testid="widget-extension-collapsed-section"]'); const collapsedSection = wrapper.find('[data-testid="widget-extension-collapsed-section"]');
expect(collapsedSection.exists()).toBe(true); expect(collapsedSection.exists()).toBe(true);
expect(collapsedSection.text()).toContain('Hello world'); expect(collapsedSection.text()).toContain('Hello world');
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment