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
0
Merge Requests
0
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
Léo-Paul Géneau
gitlab-ce
Commits
160157a9
Commit
160157a9
authored
Oct 30, 2018
by
Mike Greiling
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Prettify remaining files with differences in CE and EE
parent
ed816c3d
Changes
85
Show whitespace changes
Inline
Side-by-side
Showing
85 changed files
with
2283 additions
and
2089 deletions
+2283
-2089
app/assets/javascripts/blob_edit/blob_bundle.js
app/assets/javascripts/blob_edit/blob_bundle.js
+1
-1
app/assets/javascripts/boards/components/board.js
app/assets/javascripts/boards/components/board.js
+15
-12
app/assets/javascripts/boards/components/board_blank_state.vue
...ssets/javascripts/boards/components/board_blank_state.vue
+7
-8
app/assets/javascripts/boards/components/board_card.vue
app/assets/javascripts/boards/components/board_card.vue
+64
-64
app/assets/javascripts/boards/components/board_new_issue.vue
app/assets/javascripts/boards/components/board_new_issue.vue
+2
-1
app/assets/javascripts/boards/components/board_sidebar.js
app/assets/javascripts/boards/components/board_sidebar.js
+23
-18
app/assets/javascripts/boards/components/issue_card_inner.vue
...assets/javascripts/boards/components/issue_card_inner.vue
+128
-128
app/assets/javascripts/boards/components/modal/empty_state.vue
...ssets/javascripts/boards/components/modal/empty_state.vue
+2
-2
app/assets/javascripts/boards/components/modal/footer.vue
app/assets/javascripts/boards/components/modal/footer.vue
+7
-9
app/assets/javascripts/boards/components/modal/header.vue
app/assets/javascripts/boards/components/modal/header.vue
+40
-40
app/assets/javascripts/boards/components/modal/index.vue
app/assets/javascripts/boards/components/modal/index.vue
+115
-114
app/assets/javascripts/boards/components/modal/list.vue
app/assets/javascripts/boards/components/modal/list.vue
+99
-99
app/assets/javascripts/boards/components/modal/tabs.vue
app/assets/javascripts/boards/components/modal/tabs.vue
+15
-15
app/assets/javascripts/boards/components/new_list_dropdown.js
...assets/javascripts/boards/components/new_list_dropdown.js
+24
-19
app/assets/javascripts/boards/components/project_select.vue
app/assets/javascripts/boards/components/project_select.vue
+4
-2
app/assets/javascripts/boards/components/sidebar/remove_issue.vue
...ts/javascripts/boards/components/sidebar/remove_issue.vue
+60
-62
app/assets/javascripts/boards/filtered_search_boards.js
app/assets/javascripts/boards/filtered_search_boards.js
+6
-3
app/assets/javascripts/boards/index.js
app/assets/javascripts/boards/index.js
+3
-3
app/assets/javascripts/boards/mixins/sortable_default_options.js
...ets/javascripts/boards/mixins/sortable_default_options.js
+7
-3
app/assets/javascripts/boards/models/issue.js
app/assets/javascripts/boards/models/issue.js
+15
-15
app/assets/javascripts/boards/models/list.js
app/assets/javascripts/boards/models/list.js
+2
-2
app/assets/javascripts/boards/services/board_service.js
app/assets/javascripts/boards/services/board_service.js
+9
-3
app/assets/javascripts/boards/stores/boards_store.js
app/assets/javascripts/boards/stores/boards_store.js
+31
-26
app/assets/javascripts/boards/stores/modal_store.js
app/assets/javascripts/boards/stores/modal_store.js
+6
-6
app/assets/javascripts/commons/gitlab_ui.js
app/assets/javascripts/commons/gitlab_ui.js
+1
-5
app/assets/javascripts/diffs/components/tree_list.vue
app/assets/javascripts/diffs/components/tree_list.vue
+2
-2
app/assets/javascripts/environments/components/environments_app.vue
.../javascripts/environments/components/environments_app.vue
+75
-77
app/assets/javascripts/environments/stores/environments_store.js
...ets/javascripts/environments/stores/environments_store.js
+15
-15
app/assets/javascripts/filtered_search/dropdown_user.js
app/assets/javascripts/filtered_search/dropdown_user.js
+4
-3
app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js
...ripts/filtered_search/filtered_search_dropdown_manager.js
+14
-13
app/assets/javascripts/filtered_search/filtered_search_manager.js
...ts/javascripts/filtered_search/filtered_search_manager.js
+65
-48
app/assets/javascripts/flash.js
app/assets/javascripts/flash.js
+6
-2
app/assets/javascripts/gfm_auto_complete.js
app/assets/javascripts/gfm_auto_complete.js
+40
-21
app/assets/javascripts/jobs/components/job_app.vue
app/assets/javascripts/jobs/components/job_app.vue
+145
-145
app/assets/javascripts/jobs/components/job_log.vue
app/assets/javascripts/jobs/components/job_log.vue
+37
-37
app/assets/javascripts/jobs/index.js
app/assets/javascripts/jobs/index.js
+0
-1
app/assets/javascripts/jobs/store/getters.js
app/assets/javascripts/jobs/store/getters.js
+6
-3
app/assets/javascripts/labels_select.js
app/assets/javascripts/labels_select.js
+149
-97
app/assets/javascripts/lib/utils/ace_utils.js
app/assets/javascripts/lib/utils/ace_utils.js
+2
-2
app/assets/javascripts/lib/utils/number_utils.js
app/assets/javascripts/lib/utils/number_utils.js
+1
-1
app/assets/javascripts/members.js
app/assets/javascripts/members.js
+7
-3
app/assets/javascripts/milestone_select.js
app/assets/javascripts/milestone_select.js
+4
-1
app/assets/javascripts/notes/components/notes_app.vue
app/assets/javascripts/notes/components/notes_app.vue
+7
-1
app/assets/javascripts/notes/discussion_filters.js
app/assets/javascripts/notes/discussion_filters.js
+5
-3
app/assets/javascripts/pages/milestones/shared/components/promote_milestone_modal.vue
.../milestones/shared/components/promote_milestone_modal.vue
+55
-44
app/assets/javascripts/pages/projects/project.js
app/assets/javascripts/pages/projects/project.js
+3
-1
app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue
...projects/shared/permissions/components/settings_panel.vue
+173
-175
app/assets/javascripts/projects/project_new.js
app/assets/javascripts/projects/project_new.js
+29
-15
app/assets/javascripts/right_sidebar.js
app/assets/javascripts/right_sidebar.js
+39
-18
app/assets/javascripts/search_autocomplete.js
app/assets/javascripts/search_autocomplete.js
+3
-1
app/assets/javascripts/sidebar/components/assignees/assignees.vue
...ts/javascripts/sidebar/components/assignees/assignees.vue
+2
-3
app/assets/javascripts/sidebar/components/subscriptions/subscriptions.vue
...cripts/sidebar/components/subscriptions/subscriptions.vue
+62
-62
app/assets/javascripts/sidebar/sidebar_mediator.js
app/assets/javascripts/sidebar/sidebar_mediator.js
+12
-8
app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue
...ue_merge_request_widget/components/mr_widget_pipeline.vue
+9
-4
app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue
...merge_request_widget/components/states/ready_to_merge.vue
+21
-11
app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
...avascripts/vue_merge_request_widget/mr_widget_options.vue
+8
-4
app/assets/javascripts/vue_merge_request_widget/services/mr_widget_service.js
...ts/vue_merge_request_widget/services/mr_widget_service.js
+2
-2
app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
...cripts/vue_merge_request_widget/stores/mr_widget_store.js
+1
-2
app/assets/javascripts/vue_shared/components/filtered_search_dropdown.vue
...cripts/vue_shared/components/filtered_search_dropdown.vue
+4
-2
app/assets/javascripts/vue_shared/components/sidebar/collapsed_calendar_icon.vue
...vue_shared/components/sidebar/collapsed_calendar_icon.vue
+31
-31
app/assets/javascripts/vue_shared/components/sidebar/collapsed_grouped_date_picker.vue
...ared/components/sidebar/collapsed_grouped_date_picker.vue
+68
-73
app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_value_collapsed.vue
...onents/sidebar/labels_select/dropdown_value_collapsed.vue
+4
-1
spec/javascripts/boards/board_list_spec.js
spec/javascripts/boards/board_list_spec.js
+33
-53
spec/javascripts/boards/components/board_spec.js
spec/javascripts/boards/components/board_spec.js
+13
-24
spec/javascripts/environments/emtpy_state_spec.js
spec/javascripts/environments/emtpy_state_spec.js
+10
-13
spec/javascripts/environments/environment_item_spec.js
spec/javascripts/environments/environment_item_spec.js
+25
-31
spec/javascripts/environments/environments_app_spec.js
spec/javascripts/environments/environments_app_spec.js
+47
-40
spec/javascripts/environments/folder/environments_folder_view_spec.js
...ipts/environments/folder/environments_folder_view_spec.js
+53
-49
spec/javascripts/issue_show/components/title_spec.js
spec/javascripts/issue_show/components/title_spec.js
+6
-12
spec/javascripts/jobs/components/job_app_spec.js
spec/javascripts/jobs/components/job_app_spec.js
+1
-1
spec/javascripts/jobs/store/actions_spec.js
spec/javascripts/jobs/store/actions_spec.js
+4
-32
spec/javascripts/jobs/store/getters_spec.js
spec/javascripts/jobs/store/getters_spec.js
+3
-3
spec/javascripts/lib/utils/common_utils_spec.js
spec/javascripts/lib/utils/common_utils_spec.js
+118
-102
spec/javascripts/lib/utils/number_utility_spec.js
spec/javascripts/lib/utils/number_utility_spec.js
+7
-1
spec/javascripts/monitoring/graph/flag_spec.js
spec/javascripts/monitoring/graph/flag_spec.js
+15
-18
spec/javascripts/notes/components/discussion_filter_spec.js
spec/javascripts/notes/components/discussion_filter_spec.js
+13
-7
spec/javascripts/notes/components/note_app_spec.js
spec/javascripts/notes/components/note_app_spec.js
+2
-1
spec/javascripts/pipelines/graph/graph_component_spec.js
spec/javascripts/pipelines/graph/graph_component_spec.js
+6
-2
spec/javascripts/sidebar/assignees_spec.js
spec/javascripts/sidebar/assignees_spec.js
+48
-31
spec/javascripts/vue_mr_widget/components/mr_widget_pipeline_spec.js
...ripts/vue_mr_widget/components/mr_widget_pipeline_spec.js
+36
-36
spec/javascripts/vue_mr_widget/mock_data.js
spec/javascripts/vue_mr_widget/mock_data.js
+3
-2
spec/javascripts/vue_mr_widget/mr_widget_options_spec.js
spec/javascripts/vue_mr_widget/mr_widget_options_spec.js
+31
-28
spec/javascripts/vue_shared/components/sidebar/collapsed_grouped_date_picker_spec.js
.../components/sidebar/collapsed_grouped_date_picker_spec.js
+4
-4
spec/javascripts/vue_shared/components/sidebar/date_picker_spec.js
...scripts/vue_shared/components/sidebar/date_picker_spec.js
+6
-6
spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_value_collapsed_spec.js
...ts/sidebar/labels_select/dropdown_value_collapsed_spec.js
+3
-1
No files found.
app/assets/javascripts/blob_edit/blob_bundle.js
View file @
160157a9
...
@@ -13,7 +13,7 @@ export default () => {
...
@@ -13,7 +13,7 @@ export default () => {
if
(
editBlobForm
.
length
)
{
if
(
editBlobForm
.
length
)
{
const
urlRoot
=
editBlobForm
.
data
(
'
relativeUrlRoot
'
);
const
urlRoot
=
editBlobForm
.
data
(
'
relativeUrlRoot
'
);
const
assetsPath
=
editBlobForm
.
data
(
'
assetsPrefix
'
);
const
assetsPath
=
editBlobForm
.
data
(
'
assetsPrefix
'
);
const
filePath
=
editBlobForm
.
data
(
'
blobFilename
'
)
const
filePath
=
editBlobForm
.
data
(
'
blobFilename
'
)
;
const
currentAction
=
$
(
'
.js-file-title
'
).
data
(
'
currentAction
'
);
const
currentAction
=
$
(
'
.js-file-title
'
).
data
(
'
currentAction
'
);
const
projectId
=
editBlobForm
.
data
(
'
project-id
'
);
const
projectId
=
editBlobForm
.
data
(
'
project-id
'
);
...
...
app/assets/javascripts/boards/components/board.js
View file @
160157a9
...
@@ -42,7 +42,7 @@ export default Vue.extend({
...
@@ -42,7 +42,7 @@ export default Vue.extend({
required
:
true
,
required
:
true
,
},
},
},
},
data
()
{
data
()
{
return
{
return
{
detailIssue
:
boardsStore
.
detail
,
detailIssue
:
boardsStore
.
detail
,
filter
:
boardsStore
.
filter
,
filter
:
boardsStore
.
filter
,
...
@@ -55,27 +55,26 @@ export default Vue.extend({
...
@@ -55,27 +55,26 @@ export default Vue.extend({
},
},
isNewIssueShown
()
{
isNewIssueShown
()
{
return
this
.
list
.
type
===
'
backlog
'
||
(
!
this
.
disabled
&&
this
.
list
.
type
!==
'
closed
'
);
return
this
.
list
.
type
===
'
backlog
'
||
(
!
this
.
disabled
&&
this
.
list
.
type
!==
'
closed
'
);
}
}
,
},
},
watch
:
{
watch
:
{
filter
:
{
filter
:
{
handler
()
{
handler
()
{
this
.
list
.
page
=
1
;
this
.
list
.
page
=
1
;
this
.
list
.
getIssues
(
true
)
this
.
list
.
getIssues
(
true
).
catch
(()
=>
{
.
catch
(()
=>
{
// TODO: handle request error
// TODO: handle request error
});
});
},
},
deep
:
true
,
deep
:
true
,
}
},
},
mounted
()
{
},
mounted
()
{
this
.
sortableOptions
=
getBoardSortableDefaultOptions
({
this
.
sortableOptions
=
getBoardSortableDefaultOptions
({
disabled
:
this
.
disabled
,
disabled
:
this
.
disabled
,
group
:
'
boards
'
,
group
:
'
boards
'
,
draggable
:
'
.is-draggable
'
,
draggable
:
'
.is-draggable
'
,
handle
:
'
.js-board-handle
'
,
handle
:
'
.js-board-handle
'
,
onEnd
:
(
e
)
=>
{
onEnd
:
e
=>
{
sortableEnd
();
sortableEnd
();
if
(
e
.
newIndex
!==
undefined
&&
e
.
oldIndex
!==
e
.
newIndex
)
{
if
(
e
.
newIndex
!==
undefined
&&
e
.
oldIndex
!==
e
.
newIndex
)
{
...
@@ -86,14 +85,15 @@ export default Vue.extend({
...
@@ -86,14 +85,15 @@ export default Vue.extend({
boardsStore
.
moveList
(
list
,
order
);
boardsStore
.
moveList
(
list
,
order
);
});
});
}
}
}
}
,
});
});
this
.
sortable
=
Sortable
.
create
(
this
.
$el
.
parentNode
,
this
.
sortableOptions
);
this
.
sortable
=
Sortable
.
create
(
this
.
$el
.
parentNode
,
this
.
sortableOptions
);
},
},
created
()
{
created
()
{
if
(
this
.
list
.
isExpandable
&&
AccessorUtilities
.
isLocalStorageAccessSafe
())
{
if
(
this
.
list
.
isExpandable
&&
AccessorUtilities
.
isLocalStorageAccessSafe
())
{
const
isCollapsed
=
localStorage
.
getItem
(
`boards.
${
this
.
boardId
}
.
${
this
.
list
.
type
}
.expanded`
)
===
'
false
'
;
const
isCollapsed
=
localStorage
.
getItem
(
`boards.
${
this
.
boardId
}
.
${
this
.
list
.
type
}
.expanded`
)
===
'
false
'
;
this
.
list
.
isExpanded
=
!
isCollapsed
;
this
.
list
.
isExpanded
=
!
isCollapsed
;
}
}
...
@@ -107,7 +107,10 @@ export default Vue.extend({
...
@@ -107,7 +107,10 @@ export default Vue.extend({
this
.
list
.
isExpanded
=
!
this
.
list
.
isExpanded
;
this
.
list
.
isExpanded
=
!
this
.
list
.
isExpanded
;
if
(
AccessorUtilities
.
isLocalStorageAccessSafe
())
{
if
(
AccessorUtilities
.
isLocalStorageAccessSafe
())
{
localStorage
.
setItem
(
`boards.
${
this
.
boardId
}
.
${
this
.
list
.
type
}
.expanded`
,
this
.
list
.
isExpanded
);
localStorage
.
setItem
(
`boards.
${
this
.
boardId
}
.
${
this
.
list
.
type
}
.expanded`
,
this
.
list
.
isExpanded
,
);
}
}
}
}
},
},
...
...
app/assets/javascripts/boards/components/board_blank_state.vue
View file @
160157a9
...
@@ -32,16 +32,16 @@ export default {
...
@@ -32,16 +32,16 @@ export default {
boardsStore
.
state
.
lists
=
_
.
sortBy
(
boardsStore
.
state
.
lists
,
'
position
'
);
boardsStore
.
state
.
lists
=
_
.
sortBy
(
boardsStore
.
state
.
lists
,
'
position
'
);
// Save the labels
// Save the labels
gl
.
boardService
.
generateDefaultLists
()
gl
.
boardService
.
generateDefaultLists
()
.
then
(
res
=>
res
.
data
)
.
then
(
res
=>
res
.
data
)
.
then
(
(
data
)
=>
{
.
then
(
data
=>
{
data
.
forEach
(
(
listObj
)
=>
{
data
.
forEach
(
listObj
=>
{
const
list
=
boardsStore
.
findList
(
'
title
'
,
listObj
.
title
);
const
list
=
boardsStore
.
findList
(
'
title
'
,
listObj
.
title
);
list
.
id
=
listObj
.
id
;
list
.
id
=
listObj
.
id
;
list
.
label
.
id
=
listObj
.
label
.
id
;
list
.
label
.
id
=
listObj
.
label
.
id
;
list
.
getIssues
()
list
.
getIssues
().
catch
(()
=>
{
.
catch
(()
=>
{
// TODO: handle request error
// TODO: handle request error
});
});
});
});
...
@@ -57,7 +57,6 @@ export default {
...
@@ -57,7 +57,6 @@ export default {
clearBlankState
:
boardsStore
.
removeBlankState
.
bind
(
boardsStore
),
clearBlankState
:
boardsStore
.
removeBlankState
.
bind
(
boardsStore
),
},
},
};
};
</
script
>
</
script
>
<
template
>
<
template
>
...
...
app/assets/javascripts/boards/components/board_card.vue
View file @
160157a9
<
script
>
<
script
>
/* eslint-disable vue/require-default-prop */
/* eslint-disable vue/require-default-prop */
import
IssueCardInner
from
'
./issue_card_inner.vue
'
;
import
IssueCardInner
from
'
./issue_card_inner.vue
'
;
import
eventHub
from
'
../eventhub
'
;
import
eventHub
from
'
../eventhub
'
;
import
boardsStore
from
'
../stores/boards_store
'
;
import
boardsStore
from
'
../stores/boards_store
'
;
export
default
{
export
default
{
name
:
'
BoardsIssueCard
'
,
name
:
'
BoardsIssueCard
'
,
components
:
{
components
:
{
IssueCardInner
,
IssueCardInner
,
...
@@ -71,7 +71,7 @@
...
@@ -71,7 +71,7 @@
}
}
},
},
},
},
};
};
</
script
>
</
script
>
<
template
>
<
template
>
...
...
app/assets/javascripts/boards/components/board_new_issue.vue
View file @
160157a9
...
@@ -62,7 +62,8 @@ export default {
...
@@ -62,7 +62,8 @@ export default {
eventHub
.
$emit
(
`scroll-board-list-
${
this
.
list
.
id
}
`
);
eventHub
.
$emit
(
`scroll-board-list-
${
this
.
list
.
id
}
`
);
this
.
cancel
();
this
.
cancel
();
return
this
.
list
.
newIssue
(
issue
)
return
this
.
list
.
newIssue
(
issue
)
.
then
(()
=>
{
.
then
(()
=>
{
// Need this because our jQuery very kindly disables buttons on ALL form submissions
// Need this because our jQuery very kindly disables buttons on ALL form submissions
$
(
this
.
$refs
.
submitButton
).
enable
();
$
(
this
.
$refs
.
submitButton
).
enable
();
...
...
app/assets/javascripts/boards/components/board_sidebar.js
View file @
160157a9
...
@@ -38,7 +38,7 @@ export default Vue.extend({
...
@@ -38,7 +38,7 @@ export default Vue.extend({
};
};
},
},
computed
:
{
computed
:
{
showSidebar
()
{
showSidebar
()
{
return
Object
.
keys
(
this
.
issue
).
length
;
return
Object
.
keys
(
this
.
issue
).
length
;
},
},
milestoneTitle
()
{
milestoneTitle
()
{
...
@@ -51,18 +51,20 @@ export default Vue.extend({
...
@@ -51,18 +51,20 @@ export default Vue.extend({
return
this
.
issue
.
labels
&&
this
.
issue
.
labels
.
length
;
return
this
.
issue
.
labels
&&
this
.
issue
.
labels
.
length
;
},
},
labelDropdownTitle
()
{
labelDropdownTitle
()
{
return
this
.
hasLabels
?
sprintf
(
__
(
'
%{firstLabel} +%{labelCount} more
'
),
{
return
this
.
hasLabels
?
sprintf
(
__
(
'
%{firstLabel} +%{labelCount} more
'
),
{
firstLabel
:
this
.
issue
.
labels
[
0
].
title
,
firstLabel
:
this
.
issue
.
labels
[
0
].
title
,
labelCount
:
this
.
issue
.
labels
.
length
-
1
labelCount
:
this
.
issue
.
labels
.
length
-
1
,
})
:
__
(
'
Label
'
);
})
:
__
(
'
Label
'
);
},
},
selectedLabels
()
{
selectedLabels
()
{
return
this
.
hasLabels
?
this
.
issue
.
labels
.
map
(
l
=>
l
.
title
).
join
(
'
,
'
)
:
''
;
return
this
.
hasLabels
?
this
.
issue
.
labels
.
map
(
l
=>
l
.
title
).
join
(
'
,
'
)
:
''
;
}
}
,
},
},
watch
:
{
watch
:
{
detail
:
{
detail
:
{
handler
()
{
handler
()
{
if
(
this
.
issue
.
id
!==
this
.
detail
.
issue
.
id
)
{
if
(
this
.
issue
.
id
!==
this
.
detail
.
issue
.
id
)
{
$
(
'
.block.assignee
'
)
$
(
'
.block.assignee
'
)
.
find
(
'
input:not(.js-vue)[name="issue[assignee_ids][]"]
'
)
.
find
(
'
input:not(.js-vue)[name="issue[assignee_ids][]"]
'
)
...
@@ -71,17 +73,19 @@ export default Vue.extend({
...
@@ -71,17 +73,19 @@ export default Vue.extend({
});
});
$
(
'
.js-issue-board-sidebar
'
,
this
.
$el
).
each
((
i
,
el
)
=>
{
$
(
'
.js-issue-board-sidebar
'
,
this
.
$el
).
each
((
i
,
el
)
=>
{
$
(
el
).
data
(
'
glDropdown
'
).
clearMenu
();
$
(
el
)
.
data
(
'
glDropdown
'
)
.
clearMenu
();
});
});
}
}
this
.
issue
=
this
.
detail
.
issue
;
this
.
issue
=
this
.
detail
.
issue
;
this
.
list
=
this
.
detail
.
list
;
this
.
list
=
this
.
detail
.
list
;
},
},
deep
:
true
deep
:
true
,
},
},
},
},
created
()
{
created
()
{
// Get events from glDropdown
// Get events from glDropdown
eventHub
.
$on
(
'
sidebar.removeAssignee
'
,
this
.
removeAssignee
);
eventHub
.
$on
(
'
sidebar.removeAssignee
'
,
this
.
removeAssignee
);
eventHub
.
$on
(
'
sidebar.addAssignee
'
,
this
.
addAssignee
);
eventHub
.
$on
(
'
sidebar.addAssignee
'
,
this
.
addAssignee
);
...
@@ -94,7 +98,7 @@ export default Vue.extend({
...
@@ -94,7 +98,7 @@ export default Vue.extend({
eventHub
.
$off
(
'
sidebar.removeAllAssignees
'
,
this
.
removeAllAssignees
);
eventHub
.
$off
(
'
sidebar.removeAllAssignees
'
,
this
.
removeAllAssignees
);
eventHub
.
$off
(
'
sidebar.saveAssignees
'
,
this
.
saveAssignees
);
eventHub
.
$off
(
'
sidebar.saveAssignees
'
,
this
.
saveAssignees
);
},
},
mounted
()
{
mounted
()
{
new
IssuableContext
(
this
.
currentUser
);
new
IssuableContext
(
this
.
currentUser
);
new
MilestoneSelect
();
new
MilestoneSelect
();
new
DueDateSelectors
();
new
DueDateSelectors
();
...
@@ -102,29 +106,30 @@ export default Vue.extend({
...
@@ -102,29 +106,30 @@ export default Vue.extend({
new
Sidebar
();
new
Sidebar
();
},
},
methods
:
{
methods
:
{
closeSidebar
()
{
closeSidebar
()
{
this
.
detail
.
issue
=
{};
this
.
detail
.
issue
=
{};
},
},
assignSelf
()
{
assignSelf
()
{
// Notify gl dropdown that we are now assigning to current user
// Notify gl dropdown that we are now assigning to current user
this
.
$refs
.
assigneeBlock
.
dispatchEvent
(
new
Event
(
'
assignYourself
'
));
this
.
$refs
.
assigneeBlock
.
dispatchEvent
(
new
Event
(
'
assignYourself
'
));
this
.
addAssignee
(
this
.
currentUser
);
this
.
addAssignee
(
this
.
currentUser
);
this
.
saveAssignees
();
this
.
saveAssignees
();
},
},
removeAssignee
(
a
)
{
removeAssignee
(
a
)
{
boardsStore
.
detail
.
issue
.
removeAssignee
(
a
);
boardsStore
.
detail
.
issue
.
removeAssignee
(
a
);
},
},
addAssignee
(
a
)
{
addAssignee
(
a
)
{
boardsStore
.
detail
.
issue
.
addAssignee
(
a
);
boardsStore
.
detail
.
issue
.
addAssignee
(
a
);
},
},
removeAllAssignees
()
{
removeAllAssignees
()
{
boardsStore
.
detail
.
issue
.
removeAllAssignees
();
boardsStore
.
detail
.
issue
.
removeAllAssignees
();
},
},
saveAssignees
()
{
saveAssignees
()
{
this
.
loadingAssignees
=
true
;
this
.
loadingAssignees
=
true
;
boardsStore
.
detail
.
issue
.
update
()
boardsStore
.
detail
.
issue
.
update
()
.
then
(()
=>
{
.
then
(()
=>
{
this
.
loadingAssignees
=
false
;
this
.
loadingAssignees
=
false
;
})
})
...
...
app/assets/javascripts/boards/components/issue_card_inner.vue
View file @
160157a9
<
script
>
<
script
>
import
$
from
'
jquery
'
;
import
$
from
'
jquery
'
;
import
Icon
from
'
~/vue_shared/components/icon.vue
'
;
import
Icon
from
'
~/vue_shared/components/icon.vue
'
;
import
UserAvatarLink
from
'
../../vue_shared/components/user_avatar/user_avatar_link.vue
'
;
import
UserAvatarLink
from
'
../../vue_shared/components/user_avatar/user_avatar_link.vue
'
;
import
eventHub
from
'
../eventhub
'
;
import
eventHub
from
'
../eventhub
'
;
import
tooltip
from
'
../../vue_shared/directives/tooltip
'
;
import
tooltip
from
'
../../vue_shared/directives/tooltip
'
;
import
boardsStore
from
'
../stores/boards_store
'
;
import
boardsStore
from
'
../stores/boards_store
'
;
export
default
{
export
default
{
components
:
{
components
:
{
UserAvatarLink
,
UserAvatarLink
,
Icon
,
Icon
,
...
@@ -136,7 +136,7 @@
...
@@ -136,7 +136,7 @@
};
};
},
},
},
},
};
};
</
script
>
</
script
>
<
template
>
<
template
>
<div>
<div>
...
...
app/assets/javascripts/boards/components/modal/empty_state.vue
View file @
160157a9
...
@@ -20,7 +20,7 @@ export default {
...
@@ -20,7 +20,7 @@ export default {
computed
:
{
computed
:
{
contents
()
{
contents
()
{
const
obj
=
{
const
obj
=
{
title
:
'
You haven
\'
t added any issues to your project yet
'
,
title
:
"
You haven't added any issues to your project yet
"
,
content
:
`
content
:
`
An issue can be a bug, a todo or a feature request that needs to be
An issue can be a bug, a todo or a feature request that needs to be
discussed in a project. Besides, issues are searchable and filterable.
discussed in a project. Besides, issues are searchable and filterable.
...
@@ -28,7 +28,7 @@ export default {
...
@@ -28,7 +28,7 @@ export default {
};
};
if
(
this
.
activeTab
===
'
selected
'
)
{
if
(
this
.
activeTab
===
'
selected
'
)
{
obj
.
title
=
'
You haven
\'
t selected any issues yet
'
;
obj
.
title
=
"
You haven't selected any issues yet
"
;
obj
.
content
=
`
obj
.
content
=
`
Go back to <strong>Open issues</strong> and select some issues
Go back to <strong>Open issues</strong> and select some issues
to add to your board.
to add to your board.
...
...
app/assets/javascripts/boards/components/modal/footer.vue
View file @
160157a9
...
@@ -42,19 +42,17 @@ export default {
...
@@ -42,19 +42,17 @@ export default {
const
req
=
this
.
buildUpdateRequest
(
list
);
const
req
=
this
.
buildUpdateRequest
(
list
);
// Post the data to the backend
// Post the data to the backend
gl
.
boardService
gl
.
boardService
.
bulkUpdate
(
issueIds
,
req
).
catch
(()
=>
{
.
bulkUpdate
(
issueIds
,
req
)
.
catch
(()
=>
{
Flash
(
__
(
'
Failed to update issues, please try again.
'
));
Flash
(
__
(
'
Failed to update issues, please try again.
'
));
selectedIssues
.
forEach
((
issue
)
=>
{
selectedIssues
.
forEach
(
issue
=>
{
list
.
removeIssue
(
issue
);
list
.
removeIssue
(
issue
);
list
.
issuesSize
-=
1
;
list
.
issuesSize
-=
1
;
});
});
});
});
// Add the issues on the frontend
// Add the issues on the frontend
selectedIssues
.
forEach
(
(
issue
)
=>
{
selectedIssues
.
forEach
(
issue
=>
{
list
.
addIssue
(
issue
);
list
.
addIssue
(
issue
);
list
.
issuesSize
+=
1
;
list
.
issuesSize
+=
1
;
});
});
...
...
app/assets/javascripts/boards/components/modal/header.vue
View file @
160157a9
<
script
>
<
script
>
import
ModalFilters
from
'
./filters
'
;
import
ModalFilters
from
'
./filters
'
;
import
ModalTabs
from
'
./tabs.vue
'
;
import
ModalTabs
from
'
./tabs.vue
'
;
import
ModalStore
from
'
../../stores/modal_store
'
;
import
ModalStore
from
'
../../stores/modal_store
'
;
import
modalMixin
from
'
../../mixins/modal_mixins
'
;
import
modalMixin
from
'
../../mixins/modal_mixins
'
;
export
default
{
export
default
{
components
:
{
components
:
{
ModalTabs
,
ModalTabs
,
ModalFilters
,
ModalFilters
,
...
@@ -46,7 +46,7 @@
...
@@ -46,7 +46,7 @@
ModalStore
.
toggleAll
();
ModalStore
.
toggleAll
();
},
},
},
},
};
};
</
script
>
</
script
>
<
template
>
<
template
>
<div>
<div>
...
...
app/assets/javascripts/boards/components/modal/index.vue
View file @
160157a9
<
script
>
<
script
>
/* global ListIssue */
/* global ListIssue */
import
{
urlParamsToObject
}
from
'
~/lib/utils/common_utils
'
;
import
{
urlParamsToObject
}
from
'
~/lib/utils/common_utils
'
;
import
ModalHeader
from
'
./header.vue
'
;
import
ModalHeader
from
'
./header.vue
'
;
import
ModalList
from
'
./list.vue
'
;
import
ModalList
from
'
./list.vue
'
;
import
ModalFooter
from
'
./footer.vue
'
;
import
ModalFooter
from
'
./footer.vue
'
;
import
EmptyState
from
'
./empty_state.vue
'
;
import
EmptyState
from
'
./empty_state.vue
'
;
import
ModalStore
from
'
../../stores/modal_store
'
;
import
ModalStore
from
'
../../stores/modal_store
'
;
export
default
{
export
default
{
components
:
{
components
:
{
EmptyState
,
EmptyState
,
ModalHeader
,
ModalHeader
,
...
@@ -107,7 +107,8 @@
...
@@ -107,7 +107,8 @@
loadIssues
(
clearIssues
=
false
)
{
loadIssues
(
clearIssues
=
false
)
{
if
(
!
this
.
showAddIssuesModal
)
return
false
;
if
(
!
this
.
showAddIssuesModal
)
return
false
;
return
gl
.
boardService
.
getBacklog
({
return
gl
.
boardService
.
getBacklog
({
...
urlParamsToObject
(
this
.
filter
.
path
),
...
urlParamsToObject
(
this
.
filter
.
path
),
page
:
this
.
page
,
page
:
this
.
page
,
per
:
this
.
perPage
,
per
:
this
.
perPage
,
...
@@ -137,7 +138,7 @@
...
@@ -137,7 +138,7 @@
});
});
},
},
},
},
};
};
</
script
>
</
script
>
<
template
>
<
template
>
<div
<div
...
...
app/assets/javascripts/boards/components/modal/list.vue
View file @
160157a9
<
script
>
<
script
>
import
Icon
from
'
~/vue_shared/components/icon.vue
'
;
import
Icon
from
'
~/vue_shared/components/icon.vue
'
;
import
bp
from
'
../../../breakpoints
'
;
import
bp
from
'
../../../breakpoints
'
;
import
ModalStore
from
'
../../stores/modal_store
'
;
import
ModalStore
from
'
../../stores/modal_store
'
;
import
IssueCardInner
from
'
../issue_card_inner.vue
'
;
import
IssueCardInner
from
'
../issue_card_inner.vue
'
;
export
default
{
export
default
{
components
:
{
components
:
{
IssueCardInner
,
IssueCardInner
,
Icon
,
Icon
,
...
@@ -114,7 +114,7 @@
...
@@ -114,7 +114,7 @@
}
}
},
},
},
},
};
};
</
script
>
</
script
>
<
template
>
<
template
>
<section
<section
...
...
app/assets/javascripts/boards/components/modal/tabs.vue
View file @
160157a9
<
script
>
<
script
>
import
ModalStore
from
'
../../stores/modal_store
'
;
import
ModalStore
from
'
../../stores/modal_store
'
;
import
modalMixin
from
'
../../mixins/modal_mixins
'
;
import
modalMixin
from
'
../../mixins/modal_mixins
'
;
export
default
{
export
default
{
mixins
:
[
modalMixin
],
mixins
:
[
modalMixin
],
data
()
{
data
()
{
return
ModalStore
.
store
;
return
ModalStore
.
store
;
...
@@ -15,7 +15,7 @@
...
@@ -15,7 +15,7 @@
destroyed
()
{
destroyed
()
{
this
.
activeTab
=
'
all
'
;
this
.
activeTab
=
'
all
'
;
},
},
};
};
</
script
>
</
script
>
<
template
>
<
template
>
<div
class=
"top-area prepend-top-10 append-bottom-10"
>
<div
class=
"top-area prepend-top-10 append-bottom-10"
>
...
...
app/assets/javascripts/boards/components/new_list_dropdown.js
View file @
160157a9
...
@@ -6,7 +6,9 @@ import _ from 'underscore';
...
@@ -6,7 +6,9 @@ import _ from 'underscore';
import
CreateLabelDropdown
from
'
../../create_label
'
;
import
CreateLabelDropdown
from
'
../../create_label
'
;
import
boardsStore
from
'
../stores/boards_store
'
;
import
boardsStore
from
'
../stores/boards_store
'
;
$
(
document
).
off
(
'
created.label
'
).
on
(
'
created.label
'
,
(
e
,
label
)
=>
{
$
(
document
)
.
off
(
'
created.label
'
)
.
on
(
'
created.label
'
,
(
e
,
label
)
=>
{
boardsStore
.
new
({
boardsStore
.
new
({
title
:
label
.
title
,
title
:
label
.
title
,
position
:
boardsStore
.
state
.
lists
.
length
-
2
,
position
:
boardsStore
.
state
.
lists
.
length
-
2
,
...
@@ -17,25 +19,28 @@ $(document).off('created.label').on('created.label', (e, label) => {
...
@@ -17,25 +19,28 @@ $(document).off('created.label').on('created.label', (e, label) => {
color
:
label
.
color
,
color
:
label
.
color
,
},
},
});
});
});
});
export
default
function
initNewListDropdown
()
{
export
default
function
initNewListDropdown
()
{
$
(
'
.js-new-board-list
'
).
each
(
function
()
{
$
(
'
.js-new-board-list
'
).
each
(
function
()
{
const
$this
=
$
(
this
);
const
$this
=
$
(
this
);
new
CreateLabelDropdown
(
$this
.
closest
(
'
.dropdown
'
).
find
(
'
.dropdown-new-label
'
),
$this
.
data
(
'
namespacePath
'
),
$this
.
data
(
'
projectPath
'
));
new
CreateLabelDropdown
(
$this
.
closest
(
'
.dropdown
'
).
find
(
'
.dropdown-new-label
'
),
$this
.
data
(
'
namespacePath
'
),
$this
.
data
(
'
projectPath
'
),
);
$this
.
glDropdown
({
$this
.
glDropdown
({
data
(
term
,
callback
)
{
data
(
term
,
callback
)
{
axios
.
get
(
$this
.
attr
(
'
data-list-labels-path
'
))
axios
.
get
(
$this
.
attr
(
'
data-list-labels-path
'
)).
then
(({
data
})
=>
{
.
then
(({
data
})
=>
{
callback
(
data
);
callback
(
data
);
});
});
},
},
renderRow
(
label
)
{
renderRow
(
label
)
{
const
active
=
boardsStore
.
findList
(
'
title
'
,
label
.
title
);
const
active
=
boardsStore
.
findList
(
'
title
'
,
label
.
title
);
const
$li
=
$
(
'
<li />
'
);
const
$li
=
$
(
'
<li />
'
);
const
$a
=
$
(
'
<a />
'
,
{
const
$a
=
$
(
'
<a />
'
,
{
class
:
(
active
?
`is-active js-board-list-
${
active
.
id
}
`
:
''
)
,
class
:
active
?
`is-active js-board-list-
${
active
.
id
}
`
:
''
,
text
:
label
.
title
,
text
:
label
.
title
,
href
:
'
#
'
,
href
:
'
#
'
,
});
});
...
@@ -53,7 +58,7 @@ export default function initNewListDropdown() {
...
@@ -53,7 +58,7 @@ export default function initNewListDropdown() {
selectable
:
true
,
selectable
:
true
,
multiSelect
:
true
,
multiSelect
:
true
,
containerSelector
:
'
.js-tab-container-labels .dropdown-page-one .dropdown-content
'
,
containerSelector
:
'
.js-tab-container-labels .dropdown-page-one .dropdown-content
'
,
clicked
(
options
)
{
clicked
(
options
)
{
const
{
e
}
=
options
;
const
{
e
}
=
options
;
const
label
=
options
.
selectedObj
;
const
label
=
options
.
selectedObj
;
e
.
preventDefault
();
e
.
preventDefault
();
...
...
app/assets/javascripts/boards/components/project_select.vue
View file @
160157a9
...
@@ -46,7 +46,7 @@ export default {
...
@@ -46,7 +46,7 @@ export default {
selectable
:
true
,
selectable
:
true
,
data
:
(
term
,
callback
)
=>
{
data
:
(
term
,
callback
)
=>
{
this
.
loading
=
true
;
this
.
loading
=
true
;
return
Api
.
groupProjects
(
this
.
groupId
,
term
,
{
with_issues_enabled
:
true
},
projects
=>
{
return
Api
.
groupProjects
(
this
.
groupId
,
term
,
{
with_issues_enabled
:
true
},
projects
=>
{
this
.
loading
=
false
;
this
.
loading
=
false
;
callback
(
projects
);
callback
(
projects
);
});
});
...
@@ -54,7 +54,9 @@ export default {
...
@@ -54,7 +54,9 @@ export default {
renderRow
(
project
)
{
renderRow
(
project
)
{
return
`
return
`
<li>
<li>
<a href='#' class='dropdown-menu-link' data-project-id="
${
project
.
id
}
" data-project-name="
${
project
.
name
}
">
<a href='#' class='dropdown-menu-link' data-project-id="
${
project
.
id
}
" data-project-name="
${
project
.
name
}
">
${
_
.
escape
(
project
.
name
)}
${
_
.
escape
(
project
.
name
)}
</a>
</a>
</li>
</li>
...
...
app/assets/javascripts/boards/components/sidebar/remove_issue.vue
View file @
160157a9
<
script
>
<
script
>
import
Vue
from
'
vue
'
;
import
Vue
from
'
vue
'
;
import
Flash
from
'
../../../flash
'
;
import
Flash
from
'
../../../flash
'
;
import
{
__
}
from
'
../../../locale
'
;
import
{
__
}
from
'
../../../locale
'
;
import
boardsStore
from
'
../../stores/boards_store
'
;
import
boardsStore
from
'
../../stores/boards_store
'
;
export
default
Vue
.
extend
({
export
default
Vue
.
extend
({
props
:
{
props
:
{
issue
:
{
issue
:
{
type
:
Object
,
type
:
Object
,
...
@@ -56,9 +56,7 @@
...
@@ -56,9 +56,7 @@
buildPatchRequest
(
issue
,
lists
)
{
buildPatchRequest
(
issue
,
lists
)
{
const
listLabelIds
=
lists
.
map
(
list
=>
list
.
label
.
id
);
const
listLabelIds
=
lists
.
map
(
list
=>
list
.
label
.
id
);
const
labelIds
=
issue
.
labels
const
labelIds
=
issue
.
labels
.
map
(
label
=>
label
.
id
).
filter
(
id
=>
!
listLabelIds
.
includes
(
id
));
.
map
(
label
=>
label
.
id
)
.
filter
(
id
=>
!
listLabelIds
.
includes
(
id
));
return
{
return
{
label_ids
:
labelIds
,
label_ids
:
labelIds
,
...
@@ -73,7 +71,7 @@
...
@@ -73,7 +71,7 @@
return
req
;
return
req
;
},
},
},
},
});
});
</
script
>
</
script
>
<
template
>
<
template
>
<div
<div
...
...
app/assets/javascripts/boards/filtered_search_boards.js
View file @
160157a9
...
@@ -32,7 +32,7 @@ export default class FilteredSearchBoards extends FilteredSearchManager {
...
@@ -32,7 +32,7 @@ export default class FilteredSearchBoards extends FilteredSearchManager {
const
tokens
=
FilteredSearchContainer
.
container
.
querySelectorAll
(
'
.js-visual-token
'
);
const
tokens
=
FilteredSearchContainer
.
container
.
querySelectorAll
(
'
.js-visual-token
'
);
// Remove all the tokens as they will be replaced by the search manager
// Remove all the tokens as they will be replaced by the search manager
[].
forEach
.
call
(
tokens
,
(
el
)
=>
{
[].
forEach
.
call
(
tokens
,
el
=>
{
el
.
parentNode
.
removeChild
(
el
);
el
.
parentNode
.
removeChild
(
el
);
});
});
...
@@ -50,7 +50,10 @@ export default class FilteredSearchBoards extends FilteredSearchManager {
...
@@ -50,7 +50,10 @@ export default class FilteredSearchBoards extends FilteredSearchManager {
canEdit
(
tokenName
,
tokenValue
)
{
canEdit
(
tokenName
,
tokenValue
)
{
if
(
this
.
cantEdit
.
includes
(
tokenName
))
return
false
;
if
(
this
.
cantEdit
.
includes
(
tokenName
))
return
false
;
return
this
.
cantEditWithValue
.
findIndex
(
token
=>
token
.
name
===
tokenName
&&
return
(
token
.
value
===
tokenValue
)
===
-
1
;
this
.
cantEditWithValue
.
findIndex
(
token
=>
token
.
name
===
tokenName
&&
token
.
value
===
tokenValue
,
)
===
-
1
);
}
}
}
}
app/assets/javascripts/boards/index.js
View file @
160157a9
...
@@ -32,9 +32,9 @@ export default () => {
...
@@ -32,9 +32,9 @@ export default () => {
const
$boardApp
=
document
.
getElementById
(
'
board-app
'
);
const
$boardApp
=
document
.
getElementById
(
'
board-app
'
);
// check for browser back and trigger a hard reload to circumvent browser caching.
// check for browser back and trigger a hard reload to circumvent browser caching.
window
.
addEventListener
(
'
pageshow
'
,
(
event
)
=>
{
window
.
addEventListener
(
'
pageshow
'
,
event
=>
{
const
isNavTypeBackForward
=
window
.
performance
&&
const
isNavTypeBackForward
=
window
.
performance
.
navigation
.
type
===
NavigationType
.
TYPE_BACK_FORWARD
;
window
.
performance
&&
window
.
performance
.
navigation
.
type
===
NavigationType
.
TYPE_BACK_FORWARD
;
if
(
event
.
persisted
||
isNavTypeBackForward
)
{
if
(
event
.
persisted
||
isNavTypeBackForward
)
{
window
.
location
.
reload
();
window
.
location
.
reload
();
...
...
app/assets/javascripts/boards/mixins/sortable_default_options.js
View file @
160157a9
...
@@ -4,7 +4,8 @@ import $ from 'jquery';
...
@@ -4,7 +4,8 @@ import $ from 'jquery';
import
sortableConfig
from
'
../../sortable/sortable_config
'
;
import
sortableConfig
from
'
../../sortable/sortable_config
'
;
export
function
sortableStart
()
{
export
function
sortableStart
()
{
$
(
'
.has-tooltip
'
).
tooltip
(
'
hide
'
)
$
(
'
.has-tooltip
'
)
.
tooltip
(
'
hide
'
)
.
tooltip
(
'
disable
'
);
.
tooltip
(
'
disable
'
);
document
.
body
.
classList
.
add
(
'
is-dragging
'
);
document
.
body
.
classList
.
add
(
'
is-dragging
'
);
}
}
...
@@ -15,7 +16,8 @@ export function sortableEnd() {
...
@@ -15,7 +16,8 @@ export function sortableEnd() {
}
}
export
function
getBoardSortableDefaultOptions
(
obj
)
{
export
function
getBoardSortableDefaultOptions
(
obj
)
{
const
touchEnabled
=
(
'
ontouchstart
'
in
window
)
||
window
.
DocumentTouch
&&
document
instanceof
DocumentTouch
;
const
touchEnabled
=
'
ontouchstart
'
in
window
||
(
window
.
DocumentTouch
&&
document
instanceof
DocumentTouch
);
const
defaultSortOptions
=
Object
.
assign
({},
sortableConfig
,
{
const
defaultSortOptions
=
Object
.
assign
({},
sortableConfig
,
{
filter
:
'
.board-delete, .btn
'
,
filter
:
'
.board-delete, .btn
'
,
...
@@ -26,6 +28,8 @@ export function getBoardSortableDefaultOptions(obj) {
...
@@ -26,6 +28,8 @@ export function getBoardSortableDefaultOptions(obj) {
onEnd
:
sortableEnd
,
onEnd
:
sortableEnd
,
});
});
Object
.
keys
(
obj
).
forEach
((
key
)
=>
{
defaultSortOptions
[
key
]
=
obj
[
key
];
});
Object
.
keys
(
obj
).
forEach
(
key
=>
{
defaultSortOptions
[
key
]
=
obj
[
key
];
});
return
defaultSortOptions
;
return
defaultSortOptions
;
}
}
app/assets/javascripts/boards/models/issue.js
View file @
160157a9
...
@@ -9,7 +9,7 @@ import IssueProject from './project';
...
@@ -9,7 +9,7 @@ import IssueProject from './project';
import
boardsStore
from
'
../stores/boards_store
'
;
import
boardsStore
from
'
../stores/boards_store
'
;
class
ListIssue
{
class
ListIssue
{
constructor
(
obj
,
defaultAvatar
)
{
constructor
(
obj
,
defaultAvatar
)
{
this
.
id
=
obj
.
id
;
this
.
id
=
obj
.
id
;
this
.
iid
=
obj
.
iid
;
this
.
iid
=
obj
.
iid
;
this
.
title
=
obj
.
title
;
this
.
title
=
obj
.
title
;
...
@@ -39,54 +39,54 @@ class ListIssue {
...
@@ -39,54 +39,54 @@ class ListIssue {
this
.
milestone
=
new
ListMilestone
(
obj
.
milestone
);
this
.
milestone
=
new
ListMilestone
(
obj
.
milestone
);
}
}
obj
.
labels
.
forEach
(
(
label
)
=>
{
obj
.
labels
.
forEach
(
label
=>
{
this
.
labels
.
push
(
new
ListLabel
(
label
));
this
.
labels
.
push
(
new
ListLabel
(
label
));
});
});
this
.
assignees
=
obj
.
assignees
.
map
(
a
=>
new
ListAssignee
(
a
,
defaultAvatar
));
this
.
assignees
=
obj
.
assignees
.
map
(
a
=>
new
ListAssignee
(
a
,
defaultAvatar
));
}
}
addLabel
(
label
)
{
addLabel
(
label
)
{
if
(
!
this
.
findLabel
(
label
))
{
if
(
!
this
.
findLabel
(
label
))
{
this
.
labels
.
push
(
new
ListLabel
(
label
));
this
.
labels
.
push
(
new
ListLabel
(
label
));
}
}
}
}
findLabel
(
findLabel
)
{
findLabel
(
findLabel
)
{
return
this
.
labels
.
filter
(
label
=>
label
.
title
===
findLabel
.
title
)[
0
];
return
this
.
labels
.
filter
(
label
=>
label
.
title
===
findLabel
.
title
)[
0
];
}
}
removeLabel
(
removeLabel
)
{
removeLabel
(
removeLabel
)
{
if
(
removeLabel
)
{
if
(
removeLabel
)
{
this
.
labels
=
this
.
labels
.
filter
(
label
=>
removeLabel
.
title
!==
label
.
title
);
this
.
labels
=
this
.
labels
.
filter
(
label
=>
removeLabel
.
title
!==
label
.
title
);
}
}
}
}
removeLabels
(
labels
)
{
removeLabels
(
labels
)
{
labels
.
forEach
(
this
.
removeLabel
.
bind
(
this
));
labels
.
forEach
(
this
.
removeLabel
.
bind
(
this
));
}
}
addAssignee
(
assignee
)
{
addAssignee
(
assignee
)
{
if
(
!
this
.
findAssignee
(
assignee
))
{
if
(
!
this
.
findAssignee
(
assignee
))
{
this
.
assignees
.
push
(
new
ListAssignee
(
assignee
));
this
.
assignees
.
push
(
new
ListAssignee
(
assignee
));
}
}
}
}
findAssignee
(
findAssignee
)
{
findAssignee
(
findAssignee
)
{
return
this
.
assignees
.
filter
(
assignee
=>
assignee
.
id
===
findAssignee
.
id
)[
0
];
return
this
.
assignees
.
filter
(
assignee
=>
assignee
.
id
===
findAssignee
.
id
)[
0
];
}
}
removeAssignee
(
removeAssignee
)
{
removeAssignee
(
removeAssignee
)
{
if
(
removeAssignee
)
{
if
(
removeAssignee
)
{
this
.
assignees
=
this
.
assignees
.
filter
(
assignee
=>
assignee
.
id
!==
removeAssignee
.
id
);
this
.
assignees
=
this
.
assignees
.
filter
(
assignee
=>
assignee
.
id
!==
removeAssignee
.
id
);
}
}
}
}
removeAllAssignees
()
{
removeAllAssignees
()
{
this
.
assignees
=
[];
this
.
assignees
=
[];
}
}
getLists
()
{
getLists
()
{
return
boardsStore
.
state
.
lists
.
filter
(
list
=>
list
.
findIssue
(
this
.
id
));
return
boardsStore
.
state
.
lists
.
filter
(
list
=>
list
.
findIssue
(
this
.
id
));
}
}
...
@@ -102,14 +102,14 @@ class ListIssue {
...
@@ -102,14 +102,14 @@ class ListIssue {
this
.
isLoading
[
key
]
=
value
;
this
.
isLoading
[
key
]
=
value
;
}
}
update
()
{
update
()
{
const
data
=
{
const
data
=
{
issue
:
{
issue
:
{
milestone_id
:
this
.
milestone
?
this
.
milestone
.
id
:
null
,
milestone_id
:
this
.
milestone
?
this
.
milestone
.
id
:
null
,
due_date
:
this
.
dueDate
,
due_date
:
this
.
dueDate
,
assignee_ids
:
this
.
assignees
.
length
>
0
?
this
.
assignees
.
map
(
(
u
)
=>
u
.
id
)
:
[
0
],
assignee_ids
:
this
.
assignees
.
length
>
0
?
this
.
assignees
.
map
(
u
=>
u
.
id
)
:
[
0
],
label_ids
:
this
.
labels
.
map
(
(
label
)
=>
label
.
id
)
label_ids
:
this
.
labels
.
map
(
label
=>
label
.
id
),
}
}
,
};
};
if
(
!
data
.
issue
.
label_ids
.
length
)
{
if
(
!
data
.
issue
.
label_ids
.
length
)
{
...
...
app/assets/javascripts/boards/models/list.js
View file @
160157a9
...
@@ -234,11 +234,11 @@ class List {
...
@@ -234,11 +234,11 @@ class List {
});
});
}
}
getTypeInfo
(
type
)
{
getTypeInfo
(
type
)
{
return
TYPES
[
type
]
||
{};
return
TYPES
[
type
]
||
{};
}
}
onNewIssueResponse
(
issue
,
data
)
{
onNewIssueResponse
(
issue
,
data
)
{
issue
.
id
=
data
.
id
;
issue
.
id
=
data
.
id
;
issue
.
iid
=
data
.
iid
;
issue
.
iid
=
data
.
iid
;
issue
.
project
=
data
.
project
;
issue
.
project
=
data
.
project
;
...
...
app/assets/javascripts/boards/services/board_service.js
View file @
160157a9
...
@@ -19,7 +19,9 @@ export default class BoardService {
...
@@ -19,7 +19,9 @@ export default class BoardService {
}
}
static
generateIssuePath
(
boardId
,
id
)
{
static
generateIssuePath
(
boardId
,
id
)
{
return
`
${
gon
.
relative_url_root
}
/-/boards/
${
boardId
?
`
${
boardId
}
`
:
''
}
/issues
${
id
?
`/
${
id
}
`
:
''
}
`
;
return
`
${
gon
.
relative_url_root
}
/-/boards/
${
boardId
?
`
${
boardId
}
`
:
''
}
/issues
${
id
?
`/
${
id
}
`
:
''
}
`
;
}
}
all
()
{
all
()
{
...
@@ -54,7 +56,9 @@ export default class BoardService {
...
@@ -54,7 +56,9 @@ export default class BoardService {
getIssuesForList
(
id
,
filter
=
{})
{
getIssuesForList
(
id
,
filter
=
{})
{
const
data
=
{
id
};
const
data
=
{
id
};
Object
.
keys
(
filter
).
forEach
((
key
)
=>
{
data
[
key
]
=
filter
[
key
];
});
Object
.
keys
(
filter
).
forEach
(
key
=>
{
data
[
key
]
=
filter
[
key
];
});
return
axios
.
get
(
mergeUrlParams
(
data
,
this
.
generateIssuesPath
(
id
)));
return
axios
.
get
(
mergeUrlParams
(
data
,
this
.
generateIssuesPath
(
id
)));
}
}
...
@@ -75,7 +79,9 @@ export default class BoardService {
...
@@ -75,7 +79,9 @@ export default class BoardService {
}
}
getBacklog
(
data
)
{
getBacklog
(
data
)
{
return
axios
.
get
(
mergeUrlParams
(
data
,
`
${
gon
.
relative_url_root
}
/-/boards/
${
this
.
boardId
}
/issues.json`
));
return
axios
.
get
(
mergeUrlParams
(
data
,
`
${
gon
.
relative_url_root
}
/-/boards/
${
this
.
boardId
}
/issues.json`
),
);
}
}
bulkUpdate
(
issueIds
,
extraData
=
{})
{
bulkUpdate
(
issueIds
,
extraData
=
{})
{
...
...
app/assets/javascripts/boards/stores/boards_store.js
View file @
160157a9
...
@@ -20,20 +20,20 @@ const boardsStore = {
...
@@ -20,20 +20,20 @@ const boardsStore = {
issue
:
{},
issue
:
{},
list
:
{},
list
:
{},
},
},
create
()
{
create
()
{
this
.
state
.
lists
=
[];
this
.
state
.
lists
=
[];
this
.
filter
.
path
=
getUrlParamsArray
().
join
(
'
&
'
);
this
.
filter
.
path
=
getUrlParamsArray
().
join
(
'
&
'
);
this
.
detail
=
{
this
.
detail
=
{
issue
:
{},
issue
:
{},
};
};
},
},
addList
(
listObj
,
defaultAvatar
)
{
addList
(
listObj
,
defaultAvatar
)
{
const
list
=
new
List
(
listObj
,
defaultAvatar
);
const
list
=
new
List
(
listObj
,
defaultAvatar
);
this
.
state
.
lists
.
push
(
list
);
this
.
state
.
lists
.
push
(
list
);
return
list
;
return
list
;
},
},
new
(
listObj
)
{
new
(
listObj
)
{
const
list
=
this
.
addList
(
listObj
);
const
list
=
this
.
addList
(
listObj
);
const
backlogList
=
this
.
findList
(
'
type
'
,
'
backlog
'
,
'
backlog
'
);
const
backlogList
=
this
.
findList
(
'
type
'
,
'
backlog
'
,
'
backlog
'
);
...
@@ -50,44 +50,44 @@ const boardsStore = {
...
@@ -50,44 +50,44 @@ const boardsStore = {
});
});
this
.
removeBlankState
();
this
.
removeBlankState
();
},
},
updateNewListDropdown
(
listId
)
{
updateNewListDropdown
(
listId
)
{
$
(
`.js-board-list-
${
listId
}
`
).
removeClass
(
'
is-active
'
);
$
(
`.js-board-list-
${
listId
}
`
).
removeClass
(
'
is-active
'
);
},
},
shouldAddBlankState
()
{
shouldAddBlankState
()
{
// Decide whether to add the blank state
// Decide whether to add the blank state
return
!
(
this
.
state
.
lists
.
filter
(
list
=>
list
.
type
!==
'
backlog
'
&&
list
.
type
!==
'
closed
'
)[
0
])
;
return
!
this
.
state
.
lists
.
filter
(
list
=>
list
.
type
!==
'
backlog
'
&&
list
.
type
!==
'
closed
'
)[
0
]
;
},
},
addBlankState
()
{
addBlankState
()
{
if
(
!
this
.
shouldAddBlankState
()
||
this
.
welcomeIsHidden
()
||
this
.
disabled
)
return
;
if
(
!
this
.
shouldAddBlankState
()
||
this
.
welcomeIsHidden
()
||
this
.
disabled
)
return
;
this
.
addList
({
this
.
addList
({
id
:
'
blank
'
,
id
:
'
blank
'
,
list_type
:
'
blank
'
,
list_type
:
'
blank
'
,
title
:
'
Welcome to your Issue Board!
'
,
title
:
'
Welcome to your Issue Board!
'
,
position
:
0
position
:
0
,
});
});
this
.
state
.
lists
=
_
.
sortBy
(
this
.
state
.
lists
,
'
position
'
);
this
.
state
.
lists
=
_
.
sortBy
(
this
.
state
.
lists
,
'
position
'
);
},
},
removeBlankState
()
{
removeBlankState
()
{
this
.
removeList
(
'
blank
'
);
this
.
removeList
(
'
blank
'
);
Cookies
.
set
(
'
issue_board_welcome_hidden
'
,
'
true
'
,
{
Cookies
.
set
(
'
issue_board_welcome_hidden
'
,
'
true
'
,
{
expires
:
365
*
10
,
expires
:
365
*
10
,
path
:
''
path
:
''
,
});
});
},
},
welcomeIsHidden
()
{
welcomeIsHidden
()
{
return
Cookies
.
get
(
'
issue_board_welcome_hidden
'
)
===
'
true
'
;
return
Cookies
.
get
(
'
issue_board_welcome_hidden
'
)
===
'
true
'
;
},
},
removeList
(
id
,
type
=
'
blank
'
)
{
removeList
(
id
,
type
=
'
blank
'
)
{
const
list
=
this
.
findList
(
'
id
'
,
id
,
type
);
const
list
=
this
.
findList
(
'
id
'
,
id
,
type
);
if
(
!
list
)
return
;
if
(
!
list
)
return
;
this
.
state
.
lists
=
this
.
state
.
lists
.
filter
(
list
=>
list
.
id
!==
id
);
this
.
state
.
lists
=
this
.
state
.
lists
.
filter
(
list
=>
list
.
id
!==
id
);
},
},
moveList
(
listFrom
,
orderLists
)
{
moveList
(
listFrom
,
orderLists
)
{
orderLists
.
forEach
((
id
,
i
)
=>
{
orderLists
.
forEach
((
id
,
i
)
=>
{
const
list
=
this
.
findList
(
'
id
'
,
parseInt
(
id
,
10
));
const
list
=
this
.
findList
(
'
id
'
,
parseInt
(
id
,
10
));
...
@@ -95,21 +95,24 @@ const boardsStore = {
...
@@ -95,21 +95,24 @@ const boardsStore = {
});
});
listFrom
.
update
();
listFrom
.
update
();
},
},
moveIssueToList
(
listFrom
,
listTo
,
issue
,
newIndex
)
{
moveIssueToList
(
listFrom
,
listTo
,
issue
,
newIndex
)
{
const
issueTo
=
listTo
.
findIssue
(
issue
.
id
);
const
issueTo
=
listTo
.
findIssue
(
issue
.
id
);
const
issueLists
=
issue
.
getLists
();
const
issueLists
=
issue
.
getLists
();
const
listLabels
=
issueLists
.
map
(
listIssue
=>
listIssue
.
label
);
const
listLabels
=
issueLists
.
map
(
listIssue
=>
listIssue
.
label
);
if
(
!
issueTo
)
{
if
(
!
issueTo
)
{
// Check if target list assignee is already present in this issue
// Check if target list assignee is already present in this issue
if
((
listTo
.
type
===
'
assignee
'
&&
listFrom
.
type
===
'
assignee
'
)
&&
if
(
issue
.
findAssignee
(
listTo
.
assignee
))
{
listTo
.
type
===
'
assignee
'
&&
listFrom
.
type
===
'
assignee
'
&&
issue
.
findAssignee
(
listTo
.
assignee
)
)
{
const
targetIssue
=
listTo
.
findIssue
(
issue
.
id
);
const
targetIssue
=
listTo
.
findIssue
(
issue
.
id
);
targetIssue
.
removeAssignee
(
listFrom
.
assignee
);
targetIssue
.
removeAssignee
(
listFrom
.
assignee
);
}
else
if
(
listTo
.
type
===
'
milestone
'
)
{
}
else
if
(
listTo
.
type
===
'
milestone
'
)
{
const
currentMilestone
=
issue
.
milestone
;
const
currentMilestone
=
issue
.
milestone
;
const
currentLists
=
this
.
state
.
lists
const
currentLists
=
this
.
state
.
lists
.
filter
(
list
=>
(
list
.
type
===
'
milestone
'
&&
list
.
id
!==
listTo
.
id
)
)
.
filter
(
list
=>
list
.
type
===
'
milestone
'
&&
list
.
id
!==
listTo
.
id
)
.
filter
(
list
=>
list
.
issues
.
some
(
listIssue
=>
issue
.
id
===
listIssue
.
id
));
.
filter
(
list
=>
list
.
issues
.
some
(
listIssue
=>
issue
.
id
===
listIssue
.
id
));
issue
.
removeMilestone
(
currentMilestone
);
issue
.
removeMilestone
(
currentMilestone
);
...
@@ -126,7 +129,7 @@ const boardsStore = {
...
@@ -126,7 +129,7 @@ const boardsStore = {
}
}
if
(
listTo
.
type
===
'
closed
'
&&
listFrom
.
type
!==
'
backlog
'
)
{
if
(
listTo
.
type
===
'
closed
'
&&
listFrom
.
type
!==
'
backlog
'
)
{
issueLists
.
forEach
(
(
list
)
=>
{
issueLists
.
forEach
(
list
=>
{
list
.
removeIssue
(
issue
);
list
.
removeIssue
(
issue
);
});
});
issue
.
removeLabels
(
listLabels
);
issue
.
removeLabels
(
listLabels
);
...
@@ -144,26 +147,28 @@ const boardsStore = {
...
@@ -144,26 +147,28 @@ const boardsStore = {
return
(
return
(
(
listTo
.
type
!==
'
label
'
&&
listFrom
.
type
===
'
assignee
'
)
||
(
listTo
.
type
!==
'
label
'
&&
listFrom
.
type
===
'
assignee
'
)
||
(
listTo
.
type
!==
'
assignee
'
&&
listFrom
.
type
===
'
label
'
)
||
(
listTo
.
type
!==
'
assignee
'
&&
listFrom
.
type
===
'
label
'
)
||
(
listFrom
.
type
===
'
backlog
'
)
listFrom
.
type
===
'
backlog
'
);
);
},
},
moveIssueInList
(
list
,
issue
,
oldIndex
,
newIndex
,
idArray
)
{
moveIssueInList
(
list
,
issue
,
oldIndex
,
newIndex
,
idArray
)
{
const
beforeId
=
parseInt
(
idArray
[
newIndex
-
1
],
10
)
||
null
;
const
beforeId
=
parseInt
(
idArray
[
newIndex
-
1
],
10
)
||
null
;
const
afterId
=
parseInt
(
idArray
[
newIndex
+
1
],
10
)
||
null
;
const
afterId
=
parseInt
(
idArray
[
newIndex
+
1
],
10
)
||
null
;
list
.
moveIssue
(
issue
,
oldIndex
,
newIndex
,
beforeId
,
afterId
);
list
.
moveIssue
(
issue
,
oldIndex
,
newIndex
,
beforeId
,
afterId
);
},
},
findList
(
key
,
val
,
type
=
'
label
'
)
{
findList
(
key
,
val
,
type
=
'
label
'
)
{
const
filteredList
=
this
.
state
.
lists
.
filter
((
list
)
=>
{
const
filteredList
=
this
.
state
.
lists
.
filter
(
list
=>
{
const
byType
=
type
?
(
list
.
type
===
type
)
||
(
list
.
type
===
'
assignee
'
)
||
(
list
.
type
===
'
milestone
'
)
:
true
;
const
byType
=
type
?
list
.
type
===
type
||
list
.
type
===
'
assignee
'
||
list
.
type
===
'
milestone
'
:
true
;
return
list
[
key
]
===
val
&&
byType
;
return
list
[
key
]
===
val
&&
byType
;
});
});
return
filteredList
[
0
];
return
filteredList
[
0
];
},
},
updateFiltersUrl
()
{
updateFiltersUrl
()
{
window
.
history
.
pushState
(
null
,
null
,
`?
${
this
.
filter
.
path
}
`
);
window
.
history
.
pushState
(
null
,
null
,
`?
${
this
.
filter
.
path
}
`
);
}
}
,
};
};
// hacks added in order to allow milestone_select to function properly
// hacks added in order to allow milestone_select to function properly
...
...
app/assets/javascripts/boards/stores/modal_store.js
View file @
160157a9
...
@@ -40,7 +40,7 @@ class ModalStore {
...
@@ -40,7 +40,7 @@ class ModalStore {
toggleAll
()
{
toggleAll
()
{
const
select
=
this
.
selectedCount
()
!==
this
.
store
.
issues
.
length
;
const
select
=
this
.
selectedCount
()
!==
this
.
store
.
issues
.
length
;
this
.
store
.
issues
.
forEach
(
(
issue
)
=>
{
this
.
store
.
issues
.
forEach
(
issue
=>
{
const
issueUpdate
=
issue
;
const
issueUpdate
=
issue
;
if
(
issueUpdate
.
selected
!==
select
)
{
if
(
issueUpdate
.
selected
!==
select
)
{
...
@@ -69,13 +69,14 @@ class ModalStore {
...
@@ -69,13 +69,14 @@ class ModalStore {
removeSelectedIssue
(
issue
,
forcePurge
=
false
)
{
removeSelectedIssue
(
issue
,
forcePurge
=
false
)
{
if
(
this
.
store
.
activeTab
===
'
all
'
||
forcePurge
)
{
if
(
this
.
store
.
activeTab
===
'
all
'
||
forcePurge
)
{
this
.
store
.
selectedIssues
=
this
.
store
.
selectedIssues
this
.
store
.
selectedIssues
=
this
.
store
.
selectedIssues
.
filter
(
.
filter
(
fIssue
=>
fIssue
.
id
!==
issue
.
id
);
fIssue
=>
fIssue
.
id
!==
issue
.
id
,
);
}
}
}
}
purgeUnselectedIssues
()
{
purgeUnselectedIssues
()
{
this
.
store
.
selectedIssues
.
forEach
(
(
issue
)
=>
{
this
.
store
.
selectedIssues
.
forEach
(
issue
=>
{
if
(
!
issue
.
selected
)
{
if
(
!
issue
.
selected
)
{
this
.
removeSelectedIssue
(
issue
,
true
);
this
.
removeSelectedIssue
(
issue
,
true
);
}
}
...
@@ -87,8 +88,7 @@ class ModalStore {
...
@@ -87,8 +88,7 @@ class ModalStore {
}
}
findSelectedIssue
(
issue
)
{
findSelectedIssue
(
issue
)
{
return
this
.
store
.
selectedIssues
return
this
.
store
.
selectedIssues
.
filter
(
filteredIssue
=>
filteredIssue
.
id
===
issue
.
id
)[
0
];
.
filter
(
filteredIssue
=>
filteredIssue
.
id
===
issue
.
id
)[
0
];
}
}
}
}
...
...
app/assets/javascripts/commons/gitlab_ui.js
View file @
160157a9
import
Vue
from
'
vue
'
;
import
Vue
from
'
vue
'
;
import
{
import
{
GlProgressBar
,
GlLoadingIcon
,
GlTooltipDirective
}
from
'
@gitlab-org/gitlab-ui
'
;
GlProgressBar
,
GlLoadingIcon
,
GlTooltipDirective
,
}
from
'
@gitlab-org/gitlab-ui
'
;
Vue
.
component
(
'
gl-progress-bar
'
,
GlProgressBar
);
Vue
.
component
(
'
gl-progress-bar
'
,
GlProgressBar
);
Vue
.
component
(
'
gl-loading-icon
'
,
GlLoadingIcon
);
Vue
.
component
(
'
gl-loading-icon
'
,
GlLoadingIcon
);
...
...
app/assets/javascripts/diffs/components/tree_list.vue
View file @
160157a9
...
@@ -18,8 +18,8 @@ export default {
...
@@ -18,8 +18,8 @@ export default {
},
},
data
()
{
data
()
{
const
treeListStored
=
localStorage
.
getItem
(
treeListStorageKey
);
const
treeListStored
=
localStorage
.
getItem
(
treeListStorageKey
);
const
renderTreeList
=
treeListStored
!==
null
?
const
renderTreeList
=
convertPermissionToBoolean
(
treeListStored
)
:
true
;
treeListStored
!==
null
?
convertPermissionToBoolean
(
treeListStored
)
:
true
;
return
{
return
{
search
:
''
,
search
:
''
,
...
...
app/assets/javascripts/environments/components/environments_app.vue
View file @
160157a9
<
script
>
<
script
>
import
Flash
from
'
../../flash
'
;
import
Flash
from
'
../../flash
'
;
import
{
s__
}
from
'
../../locale
'
;
import
{
s__
}
from
'
../../locale
'
;
import
emptyState
from
'
./empty_state.vue
'
;
import
emptyState
from
'
./empty_state.vue
'
;
import
eventHub
from
'
../event_hub
'
;
import
eventHub
from
'
../event_hub
'
;
import
environmentsMixin
from
'
../mixins/environments_mixin
'
;
import
environmentsMixin
from
'
../mixins/environments_mixin
'
;
import
CIPaginationMixin
from
'
../../vue_shared/mixins/ci_pagination_api_mixin
'
;
import
CIPaginationMixin
from
'
../../vue_shared/mixins/ci_pagination_api_mixin
'
;
import
StopEnvironmentModal
from
'
./stop_environment_modal.vue
'
;
import
StopEnvironmentModal
from
'
./stop_environment_modal.vue
'
;
export
default
{
export
default
{
components
:
{
components
:
{
emptyState
,
emptyState
,
StopEnvironmentModal
,
StopEnvironmentModal
,
},
},
mixins
:
[
mixins
:
[
CIPaginationMixin
,
environmentsMixin
],
CIPaginationMixin
,
environmentsMixin
,
],
props
:
{
props
:
{
endpoint
:
{
endpoint
:
{
...
@@ -69,7 +66,8 @@
...
@@ -69,7 +66,8 @@
fetchChildEnvironments
(
folder
,
showLoader
=
false
)
{
fetchChildEnvironments
(
folder
,
showLoader
=
false
)
{
this
.
store
.
updateEnvironmentProp
(
folder
,
'
isLoadingFolderContent
'
,
showLoader
);
this
.
store
.
updateEnvironmentProp
(
folder
,
'
isLoadingFolderContent
'
,
showLoader
);
this
.
service
.
getFolderContent
(
folder
.
folder_path
)
this
.
service
.
getFolderContent
(
folder
.
folder_path
)
.
then
(
response
=>
this
.
store
.
setfolderContent
(
folder
,
response
.
data
.
environments
))
.
then
(
response
=>
this
.
store
.
setfolderContent
(
folder
,
response
.
data
.
environments
))
.
then
(()
=>
this
.
store
.
updateEnvironmentProp
(
folder
,
'
isLoadingFolderContent
'
,
false
))
.
then
(()
=>
this
.
store
.
updateEnvironmentProp
(
folder
,
'
isLoadingFolderContent
'
,
false
))
.
catch
(()
=>
{
.
catch
(()
=>
{
...
@@ -88,7 +86,7 @@
...
@@ -88,7 +86,7 @@
}
}
},
},
},
},
};
};
</
script
>
</
script
>
<
template
>
<
template
>
<div
:class=
"cssContainerClass"
>
<div
:class=
"cssContainerClass"
>
...
...
app/assets/javascripts/environments/stores/environments_store.js
View file @
160157a9
...
@@ -34,9 +34,9 @@ export default class EnvironmentsStore {
...
@@ -34,9 +34,9 @@ export default class EnvironmentsStore {
* @returns {Array}
* @returns {Array}
*/
*/
storeEnvironments
(
environments
=
[])
{
storeEnvironments
(
environments
=
[])
{
const
filteredEnvironments
=
environments
.
map
(
(
env
)
=>
{
const
filteredEnvironments
=
environments
.
map
(
env
=>
{
const
oldEnvironmentState
=
this
.
state
.
environments
const
oldEnvironmentState
=
.
find
((
element
)
=>
{
this
.
state
.
environments
.
find
(
element
=>
{
if
(
env
.
latest
)
{
if
(
env
.
latest
)
{
return
element
.
id
===
env
.
latest
.
id
;
return
element
.
id
===
env
.
latest
.
id
;
}
}
...
@@ -119,7 +119,7 @@ export default class EnvironmentsStore {
...
@@ -119,7 +119,7 @@ export default class EnvironmentsStore {
* @return {Object}
* @return {Object}
*/
*/
setfolderContent
(
folder
,
environments
)
{
setfolderContent
(
folder
,
environments
)
{
const
updatedEnvironments
=
environments
.
map
(
(
env
)
=>
{
const
updatedEnvironments
=
environments
.
map
(
env
=>
{
let
updated
=
env
;
let
updated
=
env
;
if
(
env
.
latest
)
{
if
(
env
.
latest
)
{
...
@@ -148,7 +148,7 @@ export default class EnvironmentsStore {
...
@@ -148,7 +148,7 @@ export default class EnvironmentsStore {
updateEnvironmentProp
(
environment
,
prop
,
newValue
)
{
updateEnvironmentProp
(
environment
,
prop
,
newValue
)
{
const
{
environments
}
=
this
.
state
;
const
{
environments
}
=
this
.
state
;
const
updatedEnvironments
=
environments
.
map
(
(
env
)
=>
{
const
updatedEnvironments
=
environments
.
map
(
env
=>
{
const
updateEnv
=
Object
.
assign
({},
env
);
const
updateEnv
=
Object
.
assign
({},
env
);
if
(
env
.
id
===
environment
.
id
)
{
if
(
env
.
id
===
environment
.
id
)
{
updateEnv
[
prop
]
=
newValue
;
updateEnv
[
prop
]
=
newValue
;
...
...
app/assets/javascripts/filtered_search/dropdown_user.js
View file @
160157a9
...
@@ -39,8 +39,9 @@ export default class DropdownUser extends FilteredSearchDropdown {
...
@@ -39,8 +39,9 @@ export default class DropdownUser extends FilteredSearchDropdown {
}
}
itemClicked
(
e
)
{
itemClicked
(
e
)
{
super
.
itemClicked
(
e
,
super
.
itemClicked
(
e
,
selected
=>
selected
=>
selected
.
querySelector
(
'
.dropdown-light-content
'
).
innerText
.
trim
());
selected
.
querySelector
(
'
.dropdown-light-content
'
).
innerText
.
trim
(),
);
}
}
renderContent
(
forceShowList
=
false
)
{
renderContent
(
forceShowList
=
false
)
{
...
@@ -68,7 +69,7 @@ export default class DropdownUser extends FilteredSearchDropdown {
...
@@ -68,7 +69,7 @@ export default class DropdownUser extends FilteredSearchDropdown {
// Removes the first character if it is a quotation so that we can search
// Removes the first character if it is a quotation so that we can search
// with multiple words
// with multiple words
if
(
value
[
0
]
===
'
"
'
||
value
[
0
]
===
'
\'
'
)
{
if
(
value
[
0
]
===
'
"
'
||
value
[
0
]
===
"
'
"
)
{
value
=
value
.
slice
(
1
);
value
=
value
.
slice
(
1
);
}
}
...
...
app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js
View file @
160157a9
...
@@ -108,7 +108,7 @@ export default class FilteredSearchDropdownManager {
...
@@ -108,7 +108,7 @@ export default class FilteredSearchDropdownManager {
},
},
};
};
supportedTokens
.
forEach
(
(
type
)
=>
{
supportedTokens
.
forEach
(
type
=>
{
if
(
availableMappings
[
type
])
{
if
(
availableMappings
[
type
])
{
allowedMappings
[
type
]
=
availableMappings
[
type
];
allowedMappings
[
type
]
=
availableMappings
[
type
];
}
}
...
@@ -142,10 +142,7 @@ export default class FilteredSearchDropdownManager {
...
@@ -142,10 +142,7 @@ export default class FilteredSearchDropdownManager {
}
}
static
addWordToInput
(
tokenName
,
tokenValue
=
''
,
clicked
=
false
,
options
=
{})
{
static
addWordToInput
(
tokenName
,
tokenValue
=
''
,
clicked
=
false
,
options
=
{})
{
const
{
const
{
uppercaseTokenName
=
false
,
capitalizeTokenValue
=
false
}
=
options
;
uppercaseTokenName
=
false
,
capitalizeTokenValue
=
false
,
}
=
options
;
const
input
=
FilteredSearchContainer
.
container
.
querySelector
(
'
.filtered-search
'
);
const
input
=
FilteredSearchContainer
.
container
.
querySelector
(
'
.filtered-search
'
);
FilteredSearchVisualTokens
.
addFilterVisualToken
(
tokenName
,
tokenValue
,
{
FilteredSearchVisualTokens
.
addFilterVisualToken
(
tokenName
,
tokenValue
,
{
uppercaseTokenName
,
uppercaseTokenName
,
...
@@ -164,13 +161,16 @@ export default class FilteredSearchDropdownManager {
...
@@ -164,13 +161,16 @@ export default class FilteredSearchDropdownManager {
updateDropdownOffset
(
key
)
{
updateDropdownOffset
(
key
)
{
// Always align dropdown with the input field
// Always align dropdown with the input field
let
offset
=
this
.
filteredSearchInput
.
getBoundingClientRect
().
left
-
this
.
container
.
querySelector
(
'
.scroll-container
'
).
getBoundingClientRect
().
left
;
let
offset
=
this
.
filteredSearchInput
.
getBoundingClientRect
().
left
-
this
.
container
.
querySelector
(
'
.scroll-container
'
).
getBoundingClientRect
().
left
;
const
maxInputWidth
=
240
;
const
maxInputWidth
=
240
;
const
currentDropdownWidth
=
this
.
mapping
[
key
].
element
.
clientWidth
||
maxInputWidth
;
const
currentDropdownWidth
=
this
.
mapping
[
key
].
element
.
clientWidth
||
maxInputWidth
;
// Make sure offset never exceeds the input container
// Make sure offset never exceeds the input container
const
offsetMaxWidth
=
this
.
container
.
querySelector
(
'
.scroll-container
'
).
clientWidth
-
currentDropdownWidth
;
const
offsetMaxWidth
=
this
.
container
.
querySelector
(
'
.scroll-container
'
).
clientWidth
-
currentDropdownWidth
;
if
(
offsetMaxWidth
<
offset
)
{
if
(
offsetMaxWidth
<
offset
)
{
offset
=
offsetMaxWidth
;
offset
=
offsetMaxWidth
;
}
}
...
@@ -196,8 +196,7 @@ export default class FilteredSearchDropdownManager {
...
@@ -196,8 +196,7 @@ export default class FilteredSearchDropdownManager {
const
glArguments
=
Object
.
assign
({},
defaultArguments
,
extraArguments
);
const
glArguments
=
Object
.
assign
({},
defaultArguments
,
extraArguments
);
// Passing glArguments to `new glClass(<arguments>)`
// Passing glArguments to `new glClass(<arguments>)`
mappingKey
.
reference
=
mappingKey
.
reference
=
new
(
Function
.
prototype
.
bind
.
apply
(
glClass
,
[
null
,
glArguments
]))();
new
(
Function
.
prototype
.
bind
.
apply
(
glClass
,
[
null
,
glArguments
]))();
}
}
if
(
firstLoad
)
{
if
(
firstLoad
)
{
...
@@ -224,8 +223,8 @@ export default class FilteredSearchDropdownManager {
...
@@ -224,8 +223,8 @@ export default class FilteredSearchDropdownManager {
}
}
const
match
=
this
.
filteredSearchTokenKeys
.
searchByKey
(
dropdownName
.
toLowerCase
());
const
match
=
this
.
filteredSearchTokenKeys
.
searchByKey
(
dropdownName
.
toLowerCase
());
const
shouldOpenFilterDropdown
=
match
&&
this
.
currentDropdown
!==
match
.
key
const
shouldOpenFilterDropdown
=
&&
this
.
mapping
[
match
.
key
];
match
&&
this
.
currentDropdown
!==
match
.
key
&&
this
.
mapping
[
match
.
key
];
const
shouldOpenHintDropdown
=
!
match
&&
this
.
currentDropdown
!==
'
hint
'
;
const
shouldOpenHintDropdown
=
!
match
&&
this
.
currentDropdown
!==
'
hint
'
;
if
(
shouldOpenFilterDropdown
||
shouldOpenHintDropdown
)
{
if
(
shouldOpenFilterDropdown
||
shouldOpenHintDropdown
)
{
...
@@ -236,8 +235,10 @@ export default class FilteredSearchDropdownManager {
...
@@ -236,8 +235,10 @@ export default class FilteredSearchDropdownManager {
setDropdown
()
{
setDropdown
()
{
const
query
=
DropdownUtils
.
getSearchQuery
(
true
);
const
query
=
DropdownUtils
.
getSearchQuery
(
true
);
const
{
lastToken
,
searchToken
}
=
const
{
lastToken
,
searchToken
}
=
this
.
tokenizer
.
processTokens
(
this
.
tokenizer
.
processTokens
(
query
,
this
.
filteredSearchTokenKeys
.
getKeys
());
query
,
this
.
filteredSearchTokenKeys
.
getKeys
(),
);
if
(
this
.
currentDropdown
)
{
if
(
this
.
currentDropdown
)
{
this
.
updateCurrentDropdownOffset
();
this
.
updateCurrentDropdownOffset
();
...
...
app/assets/javascripts/filtered_search/filtered_search_manager.js
View file @
160157a9
import
_
from
'
underscore
'
;
import
_
from
'
underscore
'
;
import
{
import
{
getParameterByName
,
getUrlParamsArray
}
from
'
~/lib/utils/common_utils
'
;
getParameterByName
,
getUrlParamsArray
,
}
from
'
~/lib/utils/common_utils
'
;
import
IssuableFilteredSearchTokenKeys
from
'
~/filtered_search/issuable_filtered_search_token_keys
'
;
import
IssuableFilteredSearchTokenKeys
from
'
~/filtered_search/issuable_filtered_search_token_keys
'
;
import
{
visitUrl
}
from
'
../lib/utils/url_utility
'
;
import
{
visitUrl
}
from
'
../lib/utils/url_utility
'
;
import
Flash
from
'
../flash
'
;
import
Flash
from
'
../flash
'
;
...
@@ -48,24 +45,28 @@ export default class FilteredSearchManager {
...
@@ -48,24 +45,28 @@ export default class FilteredSearchManager {
isLocalStorageAvailable
:
RecentSearchesService
.
isAvailable
(),
isLocalStorageAvailable
:
RecentSearchesService
.
isAvailable
(),
allowedKeys
:
this
.
filteredSearchTokenKeys
.
getKeys
(),
allowedKeys
:
this
.
filteredSearchTokenKeys
.
getKeys
(),
});
});
this
.
searchHistoryDropdownElement
=
document
.
querySelector
(
'
.js-filtered-search-history-dropdown
'
);
this
.
searchHistoryDropdownElement
=
document
.
querySelector
(
const
fullPath
=
this
.
searchHistoryDropdownElement
?
'
.js-filtered-search-history-dropdown
'
,
this
.
searchHistoryDropdownElement
.
dataset
.
fullPath
:
'
project
'
;
);
const
fullPath
=
this
.
searchHistoryDropdownElement
?
this
.
searchHistoryDropdownElement
.
dataset
.
fullPath
:
'
project
'
;
const
recentSearchesKey
=
`
${
fullPath
}
-
${
this
.
recentsStorageKeyNames
[
this
.
page
]}
`
;
const
recentSearchesKey
=
`
${
fullPath
}
-
${
this
.
recentsStorageKeyNames
[
this
.
page
]}
`
;
this
.
recentSearchesService
=
new
RecentSearchesService
(
recentSearchesKey
);
this
.
recentSearchesService
=
new
RecentSearchesService
(
recentSearchesKey
);
}
}
setup
()
{
setup
()
{
// Fetch recent searches from localStorage
// Fetch recent searches from localStorage
this
.
fetchingRecentSearchesPromise
=
this
.
recentSearchesService
.
fetch
()
this
.
fetchingRecentSearchesPromise
=
this
.
recentSearchesService
.
catch
((
error
)
=>
{
.
fetch
()
.
catch
(
error
=>
{
if
(
error
.
name
===
'
RecentSearchesServiceError
'
)
return
undefined
;
if
(
error
.
name
===
'
RecentSearchesServiceError
'
)
return
undefined
;
// eslint-disable-next-line no-new
// eslint-disable-next-line no-new
new
Flash
(
'
An error occurred while parsing recent searches
'
);
new
Flash
(
'
An error occurred while parsing recent searches
'
);
// Gracefully fail to empty array
// Gracefully fail to empty array
return
[];
return
[];
})
})
.
then
(
(
searches
)
=>
{
.
then
(
searches
=>
{
if
(
!
searches
)
{
if
(
!
searches
)
{
return
;
return
;
}
}
...
@@ -120,7 +121,7 @@ export default class FilteredSearchManager {
...
@@ -120,7 +121,7 @@ export default class FilteredSearchManager {
if
(
this
.
stateFilters
)
{
if
(
this
.
stateFilters
)
{
this
.
searchStateWrapper
=
this
.
searchState
.
bind
(
this
);
this
.
searchStateWrapper
=
this
.
searchState
.
bind
(
this
);
this
.
applyToStateFilters
(
(
filterEl
)
=>
{
this
.
applyToStateFilters
(
filterEl
=>
{
filterEl
.
addEventListener
(
'
click
'
,
this
.
searchStateWrapper
);
filterEl
.
addEventListener
(
'
click
'
,
this
.
searchStateWrapper
);
});
});
}
}
...
@@ -128,14 +129,14 @@ export default class FilteredSearchManager {
...
@@ -128,14 +129,14 @@ export default class FilteredSearchManager {
unbindStateEvents
()
{
unbindStateEvents
()
{
if
(
this
.
stateFilters
)
{
if
(
this
.
stateFilters
)
{
this
.
applyToStateFilters
(
(
filterEl
)
=>
{
this
.
applyToStateFilters
(
filterEl
=>
{
filterEl
.
removeEventListener
(
'
click
'
,
this
.
searchStateWrapper
);
filterEl
.
removeEventListener
(
'
click
'
,
this
.
searchStateWrapper
);
});
});
}
}
}
}
applyToStateFilters
(
callback
)
{
applyToStateFilters
(
callback
)
{
this
.
stateFilters
.
querySelectorAll
(
'
a[data-state]
'
).
forEach
(
(
filterEl
)
=>
{
this
.
stateFilters
.
querySelectorAll
(
'
a[data-state]
'
).
forEach
(
filterEl
=>
{
if
(
this
.
states
.
indexOf
(
filterEl
.
dataset
.
state
)
>
-
1
)
{
if
(
this
.
states
.
indexOf
(
filterEl
.
dataset
.
state
)
>
-
1
)
{
callback
(
filterEl
);
callback
(
filterEl
);
}
}
...
@@ -207,7 +208,7 @@ export default class FilteredSearchManager {
...
@@ -207,7 +208,7 @@ export default class FilteredSearchManager {
let
backspaceCount
=
0
;
let
backspaceCount
=
0
;
// closure for keeping track of the number of backspace keystrokes
// closure for keeping track of the number of backspace keystrokes
return
(
e
)
=>
{
return
e
=>
{
// 8 = Backspace Key
// 8 = Backspace Key
// 46 = Delete Key
// 46 = Delete Key
if
(
e
.
keyCode
===
8
||
e
.
keyCode
===
46
)
{
if
(
e
.
keyCode
===
8
||
e
.
keyCode
===
46
)
{
...
@@ -274,8 +275,12 @@ export default class FilteredSearchManager {
...
@@ -274,8 +275,12 @@ export default class FilteredSearchManager {
const
isElementInDynamicFilterDropdown
=
e
.
target
.
closest
(
'
.filter-dropdown
'
)
!==
null
;
const
isElementInDynamicFilterDropdown
=
e
.
target
.
closest
(
'
.filter-dropdown
'
)
!==
null
;
const
isElementInStaticFilterDropdown
=
e
.
target
.
closest
(
'
ul[data-dropdown]
'
)
!==
null
;
const
isElementInStaticFilterDropdown
=
e
.
target
.
closest
(
'
ul[data-dropdown]
'
)
!==
null
;
if
(
!
isElementInFilteredSearch
&&
!
isElementInDynamicFilterDropdown
&&
if
(
!
isElementInStaticFilterDropdown
&&
inputContainer
)
{
!
isElementInFilteredSearch
&&
!
isElementInDynamicFilterDropdown
&&
!
isElementInStaticFilterDropdown
&&
inputContainer
)
{
inputContainer
.
classList
.
remove
(
'
focus
'
);
inputContainer
.
classList
.
remove
(
'
focus
'
);
}
}
}
}
...
@@ -368,7 +373,7 @@ export default class FilteredSearchManager {
...
@@ -368,7 +373,7 @@ export default class FilteredSearchManager {
const
removeElements
=
[];
const
removeElements
=
[];
[].
forEach
.
call
(
this
.
tokensContainer
.
children
,
(
t
)
=>
{
[].
forEach
.
call
(
this
.
tokensContainer
.
children
,
t
=>
{
let
canClearToken
=
t
.
classList
.
contains
(
'
js-visual-token
'
);
let
canClearToken
=
t
.
classList
.
contains
(
'
js-visual-token
'
);
if
(
canClearToken
)
{
if
(
canClearToken
)
{
...
@@ -381,7 +386,7 @@ export default class FilteredSearchManager {
...
@@ -381,7 +386,7 @@ export default class FilteredSearchManager {
}
}
});
});
removeElements
.
forEach
(
(
el
)
=>
{
removeElements
.
forEach
(
el
=>
{
el
.
parentElement
.
removeChild
(
el
);
el
.
parentElement
.
removeChild
(
el
);
});
});
...
@@ -397,13 +402,14 @@ export default class FilteredSearchManager {
...
@@ -397,13 +402,14 @@ export default class FilteredSearchManager {
handleInputVisualToken
()
{
handleInputVisualToken
()
{
const
input
=
this
.
filteredSearchInput
;
const
input
=
this
.
filteredSearchInput
;
const
{
tokens
,
searchToken
}
const
{
tokens
,
searchToken
}
=
this
.
tokenizer
.
processTokens
(
=
this
.
tokenizer
.
processTokens
(
input
.
value
,
this
.
filteredSearchTokenKeys
.
getKeys
());
input
.
value
,
const
{
isLastVisualTokenValid
}
this
.
filteredSearchTokenKeys
.
getKeys
(),
=
FilteredSearchVisualTokens
.
getLastVisualTokenBeforeInput
();
);
const
{
isLastVisualTokenValid
}
=
FilteredSearchVisualTokens
.
getLastVisualTokenBeforeInput
();
if
(
isLastVisualTokenValid
)
{
if
(
isLastVisualTokenValid
)
{
tokens
.
forEach
(
(
t
)
=>
{
tokens
.
forEach
(
t
=>
{
input
.
value
=
input
.
value
.
replace
(
`
${
t
.
key
}
:
${
t
.
symbol
}${
t
.
value
}
`
,
''
);
input
.
value
=
input
.
value
.
replace
(
`
${
t
.
key
}
:
${
t
.
symbol
}${
t
.
value
}
`
,
''
);
FilteredSearchVisualTokens
.
addFilterVisualToken
(
t
.
key
,
`
${
t
.
symbol
}${
t
.
value
}
`
,
{
FilteredSearchVisualTokens
.
addFilterVisualToken
(
t
.
key
,
`
${
t
.
symbol
}${
t
.
value
}
`
,
{
uppercaseTokenName
:
this
.
filteredSearchTokenKeys
.
shouldUppercaseTokenName
(
t
.
key
),
uppercaseTokenName
:
this
.
filteredSearchTokenKeys
.
shouldUppercaseTokenName
(
t
.
key
),
...
@@ -453,13 +459,15 @@ export default class FilteredSearchManager {
...
@@ -453,13 +459,15 @@ export default class FilteredSearchManager {
saveCurrentSearchQuery
()
{
saveCurrentSearchQuery
()
{
// Don't save before we have fetched the already saved searches
// Don't save before we have fetched the already saved searches
this
.
fetchingRecentSearchesPromise
.
then
(()
=>
{
this
.
fetchingRecentSearchesPromise
.
then
(()
=>
{
const
searchQuery
=
DropdownUtils
.
getSearchQuery
();
const
searchQuery
=
DropdownUtils
.
getSearchQuery
();
if
(
searchQuery
.
length
>
0
)
{
if
(
searchQuery
.
length
>
0
)
{
const
resultantSearches
=
this
.
recentSearchesStore
.
addRecentSearch
(
searchQuery
);
const
resultantSearches
=
this
.
recentSearchesStore
.
addRecentSearch
(
searchQuery
);
this
.
recentSearchesService
.
save
(
resultantSearches
);
this
.
recentSearchesService
.
save
(
resultantSearches
);
}
}
}).
catch
(()
=>
{
})
.
catch
(()
=>
{
// https://gitlab.com/gitlab-org/gitlab-ce/issues/30821
// https://gitlab.com/gitlab-org/gitlab-ce/issues/30821
});
});
}
}
...
@@ -475,7 +483,7 @@ export default class FilteredSearchManager {
...
@@ -475,7 +483,7 @@ export default class FilteredSearchManager {
const
usernameParams
=
this
.
getUsernameParams
();
const
usernameParams
=
this
.
getUsernameParams
();
let
hasFilteredSearch
=
false
;
let
hasFilteredSearch
=
false
;
params
.
forEach
(
(
p
)
=>
{
params
.
forEach
(
p
=>
{
const
split
=
p
.
split
(
'
=
'
);
const
split
=
p
.
split
(
'
=
'
);
const
keyParam
=
decodeURIComponent
(
split
[
0
]);
const
keyParam
=
decodeURIComponent
(
split
[
0
]);
const
value
=
split
[
1
];
const
value
=
split
[
1
];
...
@@ -486,11 +494,9 @@ export default class FilteredSearchManager {
...
@@ -486,11 +494,9 @@ export default class FilteredSearchManager {
if
(
condition
)
{
if
(
condition
)
{
hasFilteredSearch
=
true
;
hasFilteredSearch
=
true
;
const
canEdit
=
this
.
canEdit
&&
this
.
canEdit
(
condition
.
tokenKey
);
const
canEdit
=
this
.
canEdit
&&
this
.
canEdit
(
condition
.
tokenKey
);
FilteredSearchVisualTokens
.
addFilterVisualToken
(
FilteredSearchVisualTokens
.
addFilterVisualToken
(
condition
.
tokenKey
,
condition
.
value
,
{
condition
.
tokenKey
,
canEdit
,
condition
.
value
,
});
{
canEdit
},
);
}
else
{
}
else
{
// Sanitize value since URL converts spaces into +
// Sanitize value since URL converts spaces into +
// Replace before decode so that we know what was originally + versus the encoded +
// Replace before decode so that we know what was originally + versus the encoded +
...
@@ -510,7 +516,7 @@ export default class FilteredSearchManager {
...
@@ -510,7 +516,7 @@ export default class FilteredSearchManager {
if
(
sanitizedValue
.
indexOf
(
'
'
)
!==
-
1
)
{
if
(
sanitizedValue
.
indexOf
(
'
'
)
!==
-
1
)
{
// Prefer ", but use ' if required
// Prefer ", but use ' if required
quotationsToUse
=
sanitizedValue
.
indexOf
(
'
"
'
)
===
-
1
?
'
"
'
:
'
\'
'
;
quotationsToUse
=
sanitizedValue
.
indexOf
(
'
"
'
)
===
-
1
?
'
"
'
:
"
'
"
;
}
}
hasFilteredSearch
=
true
;
hasFilteredSearch
=
true
;
...
@@ -531,7 +537,9 @@ export default class FilteredSearchManager {
...
@@ -531,7 +537,9 @@ export default class FilteredSearchManager {
hasFilteredSearch
=
true
;
hasFilteredSearch
=
true
;
const
tokenName
=
'
assignee
'
;
const
tokenName
=
'
assignee
'
;
const
canEdit
=
this
.
canEdit
&&
this
.
canEdit
(
tokenName
);
const
canEdit
=
this
.
canEdit
&&
this
.
canEdit
(
tokenName
);
FilteredSearchVisualTokens
.
addFilterVisualToken
(
tokenName
,
`@
${
usernameParams
[
id
]}
`
,
{
canEdit
});
FilteredSearchVisualTokens
.
addFilterVisualToken
(
tokenName
,
`@
${
usernameParams
[
id
]}
`
,
{
canEdit
,
});
}
}
}
else
if
(
!
match
&&
keyParam
===
'
author_id
'
)
{
}
else
if
(
!
match
&&
keyParam
===
'
author_id
'
)
{
const
id
=
parseInt
(
value
,
10
);
const
id
=
parseInt
(
value
,
10
);
...
@@ -539,7 +547,9 @@ export default class FilteredSearchManager {
...
@@ -539,7 +547,9 @@ export default class FilteredSearchManager {
hasFilteredSearch
=
true
;
hasFilteredSearch
=
true
;
const
tokenName
=
'
author
'
;
const
tokenName
=
'
author
'
;
const
canEdit
=
this
.
canEdit
&&
this
.
canEdit
(
tokenName
);
const
canEdit
=
this
.
canEdit
&&
this
.
canEdit
(
tokenName
);
FilteredSearchVisualTokens
.
addFilterVisualToken
(
tokenName
,
`@
${
usernameParams
[
id
]}
`
,
{
canEdit
});
FilteredSearchVisualTokens
.
addFilterVisualToken
(
tokenName
,
`@
${
usernameParams
[
id
]}
`
,
{
canEdit
,
});
}
}
}
else
if
(
!
match
&&
keyParam
===
'
search
'
)
{
}
else
if
(
!
match
&&
keyParam
===
'
search
'
)
{
hasFilteredSearch
=
true
;
hasFilteredSearch
=
true
;
...
@@ -580,9 +590,11 @@ export default class FilteredSearchManager {
...
@@ -580,9 +590,11 @@ export default class FilteredSearchManager {
const
currentState
=
state
||
getParameterByName
(
'
state
'
)
||
'
opened
'
;
const
currentState
=
state
||
getParameterByName
(
'
state
'
)
||
'
opened
'
;
paths
.
push
(
`state=
${
currentState
}
`
);
paths
.
push
(
`state=
${
currentState
}
`
);
tokens
.
forEach
((
token
)
=>
{
tokens
.
forEach
(
token
=>
{
const
condition
=
this
.
filteredSearchTokenKeys
const
condition
=
this
.
filteredSearchTokenKeys
.
searchByConditionKeyValue
(
.
searchByConditionKeyValue
(
token
.
key
,
token
.
value
.
toLowerCase
());
token
.
key
,
token
.
value
.
toLowerCase
(),
);
const
tokenConfig
=
this
.
filteredSearchTokenKeys
.
searchByKey
(
token
.
key
)
||
{};
const
tokenConfig
=
this
.
filteredSearchTokenKeys
.
searchByKey
(
token
.
key
)
||
{};
const
{
param
}
=
tokenConfig
;
const
{
param
}
=
tokenConfig
;
...
@@ -601,8 +613,10 @@ export default class FilteredSearchManager {
...
@@ -601,8 +613,10 @@ export default class FilteredSearchManager {
tokenValue
=
tokenValue
.
toLowerCase
();
tokenValue
=
tokenValue
.
toLowerCase
();
}
}
if
((
tokenValue
[
0
]
===
'
\'
'
&&
tokenValue
[
tokenValue
.
length
-
1
]
===
'
\'
'
)
||
if
(
(
tokenValue
[
0
]
===
'
"
'
&&
tokenValue
[
tokenValue
.
length
-
1
]
===
'
"
'
))
{
(
tokenValue
[
0
]
===
"
'
"
&&
tokenValue
[
tokenValue
.
length
-
1
]
===
"
'
"
)
||
(
tokenValue
[
0
]
===
'
"
'
&&
tokenValue
[
tokenValue
.
length
-
1
]
===
'
"
'
)
)
{
tokenValue
=
tokenValue
.
slice
(
1
,
tokenValue
.
length
-
1
);
tokenValue
=
tokenValue
.
slice
(
1
,
tokenValue
.
length
-
1
);
}
}
...
@@ -613,7 +627,10 @@ export default class FilteredSearchManager {
...
@@ -613,7 +627,10 @@ export default class FilteredSearchManager {
});
});
if
(
searchToken
)
{
if
(
searchToken
)
{
const
sanitized
=
searchToken
.
split
(
'
'
).
map
(
t
=>
encodeURIComponent
(
t
)).
join
(
'
+
'
);
const
sanitized
=
searchToken
.
split
(
'
'
)
.
map
(
t
=>
encodeURIComponent
(
t
))
.
join
(
'
+
'
);
paths
.
push
(
`search=
${
sanitized
}
`
);
paths
.
push
(
`search=
${
sanitized
}
`
);
}
}
...
@@ -630,7 +647,7 @@ export default class FilteredSearchManager {
...
@@ -630,7 +647,7 @@ export default class FilteredSearchManager {
const
usernamesById
=
{};
const
usernamesById
=
{};
try
{
try
{
const
attribute
=
this
.
filteredSearchInput
.
getAttribute
(
'
data-username-params
'
);
const
attribute
=
this
.
filteredSearchInput
.
getAttribute
(
'
data-username-params
'
);
JSON
.
parse
(
attribute
).
forEach
(
(
user
)
=>
{
JSON
.
parse
(
attribute
).
forEach
(
user
=>
{
usernamesById
[
user
.
id
]
=
user
.
username
;
usernamesById
[
user
.
id
]
=
user
.
username
;
});
});
}
catch
(
e
)
{
}
catch
(
e
)
{
...
...
app/assets/javascripts/flash.js
View file @
160157a9
...
@@ -40,7 +40,9 @@ const createFlashEl = (message, type, isFixedLayout = false) => `
...
@@ -40,7 +40,9 @@ const createFlashEl = (message, type, isFixedLayout = false) => `
class="flash-
${
type
}
"
class="flash-
${
type
}
"
>
>
<div
<div
class="flash-text
${
isFixedLayout
?
'
container-fluid container-limited limit-container-width
'
:
''
}
"
class="flash-text
${
isFixedLayout
?
'
container-fluid container-limited limit-container-width
'
:
''
}
"
>
>
${
_
.
escape
(
message
)}
${
_
.
escape
(
message
)}
</div>
</div>
...
@@ -78,7 +80,9 @@ const createFlash = function createFlash(
...
@@ -78,7 +80,9 @@ const createFlash = function createFlash(
if
(
!
flashContainer
)
return
null
;
if
(
!
flashContainer
)
return
null
;
const
isFixedLayout
=
navigation
?
navigation
.
parentNode
.
classList
.
contains
(
'
container-limited
'
)
:
true
;
const
isFixedLayout
=
navigation
?
navigation
.
parentNode
.
classList
.
contains
(
'
container-limited
'
)
:
true
;
flashContainer
.
innerHTML
=
createFlashEl
(
message
,
type
,
isFixedLayout
);
flashContainer
.
innerHTML
=
createFlashEl
(
message
,
type
,
isFixedLayout
);
...
...
app/assets/javascripts/gfm_auto_complete.js
View file @
160157a9
...
@@ -94,7 +94,7 @@ class GfmAutoComplete {
...
@@ -94,7 +94,7 @@ class GfmAutoComplete {
...
this
.
getDefaultCallbacks
(),
...
this
.
getDefaultCallbacks
(),
beforeSave
(
commands
)
{
beforeSave
(
commands
)
{
if
(
GfmAutoComplete
.
isLoading
(
commands
))
return
commands
;
if
(
GfmAutoComplete
.
isLoading
(
commands
))
return
commands
;
return
$
.
map
(
commands
,
(
c
)
=>
{
return
$
.
map
(
commands
,
c
=>
{
let
search
=
c
.
name
;
let
search
=
c
.
name
;
if
(
c
.
aliases
.
length
>
0
)
{
if
(
c
.
aliases
.
length
>
0
)
{
search
=
`
${
search
}
${
c
.
aliases
.
join
(
'
'
)}
`
;
search
=
`
${
search
}
${
c
.
aliases
.
join
(
'
'
)}
`
;
...
@@ -167,7 +167,7 @@ class GfmAutoComplete {
...
@@ -167,7 +167,7 @@ class GfmAutoComplete {
callbacks
:
{
callbacks
:
{
...
this
.
getDefaultCallbacks
(),
...
this
.
getDefaultCallbacks
(),
beforeSave
(
members
)
{
beforeSave
(
members
)
{
return
$
.
map
(
members
,
(
m
)
=>
{
return
$
.
map
(
members
,
m
=>
{
let
title
=
''
;
let
title
=
''
;
if
(
m
.
username
==
null
)
{
if
(
m
.
username
==
null
)
{
return
m
;
return
m
;
...
@@ -178,7 +178,9 @@ class GfmAutoComplete {
...
@@ -178,7 +178,9 @@ class GfmAutoComplete {
}
}
const
autoCompleteAvatar
=
m
.
avatar_url
||
m
.
username
.
charAt
(
0
).
toUpperCase
();
const
autoCompleteAvatar
=
m
.
avatar_url
||
m
.
username
.
charAt
(
0
).
toUpperCase
();
const
imgAvatar
=
`<img src="
${
m
.
avatar_url
}
" alt="
${
m
.
username
}
" class="avatar avatar-inline center s26"/>`
;
const
imgAvatar
=
`<img src="
${
m
.
avatar_url
}
" alt="
${
m
.
username
}
" class="avatar avatar-inline center s26"/>`
;
const
txtAvatar
=
`<div class="avatar center avatar-inline s26">
${
autoCompleteAvatar
}
</div>`
;
const
txtAvatar
=
`<div class="avatar center avatar-inline s26">
${
autoCompleteAvatar
}
</div>`
;
return
{
return
{
...
@@ -211,7 +213,7 @@ class GfmAutoComplete {
...
@@ -211,7 +213,7 @@ class GfmAutoComplete {
callbacks
:
{
callbacks
:
{
...
this
.
getDefaultCallbacks
(),
...
this
.
getDefaultCallbacks
(),
beforeSave
(
issues
)
{
beforeSave
(
issues
)
{
return
$
.
map
(
issues
,
(
i
)
=>
{
return
$
.
map
(
issues
,
i
=>
{
if
(
i
.
title
==
null
)
{
if
(
i
.
title
==
null
)
{
return
i
;
return
i
;
}
}
...
@@ -244,7 +246,7 @@ class GfmAutoComplete {
...
@@ -244,7 +246,7 @@ class GfmAutoComplete {
callbacks
:
{
callbacks
:
{
...
this
.
getDefaultCallbacks
(),
...
this
.
getDefaultCallbacks
(),
beforeSave
(
milestones
)
{
beforeSave
(
milestones
)
{
return
$
.
map
(
milestones
,
(
m
)
=>
{
return
$
.
map
(
milestones
,
m
=>
{
if
(
m
.
title
==
null
)
{
if
(
m
.
title
==
null
)
{
return
m
;
return
m
;
}
}
...
@@ -277,7 +279,7 @@ class GfmAutoComplete {
...
@@ -277,7 +279,7 @@ class GfmAutoComplete {
callbacks
:
{
callbacks
:
{
...
this
.
getDefaultCallbacks
(),
...
this
.
getDefaultCallbacks
(),
beforeSave
(
merges
)
{
beforeSave
(
merges
)
{
return
$
.
map
(
merges
,
(
m
)
=>
{
return
$
.
map
(
merges
,
m
=>
{
if
(
m
.
title
==
null
)
{
if
(
m
.
title
==
null
)
{
return
m
;
return
m
;
}
}
...
@@ -324,13 +326,20 @@ class GfmAutoComplete {
...
@@ -324,13 +326,20 @@ class GfmAutoComplete {
},
},
matcher
(
flag
,
subtext
)
{
matcher
(
flag
,
subtext
)
{
const
match
=
GfmAutoComplete
.
defaultMatcher
(
flag
,
subtext
,
this
.
app
.
controllers
);
const
match
=
GfmAutoComplete
.
defaultMatcher
(
flag
,
subtext
,
this
.
app
.
controllers
);
const
subtextNodes
=
subtext
.
split
(
/
\n
+/g
).
pop
().
split
(
GfmAutoComplete
.
regexSubtext
);
const
subtextNodes
=
subtext
.
split
(
/
\n
+/g
)
.
pop
()
.
split
(
GfmAutoComplete
.
regexSubtext
);
// Check if ~ is followed by '/label', '/relabel' or '/unlabel' commands.
// Check if ~ is followed by '/label', '/relabel' or '/unlabel' commands.
command
=
subtextNodes
.
find
((
node
)
=>
{
command
=
subtextNodes
.
find
(
node
=>
{
if
(
node
===
LABEL_COMMAND
.
LABEL
||
if
(
node
===
LABEL_COMMAND
.
LABEL
||
node
===
LABEL_COMMAND
.
RELABEL
||
node
===
LABEL_COMMAND
.
RELABEL
||
node
===
LABEL_COMMAND
.
UNLABEL
)
{
return
node
;
}
node
===
LABEL_COMMAND
.
UNLABEL
)
{
return
node
;
}
return
null
;
return
null
;
});
});
...
@@ -380,7 +389,7 @@ class GfmAutoComplete {
...
@@ -380,7 +389,7 @@ class GfmAutoComplete {
callbacks
:
{
callbacks
:
{
...
this
.
getDefaultCallbacks
(),
...
this
.
getDefaultCallbacks
(),
beforeSave
(
snippets
)
{
beforeSave
(
snippets
)
{
return
$
.
map
(
snippets
,
(
m
)
=>
{
return
$
.
map
(
snippets
,
m
=>
{
if
(
m
.
title
==
null
)
{
if
(
m
.
title
==
null
)
{
return
m
;
return
m
;
}
}
...
@@ -458,13 +467,17 @@ class GfmAutoComplete {
...
@@ -458,13 +467,17 @@ class GfmAutoComplete {
this
.
loadData
(
$input
,
at
,
validEmojiNames
);
this
.
loadData
(
$input
,
at
,
validEmojiNames
);
GfmAutoComplete
.
glEmojiTag
=
glEmojiTag
;
GfmAutoComplete
.
glEmojiTag
=
glEmojiTag
;
})
})
.
catch
(()
=>
{
this
.
isLoadingData
[
at
]
=
false
;
});
.
catch
(()
=>
{
this
.
isLoadingData
[
at
]
=
false
;
});
}
else
if
(
dataSource
)
{
}
else
if
(
dataSource
)
{
AjaxCache
.
retrieve
(
dataSource
,
true
)
AjaxCache
.
retrieve
(
dataSource
,
true
)
.
then
(
(
data
)
=>
{
.
then
(
data
=>
{
this
.
loadData
(
$input
,
at
,
data
);
this
.
loadData
(
$input
,
at
,
data
);
})
})
.
catch
(()
=>
{
this
.
isLoadingData
[
at
]
=
false
;
});
.
catch
(()
=>
{
this
.
isLoadingData
[
at
]
=
false
;
});
}
else
{
}
else
{
this
.
isLoadingData
[
at
]
=
false
;
this
.
isLoadingData
[
at
]
=
false
;
}
}
...
@@ -497,15 +510,16 @@ class GfmAutoComplete {
...
@@ -497,15 +510,16 @@ class GfmAutoComplete {
}
}
const
loadingState
=
GfmAutoComplete
.
defaultLoadingData
[
0
];
const
loadingState
=
GfmAutoComplete
.
defaultLoadingData
[
0
];
return
dataToInspect
&&
return
dataToInspect
&&
(
dataToInspect
===
loadingState
||
dataToInspect
.
name
===
loadingState
);
(
dataToInspect
===
loadingState
||
dataToInspect
.
name
===
loadingState
);
}
}
static
defaultMatcher
(
flag
,
subtext
,
controllers
)
{
static
defaultMatcher
(
flag
,
subtext
,
controllers
)
{
// The below is taken from At.js source
// The below is taken from At.js source
// Tweaked to commands to start without a space only if char before is a non-word character
// Tweaked to commands to start without a space only if char before is a non-word character
// https://github.com/ichord/At.js
// https://github.com/ichord/At.js
const
atSymbolsWithBar
=
Object
.
keys
(
controllers
).
join
(
'
|
'
).
replace
(
/
[
$
]
/
,
'
\\
$&
'
);
const
atSymbolsWithBar
=
Object
.
keys
(
controllers
)
.
join
(
'
|
'
)
.
replace
(
/
[
$
]
/
,
'
\\
$&
'
);
const
atSymbolsWithoutBar
=
Object
.
keys
(
controllers
).
join
(
''
);
const
atSymbolsWithoutBar
=
Object
.
keys
(
controllers
).
join
(
''
);
const
targetSubtext
=
subtext
.
split
(
GfmAutoComplete
.
regexSubtext
).
pop
();
const
targetSubtext
=
subtext
.
split
(
GfmAutoComplete
.
regexSubtext
).
pop
();
const
resultantFlag
=
flag
.
replace
(
/
[
-[
\]/
{}()*+?.
\\
^$|
]
/g
,
'
\\
$&
'
);
const
resultantFlag
=
flag
.
replace
(
/
[
-[
\]/
{}()*+?.
\\
^$|
]
/g
,
'
\\
$&
'
);
...
@@ -513,7 +527,10 @@ class GfmAutoComplete {
...
@@ -513,7 +527,10 @@ class GfmAutoComplete {
const
accentAChar
=
decodeURI
(
'
%C3%80
'
);
const
accentAChar
=
decodeURI
(
'
%C3%80
'
);
const
accentYChar
=
decodeURI
(
'
%C3%BF
'
);
const
accentYChar
=
decodeURI
(
'
%C3%BF
'
);
const
regexp
=
new
RegExp
(
`^(?:\\B|[^a-zA-Z0-9_\`
${
atSymbolsWithoutBar
}
]|\\s)
${
resultantFlag
}
(?!
${
atSymbolsWithBar
}
)((?:[A-Za-z
${
accentAChar
}
-
${
accentYChar
}
0-9_'.+-]|[^\\x00-\\x7a])*)$`
,
'
gi
'
);
const
regexp
=
new
RegExp
(
`^(?:\\B|[^a-zA-Z0-9_\`
${
atSymbolsWithoutBar
}
]|\\s)
${
resultantFlag
}
(?!
${
atSymbolsWithBar
}
)((?:[A-Za-z
${
accentAChar
}
-
${
accentYChar
}
0-9_'.+-]|[^\\x00-\\x7a])*)$`
,
'
gi
'
,
);
return
regexp
.
exec
(
targetSubtext
);
return
regexp
.
exec
(
targetSubtext
);
}
}
...
@@ -553,7 +570,8 @@ GfmAutoComplete.Members = {
...
@@ -553,7 +570,8 @@ GfmAutoComplete.Members = {
};
};
GfmAutoComplete
.
Labels
=
{
GfmAutoComplete
.
Labels
=
{
// eslint-disable-next-line no-template-curly-in-string
// eslint-disable-next-line no-template-curly-in-string
template
:
'
<li><span class="dropdown-label-box" style="background: ${color}"></span> ${title}</li>
'
,
template
:
'
<li><span class="dropdown-label-box" style="background: ${color}"></span> ${title}</li>
'
,
};
};
// Issues, MergeRequests and Snippets
// Issues, MergeRequests and Snippets
GfmAutoComplete
.
Issues
=
{
GfmAutoComplete
.
Issues
=
{
...
@@ -567,7 +585,8 @@ GfmAutoComplete.Milestones = {
...
@@ -567,7 +585,8 @@ GfmAutoComplete.Milestones = {
template
:
'
<li>${title}</li>
'
,
template
:
'
<li>${title}</li>
'
,
};
};
GfmAutoComplete
.
Loading
=
{
GfmAutoComplete
.
Loading
=
{
template
:
'
<li style="pointer-events: none;"><i class="fa fa-spinner fa-spin"></i> Loading...</li>
'
,
template
:
'
<li style="pointer-events: none;"><i class="fa fa-spinner fa-spin"></i> Loading...</li>
'
,
};
};
export
default
GfmAutoComplete
;
export
default
GfmAutoComplete
;
app/assets/javascripts/jobs/components/job_app.vue
View file @
160157a9
<
script
>
<
script
>
import
_
from
'
underscore
'
;
import
_
from
'
underscore
'
;
import
{
mapGetters
,
mapState
,
mapActions
}
from
'
vuex
'
;
import
{
mapGetters
,
mapState
,
mapActions
}
from
'
vuex
'
;
import
{
isScrolledToBottom
}
from
'
~/lib/utils/scroll_utils
'
;
import
{
isScrolledToBottom
}
from
'
~/lib/utils/scroll_utils
'
;
import
bp
from
'
~/breakpoints
'
;
import
bp
from
'
~/breakpoints
'
;
import
CiHeader
from
'
~/vue_shared/components/header_ci_component.vue
'
;
import
CiHeader
from
'
~/vue_shared/components/header_ci_component.vue
'
;
import
Callout
from
'
~/vue_shared/components/callout.vue
'
;
import
Callout
from
'
~/vue_shared/components/callout.vue
'
;
import
createStore
from
'
../store
'
;
import
createStore
from
'
../store
'
;
import
EmptyState
from
'
./empty_state.vue
'
;
import
EmptyState
from
'
./empty_state.vue
'
;
import
EnvironmentsBlock
from
'
./environments_block.vue
'
;
import
EnvironmentsBlock
from
'
./environments_block.vue
'
;
import
ErasedBlock
from
'
./erased_block.vue
'
;
import
ErasedBlock
from
'
./erased_block.vue
'
;
import
Log
from
'
./job_log.vue
'
;
import
Log
from
'
./job_log.vue
'
;
import
LogTopBar
from
'
./job_log_controllers.vue
'
;
import
LogTopBar
from
'
./job_log_controllers.vue
'
;
import
StuckBlock
from
'
./stuck_block.vue
'
;
import
StuckBlock
from
'
./stuck_block.vue
'
;
import
Sidebar
from
'
./sidebar.vue
'
;
import
Sidebar
from
'
./sidebar.vue
'
;
export
default
{
export
default
{
name
:
'
JobPageApp
'
,
name
:
'
JobPageApp
'
,
store
:
createStore
(),
store
:
createStore
(),
components
:
{
components
:
{
...
@@ -86,7 +86,7 @@
...
@@ -86,7 +86,7 @@
shouldRenderContent
()
{
shouldRenderContent
()
{
return
!
this
.
isLoading
&&
!
this
.
hasError
;
return
!
this
.
isLoading
&&
!
this
.
hasError
;
}
},
},
},
watch
:
{
watch
:
{
// Once the job log is loaded,
// Once the job log is loaded,
...
@@ -158,7 +158,7 @@
...
@@ -158,7 +158,7 @@
this
.
throttled
();
this
.
throttled
();
},
},
},
},
};
};
</
script
>
</
script
>
<
template
>
<
template
>
<div>
<div>
...
...
app/assets/javascripts/jobs/components/job_log.vue
View file @
160157a9
<
script
>
<
script
>
import
{
mapState
,
mapActions
}
from
'
vuex
'
;
import
{
mapState
,
mapActions
}
from
'
vuex
'
;
export
default
{
export
default
{
name
:
'
JobLog
'
,
name
:
'
JobLog
'
,
props
:
{
props
:
{
trace
:
{
trace
:
{
...
@@ -39,7 +39,7 @@
...
@@ -39,7 +39,7 @@
}
}
},
},
},
},
};
};
</
script
>
</
script
>
<
template
>
<
template
>
<pre
class=
"js-build-trace build-trace qa-build-trace"
>
<pre
class=
"js-build-trace build-trace qa-build-trace"
>
...
...
app/assets/javascripts/jobs/index.js
View file @
160157a9
...
@@ -23,4 +23,3 @@ export default () => {
...
@@ -23,4 +23,3 @@ export default () => {
},
},
});
});
};
};
app/assets/javascripts/jobs/store/getters.js
View file @
160157a9
...
@@ -35,16 +35,19 @@ export const hasEnvironment = state => !_.isEmpty(state.job.deployment_status);
...
@@ -35,16 +35,19 @@ export const hasEnvironment = state => !_.isEmpty(state.job.deployment_status);
* Used to check if it should render the job log or the empty state
* Used to check if it should render the job log or the empty state
* @returns {Boolean}
* @returns {Boolean}
*/
*/
export
const
hasTrace
=
state
=>
state
.
job
.
has_trace
||
(
!
_
.
isEmpty
(
state
.
job
.
status
)
&&
state
.
job
.
status
.
group
===
'
running
'
);
export
const
hasTrace
=
state
=>
state
.
job
.
has_trace
||
(
!
_
.
isEmpty
(
state
.
job
.
status
)
&&
state
.
job
.
status
.
group
===
'
running
'
);
export
const
emptyStateIllustration
=
state
=>
export
const
emptyStateIllustration
=
state
=>
(
state
.
job
&&
state
.
job
.
status
&&
state
.
job
.
status
.
illustration
)
||
{};
(
state
.
job
&&
state
.
job
.
status
&&
state
.
job
.
status
.
illustration
)
||
{};
export
const
emptyStateAction
=
state
=>
(
state
.
job
&&
state
.
job
.
status
&&
state
.
job
.
status
.
action
)
||
{};
export
const
emptyStateAction
=
state
=>
(
state
.
job
&&
state
.
job
.
status
&&
state
.
job
.
status
.
action
)
||
{};
export
const
isScrollingDown
=
state
=>
isScrolledToBottom
()
&&
!
state
.
isTraceComplete
;
export
const
isScrollingDown
=
state
=>
isScrolledToBottom
()
&&
!
state
.
isTraceComplete
;
export
const
hasRunnersForProject
=
state
=>
state
.
job
.
runners
.
available
&&
!
state
.
job
.
runners
.
online
;
export
const
hasRunnersForProject
=
state
=>
state
.
job
.
runners
.
available
&&
!
state
.
job
.
runners
.
online
;
// prevent babel-plugin-rewire from generating an invalid default during karma tests
// prevent babel-plugin-rewire from generating an invalid default during karma tests
export
default
()
=>
{};
export
default
()
=>
{};
app/assets/javascripts/labels_select.js
View file @
160157a9
...
@@ -25,7 +25,35 @@ export default class LabelsSelect {
...
@@ -25,7 +25,35 @@ export default class LabelsSelect {
}
}
$els
.
each
(
function
(
i
,
dropdown
)
{
$els
.
each
(
function
(
i
,
dropdown
)
{
var
$block
,
$colorPreview
,
$dropdown
,
$form
,
$loading
,
$selectbox
,
$sidebarCollapsedValue
,
$value
,
abilityName
,
defaultLabel
,
enableLabelCreateButton
,
issueURLSplit
,
issueUpdateURL
,
labelUrl
,
namespacePath
,
projectPath
,
saveLabelData
,
selectedLabel
,
showAny
,
showNo
,
$sidebarLabelTooltip
,
initialSelected
,
$toggleText
,
fieldName
,
useId
,
propertyName
,
showMenuAbove
,
$container
,
$dropdownContainer
;
var
$block
,
$colorPreview
,
$dropdown
,
$form
,
$loading
,
$selectbox
,
$sidebarCollapsedValue
,
$value
,
abilityName
,
defaultLabel
,
enableLabelCreateButton
,
issueURLSplit
,
issueUpdateURL
,
labelUrl
,
namespacePath
,
projectPath
,
saveLabelData
,
selectedLabel
,
showAny
,
showNo
,
$sidebarLabelTooltip
,
initialSelected
,
$toggleText
,
fieldName
,
useId
,
propertyName
,
showMenuAbove
,
$container
,
$dropdownContainer
;
$dropdown
=
$
(
dropdown
);
$dropdown
=
$
(
dropdown
);
$dropdownContainer
=
$dropdown
.
closest
(
'
.labels-filter
'
);
$dropdownContainer
=
$dropdown
.
closest
(
'
.labels-filter
'
);
$toggleText
=
$dropdown
.
find
(
'
.dropdown-toggle-text
'
);
$toggleText
=
$dropdown
.
find
(
'
.dropdown-toggle-text
'
);
...
@@ -34,7 +62,7 @@ export default class LabelsSelect {
...
@@ -34,7 +62,7 @@ export default class LabelsSelect {
labelUrl
=
$dropdown
.
data
(
'
labels
'
);
labelUrl
=
$dropdown
.
data
(
'
labels
'
);
issueUpdateURL
=
$dropdown
.
data
(
'
issueUpdate
'
);
issueUpdateURL
=
$dropdown
.
data
(
'
issueUpdate
'
);
selectedLabel
=
$dropdown
.
data
(
'
selected
'
);
selectedLabel
=
$dropdown
.
data
(
'
selected
'
);
if
(
(
selectedLabel
!=
null
)
&&
!
$dropdown
.
hasClass
(
'
js-multiselect
'
))
{
if
(
selectedLabel
!=
null
&&
!
$dropdown
.
hasClass
(
'
js-multiselect
'
))
{
selectedLabel
=
selectedLabel
.
split
(
'
,
'
);
selectedLabel
=
selectedLabel
.
split
(
'
,
'
);
}
}
showNo
=
$dropdown
.
data
(
'
showNo
'
);
showNo
=
$dropdown
.
data
(
'
showNo
'
);
...
@@ -50,26 +78,37 @@ export default class LabelsSelect {
...
@@ -50,26 +78,37 @@ export default class LabelsSelect {
$value
=
$block
.
find
(
'
.value
'
);
$value
=
$block
.
find
(
'
.value
'
);
$loading
=
$block
.
find
(
'
.block-loading
'
).
fadeOut
();
$loading
=
$block
.
find
(
'
.block-loading
'
).
fadeOut
();
fieldName
=
$dropdown
.
data
(
'
fieldName
'
);
fieldName
=
$dropdown
.
data
(
'
fieldName
'
);
useId
=
$dropdown
.
is
(
'
.js-issuable-form-dropdown, .js-filter-bulk-update, .js-label-sidebar-dropdown
'
);
useId
=
$dropdown
.
is
(
'
.js-issuable-form-dropdown, .js-filter-bulk-update, .js-label-sidebar-dropdown
'
,
);
propertyName
=
useId
?
'
id
'
:
'
title
'
;
propertyName
=
useId
?
'
id
'
:
'
title
'
;
initialSelected
=
$selectbox
initialSelected
=
$selectbox
.
find
(
'
input[name="
'
+
$dropdown
.
data
(
'
fieldName
'
)
+
'
"]
'
)
.
find
(
'
input[name="
'
+
$dropdown
.
data
(
'
fieldName
'
)
+
'
"]
'
)
.
map
(
function
()
{
.
map
(
function
()
{
return
this
.
value
;
return
this
.
value
;
}).
get
();
})
.
get
();
const
{
handleClick
}
=
options
;
const
{
handleClick
}
=
options
;
$sidebarLabelTooltip
.
tooltip
();
$sidebarLabelTooltip
.
tooltip
();
if
(
$dropdown
.
closest
(
'
.dropdown
'
).
find
(
'
.dropdown-new-label
'
).
length
)
{
if
(
$dropdown
.
closest
(
'
.dropdown
'
).
find
(
'
.dropdown-new-label
'
).
length
)
{
new
CreateLabelDropdown
(
$dropdown
.
closest
(
'
.dropdown
'
).
find
(
'
.dropdown-new-label
'
),
namespacePath
,
projectPath
);
new
CreateLabelDropdown
(
$dropdown
.
closest
(
'
.dropdown
'
).
find
(
'
.dropdown-new-label
'
),
namespacePath
,
projectPath
,
);
}
}
saveLabelData
=
function
()
{
saveLabelData
=
function
()
{
var
data
,
selected
;
var
data
,
selected
;
selected
=
$dropdown
.
closest
(
'
.selectbox
'
).
find
(
"
input[name='
"
+
fieldName
+
"
']
"
).
map
(
function
()
{
selected
=
$dropdown
.
closest
(
'
.selectbox
'
)
.
find
(
"
input[name='
"
+
fieldName
+
"
']
"
)
.
map
(
function
()
{
return
this
.
value
;
return
this
.
value
;
}).
get
();
})
.
get
();
if
(
_
.
isEqual
(
initialSelected
,
selected
))
return
;
if
(
_
.
isEqual
(
initialSelected
,
selected
))
return
;
initialSelected
=
selected
;
initialSelected
=
selected
;
...
@@ -82,7 +121,8 @@ export default class LabelsSelect {
...
@@ -82,7 +121,8 @@ export default class LabelsSelect {
}
}
$loading
.
removeClass
(
'
hidden
'
).
fadeIn
();
$loading
.
removeClass
(
'
hidden
'
).
fadeIn
();
$dropdown
.
trigger
(
'
loading.gl.dropdown
'
);
$dropdown
.
trigger
(
'
loading.gl.dropdown
'
);
axios
.
put
(
issueUpdateURL
,
data
)
axios
.
put
(
issueUpdateURL
,
data
)
.
then
(({
data
})
=>
{
.
then
(({
data
})
=>
{
var
labelCount
,
template
,
labelTooltipTitle
,
labelTitles
,
formattedLabels
;
var
labelCount
,
template
,
labelTooltipTitle
,
labelTitles
,
formattedLabels
;
$loading
.
fadeOut
();
$loading
.
fadeOut
();
...
@@ -96,8 +136,7 @@ export default class LabelsSelect {
...
@@ -96,8 +136,7 @@ export default class LabelsSelect {
issueUpdateURL
,
issueUpdateURL
,
});
});
labelCount
=
data
.
labels
.
length
;
labelCount
=
data
.
labels
.
length
;
}
}
else
{
else
{
template
=
'
<span class="no-value">None</span>
'
;
template
=
'
<span class="no-value">None</span>
'
;
}
}
$value
.
removeAttr
(
'
style
'
).
html
(
template
);
$value
.
removeAttr
(
'
style
'
).
html
(
template
);
...
@@ -114,17 +153,14 @@ export default class LabelsSelect {
...
@@ -114,17 +153,14 @@ export default class LabelsSelect {
}
}
labelTooltipTitle
=
labelTitles
.
join
(
'
,
'
);
labelTooltipTitle
=
labelTitles
.
join
(
'
,
'
);
}
}
else
{
else
{
labelTooltipTitle
=
__
(
'
Labels
'
);
labelTooltipTitle
=
__
(
'
Labels
'
);
}
}
$sidebarLabelTooltip
$sidebarLabelTooltip
.
attr
(
'
title
'
,
labelTooltipTitle
).
tooltip
(
'
_fixTitle
'
);
.
attr
(
'
title
'
,
labelTooltipTitle
)
.
tooltip
(
'
_fixTitle
'
);
$
(
'
.has-tooltip
'
,
$value
).
tooltip
({
$
(
'
.has-tooltip
'
,
$value
).
tooltip
({
container
:
'
body
'
container
:
'
body
'
,
});
});
})
})
.
catch
(()
=>
flash
(
__
(
'
Error saving label update.
'
)));
.
catch
(()
=>
flash
(
__
(
'
Error saving label update.
'
)));
...
@@ -132,11 +168,14 @@ export default class LabelsSelect {
...
@@ -132,11 +168,14 @@ export default class LabelsSelect {
$dropdown
.
glDropdown
({
$dropdown
.
glDropdown
({
showMenuAbove
:
showMenuAbove
,
showMenuAbove
:
showMenuAbove
,
data
:
function
(
term
,
callback
)
{
data
:
function
(
term
,
callback
)
{
axios
.
get
(
labelUrl
)
axios
.
then
((
res
)
=>
{
.
get
(
labelUrl
)
let
data
=
_
.
chain
(
res
.
data
).
groupBy
(
function
(
label
)
{
.
then
(
res
=>
{
let
data
=
_
.
chain
(
res
.
data
)
.
groupBy
(
function
(
label
)
{
return
label
.
title
;
return
label
.
title
;
}).
map
(
function
(
label
)
{
})
.
map
(
function
(
label
)
{
var
color
;
var
color
;
color
=
_
.
map
(
label
,
function
(
dup
)
{
color
=
_
.
map
(
label
,
function
(
dup
)
{
return
dup
.
color
;
return
dup
.
color
;
...
@@ -145,21 +184,22 @@ export default class LabelsSelect {
...
@@ -145,21 +184,22 @@ export default class LabelsSelect {
id
:
label
[
0
].
id
,
id
:
label
[
0
].
id
,
title
:
label
[
0
].
title
,
title
:
label
[
0
].
title
,
color
:
color
,
color
:
color
,
duplicate
:
color
.
length
>
1
duplicate
:
color
.
length
>
1
,
};
};
}).
value
();
})
.
value
();
if
(
$dropdown
.
hasClass
(
'
js-extra-options
'
))
{
if
(
$dropdown
.
hasClass
(
'
js-extra-options
'
))
{
var
extraData
=
[];
var
extraData
=
[];
if
(
showNo
)
{
if
(
showNo
)
{
extraData
.
unshift
({
extraData
.
unshift
({
id
:
0
,
id
:
0
,
title
:
'
No Label
'
title
:
'
No Label
'
,
});
});
}
}
if
(
showAny
)
{
if
(
showAny
)
{
extraData
.
unshift
({
extraData
.
unshift
({
isAny
:
true
,
isAny
:
true
,
title
:
'
Any Label
'
title
:
'
Any Label
'
,
});
});
}
}
if
(
extraData
.
length
)
{
if
(
extraData
.
length
)
{
...
@@ -176,11 +216,22 @@ export default class LabelsSelect {
...
@@ -176,11 +216,22 @@ export default class LabelsSelect {
.
catch
(()
=>
flash
(
__
(
'
Error fetching labels.
'
)));
.
catch
(()
=>
flash
(
__
(
'
Error fetching labels.
'
)));
},
},
renderRow
:
function
(
label
,
instance
)
{
renderRow
:
function
(
label
,
instance
)
{
var
$a
,
$li
,
color
,
colorEl
,
indeterminate
,
removesAll
,
selectedClass
,
spacing
,
i
,
marked
,
dropdownName
,
dropdownValue
;
var
$a
,
$li
,
color
,
colorEl
,
indeterminate
,
removesAll
,
selectedClass
,
spacing
,
i
,
marked
,
dropdownName
,
dropdownValue
;
$li
=
$
(
'
<li>
'
);
$li
=
$
(
'
<li>
'
);
$a
=
$
(
'
<a href="#">
'
);
$a
=
$
(
'
<a href="#">
'
);
selectedClass
=
[];
selectedClass
=
[];
removesAll
=
label
.
id
<=
0
||
(
label
.
id
==
null
)
;
removesAll
=
label
.
id
<=
0
||
label
.
id
==
null
;
if
(
$dropdown
.
hasClass
(
'
js-filter-bulk-update
'
))
{
if
(
$dropdown
.
hasClass
(
'
js-filter-bulk-update
'
))
{
indeterminate
=
$dropdown
.
data
(
'
indeterminate
'
)
||
[];
indeterminate
=
$dropdown
.
data
(
'
indeterminate
'
)
||
[];
marked
=
$dropdown
.
data
(
'
marked
'
)
||
[];
marked
=
$dropdown
.
data
(
'
marked
'
)
||
[];
...
@@ -200,9 +251,19 @@ export default class LabelsSelect {
...
@@ -200,9 +251,19 @@ export default class LabelsSelect {
}
else
{
}
else
{
if
(
this
.
id
(
label
))
{
if
(
this
.
id
(
label
))
{
dropdownName
=
$dropdown
.
data
(
'
fieldName
'
);
dropdownName
=
$dropdown
.
data
(
'
fieldName
'
);
dropdownValue
=
this
.
id
(
label
).
toString
().
replace
(
/'/g
,
'
\\\'
'
);
dropdownValue
=
this
.
id
(
label
)
.
toString
()
if
(
$form
.
find
(
"
input[type='hidden'][name='
"
+
dropdownName
+
"
'][value='
"
+
dropdownValue
+
"
']
"
).
length
)
{
.
replace
(
/'/g
,
"
\\
'
"
);
if
(
$form
.
find
(
"
input[type='hidden'][name='
"
+
dropdownName
+
"
'][value='
"
+
dropdownValue
+
"
']
"
,
).
length
)
{
selectedClass
.
push
(
'
is-active
'
);
selectedClass
.
push
(
'
is-active
'
);
}
}
}
}
...
@@ -213,16 +274,14 @@ export default class LabelsSelect {
...
@@ -213,16 +274,14 @@ export default class LabelsSelect {
}
}
if
(
label
.
duplicate
)
{
if
(
label
.
duplicate
)
{
color
=
DropdownUtils
.
duplicateLabelColor
(
label
.
color
);
color
=
DropdownUtils
.
duplicateLabelColor
(
label
.
color
);
}
}
else
{
else
{
if
(
label
.
color
!=
null
)
{
if
(
label
.
color
!=
null
)
{
[
color
]
=
label
.
color
;
[
color
]
=
label
.
color
;
}
}
}
}
if
(
color
)
{
if
(
color
)
{
colorEl
=
"
<span class='dropdown-label-box' style='background:
"
+
color
+
"
'></span>
"
;
colorEl
=
"
<span class='dropdown-label-box' style='background:
"
+
color
+
"
'></span>
"
;
}
}
else
{
else
{
colorEl
=
''
;
colorEl
=
''
;
}
}
// We need to identify which items are actually labels
// We need to identify which items are actually labels
...
@@ -235,7 +294,7 @@ export default class LabelsSelect {
...
@@ -235,7 +294,7 @@ export default class LabelsSelect {
return
$li
.
html
(
$a
).
prop
(
'
outerHTML
'
);
return
$li
.
html
(
$a
).
prop
(
'
outerHTML
'
);
},
},
search
:
{
search
:
{
fields
:
[
'
title
'
]
fields
:
[
'
title
'
]
,
},
},
selectable
:
true
,
selectable
:
true
,
filterable
:
true
,
filterable
:
true
,
...
@@ -255,25 +314,21 @@ export default class LabelsSelect {
...
@@ -255,25 +314,21 @@ export default class LabelsSelect {
if
(
selected
&&
selected
.
id
===
0
)
{
if
(
selected
&&
selected
.
id
===
0
)
{
this
.
selected
=
[];
this
.
selected
=
[];
return
'
No Label
'
;
return
'
No Label
'
;
}
}
else
if
(
isSelected
)
{
else
if
(
isSelected
)
{
this
.
selected
.
push
(
title
);
this
.
selected
.
push
(
title
);
}
}
else
if
(
!
isSelected
&&
title
)
{
else
if
(
!
isSelected
&&
title
)
{
var
index
=
this
.
selected
.
indexOf
(
title
);
var
index
=
this
.
selected
.
indexOf
(
title
);
this
.
selected
.
splice
(
index
,
1
);
this
.
selected
.
splice
(
index
,
1
);
}
}
if
(
selectedLabels
.
length
===
1
)
{
if
(
selectedLabels
.
length
===
1
)
{
return
selectedLabels
;
return
selectedLabels
;
}
}
else
if
(
selectedLabels
.
length
)
{
else
if
(
selectedLabels
.
length
)
{
return
sprintf
(
__
(
'
%{firstLabel} +%{labelCount} more
'
),
{
return
sprintf
(
__
(
'
%{firstLabel} +%{labelCount} more
'
),
{
firstLabel
:
selectedLabels
[
0
],
firstLabel
:
selectedLabels
[
0
],
labelCount
:
selectedLabels
.
length
-
1
labelCount
:
selectedLabels
.
length
-
1
,
});
});
}
}
else
{
else
{
return
defaultLabel
;
return
defaultLabel
;
}
}
},
},
...
@@ -285,10 +340,9 @@ export default class LabelsSelect {
...
@@ -285,10 +340,9 @@ export default class LabelsSelect {
return
label
.
id
;
return
label
.
id
;
}
}
if
(
$dropdown
.
hasClass
(
"
js-filter-submit
"
)
&&
(
label
.
isAny
==
null
)
)
{
if
(
$dropdown
.
hasClass
(
'
js-filter-submit
'
)
&&
label
.
isAny
==
null
)
{
return
label
.
title
;
return
label
.
title
;
}
}
else
{
else
{
return
label
.
id
;
return
label
.
id
;
}
}
},
},
...
@@ -310,13 +364,13 @@ export default class LabelsSelect {
...
@@ -310,13 +364,13 @@ export default class LabelsSelect {
}
}
if
(
$dropdown
.
hasClass
(
'
js-multiselect
'
))
{
if
(
$dropdown
.
hasClass
(
'
js-multiselect
'
))
{
if
(
$dropdown
.
hasClass
(
'
js-filter-submit
'
)
&&
(
isIssueIndex
||
isMRIndex
))
{
if
(
$dropdown
.
hasClass
(
'
js-filter-submit
'
)
&&
(
isIssueIndex
||
isMRIndex
))
{
selectedLabels
=
$dropdown
.
closest
(
'
form
'
).
find
(
"
input:hidden[name='
"
+
(
$dropdown
.
data
(
'
fieldName
'
))
+
"
']
"
);
selectedLabels
=
$dropdown
.
closest
(
'
form
'
)
.
find
(
"
input:hidden[name='
"
+
$dropdown
.
data
(
'
fieldName
'
)
+
"
']
"
);
Issuable
.
filterResults
(
$dropdown
.
closest
(
'
form
'
));
Issuable
.
filterResults
(
$dropdown
.
closest
(
'
form
'
));
}
}
else
if
(
$dropdown
.
hasClass
(
'
js-filter-submit
'
))
{
else
if
(
$dropdown
.
hasClass
(
'
js-filter-submit
'
))
{
$dropdown
.
closest
(
'
form
'
).
submit
();
$dropdown
.
closest
(
'
form
'
).
submit
();
}
}
else
{
else
{
if
(
!
$dropdown
.
hasClass
(
'
js-filter-bulk-update
'
))
{
if
(
!
$dropdown
.
hasClass
(
'
js-filter-bulk-update
'
))
{
saveLabelData
();
saveLabelData
();
}
}
...
@@ -325,7 +379,7 @@ export default class LabelsSelect {
...
@@ -325,7 +379,7 @@ export default class LabelsSelect {
},
},
multiSelect
:
$dropdown
.
hasClass
(
'
js-multiselect
'
),
multiSelect
:
$dropdown
.
hasClass
(
'
js-multiselect
'
),
vue
:
$dropdown
.
hasClass
(
'
js-issue-board-sidebar
'
),
vue
:
$dropdown
.
hasClass
(
'
js-issue-board-sidebar
'
),
clicked
:
function
(
clickEvent
)
{
clicked
:
function
(
clickEvent
)
{
const
{
$el
,
e
,
isMarking
}
=
clickEvent
;
const
{
$el
,
e
,
isMarking
}
=
clickEvent
;
const
label
=
clickEvent
.
selectedObj
;
const
label
=
clickEvent
.
selectedObj
;
...
@@ -339,7 +393,8 @@ export default class LabelsSelect {
...
@@ -339,7 +393,8 @@ export default class LabelsSelect {
isMRIndex
=
page
===
'
projects:merge_requests:index
'
;
isMRIndex
=
page
===
'
projects:merge_requests:index
'
;
if
(
$dropdown
.
parent
().
find
(
'
.is-active:not(.dropdown-clear-active)
'
).
length
)
{
if
(
$dropdown
.
parent
().
find
(
'
.is-active:not(.dropdown-clear-active)
'
).
length
)
{
$dropdown
.
parent
()
$dropdown
.
parent
()
.
find
(
'
.dropdown-clear-active
'
)
.
find
(
'
.dropdown-clear-active
'
)
.
removeClass
(
'
is-active
'
);
.
removeClass
(
'
is-active
'
);
}
}
...
@@ -367,28 +422,26 @@ export default class LabelsSelect {
...
@@ -367,28 +422,26 @@ export default class LabelsSelect {
e
.
preventDefault
();
e
.
preventDefault
();
return
;
return
;
}
}
else
if
(
$dropdown
.
hasClass
(
'
js-filter-submit
'
)
&&
(
isIssueIndex
||
isMRIndex
))
{
else
if
(
$dropdown
.
hasClass
(
'
js-filter-submit
'
)
&&
(
isIssueIndex
||
isMRIndex
))
{
if
(
!
$dropdown
.
hasClass
(
'
js-multiselect
'
))
{
if
(
!
$dropdown
.
hasClass
(
'
js-multiselect
'
))
{
selectedLabel
=
label
.
title
;
selectedLabel
=
label
.
title
;
return
Issuable
.
filterResults
(
$dropdown
.
closest
(
'
form
'
));
return
Issuable
.
filterResults
(
$dropdown
.
closest
(
'
form
'
));
}
}
}
}
else
if
(
$dropdown
.
hasClass
(
'
js-filter-submit
'
))
{
else
if
(
$dropdown
.
hasClass
(
'
js-filter-submit
'
))
{
return
$dropdown
.
closest
(
'
form
'
).
submit
();
return
$dropdown
.
closest
(
'
form
'
).
submit
();
}
}
else
if
(
$dropdown
.
hasClass
(
'
js-issue-board-sidebar
'
))
{
else
if
(
$dropdown
.
hasClass
(
'
js-issue-board-sidebar
'
))
{
if
(
$el
.
hasClass
(
'
is-active
'
))
{
if
(
$el
.
hasClass
(
'
is-active
'
))
{
boardsStore
.
detail
.
issue
.
labels
.
push
(
new
ListLabel
({
boardsStore
.
detail
.
issue
.
labels
.
push
(
new
ListLabel
({
id
:
label
.
id
,
id
:
label
.
id
,
title
:
label
.
title
,
title
:
label
.
title
,
color
:
label
.
color
[
0
],
color
:
label
.
color
[
0
],
textColor
:
'
#fff
'
textColor
:
'
#fff
'
,
}));
}),
}
);
else
{
}
else
{
var
{
labels
}
=
boardsStore
.
detail
.
issue
;
var
{
labels
}
=
boardsStore
.
detail
.
issue
;
labels
=
labels
.
filter
(
function
(
selectedLabel
)
{
labels
=
labels
.
filter
(
function
(
selectedLabel
)
{
return
selectedLabel
.
id
!==
label
.
id
;
return
selectedLabel
.
id
!==
label
.
id
;
});
});
boardsStore
.
detail
.
issue
.
labels
=
labels
;
boardsStore
.
detail
.
issue
.
labels
=
labels
;
...
@@ -396,19 +449,16 @@ export default class LabelsSelect {
...
@@ -396,19 +449,16 @@ export default class LabelsSelect {
$loading
.
fadeIn
();
$loading
.
fadeIn
();
boardsStore
.
detail
.
issue
.
update
(
$dropdown
.
attr
(
'
data-issue-update
'
))
boardsStore
.
detail
.
issue
.
update
(
$dropdown
.
attr
(
'
data-issue-update
'
))
.
then
(
fadeOutLoader
)
.
then
(
fadeOutLoader
)
.
catch
(
fadeOutLoader
);
.
catch
(
fadeOutLoader
);
}
}
else
if
(
handleClick
)
{
else
if
(
handleClick
)
{
e
.
preventDefault
();
e
.
preventDefault
();
handleClick
(
label
);
handleClick
(
label
);
}
}
else
{
else
{
if
(
$dropdown
.
hasClass
(
'
js-multiselect
'
))
{
if
(
$dropdown
.
hasClass
(
'
js-multiselect
'
))
{
}
else
{
}
else
{
return
saveLabelData
();
return
saveLabelData
();
}
}
}
}
...
@@ -436,7 +486,8 @@ export default class LabelsSelect {
...
@@ -436,7 +486,8 @@ export default class LabelsSelect {
// so best approach is to use traditional way of
// so best approach is to use traditional way of
// concatenation
// concatenation
// see: http://2ality.com/2016/05/template-literal-whitespace.html#joining-arrays
// see: http://2ality.com/2016/05/template-literal-whitespace.html#joining-arrays
const
tpl
=
_
.
template
([
const
tpl
=
_
.
template
(
[
'
<% _.each(labels, function(label){ %>
'
,
'
<% _.each(labels, function(label){ %>
'
,
'
<a href="<%- issueUpdateURL.slice(0, issueUpdateURL.lastIndexOf("/")) %>?label_name[]=<%- encodeURIComponent(label.title) %>">
'
,
'
<a href="<%- issueUpdateURL.slice(0, issueUpdateURL.lastIndexOf("/")) %>?label_name[]=<%- encodeURIComponent(label.title) %>">
'
,
'
<span class="badge label has-tooltip color-label" title="<%- label.description %>" style="background-color: <%- label.color %>; color: <%- label.text_color %>;">
'
,
'
<span class="badge label has-tooltip color-label" title="<%- label.description %>" style="background-color: <%- label.color %>; color: <%- label.text_color %>;">
'
,
...
@@ -444,7 +495,8 @@ export default class LabelsSelect {
...
@@ -444,7 +495,8 @@ export default class LabelsSelect {
'
</span>
'
,
'
</span>
'
,
'
</a>
'
,
'
</a>
'
,
'
<% }); %>
'
,
'
<% }); %>
'
,
].
join
(
''
));
].
join
(
''
),
);
return
tpl
(
tplData
);
return
tpl
(
tplData
);
}
}
...
...
app/assets/javascripts/lib/utils/ace_utils.js
View file @
160157a9
/* global ace */
/* global ace */
export
default
function
getModeByFileExtension
(
path
)
{
export
default
function
getModeByFileExtension
(
path
)
{
const
modelist
=
ace
.
require
(
"
ace/ext/modelist
"
);
const
modelist
=
ace
.
require
(
'
ace/ext/modelist
'
);
return
modelist
.
getModeForPath
(
path
).
mode
;
return
modelist
.
getModeForPath
(
path
).
mode
;
}
;
}
app/assets/javascripts/lib/utils/number_utils.js
View file @
160157a9
...
@@ -7,7 +7,7 @@ import { BYTES_IN_KIB } from './constants';
...
@@ -7,7 +7,7 @@ import { BYTES_IN_KIB } from './constants';
* * * Show 3 digits to the right
* * * Show 3 digits to the right
* * For 2 digits to the left of the decimal point and X digits to the right of it
* * For 2 digits to the left of the decimal point and X digits to the right of it
* * * Show 2 digits to the right
* * * Show 2 digits to the right
*/
*/
export
function
formatRelevantDigits
(
number
)
{
export
function
formatRelevantDigits
(
number
)
{
let
digitsLeft
=
''
;
let
digitsLeft
=
''
;
let
relevantDigits
=
0
;
let
relevantDigits
=
0
;
...
...
app/assets/javascripts/members.js
View file @
160157a9
...
@@ -7,8 +7,12 @@ export default class Members {
...
@@ -7,8 +7,12 @@ export default class Members {
}
}
addListeners
()
{
addListeners
()
{
$
(
'
.js-member-update-control
'
).
off
(
'
change
'
).
on
(
'
change
'
,
this
.
formSubmit
.
bind
(
this
));
$
(
'
.js-member-update-control
'
)
$
(
'
.js-edit-member-form
'
).
off
(
'
ajax:success
'
).
on
(
'
ajax:success
'
,
this
.
formSuccess
.
bind
(
this
));
.
off
(
'
change
'
)
.
on
(
'
change
'
,
this
.
formSubmit
.
bind
(
this
));
$
(
'
.js-edit-member-form
'
)
.
off
(
'
ajax:success
'
)
.
on
(
'
ajax:success
'
,
this
.
formSuccess
.
bind
(
this
));
gl
.
utils
.
disableButtonIfEmptyField
(
'
#user_ids
'
,
'
input[name=commit]
'
,
'
change
'
);
gl
.
utils
.
disableButtonIfEmptyField
(
'
#user_ids
'
,
'
input[name=commit]
'
,
'
change
'
);
}
}
...
@@ -28,7 +32,7 @@ export default class Members {
...
@@ -28,7 +32,7 @@ export default class Members {
toggleLabel
(
selected
,
$el
)
{
toggleLabel
(
selected
,
$el
)
{
return
$el
.
text
();
return
$el
.
text
();
},
},
clicked
:
(
options
)
=>
{
clicked
:
options
=>
{
this
.
formSubmit
(
null
,
options
.
$el
);
this
.
formSubmit
(
null
,
options
.
$el
);
},
},
});
});
...
...
app/assets/javascripts/milestone_select.js
View file @
160157a9
...
@@ -9,7 +9,10 @@ import '~/gl_dropdown';
...
@@ -9,7 +9,10 @@ import '~/gl_dropdown';
import
axios
from
'
./lib/utils/axios_utils
'
;
import
axios
from
'
./lib/utils/axios_utils
'
;
import
{
timeFor
}
from
'
./lib/utils/datetime_utility
'
;
import
{
timeFor
}
from
'
./lib/utils/datetime_utility
'
;
import
ModalStore
from
'
./boards/stores/modal_store
'
;
import
ModalStore
from
'
./boards/stores/modal_store
'
;
import
boardsStore
,
{
boardStoreIssueSet
,
boardStoreIssueDelete
}
from
'
./boards/stores/boards_store
'
;
import
boardsStore
,
{
boardStoreIssueSet
,
boardStoreIssueDelete
,
}
from
'
./boards/stores/boards_store
'
;
export
default
class
MilestoneSelect
{
export
default
class
MilestoneSelect
{
constructor
(
currentProject
,
els
,
options
=
{})
{
constructor
(
currentProject
,
els
,
options
=
{})
{
...
...
app/assets/javascripts/notes/components/notes_app.vue
View file @
160157a9
...
@@ -54,7 +54,13 @@ export default {
...
@@ -54,7 +54,13 @@ export default {
};
};
},
},
computed
:
{
computed
:
{
...
mapGetters
([
'
isNotesFetched
'
,
'
discussions
'
,
'
getNotesDataByProp
'
,
'
discussionCount
'
,
'
isLoading
'
]),
...
mapGetters
([
'
isNotesFetched
'
,
'
discussions
'
,
'
getNotesDataByProp
'
,
'
discussionCount
'
,
'
isLoading
'
,
]),
noteableType
()
{
noteableType
()
{
return
this
.
noteableData
.
noteableType
;
return
this
.
noteableData
.
noteableType
;
},
},
...
...
app/assets/javascripts/notes/discussion_filters.js
View file @
160157a9
import
Vue
from
'
vue
'
;
import
Vue
from
'
vue
'
;
import
DiscussionFilter
from
'
./components/discussion_filter.vue
'
;
import
DiscussionFilter
from
'
./components/discussion_filter.vue
'
;
export
default
(
store
)
=>
{
export
default
store
=>
{
const
discussionFilterEl
=
document
.
getElementById
(
'
js-vue-discussion-filter
'
);
const
discussionFilterEl
=
document
.
getElementById
(
'
js-vue-discussion-filter
'
);
if
(
discussionFilterEl
)
{
if
(
discussionFilterEl
)
{
const
{
defaultFilter
,
notesFilters
}
=
discussionFilterEl
.
dataset
;
const
{
defaultFilter
,
notesFilters
}
=
discussionFilterEl
.
dataset
;
const
defaultValue
=
defaultFilter
?
parseInt
(
defaultFilter
,
10
)
:
null
;
const
defaultValue
=
defaultFilter
?
parseInt
(
defaultFilter
,
10
)
:
null
;
const
filterValues
=
notesFilters
?
JSON
.
parse
(
notesFilters
)
:
{};
const
filterValues
=
notesFilters
?
JSON
.
parse
(
notesFilters
)
:
{};
const
filters
=
Object
.
keys
(
filterValues
).
map
(
entry
=>
const
filters
=
Object
.
keys
(
filterValues
).
map
(
entry
=>
({
({
title
:
entry
,
value
:
filterValues
[
entry
]
}));
title
:
entry
,
value
:
filterValues
[
entry
],
}));
return
new
Vue
({
return
new
Vue
({
el
:
discussionFilterEl
,
el
:
discussionFilterEl
,
...
...
app/assets/javascripts/pages/milestones/shared/components/promote_milestone_modal.vue
View file @
160157a9
<
script
>
<
script
>
import
axios
from
'
~/lib/utils/axios_utils
'
;
import
axios
from
'
~/lib/utils/axios_utils
'
;
import
createFlash
from
'
~/flash
'
;
import
createFlash
from
'
~/flash
'
;
import
GlModal
from
'
~/vue_shared/components/gl_modal.vue
'
;
import
GlModal
from
'
~/vue_shared/components/gl_modal.vue
'
;
import
{
s__
,
sprintf
}
from
'
~/locale
'
;
import
{
s__
,
sprintf
}
from
'
~/locale
'
;
import
{
visitUrl
}
from
'
~/lib/utils/url_utility
'
;
import
{
visitUrl
}
from
'
~/lib/utils/url_utility
'
;
import
eventHub
from
'
../event_hub
'
;
import
eventHub
from
'
../event_hub
'
;
export
default
{
export
default
{
components
:
{
components
:
{
GlModal
,
GlModal
,
},
},
...
@@ -26,29 +26,41 @@
...
@@ -26,29 +26,41 @@
},
},
computed
:
{
computed
:
{
title
()
{
title
()
{
return
sprintf
(
s__
(
'
Milestones|Promote %{milestoneTitle} to group milestone?
'
),
{
milestoneTitle
:
this
.
milestoneTitle
});
return
sprintf
(
s__
(
'
Milestones|Promote %{milestoneTitle} to group milestone?
'
),
{
milestoneTitle
:
this
.
milestoneTitle
,
});
},
},
text
()
{
text
()
{
return
sprintf
(
s__
(
`Milestones|Promoting %{milestoneTitle} will make it available for all projects inside %{groupName}.
return
sprintf
(
s__
(
`Milestones|Promoting %{milestoneTitle} will make it available for all projects inside %{groupName}.
Existing project milestones with the same title will be merged.
Existing project milestones with the same title will be merged.
This action cannot be reversed.`
),
{
milestoneTitle
:
this
.
milestoneTitle
,
groupName
:
this
.
groupName
});
This action cannot be reversed.`
),
{
milestoneTitle
:
this
.
milestoneTitle
,
groupName
:
this
.
groupName
},
);
},
},
},
},
methods
:
{
methods
:
{
onSubmit
()
{
onSubmit
()
{
eventHub
.
$emit
(
'
promoteMilestoneModal.requestStarted
'
,
this
.
url
);
eventHub
.
$emit
(
'
promoteMilestoneModal.requestStarted
'
,
this
.
url
);
return
axios
.
post
(
this
.
url
,
{
params
:
{
format
:
'
json
'
}
})
return
axios
.
then
((
response
)
=>
{
.
post
(
this
.
url
,
{
params
:
{
format
:
'
json
'
}
})
eventHub
.
$emit
(
'
promoteMilestoneModal.requestFinished
'
,
{
milestoneUrl
:
this
.
url
,
successful
:
true
});
.
then
(
response
=>
{
eventHub
.
$emit
(
'
promoteMilestoneModal.requestFinished
'
,
{
milestoneUrl
:
this
.
url
,
successful
:
true
,
});
visitUrl
(
response
.
data
.
url
);
visitUrl
(
response
.
data
.
url
);
})
})
.
catch
((
error
)
=>
{
.
catch
(
error
=>
{
eventHub
.
$emit
(
'
promoteMilestoneModal.requestFinished
'
,
{
milestoneUrl
:
this
.
url
,
successful
:
false
});
eventHub
.
$emit
(
'
promoteMilestoneModal.requestFinished
'
,
{
milestoneUrl
:
this
.
url
,
successful
:
false
,
});
createFlash
(
error
);
createFlash
(
error
);
});
});
},
},
},
},
};
};
</
script
>
</
script
>
<
template
>
<
template
>
<gl-modal
<gl-modal
...
@@ -65,4 +77,3 @@
...
@@ -65,4 +77,3 @@
{{ text }}
{{ text }}
</gl-modal>
</gl-modal>
</template>
</template>
app/assets/javascripts/pages/projects/project.js
View file @
160157a9
...
@@ -64,7 +64,9 @@ export default class Project {
...
@@ -64,7 +64,9 @@ export default class Project {
const
projectId
=
$
(
this
).
data
(
'
project-id
'
);
const
projectId
=
$
(
this
).
data
(
'
project-id
'
);
const
cookieKey
=
`hide_auto_devops_implicitly_enabled_banner_
${
projectId
}
`
;
const
cookieKey
=
`hide_auto_devops_implicitly_enabled_banner_
${
projectId
}
`
;
Cookies
.
set
(
cookieKey
,
'
false
'
);
Cookies
.
set
(
cookieKey
,
'
false
'
);
$
(
this
).
parents
(
'
.auto-devops-implicitly-enabled-banner
'
).
remove
();
$
(
this
)
.
parents
(
'
.auto-devops-implicitly-enabled-banner
'
)
.
remove
();
return
e
.
preventDefault
();
return
e
.
preventDefault
();
});
});
Project
.
projectSelectDropdown
();
Project
.
projectSelectDropdown
();
...
...
app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue
View file @
160157a9
<
script
>
<
script
>
import
projectFeatureSetting
from
'
./project_feature_setting.vue
'
;
import
projectFeatureSetting
from
'
./project_feature_setting.vue
'
;
import
projectFeatureToggle
from
'
../../../../../vue_shared/components/toggle_button.vue
'
;
import
projectFeatureToggle
from
'
../../../../../vue_shared/components/toggle_button.vue
'
;
import
projectSettingRow
from
'
./project_setting_row.vue
'
;
import
projectSettingRow
from
'
./project_setting_row.vue
'
;
import
{
visibilityOptions
,
visibilityLevelDescriptions
}
from
'
../constants
'
;
import
{
visibilityOptions
,
visibilityLevelDescriptions
}
from
'
../constants
'
;
import
{
toggleHiddenClassBySelector
}
from
'
../external
'
;
import
{
toggleHiddenClassBySelector
}
from
'
../external
'
;
export
default
{
export
default
{
components
:
{
components
:
{
projectFeatureSetting
,
projectFeatureSetting
,
projectFeatureToggle
,
projectFeatureToggle
,
...
@@ -91,9 +91,7 @@
...
@@ -91,9 +91,7 @@
computed
:
{
computed
:
{
featureAccessLevelOptions
()
{
featureAccessLevelOptions
()
{
const
options
=
[
const
options
=
[[
10
,
'
Only Project Members
'
]];
[
10
,
'
Only Project Members
'
],
];
if
(
this
.
visibilityLevel
!==
visibilityOptions
.
PRIVATE
)
{
if
(
this
.
visibilityLevel
!==
visibilityOptions
.
PRIVATE
)
{
options
.
push
([
20
,
'
Everyone With Access
'
]);
options
.
push
([
20
,
'
Everyone With Access
'
]);
}
}
...
@@ -196,7 +194,7 @@
...
@@ -196,7 +194,7 @@
return
this
.
allowedVisibilityOptions
.
includes
(
option
);
return
this
.
allowedVisibilityOptions
.
includes
(
option
);
},
},
},
},
};
};
</
script
>
</
script
>
<
template
>
<
template
>
...
...
app/assets/javascripts/projects/project_new.js
View file @
160157a9
...
@@ -4,8 +4,10 @@ import { slugifyWithHyphens } from '../lib/utils/text_utility';
...
@@ -4,8 +4,10 @@ import { slugifyWithHyphens } from '../lib/utils/text_utility';
let
hasUserDefinedProjectPath
=
false
;
let
hasUserDefinedProjectPath
=
false
;
const
deriveProjectPathFromUrl
=
(
$projectImportUrl
)
=>
{
const
deriveProjectPathFromUrl
=
$projectImportUrl
=>
{
const
$currentProjectPath
=
$projectImportUrl
.
parents
(
'
.toggle-import-form
'
).
find
(
'
#project_path
'
);
const
$currentProjectPath
=
$projectImportUrl
.
parents
(
'
.toggle-import-form
'
)
.
find
(
'
#project_path
'
);
if
(
hasUserDefinedProjectPath
)
{
if
(
hasUserDefinedProjectPath
)
{
return
;
return
;
}
}
...
@@ -52,9 +54,11 @@ const bindEvents = () => {
...
@@ -52,9 +54,11 @@ const bindEvents = () => {
return
;
return
;
}
}
$
(
'
.how_to_import_link
'
).
on
(
'
click
'
,
(
e
)
=>
{
$
(
'
.how_to_import_link
'
).
on
(
'
click
'
,
e
=>
{
e
.
preventDefault
();
e
.
preventDefault
();
$
(
e
.
currentTarget
).
next
(
'
.modal
'
).
show
();
$
(
e
.
currentTarget
)
.
next
(
'
.modal
'
)
.
show
();
});
});
$
(
'
.modal-header .close
'
).
on
(
'
click
'
,
()
=>
{
$
(
'
.modal-header .close
'
).
on
(
'
click
'
,
()
=>
{
...
@@ -63,15 +67,21 @@ const bindEvents = () => {
...
@@ -63,15 +67,21 @@ const bindEvents = () => {
$
(
'
.btn_import_gitlab_project
'
).
on
(
'
click
'
,
()
=>
{
$
(
'
.btn_import_gitlab_project
'
).
on
(
'
click
'
,
()
=>
{
const
importHref
=
$
(
'
a.btn_import_gitlab_project
'
).
attr
(
'
href
'
);
const
importHref
=
$
(
'
a.btn_import_gitlab_project
'
).
attr
(
'
href
'
);
$
(
'
.btn_import_gitlab_project
'
)
$
(
'
.btn_import_gitlab_project
'
).
attr
(
.
attr
(
'
href
'
,
`
${
importHref
}
?namespace_id=
${
$
(
'
#project_namespace_id
'
).
val
()}
&name=
${
$projectName
.
val
()}
&path=
${
$projectPath
.
val
()}
`
);
'
href
'
,
`
${
importHref
}
?namespace_id=
${
$
(
'
#project_namespace_id
'
,
).
val
()}
&name=
${
$projectName
.
val
()}
&path=
${
$projectPath
.
val
()}
`
,
);
});
});
if
(
$pushNewProjectTipTrigger
)
{
if
(
$pushNewProjectTipTrigger
)
{
$pushNewProjectTipTrigger
$pushNewProjectTipTrigger
.
removeAttr
(
'
rel
'
)
.
removeAttr
(
'
rel
'
)
.
removeAttr
(
'
target
'
)
.
removeAttr
(
'
target
'
)
.
on
(
'
click
'
,
(
e
)
=>
{
e
.
preventDefault
();
})
.
on
(
'
click
'
,
e
=>
{
e
.
preventDefault
();
})
.
popover
({
.
popover
({
title
:
$pushNewProjectTipTrigger
.
data
(
'
title
'
),
title
:
$pushNewProjectTipTrigger
.
data
(
'
title
'
),
placement
:
'
bottom
'
,
placement
:
'
bottom
'
,
...
@@ -79,13 +89,15 @@ const bindEvents = () => {
...
@@ -79,13 +89,15 @@ const bindEvents = () => {
content
:
$
(
'
.push-new-project-tip-template
'
).
html
(),
content
:
$
(
'
.push-new-project-tip-template
'
).
html
(),
})
})
.
on
(
'
shown.bs.popover
'
,
()
=>
{
.
on
(
'
shown.bs.popover
'
,
()
=>
{
$
(
document
).
on
(
'
click.popover touchstart.popover
'
,
(
event
)
=>
{
$
(
document
).
on
(
'
click.popover touchstart.popover
'
,
event
=>
{
if
(
$
(
event
.
target
).
closest
(
'
.popover
'
).
length
===
0
)
{
if
(
$
(
event
.
target
).
closest
(
'
.popover
'
).
length
===
0
)
{
$pushNewProjectTipTrigger
.
trigger
(
'
click
'
);
$pushNewProjectTipTrigger
.
trigger
(
'
click
'
);
}
}
});
});
const
target
=
$
(
`#
${
$pushNewProjectTipTrigger
.
attr
(
'
aria-describedby
'
)}
`
).
find
(
'
.js-select-on-focus
'
);
const
target
=
$
(
`#
${
$pushNewProjectTipTrigger
.
attr
(
'
aria-describedby
'
)}
`
).
find
(
'
.js-select-on-focus
'
,
);
addSelectOnFocusBehaviour
(
target
);
addSelectOnFocusBehaviour
(
target
);
target
.
focus
();
target
.
focus
();
...
@@ -117,13 +129,15 @@ const bindEvents = () => {
...
@@ -117,13 +129,15 @@ const bindEvents = () => {
const
selectedTemplate
=
templates
[
value
];
const
selectedTemplate
=
templates
[
value
];
$selectedTemplateText
.
text
(
selectedTemplate
.
text
);
$selectedTemplateText
.
text
(
selectedTemplate
.
text
);
$
(
selectedTemplate
.
icon
).
clone
().
addClass
(
'
d-block
'
).
appendTo
(
$selectedIcon
);
$
(
selectedTemplate
.
icon
)
.
clone
()
.
addClass
(
'
d-block
'
)
.
appendTo
(
$selectedIcon
);
const
$activeTabProjectName
=
$
(
'
.tab-pane.active #project_name
'
);
const
$activeTabProjectName
=
$
(
'
.tab-pane.active #project_name
'
);
const
$activeTabProjectPath
=
$
(
'
.tab-pane.active #project_path
'
);
const
$activeTabProjectPath
=
$
(
'
.tab-pane.active #project_path
'
);
$activeTabProjectName
.
focus
();
$activeTabProjectName
.
focus
();
$activeTabProjectName
$activeTabProjectName
.
keyup
(()
=>
{
.
keyup
(()
=>
{
onProjectNameChange
(
$activeTabProjectName
,
$activeTabProjectPath
);
onProjectNameChange
(
$activeTabProjectName
,
$activeTabProjectPath
);
hasUserDefinedProjectPath
=
$activeTabProjectPath
.
val
().
trim
().
length
>
0
;
hasUserDefinedProjectPath
=
$activeTabProjectPath
.
val
().
trim
().
length
>
0
;
});
});
...
...
app/assets/javascripts/right_sidebar.js
View file @
160157a9
...
@@ -21,7 +21,7 @@ Sidebar.initialize = function(currentUser) {
...
@@ -21,7 +21,7 @@ Sidebar.initialize = function(currentUser) {
}
}
};
};
Sidebar
.
prototype
.
removeListeners
=
function
()
{
Sidebar
.
prototype
.
removeListeners
=
function
()
{
this
.
sidebar
.
off
(
'
click
'
,
'
.sidebar-collapsed-icon
'
);
this
.
sidebar
.
off
(
'
click
'
,
'
.sidebar-collapsed-icon
'
);
this
.
sidebar
.
off
(
'
hidden.gl.dropdown
'
);
this
.
sidebar
.
off
(
'
hidden.gl.dropdown
'
);
$
(
'
.dropdown
'
).
off
(
'
loading.gl.dropdown
'
);
$
(
'
.dropdown
'
).
off
(
'
loading.gl.dropdown
'
);
...
@@ -38,10 +38,12 @@ Sidebar.prototype.addEventListeners = function() {
...
@@ -38,10 +38,12 @@ Sidebar.prototype.addEventListeners = function() {
$
(
'
.dropdown
'
).
on
(
'
loaded.gl.dropdown
'
,
this
.
sidebarDropdownLoaded
);
$
(
'
.dropdown
'
).
on
(
'
loaded.gl.dropdown
'
,
this
.
sidebarDropdownLoaded
);
$document
.
on
(
'
click
'
,
'
.js-sidebar-toggle
'
,
this
.
sidebarToggleClicked
);
$document
.
on
(
'
click
'
,
'
.js-sidebar-toggle
'
,
this
.
sidebarToggleClicked
);
return
$
(
document
).
off
(
'
click
'
,
'
.js-issuable-todo
'
).
on
(
'
click
'
,
'
.js-issuable-todo
'
,
this
.
toggleTodo
);
return
$
(
document
)
.
off
(
'
click
'
,
'
.js-issuable-todo
'
)
.
on
(
'
click
'
,
'
.js-issuable-todo
'
,
this
.
toggleTodo
);
};
};
Sidebar
.
prototype
.
sidebarToggleClicked
=
function
(
e
,
triggered
)
{
Sidebar
.
prototype
.
sidebarToggleClicked
=
function
(
e
,
triggered
)
{
var
$allGutterToggleIcons
,
$this
,
isExpanded
,
tooltipLabel
;
var
$allGutterToggleIcons
,
$this
,
isExpanded
,
tooltipLabel
;
e
.
preventDefault
();
e
.
preventDefault
();
$this
=
$
(
this
);
$this
=
$
(
this
);
...
@@ -51,18 +53,26 @@ Sidebar.prototype.sidebarToggleClicked = function (e, triggered) {
...
@@ -51,18 +53,26 @@ Sidebar.prototype.sidebarToggleClicked = function (e, triggered) {
if
(
isExpanded
)
{
if
(
isExpanded
)
{
$allGutterToggleIcons
.
removeClass
(
'
fa-angle-double-right
'
).
addClass
(
'
fa-angle-double-left
'
);
$allGutterToggleIcons
.
removeClass
(
'
fa-angle-double-right
'
).
addClass
(
'
fa-angle-double-left
'
);
$
(
'
aside.right-sidebar
'
).
removeClass
(
'
right-sidebar-expanded
'
).
addClass
(
'
right-sidebar-collapsed
'
);
$
(
'
aside.right-sidebar
'
)
$
(
'
.layout-page
'
).
removeClass
(
'
right-sidebar-expanded
'
).
addClass
(
'
right-sidebar-collapsed
'
);
.
removeClass
(
'
right-sidebar-expanded
'
)
.
addClass
(
'
right-sidebar-collapsed
'
);
$
(
'
.layout-page
'
)
.
removeClass
(
'
right-sidebar-expanded
'
)
.
addClass
(
'
right-sidebar-collapsed
'
);
}
else
{
}
else
{
$allGutterToggleIcons
.
removeClass
(
'
fa-angle-double-left
'
).
addClass
(
'
fa-angle-double-right
'
);
$allGutterToggleIcons
.
removeClass
(
'
fa-angle-double-left
'
).
addClass
(
'
fa-angle-double-right
'
);
$
(
'
aside.right-sidebar
'
).
removeClass
(
'
right-sidebar-collapsed
'
).
addClass
(
'
right-sidebar-expanded
'
);
$
(
'
aside.right-sidebar
'
)
$
(
'
.layout-page
'
).
removeClass
(
'
right-sidebar-collapsed
'
).
addClass
(
'
right-sidebar-expanded
'
);
.
removeClass
(
'
right-sidebar-collapsed
'
)
.
addClass
(
'
right-sidebar-expanded
'
);
$
(
'
.layout-page
'
)
.
removeClass
(
'
right-sidebar-collapsed
'
)
.
addClass
(
'
right-sidebar-expanded
'
);
}
}
$this
.
attr
(
'
data-original-title
'
,
tooltipLabel
);
$this
.
attr
(
'
data-original-title
'
,
tooltipLabel
);
if
(
!
triggered
)
{
if
(
!
triggered
)
{
Cookies
.
set
(
"
collapsed_gutter
"
,
$
(
'
.right-sidebar
'
).
hasClass
(
'
right-sidebar-collapsed
'
));
Cookies
.
set
(
'
collapsed_gutter
'
,
$
(
'
.right-sidebar
'
).
hasClass
(
'
right-sidebar-collapsed
'
));
}
}
};
};
...
@@ -71,21 +81,27 @@ Sidebar.prototype.toggleTodo = function(e) {
...
@@ -71,21 +81,27 @@ Sidebar.prototype.toggleTodo = function(e) {
$this
=
$
(
e
.
currentTarget
);
$this
=
$
(
e
.
currentTarget
);
ajaxType
=
$this
.
attr
(
'
data-delete-path
'
)
?
'
delete
'
:
'
post
'
;
ajaxType
=
$this
.
attr
(
'
data-delete-path
'
)
?
'
delete
'
:
'
post
'
;
if
(
$this
.
attr
(
'
data-delete-path
'
))
{
if
(
$this
.
attr
(
'
data-delete-path
'
))
{
url
=
""
+
(
$this
.
attr
(
'
data-delete-path
'
)
);
url
=
''
+
$this
.
attr
(
'
data-delete-path
'
);
}
else
{
}
else
{
url
=
""
+
(
$this
.
data
(
'
url
'
)
);
url
=
''
+
$this
.
data
(
'
url
'
);
}
}
$this
.
tooltip
(
'
hide
'
);
$this
.
tooltip
(
'
hide
'
);
$
(
'
.js-issuable-todo
'
).
disable
().
addClass
(
'
is-loading
'
);
$
(
'
.js-issuable-todo
'
)
.
disable
()
.
addClass
(
'
is-loading
'
);
axios
[
ajaxType
](
url
,
{
axios
[
ajaxType
](
url
,
{
issuable_id
:
$this
.
data
(
'
issuableId
'
),
issuable_id
:
$this
.
data
(
'
issuableId
'
),
issuable_type
:
$this
.
data
(
'
issuableType
'
),
issuable_type
:
$this
.
data
(
'
issuableType
'
),
}).
then
(({
data
})
=>
{
})
.
then
(({
data
})
=>
{
this
.
todoUpdateDone
(
data
);
this
.
todoUpdateDone
(
data
);
}).
catch
(()
=>
flash
(
`There was an error
${
ajaxType
===
'
post
'
?
'
adding a
'
:
'
deleting the
'
}
todo.`
));
})
.
catch
(()
=>
flash
(
`There was an error
${
ajaxType
===
'
post
'
?
'
adding a
'
:
'
deleting the
'
}
todo.`
),
);
};
};
Sidebar
.
prototype
.
todoUpdateDone
=
function
(
data
)
{
Sidebar
.
prototype
.
todoUpdateDone
=
function
(
data
)
{
...
@@ -99,7 +115,8 @@ Sidebar.prototype.todoUpdateDone = function(data) {
...
@@ -99,7 +115,8 @@ Sidebar.prototype.todoUpdateDone = function(data) {
const
$el
=
$
(
el
);
const
$el
=
$
(
el
);
const
$elText
=
$el
.
find
(
'
.js-issuable-todo-inner
'
);
const
$elText
=
$el
.
find
(
'
.js-issuable-todo-inner
'
);
$el
.
removeClass
(
'
is-loading
'
)
$el
.
removeClass
(
'
is-loading
'
)
.
enable
()
.
enable
()
.
attr
(
'
aria-label
'
,
$el
.
data
(
`
${
attrPrefix
}
Text`
))
.
attr
(
'
aria-label
'
,
$el
.
data
(
`
${
attrPrefix
}
Text`
))
.
attr
(
'
data-delete-path
'
,
deletePath
)
.
attr
(
'
data-delete-path
'
,
deletePath
)
...
@@ -119,7 +136,9 @@ Sidebar.prototype.todoUpdateDone = function(data) {
...
@@ -119,7 +136,9 @@ Sidebar.prototype.todoUpdateDone = function(data) {
Sidebar
.
prototype
.
sidebarDropdownLoading
=
function
(
e
)
{
Sidebar
.
prototype
.
sidebarDropdownLoading
=
function
(
e
)
{
var
$loading
,
$sidebarCollapsedIcon
,
i
,
img
;
var
$loading
,
$sidebarCollapsedIcon
,
i
,
img
;
$sidebarCollapsedIcon
=
$
(
this
).
closest
(
'
.block
'
).
find
(
'
.sidebar-collapsed-icon
'
);
$sidebarCollapsedIcon
=
$
(
this
)
.
closest
(
'
.block
'
)
.
find
(
'
.sidebar-collapsed-icon
'
);
img
=
$sidebarCollapsedIcon
.
find
(
'
img
'
);
img
=
$sidebarCollapsedIcon
.
find
(
'
img
'
);
i
=
$sidebarCollapsedIcon
.
find
(
'
i
'
);
i
=
$sidebarCollapsedIcon
.
find
(
'
i
'
);
$loading
=
$
(
'
<i class="fa fa-spinner fa-spin"></i>
'
);
$loading
=
$
(
'
<i class="fa fa-spinner fa-spin"></i>
'
);
...
@@ -134,7 +153,9 @@ Sidebar.prototype.sidebarDropdownLoading = function(e) {
...
@@ -134,7 +153,9 @@ Sidebar.prototype.sidebarDropdownLoading = function(e) {
Sidebar
.
prototype
.
sidebarDropdownLoaded
=
function
(
e
)
{
Sidebar
.
prototype
.
sidebarDropdownLoaded
=
function
(
e
)
{
var
$sidebarCollapsedIcon
,
i
,
img
;
var
$sidebarCollapsedIcon
,
i
,
img
;
$sidebarCollapsedIcon
=
$
(
this
).
closest
(
'
.block
'
).
find
(
'
.sidebar-collapsed-icon
'
);
$sidebarCollapsedIcon
=
$
(
this
)
.
closest
(
'
.block
'
)
.
find
(
'
.sidebar-collapsed-icon
'
);
img
=
$sidebarCollapsedIcon
.
find
(
'
img
'
);
img
=
$sidebarCollapsedIcon
.
find
(
'
img
'
);
$sidebarCollapsedIcon
.
find
(
'
i.fa-spin
'
).
remove
();
$sidebarCollapsedIcon
.
find
(
'
i.fa-spin
'
).
remove
();
i
=
$sidebarCollapsedIcon
.
find
(
'
i
'
);
i
=
$sidebarCollapsedIcon
.
find
(
'
i
'
);
...
@@ -220,7 +241,7 @@ Sidebar.prototype.isOpen = function() {
...
@@ -220,7 +241,7 @@ Sidebar.prototype.isOpen = function() {
};
};
Sidebar
.
prototype
.
getBlock
=
function
(
name
)
{
Sidebar
.
prototype
.
getBlock
=
function
(
name
)
{
return
this
.
sidebar
.
find
(
"
.block.
"
+
name
);
return
this
.
sidebar
.
find
(
'
.block.
'
+
name
);
};
};
export
default
Sidebar
;
export
default
Sidebar
;
app/assets/javascripts/search_autocomplete.js
View file @
160157a9
...
@@ -234,7 +234,9 @@ export class SearchAutocomplete {
...
@@ -234,7 +234,9 @@ export class SearchAutocomplete {
icon
,
icon
,
text
:
term
,
text
:
term
,
template
,
template
,
url
:
`
${
gon
.
relative_url_root
}
/search?search=
${
term
}
&project_id=
${
this
.
projectInputEl
.
val
()}
&group_id=
${
this
.
groupInputEl
.
val
()}
`
,
url
:
`
${
gon
.
relative_url_root
}
/search?search=
${
term
}
&project_id=
${
this
.
projectInputEl
.
val
()}
&group_id=
${
this
.
groupInputEl
.
val
()}
`
,
});
});
}
}
}
}
...
...
app/assets/javascripts/sidebar/components/assignees/assignees.vue
View file @
160157a9
...
@@ -74,8 +74,8 @@ export default {
...
@@ -74,8 +74,8 @@ export default {
}
}
if
(
!
this
.
users
.
length
)
{
if
(
!
this
.
users
.
length
)
{
const
emptyTooltipLabel
=
this
.
issuableType
===
'
issue
'
?
const
emptyTooltipLabel
=
__
(
'
Assignee(s)
'
)
:
__
(
'
Assignee
'
);
this
.
issuableType
===
'
issue
'
?
__
(
'
Assignee(s)
'
)
:
__
(
'
Assignee
'
);
names
.
push
(
emptyTooltipLabel
);
names
.
push
(
emptyTooltipLabel
);
}
}
...
@@ -248,4 +248,3 @@ export default {
...
@@ -248,4 +248,3 @@ export default {
</div>
</div>
</div>
</div>
</template>
</template>
app/assets/javascripts/sidebar/components/subscriptions/subscriptions.vue
View file @
160157a9
<
script
>
<
script
>
import
{
__
}
from
'
~/locale
'
;
import
{
__
}
from
'
~/locale
'
;
import
icon
from
'
~/vue_shared/components/icon.vue
'
;
import
icon
from
'
~/vue_shared/components/icon.vue
'
;
import
toggleButton
from
'
~/vue_shared/components/toggle_button.vue
'
;
import
toggleButton
from
'
~/vue_shared/components/toggle_button.vue
'
;
import
tooltip
from
'
~/vue_shared/directives/tooltip
'
;
import
tooltip
from
'
~/vue_shared/directives/tooltip
'
;
import
eventHub
from
'
../../event_hub
'
;
import
eventHub
from
'
../../event_hub
'
;
const
ICON_ON
=
'
notifications
'
;
const
ICON_ON
=
'
notifications
'
;
const
ICON_OFF
=
'
notifications-off
'
;
const
ICON_OFF
=
'
notifications-off
'
;
const
LABEL_ON
=
__
(
'
Notifications on
'
);
const
LABEL_ON
=
__
(
'
Notifications on
'
);
const
LABEL_OFF
=
__
(
'
Notifications off
'
);
const
LABEL_OFF
=
__
(
'
Notifications off
'
);
export
default
{
export
default
{
directives
:
{
directives
:
{
tooltip
,
tooltip
,
},
},
...
@@ -68,7 +68,7 @@
...
@@ -68,7 +68,7 @@
this
.
$emit
(
'
toggleSidebar
'
);
this
.
$emit
(
'
toggleSidebar
'
);
},
},
},
},
};
};
</
script
>
</
script
>
<
template
>
<
template
>
...
...
app/assets/javascripts/sidebar/sidebar_mediator.js
View file @
160157a9
...
@@ -39,9 +39,10 @@ export default class SidebarMediator {
...
@@ -39,9 +39,10 @@ export default class SidebarMediator {
}
}
fetch
()
{
fetch
()
{
return
this
.
service
.
get
()
return
this
.
service
.
get
()
.
then
(
response
=>
response
.
json
())
.
then
(
response
=>
response
.
json
())
.
then
(
(
data
)
=>
{
.
then
(
data
=>
{
this
.
processFetchedData
(
data
);
this
.
processFetchedData
(
data
);
})
})
.
catch
(()
=>
new
Flash
(
'
Error occurred when fetching sidebar data
'
));
.
catch
(()
=>
new
Flash
(
'
Error occurred when fetching sidebar data
'
));
...
@@ -56,30 +57,33 @@ export default class SidebarMediator {
...
@@ -56,30 +57,33 @@ export default class SidebarMediator {
toggleSubscription
()
{
toggleSubscription
()
{
this
.
store
.
setFetchingState
(
'
subscriptions
'
,
true
);
this
.
store
.
setFetchingState
(
'
subscriptions
'
,
true
);
return
this
.
service
.
toggleSubscription
()
return
this
.
service
.
toggleSubscription
()
.
then
(()
=>
{
.
then
(()
=>
{
this
.
store
.
setSubscribedState
(
!
this
.
store
.
subscribed
);
this
.
store
.
setSubscribedState
(
!
this
.
store
.
subscribed
);
this
.
store
.
setFetchingState
(
'
subscriptions
'
,
false
);
this
.
store
.
setFetchingState
(
'
subscriptions
'
,
false
);
})
})
.
catch
(
(
err
)
=>
{
.
catch
(
err
=>
{
this
.
store
.
setFetchingState
(
'
subscriptions
'
,
false
);
this
.
store
.
setFetchingState
(
'
subscriptions
'
,
false
);
throw
err
;
throw
err
;
});
});
}
}
fetchAutocompleteProjects
(
searchTerm
)
{
fetchAutocompleteProjects
(
searchTerm
)
{
return
this
.
service
.
getProjectsAutocomplete
(
searchTerm
)
return
this
.
service
.
getProjectsAutocomplete
(
searchTerm
)
.
then
(
response
=>
response
.
json
())
.
then
(
response
=>
response
.
json
())
.
then
(
(
data
)
=>
{
.
then
(
data
=>
{
this
.
store
.
setAutocompleteProjects
(
data
);
this
.
store
.
setAutocompleteProjects
(
data
);
return
this
.
store
.
autocompleteProjects
;
return
this
.
store
.
autocompleteProjects
;
});
});
}
}
moveIssue
()
{
moveIssue
()
{
return
this
.
service
.
moveIssue
(
this
.
store
.
moveToProjectId
)
return
this
.
service
.
moveIssue
(
this
.
store
.
moveToProjectId
)
.
then
(
response
=>
response
.
json
())
.
then
(
response
=>
response
.
json
())
.
then
(
(
data
)
=>
{
.
then
(
data
=>
{
if
(
window
.
location
.
pathname
!==
data
.
web_url
)
{
if
(
window
.
location
.
pathname
!==
data
.
web_url
)
{
visitUrl
(
data
.
web_url
);
visitUrl
(
data
.
web_url
);
}
}
...
...
app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue
View file @
160157a9
...
@@ -63,10 +63,15 @@ export default {
...
@@ -63,10 +63,15 @@ export default {
return
this
.
pipeline
.
commit
&&
Object
.
keys
(
this
.
pipeline
.
commit
).
length
>
0
;
return
this
.
pipeline
.
commit
&&
Object
.
keys
(
this
.
pipeline
.
commit
).
length
>
0
;
},
},
errorText
()
{
errorText
()
{
return
sprintf
(
__
(
'
Could not retrieve the pipeline status. For troubleshooting steps, read the %{linkStart}documentation.%{linkEnd}
'
),
{
return
sprintf
(
__
(
'
Could not retrieve the pipeline status. For troubleshooting steps, read the %{linkStart}documentation.%{linkEnd}
'
,
),
{
linkStart
:
`<a href="
${
this
.
troubleshootingDocsPath
}
">`
,
linkStart
:
`<a href="
${
this
.
troubleshootingDocsPath
}
">`
,
linkEnd
:
'
</a>
'
,
linkEnd
:
'
</a>
'
,
});
},
);
},
},
},
},
};
};
...
...
app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue
View file @
160157a9
...
@@ -71,7 +71,12 @@ export default {
...
@@ -71,7 +71,12 @@ export default {
return
defaultClass
;
return
defaultClass
;
},
},
iconClass
()
{
iconClass
()
{
if
(
this
.
status
===
'
failed
'
||
!
this
.
commitMessage
.
length
||
!
this
.
mr
.
isMergeAllowed
||
this
.
mr
.
preventMerge
)
{
if
(
this
.
status
===
'
failed
'
||
!
this
.
commitMessage
.
length
||
!
this
.
mr
.
isMergeAllowed
||
this
.
mr
.
preventMerge
)
{
return
'
warning
'
;
return
'
warning
'
;
}
}
return
'
success
'
;
return
'
success
'
;
...
@@ -90,10 +95,12 @@ export default {
...
@@ -90,10 +95,12 @@ export default {
},
},
isMergeButtonDisabled
()
{
isMergeButtonDisabled
()
{
const
{
commitMessage
}
=
this
;
const
{
commitMessage
}
=
this
;
return
Boolean
(
!
commitMessage
.
length
return
Boolean
(
||
!
this
.
shouldShowMergeControls
()
!
commitMessage
.
length
||
||
this
.
isMakingRequest
!
this
.
shouldShowMergeControls
()
||
||
this
.
mr
.
preventMerge
);
this
.
isMakingRequest
||
this
.
mr
.
preventMerge
,
);
},
},
isRemoveSourceBranchButtonDisabled
()
{
isRemoveSourceBranchButtonDisabled
()
{
return
this
.
isMergeButtonDisabled
;
return
this
.
isMergeButtonDisabled
;
...
@@ -140,9 +147,10 @@ export default {
...
@@ -140,9 +147,10 @@ export default {
};
};
this
.
isMakingRequest
=
true
;
this
.
isMakingRequest
=
true
;
this
.
service
.
merge
(
options
)
this
.
service
.
merge
(
options
)
.
then
(
res
=>
res
.
data
)
.
then
(
res
=>
res
.
data
)
.
then
(
(
data
)
=>
{
.
then
(
data
=>
{
const
hasError
=
data
.
status
===
'
failed
'
||
data
.
status
===
'
hook_validation_error
'
;
const
hasError
=
data
.
status
===
'
failed
'
||
data
.
status
===
'
hook_validation_error
'
;
if
(
data
.
status
===
'
merge_when_pipeline_succeeds
'
)
{
if
(
data
.
status
===
'
merge_when_pipeline_succeeds
'
)
{
...
@@ -167,9 +175,10 @@ export default {
...
@@ -167,9 +175,10 @@ export default {
});
});
},
},
handleMergePolling
(
continuePolling
,
stopPolling
)
{
handleMergePolling
(
continuePolling
,
stopPolling
)
{
this
.
service
.
poll
()
this
.
service
.
poll
()
.
then
(
res
=>
res
.
data
)
.
then
(
res
=>
res
.
data
)
.
then
(
(
data
)
=>
{
.
then
(
data
=>
{
if
(
data
.
state
===
'
merged
'
)
{
if
(
data
.
state
===
'
merged
'
)
{
// If state is merged we should update the widget and stop the polling
// If state is merged we should update the widget and stop the polling
eventHub
.
$emit
(
'
MRWidgetUpdateRequested
'
);
eventHub
.
$emit
(
'
MRWidgetUpdateRequested
'
);
...
@@ -205,9 +214,10 @@ export default {
...
@@ -205,9 +214,10 @@ export default {
});
});
},
},
handleRemoveBranchPolling
(
continuePolling
,
stopPolling
)
{
handleRemoveBranchPolling
(
continuePolling
,
stopPolling
)
{
this
.
service
.
poll
()
this
.
service
.
poll
()
.
then
(
res
=>
res
.
data
)
.
then
(
res
=>
res
.
data
)
.
then
(
(
data
)
=>
{
.
then
(
data
=>
{
// If source branch exists then we should continue polling
// If source branch exists then we should continue polling
// because removing a source branch is a background task and takes time
// because removing a source branch is a background task and takes time
if
(
data
.
source_branch_exists
)
{
if
(
data
.
source_branch_exists
)
{
...
...
app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
View file @
160157a9
...
@@ -116,7 +116,7 @@ export default {
...
@@ -116,7 +116,7 @@ export default {
// init polling
// init polling
this
.
initPostMergeDeploymentsPolling
();
this
.
initPostMergeDeploymentsPolling
();
}
}
}
}
,
},
},
created
()
{
created
()
{
this
.
initPolling
();
this
.
initPolling
();
...
@@ -213,7 +213,7 @@ export default {
...
@@ -213,7 +213,7 @@ export default {
})
})
.
catch
(()
=>
this
.
throwDeploymentsError
());
.
catch
(()
=>
this
.
throwDeploymentsError
());
},
},
fetchPostMergeDeployments
(){
fetchPostMergeDeployments
()
{
return
this
.
fetchDeployments
(
'
merge_commit
'
)
return
this
.
fetchDeployments
(
'
merge_commit
'
)
.
then
(({
data
})
=>
{
.
then
(({
data
})
=>
{
if
(
data
.
length
)
{
if
(
data
.
length
)
{
...
@@ -223,7 +223,11 @@ export default {
...
@@ -223,7 +223,11 @@ export default {
.
catch
(()
=>
this
.
throwDeploymentsError
());
.
catch
(()
=>
this
.
throwDeploymentsError
());
},
},
throwDeploymentsError
()
{
throwDeploymentsError
()
{
createFlash
(
__
(
'
Something went wrong while fetching the environments for this merge request. Please try again.
'
));
createFlash
(
__
(
'
Something went wrong while fetching the environments for this merge request. Please try again.
'
,
),
);
},
},
fetchActionsContent
()
{
fetchActionsContent
()
{
this
.
service
this
.
service
...
...
app/assets/javascripts/vue_merge_request_widget/services/mr_widget_service.js
View file @
160157a9
...
@@ -24,8 +24,8 @@ export default class MRWidgetService {
...
@@ -24,8 +24,8 @@ export default class MRWidgetService {
fetchDeployments
(
targetParam
)
{
fetchDeployments
(
targetParam
)
{
return
axios
.
get
(
this
.
endpoints
.
ciEnvironmentsStatusPath
,
{
return
axios
.
get
(
this
.
endpoints
.
ciEnvironmentsStatusPath
,
{
params
:
{
params
:
{
environment_target
:
targetParam
environment_target
:
targetParam
,
}
}
,
});
});
}
}
...
...
app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
View file @
160157a9
...
@@ -18,8 +18,7 @@ export default class MergeRequestStore {
...
@@ -18,8 +18,7 @@ export default class MergeRequestStore {
this
.
squash
=
data
.
squash
;
this
.
squash
=
data
.
squash
;
this
.
squashBeforeMergeHelpPath
=
this
.
squashBeforeMergeHelpPath
=
this
.
squashBeforeMergeHelpPath
||
data
.
squash_before_merge_help_path
;
this
.
squashBeforeMergeHelpPath
||
data
.
squash_before_merge_help_path
;
this
.
troubleshootingDocsPath
=
this
.
troubleshootingDocsPath
=
this
.
troubleshootingDocsPath
||
data
.
troubleshooting_docs_path
;
this
.
troubleshootingDocsPath
||
data
.
troubleshooting_docs_path
;
this
.
enableSquashBeforeMerge
=
this
.
enableSquashBeforeMerge
||
true
;
this
.
enableSquashBeforeMerge
=
this
.
enableSquashBeforeMerge
||
true
;
this
.
iid
=
data
.
iid
;
this
.
iid
=
data
.
iid
;
...
...
app/assets/javascripts/vue_shared/components/filtered_search_dropdown.vue
View file @
160157a9
...
@@ -56,12 +56,14 @@ export default {
...
@@ -56,12 +56,14 @@ export default {
filteredResults
()
{
filteredResults
()
{
if
(
this
.
filter
!==
''
)
{
if
(
this
.
filter
!==
''
)
{
return
this
.
items
.
filter
(
return
this
.
items
.
filter
(
item
=>
item
[
this
.
filterKey
]
&&
item
[
this
.
filterKey
].
toLowerCase
().
includes
(
this
.
filter
.
toLowerCase
()),
item
=>
item
[
this
.
filterKey
]
&&
item
[
this
.
filterKey
].
toLowerCase
().
includes
(
this
.
filter
.
toLowerCase
()),
);
);
}
}
return
this
.
items
.
slice
(
0
,
this
.
visibleItems
);
return
this
.
items
.
slice
(
0
,
this
.
visibleItems
);
}
}
,
},
},
mounted
()
{
mounted
()
{
/**
/**
...
...
app/assets/javascripts/vue_shared/components/sidebar/collapsed_calendar_icon.vue
View file @
160157a9
<
script
>
<
script
>
import
tooltip
from
'
~/vue_shared/directives/tooltip
'
;
import
tooltip
from
'
~/vue_shared/directives/tooltip
'
;
export
default
{
export
default
{
name
:
'
CollapsedCalendarIcon
'
,
name
:
'
CollapsedCalendarIcon
'
,
directives
:
{
directives
:
{
tooltip
,
tooltip
,
...
@@ -33,7 +33,7 @@
...
@@ -33,7 +33,7 @@
this
.
$emit
(
'
click
'
);
this
.
$emit
(
'
click
'
);
},
},
},
},
};
};
</
script
>
</
script
>
<
template
>
<
template
>
...
...
app/assets/javascripts/vue_shared/components/sidebar/collapsed_grouped_date_picker.vue
View file @
160157a9
<
script
>
<
script
>
import
{
__
}
from
'
~/locale
'
;
import
{
__
}
from
'
~/locale
'
;
import
timeagoMixin
from
'
~/vue_shared/mixins/timeago
'
;
import
timeagoMixin
from
'
~/vue_shared/mixins/timeago
'
;
import
{
dateInWords
,
timeFor
}
from
'
~/lib/utils/datetime_utility
'
;
import
{
dateInWords
,
timeFor
}
from
'
~/lib/utils/datetime_utility
'
;
import
collapsedCalendarIcon
from
'
./collapsed_calendar_icon.vue
'
;
import
collapsedCalendarIcon
from
'
./collapsed_calendar_icon.vue
'
;
export
default
{
export
default
{
name
:
'
SidebarCollapsedGroupedDatePicker
'
,
name
:
'
SidebarCollapsedGroupedDatePicker
'
,
components
:
{
components
:
{
collapsedCalendarIcon
,
collapsedCalendarIcon
,
},
},
mixins
:
[
mixins
:
[
timeagoMixin
],
timeagoMixin
,
],
props
:
{
props
:
{
collapsed
:
{
collapsed
:
{
type
:
Boolean
,
type
:
Boolean
,
...
@@ -67,10 +65,7 @@
...
@@ -67,10 +65,7 @@
const
defaultText
=
dateType
===
'
min
'
?
__
(
'
Start date
'
)
:
__
(
'
Due date
'
);
const
defaultText
=
dateType
===
'
min
'
?
__
(
'
Start date
'
)
:
__
(
'
Due date
'
);
const
date
=
this
[
`
${
dateType
}
Date`
];
const
date
=
this
[
`
${
dateType
}
Date`
];
const
timeAgo
=
dateType
===
'
min
'
?
this
.
timeFormated
(
date
)
:
timeFor
(
date
);
const
timeAgo
=
dateType
===
'
min
'
?
this
.
timeFormated
(
date
)
:
timeFor
(
date
);
const
dateText
=
date
?
[
const
dateText
=
date
?
[
this
.
dateText
(
dateType
),
`(
${
timeAgo
}
)`
].
join
(
'
'
)
:
''
;
this
.
dateText
(
dateType
),
`(
${
timeAgo
}
)`
,
].
join
(
'
'
)
:
''
;
if
(
date
)
{
if
(
date
)
{
return
[
defaultText
,
dateText
].
join
(
'
<br />
'
);
return
[
defaultText
,
dateText
].
join
(
'
<br />
'
);
...
@@ -78,7 +73,7 @@
...
@@ -78,7 +73,7 @@
return
__
(
'
Start and due date
'
);
return
__
(
'
Start and due date
'
);
},
},
},
},
};
};
</
script
>
</
script
>
<
template
>
<
template
>
...
...
app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_value_collapsed.vue
View file @
160157a9
...
@@ -14,7 +14,10 @@ export default {
...
@@ -14,7 +14,10 @@ export default {
},
},
computed
:
{
computed
:
{
labelsList
()
{
labelsList
()
{
const
labelsString
=
this
.
labels
.
slice
(
0
,
5
).
map
(
label
=>
label
.
title
).
join
(
'
,
'
);
const
labelsString
=
this
.
labels
.
slice
(
0
,
5
)
.
map
(
label
=>
label
.
title
)
.
join
(
'
,
'
);
if
(
this
.
labels
.
length
>
5
)
{
if
(
this
.
labels
.
length
>
5
)
{
return
sprintf
(
s__
(
'
LabelSelect|%{labelsString}, and %{remainingLabelCount} more
'
),
{
return
sprintf
(
s__
(
'
LabelSelect|%{labelsString}, and %{remainingLabelCount} more
'
),
{
...
...
spec/javascripts/boards/board_list_spec.js
View file @
160157a9
...
@@ -18,7 +18,7 @@ describe('Board list component', () => {
...
@@ -18,7 +18,7 @@ describe('Board list component', () => {
let
mock
;
let
mock
;
let
component
;
let
component
;
beforeEach
(
(
done
)
=>
{
beforeEach
(
done
=>
{
const
el
=
document
.
createElement
(
'
div
'
);
const
el
=
document
.
createElement
(
'
div
'
);
document
.
body
.
appendChild
(
el
);
document
.
body
.
appendChild
(
el
);
...
@@ -62,122 +62,102 @@ describe('Board list component', () => {
...
@@ -62,122 +62,102 @@ describe('Board list component', () => {
});
});
it
(
'
renders component
'
,
()
=>
{
it
(
'
renders component
'
,
()
=>
{
expect
(
expect
(
component
.
$el
.
classList
.
contains
(
'
board-list-component
'
)).
toBe
(
true
);
component
.
$el
.
classList
.
contains
(
'
board-list-component
'
),
).
toBe
(
true
);
});
});
it
(
'
renders loading icon
'
,
(
done
)
=>
{
it
(
'
renders loading icon
'
,
done
=>
{
component
.
loading
=
true
;
component
.
loading
=
true
;
Vue
.
nextTick
(()
=>
{
Vue
.
nextTick
(()
=>
{
expect
(
expect
(
component
.
$el
.
querySelector
(
'
.board-list-loading
'
)).
not
.
toBeNull
();
component
.
$el
.
querySelector
(
'
.board-list-loading
'
),
).
not
.
toBeNull
();
done
();
done
();
});
});
});
});
it
(
'
renders issues
'
,
()
=>
{
it
(
'
renders issues
'
,
()
=>
{
expect
(
expect
(
component
.
$el
.
querySelectorAll
(
'
.board-card
'
).
length
).
toBe
(
1
);
component
.
$el
.
querySelectorAll
(
'
.board-card
'
).
length
,
).
toBe
(
1
);
});
});
it
(
'
sets data attribute with issue id
'
,
()
=>
{
it
(
'
sets data attribute with issue id
'
,
()
=>
{
expect
(
expect
(
component
.
$el
.
querySelector
(
'
.board-card
'
).
getAttribute
(
'
data-issue-id
'
)).
toBe
(
'
1
'
);
component
.
$el
.
querySelector
(
'
.board-card
'
).
getAttribute
(
'
data-issue-id
'
),
).
toBe
(
'
1
'
);
});
});
it
(
'
shows new issue form
'
,
(
done
)
=>
{
it
(
'
shows new issue form
'
,
done
=>
{
component
.
toggleForm
();
component
.
toggleForm
();
Vue
.
nextTick
(()
=>
{
Vue
.
nextTick
(()
=>
{
expect
(
expect
(
component
.
$el
.
querySelector
(
'
.board-new-issue-form
'
)).
not
.
toBeNull
();
component
.
$el
.
querySelector
(
'
.board-new-issue-form
'
),
).
not
.
toBeNull
();
expect
(
expect
(
component
.
$el
.
querySelector
(
'
.is-smaller
'
)).
not
.
toBeNull
();
component
.
$el
.
querySelector
(
'
.is-smaller
'
),
).
not
.
toBeNull
();
done
();
done
();
});
});
});
});
it
(
'
shows new issue form after eventhub event
'
,
(
done
)
=>
{
it
(
'
shows new issue form after eventhub event
'
,
done
=>
{
eventHub
.
$emit
(
`hide-issue-form-
${
component
.
list
.
id
}
`
);
eventHub
.
$emit
(
`hide-issue-form-
${
component
.
list
.
id
}
`
);
Vue
.
nextTick
(()
=>
{
Vue
.
nextTick
(()
=>
{
expect
(
expect
(
component
.
$el
.
querySelector
(
'
.board-new-issue-form
'
)).
not
.
toBeNull
();
component
.
$el
.
querySelector
(
'
.board-new-issue-form
'
),
).
not
.
toBeNull
();
expect
(
expect
(
component
.
$el
.
querySelector
(
'
.is-smaller
'
)).
not
.
toBeNull
();
component
.
$el
.
querySelector
(
'
.is-smaller
'
),
).
not
.
toBeNull
();
done
();
done
();
});
});
});
});
it
(
'
does not show new issue form for closed list
'
,
(
done
)
=>
{
it
(
'
does not show new issue form for closed list
'
,
done
=>
{
component
.
list
.
type
=
'
closed
'
;
component
.
list
.
type
=
'
closed
'
;
component
.
toggleForm
();
component
.
toggleForm
();
Vue
.
nextTick
(()
=>
{
Vue
.
nextTick
(()
=>
{
expect
(
expect
(
component
.
$el
.
querySelector
(
'
.board-new-issue-form
'
)).
toBeNull
();
component
.
$el
.
querySelector
(
'
.board-new-issue-form
'
),
).
toBeNull
();
done
();
done
();
});
});
});
});
it
(
'
shows count list item
'
,
(
done
)
=>
{
it
(
'
shows count list item
'
,
done
=>
{
component
.
showCount
=
true
;
component
.
showCount
=
true
;
Vue
.
nextTick
(()
=>
{
Vue
.
nextTick
(()
=>
{
expect
(
expect
(
component
.
$el
.
querySelector
(
'
.board-list-count
'
)).
not
.
toBeNull
();
component
.
$el
.
querySelector
(
'
.board-list-count
'
),
).
not
.
toBeNull
();
expect
(
expect
(
component
.
$el
.
querySelector
(
'
.board-list-count
'
).
textContent
.
trim
()).
toBe
(
component
.
$el
.
querySelector
(
'
.board-list-count
'
).
textContent
.
trim
()
,
'
Showing all issues
'
,
)
.
toBe
(
'
Showing all issues
'
)
;
);
done
();
done
();
});
});
});
});
it
(
'
sets data attribute with invalid id
'
,
(
done
)
=>
{
it
(
'
sets data attribute with invalid id
'
,
done
=>
{
component
.
showCount
=
true
;
component
.
showCount
=
true
;
Vue
.
nextTick
(()
=>
{
Vue
.
nextTick
(()
=>
{
expect
(
expect
(
component
.
$el
.
querySelector
(
'
.board-list-count
'
).
getAttribute
(
'
data-issue-id
'
)).
toBe
(
component
.
$el
.
querySelector
(
'
.board-list-count
'
).
getAttribute
(
'
data-issue-id
'
)
,
'
-1
'
,
)
.
toBe
(
'
-1
'
)
;
);
done
();
done
();
});
});
});
});
it
(
'
shows how many more issues to load
'
,
(
done
)
=>
{
it
(
'
shows how many more issues to load
'
,
done
=>
{
component
.
showCount
=
true
;
component
.
showCount
=
true
;
component
.
list
.
issuesSize
=
20
;
component
.
list
.
issuesSize
=
20
;
Vue
.
nextTick
(()
=>
{
Vue
.
nextTick
(()
=>
{
expect
(
expect
(
component
.
$el
.
querySelector
(
'
.board-list-count
'
).
textContent
.
trim
()).
toBe
(
component
.
$el
.
querySelector
(
'
.board-list-count
'
).
textContent
.
trim
()
,
'
Showing 1 of 20 issues
'
,
)
.
toBe
(
'
Showing 1 of 20 issues
'
)
;
);
done
();
done
();
});
});
});
});
it
(
'
loads more issues after scrolling
'
,
(
done
)
=>
{
it
(
'
loads more issues after scrolling
'
,
done
=>
{
spyOn
(
component
.
list
,
'
nextPage
'
);
spyOn
(
component
.
list
,
'
nextPage
'
);
component
.
$refs
.
list
.
style
.
height
=
'
100px
'
;
component
.
$refs
.
list
.
style
.
height
=
'
100px
'
;
component
.
$refs
.
list
.
style
.
overflow
=
'
scroll
'
;
component
.
$refs
.
list
.
style
.
overflow
=
'
scroll
'
;
...
@@ -200,7 +180,9 @@ describe('Board list component', () => {
...
@@ -200,7 +180,9 @@ describe('Board list component', () => {
});
});
it
(
'
does not load issues if already loading
'
,
()
=>
{
it
(
'
does not load issues if already loading
'
,
()
=>
{
component
.
list
.
nextPage
=
spyOn
(
component
.
list
,
'
nextPage
'
).
and
.
returnValue
(
new
Promise
(()
=>
{}));
component
.
list
.
nextPage
=
spyOn
(
component
.
list
,
'
nextPage
'
).
and
.
returnValue
(
new
Promise
(()
=>
{}),
);
component
.
onScroll
();
component
.
onScroll
();
component
.
onScroll
();
component
.
onScroll
();
...
@@ -208,14 +190,12 @@ describe('Board list component', () => {
...
@@ -208,14 +190,12 @@ describe('Board list component', () => {
expect
(
component
.
list
.
nextPage
).
toHaveBeenCalledTimes
(
1
);
expect
(
component
.
list
.
nextPage
).
toHaveBeenCalledTimes
(
1
);
});
});
it
(
'
shows loading more spinner
'
,
(
done
)
=>
{
it
(
'
shows loading more spinner
'
,
done
=>
{
component
.
showCount
=
true
;
component
.
showCount
=
true
;
component
.
list
.
loadingMore
=
true
;
component
.
list
.
loadingMore
=
true
;
Vue
.
nextTick
(()
=>
{
Vue
.
nextTick
(()
=>
{
expect
(
expect
(
component
.
$el
.
querySelector
(
'
.board-list-count .fa-spinner
'
)).
not
.
toBeNull
();
component
.
$el
.
querySelector
(
'
.board-list-count .fa-spinner
'
),
).
not
.
toBeNull
();
done
();
done
();
});
});
...
...
spec/javascripts/boards/components/board_spec.js
View file @
160157a9
...
@@ -8,7 +8,7 @@ describe('Board component', () => {
...
@@ -8,7 +8,7 @@ describe('Board component', () => {
let
vm
;
let
vm
;
let
el
;
let
el
;
beforeEach
(
(
done
)
=>
{
beforeEach
(
done
=>
{
loadFixtures
(
'
boards/show.html.raw
'
);
loadFixtures
(
'
boards/show.html.raw
'
);
el
=
document
.
createElement
(
'
div
'
);
el
=
document
.
createElement
(
'
div
'
);
...
@@ -50,56 +50,46 @@ describe('Board component', () => {
...
@@ -50,56 +50,46 @@ describe('Board component', () => {
});
});
it
(
'
board is expandable when list type is backlog
'
,
()
=>
{
it
(
'
board is expandable when list type is backlog
'
,
()
=>
{
expect
(
expect
(
vm
.
$el
.
classList
.
contains
(
'
is-expandable
'
)).
toBe
(
true
);
vm
.
$el
.
classList
.
contains
(
'
is-expandable
'
),
).
toBe
(
true
);
});
});
it
(
'
board is expandable when list type is closed
'
,
(
done
)
=>
{
it
(
'
board is expandable when list type is closed
'
,
done
=>
{
vm
.
list
.
type
=
'
closed
'
;
vm
.
list
.
type
=
'
closed
'
;
Vue
.
nextTick
(()
=>
{
Vue
.
nextTick
(()
=>
{
expect
(
expect
(
vm
.
$el
.
classList
.
contains
(
'
is-expandable
'
)).
toBe
(
true
);
vm
.
$el
.
classList
.
contains
(
'
is-expandable
'
),
).
toBe
(
true
);
done
();
done
();
});
});
});
});
it
(
'
board is not expandable when list type is label
'
,
(
done
)
=>
{
it
(
'
board is not expandable when list type is label
'
,
done
=>
{
vm
.
list
.
type
=
'
label
'
;
vm
.
list
.
type
=
'
label
'
;
vm
.
list
.
isExpandable
=
false
;
vm
.
list
.
isExpandable
=
false
;
Vue
.
nextTick
(()
=>
{
Vue
.
nextTick
(()
=>
{
expect
(
expect
(
vm
.
$el
.
classList
.
contains
(
'
is-expandable
'
)).
toBe
(
false
);
vm
.
$el
.
classList
.
contains
(
'
is-expandable
'
),
).
toBe
(
false
);
done
();
done
();
});
});
});
});
it
(
'
collapses when clicking header
'
,
(
done
)
=>
{
it
(
'
collapses when clicking header
'
,
done
=>
{
vm
.
$el
.
querySelector
(
'
.board-header
'
).
click
();
vm
.
$el
.
querySelector
(
'
.board-header
'
).
click
();
Vue
.
nextTick
(()
=>
{
Vue
.
nextTick
(()
=>
{
expect
(
expect
(
vm
.
$el
.
classList
.
contains
(
'
is-collapsed
'
)).
toBe
(
true
);
vm
.
$el
.
classList
.
contains
(
'
is-collapsed
'
),
).
toBe
(
true
);
done
();
done
();
});
});
});
});
it
(
'
created sets isExpanded to true from localStorage
'
,
(
done
)
=>
{
it
(
'
created sets isExpanded to true from localStorage
'
,
done
=>
{
vm
.
$el
.
querySelector
(
'
.board-header
'
).
click
();
vm
.
$el
.
querySelector
(
'
.board-header
'
).
click
();
return
Vue
.
nextTick
()
return
Vue
.
nextTick
()
.
then
(()
=>
{
.
then
(()
=>
{
expect
(
expect
(
vm
.
$el
.
classList
.
contains
(
'
is-collapsed
'
)).
toBe
(
true
);
vm
.
$el
.
classList
.
contains
(
'
is-collapsed
'
),
).
toBe
(
true
);
// call created manually
// call created manually
vm
.
$options
.
created
[
0
].
call
(
vm
);
vm
.
$options
.
created
[
0
].
call
(
vm
);
...
@@ -107,11 +97,10 @@ describe('Board component', () => {
...
@@ -107,11 +97,10 @@ describe('Board component', () => {
return
Vue
.
nextTick
();
return
Vue
.
nextTick
();
})
})
.
then
(()
=>
{
.
then
(()
=>
{
expect
(
expect
(
vm
.
$el
.
classList
.
contains
(
'
is-collapsed
'
)).
toBe
(
true
);
vm
.
$el
.
classList
.
contains
(
'
is-collapsed
'
),
).
toBe
(
true
);
done
();
done
();
}).
catch
(
done
.
fail
);
})
.
catch
(
done
.
fail
);
});
});
});
});
spec/javascripts/environments/emtpy_state_spec.js
View file @
160157a9
import
Vue
from
'
vue
'
;
import
Vue
from
'
vue
'
;
import
emptyState
from
'
~/environments/components/empty_state.vue
'
;
import
emptyState
from
'
~/environments/components/empty_state.vue
'
;
import
mountComponent
from
'
spec/helpers/vue_mount_component_helper
'
;
import
mountComponent
from
'
spec/helpers/vue_mount_component_helper
'
;
...
@@ -25,13 +24,13 @@ describe('environments empty state', () => {
...
@@ -25,13 +24,13 @@ describe('environments empty state', () => {
});
});
it
(
'
renders empty state and new environment button
'
,
()
=>
{
it
(
'
renders empty state and new environment button
'
,
()
=>
{
expect
(
expect
(
vm
.
$el
.
querySelector
(
'
.js-blank-state-title
'
).
textContent
.
trim
()).
toEqual
(
vm
.
$el
.
querySelector
(
'
.js-blank-state-title
'
).
textContent
.
trim
()
,
"
You don't have any environments right now
"
,
)
.
toEqual
(
'
You don
\'
t have any environments right now
'
)
;
);
expect
(
expect
(
vm
.
$el
.
querySelector
(
'
.js-new-environment-button
'
).
getAttribute
(
'
href
'
)).
toEqual
(
vm
.
$el
.
querySelector
(
'
.js-new-environment-button
'
).
getAttribute
(
'
href
'
)
,
'
foo
'
,
)
.
toEqual
(
'
foo
'
)
;
);
});
});
});
});
...
@@ -45,13 +44,11 @@ describe('environments empty state', () => {
...
@@ -45,13 +44,11 @@ describe('environments empty state', () => {
});
});
it
(
'
renders empty state without new button
'
,
()
=>
{
it
(
'
renders empty state without new button
'
,
()
=>
{
expect
(
expect
(
vm
.
$el
.
querySelector
(
'
.js-blank-state-title
'
).
textContent
.
trim
()).
toEqual
(
vm
.
$el
.
querySelector
(
'
.js-blank-state-title
'
).
textContent
.
trim
()
,
"
You don't have any environments right now
"
,
)
.
toEqual
(
'
You don
\'
t have any environments right now
'
)
;
);
expect
(
expect
(
vm
.
$el
.
querySelector
(
'
.js-new-environment-button
'
)).
toBeNull
();
vm
.
$el
.
querySelector
(
'
.js-new-environment-button
'
),
).
toBeNull
();
});
});
});
});
});
});
spec/javascripts/environments/environment_item_spec.js
View file @
160157a9
...
@@ -38,7 +38,9 @@ describe('Environment item', () => {
...
@@ -38,7 +38,9 @@ describe('Environment item', () => {
});
});
it
(
'
Should render the number of children in a badge
'
,
()
=>
{
it
(
'
Should render the number of children in a badge
'
,
()
=>
{
expect
(
component
.
$el
.
querySelector
(
'
.folder-name .badge
'
).
textContent
).
toContain
(
mockItem
.
size
);
expect
(
component
.
$el
.
querySelector
(
'
.folder-name .badge
'
).
textContent
).
toContain
(
mockItem
.
size
,
);
});
});
});
});
...
@@ -68,7 +70,8 @@ describe('Environment item', () => {
...
@@ -68,7 +70,8 @@ describe('Environment item', () => {
username
:
'
root
'
,
username
:
'
root
'
,
id
:
1
,
id
:
1
,
state
:
'
active
'
,
state
:
'
active
'
,
avatar_url
:
'
https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80
\
u0026d=identicon
'
,
avatar_url
:
'
https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80
\
u0026d=identicon
'
,
web_url
:
'
http://localhost:3000/root
'
,
web_url
:
'
http://localhost:3000/root
'
,
},
},
commit
:
{
commit
:
{
...
@@ -84,7 +87,8 @@ describe('Environment item', () => {
...
@@ -84,7 +87,8 @@ describe('Environment item', () => {
username
:
'
root
'
,
username
:
'
root
'
,
id
:
1
,
id
:
1
,
state
:
'
active
'
,
state
:
'
active
'
,
avatar_url
:
'
https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80
\
u0026d=identicon
'
,
avatar_url
:
'
https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80
\
u0026d=identicon
'
,
web_url
:
'
http://localhost:3000/root
'
,
web_url
:
'
http://localhost:3000/root
'
,
},
},
commit_path
:
'
/root/ci-folders/tree/500aabcb17c97bdcf2d0c410b70cb8556f0362dd
'
,
commit_path
:
'
/root/ci-folders/tree/500aabcb17c97bdcf2d0c410b70cb8556f0362dd
'
,
...
@@ -121,18 +125,18 @@ describe('Environment item', () => {
...
@@ -121,18 +125,18 @@ describe('Environment item', () => {
});
});
it
(
'
should render environment name
'
,
()
=>
{
it
(
'
should render environment name
'
,
()
=>
{
expect
(
component
.
$el
.
querySelector
(
'
.environment-name
'
).
textContent
).
toContain
(
environment
.
name
);
expect
(
component
.
$el
.
querySelector
(
'
.environment-name
'
).
textContent
).
toContain
(
environment
.
name
,
);
});
});
describe
(
'
With deployment
'
,
()
=>
{
describe
(
'
With deployment
'
,
()
=>
{
it
(
'
should render deployment internal id
'
,
()
=>
{
it
(
'
should render deployment internal id
'
,
()
=>
{
expect
(
expect
(
component
.
$el
.
querySelector
(
'
.deployment-column span
'
).
textContent
).
toContain
(
component
.
$el
.
querySelector
(
'
.deployment-column span
'
).
textContent
,
environment
.
last_deployment
.
iid
,
)
.
toContain
(
environment
.
last_deployment
.
iid
)
;
);
expect
(
expect
(
component
.
$el
.
querySelector
(
'
.deployment-column span
'
).
textContent
).
toContain
(
'
#
'
);
component
.
$el
.
querySelector
(
'
.deployment-column span
'
).
textContent
,
).
toContain
(
'
#
'
);
});
});
it
(
'
should render last deployment date
'
,
()
=>
{
it
(
'
should render last deployment date
'
,
()
=>
{
...
@@ -156,56 +160,46 @@ describe('Environment item', () => {
...
@@ -156,56 +160,46 @@ describe('Environment item', () => {
describe
(
'
With build url
'
,
()
=>
{
describe
(
'
With build url
'
,
()
=>
{
it
(
'
Should link to build url provided
'
,
()
=>
{
it
(
'
Should link to build url provided
'
,
()
=>
{
expect
(
expect
(
component
.
$el
.
querySelector
(
'
.build-link
'
).
getAttribute
(
'
href
'
)).
toEqual
(
component
.
$el
.
querySelector
(
'
.build-link
'
).
getAttribute
(
'
href
'
)
,
environment
.
last_deployment
.
deployable
.
build_path
,
)
.
toEqual
(
environment
.
last_deployment
.
deployable
.
build_path
)
;
);
});
});
it
(
'
Should render deployable name and id
'
,
()
=>
{
it
(
'
Should render deployable name and id
'
,
()
=>
{
expect
(
expect
(
component
.
$el
.
querySelector
(
'
.build-link
'
).
getAttribute
(
'
href
'
)).
toEqual
(
component
.
$el
.
querySelector
(
'
.build-link
'
).
getAttribute
(
'
href
'
)
,
environment
.
last_deployment
.
deployable
.
build_path
,
)
.
toEqual
(
environment
.
last_deployment
.
deployable
.
build_path
)
;
);
});
});
});
});
describe
(
'
With commit information
'
,
()
=>
{
describe
(
'
With commit information
'
,
()
=>
{
it
(
'
should render commit component
'
,
()
=>
{
it
(
'
should render commit component
'
,
()
=>
{
expect
(
expect
(
component
.
$el
.
querySelector
(
'
.js-commit-component
'
)).
toBeDefined
();
component
.
$el
.
querySelector
(
'
.js-commit-component
'
),
).
toBeDefined
();
});
});
});
});
});
});
describe
(
'
With manual actions
'
,
()
=>
{
describe
(
'
With manual actions
'
,
()
=>
{
it
(
'
Should render actions component
'
,
()
=>
{
it
(
'
Should render actions component
'
,
()
=>
{
expect
(
expect
(
component
.
$el
.
querySelector
(
'
.js-manual-actions-container
'
)).
toBeDefined
();
component
.
$el
.
querySelector
(
'
.js-manual-actions-container
'
),
).
toBeDefined
();
});
});
});
});
describe
(
'
With external URL
'
,
()
=>
{
describe
(
'
With external URL
'
,
()
=>
{
it
(
'
should render external url component
'
,
()
=>
{
it
(
'
should render external url component
'
,
()
=>
{
expect
(
expect
(
component
.
$el
.
querySelector
(
'
.js-external-url-container
'
)).
toBeDefined
();
component
.
$el
.
querySelector
(
'
.js-external-url-container
'
),
).
toBeDefined
();
});
});
});
});
describe
(
'
With stop action
'
,
()
=>
{
describe
(
'
With stop action
'
,
()
=>
{
it
(
'
Should render stop action component
'
,
()
=>
{
it
(
'
Should render stop action component
'
,
()
=>
{
expect
(
expect
(
component
.
$el
.
querySelector
(
'
.js-stop-component-container
'
)).
toBeDefined
();
component
.
$el
.
querySelector
(
'
.js-stop-component-container
'
),
).
toBeDefined
();
});
});
});
});
describe
(
'
With retry action
'
,
()
=>
{
describe
(
'
With retry action
'
,
()
=>
{
it
(
'
Should render rollback component
'
,
()
=>
{
it
(
'
Should render rollback component
'
,
()
=>
{
expect
(
expect
(
component
.
$el
.
querySelector
(
'
.js-rollback-component-container
'
)).
toBeDefined
();
component
.
$el
.
querySelector
(
'
.js-rollback-component-container
'
),
).
toBeDefined
();
});
});
});
});
});
});
...
...
spec/javascripts/environments/environments_app_spec.js
View file @
160157a9
...
@@ -33,7 +33,7 @@ describe('Environment', () => {
...
@@ -33,7 +33,7 @@ describe('Environment', () => {
describe
(
'
successfull request
'
,
()
=>
{
describe
(
'
successfull request
'
,
()
=>
{
describe
(
'
without environments
'
,
()
=>
{
describe
(
'
without environments
'
,
()
=>
{
beforeEach
(
(
done
)
=>
{
beforeEach
(
done
=>
{
mock
.
onGet
(
mockData
.
endpoint
).
reply
(
200
,
{
environments
:
[]
});
mock
.
onGet
(
mockData
.
endpoint
).
reply
(
200
,
{
environments
:
[]
});
component
=
mountComponent
(
EnvironmentsComponent
,
mockData
);
component
=
mountComponent
(
EnvironmentsComponent
,
mockData
);
...
@@ -44,30 +44,34 @@ describe('Environment', () => {
...
@@ -44,30 +44,34 @@ describe('Environment', () => {
});
});
it
(
'
should render the empty state
'
,
()
=>
{
it
(
'
should render the empty state
'
,
()
=>
{
expect
(
expect
(
component
.
$el
.
querySelector
(
'
.js-new-environment-button
'
).
textContent
).
toContain
(
component
.
$el
.
querySelector
(
'
.js-new-environment-button
'
).
textContent
,
'
New environment
'
,
)
.
toContain
(
'
New environment
'
)
;
);
expect
(
expect
(
component
.
$el
.
querySelector
(
'
.js-blank-state-title
'
).
textContent
).
toContain
(
component
.
$el
.
querySelector
(
'
.js-blank-state-title
'
).
textContent
,
"
You don't have any environments right now
"
,
)
.
toContain
(
'
You don
\'
t have any environments right now
'
)
;
);
});
});
});
});
describe
(
'
with paginated environments
'
,
()
=>
{
describe
(
'
with paginated environments
'
,
()
=>
{
beforeEach
((
done
)
=>
{
beforeEach
(
done
=>
{
mock
.
onGet
(
mockData
.
endpoint
).
reply
(
200
,
{
mock
.
onGet
(
mockData
.
endpoint
).
reply
(
200
,
{
environments
:
[
environment
],
environments
:
[
environment
],
stopped_count
:
1
,
stopped_count
:
1
,
available_count
:
0
,
available_count
:
0
,
},
{
},
{
'
X-nExt-pAge
'
:
'
2
'
,
'
X-nExt-pAge
'
:
'
2
'
,
'
x-page
'
:
'
1
'
,
'
x-page
'
:
'
1
'
,
'
X-Per-Page
'
:
'
1
'
,
'
X-Per-Page
'
:
'
1
'
,
'
X-Prev-Page
'
:
''
,
'
X-Prev-Page
'
:
''
,
'
X-TOTAL
'
:
'
37
'
,
'
X-TOTAL
'
:
'
37
'
,
'
X-Total-Pages
'
:
'
2
'
,
'
X-Total-Pages
'
:
'
2
'
,
});
},
);
component
=
mountComponent
(
EnvironmentsComponent
,
mockData
);
component
=
mountComponent
(
EnvironmentsComponent
,
mockData
);
...
@@ -78,19 +82,17 @@ describe('Environment', () => {
...
@@ -78,19 +82,17 @@ describe('Environment', () => {
it
(
'
should render a table with environments
'
,
()
=>
{
it
(
'
should render a table with environments
'
,
()
=>
{
expect
(
component
.
$el
.
querySelectorAll
(
'
table
'
)).
not
.
toBeNull
();
expect
(
component
.
$el
.
querySelectorAll
(
'
table
'
)).
not
.
toBeNull
();
expect
(
expect
(
component
.
$el
.
querySelector
(
'
.environment-name
'
).
textContent
.
trim
()).
toEqual
(
component
.
$el
.
querySelector
(
'
.environment-name
'
).
textContent
.
trim
()
,
environment
.
name
,
)
.
toEqual
(
environment
.
name
)
;
);
});
});
describe
(
'
pagination
'
,
()
=>
{
describe
(
'
pagination
'
,
()
=>
{
it
(
'
should render pagination
'
,
()
=>
{
it
(
'
should render pagination
'
,
()
=>
{
expect
(
expect
(
component
.
$el
.
querySelectorAll
(
'
.gl-pagination li
'
).
length
).
toEqual
(
5
);
component
.
$el
.
querySelectorAll
(
'
.gl-pagination li
'
).
length
,
).
toEqual
(
5
);
});
});
it
(
'
should make an API request when page is clicked
'
,
(
done
)
=>
{
it
(
'
should make an API request when page is clicked
'
,
done
=>
{
spyOn
(
component
,
'
updateContent
'
);
spyOn
(
component
,
'
updateContent
'
);
setTimeout
(()
=>
{
setTimeout
(()
=>
{
component
.
$el
.
querySelector
(
'
.gl-pagination li:nth-child(5) a
'
).
click
();
component
.
$el
.
querySelector
(
'
.gl-pagination li:nth-child(5) a
'
).
click
();
...
@@ -100,7 +102,7 @@ describe('Environment', () => {
...
@@ -100,7 +102,7 @@ describe('Environment', () => {
},
0
);
},
0
);
});
});
it
(
'
should make an API request when using tabs
'
,
(
done
)
=>
{
it
(
'
should make an API request when using tabs
'
,
done
=>
{
setTimeout
(()
=>
{
setTimeout
(()
=>
{
spyOn
(
component
,
'
updateContent
'
);
spyOn
(
component
,
'
updateContent
'
);
component
.
$el
.
querySelector
(
'
.js-environments-tab-stopped
'
).
click
();
component
.
$el
.
querySelector
(
'
.js-environments-tab-stopped
'
).
click
();
...
@@ -114,7 +116,7 @@ describe('Environment', () => {
...
@@ -114,7 +116,7 @@ describe('Environment', () => {
});
});
describe
(
'
unsuccessfull request
'
,
()
=>
{
describe
(
'
unsuccessfull request
'
,
()
=>
{
beforeEach
(
(
done
)
=>
{
beforeEach
(
done
=>
{
mock
.
onGet
(
mockData
.
endpoint
).
reply
(
500
,
{});
mock
.
onGet
(
mockData
.
endpoint
).
reply
(
500
,
{});
component
=
mountComponent
(
EnvironmentsComponent
,
mockData
);
component
=
mountComponent
(
EnvironmentsComponent
,
mockData
);
...
@@ -125,15 +127,16 @@ describe('Environment', () => {
...
@@ -125,15 +127,16 @@ describe('Environment', () => {
});
});
it
(
'
should render empty state
'
,
()
=>
{
it
(
'
should render empty state
'
,
()
=>
{
expect
(
expect
(
component
.
$el
.
querySelector
(
'
.js-blank-state-title
'
).
textContent
).
toContain
(
component
.
$el
.
querySelector
(
'
.js-blank-state-title
'
).
textContent
,
"
You don't have any environments right now
"
,
)
.
toContain
(
'
You don
\'
t have any environments right now
'
)
;
);
});
});
});
});
describe
(
'
expandable folders
'
,
()
=>
{
describe
(
'
expandable folders
'
,
()
=>
{
beforeEach
(()
=>
{
beforeEach
(()
=>
{
mock
.
onGet
(
mockData
.
endpoint
).
reply
(
200
,
mock
.
onGet
(
mockData
.
endpoint
).
reply
(
200
,
{
{
environments
:
[
folder
],
environments
:
[
folder
],
stopped_count
:
0
,
stopped_count
:
0
,
...
@@ -154,7 +157,7 @@ describe('Environment', () => {
...
@@ -154,7 +157,7 @@ describe('Environment', () => {
component
=
mountComponent
(
EnvironmentsComponent
,
mockData
);
component
=
mountComponent
(
EnvironmentsComponent
,
mockData
);
});
});
it
(
'
should open a closed folder
'
,
(
done
)
=>
{
it
(
'
should open a closed folder
'
,
done
=>
{
setTimeout
(()
=>
{
setTimeout
(()
=>
{
component
.
$el
.
querySelector
(
'
.folder-name
'
).
click
();
component
.
$el
.
querySelector
(
'
.folder-name
'
).
click
();
...
@@ -165,7 +168,7 @@ describe('Environment', () => {
...
@@ -165,7 +168,7 @@ describe('Environment', () => {
},
0
);
},
0
);
});
});
it
(
'
should close an opened folder
'
,
(
done
)
=>
{
it
(
'
should close an opened folder
'
,
done
=>
{
setTimeout
(()
=>
{
setTimeout
(()
=>
{
// open folder
// open folder
component
.
$el
.
querySelector
(
'
.folder-name
'
).
click
();
component
.
$el
.
querySelector
(
'
.folder-name
'
).
click
();
...
@@ -182,7 +185,7 @@ describe('Environment', () => {
...
@@ -182,7 +185,7 @@ describe('Environment', () => {
},
0
);
},
0
);
});
});
it
(
'
should show children environments and a button to show all environments
'
,
(
done
)
=>
{
it
(
'
should show children environments and a button to show all environments
'
,
done
=>
{
setTimeout
(()
=>
{
setTimeout
(()
=>
{
// open folder
// open folder
component
.
$el
.
querySelector
(
'
.folder-name
'
).
click
();
component
.
$el
.
querySelector
(
'
.folder-name
'
).
click
();
...
@@ -191,7 +194,9 @@ describe('Environment', () => {
...
@@ -191,7 +194,9 @@ describe('Environment', () => {
// wait for next async request
// wait for next async request
setTimeout
(()
=>
{
setTimeout
(()
=>
{
expect
(
component
.
$el
.
querySelectorAll
(
'
.js-child-row
'
).
length
).
toEqual
(
1
);
expect
(
component
.
$el
.
querySelectorAll
(
'
.js-child-row
'
).
length
).
toEqual
(
1
);
expect
(
component
.
$el
.
querySelector
(
'
.text-center > a.btn
'
).
textContent
).
toContain
(
'
Show all
'
);
expect
(
component
.
$el
.
querySelector
(
'
.text-center > a.btn
'
).
textContent
).
toContain
(
'
Show all
'
,
);
done
();
done
();
});
});
});
});
...
@@ -201,7 +206,8 @@ describe('Environment', () => {
...
@@ -201,7 +206,8 @@ describe('Environment', () => {
describe
(
'
methods
'
,
()
=>
{
describe
(
'
methods
'
,
()
=>
{
beforeEach
(()
=>
{
beforeEach
(()
=>
{
mock
.
onGet
(
mockData
.
endpoint
).
reply
(
200
,
mock
.
onGet
(
mockData
.
endpoint
).
reply
(
200
,
{
{
environments
:
[],
environments
:
[],
stopped_count
:
0
,
stopped_count
:
0
,
...
@@ -215,8 +221,9 @@ describe('Environment', () => {
...
@@ -215,8 +221,9 @@ describe('Environment', () => {
});
});
describe
(
'
updateContent
'
,
()
=>
{
describe
(
'
updateContent
'
,
()
=>
{
it
(
'
should set given parameters
'
,
(
done
)
=>
{
it
(
'
should set given parameters
'
,
done
=>
{
component
.
updateContent
({
scope
:
'
stopped
'
,
page
:
'
3
'
})
component
.
updateContent
({
scope
:
'
stopped
'
,
page
:
'
3
'
})
.
then
(()
=>
{
.
then
(()
=>
{
expect
(
component
.
page
).
toEqual
(
'
3
'
);
expect
(
component
.
page
).
toEqual
(
'
3
'
);
expect
(
component
.
scope
).
toEqual
(
'
stopped
'
);
expect
(
component
.
scope
).
toEqual
(
'
stopped
'
);
...
...
spec/javascripts/environments/folder/environments_folder_view_spec.js
View file @
160157a9
...
@@ -32,37 +32,41 @@ describe('Environments Folder View', () => {
...
@@ -32,37 +32,41 @@ describe('Environments Folder View', () => {
describe
(
'
successfull request
'
,
()
=>
{
describe
(
'
successfull request
'
,
()
=>
{
beforeEach
(()
=>
{
beforeEach
(()
=>
{
mock
.
onGet
(
mockData
.
endpoint
).
reply
(
200
,
{
mock
.
onGet
(
mockData
.
endpoint
).
reply
(
200
,
{
environments
:
environmentsList
,
environments
:
environmentsList
,
stopped_count
:
1
,
stopped_count
:
1
,
available_count
:
0
,
available_count
:
0
,
},
{
},
{
'
X-nExt-pAge
'
:
'
2
'
,
'
X-nExt-pAge
'
:
'
2
'
,
'
x-page
'
:
'
1
'
,
'
x-page
'
:
'
1
'
,
'
X-Per-Page
'
:
'
2
'
,
'
X-Per-Page
'
:
'
2
'
,
'
X-Prev-Page
'
:
''
,
'
X-Prev-Page
'
:
''
,
'
X-TOTAL
'
:
'
20
'
,
'
X-TOTAL
'
:
'
20
'
,
'
X-Total-Pages
'
:
'
10
'
,
'
X-Total-Pages
'
:
'
10
'
,
});
},
);
component
=
mountComponent
(
Component
,
mockData
);
component
=
mountComponent
(
Component
,
mockData
);
});
});
it
(
'
should render a table with environments
'
,
(
done
)
=>
{
it
(
'
should render a table with environments
'
,
done
=>
{
setTimeout
(()
=>
{
setTimeout
(()
=>
{
expect
(
component
.
$el
.
querySelectorAll
(
'
table
'
)).
not
.
toBeNull
();
expect
(
component
.
$el
.
querySelectorAll
(
'
table
'
)).
not
.
toBeNull
();
expect
(
expect
(
component
.
$el
.
querySelector
(
'
.environment-name
'
).
textContent
.
trim
()).
toEqual
(
component
.
$el
.
querySelector
(
'
.environment-name
'
).
textContent
.
trim
()
,
environmentsList
[
0
].
name
,
)
.
toEqual
(
environmentsList
[
0
].
name
)
;
);
done
();
done
();
},
0
);
},
0
);
});
});
it
(
'
should render available tab with count
'
,
(
done
)
=>
{
it
(
'
should render available tab with count
'
,
done
=>
{
setTimeout
(()
=>
{
setTimeout
(()
=>
{
expect
(
expect
(
component
.
$el
.
querySelector
(
'
.js-environments-tab-available
'
).
textContent
).
toContain
(
component
.
$el
.
querySelector
(
'
.js-environments-tab-available
'
).
textContent
,
'
Available
'
,
)
.
toContain
(
'
Available
'
)
;
);
expect
(
expect
(
component
.
$el
.
querySelector
(
'
.js-environments-tab-available .badge
'
).
textContent
,
component
.
$el
.
querySelector
(
'
.js-environments-tab-available .badge
'
).
textContent
,
...
@@ -71,11 +75,11 @@ describe('Environments Folder View', () => {
...
@@ -71,11 +75,11 @@ describe('Environments Folder View', () => {
},
0
);
},
0
);
});
});
it
(
'
should render stopped tab with count
'
,
(
done
)
=>
{
it
(
'
should render stopped tab with count
'
,
done
=>
{
setTimeout
(()
=>
{
setTimeout
(()
=>
{
expect
(
expect
(
component
.
$el
.
querySelector
(
'
.js-environments-tab-stopped
'
).
textContent
).
toContain
(
component
.
$el
.
querySelector
(
'
.js-environments-tab-stopped
'
).
textContent
,
'
Stopped
'
,
)
.
toContain
(
'
Stopped
'
)
;
);
expect
(
expect
(
component
.
$el
.
querySelector
(
'
.js-environments-tab-stopped .badge
'
).
textContent
,
component
.
$el
.
querySelector
(
'
.js-environments-tab-stopped .badge
'
).
textContent
,
...
@@ -84,36 +88,37 @@ describe('Environments Folder View', () => {
...
@@ -84,36 +88,37 @@ describe('Environments Folder View', () => {
},
0
);
},
0
);
});
});
it
(
'
should render parent folder name
'
,
(
done
)
=>
{
it
(
'
should render parent folder name
'
,
done
=>
{
setTimeout
(()
=>
{
setTimeout
(()
=>
{
expect
(
expect
(
component
.
$el
.
querySelector
(
'
.js-folder-name
'
).
textContent
.
trim
()).
toContain
(
component
.
$el
.
querySelector
(
'
.js-folder-name
'
).
textContent
.
trim
()
,
'
Environments / review
'
,
)
.
toContain
(
'
Environments / review
'
)
;
);
done
();
done
();
},
0
);
},
0
);
});
});
describe
(
'
pagination
'
,
()
=>
{
describe
(
'
pagination
'
,
()
=>
{
it
(
'
should render pagination
'
,
(
done
)
=>
{
it
(
'
should render pagination
'
,
done
=>
{
setTimeout
(()
=>
{
setTimeout
(()
=>
{
expect
(
expect
(
component
.
$el
.
querySelectorAll
(
'
.gl-pagination
'
)).
not
.
toBeNull
();
component
.
$el
.
querySelectorAll
(
'
.gl-pagination
'
),
).
not
.
toBeNull
();
done
();
done
();
},
0
);
},
0
);
});
});
it
(
'
should make an API request when changing page
'
,
(
done
)
=>
{
it
(
'
should make an API request when changing page
'
,
done
=>
{
spyOn
(
component
,
'
updateContent
'
);
spyOn
(
component
,
'
updateContent
'
);
setTimeout
(()
=>
{
setTimeout
(()
=>
{
component
.
$el
.
querySelector
(
'
.gl-pagination .js-last-button a
'
).
click
();
component
.
$el
.
querySelector
(
'
.gl-pagination .js-last-button a
'
).
click
();
expect
(
component
.
updateContent
).
toHaveBeenCalledWith
({
scope
:
component
.
scope
,
page
:
'
10
'
});
expect
(
component
.
updateContent
).
toHaveBeenCalledWith
({
scope
:
component
.
scope
,
page
:
'
10
'
,
});
done
();
done
();
},
0
);
},
0
);
});
});
it
(
'
should make an API request when using tabs
'
,
(
done
)
=>
{
it
(
'
should make an API request when using tabs
'
,
done
=>
{
setTimeout
(()
=>
{
setTimeout
(()
=>
{
spyOn
(
component
,
'
updateContent
'
);
spyOn
(
component
,
'
updateContent
'
);
component
.
$el
.
querySelector
(
'
.js-environments-tab-stopped
'
).
click
();
component
.
$el
.
querySelector
(
'
.js-environments-tab-stopped
'
).
click
();
...
@@ -134,20 +139,18 @@ describe('Environments Folder View', () => {
...
@@ -134,20 +139,18 @@ describe('Environments Folder View', () => {
component
=
mountComponent
(
Component
,
mockData
);
component
=
mountComponent
(
Component
,
mockData
);
});
});
it
(
'
should not render a table
'
,
(
done
)
=>
{
it
(
'
should not render a table
'
,
done
=>
{
setTimeout
(()
=>
{
setTimeout
(()
=>
{
expect
(
expect
(
component
.
$el
.
querySelector
(
'
table
'
)).
toBe
(
null
);
component
.
$el
.
querySelector
(
'
table
'
),
).
toBe
(
null
);
done
();
done
();
},
0
);
},
0
);
});
});
it
(
'
should render available tab with count 0
'
,
(
done
)
=>
{
it
(
'
should render available tab with count 0
'
,
done
=>
{
setTimeout
(()
=>
{
setTimeout
(()
=>
{
expect
(
expect
(
component
.
$el
.
querySelector
(
'
.js-environments-tab-available
'
).
textContent
).
toContain
(
component
.
$el
.
querySelector
(
'
.js-environments-tab-available
'
).
textContent
,
'
Available
'
,
)
.
toContain
(
'
Available
'
)
;
);
expect
(
expect
(
component
.
$el
.
querySelector
(
'
.js-environments-tab-available .badge
'
).
textContent
,
component
.
$el
.
querySelector
(
'
.js-environments-tab-available .badge
'
).
textContent
,
...
@@ -156,11 +159,11 @@ describe('Environments Folder View', () => {
...
@@ -156,11 +159,11 @@ describe('Environments Folder View', () => {
},
0
);
},
0
);
});
});
it
(
'
should render stopped tab with count 0
'
,
(
done
)
=>
{
it
(
'
should render stopped tab with count 0
'
,
done
=>
{
setTimeout
(()
=>
{
setTimeout
(()
=>
{
expect
(
expect
(
component
.
$el
.
querySelector
(
'
.js-environments-tab-stopped
'
).
textContent
).
toContain
(
component
.
$el
.
querySelector
(
'
.js-environments-tab-stopped
'
).
textContent
,
'
Stopped
'
,
)
.
toContain
(
'
Stopped
'
)
;
);
expect
(
expect
(
component
.
$el
.
querySelector
(
'
.js-environments-tab-stopped .badge
'
).
textContent
,
component
.
$el
.
querySelector
(
'
.js-environments-tab-stopped .badge
'
).
textContent
,
...
@@ -181,8 +184,9 @@ describe('Environments Folder View', () => {
...
@@ -181,8 +184,9 @@ describe('Environments Folder View', () => {
});
});
describe
(
'
updateContent
'
,
()
=>
{
describe
(
'
updateContent
'
,
()
=>
{
it
(
'
should set given parameters
'
,
(
done
)
=>
{
it
(
'
should set given parameters
'
,
done
=>
{
component
.
updateContent
({
scope
:
'
stopped
'
,
page
:
'
4
'
})
component
.
updateContent
({
scope
:
'
stopped
'
,
page
:
'
4
'
})
.
then
(()
=>
{
.
then
(()
=>
{
expect
(
component
.
page
).
toEqual
(
'
4
'
);
expect
(
component
.
page
).
toEqual
(
'
4
'
);
expect
(
component
.
scope
).
toEqual
(
'
stopped
'
);
expect
(
component
.
scope
).
toEqual
(
'
stopped
'
);
...
...
spec/javascripts/issue_show/components/title_spec.js
View file @
160157a9
...
@@ -25,25 +25,21 @@ describe('Title component', () => {
...
@@ -25,25 +25,21 @@ describe('Title component', () => {
});
});
it
(
'
renders title HTML
'
,
()
=>
{
it
(
'
renders title HTML
'
,
()
=>
{
expect
(
expect
(
vm
.
$el
.
querySelector
(
'
.title
'
).
innerHTML
.
trim
()).
toBe
(
'
Testing <img>
'
);
vm
.
$el
.
querySelector
(
'
.title
'
).
innerHTML
.
trim
(),
).
toBe
(
'
Testing <img>
'
);
});
});
it
(
'
updates page title when changing titleHtml
'
,
(
done
)
=>
{
it
(
'
updates page title when changing titleHtml
'
,
done
=>
{
spyOn
(
vm
,
'
setPageTitle
'
);
spyOn
(
vm
,
'
setPageTitle
'
);
vm
.
titleHtml
=
'
test
'
;
vm
.
titleHtml
=
'
test
'
;
Vue
.
nextTick
(()
=>
{
Vue
.
nextTick
(()
=>
{
expect
(
expect
(
vm
.
setPageTitle
).
toHaveBeenCalled
();
vm
.
setPageTitle
,
).
toHaveBeenCalled
();
done
();
done
();
});
});
});
});
it
(
'
animates title changes
'
,
(
done
)
=>
{
it
(
'
animates title changes
'
,
done
=>
{
vm
.
titleHtml
=
'
test
'
;
vm
.
titleHtml
=
'
test
'
;
Vue
.
nextTick
(()
=>
{
Vue
.
nextTick
(()
=>
{
...
@@ -61,14 +57,12 @@ describe('Title component', () => {
...
@@ -61,14 +57,12 @@ describe('Title component', () => {
});
});
});
});
it
(
'
updates page title after changing title
'
,
(
done
)
=>
{
it
(
'
updates page title after changing title
'
,
done
=>
{
vm
.
titleHtml
=
'
changed
'
;
vm
.
titleHtml
=
'
changed
'
;
vm
.
titleText
=
'
changed
'
;
vm
.
titleText
=
'
changed
'
;
Vue
.
nextTick
(()
=>
{
Vue
.
nextTick
(()
=>
{
expect
(
expect
(
document
.
querySelector
(
'
title
'
).
textContent
.
trim
()).
toContain
(
'
changed
'
);
document
.
querySelector
(
'
title
'
).
textContent
.
trim
(),
).
toContain
(
'
changed
'
);
done
();
done
();
});
});
...
...
spec/javascripts/jobs/components/job_app_spec.js
View file @
160157a9
...
@@ -234,7 +234,7 @@ describe('Job App ', () => {
...
@@ -234,7 +234,7 @@ describe('Job App ', () => {
);
);
done
();
done
();
},
0
);
},
0
);
})
})
;
});
});
it
(
'
does not renders stuck block when there are no runners
'
,
done
=>
{
it
(
'
does not renders stuck block when there are no runners
'
,
done
=>
{
...
...
spec/javascripts/jobs/store/actions_spec.js
View file @
160157a9
...
@@ -68,41 +68,20 @@ describe('Job State actions', () => {
...
@@ -68,41 +68,20 @@ describe('Job State actions', () => {
describe
(
'
hideSidebar
'
,
()
=>
{
describe
(
'
hideSidebar
'
,
()
=>
{
it
(
'
should commit HIDE_SIDEBAR mutation
'
,
done
=>
{
it
(
'
should commit HIDE_SIDEBAR mutation
'
,
done
=>
{
testAction
(
testAction
(
hideSidebar
,
null
,
mockedState
,
[{
type
:
types
.
HIDE_SIDEBAR
}],
[],
done
);
hideSidebar
,
null
,
mockedState
,
[{
type
:
types
.
HIDE_SIDEBAR
}],
[],
done
,
);
});
});
});
});
describe
(
'
showSidebar
'
,
()
=>
{
describe
(
'
showSidebar
'
,
()
=>
{
it
(
'
should commit HIDE_SIDEBAR mutation
'
,
done
=>
{
it
(
'
should commit HIDE_SIDEBAR mutation
'
,
done
=>
{
testAction
(
testAction
(
showSidebar
,
null
,
mockedState
,
[{
type
:
types
.
SHOW_SIDEBAR
}],
[],
done
);
showSidebar
,
null
,
mockedState
,
[{
type
:
types
.
SHOW_SIDEBAR
}],
[],
done
,
);
});
});
});
});
describe
(
'
toggleSidebar
'
,
()
=>
{
describe
(
'
toggleSidebar
'
,
()
=>
{
describe
(
'
when isSidebarOpen is true
'
,
()
=>
{
describe
(
'
when isSidebarOpen is true
'
,
()
=>
{
it
(
'
should dispatch hideSidebar
'
,
done
=>
{
it
(
'
should dispatch hideSidebar
'
,
done
=>
{
testAction
(
testAction
(
toggleSidebar
,
null
,
mockedState
,
[],
[{
type
:
'
hideSidebar
'
}],
done
);
toggleSidebar
,
null
,
mockedState
,
[],
[{
type
:
'
hideSidebar
'
}],
done
,
);
});
});
});
});
...
@@ -110,14 +89,7 @@ describe('Job State actions', () => {
...
@@ -110,14 +89,7 @@ describe('Job State actions', () => {
it
(
'
should dispatch showSidebar
'
,
done
=>
{
it
(
'
should dispatch showSidebar
'
,
done
=>
{
mockedState
.
isSidebarOpen
=
false
;
mockedState
.
isSidebarOpen
=
false
;
testAction
(
testAction
(
toggleSidebar
,
null
,
mockedState
,
[],
[{
type
:
'
showSidebar
'
}],
done
);
toggleSidebar
,
null
,
mockedState
,
[],
[{
type
:
'
showSidebar
'
}],
done
,
);
});
});
});
});
});
});
...
...
spec/javascripts/jobs/store/getters_spec.js
View file @
160157a9
...
@@ -180,7 +180,7 @@ describe('Job Store Getters', () => {
...
@@ -180,7 +180,7 @@ describe('Job Store Getters', () => {
it
(
'
returns true
'
,
()
=>
{
it
(
'
returns true
'
,
()
=>
{
localState
.
job
.
runners
=
{
localState
.
job
.
runners
=
{
available
:
true
,
available
:
true
,
online
:
false
online
:
false
,
};
};
expect
(
getters
.
hasRunnersForProject
(
localState
)).
toEqual
(
true
);
expect
(
getters
.
hasRunnersForProject
(
localState
)).
toEqual
(
true
);
...
@@ -191,7 +191,7 @@ describe('Job Store Getters', () => {
...
@@ -191,7 +191,7 @@ describe('Job Store Getters', () => {
it
(
'
returns false
'
,
()
=>
{
it
(
'
returns false
'
,
()
=>
{
localState
.
job
.
runners
=
{
localState
.
job
.
runners
=
{
available
:
false
,
available
:
false
,
online
:
false
online
:
false
,
};
};
expect
(
getters
.
hasRunnersForProject
(
localState
)).
toEqual
(
false
);
expect
(
getters
.
hasRunnersForProject
(
localState
)).
toEqual
(
false
);
...
@@ -202,7 +202,7 @@ describe('Job Store Getters', () => {
...
@@ -202,7 +202,7 @@ describe('Job Store Getters', () => {
it
(
'
returns false
'
,
()
=>
{
it
(
'
returns false
'
,
()
=>
{
localState
.
job
.
runners
=
{
localState
.
job
.
runners
=
{
available
:
false
,
available
:
false
,
online
:
true
online
:
true
,
};
};
expect
(
getters
.
hasRunnersForProject
(
localState
)).
toEqual
(
false
);
expect
(
getters
.
hasRunnersForProject
(
localState
)).
toEqual
(
false
);
...
...
spec/javascripts/lib/utils/common_utils_spec.js
View file @
160157a9
...
@@ -35,9 +35,7 @@ describe('common_utils', () => {
...
@@ -35,9 +35,7 @@ describe('common_utils', () => {
});
});
it
(
'
should decode params
'
,
()
=>
{
it
(
'
should decode params
'
,
()
=>
{
expect
(
expect
(
commonUtils
.
urlParamsToArray
(
'
?label_name%5B%5D=test
'
)[
0
]).
toBe
(
'
label_name[]=test
'
);
commonUtils
.
urlParamsToArray
(
'
?label_name%5B%5D=test
'
)[
0
],
).
toBe
(
'
label_name[]=test
'
);
});
});
it
(
'
should remove the question mark from the search params
'
,
()
=>
{
it
(
'
should remove the question mark from the search params
'
,
()
=>
{
...
@@ -49,25 +47,19 @@ describe('common_utils', () => {
...
@@ -49,25 +47,19 @@ describe('common_utils', () => {
describe
(
'
urlParamsToObject
'
,
()
=>
{
describe
(
'
urlParamsToObject
'
,
()
=>
{
it
(
'
parses path for label with trailing +
'
,
()
=>
{
it
(
'
parses path for label with trailing +
'
,
()
=>
{
expect
(
expect
(
commonUtils
.
urlParamsToObject
(
'
label_name[]=label%2B
'
,
{})).
toEqual
({
commonUtils
.
urlParamsToObject
(
'
label_name[]=label%2B
'
,
{}),
).
toEqual
({
label_name
:
[
'
label+
'
],
label_name
:
[
'
label+
'
],
});
});
});
});
it
(
'
parses path for milestone with trailing +
'
,
()
=>
{
it
(
'
parses path for milestone with trailing +
'
,
()
=>
{
expect
(
expect
(
commonUtils
.
urlParamsToObject
(
'
milestone_title=A%2B
'
,
{})).
toEqual
({
commonUtils
.
urlParamsToObject
(
'
milestone_title=A%2B
'
,
{}),
).
toEqual
({
milestone_title
:
'
A+
'
,
milestone_title
:
'
A+
'
,
});
});
});
});
it
(
'
parses path for search terms with spaces
'
,
()
=>
{
it
(
'
parses path for search terms with spaces
'
,
()
=>
{
expect
(
expect
(
commonUtils
.
urlParamsToObject
(
'
search=two+words
'
,
{})).
toEqual
({
commonUtils
.
urlParamsToObject
(
'
search=two+words
'
,
{}),
).
toEqual
({
search
:
'
two words
'
,
search
:
'
two words
'
,
});
});
});
});
...
@@ -187,7 +179,10 @@ describe('common_utils', () => {
...
@@ -187,7 +179,10 @@ describe('common_utils', () => {
describe
(
'
parseQueryStringIntoObject
'
,
()
=>
{
describe
(
'
parseQueryStringIntoObject
'
,
()
=>
{
it
(
'
should return object with query parameters
'
,
()
=>
{
it
(
'
should return object with query parameters
'
,
()
=>
{
expect
(
commonUtils
.
parseQueryStringIntoObject
(
'
scope=all&page=2
'
)).
toEqual
({
scope
:
'
all
'
,
page
:
'
2
'
});
expect
(
commonUtils
.
parseQueryStringIntoObject
(
'
scope=all&page=2
'
)).
toEqual
({
scope
:
'
all
'
,
page
:
'
2
'
,
});
expect
(
commonUtils
.
parseQueryStringIntoObject
(
'
scope=all
'
)).
toEqual
({
scope
:
'
all
'
});
expect
(
commonUtils
.
parseQueryStringIntoObject
(
'
scope=all
'
)).
toEqual
({
scope
:
'
all
'
});
expect
(
commonUtils
.
parseQueryStringIntoObject
()).
toEqual
({});
expect
(
commonUtils
.
parseQueryStringIntoObject
()).
toEqual
({});
});
});
...
@@ -211,7 +206,9 @@ describe('common_utils', () => {
...
@@ -211,7 +206,9 @@ describe('common_utils', () => {
describe
(
'
buildUrlWithCurrentLocation
'
,
()
=>
{
describe
(
'
buildUrlWithCurrentLocation
'
,
()
=>
{
it
(
'
should build an url with current location and given parameters
'
,
()
=>
{
it
(
'
should build an url with current location and given parameters
'
,
()
=>
{
expect
(
commonUtils
.
buildUrlWithCurrentLocation
()).
toEqual
(
window
.
location
.
pathname
);
expect
(
commonUtils
.
buildUrlWithCurrentLocation
()).
toEqual
(
window
.
location
.
pathname
);
expect
(
commonUtils
.
buildUrlWithCurrentLocation
(
'
?page=2
'
)).
toEqual
(
`
${
window
.
location
.
pathname
}
?page=2`
);
expect
(
commonUtils
.
buildUrlWithCurrentLocation
(
'
?page=2
'
)).
toEqual
(
`
${
window
.
location
.
pathname
}
?page=2`
,
);
});
});
});
});
...
@@ -266,21 +263,24 @@ describe('common_utils', () => {
...
@@ -266,21 +263,24 @@ describe('common_utils', () => {
});
});
describe
(
'
normalizeCRLFHeaders
'
,
()
=>
{
describe
(
'
normalizeCRLFHeaders
'
,
()
=>
{
beforeEach
(
function
()
{
beforeEach
(
function
()
{
this
.
CLRFHeaders
=
'
a-header: a-value
\n
Another-Header: ANOTHER-VALUE
\n
LaSt-HeAdEr: last-VALUE
'
;
this
.
CLRFHeaders
=
'
a-header: a-value
\n
Another-Header: ANOTHER-VALUE
\n
LaSt-HeAdEr: last-VALUE
'
;
spyOn
(
String
.
prototype
,
'
split
'
).
and
.
callThrough
();
spyOn
(
String
.
prototype
,
'
split
'
).
and
.
callThrough
();
this
.
normalizeCRLFHeaders
=
commonUtils
.
normalizeCRLFHeaders
(
this
.
CLRFHeaders
);
this
.
normalizeCRLFHeaders
=
commonUtils
.
normalizeCRLFHeaders
(
this
.
CLRFHeaders
);
});
});
it
(
'
should split by newline
'
,
function
()
{
it
(
'
should split by newline
'
,
function
()
{
expect
(
String
.
prototype
.
split
).
toHaveBeenCalledWith
(
'
\n
'
);
expect
(
String
.
prototype
.
split
).
toHaveBeenCalledWith
(
'
\n
'
);
});
});
it
(
'
should split by colon+space for each header
'
,
function
()
{
it
(
'
should split by colon+space for each header
'
,
function
()
{
expect
(
String
.
prototype
.
split
.
calls
.
allArgs
().
filter
(
args
=>
args
[
0
]
===
'
:
'
).
length
).
toBe
(
3
);
expect
(
String
.
prototype
.
split
.
calls
.
allArgs
().
filter
(
args
=>
args
[
0
]
===
'
:
'
).
length
).
toBe
(
3
,
);
});
});
it
(
'
should return a normalized headers object
'
,
function
()
{
it
(
'
should return a normalized headers object
'
,
function
()
{
expect
(
this
.
normalizeCRLFHeaders
).
toEqual
({
expect
(
this
.
normalizeCRLFHeaders
).
toEqual
({
'
A-HEADER
'
:
'
a-value
'
,
'
A-HEADER
'
:
'
a-value
'
,
'
ANOTHER-HEADER
'
:
'
ANOTHER-VALUE
'
,
'
ANOTHER-HEADER
'
:
'
ANOTHER-VALUE
'
,
...
@@ -359,41 +359,51 @@ describe('common_utils', () => {
...
@@ -359,41 +359,51 @@ describe('common_utils', () => {
spyOn
(
window
,
'
setTimeout
'
).
and
.
callFake
(
cb
=>
origSetTimeout
(
cb
,
0
));
spyOn
(
window
,
'
setTimeout
'
).
and
.
callFake
(
cb
=>
origSetTimeout
(
cb
,
0
));
});
});
it
(
'
solves the promise from the callback
'
,
(
done
)
=>
{
it
(
'
solves the promise from the callback
'
,
done
=>
{
const
expectedResponseValue
=
'
Success!
'
;
const
expectedResponseValue
=
'
Success!
'
;
commonUtils
.
backOff
((
next
,
stop
)
=>
(
commonUtils
new
Promise
((
resolve
)
=>
{
.
backOff
((
next
,
stop
)
=>
new
Promise
(
resolve
=>
{
resolve
(
expectedResponseValue
);
resolve
(
expectedResponseValue
);
}).
then
((
resp
)
=>
{
})
.
then
(
resp
=>
{
stop
(
resp
);
stop
(
resp
);
})
})
).
catch
(
done
.
fail
)).
then
((
respBackoff
)
=>
{
.
catch
(
done
.
fail
),
)
.
then
(
respBackoff
=>
{
expect
(
respBackoff
).
toBe
(
expectedResponseValue
);
expect
(
respBackoff
).
toBe
(
expectedResponseValue
);
done
();
done
();
}).
catch
(
done
.
fail
);
})
.
catch
(
done
.
fail
);
});
});
it
(
'
catches the rejected promise from the callback
'
,
(
done
)
=>
{
it
(
'
catches the rejected promise from the callback
'
,
done
=>
{
const
errorMessage
=
'
Mistakes were made!
'
;
const
errorMessage
=
'
Mistakes were made!
'
;
commonUtils
.
backOff
((
next
,
stop
)
=>
{
commonUtils
.
backOff
((
next
,
stop
)
=>
{
new
Promise
((
resolve
,
reject
)
=>
{
new
Promise
((
resolve
,
reject
)
=>
{
reject
(
new
Error
(
errorMessage
));
reject
(
new
Error
(
errorMessage
));
}).
then
((
resp
)
=>
{
})
.
then
(
resp
=>
{
stop
(
resp
);
stop
(
resp
);
}).
catch
(
err
=>
stop
(
err
));
})
}).
catch
((
errBackoffResp
)
=>
{
.
catch
(
err
=>
stop
(
err
));
})
.
catch
(
errBackoffResp
=>
{
expect
(
errBackoffResp
instanceof
Error
).
toBe
(
true
);
expect
(
errBackoffResp
instanceof
Error
).
toBe
(
true
);
expect
(
errBackoffResp
.
message
).
toBe
(
errorMessage
);
expect
(
errBackoffResp
.
message
).
toBe
(
errorMessage
);
done
();
done
();
});
});
});
});
it
(
'
solves the promise correctly after retrying a third time
'
,
(
done
)
=>
{
it
(
'
solves the promise correctly after retrying a third time
'
,
done
=>
{
let
numberOfCalls
=
1
;
let
numberOfCalls
=
1
;
const
expectedResponseValue
=
'
Success!
'
;
const
expectedResponseValue
=
'
Success!
'
;
commonUtils
.
backOff
((
next
,
stop
)
=>
(
commonUtils
.
backOff
((
next
,
stop
)
=>
Promise
.
resolve
(
expectedResponseValue
)
Promise
.
resolve
(
expectedResponseValue
)
.
then
((
resp
)
=>
{
.
then
(
resp
=>
{
if
(
numberOfCalls
<
3
)
{
if
(
numberOfCalls
<
3
)
{
numberOfCalls
+=
1
;
numberOfCalls
+=
1
;
next
();
next
();
...
@@ -401,18 +411,20 @@ describe('common_utils', () => {
...
@@ -401,18 +411,20 @@ describe('common_utils', () => {
stop
(
resp
);
stop
(
resp
);
}
}
})
})
).
catch
(
done
.
fail
)).
then
((
respBackoff
)
=>
{
.
catch
(
done
.
fail
),
)
.
then
(
respBackoff
=>
{
const
timeouts
=
window
.
setTimeout
.
calls
.
allArgs
().
map
(([,
timeout
])
=>
timeout
);
const
timeouts
=
window
.
setTimeout
.
calls
.
allArgs
().
map
(([,
timeout
])
=>
timeout
);
expect
(
timeouts
).
toEqual
([
2000
,
4000
]);
expect
(
timeouts
).
toEqual
([
2000
,
4000
]);
expect
(
respBackoff
).
toBe
(
expectedResponseValue
);
expect
(
respBackoff
).
toBe
(
expectedResponseValue
);
done
();
done
();
}).
catch
(
done
.
fail
);
})
.
catch
(
done
.
fail
);
});
});
it
(
'
rejects the backOff promise after timing out
'
,
(
done
)
=>
{
it
(
'
rejects the backOff promise after timing out
'
,
done
=>
{
commonUtils
.
backOff
(
next
=>
next
(),
64000
)
commonUtils
.
backOff
(
next
=>
next
(),
64000
).
catch
(
errBackoffResp
=>
{
.
catch
((
errBackoffResp
)
=>
{
const
timeouts
=
window
.
setTimeout
.
calls
.
allArgs
().
map
(([,
timeout
])
=>
timeout
);
const
timeouts
=
window
.
setTimeout
.
calls
.
allArgs
().
map
(([,
timeout
])
=>
timeout
);
expect
(
timeouts
).
toEqual
([
2000
,
4000
,
8000
,
16000
,
32000
,
32000
]);
expect
(
timeouts
).
toEqual
([
2000
,
4000
,
8000
,
16000
,
32000
,
32000
]);
...
@@ -466,11 +478,14 @@ describe('common_utils', () => {
...
@@ -466,11 +478,14 @@ describe('common_utils', () => {
});
});
describe
(
'
createOverlayIcon
'
,
()
=>
{
describe
(
'
createOverlayIcon
'
,
()
=>
{
it
(
'
should return the favicon with the overlay
'
,
(
done
)
=>
{
it
(
'
should return the favicon with the overlay
'
,
done
=>
{
commonUtils
.
createOverlayIcon
(
faviconDataUrl
,
overlayDataUrl
).
then
((
url
)
=>
{
commonUtils
.
createOverlayIcon
(
faviconDataUrl
,
overlayDataUrl
)
.
then
(
url
=>
{
expect
(
url
).
toEqual
(
faviconWithOverlayDataUrl
);
expect
(
url
).
toEqual
(
faviconWithOverlayDataUrl
);
done
();
done
();
}).
catch
(
done
.
fail
);
})
.
catch
(
done
.
fail
);
});
});
});
});
...
@@ -486,11 +501,16 @@ describe('common_utils', () => {
...
@@ -486,11 +501,16 @@ describe('common_utils', () => {
document
.
body
.
removeChild
(
document
.
getElementById
(
'
favicon
'
));
document
.
body
.
removeChild
(
document
.
getElementById
(
'
favicon
'
));
});
});
it
(
'
should set page favicon to provided favicon overlay
'
,
(
done
)
=>
{
it
(
'
should set page favicon to provided favicon overlay
'
,
done
=>
{
commonUtils
.
setFaviconOverlay
(
overlayDataUrl
).
then
(()
=>
{
commonUtils
expect
(
document
.
getElementById
(
'
favicon
'
).
getAttribute
(
'
href
'
)).
toEqual
(
faviconWithOverlayDataUrl
);
.
setFaviconOverlay
(
overlayDataUrl
)
.
then
(()
=>
{
expect
(
document
.
getElementById
(
'
favicon
'
).
getAttribute
(
'
href
'
)).
toEqual
(
faviconWithOverlayDataUrl
,
);
done
();
done
();
}).
catch
(
done
.
fail
);
})
.
catch
(
done
.
fail
);
});
});
});
});
...
@@ -512,11 +532,10 @@ describe('common_utils', () => {
...
@@ -512,11 +532,10 @@ describe('common_utils', () => {
document
.
body
.
removeChild
(
document
.
getElementById
(
'
favicon
'
));
document
.
body
.
removeChild
(
document
.
getElementById
(
'
favicon
'
));
});
});
it
(
'
should reset favicon in case of error
'
,
(
done
)
=>
{
it
(
'
should reset favicon in case of error
'
,
done
=>
{
mock
.
onGet
(
BUILD_URL
).
replyOnce
(
500
);
mock
.
onGet
(
BUILD_URL
).
replyOnce
(
500
);
commonUtils
.
setCiStatusFavicon
(
BUILD_URL
)
commonUtils
.
setCiStatusFavicon
(
BUILD_URL
).
catch
(()
=>
{
.
catch
(()
=>
{
const
favicon
=
document
.
getElementById
(
'
favicon
'
);
const
favicon
=
document
.
getElementById
(
'
favicon
'
);
expect
(
favicon
.
getAttribute
(
'
href
'
)).
toEqual
(
faviconDataUrl
);
expect
(
favicon
.
getAttribute
(
'
href
'
)).
toEqual
(
faviconDataUrl
);
...
@@ -524,12 +543,13 @@ describe('common_utils', () => {
...
@@ -524,12 +543,13 @@ describe('common_utils', () => {
});
});
});
});
it
(
'
should set page favicon to CI status favicon based on provided status
'
,
(
done
)
=>
{
it
(
'
should set page favicon to CI status favicon based on provided status
'
,
done
=>
{
mock
.
onGet
(
BUILD_URL
).
reply
(
200
,
{
mock
.
onGet
(
BUILD_URL
).
reply
(
200
,
{
favicon
:
overlayDataUrl
,
favicon
:
overlayDataUrl
,
});
});
commonUtils
.
setCiStatusFavicon
(
BUILD_URL
)
commonUtils
.
setCiStatusFavicon
(
BUILD_URL
)
.
then
(()
=>
{
.
then
(()
=>
{
const
favicon
=
document
.
getElementById
(
'
favicon
'
);
const
favicon
=
document
.
getElementById
(
'
favicon
'
);
...
@@ -554,11 +574,15 @@ describe('common_utils', () => {
...
@@ -554,11 +574,15 @@ describe('common_utils', () => {
});
});
it
(
'
should return the svg for a linked icon
'
,
()
=>
{
it
(
'
should return the svg for a linked icon
'
,
()
=>
{
expect
(
commonUtils
.
spriteIcon
(
'
test
'
)).
toEqual
(
'
<svg ><use xlink:href="icons.svg#test" /></svg>
'
);
expect
(
commonUtils
.
spriteIcon
(
'
test
'
)).
toEqual
(
'
<svg ><use xlink:href="icons.svg#test" /></svg>
'
,
);
});
});
it
(
'
should set svg className when passed
'
,
()
=>
{
it
(
'
should set svg className when passed
'
,
()
=>
{
expect
(
commonUtils
.
spriteIcon
(
'
test
'
,
'
fa fa-test
'
)).
toEqual
(
'
<svg class="fa fa-test"><use xlink:href="icons.svg#test" /></svg>
'
);
expect
(
commonUtils
.
spriteIcon
(
'
test
'
,
'
fa fa-test
'
)).
toEqual
(
'
<svg class="fa fa-test"><use xlink:href="icons.svg#test" /></svg>
'
,
);
});
});
});
});
...
@@ -578,7 +602,7 @@ describe('common_utils', () => {
...
@@ -578,7 +602,7 @@ describe('common_utils', () => {
const
convertedObj
=
commonUtils
.
convertObjectPropsToCamelCase
(
mockObj
);
const
convertedObj
=
commonUtils
.
convertObjectPropsToCamelCase
(
mockObj
);
Object
.
keys
(
convertedObj
).
forEach
(
(
prop
)
=>
{
Object
.
keys
(
convertedObj
).
forEach
(
prop
=>
{
expect
(
snakeRegEx
.
test
(
prop
)).
toBeFalsy
();
expect
(
snakeRegEx
.
test
(
prop
)).
toBeFalsy
();
expect
(
convertedObj
[
prop
]).
toBe
(
mockObj
[
mappings
[
prop
]]);
expect
(
convertedObj
[
prop
]).
toBe
(
mockObj
[
mappings
[
prop
]]);
});
});
...
@@ -597,9 +621,7 @@ describe('common_utils', () => {
...
@@ -597,9 +621,7 @@ describe('common_utils', () => {
},
},
};
};
expect
(
expect
(
commonUtils
.
convertObjectPropsToCamelCase
(
obj
)).
toEqual
({
commonUtils
.
convertObjectPropsToCamelCase
(
obj
),
).
toEqual
({
snakeKey
:
{
snakeKey
:
{
child_snake_key
:
'
value
'
,
child_snake_key
:
'
value
'
,
},
},
...
@@ -614,9 +636,7 @@ describe('common_utils', () => {
...
@@ -614,9 +636,7 @@ describe('common_utils', () => {
},
},
};
};
expect
(
expect
(
commonUtils
.
convertObjectPropsToCamelCase
(
obj
,
{
deep
:
true
})).
toEqual
({
commonUtils
.
convertObjectPropsToCamelCase
(
obj
,
{
deep
:
true
}),
).
toEqual
({
snakeKey
:
{
snakeKey
:
{
childSnakeKey
:
'
value
'
,
childSnakeKey
:
'
value
'
,
},
},
...
@@ -630,9 +650,7 @@ describe('common_utils', () => {
...
@@ -630,9 +650,7 @@ describe('common_utils', () => {
},
},
];
];
expect
(
expect
(
commonUtils
.
convertObjectPropsToCamelCase
(
arr
,
{
deep
:
true
})).
toEqual
([
commonUtils
.
convertObjectPropsToCamelCase
(
arr
,
{
deep
:
true
}),
).
toEqual
([
{
{
childSnakeKey
:
'
value
'
,
childSnakeKey
:
'
value
'
,
},
},
...
@@ -648,9 +666,7 @@ describe('common_utils', () => {
...
@@ -648,9 +666,7 @@ describe('common_utils', () => {
],
],
];
];
expect
(
expect
(
commonUtils
.
convertObjectPropsToCamelCase
(
arr
,
{
deep
:
true
})).
toEqual
([
commonUtils
.
convertObjectPropsToCamelCase
(
arr
,
{
deep
:
true
}),
).
toEqual
([
[
[
{
{
childSnakeKey
:
'
value
'
,
childSnakeKey
:
'
value
'
,
...
...
spec/javascripts/lib/utils/number_utility_spec.js
View file @
160157a9
import
{
formatRelevantDigits
,
bytesToKiB
,
bytesToMiB
,
bytesToGiB
,
numberToHumanSize
}
from
'
~/lib/utils/number_utils
'
;
import
{
formatRelevantDigits
,
bytesToKiB
,
bytesToMiB
,
bytesToGiB
,
numberToHumanSize
,
}
from
'
~/lib/utils/number_utils
'
;
describe
(
'
Number Utils
'
,
()
=>
{
describe
(
'
Number Utils
'
,
()
=>
{
describe
(
'
formatRelevantDigits
'
,
()
=>
{
describe
(
'
formatRelevantDigits
'
,
()
=>
{
...
...
spec/javascripts/monitoring/graph/flag_spec.js
View file @
160157a9
...
@@ -2,7 +2,7 @@ import Vue from 'vue';
...
@@ -2,7 +2,7 @@ import Vue from 'vue';
import
GraphFlag
from
'
~/monitoring/components/graph/flag.vue
'
;
import
GraphFlag
from
'
~/monitoring/components/graph/flag.vue
'
;
import
{
deploymentData
}
from
'
../mock_data
'
;
import
{
deploymentData
}
from
'
../mock_data
'
;
const
createComponent
=
(
propsData
)
=>
{
const
createComponent
=
propsData
=>
{
const
Component
=
Vue
.
extend
(
GraphFlag
);
const
Component
=
Vue
.
extend
(
GraphFlag
);
return
new
Component
({
return
new
Component
({
...
@@ -51,8 +51,7 @@ describe('GraphFlag', () => {
...
@@ -51,8 +51,7 @@ describe('GraphFlag', () => {
it
(
'
has a line at the currentXCoordinate
'
,
()
=>
{
it
(
'
has a line at the currentXCoordinate
'
,
()
=>
{
component
=
createComponent
(
defaultValuesComponent
);
component
=
createComponent
(
defaultValuesComponent
);
expect
(
component
.
$el
.
style
.
left
)
expect
(
component
.
$el
.
style
.
left
).
toEqual
(
`
${
70
+
component
.
currentXCoordinate
}
px`
);
.
toEqual
(
`
${
70
+
component
.
currentXCoordinate
}
px`
);
});
});
describe
(
'
Deployment flag
'
,
()
=>
{
describe
(
'
Deployment flag
'
,
()
=>
{
...
@@ -62,9 +61,7 @@ describe('GraphFlag', () => {
...
@@ -62,9 +61,7 @@ describe('GraphFlag', () => {
deploymentFlagData
,
deploymentFlagData
,
});
});
expect
(
expect
(
deploymentFlagComponent
.
$el
.
querySelector
(
'
.popover-title
'
)).
toContainText
(
'
Deployed
'
);
deploymentFlagComponent
.
$el
.
querySelector
(
'
.popover-title
'
),
).
toContainText
(
'
Deployed
'
);
});
});
it
(
'
contains the ref when a tag is available
'
,
()
=>
{
it
(
'
contains the ref when a tag is available
'
,
()
=>
{
...
@@ -78,13 +75,13 @@ describe('GraphFlag', () => {
...
@@ -78,13 +75,13 @@ describe('GraphFlag', () => {
},
},
});
});
expect
(
expect
(
deploymentFlagComponent
.
$el
.
querySelector
(
'
.deploy-meta-content
'
)).
toContainText
(
deploymentFlagComponent
.
$el
.
querySelector
(
'
.deploy-meta-content
'
)
,
'
f5bcd1d9
'
,
)
.
toContainText
(
'
f5bcd1d9
'
)
;
);
expect
(
expect
(
deploymentFlagComponent
.
$el
.
querySelector
(
'
.deploy-meta-content
'
)).
toContainText
(
deploymentFlagComponent
.
$el
.
querySelector
(
'
.deploy-meta-content
'
)
,
'
1.0
'
,
)
.
toContainText
(
'
1.0
'
)
;
);
});
});
it
(
'
does not contain the ref when a tag is unavailable
'
,
()
=>
{
it
(
'
does not contain the ref when a tag is unavailable
'
,
()
=>
{
...
@@ -98,13 +95,13 @@ describe('GraphFlag', () => {
...
@@ -98,13 +95,13 @@ describe('GraphFlag', () => {
},
},
});
});
expect
(
expect
(
deploymentFlagComponent
.
$el
.
querySelector
(
'
.deploy-meta-content
'
)).
toContainText
(
deploymentFlagComponent
.
$el
.
querySelector
(
'
.deploy-meta-content
'
)
,
'
f5bcd1d9
'
,
)
.
toContainText
(
'
f5bcd1d9
'
)
;
);
expect
(
expect
(
deploymentFlagComponent
.
$el
.
querySelector
(
'
.deploy-meta-content
'
)).
not
.
toContainText
(
deploymentFlagComponent
.
$el
.
querySelector
(
'
.deploy-meta-content
'
)
,
'
1.0
'
,
)
.
not
.
toContainText
(
'
1.0
'
)
;
);
});
});
});
});
...
...
spec/javascripts/notes/components/discussion_filter_spec.js
View file @
160157a9
...
@@ -11,11 +11,13 @@ describe('DiscussionFilter component', () => {
...
@@ -11,11 +11,13 @@ describe('DiscussionFilter component', () => {
beforeEach
(()
=>
{
beforeEach
(()
=>
{
store
=
createStore
();
store
=
createStore
();
const
discussions
=
[{
const
discussions
=
[
{
...
discussionMock
,
...
discussionMock
,
id
:
discussionMock
.
id
,
id
:
discussionMock
.
id
,
notes
:
[{
...
discussionMock
.
notes
[
0
],
resolvable
:
true
,
resolved
:
true
}],
notes
:
[{
...
discussionMock
.
notes
[
0
],
resolvable
:
true
,
resolved
:
true
}],
}];
},
];
const
Component
=
Vue
.
extend
(
DiscussionFilter
);
const
Component
=
Vue
.
extend
(
DiscussionFilter
);
const
defaultValue
=
discussionFiltersMock
[
0
].
value
;
const
defaultValue
=
discussionFiltersMock
[
0
].
value
;
...
@@ -35,11 +37,15 @@ describe('DiscussionFilter component', () => {
...
@@ -35,11 +37,15 @@ describe('DiscussionFilter component', () => {
});
});
it
(
'
renders the all filters
'
,
()
=>
{
it
(
'
renders the all filters
'
,
()
=>
{
expect
(
vm
.
$el
.
querySelectorAll
(
'
.dropdown-menu li
'
).
length
).
toEqual
(
discussionFiltersMock
.
length
);
expect
(
vm
.
$el
.
querySelectorAll
(
'
.dropdown-menu li
'
).
length
).
toEqual
(
discussionFiltersMock
.
length
,
);
});
});
it
(
'
renders the default selected item
'
,
()
=>
{
it
(
'
renders the default selected item
'
,
()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
#discussion-filter-dropdown
'
).
textContent
.
trim
()).
toEqual
(
discussionFiltersMock
[
0
].
title
);
expect
(
vm
.
$el
.
querySelector
(
'
#discussion-filter-dropdown
'
).
textContent
.
trim
()).
toEqual
(
discussionFiltersMock
[
0
].
title
,
);
});
});
it
(
'
updates to the selected item
'
,
()
=>
{
it
(
'
updates to the selected item
'
,
()
=>
{
...
...
spec/javascripts/notes/components/note_app_spec.js
View file @
160157a9
...
@@ -97,7 +97,8 @@ describe('note_app', () => {
...
@@ -97,7 +97,8 @@ describe('note_app', () => {
});
});
it
(
'
should render list of notes
'
,
done
=>
{
it
(
'
should render list of notes
'
,
done
=>
{
const
note
=
mockData
.
INDIVIDUAL_NOTE_RESPONSE_MAP
.
GET
[
const
note
=
mockData
.
INDIVIDUAL_NOTE_RESPONSE_MAP
.
GET
[
'
/gitlab-org/gitlab-ce/issues/26/discussions.json
'
'
/gitlab-org/gitlab-ce/issues/26/discussions.json
'
][
0
].
notes
[
0
];
][
0
].
notes
[
0
];
...
...
spec/javascripts/pipelines/graph/graph_component_spec.js
View file @
160157a9
...
@@ -40,7 +40,9 @@ describe('graph component', () => {
...
@@ -40,7 +40,9 @@ describe('graph component', () => {
).
toEqual
(
true
);
).
toEqual
(
true
);
expect
(
expect
(
component
.
$el
.
querySelector
(
'
.stage-column:nth-child(2) .build:nth-child(1)
'
).
classList
.
contains
(
'
left-connector
'
),
component
.
$el
.
querySelector
(
'
.stage-column:nth-child(2) .build:nth-child(1)
'
)
.
classList
.
contains
(
'
left-connector
'
),
).
toEqual
(
true
);
).
toEqual
(
true
);
expect
(
component
.
$el
.
querySelector
(
'
loading-icon
'
)).
toBe
(
null
);
expect
(
component
.
$el
.
querySelector
(
'
loading-icon
'
)).
toBe
(
null
);
...
@@ -56,7 +58,9 @@ describe('graph component', () => {
...
@@ -56,7 +58,9 @@ describe('graph component', () => {
pipeline
:
graphJSON
,
pipeline
:
graphJSON
,
});
});
expect
(
component
.
$el
.
querySelector
(
'
.stage-column:nth-child(2) .stage-name
'
).
textContent
.
trim
()).
toEqual
(
'
Deploy <img src=x onerror=alert(document.domain)>
'
);
expect
(
component
.
$el
.
querySelector
(
'
.stage-column:nth-child(2) .stage-name
'
).
textContent
.
trim
(),
).
toEqual
(
'
Deploy <img src=x onerror=alert(document.domain)>
'
);
});
});
});
});
});
});
spec/javascripts/sidebar/assignees_spec.js
View file @
160157a9
...
@@ -78,9 +78,7 @@ describe('Assignee component', () => {
...
@@ -78,9 +78,7 @@ describe('Assignee component', () => {
component
=
new
AssigneeComponent
({
component
=
new
AssigneeComponent
({
propsData
:
{
propsData
:
{
rootPath
:
'
http://localhost:3000
'
,
rootPath
:
'
http://localhost:3000
'
,
users
:
[
users
:
[
UsersMock
.
user
],
UsersMock
.
user
,
],
editable
:
false
,
editable
:
false
,
},
},
}).
$mount
();
}).
$mount
();
...
@@ -90,7 +88,9 @@ describe('Assignee component', () => {
...
@@ -90,7 +88,9 @@ describe('Assignee component', () => {
expect
(
collapsed
.
childElementCount
).
toEqual
(
1
);
expect
(
collapsed
.
childElementCount
).
toEqual
(
1
);
expect
(
assignee
.
querySelector
(
'
.avatar
'
).
getAttribute
(
'
src
'
)).
toEqual
(
UsersMock
.
user
.
avatar
);
expect
(
assignee
.
querySelector
(
'
.avatar
'
).
getAttribute
(
'
src
'
)).
toEqual
(
UsersMock
.
user
.
avatar
);
expect
(
assignee
.
querySelector
(
'
.avatar
'
).
getAttribute
(
'
alt
'
)).
toEqual
(
`
${
UsersMock
.
user
.
name
}
's avatar`
);
expect
(
assignee
.
querySelector
(
'
.avatar
'
).
getAttribute
(
'
alt
'
)).
toEqual
(
`
${
UsersMock
.
user
.
name
}
's avatar`
,
);
expect
(
assignee
.
querySelector
(
'
.author
'
).
innerText
.
trim
()).
toEqual
(
UsersMock
.
user
.
name
);
expect
(
assignee
.
querySelector
(
'
.author
'
).
innerText
.
trim
()).
toEqual
(
UsersMock
.
user
.
name
);
});
});
...
@@ -98,34 +98,38 @@ describe('Assignee component', () => {
...
@@ -98,34 +98,38 @@ describe('Assignee component', () => {
component
=
new
AssigneeComponent
({
component
=
new
AssigneeComponent
({
propsData
:
{
propsData
:
{
rootPath
:
'
http://localhost:3000/
'
,
rootPath
:
'
http://localhost:3000/
'
,
users
:
[
users
:
[
UsersMock
.
user
],
UsersMock
.
user
,
],
editable
:
true
,
editable
:
true
,
},
},
}).
$mount
();
}).
$mount
();
expect
(
component
.
$el
.
querySelector
(
'
.author-link
'
)).
not
.
toBeNull
();
expect
(
component
.
$el
.
querySelector
(
'
.author-link
'
)).
not
.
toBeNull
();
// The image
// The image
expect
(
component
.
$el
.
querySelector
(
'
.author-link img
'
).
getAttribute
(
'
src
'
)).
toEqual
(
UsersMock
.
user
.
avatar
);
expect
(
component
.
$el
.
querySelector
(
'
.author-link img
'
).
getAttribute
(
'
src
'
)).
toEqual
(
UsersMock
.
user
.
avatar
,
);
// Author name
// Author name
expect
(
component
.
$el
.
querySelector
(
'
.author-link .author
'
).
innerText
.
trim
()).
toEqual
(
UsersMock
.
user
.
name
);
expect
(
component
.
$el
.
querySelector
(
'
.author-link .author
'
).
innerText
.
trim
()).
toEqual
(
UsersMock
.
user
.
name
,
);
// Username
// Username
expect
(
component
.
$el
.
querySelector
(
'
.author-link .username
'
).
innerText
.
trim
()).
toEqual
(
`@
${
UsersMock
.
user
.
username
}
`
);
expect
(
component
.
$el
.
querySelector
(
'
.author-link .username
'
).
innerText
.
trim
()).
toEqual
(
`@
${
UsersMock
.
user
.
username
}
`
,
);
});
});
it
(
'
has the root url present in the assigneeUrl method
'
,
()
=>
{
it
(
'
has the root url present in the assigneeUrl method
'
,
()
=>
{
component
=
new
AssigneeComponent
({
component
=
new
AssigneeComponent
({
propsData
:
{
propsData
:
{
rootPath
:
'
http://localhost:3000/
'
,
rootPath
:
'
http://localhost:3000/
'
,
users
:
[
users
:
[
UsersMock
.
user
],
UsersMock
.
user
,
],
editable
:
true
,
editable
:
true
,
},
},
}).
$mount
();
}).
$mount
();
expect
(
component
.
assigneeUrl
(
UsersMock
.
user
).
indexOf
(
'
http://localhost:3000/
'
)).
not
.
toEqual
(
-
1
);
expect
(
component
.
assigneeUrl
(
UsersMock
.
user
).
indexOf
(
'
http://localhost:3000/
'
)).
not
.
toEqual
(
-
1
,
);
});
});
});
});
...
@@ -147,13 +151,17 @@ describe('Assignee component', () => {
...
@@ -147,13 +151,17 @@ describe('Assignee component', () => {
const
first
=
collapsed
.
children
[
0
];
const
first
=
collapsed
.
children
[
0
];
expect
(
first
.
querySelector
(
'
.avatar
'
).
getAttribute
(
'
src
'
)).
toEqual
(
users
[
0
].
avatar
);
expect
(
first
.
querySelector
(
'
.avatar
'
).
getAttribute
(
'
src
'
)).
toEqual
(
users
[
0
].
avatar
);
expect
(
first
.
querySelector
(
'
.avatar
'
).
getAttribute
(
'
alt
'
)).
toEqual
(
`
${
users
[
0
].
name
}
's avatar`
);
expect
(
first
.
querySelector
(
'
.avatar
'
).
getAttribute
(
'
alt
'
)).
toEqual
(
`
${
users
[
0
].
name
}
's avatar`
,
);
expect
(
first
.
querySelector
(
'
.author
'
).
innerText
.
trim
()).
toEqual
(
users
[
0
].
name
);
expect
(
first
.
querySelector
(
'
.author
'
).
innerText
.
trim
()).
toEqual
(
users
[
0
].
name
);
const
second
=
collapsed
.
children
[
1
];
const
second
=
collapsed
.
children
[
1
];
expect
(
second
.
querySelector
(
'
.avatar
'
).
getAttribute
(
'
src
'
)).
toEqual
(
users
[
1
].
avatar
);
expect
(
second
.
querySelector
(
'
.avatar
'
).
getAttribute
(
'
src
'
)).
toEqual
(
users
[
1
].
avatar
);
expect
(
second
.
querySelector
(
'
.avatar
'
).
getAttribute
(
'
alt
'
)).
toEqual
(
`
${
users
[
1
].
name
}
's avatar`
);
expect
(
second
.
querySelector
(
'
.avatar
'
).
getAttribute
(
'
alt
'
)).
toEqual
(
`
${
users
[
1
].
name
}
's avatar`
,
);
expect
(
second
.
querySelector
(
'
.author
'
).
innerText
.
trim
()).
toEqual
(
users
[
1
].
name
);
expect
(
second
.
querySelector
(
'
.author
'
).
innerText
.
trim
()).
toEqual
(
users
[
1
].
name
);
});
});
...
@@ -174,7 +182,9 @@ describe('Assignee component', () => {
...
@@ -174,7 +182,9 @@ describe('Assignee component', () => {
const
first
=
collapsed
.
children
[
0
];
const
first
=
collapsed
.
children
[
0
];
expect
(
first
.
querySelector
(
'
.avatar
'
).
getAttribute
(
'
src
'
)).
toEqual
(
users
[
0
].
avatar
);
expect
(
first
.
querySelector
(
'
.avatar
'
).
getAttribute
(
'
src
'
)).
toEqual
(
users
[
0
].
avatar
);
expect
(
first
.
querySelector
(
'
.avatar
'
).
getAttribute
(
'
alt
'
)).
toEqual
(
`
${
users
[
0
].
name
}
's avatar`
);
expect
(
first
.
querySelector
(
'
.avatar
'
).
getAttribute
(
'
alt
'
)).
toEqual
(
`
${
users
[
0
].
name
}
's avatar`
,
);
expect
(
first
.
querySelector
(
'
.author
'
).
innerText
.
trim
()).
toEqual
(
users
[
0
].
name
);
expect
(
first
.
querySelector
(
'
.author
'
).
innerText
.
trim
()).
toEqual
(
users
[
0
].
name
);
const
second
=
collapsed
.
children
[
1
];
const
second
=
collapsed
.
children
[
1
];
...
@@ -196,7 +206,7 @@ describe('Assignee component', () => {
...
@@ -196,7 +206,7 @@ describe('Assignee component', () => {
expect
(
component
.
$el
.
querySelector
(
'
.user-list-more
'
)).
toBe
(
null
);
expect
(
component
.
$el
.
querySelector
(
'
.user-list-more
'
)).
toBe
(
null
);
});
});
it
(
'
Shows the "show-less" assignees label
'
,
(
done
)
=>
{
it
(
'
Shows the "show-less" assignees label
'
,
done
=>
{
const
users
=
UsersMockHelper
.
createNumberRandomUsers
(
6
);
const
users
=
UsersMockHelper
.
createNumberRandomUsers
(
6
);
component
=
new
AssigneeComponent
({
component
=
new
AssigneeComponent
({
propsData
:
{
propsData
:
{
...
@@ -206,21 +216,25 @@ describe('Assignee component', () => {
...
@@ -206,21 +216,25 @@ describe('Assignee component', () => {
},
},
}).
$mount
();
}).
$mount
();
expect
(
component
.
$el
.
querySelectorAll
(
'
.user-item
'
).
length
).
toEqual
(
component
.
defaultRenderCount
);
expect
(
component
.
$el
.
querySelectorAll
(
'
.user-item
'
).
length
).
toEqual
(
component
.
defaultRenderCount
,
);
expect
(
component
.
$el
.
querySelector
(
'
.user-list-more
'
)).
not
.
toBe
(
null
);
expect
(
component
.
$el
.
querySelector
(
'
.user-list-more
'
)).
not
.
toBe
(
null
);
const
usersLabelExpectation
=
users
.
length
-
component
.
defaultRenderCount
;
const
usersLabelExpectation
=
users
.
length
-
component
.
defaultRenderCount
;
expect
(
component
.
$el
.
querySelector
(
'
.user-list-more .btn-link
'
).
innerText
.
trim
())
expect
(
component
.
$el
.
querySelector
(
'
.user-list-more .btn-link
'
).
innerText
.
trim
()).
not
.
toBe
(
.
not
.
toBe
(
`+
${
usersLabelExpectation
}
more`
);
`+
${
usersLabelExpectation
}
more`
,
);
component
.
toggleShowLess
();
component
.
toggleShowLess
();
Vue
.
nextTick
(()
=>
{
Vue
.
nextTick
(()
=>
{
expect
(
component
.
$el
.
querySelector
(
'
.user-list-more .btn-link
'
).
innerText
.
trim
())
expect
(
component
.
$el
.
querySelector
(
'
.user-list-more .btn-link
'
).
innerText
.
trim
()).
toBe
(
.
toBe
(
'
- show less
'
);
'
- show less
'
,
);
done
();
done
();
});
});
});
});
it
(
'
Shows the "show-less" when "n+ more " label is clicked
'
,
(
done
)
=>
{
it
(
'
Shows the "show-less" when "n+ more " label is clicked
'
,
done
=>
{
const
users
=
UsersMockHelper
.
createNumberRandomUsers
(
6
);
const
users
=
UsersMockHelper
.
createNumberRandomUsers
(
6
);
component
=
new
AssigneeComponent
({
component
=
new
AssigneeComponent
({
propsData
:
{
propsData
:
{
...
@@ -232,8 +246,9 @@ describe('Assignee component', () => {
...
@@ -232,8 +246,9 @@ describe('Assignee component', () => {
component
.
$el
.
querySelector
(
'
.user-list-more .btn-link
'
).
click
();
component
.
$el
.
querySelector
(
'
.user-list-more .btn-link
'
).
click
();
Vue
.
nextTick
(()
=>
{
Vue
.
nextTick
(()
=>
{
expect
(
component
.
$el
.
querySelector
(
'
.user-list-more .btn-link
'
).
innerText
.
trim
())
expect
(
component
.
$el
.
querySelector
(
'
.user-list-more .btn-link
'
).
innerText
.
trim
()).
toBe
(
.
toBe
(
'
- show less
'
);
'
- show less
'
,
);
done
();
done
();
});
});
});
});
...
@@ -264,16 +279,18 @@ describe('Assignee component', () => {
...
@@ -264,16 +279,18 @@ describe('Assignee component', () => {
});
});
it
(
'
shows "+1 more" label
'
,
()
=>
{
it
(
'
shows "+1 more" label
'
,
()
=>
{
expect
(
component
.
$el
.
querySelector
(
'
.user-list-more .btn-link
'
).
innerText
.
trim
())
expect
(
component
.
$el
.
querySelector
(
'
.user-list-more .btn-link
'
).
innerText
.
trim
()).
toBe
(
.
toBe
(
'
+ 1 more
'
);
'
+ 1 more
'
,
);
});
});
it
(
'
shows "show less" label
'
,
(
done
)
=>
{
it
(
'
shows "show less" label
'
,
done
=>
{
component
.
toggleShowLess
();
component
.
toggleShowLess
();
Vue
.
nextTick
(()
=>
{
Vue
.
nextTick
(()
=>
{
expect
(
component
.
$el
.
querySelector
(
'
.user-list-more .btn-link
'
).
innerText
.
trim
())
expect
(
component
.
$el
.
querySelector
(
'
.user-list-more .btn-link
'
).
innerText
.
trim
()).
toBe
(
.
toBe
(
'
- show less
'
);
'
- show less
'
,
);
done
();
done
();
});
});
});
});
...
...
spec/javascripts/vue_mr_widget/components/mr_widget_pipeline_spec.js
View file @
160157a9
...
@@ -72,9 +72,9 @@ describe('MRWidgetPipeline', () => {
...
@@ -72,9 +72,9 @@ describe('MRWidgetPipeline', () => {
troubleshootingDocsPath
:
'
help
'
,
troubleshootingDocsPath
:
'
help
'
,
});
});
expect
(
expect
(
vm
.
$el
.
querySelector
(
'
.media-body
'
).
textContent
.
trim
()).
toContain
(
vm
.
$el
.
querySelector
(
'
.media-body
'
).
textContent
.
trim
()
,
'
Could not retrieve the pipeline status. For troubleshooting steps, read the <a href="help">documentation.</a>
'
,
)
.
toContain
(
'
Could not retrieve the pipeline status. For troubleshooting steps, read the <a href="help">documentation.</a>
'
)
;
);
});
});
describe
(
'
with a pipeline
'
,
()
=>
{
describe
(
'
with a pipeline
'
,
()
=>
{
...
@@ -88,34 +88,36 @@ describe('MRWidgetPipeline', () => {
...
@@ -88,34 +88,36 @@ describe('MRWidgetPipeline', () => {
});
});
it
(
'
should render pipeline ID
'
,
()
=>
{
it
(
'
should render pipeline ID
'
,
()
=>
{
expect
(
expect
(
vm
.
$el
.
querySelector
(
'
.pipeline-id
'
).
textContent
.
trim
()).
toEqual
(
vm
.
$el
.
querySelector
(
'
.pipeline-id
'
).
textContent
.
trim
()
,
`#
${
mockData
.
pipeline
.
id
}
`
,
)
.
toEqual
(
`#
${
mockData
.
pipeline
.
id
}
`
)
;
);
});
});
it
(
'
should render pipeline status and commit id
'
,
()
=>
{
it
(
'
should render pipeline status and commit id
'
,
()
=>
{
expect
(
expect
(
vm
.
$el
.
querySelector
(
'
.media-body
'
).
textContent
.
trim
()).
toContain
(
vm
.
$el
.
querySelector
(
'
.media-body
'
).
textContent
.
trim
()
,
mockData
.
pipeline
.
details
.
status
.
label
,
)
.
toContain
(
mockData
.
pipeline
.
details
.
status
.
label
)
;
);
expect
(
expect
(
vm
.
$el
.
querySelector
(
'
.js-commit-link
'
).
textContent
.
trim
()).
toEqual
(
vm
.
$el
.
querySelector
(
'
.js-commit-link
'
).
textContent
.
trim
()
,
mockData
.
pipeline
.
commit
.
short_id
,
)
.
toEqual
(
mockData
.
pipeline
.
commit
.
short_id
)
;
);
expect
(
expect
(
vm
.
$el
.
querySelector
(
'
.js-commit-link
'
).
getAttribute
(
'
href
'
)).
toEqual
(
vm
.
$el
.
querySelector
(
'
.js-commit-link
'
).
getAttribute
(
'
href
'
)
,
mockData
.
pipeline
.
commit
.
commit_path
,
)
.
toEqual
(
mockData
.
pipeline
.
commit
.
commit_path
)
;
);
});
});
it
(
'
should render pipeline graph
'
,
()
=>
{
it
(
'
should render pipeline graph
'
,
()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.mr-widget-pipeline-graph
'
)).
toBeDefined
();
expect
(
vm
.
$el
.
querySelector
(
'
.mr-widget-pipeline-graph
'
)).
toBeDefined
();
expect
(
vm
.
$el
.
querySelectorAll
(
'
.stage-container
'
).
length
).
toEqual
(
mockData
.
pipeline
.
details
.
stages
.
length
);
expect
(
vm
.
$el
.
querySelectorAll
(
'
.stage-container
'
).
length
).
toEqual
(
mockData
.
pipeline
.
details
.
stages
.
length
,
);
});
});
it
(
'
should render coverage information
'
,
()
=>
{
it
(
'
should render coverage information
'
,
()
=>
{
expect
(
expect
(
vm
.
$el
.
querySelector
(
'
.media-body
'
).
textContent
).
toContain
(
vm
.
$el
.
querySelector
(
'
.media-body
'
).
textContent
,
`Coverage
${
mockData
.
pipeline
.
coverage
}
`
,
)
.
toContain
(
`Coverage
${
mockData
.
pipeline
.
coverage
}
`
)
;
);
});
});
});
});
...
@@ -133,30 +135,30 @@ describe('MRWidgetPipeline', () => {
...
@@ -133,30 +135,30 @@ describe('MRWidgetPipeline', () => {
});
});
it
(
'
should render pipeline ID
'
,
()
=>
{
it
(
'
should render pipeline ID
'
,
()
=>
{
expect
(
expect
(
vm
.
$el
.
querySelector
(
'
.pipeline-id
'
).
textContent
.
trim
()).
toEqual
(
vm
.
$el
.
querySelector
(
'
.pipeline-id
'
).
textContent
.
trim
()
,
`#
${
mockData
.
pipeline
.
id
}
`
,
)
.
toEqual
(
`#
${
mockData
.
pipeline
.
id
}
`
)
;
);
});
});
it
(
'
should render pipeline status
'
,
()
=>
{
it
(
'
should render pipeline status
'
,
()
=>
{
expect
(
expect
(
vm
.
$el
.
querySelector
(
'
.media-body
'
).
textContent
.
trim
()).
toContain
(
vm
.
$el
.
querySelector
(
'
.media-body
'
).
textContent
.
trim
()
,
mockData
.
pipeline
.
details
.
status
.
label
,
)
.
toContain
(
mockData
.
pipeline
.
details
.
status
.
label
)
;
);
expect
(
expect
(
vm
.
$el
.
querySelector
(
'
.js-commit-link
'
)).
toBeNull
();
vm
.
$el
.
querySelector
(
'
.js-commit-link
'
),
).
toBeNull
();
});
});
it
(
'
should render pipeline graph
'
,
()
=>
{
it
(
'
should render pipeline graph
'
,
()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.mr-widget-pipeline-graph
'
)).
toBeDefined
();
expect
(
vm
.
$el
.
querySelector
(
'
.mr-widget-pipeline-graph
'
)).
toBeDefined
();
expect
(
vm
.
$el
.
querySelectorAll
(
'
.stage-container
'
).
length
).
toEqual
(
mockData
.
pipeline
.
details
.
stages
.
length
);
expect
(
vm
.
$el
.
querySelectorAll
(
'
.stage-container
'
).
length
).
toEqual
(
mockData
.
pipeline
.
details
.
stages
.
length
,
);
});
});
it
(
'
should render coverage information
'
,
()
=>
{
it
(
'
should render coverage information
'
,
()
=>
{
expect
(
expect
(
vm
.
$el
.
querySelector
(
'
.media-body
'
).
textContent
).
toContain
(
vm
.
$el
.
querySelector
(
'
.media-body
'
).
textContent
,
`Coverage
${
mockData
.
pipeline
.
coverage
}
`
,
)
.
toContain
(
`Coverage
${
mockData
.
pipeline
.
coverage
}
`
)
;
);
});
});
});
});
...
@@ -172,9 +174,7 @@ describe('MRWidgetPipeline', () => {
...
@@ -172,9 +174,7 @@ describe('MRWidgetPipeline', () => {
troubleshootingDocsPath
:
'
help
'
,
troubleshootingDocsPath
:
'
help
'
,
});
});
expect
(
expect
(
vm
.
$el
.
querySelector
(
'
.media-body
'
).
textContent
).
not
.
toContain
(
'
Coverage
'
);
vm
.
$el
.
querySelector
(
'
.media-body
'
).
textContent
,
).
not
.
toContain
(
'
Coverage
'
);
});
});
});
});
...
...
spec/javascripts/vue_mr_widget/mock_data.js
View file @
160157a9
...
@@ -218,6 +218,7 @@ export default {
...
@@ -218,6 +218,7 @@ export default {
diverged_commits_count
:
0
,
diverged_commits_count
:
0
,
only_allow_merge_if_pipeline_succeeds
:
false
,
only_allow_merge_if_pipeline_succeeds
:
false
,
commit_change_content_path
:
'
/root/acets-app/merge_requests/22/commit_change_content
'
,
commit_change_content_path
:
'
/root/acets-app/merge_requests/22/commit_change_content
'
,
merge_commit_path
:
'
http://localhost:3000/root/acets-app/commit/53027d060246c8f47e4a9310fb332aa52f221775
'
,
merge_commit_path
:
troubleshooting_docs_path
:
'
help
'
'
http://localhost:3000/root/acets-app/commit/53027d060246c8f47e4a9310fb332aa52f221775
'
,
troubleshooting_docs_path
:
'
help
'
,
};
};
spec/javascripts/vue_mr_widget/mr_widget_options_spec.js
View file @
160157a9
...
@@ -454,7 +454,7 @@ describe('mrWidgetOptions', () => {
...
@@ -454,7 +454,7 @@ describe('mrWidgetOptions', () => {
deployed_at
:
'
2017-03-22T22:44:42.258Z
'
,
deployed_at
:
'
2017-03-22T22:44:42.258Z
'
,
deployed_at_formatted
:
'
Mar 22, 2017 10:44pm
'
,
deployed_at_formatted
:
'
Mar 22, 2017 10:44pm
'
,
changes
,
changes
,
status
:
'
success
'
status
:
'
success
'
,
};
};
beforeEach
(
done
=>
{
beforeEach
(
done
=>
{
...
@@ -607,7 +607,8 @@ describe('mrWidgetOptions', () => {
...
@@ -607,7 +607,8 @@ describe('mrWidgetOptions', () => {
describe
(
'
with post merge deployments
'
,
()
=>
{
describe
(
'
with post merge deployments
'
,
()
=>
{
beforeEach
(
done
=>
{
beforeEach
(
done
=>
{
vm
.
mr
.
postMergeDeployments
=
[{
vm
.
mr
.
postMergeDeployments
=
[
{
id
:
15
,
id
:
15
,
name
:
'
review/diplo
'
,
name
:
'
review/diplo
'
,
url
:
'
/root/acets-review-apps/environments/15
'
,
url
:
'
/root/acets-review-apps/environments/15
'
,
...
@@ -625,15 +626,17 @@ describe('mrWidgetOptions', () => {
...
@@ -625,15 +626,17 @@ describe('mrWidgetOptions', () => {
},
},
{
{
path
:
'
imgs/gallery.html
'
,
path
:
'
imgs/gallery.html
'
,
external_url
:
'
http://root-master-patch-91341.volatile-watch.surge.sh/imgs/gallery.html
'
,
external_url
:
'
http://root-master-patch-91341.volatile-watch.surge.sh/imgs/gallery.html
'
,
},
},
{
{
path
:
'
about/
'
,
path
:
'
about/
'
,
external_url
:
'
http://root-master-patch-91341.volatile-watch.surge.sh/about/
'
,
external_url
:
'
http://root-master-patch-91341.volatile-watch.surge.sh/about/
'
,
},
},
],
],
status
:
'
success
'
status
:
'
success
'
,
}];
},
];
vm
.
$nextTick
(
done
);
vm
.
$nextTick
(
done
);
});
});
...
...
spec/javascripts/vue_shared/components/sidebar/collapsed_grouped_date_picker_spec.js
View file @
160157a9
...
@@ -12,7 +12,7 @@ describe('collapsedGroupedDatePicker', () => {
...
@@ -12,7 +12,7 @@ describe('collapsedGroupedDatePicker', () => {
});
});
describe
(
'
toggleCollapse events
'
,
()
=>
{
describe
(
'
toggleCollapse events
'
,
()
=>
{
beforeEach
(
(
done
)
=>
{
beforeEach
(
done
=>
{
spyOn
(
vm
,
'
toggleSidebar
'
);
spyOn
(
vm
,
'
toggleSidebar
'
);
vm
.
minDate
=
new
Date
(
'
07/17/2016
'
);
vm
.
minDate
=
new
Date
(
'
07/17/2016
'
);
Vue
.
nextTick
(
done
);
Vue
.
nextTick
(
done
);
...
@@ -26,7 +26,7 @@ describe('collapsedGroupedDatePicker', () => {
...
@@ -26,7 +26,7 @@ describe('collapsedGroupedDatePicker', () => {
});
});
describe
(
'
minDate and maxDate
'
,
()
=>
{
describe
(
'
minDate and maxDate
'
,
()
=>
{
beforeEach
(
(
done
)
=>
{
beforeEach
(
done
=>
{
vm
.
minDate
=
new
Date
(
'
07/17/2016
'
);
vm
.
minDate
=
new
Date
(
'
07/17/2016
'
);
vm
.
maxDate
=
new
Date
(
'
07/17/2017
'
);
vm
.
maxDate
=
new
Date
(
'
07/17/2017
'
);
Vue
.
nextTick
(
done
);
Vue
.
nextTick
(
done
);
...
@@ -42,7 +42,7 @@ describe('collapsedGroupedDatePicker', () => {
...
@@ -42,7 +42,7 @@ describe('collapsedGroupedDatePicker', () => {
});
});
describe
(
'
minDate
'
,
()
=>
{
describe
(
'
minDate
'
,
()
=>
{
beforeEach
(
(
done
)
=>
{
beforeEach
(
done
=>
{
vm
.
minDate
=
new
Date
(
'
07/17/2016
'
);
vm
.
minDate
=
new
Date
(
'
07/17/2016
'
);
Vue
.
nextTick
(
done
);
Vue
.
nextTick
(
done
);
});
});
...
@@ -56,7 +56,7 @@ describe('collapsedGroupedDatePicker', () => {
...
@@ -56,7 +56,7 @@ describe('collapsedGroupedDatePicker', () => {
});
});
describe
(
'
maxDate
'
,
()
=>
{
describe
(
'
maxDate
'
,
()
=>
{
beforeEach
(
(
done
)
=>
{
beforeEach
(
done
=>
{
vm
.
maxDate
=
new
Date
(
'
07/17/2017
'
);
vm
.
maxDate
=
new
Date
(
'
07/17/2017
'
);
Vue
.
nextTick
(
done
);
Vue
.
nextTick
(
done
);
});
});
...
...
spec/javascripts/vue_shared/components/sidebar/date_picker_spec.js
View file @
160157a9
...
@@ -41,7 +41,7 @@ describe('sidebarDatePicker', () => {
...
@@ -41,7 +41,7 @@ describe('sidebarDatePicker', () => {
expect
(
vm
.
$el
.
querySelector
(
'
.value-content span
'
).
innerText
.
trim
()).
toEqual
(
'
None
'
);
expect
(
vm
.
$el
.
querySelector
(
'
.value-content span
'
).
innerText
.
trim
()).
toEqual
(
'
None
'
);
});
});
it
(
'
should render date-picker when editing
'
,
(
done
)
=>
{
it
(
'
should render date-picker when editing
'
,
done
=>
{
vm
.
editing
=
true
;
vm
.
editing
=
true
;
Vue
.
nextTick
(()
=>
{
Vue
.
nextTick
(()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.pika-label
'
)).
toBeDefined
();
expect
(
vm
.
$el
.
querySelector
(
'
.pika-label
'
)).
toBeDefined
();
...
@@ -50,7 +50,7 @@ describe('sidebarDatePicker', () => {
...
@@ -50,7 +50,7 @@ describe('sidebarDatePicker', () => {
});
});
describe
(
'
editable
'
,
()
=>
{
describe
(
'
editable
'
,
()
=>
{
beforeEach
(
(
done
)
=>
{
beforeEach
(
done
=>
{
vm
.
editable
=
true
;
vm
.
editable
=
true
;
Vue
.
nextTick
(
done
);
Vue
.
nextTick
(
done
);
});
});
...
@@ -59,7 +59,7 @@ describe('sidebarDatePicker', () => {
...
@@ -59,7 +59,7 @@ describe('sidebarDatePicker', () => {
expect
(
vm
.
$el
.
querySelector
(
'
.title .btn-blank
'
).
innerText
.
trim
()).
toEqual
(
'
Edit
'
);
expect
(
vm
.
$el
.
querySelector
(
'
.title .btn-blank
'
).
innerText
.
trim
()).
toEqual
(
'
Edit
'
);
});
});
it
(
'
should enable editing when edit button is clicked
'
,
(
done
)
=>
{
it
(
'
should enable editing when edit button is clicked
'
,
done
=>
{
vm
.
isLoading
=
false
;
vm
.
isLoading
=
false
;
Vue
.
nextTick
(()
=>
{
Vue
.
nextTick
(()
=>
{
vm
.
$el
.
querySelector
(
'
.title .btn-blank
'
).
click
();
vm
.
$el
.
querySelector
(
'
.title .btn-blank
'
).
click
();
...
@@ -70,7 +70,7 @@ describe('sidebarDatePicker', () => {
...
@@ -70,7 +70,7 @@ describe('sidebarDatePicker', () => {
});
});
});
});
it
(
'
should render date if selectedDate
'
,
(
done
)
=>
{
it
(
'
should render date if selectedDate
'
,
done
=>
{
vm
.
selectedDate
=
new
Date
(
'
07/07/2017
'
);
vm
.
selectedDate
=
new
Date
(
'
07/07/2017
'
);
Vue
.
nextTick
(()
=>
{
Vue
.
nextTick
(()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.value-content strong
'
).
innerText
.
trim
()).
toEqual
(
'
Jul 7, 2017
'
);
expect
(
vm
.
$el
.
querySelector
(
'
.value-content strong
'
).
innerText
.
trim
()).
toEqual
(
'
Jul 7, 2017
'
);
...
@@ -79,7 +79,7 @@ describe('sidebarDatePicker', () => {
...
@@ -79,7 +79,7 @@ describe('sidebarDatePicker', () => {
});
});
describe
(
'
selectedDate and editable
'
,
()
=>
{
describe
(
'
selectedDate and editable
'
,
()
=>
{
beforeEach
(
(
done
)
=>
{
beforeEach
(
done
=>
{
vm
.
selectedDate
=
new
Date
(
'
07/07/2017
'
);
vm
.
selectedDate
=
new
Date
(
'
07/07/2017
'
);
vm
.
editable
=
true
;
vm
.
editable
=
true
;
Vue
.
nextTick
(
done
);
Vue
.
nextTick
(
done
);
...
@@ -100,7 +100,7 @@ describe('sidebarDatePicker', () => {
...
@@ -100,7 +100,7 @@ describe('sidebarDatePicker', () => {
});
});
describe
(
'
showToggleSidebar
'
,
()
=>
{
describe
(
'
showToggleSidebar
'
,
()
=>
{
beforeEach
(
(
done
)
=>
{
beforeEach
(
done
=>
{
vm
.
showToggleSidebar
=
true
;
vm
.
showToggleSidebar
=
true
;
Vue
.
nextTick
(
done
);
Vue
.
nextTick
(
done
);
});
});
...
...
spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_value_collapsed_spec.js
View file @
160157a9
...
@@ -49,7 +49,9 @@ describe('DropdownValueCollapsedComponent', () => {
...
@@ -49,7 +49,9 @@ describe('DropdownValueCollapsedComponent', () => {
const
vmMoreLabels
=
createComponent
(
mockMoreLabels
);
const
vmMoreLabels
=
createComponent
(
mockMoreLabels
);
expect
(
vmMoreLabels
.
labelsList
).
toBe
(
'
Foo Label, Foo Label, Foo Label, Foo Label, Foo Label, and 2 more
'
);
expect
(
vmMoreLabels
.
labelsList
).
toBe
(
'
Foo Label, Foo Label, Foo Label, Foo Label, Foo Label, and 2 more
'
,
);
vmMoreLabels
.
$destroy
();
vmMoreLabels
.
$destroy
();
});
});
...
...
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