Commit 37c24661 authored by GitLab Bot's avatar GitLab Bot

Automatic merge of gitlab-org/gitlab-ce master

parents 65dae368 bf172b11
...@@ -8,12 +8,14 @@ import SystemNote from '~/vue_shared/components/notes/system_note.vue'; ...@@ -8,12 +8,14 @@ import SystemNote from '~/vue_shared/components/notes/system_note.vue';
import NoteableNote from './noteable_note.vue'; import NoteableNote from './noteable_note.vue';
import ToggleRepliesWidget from './toggle_replies_widget.vue'; import ToggleRepliesWidget from './toggle_replies_widget.vue';
import NoteEditedText from './note_edited_text.vue'; import NoteEditedText from './note_edited_text.vue';
import DiscussionNotesRepliesWrapper from './discussion_notes_replies_wrapper.vue';
export default { export default {
name: 'DiscussionNotes', name: 'DiscussionNotes',
components: { components: {
ToggleRepliesWidget, ToggleRepliesWidget,
NoteEditedText, NoteEditedText,
DiscussionNotesRepliesWrapper,
}, },
props: { props: {
discussion: { discussion: {
...@@ -119,9 +121,7 @@ export default { ...@@ -119,9 +121,7 @@ export default {
/> />
<slot slot="avatar-badge" name="avatar-badge"></slot> <slot slot="avatar-badge" name="avatar-badge"></slot>
</component> </component>
<div <discussion-notes-replies-wrapper :is-diff-discussion="discussion.diff_discussion">
:class="discussion.diff_discussion ? 'discussion-collapsible bordered-box clearfix' : ''"
>
<toggle-replies-widget <toggle-replies-widget
v-if="hasReplies" v-if="hasReplies"
:collapsed="!isExpanded" :collapsed="!isExpanded"
...@@ -141,7 +141,7 @@ export default { ...@@ -141,7 +141,7 @@ export default {
/> />
</template> </template>
<slot :show-replies="isExpanded || !hasReplies" name="footer"></slot> <slot :show-replies="isExpanded || !hasReplies" name="footer"></slot>
</div> </discussion-notes-replies-wrapper>
</template> </template>
<template v-else> <template v-else>
<component <component
......
<script>
/**
* Wrapper for discussion notes replies section.
*
* This is a functional component using the render method because in some cases
* the wrapper is not needed and we want to simply render along the children.
*/
export default {
functional: true,
props: {
isDiffDiscussion: {
type: Boolean,
required: false,
default: false,
},
},
render(h, { props, children }) {
if (props.isDiffDiscussion) {
return h('li', { class: 'discussion-collapsible bordered-box clearfix' }, [
h('ul', { class: 'notes' }, children),
]);
}
return children;
},
};
</script>
...@@ -1095,6 +1095,10 @@ table.code { ...@@ -1095,6 +1095,10 @@ table.code {
.discussion-collapsible { .discussion-collapsible {
margin: 0 $gl-padding $gl-padding 71px; margin: 0 $gl-padding $gl-padding 71px;
.notes {
border-radius: $border-radius-default;
}
} }
.parallel { .parallel {
......
...@@ -139,7 +139,6 @@ $note-form-margin-left: 72px; ...@@ -139,7 +139,6 @@ $note-form-margin-left: 72px;
border-radius: 4px 4px 0 0; border-radius: 4px 4px 0 0;
&.collapsed { &.collapsed {
border: 0;
border-radius: 4px; border-radius: 4px;
} }
} }
......
...@@ -173,8 +173,12 @@ module ReactiveCaching ...@@ -173,8 +173,12 @@ module ReactiveCaching
end end
def within_reactive_cache_lifetime?(*args) def within_reactive_cache_lifetime?(*args)
if Feature.enabled?(:reactive_caching_check_key_exists, default_enabled: true)
Rails.cache.exist?(alive_reactive_cache_key(*args))
else
!!Rails.cache.read(alive_reactive_cache_key(*args)) !!Rails.cache.read(alive_reactive_cache_key(*args))
end end
end
def enqueuing_update(*args) def enqueuing_update(*args)
yield yield
......
---
title: Allow ReactiveCaching to support nil value
merge_request: 30456
author:
type: performance
import { mount } from '@vue/test-utils';
import DiscussionNotesRepliesWrapper from '~/notes/components/discussion_notes_replies_wrapper.vue';
const TEST_CHILDREN = '<li>Hello!</li><li>World!</li>';
// We have to wrap our SUT with a TestComponent because multiple roots are possible
// because it's a functional component.
const TestComponent = {
components: { DiscussionNotesRepliesWrapper },
template: `<ul><discussion-notes-replies-wrapper v-bind="$attrs">${TEST_CHILDREN}</discussion-notes-replies-wrapper></ul>`,
};
describe('DiscussionNotesRepliesWrapper', () => {
let wrapper;
const createComponent = (props = {}) => {
wrapper = mount(TestComponent, {
propsData: props,
sync: false,
});
};
afterEach(() => {
wrapper.destroy();
});
describe('when normal discussion', () => {
beforeEach(() => {
createComponent();
});
it('renders children directly', () => {
expect(wrapper.html()).toEqual(`<ul>${TEST_CHILDREN}</ul>`);
});
});
describe('when diff discussion', () => {
beforeEach(() => {
createComponent({
isDiffDiscussion: true,
});
});
it('wraps children with notes', () => {
const notes = wrapper.find('li.discussion-collapsible ul.notes');
expect(notes.exists()).toBe(true);
expect(notes.html()).toEqual(`<ul class="notes">${TEST_CHILDREN}</ul>`);
});
});
});
...@@ -10,6 +10,7 @@ describe('InlineDiffView', () => { ...@@ -10,6 +10,7 @@ describe('InlineDiffView', () => {
let component; let component;
const getDiffFileMock = () => Object.assign({}, diffFileMockData); const getDiffFileMock = () => Object.assign({}, diffFileMockData);
const getDiscussionsMockData = () => [Object.assign({}, discussionsMockData)]; const getDiscussionsMockData = () => [Object.assign({}, discussionsMockData)];
const notesLength = getDiscussionsMockData()[0].notes.length;
beforeEach(done => { beforeEach(done => {
const diffFile = getDiffFileMock(); const diffFile = getDiffFileMock();
...@@ -40,7 +41,7 @@ describe('InlineDiffView', () => { ...@@ -40,7 +41,7 @@ describe('InlineDiffView', () => {
Vue.nextTick(() => { Vue.nextTick(() => {
expect(el.querySelectorAll('.notes_holder').length).toEqual(1); expect(el.querySelectorAll('.notes_holder').length).toEqual(1);
expect(el.querySelectorAll('.notes_holder .note-discussion li').length).toEqual(6); expect(el.querySelectorAll('.notes_holder .note').length).toEqual(notesLength + 1);
expect(el.innerText.indexOf('comment 5')).toBeGreaterThan(-1); expect(el.innerText.indexOf('comment 5')).toBeGreaterThan(-1);
component.$store.dispatch('setInitialNotes', []); component.$store.dispatch('setInitialNotes', []);
......
...@@ -47,30 +47,12 @@ describe ReactiveCaching, :use_clean_rails_memory_store_caching do ...@@ -47,30 +47,12 @@ describe ReactiveCaching, :use_clean_rails_memory_store_caching do
subject(:go!) { instance.result } subject(:go!) { instance.result }
context 'when cache is empty' do shared_examples 'a cacheable value' do |cached_value|
it { is_expected.to be_nil }
it 'enqueues a background worker to bootstrap the cache' do
expect(ReactiveCachingWorker).to receive(:perform_async).with(CacheTest, 666)
go!
end
it 'updates the cache lifespan' do
expect(reactive_cache_alive?(instance)).to be_falsy
go!
expect(reactive_cache_alive?(instance)).to be_truthy
end
end
context 'when the cache is full' do
before do before do
stub_reactive_cache(instance, 4) stub_reactive_cache(instance, cached_value)
end end
it { is_expected.to eq(4) } it { is_expected.to eq(cached_value) }
it 'does not enqueue a background worker' do it 'does not enqueue a background worker' do
expect(ReactiveCachingWorker).not_to receive(:perform_async) expect(ReactiveCachingWorker).not_to receive(:perform_async)
...@@ -90,9 +72,7 @@ describe ReactiveCaching, :use_clean_rails_memory_store_caching do ...@@ -90,9 +72,7 @@ describe ReactiveCaching, :use_clean_rails_memory_store_caching do
end end
it { is_expected.to be_nil } it { is_expected.to be_nil }
end
context 'when cache was invalidated' do
it 'refreshes cache' do it 'refreshes cache' do
expect(ReactiveCachingWorker).to receive(:perform_async).with(CacheTest, 666) expect(ReactiveCachingWorker).to receive(:perform_async).with(CacheTest, 666)
...@@ -101,12 +81,34 @@ describe ReactiveCaching, :use_clean_rails_memory_store_caching do ...@@ -101,12 +81,34 @@ describe ReactiveCaching, :use_clean_rails_memory_store_caching do
end end
end end
context 'when cache contains non-nil but blank value' do context 'when cache is empty' do
before do it { is_expected.to be_nil }
stub_reactive_cache(instance, false)
it 'enqueues a background worker to bootstrap the cache' do
expect(ReactiveCachingWorker).to receive(:perform_async).with(CacheTest, 666)
go!
end
it 'updates the cache lifespan' do
expect(reactive_cache_alive?(instance)).to be_falsy
go!
expect(reactive_cache_alive?(instance)).to be_truthy
end
end
context 'when the cache is full' do
it_behaves_like 'a cacheable value', 4
end
context 'when the cache contains non-nil but blank value' do
it_behaves_like 'a cacheable value', false
end end
it { is_expected.to eq(false) } context 'when the cache contains nil value' do
it_behaves_like 'a cacheable value', nil
end end
end end
......
...@@ -10,7 +10,7 @@ module ReactiveCachingHelpers ...@@ -10,7 +10,7 @@ module ReactiveCachingHelpers
def stub_reactive_cache(subject = nil, data = nil, *qualifiers) def stub_reactive_cache(subject = nil, data = nil, *qualifiers)
allow(ReactiveCachingWorker).to receive(:perform_async) allow(ReactiveCachingWorker).to receive(:perform_async)
allow(ReactiveCachingWorker).to receive(:perform_in) allow(ReactiveCachingWorker).to receive(:perform_in)
write_reactive_cache(subject, data, *qualifiers) unless data.nil? write_reactive_cache(subject, data, *qualifiers) unless subject.nil?
end end
def synchronous_reactive_cache(subject) def synchronous_reactive_cache(subject)
......
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