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
d2bc316c
Commit
d2bc316c
authored
Oct 22, 2019
by
Winnie Hellmann
Committed by
Natalia Tepluhina
Oct 22, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add split button to create issue from epics tree
parent
01c33f95
Changes
13
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
483 additions
and
20 deletions
+483
-20
app/assets/javascripts/vue_shared/components/split_button.vue
...assets/javascripts/vue_shared/components/split_button.vue
+76
-0
app/assets/stylesheets/framework/dropdowns.scss
app/assets/stylesheets/framework/dropdowns.scss
+2
-1
ee/app/assets/javascripts/related_items_tree/components/create_issue_form.vue
...ripts/related_items_tree/components/create_issue_form.vue
+10
-0
ee/app/assets/javascripts/related_items_tree/components/issue_actions_split_button.vue
...ated_items_tree/components/issue_actions_split_button.vue
+37
-0
ee/app/assets/javascripts/related_items_tree/components/related_items_tree_app.vue
.../related_items_tree/components/related_items_tree_app.vue
+36
-2
ee/app/assets/javascripts/related_items_tree/components/related_items_tree_header.vue
...lated_items_tree/components/related_items_tree_header.vue
+10
-7
ee/app/controllers/groups/epics_controller.rb
ee/app/controllers/groups/epics_controller.rb
+1
-0
ee/spec/features/epics/epic_issues_spec.rb
ee/spec/features/epics/epic_issues_spec.rb
+26
-2
ee/spec/javascripts/related_items_tree/components/related_items_tree_app_spec.js
...ated_items_tree/components/related_items_tree_app_spec.js
+96
-3
ee/spec/javascripts/related_items_tree/components/related_items_tree_header_spec.js
...d_items_tree/components/related_items_tree_header_spec.js
+39
-5
locale/gitlab.pot
locale/gitlab.pot
+9
-0
spec/frontend/vue_shared/components/__snapshots__/split_button_spec.js.snap
...shared/components/__snapshots__/split_button_spec.js.snap
+37
-0
spec/frontend/vue_shared/components/split_button_spec.js
spec/frontend/vue_shared/components/split_button_spec.js
+104
-0
No files found.
app/assets/javascripts/vue_shared/components/split_button.vue
0 → 100644
View file @
d2bc316c
<
script
>
import
_
from
'
underscore
'
;
import
{
GlDropdown
,
GlDropdownDivider
,
GlDropdownItem
}
from
'
@gitlab/ui
'
;
const
isValidItem
=
item
=>
_
.
isString
(
item
.
eventName
)
&&
_
.
isString
(
item
.
title
)
&&
_
.
isString
(
item
.
description
);
export
default
{
components
:
{
GlDropdown
,
GlDropdownDivider
,
GlDropdownItem
,
},
props
:
{
actionItems
:
{
type
:
Array
,
required
:
true
,
validator
(
value
)
{
return
value
.
length
>
1
&&
value
.
every
(
isValidItem
);
},
},
menuClass
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
},
data
()
{
return
{
selectedItem
:
this
.
actionItems
[
0
],
};
},
computed
:
{
dropdownToggleText
()
{
return
this
.
selectedItem
.
title
;
},
},
methods
:
{
triggerEvent
()
{
this
.
$emit
(
this
.
selectedItem
.
eventName
);
},
},
};
</
script
>
<
template
>
<gl-dropdown
:menu-class=
"`dropdown-menu-selectable $
{menuClass}`"
split
:text="dropdownToggleText"
v-bind="$attrs"
@click="triggerEvent"
>
<template
v-for=
"(item, itemIndex) in actionItems"
>
<gl-dropdown-item
:key=
"item.eventName"
:active=
"selectedItem === item"
active-class=
"is-active"
@
click=
"selectedItem = item"
>
<strong>
{{
item
.
title
}}
</strong>
<div>
{{
item
.
description
}}
</div>
</gl-dropdown-item>
<gl-dropdown-divider
v-if=
"itemIndex
<
actionItems
.
length
-
1
"
:key=
"`$
{item.eventName}-divider`"
/>
</
template
>
</gl-dropdown>
</template>
app/assets/stylesheets/framework/dropdowns.scss
View file @
d2bc316c
...
@@ -506,7 +506,8 @@
...
@@ -506,7 +506,8 @@
.dropdown-menu-selectable
{
.dropdown-menu-selectable
{
li
{
li
{
a
,
a
,
button
{
button
,
.dropdown-item
{
padding
:
8px
40px
;
padding
:
8px
40px
;
position
:
relative
;
position
:
relative
;
...
...
ee/app/assets/javascripts/related_items_tree/components/create_issue_form.vue
0 → 100644
View file @
d2bc316c
<
template
>
<div>
<!-- eslint-disable @gitlab/vue-i18n/no-bare-strings -->
<p>
This is a placeholder for
<a
href=
"https://gitlab.com/gitlab-org/gitlab/issues/5419"
>
#5419
</a>
.
</p>
<button
class=
"btn btn-secondary"
type=
"button"
@
click=
"$emit('cancel')"
>
Cancel
</button>
</div>
</
template
>
ee/app/assets/javascripts/related_items_tree/components/issue_actions_split_button.vue
0 → 100644
View file @
d2bc316c
<
script
>
import
SplitButton
from
'
~/vue_shared/components/split_button.vue
'
;
import
{
__
}
from
'
~/locale
'
;
const
actionItems
=
[
{
title
:
__
(
'
Add an issue
'
),
description
:
__
(
'
Add an existing issue to the epic.
'
),
eventName
:
'
showAddIssueForm
'
,
},
{
title
:
__
(
'
Create an issue
'
),
description
:
__
(
'
Create a new issue and add it to the epic.
'
),
eventName
:
'
showCreateIssueForm
'
,
},
];
export
default
{
actionItems
,
components
:
{
SplitButton
,
},
};
</
script
>
<
template
>
<split-button
:action-items=
"$options.actionItems"
class=
"js-issue-actions-split-button"
menu-class=
"dropdown-menu-large"
right
size=
"sm"
v-on=
"$listeners"
/>
</
template
>
ee/app/assets/javascripts/related_items_tree/components/related_items_tree_app.vue
View file @
d2bc316c
...
@@ -3,8 +3,12 @@ import { mapState, mapActions, mapGetters } from 'vuex';
...
@@ -3,8 +3,12 @@ import { mapState, mapActions, mapGetters } from 'vuex';
import
{
GlLoadingIcon
}
from
'
@gitlab/ui
'
;
import
{
GlLoadingIcon
}
from
'
@gitlab/ui
'
;
import
{
issuableTypesMap
}
from
'
ee/related_issues/constants
'
;
import
AddItemForm
from
'
ee/related_issues/components/add_issuable_form.vue
'
;
import
AddItemForm
from
'
ee/related_issues/components/add_issuable_form.vue
'
;
import
CreateEpicForm
from
'
./create_epic_form.vue
'
;
import
CreateEpicForm
from
'
./create_epic_form.vue
'
;
import
CreateIssueForm
from
'
./create_issue_form.vue
'
;
import
IssueActionsSplitButton
from
'
./issue_actions_split_button.vue
'
;
import
TreeItemRemoveModal
from
'
./tree_item_remove_modal.vue
'
;
import
TreeItemRemoveModal
from
'
./tree_item_remove_modal.vue
'
;
import
RelatedItemsTreeHeader
from
'
./related_items_tree_header.vue
'
;
import
RelatedItemsTreeHeader
from
'
./related_items_tree_header.vue
'
;
...
@@ -22,6 +26,13 @@ export default {
...
@@ -22,6 +26,13 @@ export default {
AddItemForm
,
AddItemForm
,
CreateEpicForm
,
CreateEpicForm
,
TreeItemRemoveModal
,
TreeItemRemoveModal
,
CreateIssueForm
,
IssueActionsSplitButton
,
},
data
()
{
return
{
isCreateIssueFormVisible
:
false
,
};
},
},
computed
:
{
computed
:
{
...
mapState
([
...
mapState
([
...
@@ -44,6 +55,9 @@ export default {
...
@@ -44,6 +55,9 @@ export default {
disableContents
()
{
disableContents
()
{
return
this
.
itemAddInProgress
||
this
.
itemCreateInProgress
;
return
this
.
itemAddInProgress
||
this
.
itemCreateInProgress
;
},
},
createIssueEnabled
()
{
return
gon
.
features
&&
gon
.
features
.
epicNewIssue
;
},
},
},
mounted
()
{
mounted
()
{
this
.
fetchItems
({
this
.
fetchItems
({
...
@@ -97,6 +111,14 @@ export default {
...
@@ -97,6 +111,14 @@ export default {
this
.
toggleCreateEpicForm
({
toggleState
:
false
});
this
.
toggleCreateEpicForm
({
toggleState
:
false
});
this
.
setItemInputValue
(
''
);
this
.
setItemInputValue
(
''
);
},
},
showAddIssueForm
()
{
this
.
toggleAddItemForm
({
toggleState
:
true
,
issuableType
:
issuableTypesMap
.
ISSUE
});
},
showCreateIssueForm
()
{
this
.
toggleAddItemForm
({
toggleState
:
false
});
this
.
toggleCreateEpicForm
({
toggleState
:
false
});
this
.
isCreateIssueFormVisible
=
true
;
},
},
},
};
};
</
script
>
</
script
>
...
@@ -114,9 +136,17 @@ export default {
...
@@ -114,9 +136,17 @@ export default {
'overflow-auto': directChildren.length > $options.OVERFLOW_AFTER,
'overflow-auto': directChildren.length > $options.OVERFLOW_AFTER,
}"
}"
>
>
<related-items-tree-header
:class=
"
{ 'border-bottom-0': itemsFetchResultEmpty }" />
<related-items-tree-header
:class=
"
{ 'border-bottom-0': itemsFetchResultEmpty }">
<issue-actions-split-button
v-if=
"createIssueEnabled"
slot=
"issueActions"
class=
"ml-1"
@
showAddIssueForm=
"showAddIssueForm"
@
showCreateIssueForm=
"showCreateIssueForm"
/>
</related-items-tree-header>
<div
<div
v-if=
"showAddItemForm || showCreateEpicForm"
v-if=
"showAddItemForm || showCreateEpicForm
|| isCreateIssueFormVisible
"
class=
"card-body add-item-form-container"
class=
"card-body add-item-form-container"
:class=
"
{ 'border-bottom-0': itemsFetchResultEmpty }"
:class=
"
{ 'border-bottom-0': itemsFetchResultEmpty }"
>
>
...
@@ -140,6 +170,10 @@ export default {
...
@@ -140,6 +170,10 @@ export default {
@
createEpicFormSubmit=
"handleCreateEpicFormSubmit"
@
createEpicFormSubmit=
"handleCreateEpicFormSubmit"
@
createEpicFormCancel=
"handleCreateEpicFormCancel"
@
createEpicFormCancel=
"handleCreateEpicFormCancel"
/>
/>
<create-issue-form
v-if=
"isCreateIssueFormVisible && !showAddItemForm && !showCreateEpicForm"
@
cancel=
"isCreateIssueFormVisible = false"
/>
</div>
</div>
<related-items-tree-body
<related-items-tree-body
v-if=
"!itemsFetchResultEmpty"
v-if=
"!itemsFetchResultEmpty"
...
...
ee/app/assets/javascripts/related_items_tree/components/related_items_tree_header.vue
View file @
d2bc316c
...
@@ -75,13 +75,16 @@ export default {
...
@@ -75,13 +75,16 @@ export default {
size="sm"
size="sm"
@onActionClick="handleActionClick"
@onActionClick="handleActionClick"
/>
/>
<gl-button
:class=
"headerItems[1].qaClass"
<slot
name=
"issueActions"
>
class=
"ml-1 js-add-issues-button"
<gl-button
size=
"sm"
:class=
"headerItems[1].qaClass"
@
click=
"handleActionClick(
{ id: 0, issuableType: 'issue' })"
class=
"ml-1 js-add-issues-button"
>
{{
__
(
'
Add an issue
'
)
}}
</gl-button
size=
"sm"
>
@
click=
"handleActionClick(
{ id: 0, issuableType: 'issue' })"
>
{{
__
(
'
Add an issue
'
)
}}
</gl-button
>
</slot>
</
template
>
</
template
>
</div>
</div>
</div>
</div>
...
...
ee/app/controllers/groups/epics_controller.rb
View file @
d2bc316c
...
@@ -19,6 +19,7 @@ class Groups::EpicsController < Groups::ApplicationController
...
@@ -19,6 +19,7 @@ class Groups::EpicsController < Groups::ApplicationController
push_frontend_feature_flag
(
:epic_trees
,
@group
)
push_frontend_feature_flag
(
:epic_trees
,
@group
)
push_frontend_feature_flag
(
:roadmap_graphql
,
@group
)
push_frontend_feature_flag
(
:roadmap_graphql
,
@group
)
push_frontend_feature_flag
(
:vue_issuable_epic_sidebar
,
@group
)
push_frontend_feature_flag
(
:vue_issuable_epic_sidebar
,
@group
)
push_frontend_feature_flag
(
:epic_new_issue
,
@group
)
end
end
def
index
def
index
...
...
ee/spec/features/epics/epic_issues_spec.rb
View file @
d2bc316c
...
@@ -40,6 +40,10 @@ describe 'Epic Issues', :js do
...
@@ -40,6 +40,10 @@ describe 'Epic Issues', :js do
wait_for_requests
wait_for_requests
end
end
before
do
stub_feature_flags
(
epic_new_issue:
false
)
end
context
'when user is not a group member of a public group'
do
context
'when user is not a group member of a public group'
do
before
do
before
do
visit_epic
visit_epic
...
@@ -67,8 +71,8 @@ describe 'Epic Issues', :js do
...
@@ -67,8 +71,8 @@ describe 'Epic Issues', :js do
let
(
:issue_invalid
)
{
create
(
:issue
)
}
let
(
:issue_invalid
)
{
create
(
:issue
)
}
let
(
:epic_to_add
)
{
create
(
:epic
,
group:
group
)
}
let
(
:epic_to_add
)
{
create
(
:epic
,
group:
group
)
}
def
add_issues
(
references
)
def
add_issues
(
references
,
button_selector:
'.js-add-issues-button'
)
find
(
'.related-items-tree-container .js-add-issues-button'
).
click
find
(
".related-items-tree-container
#{
button_selector
}
"
).
click
find
(
'.related-items-tree-container .js-add-issuable-form-input'
).
set
(
references
)
find
(
'.related-items-tree-container .js-add-issuable-form-input'
).
set
(
references
)
# When adding long references, for some reason the input gets stuck
# When adding long references, for some reason the input gets stuck
# waiting for more text. Send a keystroke before clicking the button to
# waiting for more text. Send a keystroke before clicking the button to
...
@@ -148,6 +152,26 @@ describe 'Epic Issues', :js do
...
@@ -148,6 +152,26 @@ describe 'Epic Issues', :js do
end
end
end
end
context
'with epic_new_issue feature flag enabled'
do
before
do
stub_feature_flags
(
epic_new_issue:
true
)
visit_epic
end
it
'user can add new issues to the epic'
do
references
=
"
#{
issue_to_add
.
to_reference
(
full:
true
)
}
"
add_issues
(
references
,
button_selector:
'.js-issue-actions-split-button'
)
expect
(
page
).
not_to
have_selector
(
'.content-wrapper .flash-text'
)
expect
(
page
).
not_to
have_content
(
"We can't find an issue that matches what you are looking for."
)
within
(
'.related-items-tree-container ul.related-items-list'
)
do
expect
(
page
).
to
have_selector
(
'li.js-item-type-issue'
,
count:
3
)
end
end
end
it
'user can add new epics to the epic'
do
it
'user can add new epics to the epic'
do
references
=
"
#{
epic_to_add
.
to_reference
(
full:
true
)
}
"
references
=
"
#{
epic_to_add
.
to_reference
(
full:
true
)
}
"
add_epics
(
references
)
add_epics
(
references
)
...
...
ee/spec/javascripts/related_items_tree/components/related_items_tree_app_spec.js
View file @
d2bc316c
...
@@ -5,6 +5,9 @@ import RelatedItemsTreeApp from 'ee/related_items_tree/components/related_items_
...
@@ -5,6 +5,9 @@ import RelatedItemsTreeApp from 'ee/related_items_tree/components/related_items_
import
RelatedItemsTreeHeader
from
'
ee/related_items_tree/components/related_items_tree_header.vue
'
;
import
RelatedItemsTreeHeader
from
'
ee/related_items_tree/components/related_items_tree_header.vue
'
;
import
createDefaultStore
from
'
ee/related_items_tree/store
'
;
import
createDefaultStore
from
'
ee/related_items_tree/store
'
;
import
{
issuableTypesMap
}
from
'
ee/related_issues/constants
'
;
import
{
issuableTypesMap
}
from
'
ee/related_issues/constants
'
;
import
AddItemForm
from
'
ee/related_issues/components/add_issuable_form.vue
'
;
import
CreateIssueForm
from
'
ee/related_items_tree/components/create_issue_form.vue
'
;
import
IssueActionsSplitButton
from
'
ee/related_items_tree/components/issue_actions_split_button.vue
'
;
import
{
mockInitialConfig
,
mockParentItem
}
from
'
../mock_data
'
;
import
{
mockInitialConfig
,
mockParentItem
}
from
'
../mock_data
'
;
...
@@ -24,15 +27,19 @@ const createComponent = () => {
...
@@ -24,15 +27,19 @@ const createComponent = () => {
describe
(
'
RelatedItemsTreeApp
'
,
()
=>
{
describe
(
'
RelatedItemsTreeApp
'
,
()
=>
{
let
wrapper
;
let
wrapper
;
beforeEach
(()
=>
{
const
findAddItemForm
=
()
=>
wrapper
.
find
(
AddItemForm
);
wrapper
=
createComponent
(
);
const
findCreateIssueForm
=
()
=>
wrapper
.
find
(
CreateIssueForm
);
}
);
const
findIssueActionsSplitButton
=
()
=>
wrapper
.
find
(
IssueActionsSplitButton
);
afterEach
(()
=>
{
afterEach
(()
=>
{
wrapper
.
destroy
();
wrapper
.
destroy
();
});
});
describe
(
'
methods
'
,
()
=>
{
describe
(
'
methods
'
,
()
=>
{
beforeEach
(()
=>
{
wrapper
=
createComponent
();
});
describe
(
'
getRawRefs
'
,
()
=>
{
describe
(
'
getRawRefs
'
,
()
=>
{
it
(
'
returns array of references from provided string with spaces
'
,
()
=>
{
it
(
'
returns array of references from provided string with spaces
'
,
()
=>
{
const
value
=
'
&1 &2 &3
'
;
const
value
=
'
&1 &2 &3
'
;
...
@@ -165,6 +172,7 @@ describe('RelatedItemsTreeApp', () => {
...
@@ -165,6 +172,7 @@ describe('RelatedItemsTreeApp', () => {
describe
(
'
template
'
,
()
=>
{
describe
(
'
template
'
,
()
=>
{
beforeEach
(()
=>
{
beforeEach
(()
=>
{
wrapper
=
createComponent
();
wrapper
.
vm
.
$store
.
dispatch
(
'
receiveItemsSuccess
'
,
{
wrapper
.
vm
.
$store
.
dispatch
(
'
receiveItemsSuccess
'
,
{
parentItem
:
mockParentItem
,
parentItem
:
mockParentItem
,
children
:
[],
children
:
[],
...
@@ -218,5 +226,90 @@ describe('RelatedItemsTreeApp', () => {
...
@@ -218,5 +226,90 @@ describe('RelatedItemsTreeApp', () => {
done
();
done
();
});
});
});
});
it
(
'
does not render issue actions split button
'
,
()
=>
{
expect
(
findIssueActionsSplitButton
().
exists
()).
toBe
(
false
);
});
it
(
'
does not render create issue form
'
,
()
=>
{
expect
(
findCreateIssueForm
().
exists
()).
toBe
(
false
);
});
});
describe
(
'
with epicNewIssue feature flag enabled
'
,
()
=>
{
beforeEach
(
done
=>
{
window
.
gon
.
features
=
{
epicNewIssue
:
true
};
wrapper
=
createComponent
();
wrapper
.
vm
.
$store
.
state
.
itemsFetchInProgress
=
false
;
wrapper
.
vm
.
$nextTick
()
.
then
(
done
)
.
catch
(
done
.
fail
);
});
afterEach
(()
=>
{
window
.
gon
.
features
=
{};
});
it
(
'
renders issue actions split button
'
,
()
=>
{
expect
(
findIssueActionsSplitButton
().
exists
()).
toBe
(
true
);
});
describe
(
'
after split button emitted showAddIssueForm event
'
,
()
=>
{
it
(
'
shows add item form
'
,
done
=>
{
expect
(
findAddItemForm
().
exists
()).
toBe
(
false
);
findIssueActionsSplitButton
().
vm
.
$emit
(
'
showAddIssueForm
'
);
wrapper
.
vm
.
$nextTick
()
.
then
(()
=>
{
expect
(
findAddItemForm
().
exists
()).
toBe
(
true
);
})
.
then
(
done
)
.
catch
(
done
.
fail
);
});
});
describe
(
'
after split button emitted showCreateIssueForm event
'
,
()
=>
{
it
(
'
shows create item form
'
,
done
=>
{
expect
(
findCreateIssueForm
().
exists
()).
toBe
(
false
);
findIssueActionsSplitButton
().
vm
.
$emit
(
'
showCreateIssueForm
'
);
wrapper
.
vm
.
$nextTick
()
.
then
(()
=>
{
expect
(
findCreateIssueForm
().
exists
()).
toBe
(
true
);
})
.
then
(
done
)
.
catch
(
done
.
fail
);
});
});
describe
(
'
after create issue form emitted cancel event
'
,
()
=>
{
beforeEach
(
done
=>
{
findIssueActionsSplitButton
().
vm
.
$emit
(
'
showCreateIssueForm
'
);
wrapper
.
vm
.
$nextTick
()
.
then
(
done
)
.
catch
(
done
.
fail
);
});
it
(
'
hides the form
'
,
done
=>
{
expect
(
findCreateIssueForm
().
exists
()).
toBe
(
true
);
findCreateIssueForm
().
vm
.
$emit
(
'
cancel
'
);
wrapper
.
vm
.
$nextTick
()
.
then
(()
=>
{
expect
(
findCreateIssueForm
().
exists
()).
toBe
(
false
);
})
.
then
(
done
)
.
catch
(
done
.
fail
);
});
});
});
});
});
});
ee/spec/javascripts/related_items_tree/components/related_items_tree_header_spec.js
View file @
d2bc316c
...
@@ -10,7 +10,7 @@ import { issuableTypesMap } from 'ee/related_issues/constants';
...
@@ -10,7 +10,7 @@ import { issuableTypesMap } from 'ee/related_issues/constants';
import
{
mockParentItem
,
mockQueryResponse
}
from
'
../mock_data
'
;
import
{
mockParentItem
,
mockQueryResponse
}
from
'
../mock_data
'
;
const
createComponent
=
()
=>
{
const
createComponent
=
(
{
slots
}
=
{}
)
=>
{
const
store
=
createDefaultStore
();
const
store
=
createDefaultStore
();
const
localVue
=
createLocalVue
();
const
localVue
=
createLocalVue
();
const
children
=
epicUtils
.
processQueryResponse
(
mockQueryResponse
.
data
.
group
);
const
children
=
epicUtils
.
processQueryResponse
(
mockQueryResponse
.
data
.
group
);
...
@@ -29,6 +29,7 @@ const createComponent = () => {
...
@@ -29,6 +29,7 @@ const createComponent = () => {
return
shallowMount
(
RelatedItemsTreeHeader
,
{
return
shallowMount
(
RelatedItemsTreeHeader
,
{
localVue
,
localVue
,
store
,
store
,
slots
,
});
});
};
};
...
@@ -36,15 +37,15 @@ describe('RelatedItemsTree', () => {
...
@@ -36,15 +37,15 @@ describe('RelatedItemsTree', () => {
describe
(
'
RelatedItemsTreeHeader
'
,
()
=>
{
describe
(
'
RelatedItemsTreeHeader
'
,
()
=>
{
let
wrapper
;
let
wrapper
;
beforeEach
(()
=>
{
wrapper
=
createComponent
();
});
afterEach
(()
=>
{
afterEach
(()
=>
{
wrapper
.
destroy
();
wrapper
.
destroy
();
});
});
describe
(
'
computed
'
,
()
=>
{
describe
(
'
computed
'
,
()
=>
{
beforeEach
(()
=>
{
wrapper
=
createComponent
();
});
describe
(
'
badgeTooltip
'
,
()
=>
{
describe
(
'
badgeTooltip
'
,
()
=>
{
it
(
'
returns string containing epic count and issues count based on available direct children within state
'
,
()
=>
{
it
(
'
returns string containing epic count and issues count based on available direct children within state
'
,
()
=>
{
expect
(
wrapper
.
vm
.
badgeTooltip
).
toBe
(
'
2 epics and 2 issues
'
);
expect
(
wrapper
.
vm
.
badgeTooltip
).
toBe
(
'
2 epics and 2 issues
'
);
...
@@ -53,6 +54,10 @@ describe('RelatedItemsTree', () => {
...
@@ -53,6 +54,10 @@ describe('RelatedItemsTree', () => {
});
});
describe
(
'
methods
'
,
()
=>
{
describe
(
'
methods
'
,
()
=>
{
beforeEach
(()
=>
{
wrapper
=
createComponent
();
});
describe
(
'
handleActionClick
'
,
()
=>
{
describe
(
'
handleActionClick
'
,
()
=>
{
const
issuableType
=
issuableTypesMap
.
Epic
;
const
issuableType
=
issuableTypesMap
.
Epic
;
...
@@ -81,6 +86,10 @@ describe('RelatedItemsTree', () => {
...
@@ -81,6 +86,10 @@ describe('RelatedItemsTree', () => {
});
});
describe
(
'
template
'
,
()
=>
{
describe
(
'
template
'
,
()
=>
{
beforeEach
(()
=>
{
wrapper
=
createComponent
();
});
it
(
'
renders item badges container
'
,
()
=>
{
it
(
'
renders item badges container
'
,
()
=>
{
const
badgesContainerEl
=
wrapper
.
find
(
'
.issue-count-badge
'
);
const
badgesContainerEl
=
wrapper
.
find
(
'
.issue-count-badge
'
);
...
@@ -116,5 +125,30 @@ describe('RelatedItemsTree', () => {
...
@@ -116,5 +125,30 @@ describe('RelatedItemsTree', () => {
expect
(
addIssueBtn
.
text
()).
toBe
(
'
Add an issue
'
);
expect
(
addIssueBtn
.
text
()).
toBe
(
'
Add an issue
'
);
});
});
});
});
describe
(
'
slots
'
,
()
=>
{
describe
(
'
issueActions
'
,
()
=>
{
it
(
'
defaults to button
'
,
()
=>
{
wrapper
=
createComponent
();
expect
(
wrapper
.
find
(
GlButton
).
exists
()).
toBe
(
true
);
});
it
(
'
uses provided slot content
'
,
()
=>
{
const
issueActions
=
{
template
:
'
<p>custom content</p>
'
,
};
wrapper
=
createComponent
({
slots
:
{
issueActions
,
},
});
expect
(
wrapper
.
find
(
GlButton
).
exists
()).
toBe
(
false
);
expect
(
wrapper
.
find
(
issueActions
).
exists
()).
toBe
(
true
);
});
});
});
});
});
});
});
locale/gitlab.pot
View file @
d2bc316c
...
@@ -925,6 +925,9 @@ msgstr ""
...
@@ -925,6 +925,9 @@ msgstr ""
msgid "Add an SSH key"
msgid "Add an SSH key"
msgstr ""
msgstr ""
msgid "Add an existing issue to the epic."
msgstr ""
msgid "Add an issue"
msgid "Add an issue"
msgstr ""
msgstr ""
...
@@ -4672,12 +4675,18 @@ msgstr ""
...
@@ -4672,12 +4675,18 @@ msgstr ""
msgid "Create a new issue"
msgid "Create a new issue"
msgstr ""
msgstr ""
msgid "Create a new issue and add it to the epic."
msgstr ""
msgid "Create a new repository"
msgid "Create a new repository"
msgstr ""
msgstr ""
msgid "Create a personal access token on your account to pull or push via %{protocol}."
msgid "Create a personal access token on your account to pull or push via %{protocol}."
msgstr ""
msgstr ""
msgid "Create an issue"
msgstr ""
msgid "Create an issue. Issues are created for each alert triggered."
msgid "Create an issue. Issues are created for each alert triggered."
msgstr ""
msgstr ""
...
...
spec/frontend/vue_shared/components/__snapshots__/split_button_spec.js.snap
0 → 100644
View file @
d2bc316c
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`SplitButton renders actionItems 1`] = `
<gldropdown-stub
menu-class="dropdown-menu-selectable "
split="true"
text="professor"
>
<gldropdownitem-stub
active="true"
active-class="is-active"
>
<strong>
professor
</strong>
<div>
very symphonic
</div>
</gldropdownitem-stub>
<gldropdowndivider-stub />
<gldropdownitem-stub
active-class="is-active"
>
<strong>
captain
</strong>
<div>
warp drive
</div>
</gldropdownitem-stub>
<!---->
</gldropdown-stub>
`;
spec/frontend/vue_shared/components/split_button_spec.js
0 → 100644
View file @
d2bc316c
import
{
GlDropdown
,
GlDropdownItem
}
from
'
@gitlab/ui
'
;
import
{
shallowMount
}
from
'
@vue/test-utils
'
;
import
SplitButton
from
'
~/vue_shared/components/split_button.vue
'
;
const
mockActionItems
=
[
{
eventName
:
'
concert
'
,
title
:
'
professor
'
,
description
:
'
very symphonic
'
,
},
{
eventName
:
'
apocalypse
'
,
title
:
'
captain
'
,
description
:
'
warp drive
'
,
},
];
describe
(
'
SplitButton
'
,
()
=>
{
let
wrapper
;
const
createComponent
=
propsData
=>
{
wrapper
=
shallowMount
(
SplitButton
,
{
propsData
,
sync
:
false
,
});
};
const
findDropdown
=
()
=>
wrapper
.
find
(
GlDropdown
);
const
findDropdownItem
=
(
index
=
0
)
=>
findDropdown
()
.
findAll
(
GlDropdownItem
)
.
at
(
index
);
const
selectItem
=
index
=>
{
findDropdownItem
(
index
).
vm
.
$emit
(
'
click
'
);
return
wrapper
.
vm
.
$nextTick
();
};
const
clickToggleButton
=
()
=>
{
findDropdown
().
vm
.
$emit
(
'
click
'
);
return
wrapper
.
vm
.
$nextTick
();
};
it
(
'
fails for empty actionItems
'
,
()
=>
{
const
actionItems
=
[];
expect
(()
=>
createComponent
({
actionItems
})).
toThrow
();
});
it
(
'
fails for single actionItems
'
,
()
=>
{
const
actionItems
=
[
mockActionItems
[
0
]];
expect
(()
=>
createComponent
({
actionItems
})).
toThrow
();
});
it
(
'
renders actionItems
'
,
()
=>
{
createComponent
({
actionItems
:
mockActionItems
});
expect
(
wrapper
.
element
).
toMatchSnapshot
();
});
describe
(
'
toggle button text
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
({
actionItems
:
mockActionItems
});
});
it
(
'
defaults to first actionItems title
'
,
()
=>
{
expect
(
findDropdown
().
props
().
text
).
toBe
(
mockActionItems
[
0
].
title
);
});
it
(
'
changes to selected actionItems title
'
,
()
=>
selectItem
(
1
).
then
(()
=>
{
expect
(
findDropdown
().
props
().
text
).
toBe
(
mockActionItems
[
1
].
title
);
}));
});
describe
(
'
emitted event
'
,
()
=>
{
let
eventHandler
;
beforeEach
(()
=>
{
createComponent
({
actionItems
:
mockActionItems
});
});
const
addEventHandler
=
({
eventName
})
=>
{
eventHandler
=
jest
.
fn
();
wrapper
.
vm
.
$once
(
eventName
,
()
=>
eventHandler
());
};
it
(
'
defaults to first actionItems event
'
,
()
=>
{
addEventHandler
(
mockActionItems
[
0
]);
return
clickToggleButton
().
then
(()
=>
{
expect
(
eventHandler
).
toHaveBeenCalled
();
});
});
it
(
'
changes to selected actionItems event
'
,
()
=>
selectItem
(
1
)
.
then
(()
=>
addEventHandler
(
mockActionItems
[
1
]))
.
then
(
clickToggleButton
)
.
then
(()
=>
{
expect
(
eventHandler
).
toHaveBeenCalled
();
}));
});
});
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