Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
51c05183
Commit
51c05183
authored
Feb 15, 2022
by
Daniel Tian
Committed by
Andrew Fontaine
Feb 15, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Switch to GlTabs for markdown header component
MR: Changelog: changed
parent
63c25c73
Changes
7
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
196 additions
and
163 deletions
+196
-163
app/assets/javascripts/vue_shared/components/markdown/header.vue
...ets/javascripts/vue_shared/components/markdown/header.vue
+132
-123
app/assets/stylesheets/framework/markdown_area.scss
app/assets/stylesheets/framework/markdown_area.scss
+21
-0
ee/spec/features/epics/update_epic_spec.rb
ee/spec/features/epics/update_epic_spec.rb
+4
-4
ee/spec/features/groups/iteration_spec.rb
ee/spec/features/groups/iteration_spec.rb
+3
-3
spec/features/merge_request/user_posts_notes_spec.rb
spec/features/merge_request/user_posts_notes_spec.rb
+2
-2
spec/frontend/vue_shared/components/markdown/field_spec.js
spec/frontend/vue_shared/components/markdown/field_spec.js
+15
-16
spec/frontend/vue_shared/components/markdown/header_spec.js
spec/frontend/vue_shared/components/markdown/header_spec.js
+19
-15
No files found.
app/assets/javascripts/vue_shared/components/markdown/header.vue
View file @
51c05183
<
script
>
import
{
GlPopover
,
GlButton
,
GlTooltipDirective
}
from
'
@gitlab/ui
'
;
import
{
GlPopover
,
GlButton
,
GlTooltipDirective
,
GlTabs
,
GlTab
}
from
'
@gitlab/ui
'
;
import
$
from
'
jquery
'
;
import
{
keysFor
,
BOLD_TEXT
,
ITALIC_TEXT
,
LINK_TEXT
}
from
'
~/behaviors/shortcuts/keybindings
'
;
import
{
getSelectedFragment
}
from
'
~/lib/utils/common_utils
'
;
import
{
s__
}
from
'
~/locale
'
;
import
{
s__
,
__
}
from
'
~/locale
'
;
import
{
CopyAsGFM
}
from
'
../../../behaviors/markdown/copy_as_gfm
'
;
import
ToolbarButton
from
'
./toolbar_button.vue
'
;
...
...
@@ -12,6 +12,8 @@ export default {
ToolbarButton
,
GlPopover
,
GlButton
,
GlTabs
,
GlTab
,
},
directives
:
{
GlTooltip
:
GlTooltipDirective
,
...
...
@@ -144,27 +146,33 @@ export default {
italic
:
keysFor
(
ITALIC_TEXT
),
link
:
keysFor
(
LINK_TEXT
),
},
i18n
:
{
writeTabTitle
:
__
(
'
Write
'
),
previewTabTitle
:
__
(
'
Preview
'
),
},
};
</
script
>
<
template
>
<div
class=
"md-header"
>
<ul
class=
"nav-links clearfix"
>
<li
:class=
"
{ active: !previewMarkdown }" class="md-header-tab">
<button
class=
"js-write-link"
type=
"button"
@
click=
"writeMarkdownTab($event)"
>
{{
__
(
'
Write
'
)
}}
</button>
</li>
<li
:class=
"
{ active: previewMarkdown }" class="md-header-tab">
<button
class=
"js-preview-link js-md-preview-button"
type=
"button"
<gl-tabs
content-class=
"gl-display-none"
>
<gl-tab
title-link-class=
"gl-pt-3 gl-px-3 js-md-write-button"
:title=
"$options.i18n.writeTabTitle"
:active=
"!previewMarkdown"
data-testid=
"write-tab"
@
click=
"writeMarkdownTab($event)"
/>
<gl-tab
title-link-class=
"gl-pt-3 gl-px-3 js-md-preview-button"
:title=
"$options.i18n.previewTabTitle"
:active=
"previewMarkdown"
data-testid=
"preview-tab"
@
click=
"previewMarkdownTab($event)"
>
{{
__
(
'
Preview
'
)
}}
</button>
</li>
<li
:class=
"
{ active: !previewMarkdown }" class="md-header-toolbar">
/>
<template
v-if=
"!previewMarkdown"
#tabs-end
>
<div
class=
"md-header-toolbar gl-ml-auto gl-pb-3 gl-justify-content-center"
>
<toolbar-button
tag=
"**"
:button-title=
"
...
...
@@ -273,7 +281,8 @@ export default {
:button-title=
"__('Go full screen')"
icon=
"maximize"
/>
</li>
</ul>
</div>
</template>
</gl-tabs>
</div>
</template>
app/assets/stylesheets/framework/markdown_area.scss
View file @
51c05183
...
...
@@ -67,6 +67,27 @@
}
}
}
.gl-tabs-nav
{
@include
media-breakpoint-down
(
xs
)
{
.nav-item
{
flex
:
1
;
border-bottom
:
1px
solid
$border-color
;
}
.gl-tab-nav-item
{
padding-top
:
$gl-padding-4
;
padding-bottom
:
$gl-padding-8
;
}
.md-header-toolbar
{
width
:
100%
;
display
:
flex
;
flex-wrap
:
wrap
;
margin-top
:
$gl-padding-8
;
}
}
}
}
.md-header-tab
{
...
...
ee/spec/features/epics/update_epic_spec.rb
View file @
51c05183
...
...
@@ -49,7 +49,7 @@ RSpec.describe 'Update Epic', :js do
fill_in
'issue-description'
,
with:
'New epic description'
page
.
within
(
'.detail-page-description'
)
do
click_
button
(
'Preview'
)
click_
link
(
'Preview'
)
expect
(
find
(
'.md-preview-holder'
)).
to
have_content
(
'New epic description'
)
end
...
...
@@ -63,7 +63,7 @@ RSpec.describe 'Update Epic', :js do
fill_in
'issue-description'
,
with:
'New epic description'
page
.
within
(
'.detail-page-description'
)
do
click_
button
(
'Preview'
)
click_
link
(
'Preview'
)
expect
(
find
(
'.md-preview-holder'
)).
to
have_content
(
'New epic description'
)
end
...
...
@@ -76,7 +76,7 @@ RSpec.describe 'Update Epic', :js do
find
(
'.btn-edit'
).
click
page
.
within
(
'.detail-page-description'
)
do
click_
button
(
'Preview'
)
click_
link
(
'Preview'
)
expect
(
find
(
'.md-preview-holder'
)).
to
have_content
(
'New epic description'
)
end
end
...
...
@@ -122,7 +122,7 @@ RSpec.describe 'Update Epic', :js do
expect
(
page
.
find_field
(
"issue-description"
).
value
).
to
have_content
(
'banana_sample'
)
page
.
within
(
'.detail-page-description'
)
do
click_
button
(
'Preview'
)
click_
link
(
'Preview'
)
wait_for_requests
within
(
'.md-preview-holder'
)
do
...
...
ee/spec/features/groups/iteration_spec.rb
View file @
51c05183
...
...
@@ -28,14 +28,14 @@ RSpec.describe 'Group iterations' do
it
'renders description preview'
do
description
=
find
(
description_selector
)
description
.
native
.
send_keys
(
''
)
click_
button
(
'Preview'
)
click_
link
(
'Preview'
)
preview
=
find
(
'.js-vue-md-preview'
)
expect
(
preview
).
to
have_content
(
'Nothing to preview.'
)
click_
button
(
'Write'
)
click_
link
(
'Write'
)
description
.
native
.
send_keys
(
':+1: Nice'
)
click_
button
(
'Preview'
)
click_
link
(
'Preview'
)
expect
(
preview
).
to
have_css
(
'gl-emoji'
)
expect
(
find
(
'#iteration-description'
,
visible:
false
)).
not_to
be_visible
...
...
spec/features/merge_request/user_posts_notes_spec.rb
View file @
51c05183
...
...
@@ -133,7 +133,7 @@ RSpec.describe 'Merge request > User posts notes', :js do
describe
'when previewing a note'
do
it
'shows the toolbar buttons when editing a note'
do
page
.
within
(
'.js-main-target-form'
)
do
expect
(
page
).
to
have_css
(
'.md-header-toolbar
.active
'
)
expect
(
page
).
to
have_css
(
'.md-header-toolbar'
)
end
end
...
...
@@ -141,7 +141,7 @@ RSpec.describe 'Merge request > User posts notes', :js do
wait_for_requests
find
(
'.js-md-preview-button'
).
click
page
.
within
(
'.js-main-target-form'
)
do
expect
(
page
).
not_to
have_css
(
'.md-header-toolbar
.active
'
)
expect
(
page
).
not_to
have_css
(
'.md-header-toolbar'
)
end
end
end
...
...
spec/frontend/vue_shared/components/markdown/field_spec.js
View file @
51c05183
import
{
mount
}
from
'
@vue/test-utils
'
;
import
{
nextTick
}
from
'
vue
'
;
import
AxiosMockAdapter
from
'
axios-mock-adapter
'
;
import
$
from
'
jquery
'
;
import
{
TEST_HOST
,
FIXTURES_PATH
}
from
'
spec/test_constants
'
;
import
axios
from
'
~/lib/utils/axios_utils
'
;
import
MarkdownField
from
'
~/vue_shared/components/markdown/field.vue
'
;
import
{
mountExtended
}
from
'
helpers/vue_test_utils_helper
'
;
const
markdownPreviewPath
=
`
${
TEST_HOST
}
/preview`
;
const
markdownDocsPath
=
`
${
TEST_HOST
}
/docs`
;
...
...
@@ -12,8 +12,8 @@ const textareaValue = 'testing\n123';
const
uploadsPath
=
'
test/uploads
'
;
function
assertMarkdownTabs
(
isWrite
,
writeLink
,
previewLink
,
wrapper
)
{
expect
(
writeLink
.
element
.
parentNode
.
classList
.
contains
(
'
active
'
)).
toBe
(
isWrite
);
expect
(
previewLink
.
element
.
parentNode
.
classList
.
contains
(
'
active
'
)).
toBe
(
!
isWrite
);
expect
(
writeLink
.
element
.
children
[
0
]
.
classList
.
contains
(
'
active
'
)).
toBe
(
isWrite
);
expect
(
previewLink
.
element
.
children
[
0
]
.
classList
.
contains
(
'
active
'
)).
toBe
(
!
isWrite
);
expect
(
wrapper
.
find
(
'
.md-preview-holder
'
).
element
.
style
.
display
).
toBe
(
isWrite
?
'
none
'
:
''
);
}
...
...
@@ -29,14 +29,13 @@ describe('Markdown field component', () => {
afterEach
(()
=>
{
subject
.
destroy
();
subject
=
null
;
axiosMock
.
restore
();
});
function
createSubject
(
lines
=
[])
{
// We actually mount a wrapper component so that we can force Vue to rerender classes in order to test a regression
// caused by mixing Vanilla JS and Vue.
subject
=
mount
(
subject
=
mount
Extended
(
{
components
:
{
MarkdownField
,
...
...
@@ -72,8 +71,8 @@ describe('Markdown field component', () => {
);
}
const
getPreviewLink
=
()
=>
subject
.
find
(
'
.nav-links .js-preview-link
'
);
const
getWriteLink
=
()
=>
subject
.
find
(
'
.nav-links .js-write-link
'
);
const
getPreviewLink
=
()
=>
subject
.
find
ByTestId
(
'
preview-tab
'
);
const
getWriteLink
=
()
=>
subject
.
find
ByTestId
(
'
write-tab
'
);
const
getMarkdownButton
=
()
=>
subject
.
find
(
'
.js-md
'
);
const
getAllMarkdownButtons
=
()
=>
subject
.
findAll
(
'
.js-md
'
);
const
getVideo
=
()
=>
subject
.
find
(
'
video
'
);
...
...
@@ -107,15 +106,15 @@ describe('Markdown field component', () => {
it
(
'
sets preview link as active
'
,
async
()
=>
{
previewLink
=
getPreviewLink
();
previewLink
.
trigger
(
'
click
'
);
previewLink
.
vm
.
$emit
(
'
click
'
,
{
target
:
{}
}
);
await
nextTick
();
expect
(
previewLink
.
element
.
parentNode
.
classList
.
contains
(
'
active
'
)).
toBeTruthy
(
);
expect
(
previewLink
.
element
.
children
[
0
].
classList
.
contains
(
'
active
'
)).
toBe
(
true
);
});
it
(
'
shows preview loading text
'
,
async
()
=>
{
previewLink
=
getPreviewLink
();
previewLink
.
trigger
(
'
click
'
);
previewLink
.
vm
.
$emit
(
'
click
'
,
{
target
:
{}
}
);
await
nextTick
();
expect
(
subject
.
find
(
'
.md-preview-holder
'
).
element
.
textContent
.
trim
()).
toContain
(
'
Loading…
'
);
...
...
@@ -126,7 +125,7 @@ describe('Markdown field component', () => {
previewLink
=
getPreviewLink
();
previewLink
.
trigger
(
'
click
'
);
previewLink
.
vm
.
$emit
(
'
click
'
,
{
target
:
{}
}
);
await
axios
.
waitFor
(
markdownPreviewPath
);
expect
(
subject
.
find
(
'
.md-preview-holder
'
).
element
.
innerHTML
).
toContain
(
previewHTML
);
...
...
@@ -135,7 +134,7 @@ describe('Markdown field component', () => {
it
(
'
calls video.pause() on comment input when isSubmitting is changed to true
'
,
async
()
=>
{
previewLink
=
getPreviewLink
();
previewLink
.
trigger
(
'
click
'
);
previewLink
.
vm
.
$emit
(
'
click
'
,
{
target
:
{}
}
);
await
axios
.
waitFor
(
markdownPreviewPath
);
const
video
=
getVideo
();
...
...
@@ -151,19 +150,19 @@ describe('Markdown field component', () => {
writeLink
=
getWriteLink
();
previewLink
=
getPreviewLink
();
writeLink
.
trigger
(
'
click
'
);
writeLink
.
vm
.
$emit
(
'
click
'
,
{
target
:
{}
}
);
await
nextTick
();
assertMarkdownTabs
(
true
,
writeLink
,
previewLink
,
subject
);
writeLink
.
trigger
(
'
click
'
);
writeLink
.
vm
.
$emit
(
'
click
'
,
{
target
:
{}
}
);
await
nextTick
();
assertMarkdownTabs
(
true
,
writeLink
,
previewLink
,
subject
);
previewLink
.
trigger
(
'
click
'
);
previewLink
.
vm
.
$emit
(
'
click
'
,
{
target
:
{}
}
);
await
nextTick
();
assertMarkdownTabs
(
false
,
writeLink
,
previewLink
,
subject
);
previewLink
.
trigger
(
'
click
'
);
previewLink
.
vm
.
$emit
(
'
click
'
,
{
target
:
{}
}
);
await
nextTick
();
assertMarkdownTabs
(
false
,
writeLink
,
previewLink
,
subject
);
...
...
spec/frontend/vue_shared/components/markdown/header_spec.js
View file @
51c05183
import
{
shallowMount
}
from
'
@vue/test-utils
'
;
import
$
from
'
jquery
'
;
import
{
nextTick
}
from
'
vue
'
;
import
{
GlTabs
}
from
'
@gitlab/ui
'
;
import
HeaderComponent
from
'
~/vue_shared/components/markdown/header.vue
'
;
import
ToolbarButton
from
'
~/vue_shared/components/markdown/toolbar_button.vue
'
;
import
{
shallowMountExtended
}
from
'
helpers/vue_test_utils_helper
'
;
describe
(
'
Markdown field header component
'
,
()
=>
{
let
wrapper
;
const
createWrapper
=
(
props
)
=>
{
wrapper
=
shallowMount
(
HeaderComponent
,
{
wrapper
=
shallowMount
Extended
(
HeaderComponent
,
{
propsData
:
{
previewMarkdown
:
false
,
...
props
,
},
stubs
:
{
GlTabs
},
});
};
const
findWriteTab
=
()
=>
wrapper
.
findByTestId
(
'
write-tab
'
);
const
findPreviewTab
=
()
=>
wrapper
.
findByTestId
(
'
preview-tab
'
);
const
findToolbarButtons
=
()
=>
wrapper
.
findAll
(
ToolbarButton
);
const
findToolbarButtonByProp
=
(
prop
,
value
)
=>
findToolbarButtons
()
...
...
@@ -34,7 +38,6 @@ describe('Markdown field header component', () => {
afterEach
(()
=>
{
wrapper
.
destroy
();
wrapper
=
null
;
});
describe
(
'
markdown header buttons
'
,
()
=>
{
...
...
@@ -75,23 +78,26 @@ describe('Markdown field header component', () => {
});
});
it
(
'
renders `write` link as active when previewMarkdown is false
'
,
()
=>
{
expect
(
wrapper
.
find
(
'
li:nth-child(1)
'
).
classes
()).
toContain
(
'
active
'
);
it
(
'
activates `write` tab when previewMarkdown is false
'
,
()
=>
{
expect
(
findWriteTab
().
attributes
(
'
active
'
)).
toBe
(
'
true
'
);
expect
(
findPreviewTab
().
attributes
(
'
active
'
)).
toBeUndefined
();
});
it
(
'
renders `preview` link as active
when previewMarkdown is true
'
,
()
=>
{
it
(
'
activates `preview` tab
when previewMarkdown is true
'
,
()
=>
{
createWrapper
({
previewMarkdown
:
true
});
expect
(
wrapper
.
find
(
'
li:nth-child(2)
'
).
classes
()).
toContain
(
'
active
'
);
expect
(
findWriteTab
().
attributes
(
'
active
'
)).
toBeUndefined
();
expect
(
findPreviewTab
().
attributes
(
'
active
'
)).
toBe
(
'
true
'
);
});
it
(
'
emits toggle markdown event when clicking preview
'
,
async
()
=>
{
wrapper
.
find
(
'
.js-preview-link
'
).
trigger
(
'
click
'
);
it
(
'
emits toggle markdown event when clicking preview tab
'
,
async
()
=>
{
const
eventData
=
{
target
:
{}
};
findPreviewTab
().
vm
.
$emit
(
'
click
'
,
eventData
);
await
nextTick
();
expect
(
wrapper
.
emitted
(
'
preview-markdown
'
).
length
).
toEqual
(
1
);
wrapper
.
find
(
'
.js-write-link
'
).
trigger
(
'
click
'
);
findWriteTab
().
vm
.
$emit
(
'
click
'
,
eventData
);
await
nextTick
();
expect
(
wrapper
.
emitted
(
'
write-markdown
'
).
length
).
toEqual
(
1
);
...
...
@@ -109,12 +115,10 @@ describe('Markdown field header component', () => {
});
it
(
'
blurs preview link after click
'
,
()
=>
{
const
link
=
wrapper
.
find
(
'
li:nth-child(2) button
'
)
;
jest
.
spyOn
(
HTMLElement
.
prototype
,
'
blur
'
).
mockImplementation
(
);
const
target
=
{
blur
:
jest
.
fn
()
}
;
findPreviewTab
().
vm
.
$emit
(
'
click
'
,
{
target
}
);
link
.
trigger
(
'
click
'
);
expect
(
link
.
element
.
blur
).
toHaveBeenCalled
();
expect
(
target
.
blur
).
toHaveBeenCalled
();
});
it
(
'
renders markdown table template
'
,
()
=>
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment