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
62a0a5dc
Commit
62a0a5dc
authored
Aug 11, 2020
by
Coung Ngo
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refactor Jira importer code
Refactor code to move state closer to where it's used
parent
6966a8fb
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
106 additions
and
118 deletions
+106
-118
app/assets/javascripts/jira_import/components/jira_import_app.vue
...ts/javascripts/jira_import/components/jira_import_app.vue
+2
-29
app/assets/javascripts/jira_import/components/jira_import_form.vue
...s/javascripts/jira_import/components/jira_import_form.vue
+43
-24
spec/frontend/jira_import/components/jira_import_app_spec.js
spec/frontend/jira_import/components/jira_import_app_spec.js
+16
-48
spec/frontend/jira_import/components/jira_import_form_spec.js
.../frontend/jira_import/components/jira_import_form_spec.js
+45
-17
No files found.
app/assets/javascripts/jira_import/components/jira_import_app.vue
View file @
62a0a5dc
<
script
>
import
{
GlAlert
,
GlLoadingIcon
,
GlSprintf
}
from
'
@gitlab/ui
'
;
import
{
GlAlert
,
GlLoadingIcon
}
from
'
@gitlab/ui
'
;
import
{
last
}
from
'
lodash
'
;
import
{
__
}
from
'
~/locale
'
;
import
getJiraImportDetailsQuery
from
'
../queries/get_jira_import_details.query.graphql
'
;
...
...
@@ -16,7 +16,6 @@ export default {
components
:
{
GlAlert
,
GlLoadingIcon
,
GlSprintf
,
JiraImportForm
,
JiraImportProgress
,
JiraImportSetup
,
...
...
@@ -55,7 +54,6 @@ export default {
return
{
isSubmitting
:
false
,
jiraImportDetails
:
{},
selectedProject
:
undefined
,
userMappings
:
[],
errorMessage
:
''
,
showAlert
:
false
,
...
...
@@ -80,22 +78,6 @@ export default {
},
},
},
computed
:
{
numberOfPreviousImports
()
{
return
this
.
jiraImportDetails
.
imports
?.
reduce
?.(
(
acc
,
jiraProject
)
=>
(
jiraProject
.
jiraProjectKey
===
this
.
selectedProject
?
acc
+
1
:
acc
),
0
,
);
},
hasPreviousImports
()
{
return
this
.
numberOfPreviousImports
>
0
;
},
importLabel
()
{
return
this
.
selectedProject
?
`jira-import::
${
this
.
selectedProject
}
-
${
this
.
numberOfPreviousImports
+
1
}
`
:
'
jira-import::KEY-1
'
;
},
},
mounted
()
{
if
(
this
.
isJiraConfigured
)
{
this
.
$apollo
...
...
@@ -168,9 +150,6 @@ export default {
this
.
showAlert
=
false
;
},
},
previousImportsMessage
:
__
(
'
You have imported from this project %{numberOfPreviousImports} times before. Each new import will create duplicate issues.
'
,
),
};
</
script
>
...
...
@@ -179,11 +158,6 @@ export default {
<gl-alert
v-if=
"showAlert"
variant=
"danger"
@
dismiss=
"dismissAlert"
>
{{
errorMessage
}}
</gl-alert>
<gl-alert
v-if=
"hasPreviousImports"
variant=
"warning"
:dismissible=
"false"
>
<gl-sprintf
:message=
"$options.previousImportsMessage"
>
<template
#numberOfPreviousImports
>
{{
numberOfPreviousImports
}}
</
template
>
</gl-sprintf>
</gl-alert>
<jira-import-setup
v-if=
"!isJiraConfigured"
...
...
@@ -201,10 +175,9 @@ export default {
/>
<jira-import-form
v-else
v-model=
"selectedProject"
:import-label=
"importLabel"
:is-submitting=
"isSubmitting"
:issues-path=
"issuesPath"
:jira-imports=
"jiraImportDetails.imports"
:jira-projects=
"jiraImportDetails.projects"
:project-id=
"projectId"
:user-mappings=
"userMappings"
...
...
app/assets/javascripts/jira_import/components/jira_import_form.vue
View file @
62a0a5dc
<
script
>
import
{
GlAlert
,
GlButton
,
GlNewDropdown
,
GlNewDropdownItem
,
...
...
@@ -10,15 +11,19 @@ import {
GlLabel
,
GlLoadingIcon
,
GlSearchBoxByType
,
GlSprintf
,
GlTable
,
}
from
'
@gitlab/ui
'
;
import
{
debounce
}
from
'
lodash
'
;
import
axios
from
'
~/lib/utils/axios_utils
'
;
import
{
__
}
from
'
~/locale
'
;
const
debounceWait
=
500
;
export
default
{
name
:
'
JiraImportForm
'
,
components
:
{
GlAlert
,
GlButton
,
GlNewDropdown
,
GlNewDropdownItem
,
...
...
@@ -29,10 +34,13 @@ export default {
GlLabel
,
GlLoadingIcon
,
GlSearchBoxByType
,
GlSprintf
,
GlTable
,
},
currentUsername
:
gon
.
current_username
,
dropdownLabel
:
__
(
'
The GitLab user to which the Jira user %{jiraDisplayName} will be mapped
'
),
previousImportsMessage
:
__
(
`You have imported from this project %{numberOfPreviousImports} times
before. Each new import will create duplicate issues.`
),
tableConfig
:
[
{
key
:
'
jiraDisplayName
'
,
...
...
@@ -47,11 +55,10 @@ export default {
label
:
__
(
'
GitLab username
'
),
},
],
userMappingMessage
:
__
(
`Jira users have been imported from the configured Jira instance.
They can be mapped by selecting a GitLab user from the dropdown in the "GitLab username" column.
When the form appears, the dropdown defaults to the user conducting the import.`
),
props
:
{
importLabel
:
{
type
:
String
,
required
:
true
,
},
isSubmitting
:
{
type
:
Boolean
,
required
:
true
,
...
...
@@ -60,6 +67,10 @@ export default {
type
:
String
,
required
:
true
,
},
jiraImports
:
{
type
:
Array
,
required
:
true
,
},
jiraProjects
:
{
type
:
Array
,
required
:
true
,
...
...
@@ -72,16 +83,12 @@ export default {
type
:
Array
,
required
:
true
,
},
value
:
{
type
:
String
,
required
:
false
,
default
:
undefined
,
},
},
data
()
{
return
{
isFetching
:
false
,
searchTerm
:
''
,
selectedProject
:
undefined
,
selectState
:
null
,
users
:
[],
};
...
...
@@ -90,11 +97,25 @@ export default {
shouldShowNoMatchesFoundText
()
{
return
!
this
.
isFetching
&&
this
.
users
.
length
===
0
;
},
numberOfPreviousImports
()
{
return
this
.
jiraImports
?.
reduce
?.(
(
acc
,
jiraProject
)
=>
(
jiraProject
.
jiraProjectKey
===
this
.
selectedProject
?
acc
+
1
:
acc
),
0
,
);
},
hasPreviousImports
()
{
return
this
.
numberOfPreviousImports
>
0
;
},
importLabel
()
{
return
this
.
selectedProject
?
`jira-import::
${
this
.
selectedProject
}
-
${
this
.
numberOfPreviousImports
+
1
}
`
:
'
jira-import::KEY-1
'
;
},
},
watch
:
{
searchTerm
:
debounce
(
function
debouncedUserSearch
()
{
this
.
searchUsers
();
},
500
),
},
debounceWait
),
},
mounted
()
{
this
.
searchUsers
()
...
...
@@ -129,9 +150,9 @@ export default {
},
initiateJiraImport
(
event
)
{
event
.
preventDefault
();
if
(
this
.
value
)
{
if
(
this
.
selectedProject
)
{
this
.
hideValidationError
();
this
.
$emit
(
'
initiateJiraImport
'
,
this
.
value
);
this
.
$emit
(
'
initiateJiraImport
'
,
this
.
selectedProject
);
}
else
{
this
.
showValidationError
();
}
...
...
@@ -148,8 +169,16 @@ export default {
<
template
>
<div>
<gl-alert
v-if=
"hasPreviousImports"
variant=
"warning"
:dismissible=
"false"
>
<gl-sprintf
:message=
"$options.previousImportsMessage"
>
<template
#numberOfPreviousImports
>
{{
numberOfPreviousImports
}}
</
template
>
</gl-sprintf>
</gl-alert>
<h3
class=
"page-title"
>
{{ __('New Jira import') }}
</h3>
<hr
/>
<form
@
submit=
"initiateJiraImport"
>
<gl-form-group
class=
"row align-items-center"
...
...
@@ -160,12 +189,11 @@ export default {
>
<gl-form-select
id=
"jira-project-select"
v-model=
"selectedProject"
data-qa-selector=
"jira_project_dropdown"
class=
"mb-2"
:options=
"jiraProjects"
:state=
"selectState"
:value=
"value"
@
change=
"$emit('input', $event)"
/>
</gl-form-group>
...
...
@@ -186,16 +214,7 @@ export default {
<h4
class=
"gl-mb-4"
>
{{ __('Jira-GitLab user mapping template') }}
</h4>
<p>
{{
__
(
`Jira users have been imported from the configured Jira instance.
They can be mapped by selecting a GitLab user from the dropdown in the "GitLab
username" column.
When the form appears, the dropdown defaults to the user conducting the import.`
,
)
}}
</p>
<p>
{{ $options.userMappingMessage }}
</p>
<gl-table
:fields=
"$options.tableConfig"
:items=
"userMappings"
fixed
>
<
template
#cell
(
arrow
)
>
...
...
spec/frontend/jira_import/components/jira_import_app_spec.js
View file @
62a0a5dc
import
{
GlAlert
,
GlLoadingIcon
}
from
'
@gitlab/ui
'
;
import
{
mount
,
shallowMount
}
from
'
@vue/test-utils
'
;
import
{
shallowMount
}
from
'
@vue/test-utils
'
;
import
AxiosMockAdapter
from
'
axios-mock-adapter
'
;
import
Vue
from
'
vue
'
;
import
axios
from
'
~/lib/utils/axios_utils
'
;
...
...
@@ -29,14 +29,12 @@ describe('JiraImportApp', () => {
const
mountComponent
=
({
isJiraConfigured
=
true
,
errorMessage
=
''
,
selectedProject
=
'
MTG
'
,
showAlert
=
false
,
isInProgress
=
false
,
loading
=
false
,
mutate
=
mutateSpy
,
mountFunction
=
shallowMount
,
}
=
{})
=>
mountFunction
(
JiraImportApp
,
{
shallowMount
(
JiraImportApp
,
{
propsData
:
{
inProgressIllustration
:
'
in-progress-illustration.svg
'
,
isJiraConfigured
,
...
...
@@ -49,7 +47,6 @@ describe('JiraImportApp', () => {
data
()
{
return
{
isSubmitting
:
false
,
selectedProject
,
userMappings
,
errorMessage
,
showAlert
,
...
...
@@ -202,38 +199,6 @@ describe('JiraImportApp', () => {
});
});
describe
(
'
jira import form screen
'
,
()
=>
{
describe
(
'
when selected project has been imported before
'
,
()
=>
{
it
(
'
shows jira-import::MTG-3 label since project MTG has been imported 2 time before
'
,
()
=>
{
wrapper
=
mountComponent
();
expect
(
getFormComponent
().
props
(
'
importLabel
'
)).
toBe
(
'
jira-import::MTG-3
'
);
});
it
(
'
shows warning alert to explain project MTG has been imported 2 times before
'
,
()
=>
{
wrapper
=
mountComponent
({
mountFunction
:
mount
});
expect
(
getAlert
().
text
()).
toBe
(
'
You have imported from this project 2 times before. Each new import will create duplicate issues.
'
,
);
});
});
describe
(
'
when selected project has not been imported before
'
,
()
=>
{
beforeEach
(()
=>
{
wrapper
=
mountComponent
({
selectedProject
:
'
MJP
'
});
});
it
(
'
shows jira-import::MJP-1 label since project MJP has not been imported before
'
,
()
=>
{
expect
(
getFormComponent
().
props
(
'
importLabel
'
)).
toBe
(
'
jira-import::MJP-1
'
);
});
it
(
'
does not show warning alert since project MJP has not been imported before
'
,
()
=>
{
expect
(
getAlert
().
exists
()).
toBe
(
false
);
});
});
});
describe
(
'
initiating a Jira import
'
,
()
=>
{
it
(
'
calls the mutation with the expected arguments
'
,
()
=>
{
wrapper
=
mountComponent
();
...
...
@@ -263,7 +228,7 @@ describe('JiraImportApp', () => {
expect
(
mutateSpy
).
toHaveBeenCalledWith
(
expect
.
objectContaining
(
mutationArguments
));
});
it
(
'
shows alert message with error message on error
'
,
()
=>
{
it
(
'
shows alert message with error message on error
'
,
async
()
=>
{
const
mutate
=
jest
.
fn
(()
=>
Promise
.
reject
());
wrapper
=
mountComponent
({
mutate
});
...
...
@@ -271,16 +236,15 @@ describe('JiraImportApp', () => {
getFormComponent
().
vm
.
$emit
(
'
initiateJiraImport
'
,
'
MTG
'
);
// One tick doesn't update the dom to the desired state so we have two ticks here
return
Vue
.
nextTick
()
.
then
(
Vue
.
nextTick
)
.
then
(()
=>
{
await
Vue
.
nextTick
();
await
Vue
.
nextTick
();
expect
(
getAlert
().
text
()).
toBe
(
'
There was an error importing the Jira project.
'
);
});
});
});
describe
(
'
alert
'
,
()
=>
{
it
(
'
can be dismissed
'
,
()
=>
{
it
(
'
can be dismissed
'
,
async
()
=>
{
wrapper
=
mountComponent
({
errorMessage
:
'
There was an error importing the Jira project.
'
,
showAlert
:
true
,
...
...
@@ -291,11 +255,11 @@ describe('JiraImportApp', () => {
getAlert
().
vm
.
$emit
(
'
dismiss
'
);
return
Vue
.
nextTick
().
then
(()
=>
{
await
Vue
.
nextTick
();
expect
(
getAlert
().
exists
()).
toBe
(
false
);
});
});
});
describe
(
'
on mount
'
,
()
=>
{
it
(
'
makes a GraphQL mutation call to get user mappings
'
,
()
=>
{
...
...
@@ -319,11 +283,15 @@ describe('JiraImportApp', () => {
expect
(
mutateSpy
).
not
.
toHaveBeenCalled
();
});
it
(
'
shows error message when there is an error with the GraphQL mutation call
'
,
()
=>
{
it
(
'
shows error message when there is an error with the GraphQL mutation call
'
,
async
()
=>
{
const
mutate
=
jest
.
fn
(()
=>
Promise
.
reject
());
wrapper
=
mountComponent
({
mutate
});
// One tick doesn't update the dom to the desired state so we have two ticks here
await
Vue
.
nextTick
();
await
Vue
.
nextTick
();
expect
(
getAlert
().
exists
()).
toBe
(
true
);
});
});
...
...
spec/frontend/jira_import/components/jira_import_form_spec.js
View file @
62a0a5dc
import
{
GlButton
,
GlNewDropdown
,
GlFormSelect
,
GlLabel
,
GlTable
}
from
'
@gitlab/ui
'
;
import
{
Gl
Alert
,
Gl
Button
,
GlNewDropdown
,
GlFormSelect
,
GlLabel
,
GlTable
}
from
'
@gitlab/ui
'
;
import
{
getByRole
}
from
'
@testing-library/dom
'
;
import
{
mount
,
shallowMount
}
from
'
@vue/test-utils
'
;
import
AxiosMockAdapter
from
'
axios-mock-adapter
'
;
import
axios
from
'
~/lib/utils/axios_utils
'
;
import
JiraImportForm
from
'
~/jira_import/components/jira_import_form.vue
'
;
import
{
issuesPath
,
jiraProjects
,
userMappings
as
defaultUserMappings
}
from
'
../mock_data
'
;
import
{
imports
,
issuesPath
,
jiraProjects
,
userMappings
as
defaultUserMappings
,
}
from
'
../mock_data
'
;
describe
(
'
JiraImportForm
'
,
()
=>
{
let
axiosMock
;
let
wrapper
;
const
currentUsername
=
'
mrgitlab
'
;
const
importLabel
=
'
jira-import::MTG-1
'
;
const
value
=
'
MTG
'
;
const
getAlert
=
()
=>
wrapper
.
find
(
GlAlert
)
;
const
getSelectDropdown
=
()
=>
wrapper
.
find
(
GlFormSelect
);
...
...
@@ -20,6 +25,8 @@ describe('JiraImportForm', () => {
const
getCancelButton
=
()
=>
wrapper
.
findAll
(
GlButton
).
at
(
1
);
const
getLabel
=
()
=>
wrapper
.
find
(
GlLabel
);
const
getTable
=
()
=>
wrapper
.
find
(
GlTable
);
const
getUserDropdown
=
()
=>
getTable
().
find
(
GlNewDropdown
);
...
...
@@ -28,22 +35,23 @@ describe('JiraImportForm', () => {
const
mountComponent
=
({
isSubmitting
=
false
,
selectedProject
=
'
MTG
'
,
userMappings
=
defaultUserMappings
,
mountFunction
=
shallowMount
,
}
=
{})
=>
mountFunction
(
JiraImportForm
,
{
propsData
:
{
importLabel
,
isSubmitting
,
issuesPath
,
jiraImports
:
imports
,
jiraProjects
,
projectId
:
'
5
'
,
userMappings
,
value
,
},
data
:
()
=>
({
isFetching
:
false
,
searchTerm
:
''
,
selectedProject
,
selectState
:
null
,
users
:
[],
}),
...
...
@@ -60,7 +68,7 @@ describe('JiraImportForm', () => {
wrapper
=
null
;
});
describe
(
'
select dropdown
'
,
()
=>
{
describe
(
'
select dropdown
project selection
'
,
()
=>
{
it
(
'
is shown
'
,
()
=>
{
wrapper
=
mountComponent
();
...
...
@@ -77,22 +85,40 @@ describe('JiraImportForm', () => {
});
});
it
(
'
emits an "input" event when the input select value changes
'
,
()
=>
{
describe
(
'
when selected project has been imported before
'
,
()
=>
{
it
(
'
shows jira-import::MTG-3 label since project MTG has been imported 2 time before
'
,
()
=>
{
wrapper
=
mountComponent
();
getSelectDropdown
().
vm
.
$emit
(
'
change
'
,
value
);
expect
(
getLabel
().
props
(
'
title
'
)).
toBe
(
'
jira-import::MTG-3
'
);
});
expect
(
wrapper
.
emitted
(
'
input
'
)[
0
]).
toEqual
([
value
]);
it
(
'
shows warning alert to explain project MTG has been imported 2 times before
'
,
()
=>
{
wrapper
=
mountComponent
({
mountFunction
:
mount
});
expect
(
getAlert
().
text
()).
toBe
(
'
You have imported from this project 2 times before. Each new import will create duplicate issues.
'
,
);
});
});
describe
(
'
form information
'
,
()
=>
{
describe
(
'
when selected project has not been imported before
'
,
()
=>
{
beforeEach
(()
=>
{
wrapper
=
mountComponent
(
);
wrapper
=
mountComponent
({
selectedProject
:
'
MJP
'
}
);
});
it
(
'
shows a label which will be applied to imported Jira projects
'
,
()
=>
{
expect
(
wrapper
.
find
(
GlLabel
).
props
(
'
title
'
)).
toBe
(
importLabel
);
it
(
'
shows jira-import::MJP-1 label since project MJP has not been imported before
'
,
()
=>
{
expect
(
getLabel
().
props
(
'
title
'
)).
toBe
(
'
jira-import::MJP-1
'
);
});
it
(
'
does not show warning alert since project MJP has not been imported before
'
,
()
=>
{
expect
(
getAlert
().
exists
()).
toBe
(
false
);
});
});
});
describe
(
'
form information
'
,
()
=>
{
beforeEach
(()
=>
{
wrapper
=
mountComponent
();
});
it
(
'
shows a heading for the user mapping section
'
,
()
=>
{
...
...
@@ -214,11 +240,13 @@ describe('JiraImportForm', () => {
describe
(
'
form
'
,
()
=>
{
it
(
'
emits an "initiateJiraImport" event with the selected dropdown value when submitted
'
,
()
=>
{
wrapper
=
mountComponent
();
const
selectedProject
=
'
MTG
'
;
wrapper
=
mountComponent
({
selectedProject
});
wrapper
.
find
(
'
form
'
).
trigger
(
'
submit
'
);
expect
(
wrapper
.
emitted
(
'
initiateJiraImport
'
)[
0
]).
toEqual
([
value
]);
expect
(
wrapper
.
emitted
(
'
initiateJiraImport
'
)[
0
]).
toEqual
([
selectedProject
]);
});
});
});
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