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
17a35da6
Commit
17a35da6
authored
Oct 30, 2017
by
Filipa Lacerda
Committed by
Phil Hughes
Oct 30, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Ee 38869 importer status - Remove code from global namespace
parent
3dc544f4
Changes
13
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
306 additions
and
477 deletions
+306
-477
app/assets/javascripts/boards/components/board_sidebar.js
app/assets/javascripts/boards/components/board_sidebar.js
+1
-1
app/assets/javascripts/dispatcher.js
app/assets/javascripts/dispatcher.js
+3
-3
app/assets/javascripts/importer_status.js
app/assets/javascripts/importer_status.js
+71
-73
app/assets/javascripts/init_issuable_sidebar.js
app/assets/javascripts/init_issuable_sidebar.js
+1
-1
app/assets/javascripts/issuable_bulk_update_actions.js
app/assets/javascripts/issuable_bulk_update_actions.js
+0
-1
app/assets/javascripts/issuable_bulk_update_sidebar.js
app/assets/javascripts/issuable_bulk_update_sidebar.js
+4
-0
app/assets/javascripts/issuable_context.js
app/assets/javascripts/issuable_context.js
+56
-57
app/assets/javascripts/issuable_form.js
app/assets/javascripts/issuable_form.js
+97
-100
app/assets/javascripts/issuable_index.js
app/assets/javascripts/issuable_index.js
+36
-165
app/assets/javascripts/main.js
app/assets/javascripts/main.js
+2
-3
spec/javascripts/issuable_context_spec.js
spec/javascripts/issuable_context_spec.js
+1
-2
spec/javascripts/issuable_spec.js
spec/javascripts/issuable_spec.js
+33
-69
spec/javascripts/labels_issue_sidebar_spec.js
spec/javascripts/labels_issue_sidebar_spec.js
+1
-2
No files found.
app/assets/javascripts/boards/components/board_sidebar.js
View file @
17a35da6
/* eslint-disable comma-dangle, space-before-function-paren, no-new */
/* global IssuableContext */
/* global MilestoneSelect */
/* global LabelsSelect */
/* global Sidebar */
...
...
@@ -11,6 +10,7 @@ import AssigneeTitle from '../../sidebar/components/assignees/assignee_title';
import
Assignees
from
'
../../sidebar/components/assignees/assignees
'
;
import
DueDateSelectors
from
'
../../due_date_select
'
;
import
'
./sidebar/remove_issue
'
;
import
IssuableContext
from
'
../../issuable_context
'
;
const
Store
=
gl
.
issueBoards
.
BoardsStore
;
...
...
app/assets/javascripts/dispatcher.js
View file @
17a35da6
/* eslint-disable func-names, space-before-function-paren, no-var, prefer-arrow-callback, wrap-iife, no-shadow, consistent-return, one-var, one-var-declaration-per-line, camelcase, default-case, no-new, quotes, no-duplicate-case, no-case-declarations, no-fallthrough, max-len */
/* global ProjectSelect */
/* global IssuableIndex */
import
IssuableIndex
from
'
./issuable_index
'
;
/* global Milestone */
/* global IssuableForm */
import
IssuableForm
from
'
./issuable_form
'
;
/* global LabelsSelect */
/* global MilestoneSelect */
/* global NewBranchForm */
...
...
@@ -197,7 +197,7 @@ import initGroupAnalytics from './init_group_analytics';
filteredSearchManager
.
setup
();
}
const
pagePrefix
=
page
===
'
projects:merge_requests:index
'
?
'
merge_request_
'
:
'
issue_
'
;
IssuableIndex
.
init
(
pagePrefix
);
new
IssuableIndex
(
pagePrefix
);
shortcut_handler
=
new
ShortcutsNavigation
();
new
UsersSelect
();
...
...
app/assets/javascripts/importer_status.js
View file @
17a35da6
/* eslint-disable func-names, space-before-function-paren, wrap-iife, camelcase, no-var, one-var, one-var-declaration-per-line, prefer-template, quotes, object-shorthand, comma-dangle, no-unused-vars, prefer-arrow-callback, no-else-return, vars-on-top, no-new, max-len */
class
ImporterStatus
{
constructor
(
jobsUrl
,
importUrl
)
{
this
.
jobsUrl
=
jobsUrl
;
this
.
importUrl
=
importUrl
;
this
.
initStatusPage
();
this
.
setAutoUpdate
();
}
(
function
()
{
window
.
ImporterStatus
=
(
function
()
{
function
ImporterStatus
(
jobs_url
,
import_url
)
{
this
.
jobs_url
=
jobs_url
;
this
.
import_url
=
import_url
;
this
.
initStatusPage
();
this
.
setAutoUpdate
();
}
initStatusPage
()
{
$
(
'
.js-add-to-import
'
)
.
off
(
'
click
'
)
.
on
(
'
click
'
,
(
event
)
=>
{
const
$btn
=
$
(
event
.
currentTarget
);
const
$tr
=
$btn
.
closest
(
'
tr
'
);
const
$targetField
=
$tr
.
find
(
'
.import-target
'
);
const
$namespaceInput
=
$targetField
.
find
(
'
.js-select-namespace option:selected
'
);
const
id
=
$tr
.
attr
(
'
id
'
).
replace
(
'
repo_
'
,
''
);
let
targetNamespace
;
let
newName
;
if
(
$namespaceInput
.
length
>
0
)
{
targetNamespace
=
$namespaceInput
[
0
].
innerHTML
;
newName
=
$targetField
.
find
(
'
#path
'
).
prop
(
'
value
'
);
$targetField
.
empty
().
append
(
`
${
targetNamespace
}
/
${
newName
}
`
);
}
$btn
.
disable
().
addClass
(
'
is-loading
'
);
ImporterStatus
.
prototype
.
initStatusPage
=
function
()
{
$
(
'
.js-add-to-import
'
).
off
(
'
click
'
).
on
(
'
click
'
,
(
function
(
_this
)
{
return
function
(
e
)
{
var
$btn
,
$namespace_input
,
$target_field
,
$tr
,
id
,
target_namespace
,
newName
;
$btn
=
$
(
e
.
currentTarget
);
$tr
=
$btn
.
closest
(
'
tr
'
);
$target_field
=
$tr
.
find
(
'
.import-target
'
);
$namespace_input
=
$target_field
.
find
(
'
.js-select-namespace option:selected
'
);
id
=
$tr
.
attr
(
'
id
'
).
replace
(
'
repo_
'
,
''
);
target_namespace
=
null
;
newName
=
null
;
if
(
$namespace_input
.
length
>
0
)
{
target_namespace
=
$namespace_input
[
0
].
innerHTML
;
newName
=
$target_field
.
find
(
'
#path
'
).
prop
(
'
value
'
);
$target_field
.
empty
().
append
(
target_namespace
+
"
/
"
+
newName
);
}
$btn
.
disable
().
addClass
(
'
is-loading
'
);
return
$
.
post
(
_this
.
import_url
,
{
repo_id
:
id
,
target_namespace
:
target_namespace
,
new_name
:
newName
},
{
dataType
:
'
script
'
});
};
})(
this
));
return
$
(
'
.js-import-all
'
).
off
(
'
click
'
).
on
(
'
click
'
,
function
(
e
)
{
var
$btn
;
$btn
=
$
(
this
);
return
$
.
post
(
this
.
importUrl
,
{
repo_id
:
id
,
target_namespace
:
targetNamespace
,
new_name
:
newName
,
},
{
dataType
:
'
script
'
,
});
});
$
(
'
.js-import-all
'
)
.
off
(
'
click
'
)
.
on
(
'
click
'
,
function
onClickImportAll
()
{
const
$btn
=
$
(
this
);
$btn
.
disable
().
addClass
(
'
is-loading
'
);
return
$
(
'
.js-add-to-import
'
).
each
(
function
()
{
return
$
(
'
.js-add-to-import
'
).
each
(
function
triggerAddImport
()
{
return
$
(
this
).
trigger
(
'
click
'
);
});
});
};
}
setAutoUpdate
()
{
return
setInterval
(()
=>
$
.
get
(
this
.
jobsUrl
,
data
=>
$
.
each
(
data
,
(
i
,
job
)
=>
{
const
jobItem
=
$
(
`#project_
${
job
.
id
}
`
);
const
statusField
=
jobItem
.
find
(
'
.job-status
'
);
ImporterStatus
.
prototype
.
setAutoUpdate
=
function
()
{
return
setInterval
(((
function
(
_this
)
{
return
function
()
{
return
$
.
get
(
_this
.
jobs_url
,
function
(
data
)
{
return
$
.
each
(
data
,
function
(
i
,
job
)
{
var
job_item
,
status_field
;
job_item
=
$
(
"
#project_
"
+
job
.
id
);
status_field
=
job_item
.
find
(
"
.job-status
"
);
if
(
job
.
import_status
===
'
finished
'
)
{
job_item
.
removeClass
(
"
active
"
).
addClass
(
"
success
"
);
return
status_field
.
html
(
'
<span><i class="fa fa-check"></i> done</span>
'
);
}
else
if
(
job
.
import_status
===
'
scheduled
'
)
{
return
status_field
.
html
(
"
<i class='fa fa-spinner fa-spin'></i> scheduled
"
);
}
else
if
(
job
.
import_status
===
'
started
'
)
{
return
status_field
.
html
(
"
<i class='fa fa-spinner fa-spin'></i> started
"
);
}
else
{
return
status_field
.
html
(
job
.
import_status
);
}
});
});
};
})(
this
)),
4000
);
};
const
spinner
=
'
<i class="fa fa-spinner fa-spin"></i>
'
;
return
ImporterStatus
;
})();
switch
(
job
.
import_status
)
{
case
'
finished
'
:
jobItem
.
removeClass
(
'
active
'
).
addClass
(
'
success
'
);
statusField
.
html
(
'
<span><i class="fa fa-check"></i> done</span>
'
);
break
;
case
'
scheduled
'
:
statusField
.
html
(
`
${
spinner
}
scheduled`
);
break
;
case
'
started
'
:
statusField
.
html
(
`
${
spinner
}
started`
);
break
;
default
:
statusField
.
html
(
job
.
import_status
);
break
;
}
})),
4000
);
}
}
$
(
function
()
{
if
(
$
(
'
.js-importer-status
'
).
length
)
{
var
jobsImportPath
=
$
(
'
.js-importer-status
'
).
data
(
'
jobs-import-path
'
);
var
importPath
=
$
(
'
.js-importer-status
'
).
data
(
'
import-path
'
);
// eslint-disable-next-line consistent-return
export
default
function
initImporterStatus
()
{
const
importerStatus
=
document
.
querySelector
(
'
.js-importer-status
'
);
new
window
.
ImporterStatus
(
jobsImportPath
,
importPath
);
}
});
}).
call
(
window
);
if
(
importerStatus
)
{
const
data
=
importerStatus
.
dataset
;
return
new
ImporterStatus
(
data
.
jobsImportPath
,
data
.
importPath
);
}
}
app/assets/javascripts/init_issuable_sidebar.js
View file @
17a35da6
...
...
@@ -2,7 +2,7 @@
/* global MilestoneSelect */
/* global LabelsSelect */
/* global WeightSelect */
/* global IssuableContext */
import
IssuableContext
from
'
./issuable_context
'
;
/* global Sidebar */
import
DueDateSelectors
from
'
./due_date_select
'
;
...
...
app/assets/javascripts/issuable_bulk_update_actions.js
View file @
17a35da6
/* eslint-disable comma-dangle, quotes, consistent-return, func-names, array-callback-return, space-before-function-paren, prefer-arrow-callback, max-len, no-unused-expressions, no-sequences, no-underscore-dangle, no-unused-vars, no-param-reassign */
/* global IssuableIndex */
import
_
from
'
underscore
'
;
import
Flash
from
'
./flash
'
;
...
...
app/assets/javascripts/issuable_bulk_update_sidebar.js
View file @
17a35da6
...
...
@@ -5,6 +5,10 @@
/* global SubscriptionSelect */
import
IssuableBulkUpdateActions
from
'
./issuable_bulk_update_actions
'
;
import
'
./milestone_select
'
;
import
'
./issue_status_select
'
;
import
'
./subscription_select
'
;
import
'
./labels_select
'
;
const
HIDDEN_CLASS
=
'
hidden
'
;
const
DISABLED_CONTENT_CLASS
=
'
disabled-content
'
;
...
...
app/assets/javascripts/issuable_context.js
View file @
17a35da6
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-new, comma-dangle, quotes, prefer-arrow-callback, consistent-return, one-var, no-var, one-var-declaration-per-line, no-underscore-dangle, max-len */
import
Cookies
from
'
js-cookie
'
;
import
bp
from
'
./breakpoints
'
;
import
UsersSelect
from
'
./users_select
'
;
const
PARTICIPANTS_ROW_COUNT
=
7
;
(
function
()
{
this
.
IssuableContext
=
(
function
()
{
function
IssuableContext
(
currentUser
)
{
this
.
initParticipants
();
new
UsersSelect
(
currentUser
);
$
(
'
select.select2
'
).
select2
({
width
:
'
resolve
'
,
dropdownAutoWidth
:
true
});
$
(
"
.issuable-sidebar .inline-update
"
).
on
(
"
change
"
,
"
select
"
,
function
()
{
return
$
(
this
).
submit
();
});
$
(
"
.issuable-sidebar .inline-update
"
).
on
(
"
change
"
,
"
.js-assignee
"
,
function
()
{
return
$
(
this
).
submit
();
});
$
(
document
).
off
(
'
click
'
,
'
.issuable-sidebar .dropdown-content a
'
).
on
(
'
click
'
,
'
.issuable-sidebar .dropdown-content a
'
,
function
(
e
)
{
return
e
.
preventDefault
();
});
$
(
document
).
off
(
'
click
'
,
'
.edit-link
'
).
on
(
'
click
'
,
'
.edit-link
'
,
function
(
e
)
{
var
$block
,
$selectbox
;
export
default
class
IssuableContext
{
constructor
(
currentUser
)
{
this
.
initParticipants
();
this
.
userSelect
=
new
UsersSelect
(
currentUser
);
$
(
'
select.select2
'
).
select2
({
width
:
'
resolve
'
,
dropdownAutoWidth
:
true
,
});
$
(
'
.issuable-sidebar .inline-update
'
).
on
(
'
change
'
,
'
select
'
,
function
onClickSelect
()
{
return
$
(
this
).
submit
();
});
$
(
'
.issuable-sidebar .inline-update
'
).
on
(
'
change
'
,
'
.js-assignee
'
,
function
onClickAssignee
()
{
return
$
(
this
).
submit
();
});
$
(
document
)
.
off
(
'
click
'
,
'
.issuable-sidebar .dropdown-content a
'
)
.
on
(
'
click
'
,
'
.issuable-sidebar .dropdown-content a
'
,
e
=>
e
.
preventDefault
());
$
(
document
)
.
off
(
'
click
'
,
'
.edit-link
'
)
.
on
(
'
click
'
,
'
.edit-link
'
,
function
onClickEdit
(
e
)
{
e
.
preventDefault
();
$block
=
$
(
this
).
parents
(
'
.block
'
);
$selectbox
=
$block
.
find
(
'
.selectbox
'
);
const
$block
=
$
(
this
).
parents
(
'
.block
'
);
const
$selectbox
=
$block
.
find
(
'
.selectbox
'
);
if
(
$selectbox
.
is
(
'
:visible
'
))
{
$selectbox
.
hide
();
$block
.
find
(
'
.value
'
).
show
();
...
...
@@ -35,46 +37,43 @@ const PARTICIPANTS_ROW_COUNT = 7;
$selectbox
.
show
();
$block
.
find
(
'
.value
'
).
hide
();
}
if
(
$selectbox
.
is
(
'
:visible
'
))
{
return
setTimeout
(
function
()
{
return
$block
.
find
(
'
.dropdown-menu-toggle
'
).
trigger
(
'
click
'
);
},
0
);
setTimeout
(()
=>
$block
.
find
(
'
.dropdown-menu-toggle
'
).
trigger
(
'
click
'
),
0
);
}
});
window
.
addEventListener
(
'
beforeunload
'
,
function
()
{
// collapsed_gutter cookie hides the sidebar
var
bpBreakpoint
=
bp
.
getBreakpointSize
();
if
(
bpBreakpoint
===
'
xs
'
||
bpBreakpoint
===
'
sm
'
)
{
Cookies
.
set
(
'
collapsed_gutter
'
,
true
);
}
});
}
IssuableContext
.
prototype
.
initParticipants
=
function
()
{
$
(
document
).
on
(
'
click
'
,
'
.js-participants-more
'
,
this
.
toggleHiddenParticipants
);
return
$
(
'
.js-participants-author
'
).
each
(
function
(
i
)
{
if
(
i
>=
PARTICIPANTS_ROW_COUNT
)
{
return
$
(
this
).
addClass
(
'
js-participants-hidden
'
).
hide
(
);
}
});
};
window
.
addEventListener
(
'
beforeunload
'
,
()
=>
{
// collapsed_gutter cookie hides the sidebar
const
bpBreakpoint
=
bp
.
getBreakpointSize
();
if
(
bpBreakpoint
===
'
xs
'
||
bpBreakpoint
===
'
sm
'
)
{
Cookies
.
set
(
'
collapsed_gutter
'
,
true
);
}
});
}
IssuableContext
.
prototype
.
toggleHiddenParticipants
=
function
()
{
const
currentText
=
$
(
this
).
text
().
trim
();
const
lessText
=
$
(
this
).
data
(
'
less-text
'
);
const
originalText
=
$
(
this
).
data
(
'
original-text
'
);
initParticipants
()
{
$
(
document
).
on
(
'
click
'
,
'
.js-participants-more
'
,
this
.
toggleHiddenParticipants
);
return
$
(
'
.js-participants-author
'
).
each
(
function
forEachAuthor
(
i
)
{
if
(
i
>=
PARTICIPANTS_ROW_COUNT
)
{
$
(
this
).
addClass
(
'
js-participants-hidden
'
).
hide
();
}
});
}
if
(
currentText
===
originalText
)
{
$
(
this
).
text
(
lessText
);
toggleHiddenParticipants
()
{
const
currentText
=
$
(
this
).
text
().
trim
();
const
lessText
=
$
(
this
).
data
(
'
less-text
'
);
const
originalText
=
$
(
this
).
data
(
'
original-text
'
);
if
(
gl
.
lazyLoader
)
gl
.
lazyLoader
.
loadCheck
();
}
else
{
$
(
this
).
text
(
originalText
);
}
if
(
currentText
===
originalText
)
{
$
(
this
).
text
(
lessText
);
$
(
'
.js-participants-hidden
'
).
toggle
();
};
if
(
gl
.
lazyLoader
)
gl
.
lazyLoader
.
loadCheck
();
}
else
{
$
(
this
).
text
(
originalText
);
}
return
IssuableContext
;
}
)();
}
).
call
(
window
);
$
(
'
.js-participants-hidden
'
).
toggle
()
;
}
}
app/assets/javascripts/issuable_form.js
View file @
17a35da6
/* eslint-disable func-names,
space-before-function-paren, no-var, prefer-rest-params, wrap-iife, no-use-before-define, no-useless-escape, no-new, quotes
, object-shorthand, no-unused-vars, comma-dangle, no-alert, consistent-return, no-else-return, prefer-template, one-var, one-var-declaration-per-line, curly, max-len */
/* eslint-disable func-names,
prefer-rest-params, wrap-iife, no-use-before-define, no-useless-escape, no-new
, object-shorthand, no-unused-vars, comma-dangle, no-alert, consistent-return, no-else-return, prefer-template, one-var, one-var-declaration-per-line, curly, max-len */
/* global GitLab */
import
Pikaday
from
'
pikaday
'
;
...
...
@@ -9,104 +9,101 @@ import ZenMode from './zen_mode';
import
{
parsePikadayDate
,
pikadayToString
}
from
'
./lib/utils/datefix
'
;
import
groupsSelect
from
'
./groups_select
'
;
(
function
()
{
this
.
IssuableForm
=
(
function
()
{
IssuableForm
.
prototype
.
wipRegex
=
/^
\s
*
(\[
WIP
\]\s
*|WIP:
\s
*|WIP
\s
+
)
+
\s
*/i
;
function
IssuableForm
(
form
)
{
var
$issuableDueDate
,
calendar
;
this
.
form
=
form
;
this
.
toggleWip
=
this
.
toggleWip
.
bind
(
this
);
this
.
renderWipExplanation
=
this
.
renderWipExplanation
.
bind
(
this
);
this
.
resetAutosave
=
this
.
resetAutosave
.
bind
(
this
);
this
.
handleSubmit
=
this
.
handleSubmit
.
bind
(
this
);
new
GfmAutoComplete
(
gl
.
GfmAutoComplete
&&
gl
.
GfmAutoComplete
.
dataSources
).
setup
();
new
UsersSelect
();
groupsSelect
();
new
ZenMode
();
this
.
titleField
=
this
.
form
.
find
(
"
input[name*='[title]']
"
);
this
.
descriptionField
=
this
.
form
.
find
(
"
textarea[name*='[description]']
"
);
if
(
!
(
this
.
titleField
.
length
&&
this
.
descriptionField
.
length
))
{
return
;
}
this
.
initAutosave
();
this
.
form
.
on
(
"
submit
"
,
this
.
handleSubmit
);
this
.
form
.
on
(
"
click
"
,
"
.btn-cancel
"
,
this
.
resetAutosave
);
this
.
initWip
();
$issuableDueDate
=
$
(
'
#issuable-due-date
'
);
if
(
$issuableDueDate
.
length
)
{
calendar
=
new
Pikaday
({
field
:
$issuableDueDate
.
get
(
0
),
theme
:
'
gitlab-theme animate-picker
'
,
format
:
'
yyyy-mm-dd
'
,
container
:
$issuableDueDate
.
parent
().
get
(
0
),
parse
:
dateString
=>
parsePikadayDate
(
dateString
),
toString
:
date
=>
pikadayToString
(
date
),
onSelect
:
function
(
dateText
)
{
$issuableDueDate
.
val
(
calendar
.
toString
(
dateText
));
}
});
calendar
.
setDate
(
parsePikadayDate
(
$issuableDueDate
.
val
()));
}
export
default
class
IssuableForm
{
constructor
(
form
)
{
this
.
form
=
form
;
this
.
toggleWip
=
this
.
toggleWip
.
bind
(
this
);
this
.
renderWipExplanation
=
this
.
renderWipExplanation
.
bind
(
this
);
this
.
resetAutosave
=
this
.
resetAutosave
.
bind
(
this
);
this
.
handleSubmit
=
this
.
handleSubmit
.
bind
(
this
);
this
.
wipRegex
=
/^
\s
*
(\[
WIP
\]\s
*|WIP:
\s
*|WIP
\s
+
)
+
\s
*/i
;
new
GfmAutoComplete
(
gl
.
GfmAutoComplete
&&
gl
.
GfmAutoComplete
.
dataSources
).
setup
();
new
UsersSelect
();
groupsSelect
();
new
ZenMode
();
this
.
titleField
=
this
.
form
.
find
(
'
input[name*="[title]"]
'
);
this
.
descriptionField
=
this
.
form
.
find
(
'
textarea[name*="[description]"]
'
);
if
(
!
(
this
.
titleField
.
length
&&
this
.
descriptionField
.
length
))
{
return
;
}
IssuableForm
.
prototype
.
initAutosave
=
function
()
{
new
Autosave
(
this
.
titleField
,
[
document
.
location
.
pathname
,
document
.
location
.
search
,
"
title
"
]);
return
new
Autosave
(
this
.
descriptionField
,
[
document
.
location
.
pathname
,
document
.
location
.
search
,
"
description
"
]);
};
IssuableForm
.
prototype
.
handleSubmit
=
function
()
{
return
this
.
resetAutosave
();
};
IssuableForm
.
prototype
.
resetAutosave
=
function
()
{
this
.
titleField
.
data
(
"
autosave
"
).
reset
();
return
this
.
descriptionField
.
data
(
"
autosave
"
).
reset
();
};
IssuableForm
.
prototype
.
initWip
=
function
()
{
this
.
$wipExplanation
=
this
.
form
.
find
(
"
.js-wip-explanation
"
);
this
.
$noWipExplanation
=
this
.
form
.
find
(
"
.js-no-wip-explanation
"
);
if
(
!
(
this
.
$wipExplanation
.
length
&&
this
.
$noWipExplanation
.
length
))
{
return
;
}
this
.
form
.
on
(
"
click
"
,
"
.js-toggle-wip
"
,
this
.
toggleWip
);
this
.
titleField
.
on
(
"
keyup blur
"
,
this
.
renderWipExplanation
);
return
this
.
renderWipExplanation
();
};
IssuableForm
.
prototype
.
workInProgress
=
function
()
{
return
this
.
wipRegex
.
test
(
this
.
titleField
.
val
());
};
IssuableForm
.
prototype
.
renderWipExplanation
=
function
()
{
if
(
this
.
workInProgress
())
{
this
.
$wipExplanation
.
show
();
return
this
.
$noWipExplanation
.
hide
();
}
else
{
this
.
$wipExplanation
.
hide
();
return
this
.
$noWipExplanation
.
show
();
}
};
IssuableForm
.
prototype
.
toggleWip
=
function
(
event
)
{
event
.
preventDefault
();
if
(
this
.
workInProgress
())
{
this
.
removeWip
();
}
else
{
this
.
addWip
();
}
return
this
.
renderWipExplanation
();
};
IssuableForm
.
prototype
.
removeWip
=
function
()
{
return
this
.
titleField
.
val
(
this
.
titleField
.
val
().
replace
(
this
.
wipRegex
,
""
));
};
IssuableForm
.
prototype
.
addWip
=
function
()
{
return
this
.
titleField
.
val
(
"
WIP:
"
+
(
this
.
titleField
.
val
()));
};
return
IssuableForm
;
})();
}).
call
(
window
);
this
.
initAutosave
();
this
.
form
.
on
(
'
submit
'
,
this
.
handleSubmit
);
this
.
form
.
on
(
'
click
'
,
'
.btn-cancel
'
,
this
.
resetAutosave
);
this
.
initWip
();
const
$issuableDueDate
=
$
(
'
#issuable-due-date
'
);
if
(
$issuableDueDate
.
length
)
{
const
calendar
=
new
Pikaday
({
field
:
$issuableDueDate
.
get
(
0
),
theme
:
'
gitlab-theme animate-picker
'
,
format
:
'
yyyy-mm-dd
'
,
container
:
$issuableDueDate
.
parent
().
get
(
0
),
parse
:
dateString
=>
parsePikadayDate
(
dateString
),
toString
:
date
=>
pikadayToString
(
date
),
onSelect
:
dateText
=>
$issuableDueDate
.
val
(
calendar
.
toString
(
dateText
)),
});
calendar
.
setDate
(
parsePikadayDate
(
$issuableDueDate
.
val
()));
}
}
initAutosave
()
{
new
Autosave
(
this
.
titleField
,
[
document
.
location
.
pathname
,
document
.
location
.
search
,
'
title
'
]);
return
new
Autosave
(
this
.
descriptionField
,
[
document
.
location
.
pathname
,
document
.
location
.
search
,
'
description
'
]);
}
handleSubmit
()
{
return
this
.
resetAutosave
();
}
resetAutosave
()
{
this
.
titleField
.
data
(
'
autosave
'
).
reset
();
return
this
.
descriptionField
.
data
(
'
autosave
'
).
reset
();
}
initWip
()
{
this
.
$wipExplanation
=
this
.
form
.
find
(
'
.js-wip-explanation
'
);
this
.
$noWipExplanation
=
this
.
form
.
find
(
'
.js-no-wip-explanation
'
);
if
(
!
(
this
.
$wipExplanation
.
length
&&
this
.
$noWipExplanation
.
length
))
{
return
;
}
this
.
form
.
on
(
'
click
'
,
'
.js-toggle-wip
'
,
this
.
toggleWip
);
this
.
titleField
.
on
(
'
keyup blur
'
,
this
.
renderWipExplanation
);
return
this
.
renderWipExplanation
();
}
workInProgress
()
{
return
this
.
wipRegex
.
test
(
this
.
titleField
.
val
());
}
renderWipExplanation
()
{
if
(
this
.
workInProgress
())
{
this
.
$wipExplanation
.
show
();
return
this
.
$noWipExplanation
.
hide
();
}
else
{
this
.
$wipExplanation
.
hide
();
return
this
.
$noWipExplanation
.
show
();
}
}
toggleWip
(
event
)
{
event
.
preventDefault
();
if
(
this
.
workInProgress
())
{
this
.
removeWip
();
}
else
{
this
.
addWip
();
}
return
this
.
renderWipExplanation
();
}
removeWip
()
{
return
this
.
titleField
.
val
(
this
.
titleField
.
val
().
replace
(
this
.
wipRegex
,
''
));
}
addWip
()
{
this
.
titleField
.
val
(
`WIP:
${(
this
.
titleField
.
val
())}
`
);
}
}
app/assets/javascripts/issuable_index.js
View file @
17a35da6
/* eslint-disable no-param-reassign, func-names, no-var, camelcase, no-unused-vars, object-shorthand, space-before-function-paren, no-return-assign, comma-dangle, consistent-return, one-var, one-var-declaration-per-line, quotes, prefer-template, prefer-arrow-callback, wrap-iife, max-len */
/* global IssuableIndex */
import
_
from
'
underscore
'
;
import
IssuableBulkUpdateSidebar
from
'
./issuable_bulk_update_sidebar
'
;
import
IssuableBulkUpdateActions
from
'
./issuable_bulk_update_actions
'
;
((
global
)
=>
{
var
issuable_created
;
issuable_created
=
false
;
global
.
IssuableIndex
=
{
init
:
function
(
pagePrefix
)
{
IssuableIndex
.
initTemplates
();
IssuableIndex
.
initSearch
();
IssuableIndex
.
initBulkUpdate
(
pagePrefix
);
IssuableIndex
.
initResetFilters
();
IssuableIndex
.
resetIncomingEmailToken
();
IssuableIndex
.
initLabelFilterRemove
();
},
initTemplates
:
function
()
{
return
IssuableIndex
.
labelRow
=
_
.
template
(
'
<% _.each(labels, function(label){ %> <span class="label-row btn-group" role="group" aria-label="<%- label.title %>" style="color: <%- label.text_color %>;"> <a href="#" class="btn btn-transparent has-tooltip" style="background-color: <%- label.color %>;" title="<%- label.description %>" data-container="body"> <%- label.title %> </a> <button type="button" class="btn btn-transparent label-remove js-label-filter-remove" style="background-color: <%- label.color %>;" data-label="<%- label.title %>"> <i class="fa fa-times"></i> </button> </span> <% }); %>
'
);
},
initSearch
:
function
()
{
const
$searchInput
=
$
(
'
#issuable_search
'
);
IssuableIndex
.
initSearchState
(
$searchInput
);
// `immediate` param set to false debounces on the `trailing` edge, lets user finish typing
const
debouncedExecSearch
=
_
.
debounce
(
IssuableIndex
.
executeSearch
,
1000
,
false
);
$searchInput
.
off
(
'
keyup
'
).
on
(
'
keyup
'
,
debouncedExecSearch
);
// ensures existing filters are preserved when manually submitted
$
(
'
#issuable_search_form
'
).
on
(
'
submit
'
,
(
e
)
=>
{
e
.
preventDefault
();
debouncedExecSearch
(
e
);
});
},
initSearchState
:
function
(
$searchInput
)
{
const
currentSearchVal
=
$searchInput
.
val
();
IssuableIndex
.
searchState
=
{
elem
:
$searchInput
,
current
:
currentSearchVal
};
IssuableIndex
.
maybeFocusOnSearch
();
},
accessSearchPristine
:
function
(
set
)
{
// store reference to previous value to prevent search on non-mutating keyup
const
state
=
IssuableIndex
.
searchState
;
const
currentSearchVal
=
state
.
elem
.
val
();
if
(
set
)
{
state
.
current
=
currentSearchVal
;
}
else
{
return
state
.
current
===
currentSearchVal
;
}
},
maybeFocusOnSearch
:
function
()
{
const
currentSearchVal
=
IssuableIndex
.
searchState
.
current
;
if
(
currentSearchVal
&&
currentSearchVal
!==
''
)
{
const
queryLength
=
currentSearchVal
.
length
;
const
$searchInput
=
IssuableIndex
.
searchState
.
elem
;
/* The following ensures that the cursor is initially placed at
* the end of search input when focus is applied. It accounts
* for differences in browser implementations of `setSelectionRange`
* and cursor placement for elements in focus.
*/
$searchInput
.
focus
();
if
(
$searchInput
.
setSelectionRange
)
{
$searchInput
.
setSelectionRange
(
queryLength
,
queryLength
);
}
else
{
$searchInput
.
val
(
currentSearchVal
);
}
}
},
executeSearch
:
function
(
e
)
{
const
$search
=
$
(
'
#issuable_search
'
);
const
$searchName
=
$search
.
attr
(
'
name
'
);
const
$searchValue
=
$search
.
val
();
const
$filtersForm
=
$
(
'
.js-filter-form
'
);
const
$input
=
$
(
`input[name='
${
$searchName
}
']`
,
$filtersForm
);
const
isPristine
=
IssuableIndex
.
accessSearchPristine
();
if
(
isPristine
)
{
return
;
}
if
(
!
$input
.
length
)
{
$filtersForm
.
append
(
`<input type='hidden' name='
${
$searchName
}
' value='
${
_
.
escape
(
$searchValue
)}
'/>`
);
}
else
{
$input
.
val
(
$searchValue
);
}
IssuableIndex
.
filterResults
(
$filtersForm
);
},
initLabelFilterRemove
:
function
()
{
return
$
(
document
).
off
(
'
click
'
,
'
.js-label-filter-remove
'
).
on
(
'
click
'
,
'
.js-label-filter-remove
'
,
function
(
e
)
{
var
$button
;
$button
=
$
(
this
);
// Remove the label input box
$
(
'
input[name="label_name[]"]
'
).
filter
(
function
()
{
return
this
.
value
===
$button
.
data
(
'
label
'
);
}).
remove
();
// Submit the form to get new data
IssuableIndex
.
filterResults
(
$
(
'
.filter-form
'
));
});
},
filterResults
:
(
function
(
_this
)
{
return
function
(
form
)
{
var
formAction
,
formData
,
issuesUrl
;
formData
=
form
.
serializeArray
();
formData
=
formData
.
filter
(
function
(
data
)
{
return
data
.
value
!==
''
;
});
formData
=
$
.
param
(
formData
);
formAction
=
form
.
attr
(
'
action
'
);
issuesUrl
=
formAction
;
issuesUrl
+=
""
+
(
formAction
.
indexOf
(
'
?
'
)
===
-
1
?
'
?
'
:
'
&
'
);
issuesUrl
+=
formData
;
return
gl
.
utils
.
visitUrl
(
issuesUrl
);
};
})(
this
),
initResetFilters
:
function
()
{
$
(
'
.reset-filters
'
).
on
(
'
click
'
,
function
(
e
)
{
e
.
preventDefault
();
const
target
=
e
.
target
;
const
$form
=
$
(
target
).
parents
(
'
.js-filter-form
'
);
const
baseIssuesUrl
=
target
.
href
;
$form
.
attr
(
'
action
'
,
baseIssuesUrl
);
gl
.
utils
.
visitUrl
(
baseIssuesUrl
);
export
default
class
IssuableIndex
{
constructor
(
pagePrefix
)
{
this
.
initBulkUpdate
(
pagePrefix
);
IssuableIndex
.
resetIncomingEmailToken
();
}
initBulkUpdate
(
pagePrefix
)
{
const
userCanBulkUpdate
=
$
(
'
.issues-bulk-update
'
).
length
>
0
;
const
alreadyInitialized
=
!!
this
.
bulkUpdateSidebar
;
if
(
userCanBulkUpdate
&&
!
alreadyInitialized
)
{
IssuableBulkUpdateActions
.
init
({
prefixId
:
pagePrefix
,
});
},
initBulkUpdate
:
function
(
pagePrefix
)
{
const
userCanBulkUpdate
=
$
(
'
.issues-bulk-update
'
).
length
>
0
;
const
alreadyInitialized
=
!!
this
.
bulkUpdateSidebar
;
if
(
userCanBulkUpdate
&&
!
alreadyInitialized
)
{
IssuableBulkUpdateActions
.
init
({
prefixId
:
pagePrefix
,
});
this
.
bulkUpdateSidebar
=
new
IssuableBulkUpdateSidebar
();
}
},
resetIncomingEmailToken
:
function
()
{
$
(
'
.incoming-email-token-reset
'
).
on
(
'
click
'
,
function
(
e
)
{
e
.
preventDefault
();
$
.
ajax
({
type
:
'
PUT
'
,
url
:
$
(
'
.incoming-email-token-reset
'
).
attr
(
'
href
'
),
dataType
:
'
json
'
,
success
:
function
(
response
)
{
$
(
'
#issue_email
'
).
val
(
response
.
new_issue_address
).
focus
();
},
beforeSend
:
function
()
{
$
(
'
.incoming-email-token-reset
'
).
text
(
'
resetting...
'
);
},
complete
:
function
()
{
$
(
'
.incoming-email-token-reset
'
).
text
(
'
reset it
'
);
}
});
});
this
.
bulkUpdateSidebar
=
new
IssuableBulkUpdateSidebar
();
}
};
})(
window
);
}
static
resetIncomingEmailToken
()
{
$
(
'
.incoming-email-token-reset
'
).
on
(
'
click
'
,
(
e
)
=>
{
e
.
preventDefault
();
$
.
ajax
({
type
:
'
PUT
'
,
url
:
$
(
'
.incoming-email-token-reset
'
).
attr
(
'
href
'
),
dataType
:
'
json
'
,
success
(
response
)
{
$
(
'
#issue_email
'
).
val
(
response
.
new_issue_address
).
focus
();
},
beforeSend
()
{
$
(
'
.incoming-email-token-reset
'
).
text
(
'
resetting...
'
);
},
complete
()
{
$
(
'
.incoming-email-token-reset
'
).
text
(
'
reset it
'
);
},
});
});
}
}
app/assets/javascripts/main.js
View file @
17a35da6
...
...
@@ -57,9 +57,7 @@ import './gl_field_error';
import
'
./gl_field_errors
'
;
import
'
./gl_form
'
;
import
'
./header
'
;
import
'
./importer_status
'
;
import
'
./issuable_index
'
;
import
'
./issuable_context
'
;
import
initImporterStatus
from
'
./importer_status
'
;
import
'
./issuable_form
'
;
import
'
./issue
'
;
import
'
./issue_status_select
'
;
...
...
@@ -149,6 +147,7 @@ $(function () {
var
fitSidebarForSize
;
initBreadcrumbs
();
initImporterStatus
();
// Set the default path for all cookies to GitLab's root directory
Cookies
.
defaults
.
path
=
gon
.
relative_url_root
||
'
/
'
;
...
...
spec/javascripts/issuable_context_spec.js
View file @
17a35da6
/* global IssuableContext */
import
'
~/issuable_context
'
;
import
$
from
'
jquery
'
;
import
IssuableContext
from
'
~/issuable_context
'
;
describe
(
'
IssuableContext
'
,
()
=>
{
describe
(
'
toggleHiddenParticipants
'
,
()
=>
{
...
...
spec/javascripts/issuable_spec.js
View file @
17a35da6
/* global IssuableIndex */
import
'
~/lib/utils/url_utility
'
;
import
'
~/issuable_index
'
;
(()
=>
{
const
BASE_URL
=
'
/user/project/issues?scope=all&state=closed
'
;
const
DEFAULT_PARAMS
=
'
&utf8=%E2%9C%93
'
;
function
updateForm
(
formValues
,
form
)
{
$
.
each
(
formValues
,
(
id
,
value
)
=>
{
$
(
`#
${
id
}
`
,
form
).
val
(
value
);
});
}
function
resetForm
(
form
)
{
$
(
'
input[name!="utf8"]
'
,
form
).
each
((
index
,
input
)
=>
{
input
.
setAttribute
(
'
value
'
,
''
);
import
IssuableIndex
from
'
~/issuable_index
'
;
describe
(
'
Issuable
'
,
()
=>
{
let
Issuable
;
describe
(
'
initBulkUpdate
'
,
()
=>
{
it
(
'
should not set bulkUpdateSidebar
'
,
()
=>
{
Issuable
=
new
IssuableIndex
(
'
issue_
'
);
expect
(
Issuable
.
bulkUpdateSidebar
).
not
.
toBeDefined
();
});
}
describe
(
'
Issuable
'
,
()
=>
{
preloadFixtures
(
'
static/issuable_filter.html.raw
'
);
it
(
'
should set bulkUpdateSidebar
'
,
()
=>
{
const
element
=
document
.
createElement
(
'
div
'
);
element
.
classList
.
add
(
'
issues-bulk-update
'
);
document
.
body
.
appendChild
(
element
);
beforeEach
(()
=>
{
loadFixtures
(
'
static/issuable_filter.html.raw
'
);
IssuableIndex
.
init
();
});
it
(
'
should be defined
'
,
()
=>
{
expect
(
window
.
IssuableIndex
).
toBeDefined
();
Issuable
=
new
IssuableIndex
(
'
issue_
'
);
expect
(
Issuable
.
bulkUpdateSidebar
).
toBeDefined
();
});
});
describe
(
'
filtering
'
,
()
=>
{
let
$filtersForm
;
beforeEach
(()
=>
{
$filtersForm
=
$
(
'
.js-filter-form
'
);
loadFixtures
(
'
static/issuable_filter.html.raw
'
);
resetForm
(
$filtersForm
);
});
it
(
'
should contain only the default parameters
'
,
()
=>
{
spyOn
(
gl
.
utils
,
'
visitUrl
'
);
IssuableIndex
.
filterResults
(
$filtersForm
);
expect
(
gl
.
utils
.
visitUrl
).
toHaveBeenCalledWith
(
BASE_URL
+
DEFAULT_PARAMS
);
});
it
(
'
should filter for the phrase "broken"
'
,
()
=>
{
spyOn
(
gl
.
utils
,
'
visitUrl
'
);
updateForm
({
search
:
'
broken
'
},
$filtersForm
);
IssuableIndex
.
filterResults
(
$filtersForm
);
const
params
=
`
${
DEFAULT_PARAMS
}
&search=broken`
;
expect
(
gl
.
utils
.
visitUrl
).
toHaveBeenCalledWith
(
BASE_URL
+
params
);
});
it
(
'
should keep query parameters after modifying filter
'
,
()
=>
{
spyOn
(
gl
.
utils
,
'
visitUrl
'
);
describe
(
'
resetIncomingEmailToken
'
,
()
=>
{
beforeEach
(()
=>
{
const
element
=
document
.
createElement
(
'
a
'
);
element
.
classList
.
add
(
'
incoming-email-token-reset
'
);
element
.
setAttribute
(
'
href
'
,
'
foo
'
);
document
.
body
.
appendChild
(
element
);
// initial filter
updateForm
({
milestone_title
:
'
v1.0
'
},
$filtersForm
);
const
input
=
document
.
createElement
(
'
input
'
);
input
.
setAttribute
(
'
id
'
,
'
issue_email
'
);
document
.
body
.
appendChild
(
input
);
IssuableIndex
.
filterResults
(
$filtersForm
);
let
params
=
`
${
DEFAULT_PARAMS
}
&milestone_title=v1.0`
;
expect
(
gl
.
utils
.
visitUrl
).
toHaveBeenCalledWith
(
BASE_URL
+
params
);
Issuable
=
new
IssuableIndex
(
'
issue_
'
);
});
// update filter
updateForm
({
label_name
:
'
Frontend
'
},
$filtersForm
);
it
(
'
should send request to reset email token
'
,
()
=>
{
spyOn
(
jQuery
,
'
ajax
'
).
and
.
callThrough
();
document
.
querySelector
(
'
.incoming-email-token-reset
'
).
click
();
IssuableIndex
.
filterResults
(
$filtersForm
);
params
=
`
${
DEFAULT_PARAMS
}
&milestone_title=v1.0&label_name=Frontend`
;
expect
(
gl
.
utils
.
visitUrl
).
toHaveBeenCalledWith
(
BASE_URL
+
params
);
});
expect
(
jQuery
.
ajax
).
toHaveBeenCalled
();
expect
(
jQuery
.
ajax
.
calls
.
argsFor
(
0
)[
0
].
url
).
toEqual
(
'
foo
'
);
});
});
})();
});
spec/javascripts/labels_issue_sidebar_spec.js
View file @
17a35da6
/* eslint-disable no-new */
/* global IssuableContext */
import
IssuableContext
from
'
~/issuable_context
'
;
/* global LabelsSelect */
import
'
~/gl_dropdown
'
;
import
'
select2
'
;
import
'
~/api
'
;
import
'
~/create_label
'
;
import
'
~/issuable_context
'
;
import
'
~/users_select
'
;
import
'
~/labels_select
'
;
...
...
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