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
a689dbbf
Commit
a689dbbf
authored
Aug 30, 2021
by
Natalia Tepluhina
Committed by
Vitaly Slobodin
Aug 30, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Replace `DropdownTitle` component with `SidebarEditableItem`
parent
17d2fb77
Changes
12
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
142 additions
and
390 deletions
+142
-390
app/assets/javascripts/sidebar/mount_sidebar.js
app/assets/javascripts/sidebar/mount_sidebar.js
+1
-0
app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents.vue
...onents/sidebar/labels_select_widget/dropdown_contents.vue
+4
-4
app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_create_view.vue
...ar/labels_select_widget/dropdown_contents_create_view.vue
+29
-0
app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_labels_view.vue
...ar/labels_select_widget/dropdown_contents_labels_view.vue
+4
-4
app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_title.vue
...omponents/sidebar/labels_select_widget/dropdown_title.vue
+0
-40
app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/graphql/create_label.mutation.graphql
...abels_select_widget/graphql/create_label.mutation.graphql
+0
-2
app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/labels_select_root.vue
...nents/sidebar/labels_select_widget/labels_select_root.vue
+56
-133
spec/frontend/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_create_view_spec.js
...abels_select_widget/dropdown_contents_create_view_spec.js
+14
-1
spec/frontend/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_labels_view_spec.js
...abels_select_widget/dropdown_contents_labels_view_spec.js
+1
-7
spec/frontend/vue_shared/components/sidebar/labels_select_widget/dropdown_title_spec.js
...nents/sidebar/labels_select_widget/dropdown_title_spec.js
+0
-61
spec/frontend/vue_shared/components/sidebar/labels_select_widget/labels_select_root_spec.js
...s/sidebar/labels_select_widget/labels_select_root_spec.js
+33
-136
spec/frontend/vue_shared/components/sidebar/labels_select_widget/mock_data.js
...ared/components/sidebar/labels_select_widget/mock_data.js
+0
-2
No files found.
app/assets/javascripts/sidebar/mount_sidebar.js
View file @
a689dbbf
...
...
@@ -258,6 +258,7 @@ export function mountSidebarLabels() {
allowScopedLabels
:
parseBoolean
(
el
.
dataset
.
allowScopedLabels
),
initiallySelectedLabels
:
JSON
.
parse
(
el
.
dataset
.
selectedLabels
),
variant
:
DropdownVariant
.
Sidebar
,
canUpdate
:
parseBoolean
(
el
.
dataset
.
canEdit
),
},
render
:
(
createElement
)
=>
createElement
(
SidebarLabels
),
});
...
...
app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents.vue
View file @
a689dbbf
...
...
@@ -60,7 +60,7 @@ export default {
},
},
methods
:
{
...
mapActions
([
'
toggleDropdownContentsCreateView
'
,
'
toggleDropdownContents
'
]),
...
mapActions
([
'
toggleDropdownContentsCreateView
'
]),
},
};
</
script
>
...
...
@@ -83,7 +83,7 @@ export default {
size=
"small"
class=
"js-btn-back dropdown-header-button p-0"
icon=
"arrow-left"
@
click=
"toggleDropdownContentsCreateView"
@
click
.stop
=
"toggleDropdownContentsCreateView"
/>
<span
class=
"flex-grow-1"
>
{{
dropdownTitle
}}
</span>
<gl-button
...
...
@@ -92,7 +92,7 @@ export default {
size=
"small"
class=
"dropdown-header-button gl-p-0!"
icon=
"close"
@
click=
"
toggleDropdownContents
"
@
click=
"
$emit('closeDropdown')
"
/>
</div>
<component
...
...
@@ -103,7 +103,7 @@ export default {
:footer-create-label-title=
"footerCreateLabelTitle"
:footer-manage-label-title=
"footerManageLabelTitle"
@
hideCreateView=
"toggleDropdownContentsCreateView"
@
closeDropdown=
"$emit('closeDropdown
', $event)"
@
setLabels=
"$emit('setLabels
', $event)"
@
toggleDropdownContentsCreateView=
"toggleDropdownContentsCreateView"
/>
</div>
...
...
app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_create_view.vue
View file @
a689dbbf
<
script
>
import
{
GlTooltipDirective
,
GlButton
,
GlFormInput
,
GlLink
,
GlLoadingIcon
}
from
'
@gitlab/ui
'
;
import
produce
from
'
immer
'
;
import
createFlash
from
'
~/flash
'
;
import
{
__
}
from
'
~/locale
'
;
import
createLabelMutation
from
'
./graphql/create_label.mutation.graphql
'
;
import
projectLabelsQuery
from
'
./graphql/project_labels.query.graphql
'
;
const
errorMessage
=
__
(
'
Error creating label.
'
);
...
...
@@ -47,6 +49,25 @@ export default {
handleColorClick
(
color
)
{
this
.
selectedColor
=
this
.
getColorCode
(
color
);
},
updateLabelsInCache
(
store
,
label
)
{
const
sourceData
=
store
.
readQuery
({
query
:
projectLabelsQuery
,
variables
:
{
fullPath
:
this
.
projectPath
,
searchTerm
:
''
},
});
const
collator
=
new
Intl
.
Collator
(
'
en
'
);
const
data
=
produce
(
sourceData
,
(
draftData
)
=>
{
const
{
nodes
}
=
draftData
.
workspace
.
labels
;
nodes
.
push
(
label
);
nodes
.
sort
((
a
,
b
)
=>
collator
.
compare
(
a
.
title
,
b
.
title
));
});
store
.
writeQuery
({
query
:
projectLabelsQuery
,
variables
:
{
fullPath
:
this
.
projectPath
,
searchTerm
:
''
},
data
,
});
},
async
createLabel
()
{
this
.
labelCreateInProgress
=
true
;
try
{
...
...
@@ -59,6 +80,14 @@ export default {
color
:
this
.
selectedColor
,
projectPath
:
this
.
projectPath
,
},
update
:
(
store
,
{
data
:
{
labelCreate
:
{
label
},
},
},
)
=>
this
.
updateLabelsInCache
(
store
,
label
),
});
if
(
labelCreate
.
errors
.
length
)
{
createFlash
({
message
:
errorMessage
});
...
...
app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_labels_view.vue
View file @
a689dbbf
...
...
@@ -112,7 +112,7 @@ export default {
this
.
debouncedSearchKeyUpdate
=
debounce
(
this
.
setSearchKey
,
DEFAULT_DEBOUNCE_AND_THROTTLE_MS
);
},
beforeDestroy
()
{
this
.
$emit
(
'
closeDropdown
'
,
this
.
localSelectedLabels
);
this
.
$emit
(
'
setLabels
'
,
this
.
localSelectedLabels
);
this
.
debouncedSearchKeyUpdate
.
cancel
();
},
methods
:
{
...
...
@@ -166,7 +166,7 @@ export default {
this
.
updateSelectedLabels
(
this
.
visibleLabels
[
this
.
currentHighlightItem
]);
this
.
searchKey
=
''
;
}
else
if
(
e
.
keyCode
===
ESC_KEY_CODE
)
{
this
.
$emit
(
'
closeDropdown
'
,
this
.
localSelectedLabels
);
this
.
$emit
(
'
setLabels
'
,
this
.
localSelectedLabels
);
}
if
(
e
.
keyCode
!==
ESC_KEY_CODE
)
{
...
...
@@ -180,7 +180,7 @@ export default {
handleLabelClick
(
label
)
{
this
.
updateSelectedLabels
(
label
);
if
(
!
this
.
allowMultiselect
)
{
this
.
$emit
(
'
closeDropdown
'
,
this
.
localSelectedLabels
);
this
.
$emit
(
'
setLabels
'
,
this
.
localSelectedLabels
);
}
},
setSearchKey
(
value
)
{
...
...
@@ -240,7 +240,7 @@ export default {
<gl-link
class=
"gl-display-flex gl-flex-direction-row gl-w-full gl-overflow-break-word label-item"
data-testid=
"create-label-button"
@
click=
"$emit('toggleDropdownContentsCreateView')"
@
click
.stop
=
"$emit('toggleDropdownContentsCreateView')"
>
{{
footerCreateLabelTitle
}}
</gl-link>
...
...
app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_title.vue
deleted
100644 → 0
View file @
17d2fb77
<
script
>
import
{
GlButton
,
GlLoadingIcon
}
from
'
@gitlab/ui
'
;
import
{
mapState
,
mapActions
}
from
'
vuex
'
;
export
default
{
components
:
{
GlButton
,
GlLoadingIcon
,
},
props
:
{
labelsSelectInProgress
:
{
type
:
Boolean
,
required
:
true
,
},
},
computed
:
{
...
mapState
([
'
allowLabelEdit
'
,
'
labelsFetchInProgress
'
]),
},
methods
:
{
...
mapActions
([
'
toggleDropdownContents
'
]),
},
};
</
script
>
<
template
>
<div
class=
"title hide-collapsed gl-mb-3"
>
{{
__
(
'
Labels
'
)
}}
<template
v-if=
"allowLabelEdit"
>
<gl-loading-icon
v-show=
"labelsSelectInProgress"
size=
"sm"
inline
/>
<gl-button
category=
"tertiary"
size=
"small"
class=
"float-right js-sidebar-dropdown-toggle gl-mr-n2"
data-qa-selector=
"labels_edit_button"
@
click=
"toggleDropdownContents"
>
{{
__
(
'
Edit
'
)
}}
</gl-button
>
</
template
>
</div>
</template>
app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/graphql/create_label.mutation.graphql
View file @
a689dbbf
...
...
@@ -6,9 +6,7 @@ mutation createLabel($title: String!, $color: String, $projectPath: ID, $groupPa
id
color
description
descriptionHtml
title
textColor
}
errors
}
...
...
app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/labels_select_root.vue
View file @
a689dbbf
<
script
>
import
$
from
'
jquery
'
;
import
Vue
from
'
vue
'
;
import
Vuex
,
{
mapState
,
mapActions
,
mapGetters
}
from
'
vuex
'
;
import
{
isInViewport
}
from
'
~/lib/utils/common_utils
'
;
import
{
__
}
from
'
~/locale
'
;
import
SidebarEditableItem
from
'
~/sidebar/components/sidebar_editable_item.vue
'
;
import
{
DropdownVariant
}
from
'
./constants
'
;
import
DropdownButton
from
'
./dropdown_button.vue
'
;
import
DropdownContents
from
'
./dropdown_contents.vue
'
;
import
DropdownTitle
from
'
./dropdown_title.vue
'
;
import
DropdownValue
from
'
./dropdown_value.vue
'
;
import
DropdownValueCollapsed
from
'
./dropdown_value_collapsed.vue
'
;
import
issueLabelsQuery
from
'
./graphql/issue_labels.query.graphql
'
;
...
...
@@ -19,11 +17,11 @@ Vue.use(Vuex);
export
default
{
store
:
new
Vuex
.
Store
(
labelsSelectModule
()),
components
:
{
DropdownTitle
,
DropdownValue
,
DropdownButton
,
DropdownContents
,
DropdownValueCollapsed
,
SidebarEditableItem
,
},
inject
:
[
'
iid
'
,
'
projectPath
'
],
props
:
{
...
...
@@ -139,15 +137,12 @@ export default {
},
},
computed
:
{
...
mapState
([
'
showDropdown
Button
'
,
'
showDropdown
Contents
'
]),
...
mapState
([
'
showDropdownContents
'
]),
...
mapGetters
([
'
isDropdownVariantSidebar
'
,
'
isDropdownVariantStandalone
'
,
'
isDropdownVariantEmbedded
'
,
]),
dropdownButtonVisible
()
{
return
this
.
isDropdownVariantSidebar
?
this
.
showDropdownButton
:
true
;
},
},
watch
:
{
selectedLabels
(
selectedLabels
)
{
...
...
@@ -182,99 +177,20 @@ export default {
footerCreateLabelTitle
:
this
.
footerCreateLabelTitle
,
footerManageLabelTitle
:
this
.
footerManageLabelTitle
,
});
this
.
$store
.
subscribeAction
({
after
:
this
.
handleVuexActionDispatch
,
});
document
.
addEventListener
(
'
mousedown
'
,
this
.
handleDocumentMousedown
);
document
.
addEventListener
(
'
click
'
,
this
.
handleDocumentClick
);
},
beforeDestroy
()
{
document
.
removeEventListener
(
'
mousedown
'
,
this
.
handleDocumentMousedown
);
document
.
removeEventListener
(
'
click
'
,
this
.
handleDocumentClick
);
},
methods
:
{
...
mapActions
([
'
setInitialState
'
,
'
toggleDropdownContents
'
]),
/**
* This method stores a mousedown event's target.
* Required by the click listener because the click
* event itself has no reference to this element.
*/
handleDocumentMousedown
({
target
})
{
this
.
mousedownTarget
=
target
;
},
/**
* This method listens for document-wide click event
* and toggle dropdown if user clicks anywhere outside
* the dropdown while dropdown is visible.
*/
handleDocumentClick
({
target
})
{
// We also perform the toggle exception check for the
// last mousedown event's target to avoid hiding the
// box when the mousedown happened inside the box and
// only the mouseup did not.
if
(
this
.
showDropdownContents
&&
!
this
.
preventDropdownToggleOnClick
(
target
)
&&
!
this
.
preventDropdownToggleOnClick
(
this
.
mousedownTarget
)
)
{
this
.
toggleDropdownContents
();
}
},
/**
* This method checks whether a given click target
* should prevent the dropdown from being toggled.
*/
preventDropdownToggleOnClick
(
target
)
{
// This approach of element detection is needed
// as the dropdown wrapper is not using `GlDropdown` as
// it will also require us to use `BDropdownForm`
// which is yet to be implemented in GitLab UI.
const
hasExceptionClass
=
[
'
js-dropdown-button
'
,
'
js-btn-cancel-create
'
,
'
js-sidebar-dropdown-toggle
'
,
].
some
(
(
className
)
=>
target
?.
classList
.
contains
(
className
)
||
target
?.
parentElement
?.
classList
.
contains
(
className
),
);
const
hasExceptionParent
=
[
'
.js-btn-back
'
,
'
.js-labels-list
'
].
some
(
(
className
)
=>
$
(
target
).
parents
(
className
).
length
,
);
const
isInDropdownButtonCollapsed
=
this
.
$refs
.
dropdownButtonCollapsed
?.
$el
.
contains
(
target
);
const
isInDropdownContents
=
this
.
$refs
.
dropdownContents
?.
$el
.
contains
(
target
);
return
(
hasExceptionClass
||
hasExceptionParent
||
isInDropdownButtonCollapsed
||
isInDropdownContents
);
},
...
mapActions
([
'
setInitialState
'
]),
handleDropdownClose
(
labels
)
{
// Only emit label updates if there are any labels to update
// on UI.
if
(
this
.
showDropdownContents
)
{
this
.
toggleDropdownContents
();
}
if
(
labels
.
length
)
this
.
$emit
(
'
updateSelectedLabels
'
,
labels
);
this
.
$emit
(
'
onDropdownClose
'
);
},
collapseDropdown
()
{
this
.
$refs
.
editable
.
collapse
();
},
handleCollapsedValueClick
()
{
this
.
$emit
(
'
toggleCollapse
'
);
},
setContentIsOnViewport
(
showDropdownContents
)
{
if
(
!
showDropdownContents
)
{
this
.
contentIsOnViewport
=
true
;
return
;
}
setContentIsOnViewport
()
{
this
.
$nextTick
(()
=>
{
if
(
this
.
$refs
.
dropdownContents
)
{
this
.
contentIsOnViewport
=
isInViewport
(
this
.
$refs
.
dropdownContents
.
$el
);
...
...
@@ -299,48 +215,55 @@ export default {
:labels=
"issueLabels"
@
onValueClick=
"handleCollapsedValueClick"
/>
<dropdown-title
:allow-label-edit=
"allowLabelEdit"
:labels-select-in-progress=
"labelsSelectInProgress"
/>
<dropdown-value
:disable-labels=
"labelsSelectInProgress"
:selected-labels=
"issueLabels"
:allow-label-remove=
"allowLabelRemove"
:allow-scoped-labels=
"allowScopedLabels"
:labels-filter-base-path=
"labelsFilterBasePath"
:labels-filter-param=
"labelsFilterParam"
@
onLabelRemove=
"$emit('onLabelRemove', $event)"
<sidebar-editable-item
ref=
"editable"
:title=
"__('Labels')"
:loading=
"labelsSelectInProgress"
@
open=
"setContentIsOnViewport"
@
close=
"contentIsOnViewport = true"
>
<slot></slot>
</dropdown-value>
<dropdown-button
v-show=
"dropdownButtonVisible"
class=
"gl-mt-2"
/>
<dropdown-contents
v-if=
"dropdownButtonVisible && showDropdownContents"
ref=
"dropdownContents"
:allow-multiselect=
"allowMultiselect"
:labels-list-title=
"labelsListTitle"
:footer-create-label-title=
"footerCreateLabelTitle"
:footer-manage-label-title=
"footerManageLabelTitle"
:render-on-top=
"!contentIsOnViewport"
:labels-create-title=
"labelsCreateTitle"
:selected-labels=
"selectedLabels"
@
closeDropdown=
"handleDropdownClose"
/>
</
template
>
<
template
v-if=
"isDropdownVariantStandalone || isDropdownVariantEmbedded"
>
<dropdown-button
v-show=
"dropdownButtonVisible"
/>
<dropdown-contents
v-if=
"dropdownButtonVisible && showDropdownContents"
ref=
"dropdownContents"
:allow-multiselect=
"allowMultiselect"
:labels-list-title=
"labelsListTitle"
:footer-create-label-title=
"footerCreateLabelTitle"
:footer-manage-label-title=
"footerManageLabelTitle"
:render-on-top=
"!contentIsOnViewport"
:selected-labels=
"selectedLabels"
@
closeDropdown=
"handleDropdownClose"
/>
<template
#collapsed
>
<dropdown-value
:disable-labels=
"labelsSelectInProgress"
:selected-labels=
"issueLabels"
:allow-label-remove=
"allowLabelRemove"
:allow-scoped-labels=
"allowScopedLabels"
:labels-filter-base-path=
"labelsFilterBasePath"
:labels-filter-param=
"labelsFilterParam"
@
onLabelRemove=
"$emit('onLabelRemove', $event)"
>
<slot></slot>
</dropdown-value>
</
template
>
<
template
#default=
"{ edit }"
>
<dropdown-value
:disable-labels=
"labelsSelectInProgress"
:selected-labels=
"issueLabels"
:allow-label-remove=
"allowLabelRemove"
:allow-scoped-labels=
"allowScopedLabels"
:labels-filter-base-path=
"labelsFilterBasePath"
:labels-filter-param=
"labelsFilterParam"
class=
"gl-mb-2"
@
onLabelRemove=
"$emit('onLabelRemove', $event)"
>
<slot></slot>
</dropdown-value>
<dropdown-button
/>
<dropdown-contents
v-if=
"edit"
ref=
"dropdownContents"
:allow-multiselect=
"allowMultiselect"
:labels-list-title=
"labelsListTitle"
:footer-create-label-title=
"footerCreateLabelTitle"
:footer-manage-label-title=
"footerManageLabelTitle"
:render-on-top=
"!contentIsOnViewport"
:labels-create-title=
"labelsCreateTitle"
:selected-labels=
"selectedLabels"
@
closeDropdown=
"collapseDropdown"
@
setLabels=
"handleDropdownClose"
/>
</
template
>
</sidebar-editable-item>
</template>
</div>
</template>
spec/frontend/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_create_view_spec.js
View file @
a689dbbf
...
...
@@ -7,7 +7,12 @@ import waitForPromises from 'helpers/wait_for_promises';
import
createFlash
from
'
~/flash
'
;
import
DropdownContentsCreateView
from
'
~/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_create_view.vue
'
;
import
createLabelMutation
from
'
~/vue_shared/components/sidebar/labels_select_widget/graphql/create_label.mutation.graphql
'
;
import
{
mockSuggestedColors
,
createLabelSuccessfulResponse
}
from
'
./mock_data
'
;
import
projectLabelsQuery
from
'
~/vue_shared/components/sidebar/labels_select_widget/graphql/project_labels.query.graphql
'
;
import
{
mockSuggestedColors
,
createLabelSuccessfulResponse
,
labelsQueryResponse
,
}
from
'
./mock_data
'
;
jest
.
mock
(
'
~/flash
'
);
...
...
@@ -44,6 +49,14 @@ describe('DropdownContentsCreateView', () => {
const
createComponent
=
({
mutationHandler
=
createLabelSuccessHandler
}
=
{})
=>
{
const
mockApollo
=
createMockApollo
([[
createLabelMutation
,
mutationHandler
]]);
mockApollo
.
clients
.
defaultClient
.
cache
.
writeQuery
({
query
:
projectLabelsQuery
,
data
:
labelsQueryResponse
.
data
,
variables
:
{
fullPath
:
''
,
searchTerm
:
''
,
},
});
wrapper
=
shallowMount
(
DropdownContentsCreateView
,
{
localVue
,
...
...
spec/frontend/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_labels_view_spec.js
View file @
a689dbbf
...
...
@@ -137,12 +137,6 @@ describe('DropdownContentsLabelsView', () => {
expect
(
findLabels
().
at
(
0
).
attributes
(
'
islabelset
'
)).
toBe
(
'
true
'
);
});
it
(
'
emits `closeDropdown event` when Esc button is pressed
'
,
()
=>
{
findDropdownWrapper
().
trigger
(
'
keydown.esc
'
);
expect
(
wrapper
.
emitted
(
'
closeDropdown
'
)).
toEqual
([[
selectedLabels
]]);
});
});
it
(
'
when search returns 0 results
'
,
async
()
=>
{
...
...
@@ -205,7 +199,7 @@ describe('DropdownContentsLabelsView', () => {
});
it
(
'
emits `toggleDropdownContentsCreateView` event on create label button click
'
,
()
=>
{
findCreateLabelButton
().
vm
.
$emit
(
'
click
'
);
findCreateLabelButton
().
vm
.
$emit
(
'
click
'
,
new
MouseEvent
(
'
click
'
)
);
expect
(
wrapper
.
emitted
(
'
toggleDropdownContentsCreateView
'
)).
toEqual
([[]]);
});
...
...
spec/frontend/vue_shared/components/sidebar/labels_select_widget/dropdown_title_spec.js
deleted
100644 → 0
View file @
17d2fb77
import
{
GlButton
,
GlLoadingIcon
}
from
'
@gitlab/ui
'
;
import
{
shallowMount
,
createLocalVue
}
from
'
@vue/test-utils
'
;
import
Vuex
from
'
vuex
'
;
import
DropdownTitle
from
'
~/vue_shared/components/sidebar/labels_select_widget/dropdown_title.vue
'
;
import
labelsSelectModule
from
'
~/vue_shared/components/sidebar/labels_select_widget/store
'
;
import
{
mockConfig
}
from
'
./mock_data
'
;
const
localVue
=
createLocalVue
();
localVue
.
use
(
Vuex
);
const
createComponent
=
(
initialState
=
mockConfig
)
=>
{
const
store
=
new
Vuex
.
Store
(
labelsSelectModule
());
store
.
dispatch
(
'
setInitialState
'
,
initialState
);
return
shallowMount
(
DropdownTitle
,
{
localVue
,
store
,
propsData
:
{
labelsSelectInProgress
:
false
,
},
});
};
describe
(
'
DropdownTitle
'
,
()
=>
{
let
wrapper
;
beforeEach
(()
=>
{
wrapper
=
createComponent
();
});
afterEach
(()
=>
{
wrapper
.
destroy
();
});
describe
(
'
template
'
,
()
=>
{
it
(
'
renders component container element with string "Labels"
'
,
()
=>
{
expect
(
wrapper
.
text
()).
toContain
(
'
Labels
'
);
});
it
(
'
renders edit link
'
,
()
=>
{
const
editBtnEl
=
wrapper
.
find
(
GlButton
);
expect
(
editBtnEl
.
exists
()).
toBe
(
true
);
expect
(
editBtnEl
.
text
()).
toBe
(
'
Edit
'
);
});
it
(
'
renders loading icon element when `labelsSelectInProgress` prop is true
'
,
()
=>
{
wrapper
.
setProps
({
labelsSelectInProgress
:
true
,
});
return
wrapper
.
vm
.
$nextTick
(()
=>
{
expect
(
wrapper
.
find
(
GlLoadingIcon
).
isVisible
()).
toBe
(
true
);
});
});
});
});
spec/frontend/vue_shared/components/sidebar/labels_select_widget/labels_select_root_spec.js
View file @
a689dbbf
import
{
shallowMount
,
createLocalVue
}
from
'
@vue/test-utils
'
;
import
Vuex
from
'
vuex
'
;
import
{
isInViewport
}
from
'
~/lib/utils/common_utils
'
;
import
{
DropdownVariant
}
from
'
~/vue_shared/components/sidebar/labels_select_widget/constants
'
;
import
DropdownButton
from
'
~/vue_shared/components/sidebar/labels_select_widget/dropdown_button.vue
'
;
import
SidebarEditableItem
from
'
~/sidebar/components/sidebar_editable_item.vue
'
;
import
DropdownContents
from
'
~/vue_shared/components/sidebar/labels_select_widget/dropdown_contents.vue
'
;
import
DropdownTitle
from
'
~/vue_shared/components/sidebar/labels_select_widget/dropdown_title.vue
'
;
import
DropdownValue
from
'
~/vue_shared/components/sidebar/labels_select_widget/dropdown_value.vue
'
;
import
DropdownValueCollapsed
from
'
~/vue_shared/components/sidebar/labels_select_widget/dropdown_value_collapsed.vue
'
;
import
LabelsSelectRoot
from
'
~/vue_shared/components/sidebar/labels_select_widget/labels_select_root.vue
'
;
...
...
@@ -32,11 +28,13 @@ describe('LabelsSelectRoot', () => {
store
,
propsData
:
config
,
stubs
:
{
'
dropdown-contents
'
:
DropdownContents
,
DropdownContents
,
SidebarEditableItem
,
},
provide
:
{
iid
:
'
1
'
,
projectPath
:
'
test
'
,
canUpdate
:
true
,
},
});
};
...
...
@@ -49,145 +47,44 @@ describe('LabelsSelectRoot', () => {
wrapper
.
destroy
();
});
describe
(
'
methods
'
,
()
=>
{
describe
(
'
handleDropdownClose
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
();
});
it
(
'
emits `updateSelectedLabels` & `onDropdownClose` events on component when provided `labels` param is not empty
'
,
()
=>
{
wrapper
.
vm
.
handleDropdownClose
([{
id
:
1
},
{
id
:
2
}]);
expect
(
wrapper
.
emitted
().
updateSelectedLabels
).
toBeTruthy
();
expect
(
wrapper
.
emitted
().
onDropdownClose
).
toBeTruthy
();
});
it
(
'
emits only `onDropdownClose` event on component when provided `labels` param is empty
'
,
()
=>
{
wrapper
.
vm
.
handleDropdownClose
([]);
expect
(
wrapper
.
emitted
().
updateSelectedLabels
).
toBeFalsy
();
expect
(
wrapper
.
emitted
().
onDropdownClose
).
toBeTruthy
();
});
});
describe
(
'
handleCollapsedValueClick
'
,
()
=>
{
it
(
'
emits `toggleCollapse` event on component
'
,
()
=>
{
createComponent
();
wrapper
.
vm
.
handleCollapsedValueClick
();
expect
(
wrapper
.
emitted
().
toggleCollapse
).
toBeTruthy
();
});
});
it
(
'
renders component with classes `labels-select-wrapper position-relative`
'
,
()
=>
{
createComponent
();
expect
(
wrapper
.
classes
()).
toEqual
([
'
labels-select-wrapper
'
,
'
position-relative
'
]);
});
describe
(
'
template
'
,
()
=>
{
it
(
'
renders component with classes `labels-select-wrapper position-relative`
'
,
()
=>
{
createComponent
();
expect
(
wrapper
.
attributes
(
'
class
'
)).
toContain
(
'
labels-select-wrapper position-relative
'
);
});
it
.
each
`
variant | cssClass
${
'
standalone
'
}
|
${
'
is-standalone
'
}
${
'
embedded
'
}
|
${
'
is-embedded
'
}
`
(
'
renders component root element with CSS class `$cssClass` when `state.variant` is "$variant"
'
,
({
variant
,
cssClass
})
=>
{
createComponent
({
...
mockConfig
,
variant
,
});
return
wrapper
.
vm
.
$nextTick
(()
=>
{
expect
(
wrapper
.
classes
()).
toContain
(
cssClass
);
});
},
);
it
(
'
renders `dropdown-value-collapsed` component when `allowLabelCreate` prop is `true`
'
,
async
()
=>
{
createComponent
();
await
wrapper
.
vm
.
$nextTick
;
expect
(
wrapper
.
find
(
DropdownValueCollapsed
).
exists
()).
toBe
(
true
);
});
it
(
'
renders `dropdown-title` component
'
,
async
()
=>
{
createComponent
();
await
wrapper
.
vm
.
$nextTick
;
expect
(
wrapper
.
find
(
DropdownTitle
).
exists
()).
toBe
(
true
);
});
it
(
'
renders `dropdown-value` component
'
,
async
()
=>
{
createComponent
(
mockConfig
,
{
default
:
'
None
'
,
it
.
each
`
variant | cssClass
${
'
standalone
'
}
|
${
'
is-standalone
'
}
${
'
embedded
'
}
|
${
'
is-embedded
'
}
`
(
'
renders component root element with CSS class `$cssClass` when `state.variant` is "$variant"
'
,
({
variant
,
cssClass
})
=>
{
createComponent
({
...
mockConfig
,
variant
,
});
await
wrapper
.
vm
.
$nextTick
;
const
valueComp
=
wrapper
.
find
(
DropdownValue
);
expect
(
valueComp
.
exists
()).
toBe
(
true
);
expect
(
valueComp
.
text
()).
toBe
(
'
None
'
);
});
it
(
'
renders `dropdown-button` component when `showDropdownButton` prop is `true`
'
,
async
()
=>
{
createComponent
();
wrapper
.
vm
.
$store
.
dispatch
(
'
toggleDropdownButton
'
);
await
wrapper
.
vm
.
$nextTick
;
expect
(
wrapper
.
find
(
DropdownButton
).
exists
()).
toBe
(
true
);
});
it
(
'
renders `dropdown-contents` component when `showDropdownButton` & `showDropdownContents` prop is `true`
'
,
async
()
=>
{
createComponent
();
wrapper
.
vm
.
$store
.
dispatch
(
'
toggleDropdownContents
'
);
await
wrapper
.
vm
.
$nextTick
;
expect
(
wrapper
.
find
(
DropdownContents
).
exists
()).
toBe
(
true
);
});
describe
(
'
sets content direction based on viewport
'
,
()
=>
{
describe
.
each
(
Object
.
values
(
DropdownVariant
))(
'
when labels variant is "%s"
'
,
({
variant
})
=>
{
beforeEach
(()
=>
{
createComponent
({
...
mockConfig
,
variant
});
wrapper
.
vm
.
$store
.
dispatch
(
'
toggleDropdownContents
'
);
});
it
(
'
set direction when out of viewport
'
,
()
=>
{
isInViewport
.
mockImplementation
(()
=>
false
);
wrapper
.
vm
.
setContentIsOnViewport
(
wrapper
.
vm
.
$store
.
state
);
return
wrapper
.
vm
.
$nextTick
().
then
(()
=>
{
expect
(
wrapper
.
find
(
DropdownContents
).
props
(
'
renderOnTop
'
)).
toBe
(
true
);
});
});
it
(
'
does not set direction when inside of viewport
'
,
()
=>
{
isInViewport
.
mockImplementation
(()
=>
true
);
wrapper
.
vm
.
setContentIsOnViewport
(
wrapper
.
vm
.
$store
.
state
);
return
wrapper
.
vm
.
$nextTick
().
then
(()
=>
{
expect
(
wrapper
.
find
(
DropdownContents
).
props
(
'
renderOnTop
'
)).
toBe
(
false
);
});
});
},
);
});
});
return
wrapper
.
vm
.
$nextTick
(()
=>
{
expect
(
wrapper
.
classes
()).
toContain
(
cssClass
);
});
},
);
it
(
'
calls toggleDropdownContents action when isEditing prop is changing to true
'
,
async
()
=>
{
it
(
'
renders `dropdown-value-collapsed` component when `allowLabelCreate` prop is `true`
'
,
async
()
=>
{
createComponent
();
jest
.
spyOn
(
store
,
'
dispatch
'
).
mockResolvedValue
();
await
wrapper
.
setProps
({
isEditing
:
true
});
expect
(
store
.
dispatch
).
toHaveBeenCalledWith
(
'
toggleDropdownContents
'
);
await
wrapper
.
vm
.
$nextTick
;
expect
(
wrapper
.
find
(
DropdownValueCollapsed
).
exists
()).
toBe
(
true
);
});
it
(
'
does not call toggleDropdownContents action when isEditing prop is changing to false
'
,
async
()
=>
{
createComponent
();
it
(
'
renders `dropdown-value` component
'
,
async
()
=>
{
createComponent
(
mockConfig
,
{
default
:
'
None
'
,
});
await
wrapper
.
vm
.
$nextTick
;
jest
.
spyOn
(
store
,
'
dispatch
'
).
mockResolvedValue
();
await
wrapper
.
setProps
({
isEditing
:
false
});
const
valueComp
=
wrapper
.
find
(
DropdownValue
);
expect
(
store
.
dispatch
).
not
.
toHaveBeenCalled
();
expect
(
valueComp
.
exists
()).
toBe
(
true
);
expect
(
valueComp
.
text
()).
toBe
(
'
None
'
);
});
});
spec/frontend/vue_shared/components/sidebar/labels_select_widget/mock_data.js
View file @
a689dbbf
...
...
@@ -83,9 +83,7 @@ export const createLabelSuccessfulResponse = {
id
:
'
gid://gitlab/ProjectLabel/126
'
,
color
:
'
#dc143c
'
,
description
:
null
,
descriptionHtml
:
''
,
title
:
'
ewrwrwer
'
,
textColor
:
'
#FFFFFF
'
,
__typename
:
'
Label
'
,
},
errors
:
[],
...
...
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