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
0d7afb95
Commit
0d7afb95
authored
May 29, 2019
by
Denys Mishunov
Committed by
Fatih Acet
May 29, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Updated heading for default state in Web IDE
Resolves
https://gitlab.com/gitlab-org/gitlab-ce/issues/60107
parent
4ca791e6
Changes
21
Hide whitespace changes
Inline
Side-by-side
Showing
21 changed files
with
620 additions
and
244 deletions
+620
-244
app/assets/javascripts/ide/components/ide.vue
app/assets/javascripts/ide/components/ide.vue
+34
-6
app/assets/javascripts/ide/components/ide_tree_list.vue
app/assets/javascripts/ide/components/ide_tree_list.vue
+11
-8
app/assets/javascripts/ide/stores/actions.js
app/assets/javascripts/ide/stores/actions.js
+51
-1
app/assets/javascripts/ide/stores/actions/project.js
app/assets/javascripts/ide/stores/actions/project.js
+51
-67
app/assets/javascripts/ide/stores/actions/tree.js
app/assets/javascripts/ide/stores/actions/tree.js
+7
-11
app/assets/javascripts/ide/stores/getters.js
app/assets/javascripts/ide/stores/getters.js
+3
-0
app/assets/javascripts/ide/stores/modules/commit/actions.js
app/assets/javascripts/ide/stores/modules/commit/actions.js
+11
-0
app/assets/javascripts/ide/stores/mutation_types.js
app/assets/javascripts/ide/stores/mutation_types.js
+1
-0
app/assets/javascripts/ide/stores/mutations/branch.js
app/assets/javascripts/ide/stores/mutations/branch.js
+6
-0
app/assets/javascripts/ide/stores/mutations/project.js
app/assets/javascripts/ide/stores/mutations/project.js
+5
-0
changelogs/unreleased/45687-web-ide-empty-state.yml
changelogs/unreleased/45687-web-ide-empty-state.yml
+5
-0
lib/api/entities.rb
lib/api/entities.rb
+1
-0
locale/gitlab.pot
locale/gitlab.pot
+18
-0
spec/frontend/ide/stores/mutations/branch_spec.js
spec/frontend/ide/stores/mutations/branch_spec.js
+35
-0
spec/frontend/ide/stores/mutations/project_spec.js
spec/frontend/ide/stores/mutations/project_spec.js
+23
-0
spec/javascripts/ide/components/ide_spec.js
spec/javascripts/ide/components/ide_spec.js
+65
-27
spec/javascripts/ide/components/ide_tree_list_spec.js
spec/javascripts/ide/components/ide_tree_list_spec.js
+41
-18
spec/javascripts/ide/stores/actions/project_spec.js
spec/javascripts/ide/stores/actions/project_spec.js
+129
-74
spec/javascripts/ide/stores/actions/tree_spec.js
spec/javascripts/ide/stores/actions/tree_spec.js
+0
-32
spec/javascripts/ide/stores/actions_spec.js
spec/javascripts/ide/stores/actions_spec.js
+64
-0
spec/javascripts/ide/stores/modules/commit/actions_spec.js
spec/javascripts/ide/stores/modules/commit/actions_spec.js
+59
-0
No files found.
app/assets/javascripts/ide/components/ide.vue
View file @
0d7afb95
<
script
>
import
Vue
from
'
vue
'
;
import
{
mapActions
,
mapState
,
mapGetters
}
from
'
vuex
'
;
import
{
GlButton
,
GlLoadingIcon
}
from
'
@gitlab/ui
'
;
import
{
__
}
from
'
~/locale
'
;
import
FindFile
from
'
~/vue_shared/components/file_finder/index.vue
'
;
import
NewModal
from
'
./new_dropdown/modal.vue
'
;
...
...
@@ -22,6 +23,8 @@ export default {
FindFile
,
ErrorMessage
,
CommitEditorHeader
,
GlButton
,
GlLoadingIcon
,
},
props
:
{
rightPaneComponent
:
{
...
...
@@ -47,13 +50,15 @@ export default {
'
someUncommittedChanges
'
,
'
isCommitModeActive
'
,
'
allBlobs
'
,
'
emptyRepo
'
,
'
currentTree
'
,
]),
},
mounted
()
{
window
.
onbeforeunload
=
e
=>
this
.
onBeforeUnload
(
e
);
},
methods
:
{
...
mapActions
([
'
toggleFileFinder
'
]),
...
mapActions
([
'
toggleFileFinder
'
,
'
openNewEntryModal
'
]),
onBeforeUnload
(
e
=
{})
{
const
returnValue
=
__
(
'
Are you sure you want to lose unsaved changes?
'
);
...
...
@@ -98,17 +103,40 @@ export default {
<repo-editor
:file=
"activeFile"
class=
"multi-file-edit-pane-content"
/>
</
template
>
<
template
v-else
>
<div
v-once
class=
"ide-empty-state"
>
<div
class=
"ide-empty-state"
>
<div
class=
"row js-empty-state"
>
<div
class=
"col-12"
>
<div
class=
"svg-content svg-250"
><img
:src=
"emptyStateSvgPath"
/></div>
</div>
<div
class=
"col-12"
>
<div
class=
"text-content text-center"
>
<h4>
Welcome to the GitLab IDE
</h4>
<p>
Select a file from the left sidebar to begin editing. Afterwards, you'll be able
to commit your changes.
<h4>
{{
__
(
'
Make and review changes in the browser with the Web IDE
'
)
}}
</h4>
<template
v-if=
"emptyRepo"
>
<p>
{{
__
(
"
Create a new file as there are no files yet. Afterwards, you'll be able to commit your changes.
"
,
)
}}
</p>
<gl-button
variant=
"success"
:title=
"__('New file')"
:aria-label=
"__('New file')"
@
click=
"openNewEntryModal(
{ type: 'blob' })"
>
{{
__
(
'
New file
'
)
}}
</gl-button>
</
template
>
<gl-loading-icon
v-else-if=
"!currentTree || currentTree.loading"
size=
"md"
/>
<p
v-else
>
{{
__(
"Select a file from the left sidebar to begin editing. Afterwards, you'll be able to commit your changes.",
)
}}
</p>
</div>
</div>
...
...
app/assets/javascripts/ide/components/ide_tree_list.vue
View file @
0d7afb95
...
...
@@ -54,14 +54,17 @@ export default {
<slot
name=
"header"
></slot>
</header>
<div
class=
"ide-tree-body h-100"
>
<file-row
v-for=
"file in currentTree.tree"
:key=
"file.key"
:file=
"file"
:level=
"0"
:extra-component=
"$options.FileRowExtra"
@
toggleTreeOpen=
"toggleTreeOpen"
/>
<template
v-if=
"currentTree.tree.length"
>
<file-row
v-for=
"file in currentTree.tree"
:key=
"file.key"
:file=
"file"
:level=
"0"
:extra-component=
"$options.FileRowExtra"
@
toggleTreeOpen=
"toggleTreeOpen"
/>
</
template
>
<div
v-else
class=
"file-row"
>
{{ __('No files') }}
</div>
</div>
</template>
</div>
...
...
app/assets/javascripts/ide/stores/actions.js
View file @
0d7afb95
import
$
from
'
jquery
'
;
import
Vue
from
'
vue
'
;
import
{
__
,
sprintf
}
from
'
~/locale
'
;
import
{
visitUrl
}
from
'
~/lib/utils/url_utility
'
;
import
flash
from
'
~/flash
'
;
import
_
from
'
underscore
'
;
import
*
as
types
from
'
./mutation_types
'
;
import
{
decorateFiles
}
from
'
../lib/files
'
;
import
{
stageKeys
}
from
'
../constants
'
;
import
service
from
'
../services
'
;
export
const
redirectToUrl
=
(
_
,
url
)
=>
visitUrl
(
url
);
export
const
redirectToUrl
=
(
self
,
url
)
=>
visitUrl
(
url
);
export
const
setInitialData
=
({
commit
},
data
)
=>
commit
(
types
.
SET_INITIAL_DATA
,
data
);
...
...
@@ -239,6 +242,53 @@ export const renameEntry = (
}
};
export
const
getBranchData
=
({
commit
,
state
},
{
projectId
,
branchId
,
force
=
false
}
=
{})
=>
new
Promise
((
resolve
,
reject
)
=>
{
const
currentProject
=
state
.
projects
[
projectId
];
if
(
!
currentProject
||
!
currentProject
.
branches
[
branchId
]
||
force
)
{
service
.
getBranchData
(
projectId
,
branchId
)
.
then
(({
data
})
=>
{
const
{
id
}
=
data
.
commit
;
commit
(
types
.
SET_BRANCH
,
{
projectPath
:
projectId
,
branchName
:
branchId
,
branch
:
data
,
});
commit
(
types
.
SET_BRANCH_WORKING_REFERENCE
,
{
projectId
,
branchId
,
reference
:
id
});
resolve
(
data
);
})
.
catch
(
e
=>
{
if
(
e
.
response
.
status
===
404
)
{
reject
(
e
);
}
else
{
flash
(
__
(
'
Error loading branch data. Please try again.
'
),
'
alert
'
,
document
,
null
,
false
,
true
,
);
reject
(
new
Error
(
sprintf
(
__
(
'
Branch not loaded - %{branchId}
'
),
{
branchId
:
`<strong>
${
_
.
escape
(
projectId
)}
/
${
_
.
escape
(
branchId
)}
</strong>`
,
},
false
,
),
),
);
}
});
}
else
{
resolve
(
currentProject
.
branches
[
branchId
]);
}
});
export
*
from
'
./actions/tree
'
;
export
*
from
'
./actions/file
'
;
export
*
from
'
./actions/project
'
;
...
...
app/assets/javascripts/ide/stores/actions/project.js
View file @
0d7afb95
...
...
@@ -35,48 +35,6 @@ export const getProjectData = ({ commit, state }, { namespace, projectId, force
}
});
export
const
getBranchData
=
(
{
commit
,
dispatch
,
state
},
{
projectId
,
branchId
,
force
=
false
}
=
{},
)
=>
new
Promise
((
resolve
,
reject
)
=>
{
if
(
typeof
state
.
projects
[
`
${
projectId
}
`
]
===
'
undefined
'
||
!
state
.
projects
[
`
${
projectId
}
`
].
branches
[
branchId
]
||
force
)
{
service
.
getBranchData
(
`
${
projectId
}
`
,
branchId
)
.
then
(({
data
})
=>
{
const
{
id
}
=
data
.
commit
;
commit
(
types
.
SET_BRANCH
,
{
projectPath
:
`
${
projectId
}
`
,
branchName
:
branchId
,
branch
:
data
,
});
commit
(
types
.
SET_BRANCH_WORKING_REFERENCE
,
{
projectId
,
branchId
,
reference
:
id
});
resolve
(
data
);
})
.
catch
(
e
=>
{
if
(
e
.
response
.
status
===
404
)
{
dispatch
(
'
showBranchNotFoundError
'
,
branchId
);
}
else
{
flash
(
__
(
'
Error loading branch data. Please try again.
'
),
'
alert
'
,
document
,
null
,
false
,
true
,
);
}
reject
(
new
Error
(
`Branch not loaded -
${
projectId
}
/
${
branchId
}
`
));
});
}
else
{
resolve
(
state
.
projects
[
`
${
projectId
}
`
].
branches
[
branchId
]);
}
});
export
const
refreshLastCommitData
=
({
commit
},
{
projectId
,
branchId
}
=
{})
=>
service
.
getBranchData
(
projectId
,
branchId
)
...
...
@@ -125,40 +83,66 @@ export const showBranchNotFoundError = ({ dispatch }, branchId) => {
});
};
export
const
openBranch
=
({
dispatch
,
state
},
{
projectId
,
branchId
,
basePath
})
=>
{
dispatch
(
'
setCurrentBranchId
'
,
branchId
)
;
dispatch
(
'
getBranchData
'
,
{
projectId
,
branchId
,
export
const
showEmptyState
=
({
commit
,
state
},
{
projectId
,
branchId
})
=>
{
const
treePath
=
`
${
projectId
}
/
${
branchId
}
`
;
commit
(
types
.
CREATE_TREE
,
{
treePath
});
commit
(
types
.
TOGGLE_LOADING
,
{
entry
:
state
.
trees
[
treePath
]
,
forceValue
:
false
,
});
};
return
dispatch
(
'
getFiles
'
,
{
export
const
openBranch
=
({
dispatch
,
state
,
getters
},
{
projectId
,
branchId
,
basePath
})
=>
{
dispatch
(
'
setCurrentBranchId
'
,
branchId
);
if
(
getters
.
emptyRepo
)
{
return
dispatch
(
'
showEmptyState
'
,
{
projectId
,
branchId
});
}
return
dispatch
(
'
getBranchData
'
,
{
projectId
,
branchId
,
})
.
then
(()
=>
{
if
(
basePath
)
{
const
path
=
basePath
.
slice
(
-
1
)
===
'
/
'
?
basePath
.
slice
(
0
,
-
1
)
:
basePath
;
const
treeEntryKey
=
Object
.
keys
(
state
.
entries
).
find
(
key
=>
key
===
path
&&
!
state
.
entries
[
key
].
pending
,
);
const
treeEntry
=
state
.
entries
[
treeEntryKey
];
if
(
treeEntry
)
{
dispatch
(
'
handleTreeEntryAction
'
,
treeEntry
);
}
else
{
dispatch
(
'
createTempEntry
'
,
{
name
:
path
,
type
:
'
blob
'
,
});
}
}
})
.
then
(()
=>
{
dispatch
(
'
getMergeRequestsForBranch
'
,
{
projectId
,
branchId
,
});
dispatch
(
'
getFiles
'
,
{
projectId
,
branchId
,
})
.
then
(()
=>
{
if
(
basePath
)
{
const
path
=
basePath
.
slice
(
-
1
)
===
'
/
'
?
basePath
.
slice
(
0
,
-
1
)
:
basePath
;
const
treeEntryKey
=
Object
.
keys
(
state
.
entries
).
find
(
key
=>
key
===
path
&&
!
state
.
entries
[
key
].
pending
,
);
const
treeEntry
=
state
.
entries
[
treeEntryKey
];
if
(
treeEntry
)
{
dispatch
(
'
handleTreeEntryAction
'
,
treeEntry
);
}
else
{
dispatch
(
'
createTempEntry
'
,
{
name
:
path
,
type
:
'
blob
'
,
});
}
}
})
.
catch
(
()
=>
new
Error
(
sprintf
(
__
(
'
An error occurred whilst getting files for - %{branchId}
'
),
{
branchId
:
`<strong>
${
_
.
escape
(
projectId
)}
/
${
_
.
escape
(
branchId
)}
</strong>`
,
},
false
,
),
),
);
})
.
catch
(()
=>
{
dispatch
(
'
showBranchNotFoundError
'
,
branchId
);
});
};
app/assets/javascripts/ide/stores/actions/tree.js
View file @
0d7afb95
...
...
@@ -74,17 +74,13 @@ export const getFiles = ({ state, commit, dispatch }, { projectId, branchId } =
resolve
();
})
.
catch
(
e
=>
{
if
(
e
.
response
.
status
===
404
)
{
dispatch
(
'
showBranchNotFoundError
'
,
branchId
);
}
else
{
dispatch
(
'
setErrorMessage
'
,
{
text
:
__
(
'
An error occurred whilst loading all the files.
'
),
action
:
payload
=>
dispatch
(
'
getFiles
'
,
payload
).
then
(()
=>
dispatch
(
'
setErrorMessage
'
,
null
)),
actionText
:
__
(
'
Please try again
'
),
actionPayload
:
{
projectId
,
branchId
},
});
}
dispatch
(
'
setErrorMessage
'
,
{
text
:
__
(
'
An error occurred whilst loading all the files.
'
),
action
:
payload
=>
dispatch
(
'
getFiles
'
,
payload
).
then
(()
=>
dispatch
(
'
setErrorMessage
'
,
null
)),
actionText
:
__
(
'
Please try again
'
),
actionPayload
:
{
projectId
,
branchId
},
});
reject
(
e
);
});
}
else
{
...
...
app/assets/javascripts/ide/stores/getters.js
View file @
0d7afb95
...
...
@@ -36,6 +36,9 @@ export const currentMergeRequest = state => {
export
const
currentProject
=
state
=>
state
.
projects
[
state
.
currentProjectId
];
export
const
emptyRepo
=
state
=>
state
.
projects
[
state
.
currentProjectId
]
&&
state
.
projects
[
state
.
currentProjectId
].
empty_repo
;
export
const
currentTree
=
state
=>
state
.
trees
[
`
${
state
.
currentProjectId
}
/
${
state
.
currentBranchId
}
`
];
...
...
app/assets/javascripts/ide/stores/modules/commit/actions.js
View file @
0d7afb95
...
...
@@ -135,6 +135,17 @@ export const commitChanges = ({ commit, state, getters, dispatch, rootState, roo
return
null
;
}
if
(
!
data
.
parent_ids
.
length
)
{
commit
(
rootTypes
.
TOGGLE_EMPTY_STATE
,
{
projectPath
:
rootState
.
currentProjectId
,
value
:
false
,
},
{
root
:
true
},
);
}
dispatch
(
'
setLastCommitMessage
'
,
data
);
dispatch
(
'
updateCommitMessage
'
,
''
);
return
dispatch
(
'
updateFilesAfterCommit
'
,
{
...
...
app/assets/javascripts/ide/stores/mutation_types.js
View file @
0d7afb95
...
...
@@ -12,6 +12,7 @@ export const SET_LINKS = 'SET_LINKS';
export
const
SET_PROJECT
=
'
SET_PROJECT
'
;
export
const
SET_CURRENT_PROJECT
=
'
SET_CURRENT_PROJECT
'
;
export
const
TOGGLE_PROJECT_OPEN
=
'
TOGGLE_PROJECT_OPEN
'
;
export
const
TOGGLE_EMPTY_STATE
=
'
TOGGLE_EMPTY_STATE
'
;
// Merge Request Mutation Types
export
const
SET_MERGE_REQUEST
=
'
SET_MERGE_REQUEST
'
;
...
...
app/assets/javascripts/ide/stores/mutations/branch.js
View file @
0d7afb95
...
...
@@ -19,6 +19,12 @@ export default {
});
},
[
types
.
SET_BRANCH_WORKING_REFERENCE
](
state
,
{
projectId
,
branchId
,
reference
})
{
if
(
!
state
.
projects
[
projectId
].
branches
[
branchId
])
{
Object
.
assign
(
state
.
projects
[
projectId
].
branches
,
{
[
branchId
]:
{},
});
}
Object
.
assign
(
state
.
projects
[
projectId
].
branches
[
branchId
],
{
workingReference
:
reference
,
});
...
...
app/assets/javascripts/ide/stores/mutations/project.js
View file @
0d7afb95
...
...
@@ -21,4 +21,9 @@ export default {
}),
});
},
[
types
.
TOGGLE_EMPTY_STATE
](
state
,
{
projectPath
,
value
})
{
Object
.
assign
(
state
.
projects
[
projectPath
],
{
empty_repo
:
value
,
});
},
};
changelogs/unreleased/45687-web-ide-empty-state.yml
0 → 100644
View file @
0d7afb95
---
title
:
Empty project state for Web IDE
merge_request
:
26556
author
:
type
:
added
lib/api/entities.rb
View file @
0d7afb95
...
...
@@ -239,6 +239,7 @@ module API
end
end
expose
:empty_repo?
,
as: :empty_repo
expose
:archived?
,
as: :archived
expose
:visibility
expose
:owner
,
using:
Entities
::
UserBasic
,
unless:
->
(
project
,
options
)
{
project
.
group
}
...
...
locale/gitlab.pot
View file @
0d7afb95
...
...
@@ -952,6 +952,9 @@ msgstr ""
msgid "An error occurred whilst fetching the latest pipeline."
msgstr ""
msgid "An error occurred whilst getting files for - %{branchId}"
msgstr ""
msgid "An error occurred whilst loading all the files."
msgstr ""
...
...
@@ -1482,6 +1485,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
msgid "Branch not loaded - %{branchId}"
msgstr ""
msgid "BranchSwitcherPlaceholder|Search branches"
msgstr ""
...
...
@@ -2993,6 +2999,9 @@ msgstr ""
msgid "Create a new branch"
msgstr ""
msgid "Create a new file as there are no files yet. Afterwards, you'll be able to commit your changes."
msgstr ""
msgid "Create a new issue"
msgstr ""
...
...
@@ -5796,6 +5805,9 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
msgid "Make and review changes in the browser with the Web IDE"
msgstr ""
msgid "Make issue confidential."
msgstr ""
...
...
@@ -6452,6 +6464,9 @@ msgstr ""
msgid "No file selected"
msgstr ""
msgid "No files"
msgstr ""
msgid "No files found."
msgstr ""
...
...
@@ -8615,6 +8630,9 @@ msgstr ""
msgid "Select Archive Format"
msgstr ""
msgid "Select a file from the left sidebar to begin editing. Afterwards, you'll be able to commit your changes."
msgstr ""
msgid "Select a group to invite"
msgstr ""
...
...
spec/frontend/ide/stores/mutations/branch_spec.js
View file @
0d7afb95
...
...
@@ -37,4 +37,39 @@ describe('Multi-file store branch mutations', () => {
expect
(
localState
.
projects
.
Example
.
branches
.
master
.
commit
.
title
).
toBe
(
'
Example commit
'
);
});
});
describe
(
'
SET_BRANCH_WORKING_REFERENCE
'
,
()
=>
{
beforeEach
(()
=>
{
localState
.
projects
=
{
Foo
:
{
branches
:
{
bar
:
{},
},
},
};
});
it
(
'
sets workingReference for existing branch
'
,
()
=>
{
mutations
.
SET_BRANCH_WORKING_REFERENCE
(
localState
,
{
projectId
:
'
Foo
'
,
branchId
:
'
bar
'
,
reference
:
'
foo-bar-ref
'
,
});
expect
(
localState
.
projects
.
Foo
.
branches
.
bar
.
workingReference
).
toBe
(
'
foo-bar-ref
'
);
});
it
(
'
does not fail on non-existent just yet branch
'
,
()
=>
{
expect
(
localState
.
projects
.
Foo
.
branches
.
unknown
).
toBeUndefined
();
mutations
.
SET_BRANCH_WORKING_REFERENCE
(
localState
,
{
projectId
:
'
Foo
'
,
branchId
:
'
unknown
'
,
reference
:
'
fun-fun-ref
'
,
});
expect
(
localState
.
projects
.
Foo
.
branches
.
unknown
).
not
.
toBeUndefined
();
expect
(
localState
.
projects
.
Foo
.
branches
.
unknown
.
workingReference
).
toBe
(
'
fun-fun-ref
'
);
});
});
});
spec/frontend/ide/stores/mutations/project_spec.js
0 → 100644
View file @
0d7afb95
import
mutations
from
'
~/ide/stores/mutations/project
'
;
import
state
from
'
~/ide/stores/state
'
;
describe
(
'
Multi-file store branch mutations
'
,
()
=>
{
let
localState
;
beforeEach
(()
=>
{
localState
=
state
();
localState
.
projects
=
{
abcproject
:
{
empty_repo
:
true
}
};
});
describe
(
'
TOGGLE_EMPTY_STATE
'
,
()
=>
{
it
(
'
sets empty_repo for project to passed value
'
,
()
=>
{
mutations
.
TOGGLE_EMPTY_STATE
(
localState
,
{
projectPath
:
'
abcproject
'
,
value
:
false
});
expect
(
localState
.
projects
.
abcproject
.
empty_repo
).
toBe
(
false
);
mutations
.
TOGGLE_EMPTY_STATE
(
localState
,
{
projectPath
:
'
abcproject
'
,
value
:
true
});
expect
(
localState
.
projects
.
abcproject
.
empty_repo
).
toBe
(
true
);
});
});
});
spec/javascripts/ide/components/ide_spec.js
View file @
0d7afb95
...
...
@@ -5,21 +5,53 @@ import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helpe
import
{
file
,
resetStore
}
from
'
../helpers
'
;
import
{
projectData
}
from
'
../mock_data
'
;
describe
(
'
ide component
'
,
()
=>
{
function
bootstrap
(
projData
)
{
const
Component
=
Vue
.
extend
(
ide
);
store
.
state
.
currentProjectId
=
'
abcproject
'
;
store
.
state
.
currentBranchId
=
'
master
'
;
store
.
state
.
projects
.
abcproject
=
Object
.
assign
({},
projData
);
Vue
.
set
(
store
.
state
.
trees
,
'
abcproject/master
'
,
{
tree
:
[],
loading
:
false
,
});
return
createComponentWithStore
(
Component
,
store
,
{
emptyStateSvgPath
:
'
svg
'
,
noChangesStateSvgPath
:
'
svg
'
,
committedStateSvgPath
:
'
svg
'
,
});
}
describe
(
'
ide component, empty repo
'
,
()
=>
{
let
vm
;
beforeEach
(()
=>
{
const
Component
=
Vue
.
extend
(
ide
);
const
emptyProjData
=
Object
.
assign
({},
projectData
,
{
empty_repo
:
true
,
branches
:
{}
});
vm
=
bootstrap
(
emptyProjData
);
vm
.
$mount
();
});
store
.
state
.
currentProjectId
=
'
abcproject
'
;
store
.
state
.
currentBranchId
=
'
master
'
;
store
.
state
.
projects
.
abcproject
=
Object
.
assign
({},
projectData
);
afterEach
(()
=>
{
vm
.
$destroy
();
resetStore
(
vm
.
$store
);
});
vm
=
createComponentWithStore
(
Component
,
store
,
{
emptyStateSvgPath
:
'
svg
'
,
noChangesStateSvgPath
:
'
svg
'
,
committedStateSvgPath
:
'
svg
'
,
}).
$mount
();
it
(
'
renders "New file" button in empty repo
'
,
done
=>
{
vm
.
$nextTick
(()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.ide-empty-state button[title="New file"]
'
)).
not
.
toBeNull
();
done
();
});
});
});
describe
(
'
ide component, non-empty repo
'
,
()
=>
{
let
vm
;
beforeEach
(()
=>
{
vm
=
bootstrap
(
projectData
);
vm
.
$mount
();
});
afterEach
(()
=>
{
...
...
@@ -28,17 +60,15 @@ describe('ide component', () => {
resetStore
(
vm
.
$store
);
});
it
(
'
does not render right when no files open
'
,
()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.panel-right
'
)).
toBeNull
();
});
it
(
'
shows error message when set
'
,
done
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.flash-container
'
)).
toBe
(
null
);
it
(
'
renders right panel when files are open
'
,
done
=>
{
vm
.
$store
.
state
.
trees
[
'
abcproject/mybranch
'
]
=
{
tree
:
[
file
()],
vm
.
$store
.
state
.
errorMessage
=
{
text
:
'
error
'
,
};
Vue
.
nextTick
(()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.
panel-right
'
)).
toBeNull
(
);
vm
.
$
nextTick
(()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.
flash-container
'
)).
not
.
toBe
(
null
);
done
();
});
...
...
@@ -71,17 +101,25 @@ describe('ide component', () => {
});
});
it
(
'
shows error message when set
'
,
done
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.flash-container
'
)).
toBe
(
null
);
vm
.
$store
.
state
.
errorMessage
=
{
text
:
'
error
'
,
};
describe
(
'
non-existent branch
'
,
()
=>
{
it
(
'
does not render "New file" button for non-existent branch when repo is not empty
'
,
done
=>
{
vm
.
$nextTick
(()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.ide-empty-state button[title="New file"]
'
)).
toBeNull
();
done
();
});
});
});
vm
.
$nextTick
(()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.flash-container
'
)).
not
.
toBe
(
null
);
describe
(
'
branch with files
'
,
()
=>
{
beforeEach
(()
=>
{
store
.
state
.
trees
[
'
abcproject/master
'
].
tree
=
[
file
()];
});
done
();
it
(
'
does not render "New file" button
'
,
done
=>
{
vm
.
$nextTick
(()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.ide-empty-state button[title="New file"]
'
)).
toBeNull
();
done
();
});
});
});
});
spec/javascripts/ide/components/ide_tree_list_spec.js
View file @
0d7afb95
...
...
@@ -7,25 +7,23 @@ import { projectData } from '../mock_data';
describe
(
'
IDE tree list
'
,
()
=>
{
const
Component
=
Vue
.
extend
(
IdeTreeList
);
const
normalBranchTree
=
[
file
(
'
fileName
'
)];
const
emptyBranchTree
=
[];
let
vm
;
beforeEach
((
)
=>
{
const
bootstrapWithTree
=
(
tree
=
normalBranchTree
)
=>
{
store
.
state
.
currentProjectId
=
'
abcproject
'
;
store
.
state
.
currentBranchId
=
'
master
'
;
store
.
state
.
projects
.
abcproject
=
Object
.
assign
({},
projectData
);
Vue
.
set
(
store
.
state
.
trees
,
'
abcproject/master
'
,
{
tree
:
[
file
(
'
fileName
'
)]
,
tree
,
loading
:
false
,
});
vm
=
createComponentWithStore
(
Component
,
store
,
{
viewerType
:
'
edit
'
,
});
spyOn
(
vm
,
'
updateViewer
'
).
and
.
callThrough
();
vm
.
$mount
();
});
};
afterEach
(()
=>
{
vm
.
$destroy
();
...
...
@@ -33,22 +31,47 @@ describe('IDE tree list', () => {
resetStore
(
vm
.
$store
);
});
it
(
'
updates viewer on mount
'
,
()
=>
{
expect
(
vm
.
updateViewer
).
toHaveBeenCalledWith
(
'
edit
'
);
});
describe
(
'
normal branch
'
,
()
=>
{
beforeEach
(()
=>
{
bootstrapWithTree
();
spyOn
(
vm
,
'
updateViewer
'
).
and
.
callThrough
();
vm
.
$mount
();
});
it
(
'
updates viewer on mount
'
,
()
=>
{
expect
(
vm
.
updateViewer
).
toHaveBeenCalledWith
(
'
edit
'
);
});
it
(
'
renders loading indicator
'
,
done
=>
{
store
.
state
.
trees
[
'
abcproject/master
'
].
loading
=
true
;
it
(
'
renders loading indicator
'
,
done
=>
{
store
.
state
.
trees
[
'
abcproject/master
'
].
loading
=
true
;
vm
.
$nextTick
(()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.multi-file-loading-container
'
)).
not
.
toBeNull
();
expect
(
vm
.
$el
.
querySelectorAll
(
'
.multi-file-loading-container
'
).
length
).
toBe
(
3
);
vm
.
$nextTick
(()
=>
{
expect
(
vm
.
$el
.
querySelector
(
'
.multi-file-loading-container
'
)).
not
.
toBeNull
(
);
expect
(
vm
.
$el
.
querySelectorAll
(
'
.multi-file-loading-container
'
).
length
).
toBe
(
3
);
done
();
}
);
}
);
done
();
it
(
'
renders list of files
'
,
()
=>
{
expect
(
vm
.
$el
.
textContent
).
toContain
(
'
fileName
'
);
});
});
it
(
'
renders list of files
'
,
()
=>
{
expect
(
vm
.
$el
.
textContent
).
toContain
(
'
fileName
'
);
describe
(
'
empty-branch state
'
,
()
=>
{
beforeEach
(()
=>
{
bootstrapWithTree
(
emptyBranchTree
);
spyOn
(
vm
,
'
updateViewer
'
).
and
.
callThrough
();
vm
.
$mount
();
});
it
(
'
does not load files if the branch is empty
'
,
()
=>
{
expect
(
vm
.
$el
.
textContent
).
not
.
toContain
(
'
fileName
'
);
expect
(
vm
.
$el
.
textContent
).
toContain
(
'
No files
'
);
});
});
});
spec/javascripts/ide/stores/actions/project_spec.js
View file @
0d7afb95
...
...
@@ -4,7 +4,7 @@ import {
refreshLastCommitData
,
showBranchNotFoundError
,
createNewBranchFromDefault
,
getBranchData
,
showEmptyState
,
openBranch
,
}
from
'
~/ide/stores/actions
'
;
import
store
from
'
~/ide/stores
'
;
...
...
@@ -196,39 +196,44 @@ describe('IDE store project actions', () => {
});
});
describe
(
'
getBranchData
'
,
()
=>
{
describe
(
'
error
'
,
()
=>
{
it
(
'
dispatches branch not found action when response is 404
'
,
done
=>
{
const
dispatch
=
jasmine
.
createSpy
(
'
dispatchSpy
'
);
mock
.
onGet
(
/
(
.*
)
/
).
replyOnce
(
404
);
getBranchData
(
describe
(
'
showEmptyState
'
,
()
=>
{
it
(
'
commits proper mutations when supplied error is 404
'
,
done
=>
{
testAction
(
showEmptyState
,
{
err
:
{
response
:
{
status
:
404
,
},
},
projectId
:
'
abc/def
'
,
branchId
:
'
master
'
,
},
store
.
state
,
[
{
commit
()
{},
dispatch
,
state
:
store
.
state
,
type
:
'
CREATE_TREE
'
,
payload
:
{
treePath
:
'
abc/def/master
'
,
},
},
{
projectId
:
'
abc/def
'
,
branchId
:
'
master-testing
'
,
type
:
'
TOGGLE_LOADING
'
,
payload
:
{
entry
:
store
.
state
.
trees
[
'
abc/def/master
'
],
forceValue
:
false
,
},
},
)
.
then
(
done
.
fail
)
.
catch
(()
=>
{
expect
(
dispatch
.
calls
.
argsFor
(
0
)).
toEqual
([
'
showBranchNotFoundError
'
,
'
master-testing
'
,
]);
done
();
});
});
],
[],
done
,
);
});
});
describe
(
'
openBranch
'
,
()
=>
{
const
branch
=
{
projectId
:
'
feature/lorem-ipsum
'
,
projectId
:
'
abc/def
'
,
branchId
:
'
123-lorem
'
,
};
...
...
@@ -238,63 +243,113 @@ describe('IDE store project actions', () => {
'
foo/bar-pending
'
:
{
pending
:
true
},
'
foo/bar
'
:
{
pending
:
false
},
};
spyOn
(
store
,
'
dispatch
'
).
and
.
returnValue
(
Promise
.
resolve
());
});
it
(
'
dispatches branch actions
'
,
done
=>
{
openBranch
(
store
,
branch
)
.
then
(()
=>
{
expect
(
store
.
dispatch
.
calls
.
allArgs
()).
toEqual
([
[
'
setCurrentBranchId
'
,
branch
.
branchId
],
[
'
getBranchData
'
,
branch
],
[
'
getFiles
'
,
branch
],
[
'
getMergeRequestsForBranch
'
,
branch
],
]);
})
.
then
(
done
)
.
catch
(
done
.
fail
);
});
describe
(
'
empty repo
'
,
()
=>
{
beforeEach
(()
=>
{
spyOn
(
store
,
'
dispatch
'
).
and
.
returnValue
(
Promise
.
resolve
());
it
(
'
handles tree entry action, if basePath is given
'
,
done
=>
{
openBranch
(
store
,
{
...
branch
,
basePath
:
'
foo/bar/
'
})
.
then
(()
=>
{
expect
(
store
.
dispatch
).
toHaveBeenCalledWith
(
'
handleTreeEntryAction
'
,
store
.
state
.
entries
[
'
foo/bar
'
],
);
})
.
then
(
done
)
.
catch
(
done
.
fail
);
store
.
state
.
currentProjectId
=
'
abc/def
'
;
store
.
state
.
projects
[
'
abc/def
'
]
=
{
empty_repo
:
true
,
};
});
afterEach
(()
=>
{
resetStore
(
store
);
});
it
(
'
dispatches showEmptyState action right away
'
,
done
=>
{
openBranch
(
store
,
branch
)
.
then
(()
=>
{
expect
(
store
.
dispatch
.
calls
.
allArgs
()).
toEqual
([
[
'
setCurrentBranchId
'
,
branch
.
branchId
],
[
'
showEmptyState
'
,
branch
],
]);
done
();
})
.
catch
(
done
.
fail
);
});
});
it
(
'
does not handle tree entry action, if entry is pending
'
,
done
=>
{
openBranch
(
store
,
{
...
branch
,
basePath
:
'
foo/bar-pending
'
})
.
then
(()
=>
{
expect
(
store
.
dispatch
).
not
.
toHaveBeenCalledWith
(
'
handleTreeEntryAction
'
,
jasmine
.
anything
(),
);
})
.
then
(
done
)
.
catch
(
done
.
fail
);
describe
(
'
existing branch
'
,
()
=>
{
beforeEach
(()
=>
{
spyOn
(
store
,
'
dispatch
'
).
and
.
returnValue
(
Promise
.
resolve
());
});
it
(
'
dispatches branch actions
'
,
done
=>
{
openBranch
(
store
,
branch
)
.
then
(()
=>
{
expect
(
store
.
dispatch
.
calls
.
allArgs
()).
toEqual
([
[
'
setCurrentBranchId
'
,
branch
.
branchId
],
[
'
getBranchData
'
,
branch
],
[
'
getMergeRequestsForBranch
'
,
branch
],
[
'
getFiles
'
,
branch
],
]);
})
.
then
(
done
)
.
catch
(
done
.
fail
);
});
it
(
'
handles tree entry action, if basePath is given
'
,
done
=>
{
openBranch
(
store
,
{
...
branch
,
basePath
:
'
foo/bar/
'
})
.
then
(()
=>
{
expect
(
store
.
dispatch
).
toHaveBeenCalledWith
(
'
handleTreeEntryAction
'
,
store
.
state
.
entries
[
'
foo/bar
'
],
);
})
.
then
(
done
)
.
catch
(
done
.
fail
);
});
it
(
'
does not handle tree entry action, if entry is pending
'
,
done
=>
{
openBranch
(
store
,
{
...
branch
,
basePath
:
'
foo/bar-pending
'
})
.
then
(()
=>
{
expect
(
store
.
dispatch
).
not
.
toHaveBeenCalledWith
(
'
handleTreeEntryAction
'
,
jasmine
.
anything
(),
);
})
.
then
(
done
)
.
catch
(
done
.
fail
);
});
it
(
'
creates a new file supplied via URL if the file does not exist yet
'
,
done
=>
{
openBranch
(
store
,
{
...
branch
,
basePath
:
'
not-existent.md
'
})
.
then
(()
=>
{
expect
(
store
.
dispatch
).
not
.
toHaveBeenCalledWith
(
'
handleTreeEntryAction
'
,
jasmine
.
anything
(),
);
expect
(
store
.
dispatch
).
toHaveBeenCalledWith
(
'
createTempEntry
'
,
{
name
:
'
not-existent.md
'
,
type
:
'
blob
'
,
});
})
.
then
(
done
)
.
catch
(
done
.
fail
);
});
});
it
(
'
creates a new file supplied via URL if the file does not exist yet
'
,
done
=>
{
openBranch
(
store
,
{
...
branch
,
basePath
:
'
not-existent.md
'
})
.
then
(()
=>
{
expect
(
store
.
dispatch
).
not
.
toHaveBeenCalledWith
(
'
handleTreeEntryAction
'
,
jasmine
.
anything
(),
);
describe
(
'
non-existent branch
'
,
()
=>
{
beforeEach
(()
=>
{
spyOn
(
store
,
'
dispatch
'
).
and
.
returnValue
(
Promise
.
reject
());
});
expect
(
store
.
dispatch
).
toHaveBeenCalledWith
(
'
createTempEntry
'
,
{
name
:
'
not-existent.md
'
,
type
:
'
blob
'
,
});
})
.
then
(
done
)
.
catch
(
done
.
fail
);
it
(
'
dispatches correct branch actions
'
,
done
=>
{
openBranch
(
store
,
branch
)
.
then
(()
=>
{
expect
(
store
.
dispatch
.
calls
.
allArgs
()).
toEqual
([
[
'
setCurrentBranchId
'
,
branch
.
branchId
],
[
'
getBranchData
'
,
branch
],
[
'
showBranchNotFoundError
'
,
branch
.
branchId
],
]);
})
.
then
(
done
)
.
catch
(
done
.
fail
);
});
});
});
});
spec/javascripts/ide/stores/actions/tree_spec.js
View file @
0d7afb95
...
...
@@ -93,38 +93,6 @@ describe('Multi-file store tree actions', () => {
});
describe
(
'
error
'
,
()
=>
{
it
(
'
dispatches branch not found actions when response is 404
'
,
done
=>
{
const
dispatch
=
jasmine
.
createSpy
(
'
dispatchSpy
'
);
store
.
state
.
projects
=
{
'
abc/def
'
:
{
web_url
:
`
${
gl
.
TEST_HOST
}
/files`
,
},
};
mock
.
onGet
(
/
(
.*
)
/
).
replyOnce
(
404
);
getFiles
(
{
commit
()
{},
dispatch
,
state
:
store
.
state
,
},
{
projectId
:
'
abc/def
'
,
branchId
:
'
master-testing
'
,
},
)
.
then
(
done
.
fail
)
.
catch
(()
=>
{
expect
(
dispatch
.
calls
.
argsFor
(
0
)).
toEqual
([
'
showBranchNotFoundError
'
,
'
master-testing
'
,
]);
done
();
});
});
it
(
'
dispatches error action
'
,
done
=>
{
const
dispatch
=
jasmine
.
createSpy
(
'
dispatchSpy
'
);
...
...
spec/javascripts/ide/stores/actions_spec.js
View file @
0d7afb95
...
...
@@ -9,12 +9,15 @@ import actions, {
setErrorMessage
,
deleteEntry
,
renameEntry
,
getBranchData
,
}
from
'
~/ide/stores/actions
'
;
import
axios
from
'
~/lib/utils/axios_utils
'
;
import
store
from
'
~/ide/stores
'
;
import
*
as
types
from
'
~/ide/stores/mutation_types
'
;
import
router
from
'
~/ide/ide_router
'
;
import
{
resetStore
,
file
}
from
'
../helpers
'
;
import
testAction
from
'
../../helpers/vuex_action_helper
'
;
import
MockAdapter
from
'
axios-mock-adapter
'
;
describe
(
'
Multi-file store actions
'
,
()
=>
{
beforeEach
(()
=>
{
...
...
@@ -560,4 +563,65 @@ describe('Multi-file store actions', () => {
);
});
});
describe
(
'
getBranchData
'
,
()
=>
{
let
mock
;
beforeEach
(()
=>
{
mock
=
new
MockAdapter
(
axios
);
});
afterEach
(()
=>
{
mock
.
restore
();
});
describe
(
'
error
'
,
()
=>
{
let
dispatch
;
const
callParams
=
[
{
commit
()
{},
state
:
store
.
state
,
},
{
projectId
:
'
abc/def
'
,
branchId
:
'
master-testing
'
,
},
];
beforeEach
(()
=>
{
dispatch
=
jasmine
.
createSpy
(
'
dispatchSpy
'
);
document
.
body
.
innerHTML
+=
'
<div class="flash-container"></div>
'
;
});
afterEach
(()
=>
{
document
.
querySelector
(
'
.flash-container
'
).
remove
();
});
it
(
'
passes the error further unchanged without dispatching any action when response is 404
'
,
done
=>
{
mock
.
onGet
(
/
(
.*
)
/
).
replyOnce
(
404
);
getBranchData
(...
callParams
)
.
then
(
done
.
fail
)
.
catch
(
e
=>
{
expect
(
dispatch
.
calls
.
count
()).
toEqual
(
0
);
expect
(
e
.
response
.
status
).
toEqual
(
404
);
expect
(
document
.
querySelector
(
'
.flash-alert
'
)).
toBeNull
();
done
();
});
});
it
(
'
does not pass the error further and flashes an alert if error is not 404
'
,
done
=>
{
mock
.
onGet
(
/
(
.*
)
/
).
replyOnce
(
418
);
getBranchData
(...
callParams
)
.
then
(
done
.
fail
)
.
catch
(
e
=>
{
expect
(
dispatch
.
calls
.
count
()).
toEqual
(
0
);
expect
(
e
.
response
).
toBeUndefined
();
expect
(
document
.
querySelector
(
'
.flash-alert
'
)).
not
.
toBeNull
();
done
();
});
});
});
});
});
spec/javascripts/ide/stores/modules/commit/actions_spec.js
View file @
0d7afb95
...
...
@@ -272,6 +272,7 @@ describe('IDE commit module actions', () => {
short_id
:
'
123
'
,
message
:
'
test message
'
,
committed_date
:
'
date
'
,
parent_ids
:
'
321
'
,
stats
:
{
additions
:
'
1
'
,
deletions
:
'
2
'
,
...
...
@@ -463,5 +464,63 @@ describe('IDE commit module actions', () => {
.
catch
(
done
.
fail
);
});
});
describe
(
'
first commit of a branch
'
,
()
=>
{
const
COMMIT_RESPONSE
=
{
id
:
'
123456
'
,
short_id
:
'
123
'
,
message
:
'
test message
'
,
committed_date
:
'
date
'
,
parent_ids
:
[],
stats
:
{
additions
:
'
1
'
,
deletions
:
'
2
'
,
},
};
it
(
'
commits TOGGLE_EMPTY_STATE mutation on empty repo
'
,
done
=>
{
spyOn
(
service
,
'
commit
'
).
and
.
returnValue
(
Promise
.
resolve
({
data
:
COMMIT_RESPONSE
,
}),
);
spyOn
(
store
,
'
commit
'
).
and
.
callThrough
();
store
.
dispatch
(
'
commit/commitChanges
'
)
.
then
(()
=>
{
expect
(
store
.
commit
.
calls
.
allArgs
()).
toEqual
(
jasmine
.
arrayContaining
([
[
'
TOGGLE_EMPTY_STATE
'
,
jasmine
.
any
(
Object
),
jasmine
.
any
(
Object
)],
]),
);
done
();
})
.
catch
(
done
.
fail
);
});
it
(
'
does not commmit TOGGLE_EMPTY_STATE mutation on existing project
'
,
done
=>
{
COMMIT_RESPONSE
.
parent_ids
.
push
(
'
1234
'
);
spyOn
(
service
,
'
commit
'
).
and
.
returnValue
(
Promise
.
resolve
({
data
:
COMMIT_RESPONSE
,
}),
);
spyOn
(
store
,
'
commit
'
).
and
.
callThrough
();
store
.
dispatch
(
'
commit/commitChanges
'
)
.
then
(()
=>
{
expect
(
store
.
commit
.
calls
.
allArgs
()).
not
.
toEqual
(
jasmine
.
arrayContaining
([
[
'
TOGGLE_EMPTY_STATE
'
,
jasmine
.
any
(
Object
),
jasmine
.
any
(
Object
)],
]),
);
done
();
})
.
catch
(
done
.
fail
);
});
});
});
});
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