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
aec4c074
Commit
aec4c074
authored
Jul 09, 2020
by
Sean McGivern
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Revert "Merge branch '196066-add-milestone-expired-info' into 'master'"
This reverts merge request !35595
parent
061db4a2
Changes
24
Hide whitespace changes
Inline
Side-by-side
Showing
24 changed files
with
107 additions
and
218 deletions
+107
-218
app/assets/javascripts/api.js
app/assets/javascripts/api.js
+2
-13
app/assets/javascripts/boards/components/board_form.vue
app/assets/javascripts/boards/components/board_form.vue
+5
-0
app/assets/javascripts/boards/components/boards_selector.vue
app/assets/javascripts/boards/components/boards_selector.vue
+5
-0
app/assets/javascripts/boards/components/modal/header.vue
app/assets/javascripts/boards/components/modal/header.vue
+4
-0
app/assets/javascripts/boards/components/modal/index.vue
app/assets/javascripts/boards/components/modal/index.vue
+9
-1
app/assets/javascripts/boards/mount_multiple_boards_switcher.js
...sets/javascripts/boards/mount_multiple_boards_switcher.js
+1
-1
app/assets/javascripts/milestone_select.js
app/assets/javascripts/milestone_select.js
+49
-102
app/views/shared/boards/components/sidebar/_milestone.html.haml
...ews/shared/boards/components/sidebar/_milestone.html.haml
+1
-2
app/views/shared/issuable/_sidebar.html.haml
app/views/shared/issuable/_sidebar.html.haml
+1
-2
changelogs/unreleased/196066-add-milestone-expired-info.yml
changelogs/unreleased/196066-add-milestone-expired-info.yml
+0
-5
doc/api/group_milestones.md
doc/api/group_milestones.md
+0
-1
doc/api/milestones.md
doc/api/milestones.md
+1
-2
ee/app/assets/javascripts/boards/components/board_scope.vue
ee/app/assets/javascripts/boards/components/board_scope.vue
+5
-2
ee/app/assets/javascripts/boards/components/milestone_select.vue
...assets/javascripts/boards/components/milestone_select.vue
+4
-11
ee/spec/fixtures/api/schemas/entities/milestone.json
ee/spec/fixtures/api/schemas/entities/milestone.json
+1
-2
ee/spec/frontend/boards/components/board_scope_spec.js
ee/spec/frontend/boards/components/board_scope_spec.js
+1
-0
ee/spec/frontend/boards/milestone_select_spec.js
ee/spec/frontend/boards/milestone_select_spec.js
+14
-12
lib/api/entities/milestone.rb
lib/api/entities/milestone.rb
+0
-1
locale/gitlab.pot
locale/gitlab.pot
+0
-9
spec/fixtures/api/schemas/public_api/v4/milestone.json
spec/fixtures/api/schemas/public_api/v4/milestone.json
+1
-3
spec/fixtures/api/schemas/public_api/v4/milestone_with_stats.json
...tures/api/schemas/public_api/v4/milestone_with_stats.json
+1
-3
spec/frontend/api_spec.js
spec/frontend/api_spec.js
+0
-46
spec/frontend/boards/components/board_form_spec.js
spec/frontend/boards/components/board_form_spec.js
+1
-0
spec/frontend/boards/components/boards_selector_spec.js
spec/frontend/boards/components/boards_selector_spec.js
+1
-0
No files found.
app/assets/javascripts/api.js
View file @
aec4c074
...
@@ -9,7 +9,6 @@ const Api = {
...
@@ -9,7 +9,6 @@ const Api = {
groupsPath
:
'
/api/:version/groups.json
'
,
groupsPath
:
'
/api/:version/groups.json
'
,
groupPath
:
'
/api/:version/groups/:id
'
,
groupPath
:
'
/api/:version/groups/:id
'
,
groupMembersPath
:
'
/api/:version/groups/:id/members
'
,
groupMembersPath
:
'
/api/:version/groups/:id/members
'
,
groupMilestonesPath
:
'
/api/:version/groups/:id/milestones
'
,
subgroupsPath
:
'
/api/:version/groups/:id/subgroups
'
,
subgroupsPath
:
'
/api/:version/groups/:id/subgroups
'
,
namespacesPath
:
'
/api/:version/namespaces.json
'
,
namespacesPath
:
'
/api/:version/namespaces.json
'
,
groupProjectsPath
:
'
/api/:version/groups/:id/projects.json
'
,
groupProjectsPath
:
'
/api/:version/groups/:id/projects.json
'
,
...
@@ -101,14 +100,6 @@ const Api = {
...
@@ -101,14 +100,6 @@ const Api = {
return
axios
.
get
(
url
).
then
(({
data
})
=>
data
);
return
axios
.
get
(
url
).
then
(({
data
})
=>
data
);
},
},
groupMilestones
(
groupId
,
params
=
{})
{
const
url
=
Api
.
buildUrl
(
Api
.
groupMilestonesPath
).
replace
(
'
:id
'
,
encodeURIComponent
(
groupId
));
return
axios
.
get
(
url
,
{
params
,
});
},
// Return namespaces list. Filtered by query
// Return namespaces list. Filtered by query
namespaces
(
query
,
callback
)
{
namespaces
(
query
,
callback
)
{
const
url
=
Api
.
buildUrl
(
Api
.
namespacesPath
);
const
url
=
Api
.
buildUrl
(
Api
.
namespacesPath
);
...
@@ -273,12 +264,10 @@ const Api = {
...
@@ -273,12 +264,10 @@ const Api = {
});
});
},
},
projectMilestones
(
id
,
params
=
{}
)
{
projectMilestones
(
id
)
{
const
url
=
Api
.
buildUrl
(
Api
.
projectMilestonesPath
).
replace
(
'
:id
'
,
encodeURIComponent
(
id
));
const
url
=
Api
.
buildUrl
(
Api
.
projectMilestonesPath
).
replace
(
'
:id
'
,
encodeURIComponent
(
id
));
return
axios
.
get
(
url
,
{
return
axios
.
get
(
url
);
params
,
});
},
},
mergeRequests
(
params
=
{})
{
mergeRequests
(
params
=
{})
{
...
...
app/assets/javascripts/boards/components/board_form.vue
View file @
aec4c074
...
@@ -25,6 +25,10 @@ export default {
...
@@ -25,6 +25,10 @@ export default {
type
:
Boolean
,
type
:
Boolean
,
required
:
true
,
required
:
true
,
},
},
milestonePath
:
{
type
:
String
,
required
:
true
,
},
labelsPath
:
{
labelsPath
:
{
type
:
String
,
type
:
String
,
required
:
true
,
required
:
true
,
...
@@ -197,6 +201,7 @@ export default {
...
@@ -197,6 +201,7 @@ export default {
:collapse-scope=
"isNewForm"
:collapse-scope=
"isNewForm"
:board=
"board"
:board=
"board"
:can-admin-board=
"canAdminBoard"
:can-admin-board=
"canAdminBoard"
:milestone-path=
"milestonePath"
:labels-path=
"labelsPath"
:labels-path=
"labelsPath"
:enable-scoped-labels=
"enableScopedLabels"
:enable-scoped-labels=
"enableScopedLabels"
:project-id=
"projectId"
:project-id=
"projectId"
...
...
app/assets/javascripts/boards/components/boards_selector.vue
View file @
aec4c074
...
@@ -36,6 +36,10 @@ export default {
...
@@ -36,6 +36,10 @@ export default {
type
:
Object
,
type
:
Object
,
required
:
true
,
required
:
true
,
},
},
milestonePath
:
{
type
:
String
,
required
:
true
,
},
throttleDuration
:
{
throttleDuration
:
{
type
:
Number
,
type
:
Number
,
default
:
200
,
default
:
200
,
...
@@ -331,6 +335,7 @@ export default {
...
@@ -331,6 +335,7 @@ export default {
<board-form
<board-form
v-if=
"currentPage"
v-if=
"currentPage"
:milestone-path=
"milestonePath"
:labels-path=
"labelsPath"
:labels-path=
"labelsPath"
:project-id=
"projectId"
:project-id=
"projectId"
:group-id=
"groupId"
:group-id=
"groupId"
...
...
app/assets/javascripts/boards/components/modal/header.vue
View file @
aec4c074
...
@@ -17,6 +17,10 @@ export default {
...
@@ -17,6 +17,10 @@ export default {
type
:
Number
,
type
:
Number
,
required
:
true
,
required
:
true
,
},
},
milestonePath
:
{
type
:
String
,
required
:
true
,
},
labelPath
:
{
labelPath
:
{
type
:
String
,
type
:
String
,
required
:
true
,
required
:
true
,
...
...
app/assets/javascripts/boards/components/modal/index.vue
View file @
aec4c074
...
@@ -38,6 +38,10 @@ export default {
...
@@ -38,6 +38,10 @@ export default {
type
:
Number
,
type
:
Number
,
required
:
true
,
required
:
true
,
},
},
milestonePath
:
{
type
:
String
,
required
:
true
,
},
labelPath
:
{
labelPath
:
{
type
:
String
,
type
:
String
,
required
:
true
,
required
:
true
,
...
@@ -145,7 +149,11 @@ export default {
...
@@ -145,7 +149,11 @@ export default {
class=
"add-issues-modal d-flex position-fixed position-top-0 position-bottom-0 position-left-0 position-right-0 h-100"
class=
"add-issues-modal d-flex position-fixed position-top-0 position-bottom-0 position-left-0 position-right-0 h-100"
>
>
<div
class=
"add-issues-container d-flex flex-column m-auto rounded"
>
<div
class=
"add-issues-container d-flex flex-column m-auto rounded"
>
<modal-header
:project-id=
"projectId"
:label-path=
"labelPath"
/>
<modal-header
:project-id=
"projectId"
:milestone-path=
"milestonePath"
:label-path=
"labelPath"
/>
<modal-list
<modal-list
v-if=
"!loading && showList && !filterLoading"
v-if=
"!loading && showList && !filterLoading"
:issue-link-base=
"issueLinkBase"
:issue-link-base=
"issueLinkBase"
...
...
app/assets/javascripts/boards/mount_multiple_boards_switcher.js
View file @
aec4c074
...
@@ -27,7 +27,7 @@ export default () => {
...
@@ -27,7 +27,7 @@ export default () => {
hasMissingBoards
:
parseBoolean
(
dataset
.
hasMissingBoards
),
hasMissingBoards
:
parseBoolean
(
dataset
.
hasMissingBoards
),
canAdminBoard
:
parseBoolean
(
dataset
.
canAdminBoard
),
canAdminBoard
:
parseBoolean
(
dataset
.
canAdminBoard
),
multipleIssueBoardsAvailable
:
parseBoolean
(
dataset
.
multipleIssueBoardsAvailable
),
multipleIssueBoardsAvailable
:
parseBoolean
(
dataset
.
multipleIssueBoardsAvailable
),
projectId
:
dataset
.
projectId
?
Number
(
dataset
.
projectId
)
:
0
,
projectId
:
Number
(
dataset
.
projectId
)
,
groupId
:
Number
(
dataset
.
groupId
),
groupId
:
Number
(
dataset
.
groupId
),
scopedIssueBoardFeatureEnabled
:
parseBoolean
(
dataset
.
scopedIssueBoardFeatureEnabled
),
scopedIssueBoardFeatureEnabled
:
parseBoolean
(
dataset
.
scopedIssueBoardFeatureEnabled
),
weights
:
JSON
.
parse
(
dataset
.
weights
),
weights
:
JSON
.
parse
(
dataset
.
weights
),
...
...
app/assets/javascripts/milestone_select.js
View file @
aec4c074
...
@@ -4,11 +4,10 @@
...
@@ -4,11 +4,10 @@
import
$
from
'
jquery
'
;
import
$
from
'
jquery
'
;
import
{
template
,
escape
}
from
'
lodash
'
;
import
{
template
,
escape
}
from
'
lodash
'
;
import
{
__
,
sprintf
}
from
'
~/locale
'
;
import
{
__
}
from
'
~/locale
'
;
import
'
~/gl_dropdown
'
;
import
'
~/gl_dropdown
'
;
import
Api
from
'
~/api
'
;
import
axios
from
'
./lib/utils/axios_utils
'
;
import
axios
from
'
./lib/utils/axios_utils
'
;
import
{
timeFor
,
parsePikadayDate
,
dateInWords
}
from
'
./lib/utils/datetime_utility
'
;
import
{
timeFor
}
from
'
./lib/utils/datetime_utility
'
;
import
ModalStore
from
'
./boards/stores/modal_store
'
;
import
ModalStore
from
'
./boards/stores/modal_store
'
;
import
boardsStore
,
{
import
boardsStore
,
{
boardStoreIssueSet
,
boardStoreIssueSet
,
...
@@ -35,10 +34,10 @@ export default class MilestoneSelect {
...
@@ -35,10 +34,10 @@ export default class MilestoneSelect {
$els
.
each
((
i
,
dropdown
)
=>
{
$els
.
each
((
i
,
dropdown
)
=>
{
let
milestoneLinkNoneTemplate
,
let
milestoneLinkNoneTemplate
,
milestoneLinkTemplate
,
milestoneLinkTemplate
,
milestoneExpiredLinkTemplate
,
selectedMilestone
,
selectedMilestone
,
selectedMilestoneDefault
;
selectedMilestoneDefault
;
const
$dropdown
=
$
(
dropdown
);
const
$dropdown
=
$
(
dropdown
);
const
milestonesUrl
=
$dropdown
.
data
(
'
milestones
'
);
const
issueUpdateURL
=
$dropdown
.
data
(
'
issueUpdate
'
);
const
issueUpdateURL
=
$dropdown
.
data
(
'
issueUpdate
'
);
const
showNo
=
$dropdown
.
data
(
'
showNo
'
);
const
showNo
=
$dropdown
.
data
(
'
showNo
'
);
const
showAny
=
$dropdown
.
data
(
'
showAny
'
);
const
showAny
=
$dropdown
.
data
(
'
showAny
'
);
...
@@ -64,101 +63,58 @@ export default class MilestoneSelect {
...
@@ -64,101 +63,58 @@ export default class MilestoneSelect {
milestoneLinkTemplate
=
template
(
milestoneLinkTemplate
=
template
(
'
<a href="<%- web_url %>" class="bold has-tooltip" data-container="body" title="<%- remaining %>"><%- title %></a>
'
,
'
<a href="<%- web_url %>" class="bold has-tooltip" data-container="body" title="<%- remaining %>"><%- title %></a>
'
,
);
);
milestoneExpiredLinkTemplate
=
template
(
'
<a href="<%- web_url %>" class="bold has-tooltip" data-container="body" title="<%- remaining %>"><%- title %> (Past due)</a>
'
,
);
milestoneLinkNoneTemplate
=
`<span class="no-value">
${
__
(
'
None
'
)}
</span>`
;
milestoneLinkNoneTemplate
=
`<span class="no-value">
${
__
(
'
None
'
)}
</span>`
;
}
}
return
$dropdown
.
glDropdown
({
return
$dropdown
.
glDropdown
({
showMenuAbove
,
showMenuAbove
,
data
:
(
term
,
callback
)
=>
{
data
:
(
term
,
callback
)
=>
let
contextId
=
$dropdown
.
get
(
0
).
dataset
.
projectId
;
axios
.
get
(
milestonesUrl
).
then
(({
data
})
=>
{
let
getMilestones
=
Api
.
projectMilestones
;
const
extraOptions
=
[];
if
(
showAny
)
{
if
(
!
contextId
)
{
extraOptions
.
push
({
contextId
=
$dropdown
.
get
(
0
).
dataset
.
groupId
;
id
:
null
,
getMilestones
=
Api
.
groupMilestones
;
name
:
null
,
}
title
:
__
(
'
Any milestone
'
),
});
// We don't use $.data() as it caches initial value and never updates!
}
return
getMilestones
(
contextId
,
{
state
:
'
active
'
})
if
(
showNo
)
{
.
then
(({
data
})
=>
extraOptions
.
push
({
data
id
:
-
1
,
.
map
(
m
=>
({
name
:
__
(
'
No milestone
'
),
...
m
,
title
:
__
(
'
No milestone
'
),
// Public API includes `title` instead of `name`.
});
name
:
m
.
title
,
}
}))
if
(
showUpcoming
)
{
.
sort
((
mA
,
mB
)
=>
{
extraOptions
.
push
({
// Move all expired milestones to the bottom.
id
:
-
2
,
if
(
mA
.
expired
)
{
name
:
'
#upcoming
'
,
return
1
;
title
:
__
(
'
Upcoming
'
),
}
});
if
(
mB
.
expired
)
{
}
return
-
1
;
if
(
showStarted
)
{
}
extraOptions
.
push
({
return
0
;
id
:
-
3
,
}),
name
:
'
#started
'
,
)
title
:
__
(
'
Started
'
),
.
then
(
data
=>
{
});
const
extraOptions
=
[];
}
if
(
showAny
)
{
if
(
extraOptions
.
length
)
{
extraOptions
.
push
({
extraOptions
.
push
({
type
:
'
divider
'
});
id
:
null
,
}
name
:
null
,
title
:
__
(
'
Any milestone
'
),
});
}
if
(
showNo
)
{
extraOptions
.
push
({
id
:
-
1
,
name
:
__
(
'
No milestone
'
),
title
:
__
(
'
No milestone
'
),
});
}
if
(
showUpcoming
)
{
extraOptions
.
push
({
id
:
-
2
,
name
:
'
#upcoming
'
,
title
:
__
(
'
Upcoming
'
),
});
}
if
(
showStarted
)
{
extraOptions
.
push
({
id
:
-
3
,
name
:
'
#started
'
,
title
:
__
(
'
Started
'
),
});
}
if
(
extraOptions
.
length
)
{
extraOptions
.
push
({
type
:
'
divider
'
});
}
callback
(
extraOptions
.
concat
(
data
));
if
(
showMenuAbove
)
{
$dropdown
.
data
(
'
glDropdown
'
).
positionMenuAbove
();
}
$
(
`[data-milestone-id="
${
selectedMilestone
}
"] > a`
).
addClass
(
'
is-active
'
);
});
},
renderRow
:
milestone
=>
{
const
milestoneName
=
milestone
.
title
||
milestone
.
name
;
let
milestoneDisplayName
=
escape
(
milestoneName
);
if
(
milestone
.
expired
)
{
milestoneDisplayName
=
sprintf
(
__
(
'
%{milestone} (expired)
'
),
{
milestone
:
milestoneDisplayName
,
});
}
return
`
callback
(
extraOptions
.
concat
(
data
));
<li data-milestone-id="
${
escape
(
milestoneName
)}
">
if
(
showMenuAbove
)
{
$dropdown
.
data
(
'
glDropdown
'
).
positionMenuAbove
();
}
$
(
`[data-milestone-id="
${
escape
(
selectedMilestone
)}
"] > a`
).
addClass
(
'
is-active
'
);
}),
renderRow
:
milestone
=>
`
<li data-milestone-id="
${
escape
(
milestone
.
name
)}
">
<a href='#' class='dropdown-menu-milestone-link'>
<a href='#' class='dropdown-menu-milestone-link'>
${
milestoneDisplayName
}
${
escape
(
milestone
.
title
)
}
</a>
</a>
</li>
</li>
`
;
`
,
},
filterable
:
true
,
filterable
:
true
,
search
:
{
search
:
{
fields
:
[
'
title
'
],
fields
:
[
'
title
'
],
...
@@ -193,7 +149,7 @@ export default class MilestoneSelect {
...
@@ -193,7 +149,7 @@ export default class MilestoneSelect {
selectedMilestone
=
$dropdown
[
0
].
dataset
.
selected
||
selectedMilestoneDefault
;
selectedMilestone
=
$dropdown
[
0
].
dataset
.
selected
||
selectedMilestoneDefault
;
}
}
$
(
'
a.is-active
'
,
$el
).
removeClass
(
'
is-active
'
);
$
(
'
a.is-active
'
,
$el
).
removeClass
(
'
is-active
'
);
$
(
`[data-milestone-id="
${
selectedMilestone
}
"] > a`
,
$el
).
addClass
(
'
is-active
'
);
$
(
`[data-milestone-id="
${
escape
(
selectedMilestone
)
}
"] > a`
,
$el
).
addClass
(
'
is-active
'
);
},
},
vue
:
$dropdown
.
hasClass
(
'
js-issue-board-sidebar
'
),
vue
:
$dropdown
.
hasClass
(
'
js-issue-board-sidebar
'
),
clicked
:
clickEvent
=>
{
clicked
:
clickEvent
=>
{
...
@@ -281,16 +237,7 @@ export default class MilestoneSelect {
...
@@ -281,16 +237,7 @@ export default class MilestoneSelect {
if
(
data
.
milestone
!=
null
)
{
if
(
data
.
milestone
!=
null
)
{
data
.
milestone
.
remaining
=
timeFor
(
data
.
milestone
.
due_date
);
data
.
milestone
.
remaining
=
timeFor
(
data
.
milestone
.
due_date
);
data
.
milestone
.
name
=
data
.
milestone
.
title
;
data
.
milestone
.
name
=
data
.
milestone
.
title
;
$value
.
html
(
$value
.
html
(
milestoneLinkTemplate
(
data
.
milestone
));
data
.
milestone
.
expired
?
milestoneExpiredLinkTemplate
({
...
data
.
milestone
,
remaining
:
sprintf
(
__
(
'
%{due_date} (Past due)
'
),
{
due_date
:
dateInWords
(
parsePikadayDate
(
data
.
milestone
.
due_date
)),
}),
})
:
milestoneLinkTemplate
(
data
.
milestone
),
);
return
$sidebarCollapsedValue
return
$sidebarCollapsedValue
.
attr
(
.
attr
(
'
data-original-title
'
,
'
data-original-title
'
,
...
...
app/views/shared/boards/components/sidebar/_milestone.html.haml
View file @
aec4c074
...
@@ -18,8 +18,7 @@
...
@@ -18,8 +18,7 @@
.dropdown
.dropdown
%button
.dropdown-menu-toggle.js-milestone-select.js-issue-board-sidebar
{
type:
"button"
,
data:
{
toggle:
"dropdown"
,
show_no:
"true"
,
field_name:
"issue[milestone_id]"
,
milestones:
milestones_filter_path
(
format: :json
),
ability_name:
"issue"
,
use_id:
"true"
,
default_no:
"true"
},
%button
.dropdown-menu-toggle.js-milestone-select.js-issue-board-sidebar
{
type:
"button"
,
data:
{
toggle:
"dropdown"
,
show_no:
"true"
,
field_name:
"issue[milestone_id]"
,
milestones:
milestones_filter_path
(
format: :json
),
ability_name:
"issue"
,
use_id:
"true"
,
default_no:
"true"
},
":data-selected"
=>
"milestoneTitle"
,
":data-selected"
=>
"milestoneTitle"
,
":data-issuable-id"
=>
"issue.iid"
,
":data-issuable-id"
=>
"issue.iid"
}
":data-project-id"
=>
"issue.project_id"
}
=
_
(
"Milestone"
)
=
_
(
"Milestone"
)
=
icon
(
"chevron-down"
)
=
icon
(
"chevron-down"
)
.dropdown-menu.dropdown-select.dropdown-menu-selectable
.dropdown-menu.dropdown-select.dropdown-menu-selectable
...
...
app/views/shared/issuable/_sidebar.html.haml
View file @
aec4c074
...
@@ -45,8 +45,7 @@
...
@@ -45,8 +45,7 @@
=
link_to
_
(
'Edit'
),
'#'
,
class:
'js-sidebar-dropdown-toggle edit-link float-right'
,
data:
{
qa_selector:
"edit_milestone_link"
,
track_label:
"right_sidebar"
,
track_property:
"milestone"
,
track_event:
"click_edit_button"
,
track_value:
""
}
=
link_to
_
(
'Edit'
),
'#'
,
class:
'js-sidebar-dropdown-toggle edit-link float-right'
,
data:
{
qa_selector:
"edit_milestone_link"
,
track_label:
"right_sidebar"
,
track_property:
"milestone"
,
track_event:
"click_edit_button"
,
track_value:
""
}
.value.hide-collapsed
.value.hide-collapsed
-
if
milestone
.
present?
-
if
milestone
.
present?
-
milestone_title
=
milestone
[
:expired
]
?
_
(
"%{milestone_name} (Past due)"
).
html_safe
%
{
milestone_name:
milestone
[
:title
]
}
:
milestone
[
:title
]
=
link_to
milestone
[
:title
],
milestone
[
:web_url
],
class:
"bold has-tooltip"
,
title:
sidebar_milestone_remaining_days
(
milestone
),
data:
{
container:
"body"
,
html:
'true'
,
boundary:
'viewport'
,
qa_selector:
'milestone_link'
,
qa_title:
milestone
[
:title
]
}
=
link_to
milestone_title
,
milestone
[
:web_url
],
class:
"bold has-tooltip"
,
title:
sidebar_milestone_remaining_days
(
milestone
),
data:
{
container:
"body"
,
html:
'true'
,
boundary:
'viewport'
,
qa_selector:
'milestone_link'
,
qa_title:
milestone
[
:title
]
}
-
else
-
else
%span
.no-value
%span
.no-value
=
_
(
'None'
)
=
_
(
'None'
)
...
...
changelogs/unreleased/196066-add-milestone-expired-info.yml
deleted
100644 → 0
View file @
061db4a2
---
title
:
Show expired milestones at the bottom of the list within dropdown
merge_request
:
35595
author
:
type
:
changed
doc/api/group_milestones.md
View file @
aec4c074
...
@@ -54,7 +54,6 @@ Example Response:
...
@@ -54,7 +54,6 @@ Example Response:
"state"
:
"active"
,
"state"
:
"active"
,
"updated_at"
:
"2013-10-02T09:24:18Z"
,
"updated_at"
:
"2013-10-02T09:24:18Z"
,
"created_at"
:
"2013-10-02T09:24:18Z"
,
"created_at"
:
"2013-10-02T09:24:18Z"
,
"expired"
:
false
,
"web_url"
:
"https://gitlab.com/groups/gitlab-org/-/milestones/42"
"web_url"
:
"https://gitlab.com/groups/gitlab-org/-/milestones/42"
}
}
]
]
...
...
doc/api/milestones.md
View file @
aec4c074
...
@@ -51,8 +51,7 @@ Example Response:
...
@@ -51,8 +51,7 @@ Example Response:
"start_date"
:
"2013-11-10"
,
"start_date"
:
"2013-11-10"
,
"state"
:
"active"
,
"state"
:
"active"
,
"updated_at"
:
"2013-10-02T09:24:18Z"
,
"updated_at"
:
"2013-10-02T09:24:18Z"
,
"created_at"
:
"2013-10-02T09:24:18Z"
,
"created_at"
:
"2013-10-02T09:24:18Z"
"expired"
:
false
}
}
]
]
```
```
...
...
ee/app/assets/javascripts/boards/components/board_scope.vue
View file @
aec4c074
...
@@ -27,6 +27,10 @@ export default {
...
@@ -27,6 +27,10 @@ export default {
type
:
Object
,
type
:
Object
,
required
:
true
,
required
:
true
,
},
},
milestonePath
:
{
type
:
String
,
required
:
true
,
},
labelsPath
:
{
labelsPath
:
{
type
:
String
,
type
:
String
,
required
:
true
,
required
:
true
,
...
@@ -102,8 +106,7 @@ export default {
...
@@ -102,8 +106,7 @@ export default {
<div
v-if=
"!collapseScope || expanded"
>
<div
v-if=
"!collapseScope || expanded"
>
<board-milestone-select
<board-milestone-select
:board=
"board"
:board=
"board"
:group-id=
"groupId"
:milestone-path=
"milestonePath"
:project-id=
"projectId"
:can-edit=
"canAdminBoard"
:can-edit=
"canAdminBoard"
/>
/>
...
...
ee/app/assets/javascripts/boards/components/milestone_select.vue
View file @
aec4c074
...
@@ -15,15 +15,9 @@ export default {
...
@@ -15,15 +15,9 @@ export default {
type
:
Object
,
type
:
Object
,
required
:
true
,
required
:
true
,
},
},
groupId
:
{
milestonePath
:
{
type
:
Number
,
type
:
String
,
required
:
false
,
required
:
true
,
default
:
0
,
},
projectId
:
{
type
:
Number
,
required
:
false
,
default
:
0
,
},
},
canEdit
:
{
canEdit
:
{
type
:
Boolean
,
type
:
Boolean
,
...
@@ -90,8 +84,7 @@ export default {
...
@@ -90,8 +84,7 @@ export default {
<button
<button
ref=
"dropdownButton"
ref=
"dropdownButton"
:data-selected=
"selected"
:data-selected=
"selected"
:data-project-id=
"projectId"
:data-milestones=
"milestonePath"
:data-group-id=
"groupId"
:data-show-no=
"true"
:data-show-no=
"true"
:data-show-any=
"true"
:data-show-any=
"true"
:data-show-started=
"true"
:data-show-started=
"true"
...
...
ee/spec/fixtures/api/schemas/entities/milestone.json
View file @
aec4c074
{
{
"type"
:
"object"
,
"type"
:
"object"
,
"properties"
:
{
"properties"
:
{
"id"
:
{
"type"
:
"integer"
},
"id"
:
{
"type"
:
"integer"
},
"iid"
:
{
"type"
:
"integer"
},
"iid"
:
{
"type"
:
"integer"
},
"project_id"
:
{
"type"
:
[
"integer"
,
"null"
]
},
"project_id"
:
{
"type"
:
[
"integer"
,
"null"
]
},
...
@@ -12,7 +12,6 @@
...
@@ -12,7 +12,6 @@
"updated_at"
:
{
"type"
:
"string"
},
"updated_at"
:
{
"type"
:
"string"
},
"start_date"
:
{
"type"
:
[
"date"
,
"null"
]
},
"start_date"
:
{
"type"
:
[
"date"
,
"null"
]
},
"due_date"
:
{
"type"
:
[
"date"
,
"null"
]
},
"due_date"
:
{
"type"
:
[
"date"
,
"null"
]
},
"expired"
:
{
"type"
:
[
"boolean"
,
"null"
]
},
"web_url"
:
{
"type"
:
"string"
}
"web_url"
:
{
"type"
:
"string"
}
},
},
"additionalProperties"
:
false
"additionalProperties"
:
false
...
...
ee/spec/frontend/boards/components/board_scope_spec.js
View file @
aec4c074
...
@@ -14,6 +14,7 @@ describe('BoardScope', () => {
...
@@ -14,6 +14,7 @@ describe('BoardScope', () => {
labels
:
[],
labels
:
[],
assignee
:
{},
assignee
:
{},
},
},
milestonePath
:
`
${
TEST_HOST
}
/milestones`
,
labelsPath
:
`
${
TEST_HOST
}
/labels`
,
labelsPath
:
`
${
TEST_HOST
}
/labels`
,
};
};
...
...
ee/spec/frontend/boards/milestone_select_spec.js
View file @
aec4c074
import
Vue
from
'
vue
'
;
import
Vue
from
'
vue
'
;
import
Api
from
'
~/api
'
;
import
MockAdapater
from
'
axios-mock-adapter
'
;
import
MilestoneSelect
from
'
ee/boards/components/milestone_select.vue
'
;
import
MilestoneSelect
from
'
ee/boards/components/milestone_select.vue
'
;
import
{
boardObj
}
from
'
jest/boards/mock_data
'
;
import
{
boardObj
}
from
'
jest/boards/mock_data
'
;
import
axios
from
'
~/lib/utils/axios_utils
'
;
import
IssuableContext
from
'
~/issuable_context
'
;
import
IssuableContext
from
'
~/issuable_context
'
;
let
vm
;
let
vm
;
...
@@ -20,16 +21,12 @@ const milestone = {
...
@@ -20,16 +21,12 @@ const milestone = {
id
:
1
,
id
:
1
,
title
:
'
first milestone
'
,
title
:
'
first milestone
'
,
name
:
'
first milestone
'
,
name
:
'
first milestone
'
,
due_date
:
'
2015-05-05
'
,
expired
:
true
,
};
};
const
milestone2
=
{
const
milestone2
=
{
id
:
2
,
id
:
2
,
title
:
'
second milestone
'
,
title
:
'
second milestone
'
,
name
:
'
second milestone
'
,
name
:
'
second milestone
'
,
due_date
:
null
,
expired
:
false
,
};
};
describe
(
'
Milestone select component
'
,
()
=>
{
describe
(
'
Milestone select component
'
,
()
=>
{
...
@@ -43,8 +40,7 @@ describe('Milestone select component', () => {
...
@@ -43,8 +40,7 @@ describe('Milestone select component', () => {
vm
=
new
Component
({
vm
=
new
Component
({
propsData
:
{
propsData
:
{
board
:
boardObj
,
board
:
boardObj
,
groupId
:
2
,
milestonePath
:
'
/test/issue-boards/milestones.json
'
,
projectId
:
2
,
canEdit
:
true
,
canEdit
:
true
,
},
},
}).
$mount
(
'
.test-container
'
);
}).
$mount
(
'
.test-container
'
);
...
@@ -96,8 +92,15 @@ describe('Milestone select component', () => {
...
@@ -96,8 +92,15 @@ describe('Milestone select component', () => {
});
});
describe
(
'
clicking dropdown items
'
,
()
=>
{
describe
(
'
clicking dropdown items
'
,
()
=>
{
let
mock
;
beforeEach
(()
=>
{
beforeEach
(()
=>
{
jest
.
spyOn
(
Api
,
'
projectMilestones
'
).
mockResolvedValue
({
data
:
[
milestone
,
milestone2
]
});
mock
=
new
MockAdapater
(
axios
);
mock
.
onGet
(
'
/test/issue-boards/milestones.json
'
).
reply
(
200
,
[
milestone
,
milestone2
]);
});
afterEach
(()
=>
{
mock
.
restore
();
});
});
it
(
'
sets Any milestone
'
,
async
done
=>
{
it
(
'
sets Any milestone
'
,
async
done
=>
{
...
@@ -144,10 +147,9 @@ describe('Milestone select component', () => {
...
@@ -144,10 +147,9 @@ describe('Milestone select component', () => {
});
});
setImmediate
(()
=>
{
setImmediate
(()
=>
{
// "second milestone" is not expired, hence it shows up to the top.
expect
(
activeDropdownItem
(
0
)).
toEqual
(
'
first milestone
'
);
expect
(
activeDropdownItem
(
0
)).
toBe
(
'
second milestone
'
);
expect
(
selectedText
()).
toEqual
(
'
first milestone
'
);
expect
(
selectedText
()).
toBe
(
'
second milestone
'
);
expect
(
vm
.
board
.
milestone
).
toEqual
(
milestone
);
expect
(
vm
.
board
.
milestone
).
toEqual
(
milestone2
);
done
();
done
();
});
});
});
});
...
...
lib/api/entities/milestone.rb
View file @
aec4c074
...
@@ -10,7 +10,6 @@ module API
...
@@ -10,7 +10,6 @@ module API
expose
:state
,
:created_at
,
:updated_at
expose
:state
,
:created_at
,
:updated_at
expose
:due_date
expose
:due_date
expose
:start_date
expose
:start_date
expose
:expired?
,
as: :expired
expose
:web_url
do
|
milestone
,
_options
|
expose
:web_url
do
|
milestone
,
_options
|
Gitlab
::
UrlBuilder
.
build
(
milestone
)
Gitlab
::
UrlBuilder
.
build
(
milestone
)
...
...
locale/gitlab.pot
View file @
aec4c074
...
@@ -358,9 +358,6 @@ msgstr ""
...
@@ -358,9 +358,6 @@ msgstr ""
msgid "%{description}- Sentry event: %{errorUrl}- First seen: %{firstSeen}- Last seen: %{lastSeen} %{countLabel}: %{count}%{userCountLabel}: %{userCount}"
msgid "%{description}- Sentry event: %{errorUrl}- First seen: %{firstSeen}- Last seen: %{lastSeen} %{countLabel}: %{count}%{userCountLabel}: %{userCount}"
msgstr ""
msgstr ""
msgid "%{due_date} (Past due)"
msgstr ""
msgid "%{duration}ms"
msgid "%{duration}ms"
msgstr ""
msgstr ""
...
@@ -487,12 +484,6 @@ msgstr ""
...
@@ -487,12 +484,6 @@ msgstr ""
msgid "%{mergeLength}/%{usersLength} can merge"
msgid "%{mergeLength}/%{usersLength} can merge"
msgstr ""
msgstr ""
msgid "%{milestone_name} (Past due)"
msgstr ""
msgid "%{milestone} (expired)"
msgstr ""
msgid "%{mrText}, this issue will be closed automatically."
msgid "%{mrText}, this issue will be closed automatically."
msgstr ""
msgstr ""
...
...
spec/fixtures/api/schemas/public_api/v4/milestone.json
View file @
aec4c074
...
@@ -12,13 +12,11 @@
...
@@ -12,13 +12,11 @@
"updated_at"
:
{
"type"
:
"date"
},
"updated_at"
:
{
"type"
:
"date"
},
"start_date"
:
{
"type"
:
"date"
},
"start_date"
:
{
"type"
:
"date"
},
"due_date"
:
{
"type"
:
"date"
},
"due_date"
:
{
"type"
:
"date"
},
"expired"
:
{
"type"
:
[
"boolean"
,
"null"
]
},
"web_url"
:
{
"type"
:
"string"
}
"web_url"
:
{
"type"
:
"string"
}
},
},
"required"
:
[
"required"
:
[
"id"
,
"iid"
,
"title"
,
"description"
,
"state"
,
"id"
,
"iid"
,
"title"
,
"description"
,
"state"
,
"state"
,
"created_at"
,
"updated_at"
,
"start_date"
,
"state"
,
"created_at"
,
"updated_at"
,
"start_date"
,
"due_date"
"due_date"
,
"expired"
],
],
"additionalProperties"
:
false
"additionalProperties"
:
false
}
}
spec/fixtures/api/schemas/public_api/v4/milestone_with_stats.json
View file @
aec4c074
...
@@ -12,7 +12,6 @@
...
@@ -12,7 +12,6 @@
"updated_at"
:
{
"type"
:
"date"
},
"updated_at"
:
{
"type"
:
"date"
},
"start_date"
:
{
"type"
:
"date"
},
"start_date"
:
{
"type"
:
"date"
},
"due_date"
:
{
"type"
:
"date"
},
"due_date"
:
{
"type"
:
"date"
},
"expired"
:
{
"type"
:
[
"boolean"
,
"null"
]
},
"web_url"
:
{
"type"
:
"string"
},
"web_url"
:
{
"type"
:
"string"
},
"issue_stats"
:
{
"issue_stats"
:
{
"required"
:
[
"total"
,
"closed"
],
"required"
:
[
"total"
,
"closed"
],
...
@@ -25,8 +24,7 @@
...
@@ -25,8 +24,7 @@
},
},
"required"
:
[
"required"
:
[
"id"
,
"iid"
,
"title"
,
"description"
,
"state"
,
"id"
,
"iid"
,
"title"
,
"description"
,
"state"
,
"state"
,
"created_at"
,
"updated_at"
,
"start_date"
,
"state"
,
"created_at"
,
"updated_at"
,
"start_date"
,
"due_date"
,
"issue_stats"
"due_date"
,
"expired"
,
"issue_stats"
],
],
"additionalProperties"
:
false
"additionalProperties"
:
false
}
}
spec/frontend/api_spec.js
View file @
aec4c074
...
@@ -96,29 +96,6 @@ describe('Api', () => {
...
@@ -96,29 +96,6 @@ describe('Api', () => {
});
});
});
});
describe
(
'
groupMilestones
'
,
()
=>
{
it
(
'
fetches group milestones
'
,
done
=>
{
const
groupId
=
1
;
const
options
=
{
state
:
'
active
'
};
const
expectedUrl
=
`
${
dummyUrlRoot
}
/api/
${
dummyApiVersion
}
/groups/1/milestones`
;
mock
.
onGet
(
expectedUrl
).
reply
(
200
,
[
{
id
:
1
,
title
:
'
milestone1
'
,
state
:
'
active
'
,
},
]);
Api
.
groupMilestones
(
groupId
,
options
)
.
then
(({
data
})
=>
{
expect
(
data
.
length
).
toBe
(
1
);
expect
(
data
[
0
].
title
).
toBe
(
'
milestone1
'
);
})
.
then
(
done
)
.
catch
(
done
.
fail
);
});
});
describe
(
'
namespaces
'
,
()
=>
{
describe
(
'
namespaces
'
,
()
=>
{
it
(
'
fetches namespaces
'
,
done
=>
{
it
(
'
fetches namespaces
'
,
done
=>
{
const
query
=
'
dummy query
'
;
const
query
=
'
dummy query
'
;
...
@@ -319,29 +296,6 @@ describe('Api', () => {
...
@@ -319,29 +296,6 @@ describe('Api', () => {
});
});
});
});
describe
(
'
projectMilestones
'
,
()
=>
{
it
(
'
fetches project milestones
'
,
done
=>
{
const
projectId
=
1
;
const
options
=
{
state
:
'
active
'
};
const
expectedUrl
=
`
${
dummyUrlRoot
}
/api/
${
dummyApiVersion
}
/projects/1/milestones`
;
mock
.
onGet
(
expectedUrl
).
reply
(
200
,
[
{
id
:
1
,
title
:
'
milestone1
'
,
state
:
'
active
'
,
},
]);
Api
.
projectMilestones
(
projectId
,
options
)
.
then
(({
data
})
=>
{
expect
(
data
.
length
).
toBe
(
1
);
expect
(
data
[
0
].
title
).
toBe
(
'
milestone1
'
);
})
.
then
(
done
)
.
catch
(
done
.
fail
);
});
});
describe
(
'
newLabel
'
,
()
=>
{
describe
(
'
newLabel
'
,
()
=>
{
it
(
'
creates a new label
'
,
done
=>
{
it
(
'
creates a new label
'
,
done
=>
{
const
namespace
=
'
some namespace
'
;
const
namespace
=
'
some namespace
'
;
...
...
spec/frontend/boards/components/board_form_spec.js
View file @
aec4c074
...
@@ -10,6 +10,7 @@ describe('board_form.vue', () => {
...
@@ -10,6 +10,7 @@ describe('board_form.vue', () => {
const
propsData
=
{
const
propsData
=
{
canAdminBoard
:
false
,
canAdminBoard
:
false
,
labelsPath
:
`
${
gl
.
TEST_HOST
}
/labels/path`
,
labelsPath
:
`
${
gl
.
TEST_HOST
}
/labels/path`
,
milestonePath
:
`
${
gl
.
TEST_HOST
}
/milestone/path`
,
};
};
const
findModal
=
()
=>
wrapper
.
find
(
DeprecatedModal
);
const
findModal
=
()
=>
wrapper
.
find
(
DeprecatedModal
);
...
...
spec/frontend/boards/components/boards_selector_spec.js
View file @
aec4c074
...
@@ -81,6 +81,7 @@ describe('BoardsSelector', () => {
...
@@ -81,6 +81,7 @@ describe('BoardsSelector', () => {
assignee_id
:
null
,
assignee_id
:
null
,
labels
:
[],
labels
:
[],
},
},
milestonePath
:
`
${
TEST_HOST
}
/milestone/path`
,
boardBaseUrl
:
`
${
TEST_HOST
}
/board/base/url`
,
boardBaseUrl
:
`
${
TEST_HOST
}
/board/base/url`
,
hasMissingBoards
:
false
,
hasMissingBoards
:
false
,
canAdminBoard
:
true
,
canAdminBoard
:
true
,
...
...
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