Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
436891da
Commit
436891da
authored
Apr 01, 2018
by
GitLab Bot
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'upstream/master' into ce-to-ee-2018-04-01
# Conflicts: # spec/javascripts/api_spec.js [ci skip]
parents
e7fe6152
6b89ab11
Changes
41
Hide whitespace changes
Inline
Side-by-side
Showing
41 changed files
with
1387 additions
and
571 deletions
+1387
-571
app/assets/javascripts/api.js
app/assets/javascripts/api.js
+88
-58
app/assets/javascripts/ide/components/changed_file_icon.vue
app/assets/javascripts/ide/components/changed_file_icon.vue
+17
-17
app/assets/javascripts/ide/components/editor_mode_dropdown.vue
...ssets/javascripts/ide/components/editor_mode_dropdown.vue
+63
-24
app/assets/javascripts/ide/components/ide.vue
app/assets/javascripts/ide/components/ide.vue
+43
-42
app/assets/javascripts/ide/components/mr_file_icon.vue
app/assets/javascripts/ide/components/mr_file_icon.vue
+23
-0
app/assets/javascripts/ide/components/repo_editor.vue
app/assets/javascripts/ide/components/repo_editor.vue
+17
-12
app/assets/javascripts/ide/components/repo_file.vue
app/assets/javascripts/ide/components/repo_file.vue
+12
-9
app/assets/javascripts/ide/components/repo_file_status_icon.vue
...sets/javascripts/ide/components/repo_file_status_icon.vue
+20
-20
app/assets/javascripts/ide/components/repo_tabs.vue
app/assets/javascripts/ide/components/repo_tabs.vue
+38
-33
app/assets/javascripts/ide/ide_router.js
app/assets/javascripts/ide/ide_router.js
+56
-4
app/assets/javascripts/ide/lib/common/model.js
app/assets/javascripts/ide/lib/common/model.js
+16
-12
app/assets/javascripts/ide/lib/editor.js
app/assets/javascripts/ide/lib/editor.js
+13
-7
app/assets/javascripts/ide/services/index.js
app/assets/javascripts/ide/services/index.js
+24
-1
app/assets/javascripts/ide/stores/actions.js
app/assets/javascripts/ide/stores/actions.js
+4
-7
app/assets/javascripts/ide/stores/actions/file.js
app/assets/javascripts/ide/stores/actions/file.js
+40
-33
app/assets/javascripts/ide/stores/actions/merge_request.js
app/assets/javascripts/ide/stores/actions/merge_request.js
+84
-0
app/assets/javascripts/ide/stores/actions/tree.js
app/assets/javascripts/ide/stores/actions/tree.js
+50
-48
app/assets/javascripts/ide/stores/getters.js
app/assets/javascripts/ide/stores/getters.js
+11
-4
app/assets/javascripts/ide/stores/mutation_types.js
app/assets/javascripts/ide/stores/mutation_types.js
+8
-0
app/assets/javascripts/ide/stores/mutations.js
app/assets/javascripts/ide/stores/mutations.js
+4
-7
app/assets/javascripts/ide/stores/mutations/file.js
app/assets/javascripts/ide/stores/mutations/file.js
+12
-0
app/assets/javascripts/ide/stores/mutations/merge_request.js
app/assets/javascripts/ide/stores/mutations/merge_request.js
+33
-0
app/assets/javascripts/ide/stores/mutations/project.js
app/assets/javascripts/ide/stores/mutations/project.js
+1
-0
app/assets/javascripts/ide/stores/state.js
app/assets/javascripts/ide/stores/state.js
+1
-0
app/assets/javascripts/ide/stores/utils.js
app/assets/javascripts/ide/stores/utils.js
+12
-10
app/assets/javascripts/lib/utils/url_utility.js
app/assets/javascripts/lib/utils/url_utility.js
+9
-1
app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue
.../vue_merge_request_widget/components/mr_widget_header.vue
+54
-43
app/assets/stylesheets/pages/repo.scss
app/assets/stylesheets/pages/repo.scss
+1
-0
spec/javascripts/api_spec.js
spec/javascripts/api_spec.js
+137
-51
spec/javascripts/ide/components/changed_file_icon_spec.js
spec/javascripts/ide/components/changed_file_icon_spec.js
+2
-1
spec/javascripts/ide/components/repo_editor_spec.js
spec/javascripts/ide/components/repo_editor_spec.js
+58
-0
spec/javascripts/ide/components/repo_tabs_spec.js
spec/javascripts/ide/components/repo_tabs_spec.js
+2
-0
spec/javascripts/ide/lib/common/model_spec.js
spec/javascripts/ide/lib/common/model_spec.js
+12
-2
spec/javascripts/ide/lib/editor_spec.js
spec/javascripts/ide/lib/editor_spec.js
+25
-0
spec/javascripts/ide/stores/actions/file_spec.js
spec/javascripts/ide/stores/actions/file_spec.js
+35
-8
spec/javascripts/ide/stores/actions/merge_request_spec.js
spec/javascripts/ide/stores/actions/merge_request_spec.js
+110
-0
spec/javascripts/ide/stores/actions/tree_spec.js
spec/javascripts/ide/stores/actions/tree_spec.js
+3
-9
spec/javascripts/ide/stores/getters_spec.js
spec/javascripts/ide/stores/getters_spec.js
+21
-1
spec/javascripts/ide/stores/mutations/file_spec.js
spec/javascripts/ide/stores/mutations/file_spec.js
+25
-1
spec/javascripts/ide/stores/mutations/merge_request_spec.js
spec/javascripts/ide/stores/mutations/merge_request_spec.js
+65
-0
spec/javascripts/vue_mr_widget/components/mr_widget_header_spec.js
...scripts/vue_mr_widget/components/mr_widget_header_spec.js
+138
-106
No files found.
app/assets/javascripts/api.js
View file @
436891da
...
...
@@ -10,6 +10,9 @@ const Api = {
projectsPath
:
'
/api/:version/projects.json
'
,
projectPath
:
'
/api/:version/projects/:id
'
,
projectLabelsPath
:
'
/:namespace_path/:project_path/labels
'
,
mergeRequestPath
:
'
/api/:version/projects/:id/merge_requests/:mrid
'
,
mergeRequestChangesPath
:
'
/api/:version/projects/:id/merge_requests/:mrid/changes
'
,
mergeRequestVersionsPath
:
'
/api/:version/projects/:id/merge_requests/:mrid/versions
'
,
groupLabelsPath
:
'
/groups/:namespace_path/-/labels
'
,
licensePath
:
'
/api/:version/templates/licenses/:key
'
,
gitignorePath
:
'
/api/:version/templates/gitignores/:key
'
,
...
...
@@ -24,25 +27,27 @@ const Api = {
geoNodesPath
:
'
/api/:version/geo_nodes
'
,
group
(
groupId
,
callback
)
{
const
url
=
Api
.
buildUrl
(
Api
.
groupPath
)
.
replace
(
'
:id
'
,
groupId
);
return
axios
.
get
(
url
)
.
then
(({
data
})
=>
{
callback
(
data
);
const
url
=
Api
.
buildUrl
(
Api
.
groupPath
).
replace
(
'
:id
'
,
groupId
);
return
axios
.
get
(
url
).
then
(({
data
})
=>
{
callback
(
data
);
return
data
;
});
return
data
;
});
},
// Return groups list. Filtered by query
groups
(
query
,
options
,
callback
=
$
.
noop
)
{
const
url
=
Api
.
buildUrl
(
Api
.
groupsPath
);
return
axios
.
get
(
url
,
{
params
:
Object
.
assign
({
search
:
query
,
per_page
:
20
,
},
options
),
})
return
axios
.
get
(
url
,
{
params
:
Object
.
assign
(
{
search
:
query
,
per_page
:
20
,
},
options
,
),
})
.
then
(({
data
})
=>
{
callback
(
data
);
...
...
@@ -53,12 +58,13 @@ const Api = {
// Return namespaces list. Filtered by query
namespaces
(
query
,
callback
)
{
const
url
=
Api
.
buildUrl
(
Api
.
namespacesPath
);
return
axios
.
get
(
url
,
{
params
:
{
search
:
query
,
per_page
:
20
,
},
})
return
axios
.
get
(
url
,
{
params
:
{
search
:
query
,
per_page
:
20
,
},
})
.
then
(({
data
})
=>
callback
(
data
));
},
...
...
@@ -75,9 +81,10 @@ const Api = {
defaults
.
membership
=
true
;
}
return
axios
.
get
(
url
,
{
params
:
Object
.
assign
(
defaults
,
options
),
})
return
axios
.
get
(
url
,
{
params
:
Object
.
assign
(
defaults
,
options
),
})
.
then
(({
data
})
=>
{
callback
(
data
);
...
...
@@ -87,8 +94,32 @@ const Api = {
// Return single project
project
(
projectPath
)
{
const
url
=
Api
.
buildUrl
(
Api
.
projectPath
)
.
replace
(
'
:id
'
,
encodeURIComponent
(
projectPath
));
const
url
=
Api
.
buildUrl
(
Api
.
projectPath
).
replace
(
'
:id
'
,
encodeURIComponent
(
projectPath
));
return
axios
.
get
(
url
);
},
// Return Merge Request for project
mergeRequest
(
projectPath
,
mergeRequestId
)
{
const
url
=
Api
.
buildUrl
(
Api
.
mergeRequestPath
)
.
replace
(
'
:id
'
,
encodeURIComponent
(
projectPath
))
.
replace
(
'
:mrid
'
,
mergeRequestId
);
return
axios
.
get
(
url
);
},
mergeRequestChanges
(
projectPath
,
mergeRequestId
)
{
const
url
=
Api
.
buildUrl
(
Api
.
mergeRequestChangesPath
)
.
replace
(
'
:id
'
,
encodeURIComponent
(
projectPath
))
.
replace
(
'
:mrid
'
,
mergeRequestId
);
return
axios
.
get
(
url
);
},
mergeRequestVersions
(
projectPath
,
mergeRequestId
)
{
const
url
=
Api
.
buildUrl
(
Api
.
mergeRequestVersionsPath
)
.
replace
(
'
:id
'
,
encodeURIComponent
(
projectPath
))
.
replace
(
'
:mrid
'
,
mergeRequestId
);
return
axios
.
get
(
url
);
},
...
...
@@ -104,30 +135,30 @@ const Api = {
url
=
Api
.
buildUrl
(
Api
.
groupLabelsPath
).
replace
(
'
:namespace_path
'
,
namespacePath
);
}
return
axios
.
post
(
url
,
{
label
:
data
,
})
return
axios
.
post
(
url
,
{
label
:
data
,
})
.
then
(
res
=>
callback
(
res
.
data
))
.
catch
(
e
=>
callback
(
e
.
response
.
data
));
},
// Return group projects list. Filtered by query
groupProjects
(
groupId
,
query
,
callback
)
{
const
url
=
Api
.
buildUrl
(
Api
.
groupProjectsPath
)
.
replace
(
'
:id
'
,
groupId
);
return
axios
.
get
(
url
,
{
params
:
{
search
:
query
,
per_page
:
20
,
},
})
const
url
=
Api
.
buildUrl
(
Api
.
groupProjectsPath
)
.
replace
(
'
:id
'
,
groupId
);
return
axios
.
get
(
url
,
{
params
:
{
search
:
query
,
per_page
:
20
,
},
})
.
then
(({
data
})
=>
callback
(
data
));
},
commitMultiple
(
id
,
data
)
{
// see https://docs.gitlab.com/ce/api/commits.html#create-a-commit-with-multiple-files-and-actions
const
url
=
Api
.
buildUrl
(
Api
.
commitPath
)
.
replace
(
'
:id
'
,
encodeURIComponent
(
id
));
const
url
=
Api
.
buildUrl
(
Api
.
commitPath
).
replace
(
'
:id
'
,
encodeURIComponent
(
id
));
return
axios
.
post
(
url
,
JSON
.
stringify
(
data
),
{
headers
:
{
'
Content-Type
'
:
'
application/json; charset=utf-8
'
,
...
...
@@ -138,39 +169,34 @@ const Api = {
branchSingle
(
id
,
branch
)
{
const
url
=
Api
.
buildUrl
(
Api
.
branchSinglePath
)
.
replace
(
'
:id
'
,
encodeURIComponent
(
id
))
.
replace
(
'
:branch
'
,
branch
);
.
replace
(
'
:branch
'
,
encodeURIComponent
(
branch
)
);
return
axios
.
get
(
url
);
},
// Return text for a specific license
licenseText
(
key
,
data
,
callback
)
{
const
url
=
Api
.
buildUrl
(
Api
.
licensePath
)
.
replace
(
'
:key
'
,
key
);
return
axios
.
get
(
url
,
{
params
:
data
,
})
const
url
=
Api
.
buildUrl
(
Api
.
licensePath
)
.
replace
(
'
:key
'
,
key
);
return
axios
.
get
(
url
,
{
params
:
data
,
})
.
then
(
res
=>
callback
(
res
.
data
));
},
gitignoreText
(
key
,
callback
)
{
const
url
=
Api
.
buildUrl
(
Api
.
gitignorePath
)
.
replace
(
'
:key
'
,
key
);
return
axios
.
get
(
url
)
.
then
(({
data
})
=>
callback
(
data
));
const
url
=
Api
.
buildUrl
(
Api
.
gitignorePath
).
replace
(
'
:key
'
,
key
);
return
axios
.
get
(
url
).
then
(({
data
})
=>
callback
(
data
));
},
gitlabCiYml
(
key
,
callback
)
{
const
url
=
Api
.
buildUrl
(
Api
.
gitlabCiYmlPath
)
.
replace
(
'
:key
'
,
key
);
return
axios
.
get
(
url
)
.
then
(({
data
})
=>
callback
(
data
));
const
url
=
Api
.
buildUrl
(
Api
.
gitlabCiYmlPath
).
replace
(
'
:key
'
,
key
);
return
axios
.
get
(
url
).
then
(({
data
})
=>
callback
(
data
));
},
dockerfileYml
(
key
,
callback
)
{
const
url
=
Api
.
buildUrl
(
Api
.
dockerfilePath
).
replace
(
'
:key
'
,
key
);
return
axios
.
get
(
url
)
.
then
(({
data
})
=>
callback
(
data
));
return
axios
.
get
(
url
).
then
(({
data
})
=>
callback
(
data
));
},
issueTemplate
(
namespacePath
,
projectPath
,
key
,
type
,
callback
)
{
...
...
@@ -179,7 +205,8 @@ const Api = {
.
replace
(
'
:type
'
,
type
)
.
replace
(
'
:project_path
'
,
projectPath
)
.
replace
(
'
:namespace_path
'
,
namespacePath
);
return
axios
.
get
(
url
)
return
axios
.
get
(
url
)
.
then
(({
data
})
=>
callback
(
null
,
data
))
.
catch
(
callback
);
},
...
...
@@ -187,10 +214,13 @@ const Api = {
users
(
query
,
options
)
{
const
url
=
Api
.
buildUrl
(
this
.
usersPath
);
return
axios
.
get
(
url
,
{
params
:
Object
.
assign
({
search
:
query
,
per_page
:
20
,
},
options
),
params
:
Object
.
assign
(
{
search
:
query
,
per_page
:
20
,
},
options
,
),
});
},
...
...
app/assets/javascripts/ide/components/changed_file_icon.vue
View file @
436891da
<
script
>
import
icon
from
'
~/vue_shared/components/icon.vue
'
;
import
icon
from
'
~/vue_shared/components/icon.vue
'
;
export
default
{
components
:
{
icon
,
export
default
{
components
:
{
icon
,
},
props
:
{
file
:
{
type
:
Object
,
required
:
true
,
},
props
:
{
file
:
{
type
:
Object
,
required
:
true
,
},
},
computed
:
{
changedIcon
()
{
return
this
.
file
.
tempFile
?
'
file-addition
'
:
'
file-modified
'
;
},
computed
:
{
changedIcon
()
{
return
this
.
file
.
tempFile
?
'
file-addition
'
:
'
file-modified
'
;
},
changedIconClass
()
{
return
`multi-
${
this
.
changedIcon
}
`
;
},
changedIconClass
()
{
return
`multi-
${
this
.
changedIcon
}
`
;
},
};
},
};
</
script
>
<
template
>
...
...
app/assets/javascripts/ide/components/editor_mode_dropdown.vue
View file @
436891da
<
script
>
import
Icon
from
'
~/vue_shared/components/icon.vue
'
;
import
Icon
from
'
~/vue_shared/components/icon.vue
'
;
import
{
__
,
sprintf
}
from
'
~/locale
'
;
export
default
{
components
:
{
Icon
,
export
default
{
components
:
{
Icon
,
},
props
:
{
hasChanges
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
props
:
{
hasChanges
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
viewer
:
{
type
:
String
,
required
:
true
,
},
showShadow
:
{
type
:
Boolean
,
required
:
true
,
},
mergeRequestId
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
methods
:
{
changeMode
(
mode
)
{
this
.
$emit
(
'
click
'
,
mode
);
},
viewer
:
{
type
:
String
,
required
:
true
,
},
};
showShadow
:
{
type
:
Boolean
,
required
:
true
,
},
},
computed
:
{
mergeReviewLine
()
{
return
sprintf
(
__
(
'
Reviewing (merge request !%{mergeRequestId})
'
),
{
mergeRequestId
:
this
.
mergeRequestId
,
});
},
},
methods
:
{
changeMode
(
mode
)
{
this
.
$emit
(
'
click
'
,
mode
);
},
},
};
</
script
>
<
template
>
...
...
@@ -43,7 +56,10 @@
}"
data-toggle="dropdown"
>
<template
v-if=
"viewer === 'editor'"
>
<template
v-if=
"viewer === 'mrdiff' && mergeRequestId"
>
{{
mergeReviewLine
}}
</
template
>
<
template
v-else-if=
"viewer === 'editor'"
>
{{
__
(
'
Editing
'
)
}}
</
template
>
<
template
v-else
>
...
...
@@ -57,6 +73,29 @@
</button>
<div
class=
"dropdown-menu dropdown-menu-selectable dropdown-open-left"
>
<ul>
<
template
v-if=
"mergeRequestId"
>
<li>
<a
href=
"#"
@
click.prevent=
"changeMode('mrdiff')"
:class=
"
{
'is-active': viewer === 'mrdiff',
}"
>
<strong
class=
"dropdown-menu-inner-title"
>
{{
mergeReviewLine
}}
</strong>
<span
class=
"dropdown-menu-inner-content"
>
{{
__
(
'
Compare changes with the merge request target branch
'
)
}}
</span>
</a>
</li>
<li
role=
"separator"
class=
"divider"
>
</li>
</
template
>
<li>
<a
href=
"#"
...
...
app/assets/javascripts/ide/components/ide.vue
View file @
436891da
<
script
>
import
{
mapState
,
mapGetters
}
from
'
vuex
'
;
import
ideSidebar
from
'
./ide_side_bar.vue
'
;
import
ideContextbar
from
'
./ide_context_bar.vue
'
;
import
repoTabs
from
'
./repo_tabs.vue
'
;
import
repoFileButtons
from
'
./repo_file_buttons.vue
'
;
import
ideStatusBar
from
'
./ide_status_bar.vue
'
;
import
repoEditor
from
'
./repo_editor.vue
'
;
import
{
mapState
,
mapGetters
}
from
'
vuex
'
;
import
ideSidebar
from
'
./ide_side_bar.vue
'
;
import
ideContextbar
from
'
./ide_context_bar.vue
'
;
import
repoTabs
from
'
./repo_tabs.vue
'
;
import
repoFileButtons
from
'
./repo_file_buttons.vue
'
;
import
ideStatusBar
from
'
./ide_status_bar.vue
'
;
import
repoEditor
from
'
./repo_editor.vue
'
;
export
default
{
components
:
{
ideSidebar
,
ideContextbar
,
repoTabs
,
repoFileButtons
,
ideStatusBar
,
repoEditor
,
export
default
{
components
:
{
ideSidebar
,
ideContextbar
,
repoTabs
,
repoFileButtons
,
ideStatusBar
,
repoEditor
,
},
props
:
{
emptyStateSvgPath
:
{
type
:
String
,
required
:
true
,
},
props
:
{
emptyStateSvgPath
:
{
type
:
String
,
required
:
true
,
},
noChangesStateSvgPath
:
{
type
:
String
,
required
:
true
,
},
committedStateSvgPath
:
{
type
:
String
,
required
:
true
,
},
noChangesStateSvgPath
:
{
type
:
String
,
required
:
true
,
},
com
puted
:
{
...
mapState
([
'
changedFiles
'
,
'
openFiles
'
,
'
viewer
'
])
,
...
mapGetters
([
'
activeFile
'
,
'
hasChanges
'
])
,
com
mittedStateSvgPath
:
{
type
:
String
,
required
:
true
,
},
mounted
()
{
const
returnValue
=
'
Are you sure you want to lose unsaved changes?
'
;
window
.
onbeforeunload
=
e
=>
{
if
(
!
this
.
changedFiles
.
length
)
return
undefined
;
},
computed
:
{
...
mapState
([
'
changedFiles
'
,
'
openFiles
'
,
'
viewer
'
,
'
currentMergeRequestId
'
]),
...
mapGetters
([
'
activeFile
'
,
'
hasChanges
'
]),
},
mounted
()
{
const
returnValue
=
'
Are you sure you want to lose unsaved changes?
'
;
window
.
onbeforeunload
=
e
=>
{
if
(
!
this
.
changedFiles
.
length
)
return
undefined
;
Object
.
assign
(
e
,
{
returnValue
,
});
return
returnValue
;
};
},
};
Object
.
assign
(
e
,
{
returnValue
,
});
return
returnValue
;
};
},
};
</
script
>
<
template
>
...
...
@@ -63,6 +63,7 @@
:files=
"openFiles"
:viewer=
"viewer"
:has-changes=
"hasChanges"
:merge-request-id=
"currentMergeRequestId"
/>
<repo-editor
class=
"multi-file-edit-pane-content"
...
...
app/assets/javascripts/ide/components/mr_file_icon.vue
0 → 100644
View file @
436891da
<
script
>
import
icon
from
'
~/vue_shared/components/icon.vue
'
;
import
tooltip
from
'
~/vue_shared/directives/tooltip
'
;
export
default
{
components
:
{
icon
,
},
directives
:
{
tooltip
,
},
};
</
script
>
<
template
>
<icon
name=
"git-merge"
v-tooltip
title=
"__('Part of merge request changes')"
css-classes=
"ide-file-changed-icon"
:size=
"12"
/>
</
template
>
app/assets/javascripts/ide/components/repo_editor.vue
View file @
436891da
<
script
>
/* global monaco */
import
{
mapState
,
mapActions
}
from
'
vuex
'
;
import
{
mapState
,
map
Getters
,
map
Actions
}
from
'
vuex
'
;
import
flash
from
'
~/flash
'
;
import
monacoLoader
from
'
../monaco_loader
'
;
import
Editor
from
'
../lib/editor
'
;
...
...
@@ -13,12 +13,8 @@ export default {
},
},
computed
:
{
...
mapState
([
'
leftPanelCollapsed
'
,
'
rightPanelCollapsed
'
,
'
viewer
'
,
'
delayViewerUpdated
'
,
]),
...
mapState
([
'
leftPanelCollapsed
'
,
'
rightPanelCollapsed
'
,
'
viewer
'
,
'
delayViewerUpdated
'
]),
...
mapGetters
([
'
currentMergeRequest
'
]),
shouldHideEditor
()
{
return
this
.
file
&&
this
.
file
.
binary
&&
!
this
.
file
.
raw
;
},
...
...
@@ -68,9 +64,14 @@ export default {
this
.
editor
.
clearEditor
();
this
.
getRawFileData
(
this
.
file
)
this
.
getRawFileData
({
path
:
this
.
file
.
path
,
baseSha
:
this
.
currentMergeRequest
?
this
.
currentMergeRequest
.
baseCommitSha
:
''
,
})
.
then
(()
=>
{
const
viewerPromise
=
this
.
delayViewerUpdated
?
this
.
updateViewer
(
'
editor
'
)
:
Promise
.
resolve
();
const
viewerPromise
=
this
.
delayViewerUpdated
?
this
.
updateViewer
(
'
editor
'
)
:
Promise
.
resolve
();
return
viewerPromise
;
})
...
...
@@ -78,7 +79,7 @@ export default {
this
.
updateDelayViewerUpdated
(
false
);
this
.
createEditorInstance
();
})
.
catch
(
(
err
)
=>
{
.
catch
(
err
=>
{
flash
(
'
Error setting up monaco. Please try again.
'
,
'
alert
'
,
document
,
null
,
false
,
true
);
throw
err
;
});
...
...
@@ -101,9 +102,13 @@ export default {
this
.
model
=
this
.
editor
.
createModel
(
this
.
file
);
this
.
editor
.
attachModel
(
this
.
model
);
if
(
this
.
viewer
===
'
mrdiff
'
)
{
this
.
editor
.
attachMergeRequestModel
(
this
.
model
);
}
else
{
this
.
editor
.
attachModel
(
this
.
model
);
}
this
.
model
.
onChange
(
(
model
)
=>
{
this
.
model
.
onChange
(
model
=>
{
const
{
file
}
=
model
;
if
(
file
.
active
)
{
...
...
app/assets/javascripts/ide/components/repo_file.vue
View file @
436891da
...
...
@@ -6,6 +6,7 @@ import router from '../ide_router';
import
newDropdown
from
'
./new_dropdown/index.vue
'
;
import
fileStatusIcon
from
'
./repo_file_status_icon.vue
'
;
import
changedFileIcon
from
'
./changed_file_icon.vue
'
;
import
mrFileIcon
from
'
./mr_file_icon.vue
'
;
export
default
{
name
:
'
RepoFile
'
,
...
...
@@ -15,6 +16,7 @@ export default {
fileStatusIcon
,
fileIcon
,
changedFileIcon
,
mrFileIcon
,
},
props
:
{
file
:
{
...
...
@@ -56,10 +58,7 @@ export default {
...
mapActions
([
'
toggleTreeOpen
'
,
'
updateDelayViewerUpdated
'
]),
clickFile
()
{
// Manual Action if a tree is selected/opened
if
(
this
.
isTree
&&
this
.
$router
.
currentRoute
.
path
===
`/project
${
this
.
file
.
url
}
`
)
{
if
(
this
.
isTree
&&
this
.
$router
.
currentRoute
.
path
===
`/project
${
this
.
file
.
url
}
`
)
{
this
.
toggleTreeOpen
(
this
.
file
.
path
);
}
...
...
@@ -102,11 +101,15 @@ export default {
:file=
"file"
/>
</span>
<changed-file-icon
:file=
"file"
v-if=
"file.changed || file.tempFile"
class=
"prepend-top-5 pull-right"
/>
<span
class=
"pull-right"
>
<mr-file-icon
v-if=
"file.mrChange"
/>
<changed-file-icon
:file=
"file"
v-if=
"file.changed || file.tempFile"
/>
</span>
<new-dropdown
v-if=
"isTree"
:project-id=
"file.projectId"
...
...
app/assets/javascripts/ide/components/repo_file_status_icon.vue
View file @
436891da
<
script
>
import
icon
from
'
~/vue_shared/components/icon.vue
'
;
import
tooltip
from
'
~/vue_shared/directives/tooltip
'
;
import
'
~/lib/utils/datetime_utility
'
;
import
icon
from
'
~/vue_shared/components/icon.vue
'
;
import
tooltip
from
'
~/vue_shared/directives/tooltip
'
;
import
'
~/lib/utils/datetime_utility
'
;
export
default
{
components
:
{
icon
,
export
default
{
components
:
{
icon
,
},
directives
:
{
tooltip
,
},
props
:
{
file
:
{
type
:
Object
,
required
:
true
,
},
directives
:
{
tooltip
,
},
computed
:
{
lockTooltip
()
{
return
`Locked by
${
this
.
file
.
file_lock
.
user
.
name
}
`
;
},
props
:
{
file
:
{
type
:
Object
,
required
:
true
,
},
},
computed
:
{
lockTooltip
()
{
return
`Locked by
${
this
.
file
.
file_lock
.
user
.
name
}
`
;
},
},
};
},
};
</
script
>
<
template
>
...
...
app/assets/javascripts/ide/components/repo_tabs.vue
View file @
436891da
<
script
>
import
{
mapActions
}
from
'
vuex
'
;
import
RepoTab
from
'
./repo_tab.vue
'
;
import
EditorMode
from
'
./editor_mode_dropdown.vue
'
;
import
{
mapActions
}
from
'
vuex
'
;
import
RepoTab
from
'
./repo_tab.vue
'
;
import
EditorMode
from
'
./editor_mode_dropdown.vue
'
;
export
default
{
components
:
{
RepoTab
,
EditorMode
,
export
default
{
components
:
{
RepoTab
,
EditorMode
,
},
props
:
{
files
:
{
type
:
Array
,
required
:
true
,
},
props
:
{
files
:
{
type
:
Array
,
required
:
true
,
},
viewer
:
{
type
:
String
,
required
:
true
,
},
hasChanges
:
{
type
:
Boolean
,
required
:
true
,
},
viewer
:
{
type
:
String
,
required
:
true
,
},
data
()
{
return
{
showShadow
:
false
,
};
hasChanges
:
{
type
:
Boolean
,
required
:
true
,
},
updated
()
{
if
(
!
this
.
$refs
.
tabsScroller
)
return
;
this
.
showShadow
=
this
.
$refs
.
tabsScroller
.
scrollWidth
>
this
.
$refs
.
tabsScroller
.
offsetWidth
;
},
methods
:
{
...
mapActions
([
'
updateViewer
'
]),
mergeRequestId
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
};
},
data
()
{
return
{
showShadow
:
false
,
};
},
updated
()
{
if
(
!
this
.
$refs
.
tabsScroller
)
return
;
this
.
showShadow
=
this
.
$refs
.
tabsScroller
.
scrollWidth
>
this
.
$refs
.
tabsScroller
.
offsetWidth
;
},
methods
:
{
...
mapActions
([
'
updateViewer
'
]),
},
};
</
script
>
<
template
>
...
...
@@ -55,6 +59,7 @@
:viewer=
"viewer"
:show-shadow=
"showShadow"
:has-changes=
"hasChanges"
:merge-request-id=
"mergeRequestId"
@
click=
"updateViewer"
/>
</div>
...
...
app/assets/javascripts/ide/ide_router.js
View file @
436891da
...
...
@@ -44,7 +44,7 @@ const router = new VueRouter({
component
:
EmptyRouterComponent
,
},
{
path
:
'
m
r
/:mrid
'
,
path
:
'
m
erge_requests
/:mrid
'
,
component
:
EmptyRouterComponent
,
},
],
...
...
@@ -76,9 +76,7 @@ router.beforeEach((to, from, next) => {
.
then
(()
=>
{
if
(
to
.
params
[
0
])
{
const
path
=
to
.
params
[
0
].
slice
(
-
1
)
===
'
/
'
?
to
.
params
[
0
].
slice
(
0
,
-
1
)
:
to
.
params
[
0
];
to
.
params
[
0
].
slice
(
-
1
)
===
'
/
'
?
to
.
params
[
0
].
slice
(
0
,
-
1
)
:
to
.
params
[
0
];
const
treeEntry
=
store
.
state
.
entries
[
path
];
if
(
treeEntry
)
{
store
.
dispatch
(
'
handleTreeEntryAction
'
,
treeEntry
);
...
...
@@ -96,6 +94,60 @@ router.beforeEach((to, from, next) => {
);
throw
e
;
});
}
else
if
(
to
.
params
.
mrid
)
{
store
.
dispatch
(
'
updateViewer
'
,
'
mrdiff
'
);
store
.
dispatch
(
'
getMergeRequestData
'
,
{
projectId
:
fullProjectId
,
mergeRequestId
:
to
.
params
.
mrid
,
})
.
then
(
mr
=>
{
store
.
dispatch
(
'
getBranchData
'
,
{
projectId
:
fullProjectId
,
branchId
:
mr
.
source_branch
,
});
return
store
.
dispatch
(
'
getFiles
'
,
{
projectId
:
fullProjectId
,
branchId
:
mr
.
source_branch
,
});
})
.
then
(()
=>
store
.
dispatch
(
'
getMergeRequestVersions
'
,
{
projectId
:
fullProjectId
,
mergeRequestId
:
to
.
params
.
mrid
,
}),
)
.
then
(()
=>
store
.
dispatch
(
'
getMergeRequestChanges
'
,
{
projectId
:
fullProjectId
,
mergeRequestId
:
to
.
params
.
mrid
,
}),
)
.
then
(
mrChanges
=>
{
mrChanges
.
changes
.
forEach
((
change
,
ind
)
=>
{
const
changeTreeEntry
=
store
.
state
.
entries
[
change
.
new_path
];
if
(
changeTreeEntry
)
{
store
.
dispatch
(
'
setFileMrChange
'
,
{
file
:
changeTreeEntry
,
mrChange
:
change
,
});
if
(
ind
<
10
)
{
store
.
dispatch
(
'
getFileData
'
,
{
path
:
change
.
new_path
,
makeFileActive
:
ind
===
0
,
});
}
}
});
})
.
catch
(
e
=>
{
flash
(
'
Error while loading the merge request. Please try again.
'
);
throw
e
;
});
}
})
.
catch
(
e
=>
{
...
...
app/assets/javascripts/ide/lib/common/model.js
View file @
436891da
...
...
@@ -21,6 +21,15 @@ export default class Model {
new
this
.
monaco
.
Uri
(
null
,
null
,
this
.
file
.
path
),
)),
);
if
(
this
.
file
.
mrChange
)
{
this
.
disposable
.
add
(
(
this
.
baseModel
=
this
.
monaco
.
editor
.
createModel
(
this
.
file
.
baseRaw
,
undefined
,
new
this
.
monaco
.
Uri
(
null
,
null
,
`target/
${
this
.
file
.
path
}
`
),
)),
);
}
this
.
events
=
new
Map
();
...
...
@@ -28,10 +37,7 @@ export default class Model {
this
.
dispose
=
this
.
dispose
.
bind
(
this
);
eventHub
.
$on
(
`editor.update.model.dispose.
${
this
.
file
.
path
}
`
,
this
.
dispose
);
eventHub
.
$on
(
`editor.update.model.content.
${
this
.
file
.
path
}
`
,
this
.
updateContent
,
);
eventHub
.
$on
(
`editor.update.model.content.
${
this
.
file
.
path
}
`
,
this
.
updateContent
);
}
get
url
()
{
...
...
@@ -58,6 +64,10 @@ export default class Model {
return
this
.
originalModel
;
}
getBaseModel
()
{
return
this
.
baseModel
;
}
setValue
(
value
)
{
this
.
getModel
().
setValue
(
value
);
}
...
...
@@ -78,13 +88,7 @@ export default class Model {
this
.
disposable
.
dispose
();
this
.
events
.
clear
();
eventHub
.
$off
(
`editor.update.model.dispose.
${
this
.
file
.
path
}
`
,
this
.
dispose
,
);
eventHub
.
$off
(
`editor.update.model.content.
${
this
.
file
.
path
}
`
,
this
.
updateContent
,
);
eventHub
.
$off
(
`editor.update.model.dispose.
${
this
.
file
.
path
}
`
,
this
.
dispose
);
eventHub
.
$off
(
`editor.update.model.content.
${
this
.
file
.
path
}
`
,
this
.
updateContent
);
}
}
app/assets/javascripts/ide/lib/editor.js
View file @
436891da
...
...
@@ -109,11 +109,19 @@ export default class Editor {
if
(
this
.
dirtyDiffController
)
this
.
dirtyDiffController
.
reDecorate
(
model
);
}
attachMergeRequestModel
(
model
)
{
this
.
instance
.
setModel
({
original
:
model
.
getBaseModel
(),
modified
:
model
.
getModel
(),
});
this
.
monaco
.
editor
.
createDiffNavigator
(
this
.
instance
,
{
alwaysRevealFirst
:
true
,
});
}
setupMonacoTheme
()
{
this
.
monaco
.
editor
.
defineTheme
(
gitlabTheme
.
themeName
,
gitlabTheme
.
monacoTheme
,
);
this
.
monaco
.
editor
.
defineTheme
(
gitlabTheme
.
themeName
,
gitlabTheme
.
monacoTheme
);
this
.
monaco
.
editor
.
setTheme
(
'
gitlab
'
);
}
...
...
@@ -161,8 +169,6 @@ export default class Editor {
onPositionChange
(
cb
)
{
if
(
!
this
.
instance
.
onDidChangeCursorPosition
)
return
;
this
.
disposable
.
add
(
this
.
instance
.
onDidChangeCursorPosition
(
e
=>
cb
(
this
.
instance
,
e
)),
);
this
.
disposable
.
add
(
this
.
instance
.
onDidChangeCursorPosition
(
e
=>
cb
(
this
.
instance
,
e
)));
}
}
app/assets/javascripts/ide/services/index.js
View file @
436891da
...
...
@@ -20,12 +20,35 @@ export default {
return
Promise
.
resolve
(
file
.
raw
);
}
return
Vue
.
http
.
get
(
file
.
rawPath
,
{
params
:
{
format
:
'
json
'
}
})
return
Vue
.
http
.
get
(
file
.
rawPath
,
{
params
:
{
format
:
'
json
'
}
}).
then
(
res
=>
res
.
text
());
},
getBaseRawFileData
(
file
,
sha
)
{
if
(
file
.
tempFile
)
{
return
Promise
.
resolve
(
file
.
baseRaw
);
}
if
(
file
.
baseRaw
)
{
return
Promise
.
resolve
(
file
.
baseRaw
);
}
return
Vue
.
http
.
get
(
file
.
rawPath
.
replace
(
`/raw/
${
file
.
branchId
}
/
${
file
.
path
}
`
,
`/raw/
${
sha
}
/
${
file
.
path
}
`
),
{
params
:
{
format
:
'
json
'
},
})
.
then
(
res
=>
res
.
text
());
},
getProjectData
(
namespace
,
project
)
{
return
Api
.
project
(
`
${
namespace
}
/
${
project
}
`
);
},
getProjectMergeRequestData
(
projectId
,
mergeRequestId
)
{
return
Api
.
mergeRequest
(
projectId
,
mergeRequestId
);
},
getProjectMergeRequestChanges
(
projectId
,
mergeRequestId
)
{
return
Api
.
mergeRequestChanges
(
projectId
,
mergeRequestId
);
},
getProjectMergeRequestVersions
(
projectId
,
mergeRequestId
)
{
return
Api
.
mergeRequestVersions
(
projectId
,
mergeRequestId
);
},
getBranchData
(
projectId
,
currentBranchId
)
{
return
Api
.
branchSingle
(
projectId
,
currentBranchId
);
},
...
...
app/assets/javascripts/ide/stores/actions.js
View file @
436891da
...
...
@@ -6,8 +6,7 @@ import FilesDecoratorWorker from './workers/files_decorator_worker';
export
const
redirectToUrl
=
(
_
,
url
)
=>
visitUrl
(
url
);
export
const
setInitialData
=
({
commit
},
data
)
=>
commit
(
types
.
SET_INITIAL_DATA
,
data
);
export
const
setInitialData
=
({
commit
},
data
)
=>
commit
(
types
.
SET_INITIAL_DATA
,
data
);
export
const
discardAllChanges
=
({
state
,
commit
,
dispatch
})
=>
{
state
.
changedFiles
.
forEach
(
file
=>
{
...
...
@@ -43,14 +42,11 @@ export const createTempEntry = (
)
=>
new
Promise
(
resolve
=>
{
const
worker
=
new
FilesDecoratorWorker
();
const
fullName
=
name
.
slice
(
-
1
)
!==
'
/
'
&&
type
===
'
tree
'
?
`
${
name
}
/`
:
name
;
const
fullName
=
name
.
slice
(
-
1
)
!==
'
/
'
&&
type
===
'
tree
'
?
`
${
name
}
/`
:
name
;
if
(
state
.
entries
[
name
])
{
flash
(
`The name "
${
name
.
split
(
'
/
'
)
.
pop
()}
" is already taken in this directory.`
,
`The name "
${
name
.
split
(
'
/
'
).
pop
()}
" is already taken in this directory.`
,
'
alert
'
,
document
,
null
,
...
...
@@ -119,3 +115,4 @@ export const updateDelayViewerUpdated = ({ commit }, delay) => {
export
*
from
'
./actions/tree
'
;
export
*
from
'
./actions/file
'
;
export
*
from
'
./actions/project
'
;
export
*
from
'
./actions/merge_request
'
;
app/assets/javascripts/ide/stores/actions/file.js
View file @
436891da
...
...
@@ -46,53 +46,63 @@ export const setFileActive = ({ commit, state, getters, dispatch }, path) => {
commit
(
types
.
SET_CURRENT_BRANCH
,
file
.
branchId
);
};
export
const
getFileData
=
({
state
,
commit
,
dispatch
},
file
)
=>
{
export
const
getFileData
=
({
state
,
commit
,
dispatch
},
{
path
,
makeFileActive
=
true
})
=>
{
const
file
=
state
.
entries
[
path
];
commit
(
types
.
TOGGLE_LOADING
,
{
entry
:
file
});
return
service
.
getFileData
(
file
.
url
)
.
then
(
res
=>
{
const
pageTitle
=
decodeURI
(
normalizeHeaders
(
res
.
headers
)[
'
PAGE-TITLE
'
]);
setPageTitle
(
pageTitle
);
return
res
.
json
();
})
.
then
(
data
=>
{
commit
(
types
.
SET_FILE_DATA
,
{
data
,
file
});
commit
(
types
.
TOGGLE_FILE_OPEN
,
file
.
path
);
dispatch
(
'
setFileActive
'
,
file
.
path
);
commit
(
types
.
TOGGLE_FILE_OPEN
,
path
);
if
(
makeFileActive
)
dispatch
(
'
setFileActive
'
,
path
);
commit
(
types
.
TOGGLE_LOADING
,
{
entry
:
file
});
})
.
catch
(()
=>
{
commit
(
types
.
TOGGLE_LOADING
,
{
entry
:
file
});
flash
(
'
Error loading file data. Please try again.
'
,
'
alert
'
,
document
,
null
,
false
,
true
,
);
flash
(
'
Error loading file data. Please try again.
'
,
'
alert
'
,
document
,
null
,
false
,
true
);
});
};
export
const
getRawFileData
=
({
commit
,
dispatch
},
file
)
=>
service
.
getRawFileData
(
file
)
.
then
(
raw
=>
{
commit
(
types
.
SET_FILE_RAW_DATA
,
{
file
,
raw
});
})
.
catch
(()
=>
flash
(
'
Error loading file content. Please try again.
'
,
'
alert
'
,
document
,
null
,
false
,
true
,
),
);
export
const
setFileMrChange
=
({
state
,
commit
},
{
file
,
mrChange
})
=>
{
commit
(
types
.
SET_FILE_MERGE_REQUEST_CHANGE
,
{
file
,
mrChange
});
};
export
const
getRawFileData
=
({
state
,
commit
,
dispatch
},
{
path
,
baseSha
})
=>
{
const
file
=
state
.
entries
[
path
];
return
new
Promise
((
resolve
,
reject
)
=>
{
service
.
getRawFileData
(
file
)
.
then
(
raw
=>
{
commit
(
types
.
SET_FILE_RAW_DATA
,
{
file
,
raw
});
if
(
file
.
mrChange
&&
file
.
mrChange
.
new_file
===
false
)
{
service
.
getBaseRawFileData
(
file
,
baseSha
)
.
then
(
baseRaw
=>
{
commit
(
types
.
SET_FILE_BASE_RAW_DATA
,
{
file
,
baseRaw
,
});
resolve
(
raw
);
})
.
catch
(
e
=>
{
reject
(
e
);
});
}
else
{
resolve
(
raw
);
}
})
.
catch
(()
=>
{
flash
(
'
Error loading file content. Please try again.
'
);
reject
();
});
});
};
export
const
changeFileContent
=
({
state
,
commit
},
{
path
,
content
})
=>
{
const
file
=
state
.
entries
[
path
];
...
...
@@ -119,10 +129,7 @@ export const setFileEOL = ({ getters, commit }, { eol }) => {
}
};
export
const
setEditorPosition
=
(
{
getters
,
commit
},
{
editorRow
,
editorColumn
},
)
=>
{
export
const
setEditorPosition
=
({
getters
,
commit
},
{
editorRow
,
editorColumn
})
=>
{
if
(
getters
.
activeFile
)
{
commit
(
types
.
SET_FILE_POSITION
,
{
file
:
getters
.
activeFile
,
...
...
app/assets/javascripts/ide/stores/actions/merge_request.js
0 → 100644
View file @
436891da
import
flash
from
'
~/flash
'
;
import
service
from
'
../../services
'
;
import
*
as
types
from
'
../mutation_types
'
;
export
const
getMergeRequestData
=
(
{
commit
,
state
,
dispatch
},
{
projectId
,
mergeRequestId
,
force
=
false
}
=
{},
)
=>
new
Promise
((
resolve
,
reject
)
=>
{
if
(
!
state
.
projects
[
projectId
].
mergeRequests
[
mergeRequestId
]
||
force
)
{
service
.
getProjectMergeRequestData
(
projectId
,
mergeRequestId
)
.
then
(
res
=>
res
.
data
)
.
then
(
data
=>
{
commit
(
types
.
SET_MERGE_REQUEST
,
{
projectPath
:
projectId
,
mergeRequestId
,
mergeRequest
:
data
,
});
if
(
!
state
.
currentMergeRequestId
)
{
commit
(
types
.
SET_CURRENT_MERGE_REQUEST
,
mergeRequestId
);
}
resolve
(
data
);
})
.
catch
(()
=>
{
flash
(
'
Error loading merge request data. Please try again.
'
);
reject
(
new
Error
(
`Merge Request not loaded
${
projectId
}
`
));
});
}
else
{
resolve
(
state
.
projects
[
projectId
].
mergeRequests
[
mergeRequestId
]);
}
});
export
const
getMergeRequestChanges
=
(
{
commit
,
state
,
dispatch
},
{
projectId
,
mergeRequestId
,
force
=
false
}
=
{},
)
=>
new
Promise
((
resolve
,
reject
)
=>
{
if
(
!
state
.
projects
[
projectId
].
mergeRequests
[
mergeRequestId
].
changes
.
length
||
force
)
{
service
.
getProjectMergeRequestChanges
(
projectId
,
mergeRequestId
)
.
then
(
res
=>
res
.
data
)
.
then
(
data
=>
{
commit
(
types
.
SET_MERGE_REQUEST_CHANGES
,
{
projectPath
:
projectId
,
mergeRequestId
,
changes
:
data
,
});
resolve
(
data
);
})
.
catch
(()
=>
{
flash
(
'
Error loading merge request changes. Please try again.
'
);
reject
(
new
Error
(
`Merge Request Changes not loaded
${
projectId
}
`
));
});
}
else
{
resolve
(
state
.
projects
[
projectId
].
mergeRequests
[
mergeRequestId
].
changes
);
}
});
export
const
getMergeRequestVersions
=
(
{
commit
,
state
,
dispatch
},
{
projectId
,
mergeRequestId
,
force
=
false
}
=
{},
)
=>
new
Promise
((
resolve
,
reject
)
=>
{
if
(
!
state
.
projects
[
projectId
].
mergeRequests
[
mergeRequestId
].
versions
.
length
||
force
)
{
service
.
getProjectMergeRequestVersions
(
projectId
,
mergeRequestId
)
.
then
(
res
=>
res
.
data
)
.
then
(
data
=>
{
commit
(
types
.
SET_MERGE_REQUEST_VERSIONS
,
{
projectPath
:
projectId
,
mergeRequestId
,
versions
:
data
,
});
resolve
(
data
);
})
.
catch
(()
=>
{
flash
(
'
Error loading merge request versions. Please try again.
'
);
reject
(
new
Error
(
`Merge Request Versions not loaded
${
projectId
}
`
));
});
}
else
{
resolve
(
state
.
projects
[
projectId
].
mergeRequests
[
mergeRequestId
].
versions
);
}
});
app/assets/javascripts/ide/stores/actions/tree.js
View file @
436891da
...
...
@@ -2,9 +2,7 @@ import { normalizeHeaders } from '~/lib/utils/common_utils';
import
flash
from
'
~/flash
'
;
import
service
from
'
../../services
'
;
import
*
as
types
from
'
../mutation_types
'
;
import
{
findEntry
,
}
from
'
../utils
'
;
import
{
findEntry
}
from
'
../utils
'
;
import
FilesDecoratorWorker
from
'
../workers/files_decorator_worker
'
;
export
const
toggleTreeOpen
=
({
commit
,
dispatch
},
path
)
=>
{
...
...
@@ -21,23 +19,24 @@ export const handleTreeEntryAction = ({ commit, dispatch }, row) => {
dispatch
(
'
setFileActive
'
,
row
.
path
);
}
else
{
dispatch
(
'
getFileData
'
,
row
);
dispatch
(
'
getFileData
'
,
{
path
:
row
.
path
}
);
}
};
export
const
getLastCommitData
=
({
state
,
commit
,
dispatch
,
getters
},
tree
=
state
)
=>
{
if
(
!
tree
||
tree
.
lastCommitPath
===
null
||
!
tree
.
lastCommitPath
)
return
;
service
.
getTreeLastCommit
(
tree
.
lastCommitPath
)
.
then
((
res
)
=>
{
service
.
getTreeLastCommit
(
tree
.
lastCommitPath
)
.
then
(
res
=>
{
const
lastCommitPath
=
normalizeHeaders
(
res
.
headers
)[
'
MORE-LOGS-URL
'
]
||
null
;
commit
(
types
.
SET_LAST_COMMIT_URL
,
{
tree
,
url
:
lastCommitPath
});
return
res
.
json
();
})
.
then
(
(
data
)
=>
{
data
.
forEach
(
(
lastCommit
)
=>
{
.
then
(
data
=>
{
data
.
forEach
(
lastCommit
=>
{
const
entry
=
findEntry
(
tree
.
tree
,
lastCommit
.
type
,
lastCommit
.
file_name
);
if
(
entry
)
{
...
...
@@ -50,44 +49,47 @@ export const getLastCommitData = ({ state, commit, dispatch, getters }, tree = s
.
catch
(()
=>
flash
(
'
Error fetching log data.
'
,
'
alert
'
,
document
,
null
,
false
,
true
));
};
export
const
getFiles
=
(
{
state
,
commit
,
dispatch
},
{
projectId
,
branchId
}
=
{},
)
=>
new
Promise
((
resolve
,
reject
)
=>
{
if
(
!
state
.
trees
[
`
${
projectId
}
/
${
branchId
}
`
])
{
const
selectedProject
=
state
.
projects
[
projectId
];
commit
(
types
.
CREATE_TREE
,
{
treePath
:
`
${
projectId
}
/
${
branchId
}
`
});
service
.
getFiles
(
selectedProject
.
web_url
,
branchId
)
.
then
(
res
=>
res
.
json
())
.
then
((
data
)
=>
{
const
worker
=
new
FilesDecoratorWorker
();
worker
.
addEventListener
(
'
message
'
,
(
e
)
=>
{
const
{
entries
,
treeList
}
=
e
.
data
;
const
selectedTree
=
state
.
trees
[
`
${
projectId
}
/
${
branchId
}
`
];
commit
(
types
.
SET_ENTRIES
,
entries
);
commit
(
types
.
SET_DIRECTORY_DATA
,
{
treePath
:
`
${
projectId
}
/
${
branchId
}
`
,
data
:
treeList
});
commit
(
types
.
TOGGLE_LOADING
,
{
entry
:
selectedTree
,
forceValue
:
false
});
worker
.
terminate
();
resolve
();
});
worker
.
postMessage
({
data
,
projectId
,
branchId
,
export
const
getFiles
=
({
state
,
commit
,
dispatch
},
{
projectId
,
branchId
}
=
{})
=>
new
Promise
((
resolve
,
reject
)
=>
{
if
(
!
state
.
trees
[
`
${
projectId
}
/
${
branchId
}
`
])
{
const
selectedProject
=
state
.
projects
[
projectId
];
commit
(
types
.
CREATE_TREE
,
{
treePath
:
`
${
projectId
}
/
${
branchId
}
`
});
service
.
getFiles
(
selectedProject
.
web_url
,
branchId
)
.
then
(
res
=>
res
.
json
())
.
then
(
data
=>
{
const
worker
=
new
FilesDecoratorWorker
();
worker
.
addEventListener
(
'
message
'
,
e
=>
{
const
{
entries
,
treeList
}
=
e
.
data
;
const
selectedTree
=
state
.
trees
[
`
${
projectId
}
/
${
branchId
}
`
];
commit
(
types
.
SET_ENTRIES
,
entries
);
commit
(
types
.
SET_DIRECTORY_DATA
,
{
treePath
:
`
${
projectId
}
/
${
branchId
}
`
,
data
:
treeList
,
});
commit
(
types
.
TOGGLE_LOADING
,
{
entry
:
selectedTree
,
forceValue
:
false
,
});
worker
.
terminate
();
resolve
();
});
worker
.
postMessage
({
data
,
projectId
,
branchId
,
});
})
.
catch
(
e
=>
{
flash
(
'
Error loading tree data. Please try again.
'
,
'
alert
'
,
document
,
null
,
false
,
true
);
reject
(
e
);
});
})
.
catch
((
e
)
=>
{
flash
(
'
Error loading tree data. Please try again.
'
,
'
alert
'
,
document
,
null
,
false
,
true
);
reject
(
e
);
});
}
else
{
resolve
();
}
});
}
else
{
resolve
();
}
});
app/assets/javascripts/ide/stores/getters.js
View file @
436891da
export
const
activeFile
=
state
=>
state
.
openFiles
.
find
(
file
=>
file
.
active
)
||
null
;
export
const
activeFile
=
state
=>
state
.
openFiles
.
find
(
file
=>
file
.
active
)
||
null
;
export
const
addedFiles
=
state
=>
state
.
changedFiles
.
filter
(
f
=>
f
.
tempFile
);
export
const
modifiedFiles
=
state
=>
state
.
changedFiles
.
filter
(
f
=>
!
f
.
tempFile
);
export
const
modifiedFiles
=
state
=>
state
.
changedFiles
.
filter
(
f
=>
!
f
.
tempFile
);
export
const
projectsWithTrees
=
state
=>
Object
.
keys
(
state
.
projects
).
map
(
projectId
=>
{
...
...
@@ -23,8 +21,17 @@ export const projectsWithTrees = state =>
};
});
export
const
currentMergeRequest
=
state
=>
{
if
(
state
.
projects
[
state
.
currentProjectId
])
{
return
state
.
projects
[
state
.
currentProjectId
].
mergeRequests
[
state
.
currentMergeRequestId
];
}
return
null
;
};
// eslint-disable-next-line no-confusing-arrow
export
const
currentIcon
=
state
=>
state
.
rightPanelCollapsed
?
'
angle-double-left
'
:
'
angle-double-right
'
;
export
const
hasChanges
=
state
=>
!!
state
.
changedFiles
.
length
;
export
const
hasMergeRequest
=
state
=>
!!
state
.
currentMergeRequestId
;
app/assets/javascripts/ide/stores/mutation_types.js
View file @
436891da
...
...
@@ -11,6 +11,12 @@ export const SET_PROJECT = 'SET_PROJECT';
export
const
SET_CURRENT_PROJECT
=
'
SET_CURRENT_PROJECT
'
;
export
const
TOGGLE_PROJECT_OPEN
=
'
TOGGLE_PROJECT_OPEN
'
;
// Merge Request Mutation Types
export
const
SET_MERGE_REQUEST
=
'
SET_MERGE_REQUEST
'
;
export
const
SET_CURRENT_MERGE_REQUEST
=
'
SET_CURRENT_MERGE_REQUEST
'
;
export
const
SET_MERGE_REQUEST_CHANGES
=
'
SET_MERGE_REQUEST_CHANGES
'
;
export
const
SET_MERGE_REQUEST_VERSIONS
=
'
SET_MERGE_REQUEST_VERSIONS
'
;
// Branch Mutation Types
export
const
SET_BRANCH
=
'
SET_BRANCH
'
;
export
const
SET_BRANCH_WORKING_REFERENCE
=
'
SET_BRANCH_WORKING_REFERENCE
'
;
...
...
@@ -28,6 +34,7 @@ export const SET_FILE_DATA = 'SET_FILE_DATA';
export
const
TOGGLE_FILE_OPEN
=
'
TOGGLE_FILE_OPEN
'
;
export
const
SET_FILE_ACTIVE
=
'
SET_FILE_ACTIVE
'
;
export
const
SET_FILE_RAW_DATA
=
'
SET_FILE_RAW_DATA
'
;
export
const
SET_FILE_BASE_RAW_DATA
=
'
SET_FILE_BASE_RAW_DATA
'
;
export
const
UPDATE_FILE_CONTENT
=
'
UPDATE_FILE_CONTENT
'
;
export
const
SET_FILE_LANGUAGE
=
'
SET_FILE_LANGUAGE
'
;
export
const
SET_FILE_POSITION
=
'
SET_FILE_POSITION
'
;
...
...
@@ -39,5 +46,6 @@ export const TOGGLE_FILE_CHANGED = 'TOGGLE_FILE_CHANGED';
export
const
SET_CURRENT_BRANCH
=
'
SET_CURRENT_BRANCH
'
;
export
const
SET_ENTRIES
=
'
SET_ENTRIES
'
;
export
const
CREATE_TMP_ENTRY
=
'
CREATE_TMP_ENTRY
'
;
export
const
SET_FILE_MERGE_REQUEST_CHANGE
=
'
SET_FILE_MERGE_REQUEST_CHANGE
'
;
export
const
UPDATE_VIEWER
=
'
UPDATE_VIEWER
'
;
export
const
UPDATE_DELAY_VIEWER_CHANGE
=
'
UPDATE_DELAY_VIEWER_CHANGE
'
;
app/assets/javascripts/ide/stores/mutations.js
View file @
436891da
import
*
as
types
from
'
./mutation_types
'
;
import
projectMutations
from
'
./mutations/project
'
;
import
mergeRequestMutation
from
'
./mutations/merge_request
'
;
import
fileMutations
from
'
./mutations/file
'
;
import
treeMutations
from
'
./mutations/tree
'
;
import
branchMutations
from
'
./mutations/branch
'
;
...
...
@@ -11,10 +12,7 @@ export default {
[
types
.
TOGGLE_LOADING
](
state
,
{
entry
,
forceValue
=
undefined
})
{
if
(
entry
.
path
)
{
Object
.
assign
(
state
.
entries
[
entry
.
path
],
{
loading
:
forceValue
!==
undefined
?
forceValue
:
!
state
.
entries
[
entry
.
path
].
loading
,
loading
:
forceValue
!==
undefined
?
forceValue
:
!
state
.
entries
[
entry
.
path
].
loading
,
});
}
else
{
Object
.
assign
(
entry
,
{
...
...
@@ -83,9 +81,7 @@ export default {
if
(
!
foundEntry
)
{
Object
.
assign
(
state
.
trees
[
`
${
projectId
}
/
${
branchId
}
`
],
{
tree
:
state
.
trees
[
`
${
projectId
}
/
${
branchId
}
`
].
tree
.
concat
(
data
.
treeList
,
),
tree
:
state
.
trees
[
`
${
projectId
}
/
${
branchId
}
`
].
tree
.
concat
(
data
.
treeList
),
});
}
},
...
...
@@ -100,6 +96,7 @@ export default {
});
},
...
projectMutations
,
...
mergeRequestMutation
,
...
fileMutations
,
...
treeMutations
,
...
branchMutations
,
...
...
app/assets/javascripts/ide/stores/mutations/file.js
View file @
436891da
...
...
@@ -28,6 +28,8 @@ export default {
rawPath
:
data
.
raw_path
,
binary
:
data
.
binary
,
renderError
:
data
.
render_error
,
raw
:
null
,
baseRaw
:
null
,
});
},
[
types
.
SET_FILE_RAW_DATA
](
state
,
{
file
,
raw
})
{
...
...
@@ -35,6 +37,11 @@ export default {
raw
,
});
},
[
types
.
SET_FILE_BASE_RAW_DATA
](
state
,
{
file
,
baseRaw
})
{
Object
.
assign
(
state
.
entries
[
file
.
path
],
{
baseRaw
,
});
},
[
types
.
UPDATE_FILE_CONTENT
](
state
,
{
path
,
content
})
{
const
changed
=
content
!==
state
.
entries
[
path
].
raw
;
...
...
@@ -59,6 +66,11 @@ export default {
editorColumn
,
});
},
[
types
.
SET_FILE_MERGE_REQUEST_CHANGE
](
state
,
{
file
,
mrChange
})
{
Object
.
assign
(
state
.
entries
[
file
.
path
],
{
mrChange
,
});
},
[
types
.
DISCARD_FILE_CHANGES
](
state
,
path
)
{
Object
.
assign
(
state
.
entries
[
path
],
{
content
:
state
.
entries
[
path
].
raw
,
...
...
app/assets/javascripts/ide/stores/mutations/merge_request.js
0 → 100644
View file @
436891da
import
*
as
types
from
'
../mutation_types
'
;
export
default
{
[
types
.
SET_CURRENT_MERGE_REQUEST
](
state
,
currentMergeRequestId
)
{
Object
.
assign
(
state
,
{
currentMergeRequestId
,
});
},
[
types
.
SET_MERGE_REQUEST
](
state
,
{
projectPath
,
mergeRequestId
,
mergeRequest
})
{
Object
.
assign
(
state
.
projects
[
projectPath
],
{
mergeRequests
:
{
[
mergeRequestId
]:
{
...
mergeRequest
,
active
:
true
,
changes
:
[],
versions
:
[],
baseCommitSha
:
null
,
},
},
});
},
[
types
.
SET_MERGE_REQUEST_CHANGES
](
state
,
{
projectPath
,
mergeRequestId
,
changes
})
{
Object
.
assign
(
state
.
projects
[
projectPath
].
mergeRequests
[
mergeRequestId
],
{
changes
,
});
},
[
types
.
SET_MERGE_REQUEST_VERSIONS
](
state
,
{
projectPath
,
mergeRequestId
,
versions
})
{
Object
.
assign
(
state
.
projects
[
projectPath
].
mergeRequests
[
mergeRequestId
],
{
versions
,
baseCommitSha
:
versions
.
length
?
versions
[
0
].
base_commit_sha
:
null
,
});
},
};
app/assets/javascripts/ide/stores/mutations/project.js
View file @
436891da
...
...
@@ -11,6 +11,7 @@ export default {
Object
.
assign
(
project
,
{
tree
:
[],
branches
:
{},
mergeRequests
:
{},
active
:
true
,
});
...
...
app/assets/javascripts/ide/stores/state.js
View file @
436891da
export
default
()
=>
({
currentProjectId
:
''
,
currentBranchId
:
''
,
currentMergeRequestId
:
''
,
changedFiles
:
[],
endpoints
:
{},
lastCommitMsg
:
''
,
...
...
app/assets/javascripts/ide/stores/utils.js
View file @
436891da
...
...
@@ -38,7 +38,7 @@ export const dataStructure = () => ({
eol
:
''
,
});
export
const
decorateData
=
(
entity
)
=>
{
export
const
decorateData
=
entity
=>
{
const
{
id
,
projectId
,
...
...
@@ -57,7 +57,6 @@ export const decorateData = (entity) => {
base64
=
false
,
file_lock
,
}
=
entity
;
return
{
...
...
@@ -80,17 +79,15 @@ export const decorateData = (entity) => {
base64
,
file_lock
,
};
};
export
const
findEntry
=
(
tree
,
type
,
name
,
prop
=
'
name
'
)
=>
tree
.
find
(
f
=>
f
.
type
===
type
&&
f
[
prop
]
===
name
,
);
export
const
findEntry
=
(
tree
,
type
,
name
,
prop
=
'
name
'
)
=>
tree
.
find
(
f
=>
f
.
type
===
type
&&
f
[
prop
]
===
name
);
export
const
findIndexOfFile
=
(
state
,
file
)
=>
state
.
findIndex
(
f
=>
f
.
path
===
file
.
path
);
export
const
setPageTitle
=
(
title
)
=>
{
export
const
setPageTitle
=
title
=>
{
document
.
title
=
title
;
};
...
...
@@ -120,6 +117,11 @@ const sortTreesByTypeAndName = (a, b) => {
return
0
;
};
export
const
sortTree
=
sortedTree
=>
sortedTree
.
map
(
entity
=>
Object
.
assign
(
entity
,
{
tree
:
entity
.
tree
.
length
?
sortTree
(
entity
.
tree
)
:
[],
})).
sort
(
sortTreesByTypeAndName
);
export
const
sortTree
=
sortedTree
=>
sortedTree
.
map
(
entity
=>
Object
.
assign
(
entity
,
{
tree
:
entity
.
tree
.
length
?
sortTree
(
entity
.
tree
)
:
[],
}),
)
.
sort
(
sortTreesByTypeAndName
);
app/assets/javascripts/lib/utils/url_utility.js
View file @
436891da
...
...
@@ -51,7 +51,7 @@ export function removeParams(params) {
const
url
=
document
.
createElement
(
'
a
'
);
url
.
href
=
window
.
location
.
href
;
params
.
forEach
(
(
param
)
=>
{
params
.
forEach
(
param
=>
{
url
.
search
=
removeParamQueryString
(
url
.
search
,
param
);
});
...
...
@@ -83,3 +83,11 @@ export function refreshCurrentPage() {
export
function
redirectTo
(
url
)
{
return
window
.
location
.
assign
(
url
);
}
export
function
webIDEUrl
(
route
=
undefined
)
{
let
returnUrl
=
`
${
gon
.
relative_url_root
}
/-/ide/`
;
if
(
route
)
{
returnUrl
+=
`project
${
route
}
`
;
}
return
returnUrl
;
}
app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue
View file @
436891da
<
script
>
import
tooltip
from
'
~/vue_shared/directives/tooltip
'
;
import
{
n__
}
from
'
~/locale
'
;
import
icon
from
'
~/vue_shared/components/icon.vue
'
;
import
clipboardButton
from
'
~/vue_shared/components/clipboard_button.vue
'
;
import
tooltip
from
'
~/vue_shared/directives/tooltip
'
;
import
{
n__
}
from
'
~/locale
'
;
import
{
webIDEUrl
}
from
'
~/lib/utils/url_utility
'
;
import
icon
from
'
~/vue_shared/components/icon.vue
'
;
import
clipboardButton
from
'
~/vue_shared/components/clipboard_button.vue
'
;
export
default
{
name
:
'
MRWidgetHeader
'
,
directives
:
{
tooltip
,
export
default
{
name
:
'
MRWidgetHeader
'
,
directives
:
{
tooltip
,
},
components
:
{
icon
,
clipboardButton
,
},
props
:
{
mr
:
{
type
:
Object
,
required
:
true
,
},
components
:
{
icon
,
clipboardButton
,
},
computed
:
{
shouldShowCommitsBehindText
()
{
return
this
.
mr
.
divergedCommitsCount
>
0
;
},
props
:
{
mr
:
{
type
:
Object
,
required
:
true
,
},
commitsText
()
{
return
n__
(
'
%d commit behind
'
,
'
%d commits behind
'
,
this
.
mr
.
divergedCommitsCount
);
},
computed
:
{
shouldShowCommitsBehindText
()
{
return
this
.
mr
.
divergedCommitsCount
>
0
;
},
commitsText
()
{
return
n__
(
'
%d commit behind
'
,
'
%d commits behind
'
,
this
.
mr
.
divergedCommitsCount
);
},
branchNameClipboardData
()
{
// This supports code in app/assets/javascripts/copy_to_clipboard.js that
// works around ClipboardJS limitations to allow the context-specific
// copy/pasting of plain text or GFM.
return
JSON
.
stringify
({
text
:
this
.
mr
.
sourceBranch
,
gfm
:
`\`
${
this
.
mr
.
sourceBranch
}
\``
,
});
},
isSourceBranchLong
()
{
return
this
.
isBranchTitleLong
(
this
.
mr
.
sourceBranch
);
},
isTargetBranchLong
()
{
return
this
.
isBranchTitleLong
(
this
.
mr
.
targetBranch
);
},
branchNameClipboardData
()
{
// This supports code in app/assets/javascripts/copy_to_clipboard.js that
// works around ClipboardJS limitations to allow the context-specific
// copy/pasting of plain text or GFM.
return
JSON
.
stringify
({
text
:
this
.
mr
.
sourceBranch
,
gfm
:
`\`
${
this
.
mr
.
sourceBranch
}
\``
,
});
},
methods
:
{
isBranchTitleLong
(
branchTitle
)
{
return
branchTitle
.
length
>
32
;
},
isSourceBranchLong
()
{
return
this
.
isBranchTitleLong
(
this
.
mr
.
sourceBranch
);
},
};
isTargetBranchLong
()
{
return
this
.
isBranchTitleLong
(
this
.
mr
.
targetBranch
);
},
webIdePath
()
{
return
webIDEUrl
(
this
.
mr
.
statusPath
.
replace
(
'
.json
'
,
''
));
},
},
methods
:
{
isBranchTitleLong
(
branchTitle
)
{
return
branchTitle
.
length
>
32
;
},
},
};
</
script
>
<
template
>
<div
class=
"mr-source-target"
>
...
...
@@ -96,6 +100,13 @@
</div>
<div
v-if=
"mr.isOpen"
>
<a
v-if=
"!mr.sourceBranchRemoved"
:href=
"webIdePath"
class=
"btn btn-sm btn-default inline js-web-ide"
>
{{
s__
(
"
mrWidget|Web IDE
"
)
}}
</a>
<button
data-target=
"#modal_merge_info"
data-toggle=
"modal"
...
...
app/assets/stylesheets/pages/repo.scss
View file @
436891da
...
...
@@ -53,6 +53,7 @@
flex
:
1
;
white-space
:
nowrap
;
text-overflow
:
ellipsis
;
max-width
:
inherit
;
svg
{
vertical-align
:
middle
;
...
...
spec/javascripts/api_spec.js
View file @
436891da
...
...
@@ -35,14 +35,14 @@ describe('Api', () => {
});
describe
(
'
group
'
,
()
=>
{
it
(
'
fetches a group
'
,
(
done
)
=>
{
it
(
'
fetches a group
'
,
done
=>
{
const
groupId
=
'
123456
'
;
const
expectedUrl
=
`
${
dummyUrlRoot
}
/api/
${
dummyApiVersion
}
/groups/
${
groupId
}
`
;
mock
.
onGet
(
expectedUrl
).
reply
(
200
,
{
name
:
'
test
'
,
});
Api
.
group
(
groupId
,
(
response
)
=>
{
Api
.
group
(
groupId
,
response
=>
{
expect
(
response
.
name
).
toBe
(
'
test
'
);
done
();
});
...
...
@@ -50,15 +50,17 @@ describe('Api', () => {
});
describe
(
'
groups
'
,
()
=>
{
it
(
'
fetches groups
'
,
(
done
)
=>
{
it
(
'
fetches groups
'
,
done
=>
{
const
query
=
'
dummy query
'
;
const
options
=
{
unused
:
'
option
'
};
const
expectedUrl
=
`
${
dummyUrlRoot
}
/api/
${
dummyApiVersion
}
/groups.json`
;
mock
.
onGet
(
expectedUrl
).
reply
(
200
,
[{
name
:
'
test
'
,
}]);
mock
.
onGet
(
expectedUrl
).
reply
(
200
,
[
{
name
:
'
test
'
,
},
]);
Api
.
groups
(
query
,
options
,
(
response
)
=>
{
Api
.
groups
(
query
,
options
,
response
=>
{
expect
(
response
.
length
).
toBe
(
1
);
expect
(
response
[
0
].
name
).
toBe
(
'
test
'
);
done
();
...
...
@@ -67,14 +69,16 @@ describe('Api', () => {
});
describe
(
'
namespaces
'
,
()
=>
{
it
(
'
fetches namespaces
'
,
(
done
)
=>
{
it
(
'
fetches namespaces
'
,
done
=>
{
const
query
=
'
dummy query
'
;
const
expectedUrl
=
`
${
dummyUrlRoot
}
/api/
${
dummyApiVersion
}
/namespaces.json`
;
mock
.
onGet
(
expectedUrl
).
reply
(
200
,
[{
name
:
'
test
'
,
}]);
mock
.
onGet
(
expectedUrl
).
reply
(
200
,
[
{
name
:
'
test
'
,
},
]);
Api
.
namespaces
(
query
,
(
response
)
=>
{
Api
.
namespaces
(
query
,
response
=>
{
expect
(
response
.
length
).
toBe
(
1
);
expect
(
response
[
0
].
name
).
toBe
(
'
test
'
);
done
();
...
...
@@ -83,31 +87,35 @@ describe('Api', () => {
});
describe
(
'
projects
'
,
()
=>
{
it
(
'
fetches projects with membership when logged in
'
,
(
done
)
=>
{
it
(
'
fetches projects with membership when logged in
'
,
done
=>
{
const
query
=
'
dummy query
'
;
const
options
=
{
unused
:
'
option
'
};
const
expectedUrl
=
`
${
dummyUrlRoot
}
/api/
${
dummyApiVersion
}
/projects.json`
;
window
.
gon
.
current_user_id
=
1
;
mock
.
onGet
(
expectedUrl
).
reply
(
200
,
[{
name
:
'
test
'
,
}]);
mock
.
onGet
(
expectedUrl
).
reply
(
200
,
[
{
name
:
'
test
'
,
},
]);
Api
.
projects
(
query
,
options
,
(
response
)
=>
{
Api
.
projects
(
query
,
options
,
response
=>
{
expect
(
response
.
length
).
toBe
(
1
);
expect
(
response
[
0
].
name
).
toBe
(
'
test
'
);
done
();
});
});
it
(
'
fetches projects without membership when not logged in
'
,
(
done
)
=>
{
it
(
'
fetches projects without membership when not logged in
'
,
done
=>
{
const
query
=
'
dummy query
'
;
const
options
=
{
unused
:
'
option
'
};
const
expectedUrl
=
`
${
dummyUrlRoot
}
/api/
${
dummyApiVersion
}
/projects.json`
;
mock
.
onGet
(
expectedUrl
).
reply
(
200
,
[{
name
:
'
test
'
,
}]);
mock
.
onGet
(
expectedUrl
).
reply
(
200
,
[
{
name
:
'
test
'
,
},
]);
Api
.
projects
(
query
,
options
,
(
response
)
=>
{
Api
.
projects
(
query
,
options
,
response
=>
{
expect
(
response
.
length
).
toBe
(
1
);
expect
(
response
[
0
].
name
).
toBe
(
'
test
'
);
done
();
...
...
@@ -115,8 +123,65 @@ describe('Api', () => {
});
});
describe
(
'
mergerequest
'
,
()
=>
{
it
(
'
fetches a merge request
'
,
done
=>
{
const
projectPath
=
'
abc
'
;
const
mergeRequestId
=
'
123456
'
;
const
expectedUrl
=
`
${
dummyUrlRoot
}
/api/
${
dummyApiVersion
}
/projects/
${
projectPath
}
/merge_requests/
${
mergeRequestId
}
`
;
mock
.
onGet
(
expectedUrl
).
reply
(
200
,
{
title
:
'
test
'
,
});
Api
.
mergeRequest
(
projectPath
,
mergeRequestId
)
.
then
(({
data
})
=>
{
expect
(
data
.
title
).
toBe
(
'
test
'
);
})
.
then
(
done
)
.
catch
(
done
.
fail
);
});
});
describe
(
'
mergerequest changes
'
,
()
=>
{
it
(
'
fetches the changes of a merge request
'
,
done
=>
{
const
projectPath
=
'
abc
'
;
const
mergeRequestId
=
'
123456
'
;
const
expectedUrl
=
`
${
dummyUrlRoot
}
/api/
${
dummyApiVersion
}
/projects/
${
projectPath
}
/merge_requests/
${
mergeRequestId
}
/changes`
;
mock
.
onGet
(
expectedUrl
).
reply
(
200
,
{
title
:
'
test
'
,
});
Api
.
mergeRequestChanges
(
projectPath
,
mergeRequestId
)
.
then
(({
data
})
=>
{
expect
(
data
.
title
).
toBe
(
'
test
'
);
})
.
then
(
done
)
.
catch
(
done
.
fail
);
});
});
describe
(
'
mergerequest versions
'
,
()
=>
{
it
(
'
fetches the versions of a merge request
'
,
done
=>
{
const
projectPath
=
'
abc
'
;
const
mergeRequestId
=
'
123456
'
;
const
expectedUrl
=
`
${
dummyUrlRoot
}
/api/
${
dummyApiVersion
}
/projects/
${
projectPath
}
/merge_requests/
${
mergeRequestId
}
/versions`
;
mock
.
onGet
(
expectedUrl
).
reply
(
200
,
[
{
id
:
123
,
},
]);
Api
.
mergeRequestVersions
(
projectPath
,
mergeRequestId
)
.
then
(({
data
})
=>
{
expect
(
data
.
length
).
toBe
(
1
);
expect
(
data
[
0
].
id
).
toBe
(
123
);
})
.
then
(
done
)
.
catch
(
done
.
fail
);
});
});
describe
(
'
newLabel
'
,
()
=>
{
it
(
'
creates a new label
'
,
(
done
)
=>
{
it
(
'
creates a new label
'
,
done
=>
{
const
namespace
=
'
some namespace
'
;
const
project
=
'
some project
'
;
const
labelData
=
{
some
:
'
data
'
};
...
...
@@ -124,36 +189,51 @@ describe('Api', () => {
const
expectedData
=
{
label
:
labelData
,
};
mock
.
onPost
(
expectedUrl
).
reply
(
(
config
)
=>
{
mock
.
onPost
(
expectedUrl
).
reply
(
config
=>
{
expect
(
config
.
data
).
toBe
(
JSON
.
stringify
(
expectedData
));
return
[
200
,
{
name
:
'
test
'
,
}];
return
[
200
,
{
name
:
'
test
'
,
},
];
});
Api
.
newLabel
(
namespace
,
project
,
labelData
,
(
response
)
=>
{
Api
.
newLabel
(
namespace
,
project
,
labelData
,
response
=>
{
expect
(
response
.
name
).
toBe
(
'
test
'
);
done
();
});
});
<<<<<<<
HEAD
it
(
'
creates a new group label
'
,
(
done
)
=>
{
const
namespace
=
'
some namespace
'
;
=======
it
(
'
creates a group label
'
,
done
=>
{
const
namespace
=
'
group/subgroup
'
;
>>>>>>>
upstream
/
master
const
labelData
=
{
some
:
'
data
'
};
const
expectedUrl
=
Api
.
buildUrl
(
Api
.
groupLabelsPath
).
replace
(
'
:namespace_path
'
,
namespace
);
const
expectedData
=
{
label
:
labelData
,
};
mock
.
onPost
(
expectedUrl
).
reply
(
(
config
)
=>
{
mock
.
onPost
(
expectedUrl
).
reply
(
config
=>
{
expect
(
config
.
data
).
toBe
(
JSON
.
stringify
(
expectedData
));
return
[
200
,
{
name
:
'
test
'
,
}];
return
[
200
,
{
name
:
'
test
'
,
},
];
});
<<<<<<<
HEAD
Api
.
newLabel
(
namespace
,
null
,
labelData
,
(
response
)
=>
{
=======
Api
.
newLabel
(
namespace
,
undefined
,
labelData
,
response
=>
{
>>>>>>>
upstream
/
master
expect
(
response
.
name
).
toBe
(
'
test
'
);
done
();
});
...
...
@@ -161,15 +241,17 @@ describe('Api', () => {
});
describe
(
'
groupProjects
'
,
()
=>
{
it
(
'
fetches group projects
'
,
(
done
)
=>
{
it
(
'
fetches group projects
'
,
done
=>
{
const
groupId
=
'
123456
'
;
const
query
=
'
dummy query
'
;
const
expectedUrl
=
`
${
dummyUrlRoot
}
/api/
${
dummyApiVersion
}
/groups/
${
groupId
}
/projects.json`
;
mock
.
onGet
(
expectedUrl
).
reply
(
200
,
[{
name
:
'
test
'
,
}]);
mock
.
onGet
(
expectedUrl
).
reply
(
200
,
[
{
name
:
'
test
'
,
},
]);
Api
.
groupProjects
(
groupId
,
query
,
(
response
)
=>
{
Api
.
groupProjects
(
groupId
,
query
,
response
=>
{
expect
(
response
.
length
).
toBe
(
1
);
expect
(
response
[
0
].
name
).
toBe
(
'
test
'
);
done
();
...
...
@@ -178,13 +260,13 @@ describe('Api', () => {
});
describe
(
'
licenseText
'
,
()
=>
{
it
(
'
fetches a license text
'
,
(
done
)
=>
{
it
(
'
fetches a license text
'
,
done
=>
{
const
licenseKey
=
"
driver's license
"
;
const
data
=
{
unused
:
'
option
'
};
const
expectedUrl
=
`
${
dummyUrlRoot
}
/api/
${
dummyApiVersion
}
/templates/licenses/
${
licenseKey
}
`
;
mock
.
onGet
(
expectedUrl
).
reply
(
200
,
'
test
'
);
Api
.
licenseText
(
licenseKey
,
data
,
(
response
)
=>
{
Api
.
licenseText
(
licenseKey
,
data
,
response
=>
{
expect
(
response
).
toBe
(
'
test
'
);
done
();
});
...
...
@@ -192,12 +274,12 @@ describe('Api', () => {
});
describe
(
'
gitignoreText
'
,
()
=>
{
it
(
'
fetches a gitignore text
'
,
(
done
)
=>
{
it
(
'
fetches a gitignore text
'
,
done
=>
{
const
gitignoreKey
=
'
ignore git
'
;
const
expectedUrl
=
`
${
dummyUrlRoot
}
/api/
${
dummyApiVersion
}
/templates/gitignores/
${
gitignoreKey
}
`
;
mock
.
onGet
(
expectedUrl
).
reply
(
200
,
'
test
'
);
Api
.
gitignoreText
(
gitignoreKey
,
(
response
)
=>
{
Api
.
gitignoreText
(
gitignoreKey
,
response
=>
{
expect
(
response
).
toBe
(
'
test
'
);
done
();
});
...
...
@@ -205,12 +287,12 @@ describe('Api', () => {
});
describe
(
'
gitlabCiYml
'
,
()
=>
{
it
(
'
fetches a .gitlab-ci.yml
'
,
(
done
)
=>
{
it
(
'
fetches a .gitlab-ci.yml
'
,
done
=>
{
const
gitlabCiYmlKey
=
'
Y CI ML
'
;
const
expectedUrl
=
`
${
dummyUrlRoot
}
/api/
${
dummyApiVersion
}
/templates/gitlab_ci_ymls/
${
gitlabCiYmlKey
}
`
;
mock
.
onGet
(
expectedUrl
).
reply
(
200
,
'
test
'
);
Api
.
gitlabCiYml
(
gitlabCiYmlKey
,
(
response
)
=>
{
Api
.
gitlabCiYml
(
gitlabCiYmlKey
,
response
=>
{
expect
(
response
).
toBe
(
'
test
'
);
done
();
});
...
...
@@ -218,12 +300,12 @@ describe('Api', () => {
});
describe
(
'
dockerfileYml
'
,
()
=>
{
it
(
'
fetches a Dockerfile
'
,
(
done
)
=>
{
it
(
'
fetches a Dockerfile
'
,
done
=>
{
const
dockerfileYmlKey
=
'
a giant whale
'
;
const
expectedUrl
=
`
${
dummyUrlRoot
}
/api/
${
dummyApiVersion
}
/templates/dockerfiles/
${
dockerfileYmlKey
}
`
;
mock
.
onGet
(
expectedUrl
).
reply
(
200
,
'
test
'
);
Api
.
dockerfileYml
(
dockerfileYmlKey
,
(
response
)
=>
{
Api
.
dockerfileYml
(
dockerfileYmlKey
,
response
=>
{
expect
(
response
).
toBe
(
'
test
'
);
done
();
});
...
...
@@ -231,12 +313,14 @@ describe('Api', () => {
});
describe
(
'
issueTemplate
'
,
()
=>
{
it
(
'
fetches an issue template
'
,
(
done
)
=>
{
it
(
'
fetches an issue template
'
,
done
=>
{
const
namespace
=
'
some namespace
'
;
const
project
=
'
some project
'
;
const
templateKey
=
'
template #%?.key
'
;
const
templateType
=
'
template type
'
;
const
expectedUrl
=
`
${
dummyUrlRoot
}
/
${
namespace
}
/
${
project
}
/templates/
${
templateType
}
/
${
encodeURIComponent
(
templateKey
)}
`
;
const
expectedUrl
=
`
${
dummyUrlRoot
}
/
${
namespace
}
/
${
project
}
/templates/
${
templateType
}
/
${
encodeURIComponent
(
templateKey
,
)}
`
;
mock
.
onGet
(
expectedUrl
).
reply
(
200
,
'
test
'
);
Api
.
issueTemplate
(
namespace
,
project
,
templateKey
,
templateType
,
(
error
,
response
)
=>
{
...
...
@@ -247,13 +331,15 @@ describe('Api', () => {
});
describe
(
'
users
'
,
()
=>
{
it
(
'
fetches users
'
,
(
done
)
=>
{
it
(
'
fetches users
'
,
done
=>
{
const
query
=
'
dummy query
'
;
const
options
=
{
unused
:
'
option
'
};
const
expectedUrl
=
`
${
dummyUrlRoot
}
/api/
${
dummyApiVersion
}
/users.json`
;
mock
.
onGet
(
expectedUrl
).
reply
(
200
,
[{
name
:
'
test
'
,
}]);
mock
.
onGet
(
expectedUrl
).
reply
(
200
,
[
{
name
:
'
test
'
,
},
]);
Api
.
users
(
query
,
options
)
.
then
(({
data
})
=>
{
...
...
spec/javascripts/ide/components/changed_file_icon_spec.js
View file @
436891da
...
...
@@ -11,6 +11,7 @@ describe('IDE changed file icon', () => {
vm
=
createComponent
(
component
,
{
file
:
{
tempFile
:
false
,
changed
:
true
,
},
});
});
...
...
@@ -20,7 +21,7 @@ describe('IDE changed file icon', () => {
});
describe
(
'
changedIcon
'
,
()
=>
{
it
(
'
equals file-modified when not a temp file
'
,
()
=>
{
it
(
'
equals file-modified when not a temp file
and has changes
'
,
()
=>
{
expect
(
vm
.
changedIcon
).
toBe
(
'
file-modified
'
);
});
...
...
spec/javascripts/ide/components/repo_editor_spec.js
View file @
436891da
...
...
@@ -89,6 +89,20 @@ describe('RepoEditor', () => {
done
();
});
});
it
(
'
calls createDiffInstance when viewer is a merge request diff
'
,
done
=>
{
vm
.
$store
.
state
.
viewer
=
'
mrdiff
'
;
spyOn
(
vm
.
editor
,
'
createDiffInstance
'
);
vm
.
createEditorInstance
();
vm
.
$nextTick
(()
=>
{
expect
(
vm
.
editor
.
createDiffInstance
).
toHaveBeenCalled
();
done
();
});
});
});
describe
(
'
setupEditor
'
,
()
=>
{
...
...
@@ -134,4 +148,48 @@ describe('RepoEditor', () => {
});
});
});
describe
(
'
setup editor for merge request viewing
'
,
()
=>
{
beforeEach
(
done
=>
{
// Resetting as the main test setup has already done it
vm
.
$destroy
();
resetStore
(
vm
.
$store
);
Editor
.
editorInstance
.
modelManager
.
dispose
();
const
f
=
{
...
file
(),
active
:
true
,
tempFile
:
true
,
html
:
'
testing
'
,
mrChange
:
{
diff
:
'
ABC
'
},
baseRaw
:
'
testing
'
,
content
:
'
test
'
,
};
const
RepoEditor
=
Vue
.
extend
(
repoEditor
);
vm
=
createComponentWithStore
(
RepoEditor
,
store
,
{
file
:
f
,
});
vm
.
$store
.
state
.
openFiles
.
push
(
f
);
vm
.
$store
.
state
.
entries
[
f
.
path
]
=
f
;
vm
.
$store
.
state
.
viewer
=
'
mrdiff
'
;
vm
.
monaco
=
true
;
vm
.
$mount
();
monacoLoader
([
'
vs/editor/editor.main
'
],
()
=>
{
setTimeout
(
done
,
0
);
});
});
it
(
'
attaches merge request model to editor when merge request diff
'
,
()
=>
{
spyOn
(
vm
.
editor
,
'
attachMergeRequestModel
'
).
and
.
callThrough
();
vm
.
setupEditor
();
expect
(
vm
.
editor
.
attachMergeRequestModel
).
toHaveBeenCalledWith
(
vm
.
model
);
});
});
});
spec/javascripts/ide/components/repo_tabs_spec.js
View file @
436891da
...
...
@@ -17,6 +17,7 @@ describe('RepoTabs', () => {
files
:
openedFiles
,
viewer
:
'
editor
'
,
hasChanges
:
false
,
hasMergeRequest
:
false
,
});
openedFiles
[
0
].
active
=
true
;
...
...
@@ -56,6 +57,7 @@ describe('RepoTabs', () => {
files
:
[],
viewer
:
'
editor
'
,
hasChanges
:
false
,
hasMergeRequest
:
false
,
},
'
#test-app
'
,
);
...
...
spec/javascripts/ide/lib/common/model_spec.js
View file @
436891da
...
...
@@ -11,7 +11,10 @@ describe('Multi-file editor library model', () => {
spyOn
(
eventHub
,
'
$on
'
).
and
.
callThrough
();
monacoLoader
([
'
vs/editor/editor.main
'
],
()
=>
{
model
=
new
Model
(
monaco
,
file
(
'
path
'
));
const
f
=
file
(
'
path
'
);
f
.
mrChange
=
{
diff
:
'
ABC
'
};
f
.
baseRaw
=
'
test
'
;
model
=
new
Model
(
monaco
,
f
);
done
();
});
...
...
@@ -21,9 +24,10 @@ describe('Multi-file editor library model', () => {
model
.
dispose
();
});
it
(
'
creates original model & new model
'
,
()
=>
{
it
(
'
creates original model &
base model &
new model
'
,
()
=>
{
expect
(
model
.
originalModel
).
not
.
toBeNull
();
expect
(
model
.
model
).
not
.
toBeNull
();
expect
(
model
.
baseModel
).
not
.
toBeNull
();
});
it
(
'
adds eventHub listener
'
,
()
=>
{
...
...
@@ -51,6 +55,12 @@ describe('Multi-file editor library model', () => {
});
});
describe
(
'
getBaseModel
'
,
()
=>
{
it
(
'
returns base model
'
,
()
=>
{
expect
(
model
.
getBaseModel
()).
toBe
(
model
.
baseModel
);
});
});
describe
(
'
setValue
'
,
()
=>
{
it
(
'
updates models value
'
,
()
=>
{
model
.
setValue
(
'
testing 123
'
);
...
...
spec/javascripts/ide/lib/editor_spec.js
View file @
436891da
...
...
@@ -143,6 +143,31 @@ describe('Multi-file editor library', () => {
});
});
describe
(
'
attachMergeRequestModel
'
,
()
=>
{
let
model
;
beforeEach
(()
=>
{
instance
.
createDiffInstance
(
document
.
createElement
(
'
div
'
));
const
f
=
file
();
f
.
mrChanges
=
{
diff
:
'
ABC
'
};
f
.
baseRaw
=
'
testing
'
;
model
=
instance
.
createModel
(
f
);
});
it
(
'
sets original & modified
'
,
()
=>
{
spyOn
(
instance
.
instance
,
'
setModel
'
);
instance
.
attachMergeRequestModel
(
model
);
expect
(
instance
.
instance
.
setModel
).
toHaveBeenCalledWith
({
original
:
model
.
getBaseModel
(),
modified
:
model
.
getModel
(),
});
});
});
describe
(
'
clearEditor
'
,
()
=>
{
it
(
'
resets the editor model
'
,
()
=>
{
instance
.
createInstance
(
document
.
createElement
(
'
div
'
));
...
...
spec/javascripts/ide/stores/actions/file_spec.js
View file @
436891da
...
...
@@ -5,7 +5,7 @@ import router from '~/ide/ide_router';
import
eventHub
from
'
~/ide/eventhub
'
;
import
{
file
,
resetStore
}
from
'
../../helpers
'
;
describe
(
'
Multi-file
store file actions
'
,
()
=>
{
describe
(
'
IDE
store file actions
'
,
()
=>
{
beforeEach
(()
=>
{
spyOn
(
router
,
'
push
'
);
});
...
...
@@ -189,7 +189,7 @@ describe('Multi-file store file actions', () => {
it
(
'
calls the service
'
,
done
=>
{
store
.
dispatch
(
'
getFileData
'
,
localFile
)
.
dispatch
(
'
getFileData
'
,
{
path
:
localFile
.
path
}
)
.
then
(()
=>
{
expect
(
service
.
getFileData
).
toHaveBeenCalledWith
(
'
getFileDataURL
'
);
...
...
@@ -200,7 +200,7 @@ describe('Multi-file store file actions', () => {
it
(
'
sets the file data
'
,
done
=>
{
store
.
dispatch
(
'
getFileData
'
,
localFile
)
.
dispatch
(
'
getFileData
'
,
{
path
:
localFile
.
path
}
)
.
then
(()
=>
{
expect
(
localFile
.
blamePath
).
toBe
(
'
blame_path
'
);
...
...
@@ -211,7 +211,7 @@ describe('Multi-file store file actions', () => {
it
(
'
sets document title
'
,
done
=>
{
store
.
dispatch
(
'
getFileData
'
,
localFile
)
.
dispatch
(
'
getFileData
'
,
{
path
:
localFile
.
path
}
)
.
then
(()
=>
{
expect
(
document
.
title
).
toBe
(
'
testing getFileData
'
);
...
...
@@ -222,7 +222,7 @@ describe('Multi-file store file actions', () => {
it
(
'
sets the file as active
'
,
done
=>
{
store
.
dispatch
(
'
getFileData
'
,
localFile
)
.
dispatch
(
'
getFileData
'
,
{
path
:
localFile
.
path
}
)
.
then
(()
=>
{
expect
(
localFile
.
active
).
toBeTruthy
();
...
...
@@ -231,9 +231,20 @@ describe('Multi-file store file actions', () => {
.
catch
(
done
.
fail
);
});
it
(
'
sets the file not as active if we pass makeFileActive false
'
,
done
=>
{
store
.
dispatch
(
'
getFileData
'
,
{
path
:
localFile
.
path
,
makeFileActive
:
false
})
.
then
(()
=>
{
expect
(
localFile
.
active
).
toBeFalsy
();
done
();
})
.
catch
(
done
.
fail
);
});
it
(
'
adds the file to open files
'
,
done
=>
{
store
.
dispatch
(
'
getFileData
'
,
localFile
)
.
dispatch
(
'
getFileData
'
,
{
path
:
localFile
.
path
}
)
.
then
(()
=>
{
expect
(
store
.
state
.
openFiles
.
length
).
toBe
(
1
);
expect
(
store
.
state
.
openFiles
[
0
].
name
).
toBe
(
localFile
.
name
);
...
...
@@ -256,7 +267,7 @@ describe('Multi-file store file actions', () => {
it
(
'
calls getRawFileData service method
'
,
done
=>
{
store
.
dispatch
(
'
getRawFileData
'
,
tmpFile
)
.
dispatch
(
'
getRawFileData
'
,
{
path
:
tmpFile
.
path
}
)
.
then
(()
=>
{
expect
(
service
.
getRawFileData
).
toHaveBeenCalledWith
(
tmpFile
);
...
...
@@ -267,7 +278,7 @@ describe('Multi-file store file actions', () => {
it
(
'
updates file raw data
'
,
done
=>
{
store
.
dispatch
(
'
getRawFileData
'
,
tmpFile
)
.
dispatch
(
'
getRawFileData
'
,
{
path
:
tmpFile
.
path
}
)
.
then
(()
=>
{
expect
(
tmpFile
.
raw
).
toBe
(
'
raw
'
);
...
...
@@ -275,6 +286,22 @@ describe('Multi-file store file actions', () => {
})
.
catch
(
done
.
fail
);
});
it
(
'
calls also getBaseRawFileData service method
'
,
done
=>
{
spyOn
(
service
,
'
getBaseRawFileData
'
).
and
.
returnValue
(
Promise
.
resolve
(
'
baseraw
'
));
tmpFile
.
mrChange
=
{
new_file
:
false
};
store
.
dispatch
(
'
getRawFileData
'
,
{
path
:
tmpFile
.
path
,
baseSha
:
'
SHA
'
})
.
then
(()
=>
{
expect
(
service
.
getBaseRawFileData
).
toHaveBeenCalledWith
(
tmpFile
,
'
SHA
'
);
expect
(
tmpFile
.
baseRaw
).
toBe
(
'
baseraw
'
);
done
();
})
.
catch
(
done
.
fail
);
});
});
describe
(
'
changeFileContent
'
,
()
=>
{
...
...
spec/javascripts/ide/stores/actions/merge_request_spec.js
0 → 100644
View file @
436891da
import
store
from
'
~/ide/stores
'
;
import
service
from
'
~/ide/services
'
;
import
{
resetStore
}
from
'
../../helpers
'
;
describe
(
'
IDE store merge request actions
'
,
()
=>
{
beforeEach
(()
=>
{
store
.
state
.
projects
.
abcproject
=
{
mergeRequests
:
{},
};
});
afterEach
(()
=>
{
resetStore
(
store
);
});
describe
(
'
getMergeRequestData
'
,
()
=>
{
beforeEach
(()
=>
{
spyOn
(
service
,
'
getProjectMergeRequestData
'
).
and
.
returnValue
(
Promise
.
resolve
({
data
:
{
title
:
'
mergerequest
'
}
}),
);
});
it
(
'
calls getProjectMergeRequestData service method
'
,
done
=>
{
store
.
dispatch
(
'
getMergeRequestData
'
,
{
projectId
:
'
abcproject
'
,
mergeRequestId
:
1
})
.
then
(()
=>
{
expect
(
service
.
getProjectMergeRequestData
).
toHaveBeenCalledWith
(
'
abcproject
'
,
1
);
done
();
})
.
catch
(
done
.
fail
);
});
it
(
'
sets the Merge Request Object
'
,
done
=>
{
store
.
dispatch
(
'
getMergeRequestData
'
,
{
projectId
:
'
abcproject
'
,
mergeRequestId
:
1
})
.
then
(()
=>
{
expect
(
store
.
state
.
projects
.
abcproject
.
mergeRequests
[
'
1
'
].
title
).
toBe
(
'
mergerequest
'
);
expect
(
store
.
state
.
currentMergeRequestId
).
toBe
(
1
);
done
();
})
.
catch
(
done
.
fail
);
});
});
describe
(
'
getMergeRequestChanges
'
,
()
=>
{
beforeEach
(()
=>
{
spyOn
(
service
,
'
getProjectMergeRequestChanges
'
).
and
.
returnValue
(
Promise
.
resolve
({
data
:
{
title
:
'
mergerequest
'
}
}),
);
store
.
state
.
projects
.
abcproject
.
mergeRequests
[
'
1
'
]
=
{
changes
:
[]
};
});
it
(
'
calls getProjectMergeRequestChanges service method
'
,
done
=>
{
store
.
dispatch
(
'
getMergeRequestChanges
'
,
{
projectId
:
'
abcproject
'
,
mergeRequestId
:
1
})
.
then
(()
=>
{
expect
(
service
.
getProjectMergeRequestChanges
).
toHaveBeenCalledWith
(
'
abcproject
'
,
1
);
done
();
})
.
catch
(
done
.
fail
);
});
it
(
'
sets the Merge Request Changes Object
'
,
done
=>
{
store
.
dispatch
(
'
getMergeRequestChanges
'
,
{
projectId
:
'
abcproject
'
,
mergeRequestId
:
1
})
.
then
(()
=>
{
expect
(
store
.
state
.
projects
.
abcproject
.
mergeRequests
[
'
1
'
].
changes
.
title
).
toBe
(
'
mergerequest
'
,
);
done
();
})
.
catch
(
done
.
fail
);
});
});
describe
(
'
getMergeRequestVersions
'
,
()
=>
{
beforeEach
(()
=>
{
spyOn
(
service
,
'
getProjectMergeRequestVersions
'
).
and
.
returnValue
(
Promise
.
resolve
({
data
:
[{
id
:
789
}]
}),
);
store
.
state
.
projects
.
abcproject
.
mergeRequests
[
'
1
'
]
=
{
versions
:
[]
};
});
it
(
'
calls getProjectMergeRequestVersions service method
'
,
done
=>
{
store
.
dispatch
(
'
getMergeRequestVersions
'
,
{
projectId
:
'
abcproject
'
,
mergeRequestId
:
1
})
.
then
(()
=>
{
expect
(
service
.
getProjectMergeRequestVersions
).
toHaveBeenCalledWith
(
'
abcproject
'
,
1
);
done
();
})
.
catch
(
done
.
fail
);
});
it
(
'
sets the Merge Request Versions Object
'
,
done
=>
{
store
.
dispatch
(
'
getMergeRequestVersions
'
,
{
projectId
:
'
abcproject
'
,
mergeRequestId
:
1
})
.
then
(()
=>
{
expect
(
store
.
state
.
projects
.
abcproject
.
mergeRequests
[
'
1
'
].
versions
.
length
).
toBe
(
1
);
done
();
})
.
catch
(
done
.
fail
);
});
});
});
spec/javascripts/ide/stores/actions/tree_spec.js
View file @
436891da
...
...
@@ -68,9 +68,7 @@ describe('Multi-file store tree actions', () => {
expect
(
projectTree
.
tree
[
0
].
tree
[
1
].
name
).
toBe
(
'
fileinfolder.js
'
);
expect
(
projectTree
.
tree
[
1
].
type
).
toBe
(
'
blob
'
);
expect
(
projectTree
.
tree
[
0
].
tree
[
0
].
tree
[
0
].
type
).
toBe
(
'
blob
'
);
expect
(
projectTree
.
tree
[
0
].
tree
[
0
].
tree
[
0
].
name
).
toBe
(
'
fileinsubfolder.js
'
,
);
expect
(
projectTree
.
tree
[
0
].
tree
[
0
].
tree
[
0
].
name
).
toBe
(
'
fileinsubfolder.js
'
);
done
();
})
...
...
@@ -132,9 +130,7 @@ describe('Multi-file store tree actions', () => {
store
.
dispatch
(
'
getLastCommitData
'
,
projectTree
)
.
then
(()
=>
{
expect
(
service
.
getTreeLastCommit
).
toHaveBeenCalledWith
(
'
lastcommitpath
'
,
);
expect
(
service
.
getTreeLastCommit
).
toHaveBeenCalledWith
(
'
lastcommitpath
'
);
done
();
})
...
...
@@ -160,9 +156,7 @@ describe('Multi-file store tree actions', () => {
.
dispatch
(
'
getLastCommitData
'
,
projectTree
)
.
then
(
Vue
.
nextTick
)
.
then
(()
=>
{
expect
(
projectTree
.
tree
[
0
].
lastCommit
.
message
).
not
.
toBe
(
'
commit message
'
,
);
expect
(
projectTree
.
tree
[
0
].
lastCommit
.
message
).
not
.
toBe
(
'
commit message
'
);
done
();
})
...
...
spec/javascripts/ide/stores/getters_spec.js
View file @
436891da
...
...
@@ -2,7 +2,7 @@ import * as getters from '~/ide/stores/getters';
import
state
from
'
~/ide/stores/state
'
;
import
{
file
}
from
'
../helpers
'
;
describe
(
'
Multi-file
store getters
'
,
()
=>
{
describe
(
'
IDE
store getters
'
,
()
=>
{
let
localState
;
beforeEach
(()
=>
{
...
...
@@ -52,4 +52,24 @@ describe('Multi-file store getters', () => {
expect
(
modifiedFiles
[
0
].
name
).
toBe
(
'
added
'
);
});
});
describe
(
'
currentMergeRequest
'
,
()
=>
{
it
(
'
returns Current Merge Request
'
,
()
=>
{
localState
.
currentProjectId
=
'
abcproject
'
;
localState
.
currentMergeRequestId
=
1
;
localState
.
projects
.
abcproject
=
{
mergeRequests
:
{
1
:
{
mergeId
:
1
},
},
};
expect
(
getters
.
currentMergeRequest
(
localState
).
mergeId
).
toBe
(
1
);
});
it
(
'
returns null if no active Merge Request was found
'
,
()
=>
{
localState
.
currentProjectId
=
'
otherproject
'
;
expect
(
getters
.
currentMergeRequest
(
localState
)).
toBeNull
();
});
});
});
spec/javascripts/ide/stores/mutations/file_spec.js
View file @
436891da
...
...
@@ -2,7 +2,7 @@ import mutations from '~/ide/stores/mutations/file';
import
state
from
'
~/ide/stores/state
'
;
import
{
file
}
from
'
../../helpers
'
;
describe
(
'
Multi-file
store file mutations
'
,
()
=>
{
describe
(
'
IDE
store file mutations
'
,
()
=>
{
let
localState
;
let
localFile
;
...
...
@@ -62,6 +62,8 @@ describe('Multi-file store file mutations', () => {
expect
(
localFile
.
rawPath
).
toBe
(
'
raw
'
);
expect
(
localFile
.
binary
).
toBeTruthy
();
expect
(
localFile
.
renderError
).
toBe
(
'
render_error
'
);
expect
(
localFile
.
raw
).
toBeNull
();
expect
(
localFile
.
baseRaw
).
toBeNull
();
});
});
...
...
@@ -76,6 +78,17 @@ describe('Multi-file store file mutations', () => {
});
});
describe
(
'
SET_FILE_BASE_RAW_DATA
'
,
()
=>
{
it
(
'
sets raw data from base branch
'
,
()
=>
{
mutations
.
SET_FILE_BASE_RAW_DATA
(
localState
,
{
file
:
localFile
,
baseRaw
:
'
testing
'
,
});
expect
(
localFile
.
baseRaw
).
toBe
(
'
testing
'
);
});
});
describe
(
'
UPDATE_FILE_CONTENT
'
,
()
=>
{
beforeEach
(()
=>
{
localFile
.
raw
=
'
test
'
;
...
...
@@ -112,6 +125,17 @@ describe('Multi-file store file mutations', () => {
});
});
describe
(
'
SET_FILE_MERGE_REQUEST_CHANGE
'
,
()
=>
{
it
(
'
sets file mr change
'
,
()
=>
{
mutations
.
SET_FILE_MERGE_REQUEST_CHANGE
(
localState
,
{
file
:
localFile
,
mrChange
:
{
diff
:
'
ABC
'
},
});
expect
(
localFile
.
mrChange
.
diff
).
toBe
(
'
ABC
'
);
});
});
describe
(
'
DISCARD_FILE_CHANGES
'
,
()
=>
{
beforeEach
(()
=>
{
localFile
.
content
=
'
test
'
;
...
...
spec/javascripts/ide/stores/mutations/merge_request_spec.js
0 → 100644
View file @
436891da
import
mutations
from
'
~/ide/stores/mutations/merge_request
'
;
import
state
from
'
~/ide/stores/state
'
;
describe
(
'
IDE store merge request mutations
'
,
()
=>
{
let
localState
;
beforeEach
(()
=>
{
localState
=
state
();
localState
.
projects
=
{
abcproject
:
{
mergeRequests
:
{}
}
};
mutations
.
SET_MERGE_REQUEST
(
localState
,
{
projectPath
:
'
abcproject
'
,
mergeRequestId
:
1
,
mergeRequest
:
{
title
:
'
mr
'
,
},
});
});
describe
(
'
SET_CURRENT_MERGE_REQUEST
'
,
()
=>
{
it
(
'
sets current merge request
'
,
()
=>
{
mutations
.
SET_CURRENT_MERGE_REQUEST
(
localState
,
2
);
expect
(
localState
.
currentMergeRequestId
).
toBe
(
2
);
});
});
describe
(
'
SET_MERGE_REQUEST
'
,
()
=>
{
it
(
'
setsmerge request data
'
,
()
=>
{
const
newMr
=
localState
.
projects
.
abcproject
.
mergeRequests
[
1
];
expect
(
newMr
.
title
).
toBe
(
'
mr
'
);
expect
(
newMr
.
active
).
toBeTruthy
();
});
});
describe
(
'
SET_MERGE_REQUEST_CHANGES
'
,
()
=>
{
it
(
'
sets merge request changes
'
,
()
=>
{
mutations
.
SET_MERGE_REQUEST_CHANGES
(
localState
,
{
projectPath
:
'
abcproject
'
,
mergeRequestId
:
1
,
changes
:
{
diff
:
'
abc
'
,
},
});
const
newMr
=
localState
.
projects
.
abcproject
.
mergeRequests
[
1
];
expect
(
newMr
.
changes
.
diff
).
toBe
(
'
abc
'
);
});
});
describe
(
'
SET_MERGE_REQUEST_VERSIONS
'
,
()
=>
{
it
(
'
sets merge request versions
'
,
()
=>
{
mutations
.
SET_MERGE_REQUEST_VERSIONS
(
localState
,
{
projectPath
:
'
abcproject
'
,
mergeRequestId
:
1
,
versions
:
[{
id
:
123
}],
});
const
newMr
=
localState
.
projects
.
abcproject
.
mergeRequests
[
1
];
expect
(
newMr
.
versions
.
length
).
toBe
(
1
);
expect
(
newMr
.
versions
[
0
].
id
).
toBe
(
123
);
});
});
});
spec/javascripts/vue_mr_widget/components/mr_widget_header_spec.js
View file @
436891da
...
...
@@ -17,46 +17,58 @@ describe('MRWidgetHeader', () => {
describe
(
'
computed
'
,
()
=>
{
describe
(
'
shouldShowCommitsBehindText
'
,
()
=>
{
it
(
'
return true when there are divergedCommitsCount
'
,
()
=>
{
vm
=
mountComponent
(
Component
,
{
mr
:
{
divergedCommitsCount
:
12
,
sourceBranch
:
'
mr-widget-refactor
'
,
sourceBranchLink
:
'
<a href="/foo/bar/mr-widget-refactor">Link</a>
'
,
targetBranch
:
'
master
'
,
}
});
vm
=
mountComponent
(
Component
,
{
mr
:
{
divergedCommitsCount
:
12
,
sourceBranch
:
'
mr-widget-refactor
'
,
sourceBranchLink
:
'
<a href="/foo/bar/mr-widget-refactor">Link</a>
'
,
targetBranch
:
'
master
'
,
statusPath
:
'
abc
'
,
},
});
expect
(
vm
.
shouldShowCommitsBehindText
).
toEqual
(
true
);
});
it
(
'
returns false where there are no divergedComits count
'
,
()
=>
{
vm
=
mountComponent
(
Component
,
{
mr
:
{
divergedCommitsCount
:
0
,
sourceBranch
:
'
mr-widget-refactor
'
,
sourceBranchLink
:
'
<a href="/foo/bar/mr-widget-refactor">Link</a>
'
,
targetBranch
:
'
master
'
,
}
});
vm
=
mountComponent
(
Component
,
{
mr
:
{
divergedCommitsCount
:
0
,
sourceBranch
:
'
mr-widget-refactor
'
,
sourceBranchLink
:
'
<a href="/foo/bar/mr-widget-refactor">Link</a>
'
,
targetBranch
:
'
master
'
,
statusPath
:
'
abc
'
,
},
});
expect
(
vm
.
shouldShowCommitsBehindText
).
toEqual
(
false
);
});
});
describe
(
'
commitsText
'
,
()
=>
{
it
(
'
returns singular when there is one commit
'
,
()
=>
{
vm
=
mountComponent
(
Component
,
{
mr
:
{
divergedCommitsCount
:
1
,
sourceBranch
:
'
mr-widget-refactor
'
,
sourceBranchLink
:
'
<a href="/foo/bar/mr-widget-refactor">Link</a>
'
,
targetBranch
:
'
master
'
,
}
});
vm
=
mountComponent
(
Component
,
{
mr
:
{
divergedCommitsCount
:
1
,
sourceBranch
:
'
mr-widget-refactor
'
,
sourceBranchLink
:
'
<a href="/foo/bar/mr-widget-refactor">Link</a>
'
,
targetBranch
:
'
master
'
,
statusPath
:
'
abc
'
,
},
});
expect
(
vm
.
commitsText
).
toEqual
(
'
1 commit behind
'
);
});
it
(
'
returns plural when there is more than one commit
'
,
()
=>
{
vm
=
mountComponent
(
Component
,
{
mr
:
{
divergedCommitsCount
:
2
,
sourceBranch
:
'
mr-widget-refactor
'
,
sourceBranchLink
:
'
<a href="/foo/bar/mr-widget-refactor">Link</a>
'
,
targetBranch
:
'
master
'
,
}
});
vm
=
mountComponent
(
Component
,
{
mr
:
{
divergedCommitsCount
:
2
,
sourceBranch
:
'
mr-widget-refactor
'
,
sourceBranchLink
:
'
<a href="/foo/bar/mr-widget-refactor">Link</a>
'
,
targetBranch
:
'
master
'
,
statusPath
:
'
abc
'
,
},
});
expect
(
vm
.
commitsText
).
toEqual
(
'
2 commits behind
'
);
});
...
...
@@ -66,24 +78,27 @@ describe('MRWidgetHeader', () => {
describe
(
'
template
'
,
()
=>
{
describe
(
'
common elements
'
,
()
=>
{
beforeEach
(()
=>
{
vm
=
mountComponent
(
Component
,
{
mr
:
{
divergedCommitsCount
:
12
,
sourceBranch
:
'
mr-widget-refactor
'
,
sourceBranchLink
:
'
<a href="/foo/bar/mr-widget-refactor">mr-widget-refactor</a>
'
,
sourceBranchRemoved
:
false
,
targetBranchPath
:
'
foo/bar/commits-path
'
,
targetBranchTreePath
:
'
foo/bar/tree/path
'
,
targetBranch
:
'
master
'
,
isOpen
:
true
,
emailPatchesPath
:
'
/mr/email-patches
'
,
plainDiffPath
:
'
/mr/plainDiffPath
'
,
}
});
vm
=
mountComponent
(
Component
,
{
mr
:
{
divergedCommitsCount
:
12
,
sourceBranch
:
'
mr-widget-refactor
'
,
sourceBranchLink
:
'
<a href="/foo/bar/mr-widget-refactor">mr-widget-refactor</a>
'
,
sourceBranchRemoved
:
false
,
targetBranchPath
:
'
foo/bar/commits-path
'
,
targetBranchTreePath
:
'
foo/bar/tree/path
'
,
targetBranch
:
'
master
'
,
isOpen
:
true
,
emailPatchesPath
:
'
/mr/email-patches
'
,
plainDiffPath
:
'
/mr/plainDiffPath
'
,
statusPath
:
'
abc
'
,
},
});
});
it
(
'
renders source branch link
'
,
()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.js-source-branch
'
).
innerHTML
,
)
.
toEqual
(
'
<a href="/foo/bar/mr-widget-refactor">mr-widget-refactor</a>
'
)
;
expect
(
vm
.
$el
.
querySelector
(
'
.js-source-branch
'
).
innerHTML
).
toEqual
(
'
<a href="/foo/bar/mr-widget-refactor">mr-widget-refactor</a>
'
,
);
});
it
(
'
renders clipboard button
'
,
()
=>
{
...
...
@@ -101,18 +116,21 @@ describe('MRWidgetHeader', () => {
});
beforeEach
(()
=>
{
vm
=
mountComponent
(
Component
,
{
mr
:
{
divergedCommitsCount
:
12
,
sourceBranch
:
'
mr-widget-refactor
'
,
sourceBranchLink
:
'
<a href="/foo/bar/mr-widget-refactor">mr-widget-refactor</a>
'
,
sourceBranchRemoved
:
false
,
targetBranchPath
:
'
foo/bar/commits-path
'
,
targetBranchTreePath
:
'
foo/bar/tree/path
'
,
targetBranch
:
'
master
'
,
isOpen
:
true
,
emailPatchesPath
:
'
/mr/email-patches
'
,
plainDiffPath
:
'
/mr/plainDiffPath
'
,
}
});
vm
=
mountComponent
(
Component
,
{
mr
:
{
divergedCommitsCount
:
12
,
sourceBranch
:
'
mr-widget-refactor
'
,
sourceBranchLink
:
'
<a href="/foo/bar/mr-widget-refactor">mr-widget-refactor</a>
'
,
sourceBranchRemoved
:
false
,
targetBranchPath
:
'
foo/bar/commits-path
'
,
targetBranchTreePath
:
'
foo/bar/tree/path
'
,
targetBranch
:
'
master
'
,
isOpen
:
true
,
emailPatchesPath
:
'
/mr/email-patches
'
,
plainDiffPath
:
'
/mr/plainDiffPath
'
,
statusPath
:
'
abc
'
,
},
});
});
it
(
'
renders checkout branch button with modal trigger
'
,
()
=>
{
...
...
@@ -123,39 +141,49 @@ describe('MRWidgetHeader', () => {
expect
(
button
.
getAttribute
(
'
data-toggle
'
)).
toEqual
(
'
modal
'
);
});
it
(
'
renders web ide button
'
,
()
=>
{
const
button
=
vm
.
$el
.
querySelector
(
'
.js-web-ide
'
);
expect
(
button
.
textContent
.
trim
()).
toEqual
(
'
Web IDE
'
);
expect
(
button
.
getAttribute
(
'
href
'
)).
toEqual
(
'
undefined/-/ide/projectabc
'
);
});
it
(
'
renders download dropdown with links
'
,
()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.js-download-email-patches
'
).
textContent
.
trim
()
,
)
.
toEqual
(
'
Email patches
'
)
;
expect
(
vm
.
$el
.
querySelector
(
'
.js-download-email-patches
'
).
textContent
.
trim
()).
toEqual
(
'
Email patches
'
,
);
expect
(
vm
.
$el
.
querySelector
(
'
.js-download-email-patches
'
).
getAttribute
(
'
href
'
)
,
)
.
toEqual
(
'
/mr/email-patches
'
)
;
expect
(
vm
.
$el
.
querySelector
(
'
.js-download-email-patches
'
).
getAttribute
(
'
href
'
)).
toEqual
(
'
/mr/email-patches
'
,
);
expect
(
vm
.
$el
.
querySelector
(
'
.js-download-plain-diff
'
).
textContent
.
trim
()
,
)
.
toEqual
(
'
Plain diff
'
)
;
expect
(
vm
.
$el
.
querySelector
(
'
.js-download-plain-diff
'
).
textContent
.
trim
()).
toEqual
(
'
Plain diff
'
,
);
expect
(
vm
.
$el
.
querySelector
(
'
.js-download-plain-diff
'
).
getAttribute
(
'
href
'
)
,
)
.
toEqual
(
'
/mr/plainDiffPath
'
)
;
expect
(
vm
.
$el
.
querySelector
(
'
.js-download-plain-diff
'
).
getAttribute
(
'
href
'
)).
toEqual
(
'
/mr/plainDiffPath
'
,
);
});
});
describe
(
'
with a closed merge request
'
,
()
=>
{
beforeEach
(()
=>
{
vm
=
mountComponent
(
Component
,
{
mr
:
{
divergedCommitsCount
:
12
,
sourceBranch
:
'
mr-widget-refactor
'
,
sourceBranchLink
:
'
<a href="/foo/bar/mr-widget-refactor">mr-widget-refactor</a>
'
,
sourceBranchRemoved
:
false
,
targetBranchPath
:
'
foo/bar/commits-path
'
,
targetBranchTreePath
:
'
foo/bar/tree/path
'
,
targetBranch
:
'
master
'
,
isOpen
:
false
,
emailPatchesPath
:
'
/mr/email-patches
'
,
plainDiffPath
:
'
/mr/plainDiffPath
'
,
}
});
vm
=
mountComponent
(
Component
,
{
mr
:
{
divergedCommitsCount
:
12
,
sourceBranch
:
'
mr-widget-refactor
'
,
sourceBranchLink
:
'
<a href="/foo/bar/mr-widget-refactor">mr-widget-refactor</a>
'
,
sourceBranchRemoved
:
false
,
targetBranchPath
:
'
foo/bar/commits-path
'
,
targetBranchTreePath
:
'
foo/bar/tree/path
'
,
targetBranch
:
'
master
'
,
isOpen
:
false
,
emailPatchesPath
:
'
/mr/email-patches
'
,
plainDiffPath
:
'
/mr/plainDiffPath
'
,
statusPath
:
'
abc
'
,
},
});
});
it
(
'
does not render checkout branch button with modal trigger
'
,
()
=>
{
...
...
@@ -165,30 +193,29 @@ describe('MRWidgetHeader', () => {
});
it
(
'
does not render download dropdown with links
'
,
()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.js-download-email-patches
'
),
).
toEqual
(
null
);
expect
(
vm
.
$el
.
querySelector
(
'
.js-download-email-patches
'
)).
toEqual
(
null
);
expect
(
vm
.
$el
.
querySelector
(
'
.js-download-plain-diff
'
),
).
toEqual
(
null
);
expect
(
vm
.
$el
.
querySelector
(
'
.js-download-plain-diff
'
)).
toEqual
(
null
);
});
});
describe
(
'
without diverged commits
'
,
()
=>
{
beforeEach
(()
=>
{
vm
=
mountComponent
(
Component
,
{
mr
:
{
divergedCommitsCount
:
0
,
sourceBranch
:
'
mr-widget-refactor
'
,
sourceBranchLink
:
'
<a href="/foo/bar/mr-widget-refactor">mr-widget-refactor</a>
'
,
sourceBranchRemoved
:
false
,
targetBranchPath
:
'
foo/bar/commits-path
'
,
targetBranchTreePath
:
'
foo/bar/tree/path
'
,
targetBranch
:
'
master
'
,
isOpen
:
true
,
emailPatchesPath
:
'
/mr/email-patches
'
,
plainDiffPath
:
'
/mr/plainDiffPath
'
,
}
});
vm
=
mountComponent
(
Component
,
{
mr
:
{
divergedCommitsCount
:
0
,
sourceBranch
:
'
mr-widget-refactor
'
,
sourceBranchLink
:
'
<a href="/foo/bar/mr-widget-refactor">mr-widget-refactor</a>
'
,
sourceBranchRemoved
:
false
,
targetBranchPath
:
'
foo/bar/commits-path
'
,
targetBranchTreePath
:
'
foo/bar/tree/path
'
,
targetBranch
:
'
master
'
,
isOpen
:
true
,
emailPatchesPath
:
'
/mr/email-patches
'
,
plainDiffPath
:
'
/mr/plainDiffPath
'
,
statusPath
:
'
abc
'
,
},
});
});
it
(
'
does not render diverged commits info
'
,
()
=>
{
...
...
@@ -198,22 +225,27 @@ describe('MRWidgetHeader', () => {
describe
(
'
with diverged commits
'
,
()
=>
{
beforeEach
(()
=>
{
vm
=
mountComponent
(
Component
,
{
mr
:
{
divergedCommitsCount
:
12
,
sourceBranch
:
'
mr-widget-refactor
'
,
sourceBranchLink
:
'
<a href="/foo/bar/mr-widget-refactor">mr-widget-refactor</a>
'
,
sourceBranchRemoved
:
false
,
targetBranchPath
:
'
foo/bar/commits-path
'
,
targetBranchTreePath
:
'
foo/bar/tree/path
'
,
targetBranch
:
'
master
'
,
isOpen
:
true
,
emailPatchesPath
:
'
/mr/email-patches
'
,
plainDiffPath
:
'
/mr/plainDiffPath
'
,
}
});
vm
=
mountComponent
(
Component
,
{
mr
:
{
divergedCommitsCount
:
12
,
sourceBranch
:
'
mr-widget-refactor
'
,
sourceBranchLink
:
'
<a href="/foo/bar/mr-widget-refactor">mr-widget-refactor</a>
'
,
sourceBranchRemoved
:
false
,
targetBranchPath
:
'
foo/bar/commits-path
'
,
targetBranchTreePath
:
'
foo/bar/tree/path
'
,
targetBranch
:
'
master
'
,
isOpen
:
true
,
emailPatchesPath
:
'
/mr/email-patches
'
,
plainDiffPath
:
'
/mr/plainDiffPath
'
,
statusPath
:
'
abc
'
,
},
});
});
it
(
'
renders diverged commits info
'
,
()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.diverged-commits-count
'
).
textContent
.
trim
()).
toEqual
(
'
(12 commits behind)
'
);
expect
(
vm
.
$el
.
querySelector
(
'
.diverged-commits-count
'
).
textContent
.
trim
()).
toEqual
(
'
(12 commits behind)
'
,
);
});
});
});
...
...
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