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
337b2c80
Commit
337b2c80
authored
Oct 04, 2018
by
Martin Wortschack
Committed by
Phil Hughes
Oct 04, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Resolve "Add new "Overview" tab on user profile page"
parent
14ed916c
Changes
16
Show whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
398 additions
and
61 deletions
+398
-61
app/assets/javascripts/pages/users/activity_calendar.js
app/assets/javascripts/pages/users/activity_calendar.js
+18
-8
app/assets/javascripts/pages/users/user_overview_block.js
app/assets/javascripts/pages/users/user_overview_block.js
+42
-0
app/assets/javascripts/pages/users/user_tabs.js
app/assets/javascripts/pages/users/user_tabs.js
+67
-17
app/assets/stylesheets/framework/calendar.scss
app/assets/stylesheets/framework/calendar.scss
+7
-5
app/controllers/users_controller.rb
app/controllers/users_controller.rb
+9
-4
app/finders/user_recent_events_finder.rb
app/finders/user_recent_events_finder.rb
+1
-1
app/helpers/users_helper.rb
app/helpers/users_helper.rb
+1
-1
app/views/users/_overview.html.haml
app/views/users/_overview.html.haml
+32
-0
app/views/users/show.html.haml
app/views/users/show.html.haml
+23
-15
changelogs/unreleased/49801-add-new-overview-tab-on-user-profile-page.yml
...eased/49801-add-new-overview-tab-on-user-profile-page.yml
+5
-0
config/routes/user.rb
config/routes/user.rb
+1
-0
locale/gitlab.pot
locale/gitlab.pot
+54
-0
spec/features/calendar_spec.rb
spec/features/calendar_spec.rb
+12
-9
spec/features/dashboard/datetime_on_tooltips_spec.rb
spec/features/dashboard/datetime_on_tooltips_spec.rb
+1
-1
spec/features/users/overview_spec.rb
spec/features/users/overview_spec.rb
+123
-0
spec/features/users/show_spec.rb
spec/features/users/show_spec.rb
+2
-0
No files found.
app/assets/javascripts/pages/users/activity_calendar.js
View file @
337b2c80
...
@@ -43,7 +43,15 @@ const initColorKey = () =>
...
@@ -43,7 +43,15 @@ const initColorKey = () =>
.
domain
([
0
,
3
]);
.
domain
([
0
,
3
]);
export
default
class
ActivityCalendar
{
export
default
class
ActivityCalendar
{
constructor
(
container
,
timestamps
,
calendarActivitiesPath
,
utcOffset
=
0
,
firstDayOfWeek
=
0
)
{
constructor
(
container
,
activitiesContainer
,
timestamps
,
calendarActivitiesPath
,
utcOffset
=
0
,
firstDayOfWeek
=
0
,
monthsAgo
=
12
,
)
{
this
.
calendarActivitiesPath
=
calendarActivitiesPath
;
this
.
calendarActivitiesPath
=
calendarActivitiesPath
;
this
.
clickDay
=
this
.
clickDay
.
bind
(
this
);
this
.
clickDay
=
this
.
clickDay
.
bind
(
this
);
this
.
currentSelectedDate
=
''
;
this
.
currentSelectedDate
=
''
;
...
@@ -66,6 +74,8 @@ export default class ActivityCalendar {
...
@@ -66,6 +74,8 @@ export default class ActivityCalendar {
];
];
this
.
months
=
[];
this
.
months
=
[];
this
.
firstDayOfWeek
=
firstDayOfWeek
;
this
.
firstDayOfWeek
=
firstDayOfWeek
;
this
.
activitiesContainer
=
activitiesContainer
;
this
.
container
=
container
;
// Loop through the timestamps to create a group of objects
// Loop through the timestamps to create a group of objects
// The group of objects will be grouped based on the day of the week they are
// The group of objects will be grouped based on the day of the week they are
...
@@ -75,13 +85,13 @@ export default class ActivityCalendar {
...
@@ -75,13 +85,13 @@ export default class ActivityCalendar {
const
today
=
getSystemDate
(
utcOffset
);
const
today
=
getSystemDate
(
utcOffset
);
today
.
setHours
(
0
,
0
,
0
,
0
,
0
);
today
.
setHours
(
0
,
0
,
0
,
0
,
0
);
const
oneYear
Ago
=
new
Date
(
today
);
const
time
Ago
=
new
Date
(
today
);
oneYearAgo
.
setFullYear
(
today
.
getFullYear
()
-
1
);
timeAgo
.
setMonth
(
today
.
getMonth
()
-
monthsAgo
);
const
days
=
getDayDifference
(
oneYear
Ago
,
today
);
const
days
=
getDayDifference
(
time
Ago
,
today
);
for
(
let
i
=
0
;
i
<=
days
;
i
+=
1
)
{
for
(
let
i
=
0
;
i
<=
days
;
i
+=
1
)
{
const
date
=
new
Date
(
oneYear
Ago
);
const
date
=
new
Date
(
time
Ago
);
date
.
setDate
(
date
.
getDate
()
+
i
);
date
.
setDate
(
date
.
getDate
()
+
i
);
const
day
=
date
.
getDay
();
const
day
=
date
.
getDay
();
...
@@ -280,7 +290,7 @@ export default class ActivityCalendar {
...
@@ -280,7 +290,7 @@ export default class ActivityCalendar {
this
.
currentSelectedDate
.
getDate
(),
this
.
currentSelectedDate
.
getDate
(),
].
join
(
'
-
'
);
].
join
(
'
-
'
);
$
(
'
.user-calendar-activities
'
).
html
(
LOADING_HTML
);
$
(
this
.
activitiesContainer
).
html
(
LOADING_HTML
);
axios
axios
.
get
(
this
.
calendarActivitiesPath
,
{
.
get
(
this
.
calendarActivitiesPath
,
{
...
@@ -289,11 +299,11 @@ export default class ActivityCalendar {
...
@@ -289,11 +299,11 @@ export default class ActivityCalendar {
},
},
responseType
:
'
text
'
,
responseType
:
'
text
'
,
})
})
.
then
(({
data
})
=>
$
(
'
.user-calendar-activities
'
).
html
(
data
))
.
then
(({
data
})
=>
$
(
this
.
activitiesContainer
).
html
(
data
))
.
catch
(()
=>
flash
(
__
(
'
An error occurred while retrieving calendar activity
'
)));
.
catch
(()
=>
flash
(
__
(
'
An error occurred while retrieving calendar activity
'
)));
}
else
{
}
else
{
this
.
currentSelectedDate
=
''
;
this
.
currentSelectedDate
=
''
;
$
(
'
.user-calendar-activities
'
).
html
(
''
);
$
(
this
.
activitiesContainer
).
html
(
''
);
}
}
}
}
}
}
app/assets/javascripts/pages/users/user_overview_block.js
0 → 100644
View file @
337b2c80
import
axios
from
'
~/lib/utils/axios_utils
'
;
export
default
class
UserOverviewBlock
{
constructor
(
options
=
{})
{
this
.
container
=
options
.
container
;
this
.
url
=
options
.
url
;
this
.
limit
=
options
.
limit
||
20
;
this
.
loadData
();
}
loadData
()
{
const
loadingEl
=
document
.
querySelector
(
`
${
this
.
container
}
.loading`
);
loadingEl
.
classList
.
remove
(
'
hide
'
);
axios
.
get
(
this
.
url
,
{
params
:
{
limit
:
this
.
limit
,
},
})
.
then
(({
data
})
=>
this
.
render
(
data
))
.
catch
(()
=>
loadingEl
.
classList
.
add
(
'
hide
'
));
}
render
(
data
)
{
const
{
html
,
count
}
=
data
;
const
contentList
=
document
.
querySelector
(
`
${
this
.
container
}
.overview-content-list`
);
contentList
.
innerHTML
+=
html
;
const
loadingEl
=
document
.
querySelector
(
`
${
this
.
container
}
.loading`
);
if
(
count
&&
count
>
0
)
{
document
.
querySelector
(
`
${
this
.
container
}
.js-view-all`
).
classList
.
remove
(
'
hide
'
);
}
else
{
document
.
querySelector
(
`
${
this
.
container
}
.nothing-here-block`
).
classList
.
add
(
'
text-left
'
,
'
p-0
'
);
}
loadingEl
.
classList
.
add
(
'
hide
'
);
}
}
app/assets/javascripts/pages/users/user_tabs.js
View file @
337b2c80
...
@@ -2,9 +2,10 @@ import $ from 'jquery';
...
@@ -2,9 +2,10 @@ import $ from 'jquery';
import
axios
from
'
~/lib/utils/axios_utils
'
;
import
axios
from
'
~/lib/utils/axios_utils
'
;
import
Activities
from
'
~/activities
'
;
import
Activities
from
'
~/activities
'
;
import
{
localTimeAgo
}
from
'
~/lib/utils/datetime_utility
'
;
import
{
localTimeAgo
}
from
'
~/lib/utils/datetime_utility
'
;
import
{
__
}
from
'
~/locale
'
;
import
{
__
,
sprintf
}
from
'
~/locale
'
;
import
flash
from
'
~/flash
'
;
import
flash
from
'
~/flash
'
;
import
ActivityCalendar
from
'
./activity_calendar
'
;
import
ActivityCalendar
from
'
./activity_calendar
'
;
import
UserOverviewBlock
from
'
./user_overview_block
'
;
/**
/**
* UserTabs
* UserTabs
...
@@ -61,19 +62,28 @@ import ActivityCalendar from './activity_calendar';
...
@@ -61,19 +62,28 @@ import ActivityCalendar from './activity_calendar';
* </div>
* </div>
*/
*/
const
CALENDAR_TEMPLATE
=
`
const
CALENDAR_TEMPLATES
=
{
activity
:
`
<div class="clearfix calendar">
<div class="clearfix calendar">
<div class="js-contrib-calendar"></div>
<div class="js-contrib-calendar"></div>
<div class="calendar-hint">
<div class="calendar-hint bottom-right"></div>
Summary of issues, merge requests, push events, and comments
</div>
</div>
`
,
overview
:
`
<div class="clearfix calendar">
<div class="calendar-hint"></div>
<div class="js-contrib-calendar prepend-top-20"></div>
</div>
</div>
`
;
`
,
};
const
CALENDAR_PERIOD_6_MONTHS
=
6
;
const
CALENDAR_PERIOD_12_MONTHS
=
12
;
export
default
class
UserTabs
{
export
default
class
UserTabs
{
constructor
({
defaultAction
,
action
,
parentEl
})
{
constructor
({
defaultAction
,
action
,
parentEl
})
{
this
.
loaded
=
{};
this
.
loaded
=
{};
this
.
defaultAction
=
defaultAction
||
'
activity
'
;
this
.
defaultAction
=
defaultAction
||
'
overview
'
;
this
.
action
=
action
||
this
.
defaultAction
;
this
.
action
=
action
||
this
.
defaultAction
;
this
.
$parentEl
=
$
(
parentEl
)
||
$
(
document
);
this
.
$parentEl
=
$
(
parentEl
)
||
$
(
document
);
this
.
windowLocation
=
window
.
location
;
this
.
windowLocation
=
window
.
location
;
...
@@ -124,6 +134,8 @@ export default class UserTabs {
...
@@ -124,6 +134,8 @@ export default class UserTabs {
}
}
if
(
action
===
'
activity
'
)
{
if
(
action
===
'
activity
'
)
{
this
.
loadActivities
();
this
.
loadActivities
();
}
else
if
(
action
===
'
overview
'
)
{
this
.
loadOverviewTab
();
}
}
const
loadableActions
=
[
'
groups
'
,
'
contributed
'
,
'
projects
'
,
'
snippets
'
];
const
loadableActions
=
[
'
groups
'
,
'
contributed
'
,
'
projects
'
,
'
snippets
'
];
...
@@ -154,7 +166,40 @@ export default class UserTabs {
...
@@ -154,7 +166,40 @@ export default class UserTabs {
if
(
this
.
loaded
.
activity
)
{
if
(
this
.
loaded
.
activity
)
{
return
;
return
;
}
}
const
$calendarWrap
=
this
.
$parentEl
.
find
(
'
.user-calendar
'
);
this
.
loadActivityCalendar
(
'
activity
'
);
// eslint-disable-next-line no-new
new
Activities
();
this
.
loaded
.
activity
=
true
;
}
loadOverviewTab
()
{
if
(
this
.
loaded
.
overview
)
{
return
;
}
this
.
loadActivityCalendar
(
'
overview
'
);
UserTabs
.
renderMostRecentBlocks
(
'
#js-overview .activities-block
'
,
5
);
UserTabs
.
renderMostRecentBlocks
(
'
#js-overview .projects-block
'
,
10
);
this
.
loaded
.
overview
=
true
;
}
static
renderMostRecentBlocks
(
container
,
limit
)
{
// eslint-disable-next-line no-new
new
UserOverviewBlock
({
container
,
url
:
$
(
`
${
container
}
.overview-content-list`
).
data
(
'
href
'
),
limit
,
});
}
loadActivityCalendar
(
action
)
{
const
monthsAgo
=
action
===
'
overview
'
?
CALENDAR_PERIOD_6_MONTHS
:
CALENDAR_PERIOD_12_MONTHS
;
const
$calendarWrap
=
this
.
$parentEl
.
find
(
'
.tab-pane.active .user-calendar
'
);
const
calendarPath
=
$calendarWrap
.
data
(
'
calendarPath
'
);
const
calendarPath
=
$calendarWrap
.
data
(
'
calendarPath
'
);
const
calendarActivitiesPath
=
$calendarWrap
.
data
(
'
calendarActivitiesPath
'
);
const
calendarActivitiesPath
=
$calendarWrap
.
data
(
'
calendarActivitiesPath
'
);
const
utcOffset
=
$calendarWrap
.
data
(
'
utcOffset
'
);
const
utcOffset
=
$calendarWrap
.
data
(
'
utcOffset
'
);
...
@@ -166,17 +211,22 @@ export default class UserTabs {
...
@@ -166,17 +211,22 @@ export default class UserTabs {
axios
axios
.
get
(
calendarPath
)
.
get
(
calendarPath
)
.
then
(({
data
})
=>
{
.
then
(({
data
})
=>
{
$calendarWrap
.
html
(
CALENDAR_TEMPLATE
);
$calendarWrap
.
html
(
CALENDAR_TEMPLATES
[
action
]);
$calendarWrap
.
find
(
'
.calendar-hint
'
).
append
(
`(Timezone:
${
utcFormatted
}
)`
);
let
calendarHint
=
''
;
if
(
action
===
'
activity
'
)
{
calendarHint
=
sprintf
(
__
(
'
Summary of issues, merge requests, push events, and comments (Timezone: %{utcFormatted})
'
),
{
utcFormatted
});
}
else
if
(
action
===
'
overview
'
)
{
calendarHint
=
__
(
'
Issues, merge requests, pushes and comments.
'
);
}
$calendarWrap
.
find
(
'
.calendar-hint
'
).
text
(
calendarHint
);
// eslint-disable-next-line no-new
// eslint-disable-next-line no-new
new
ActivityCalendar
(
'
.
js-contrib-calendar
'
,
data
,
calendarActivitiesPath
,
utcOffset
);
new
ActivityCalendar
(
'
.
tab-pane.active .js-contrib-calendar
'
,
'
.tab-pane.active .user-calendar-activities
'
,
data
,
calendarActivitiesPath
,
utcOffset
,
0
,
monthsAgo
);
})
})
.
catch
(()
=>
flash
(
__
(
'
There was an error loading users activity calendar.
'
)));
.
catch
(()
=>
flash
(
__
(
'
There was an error loading users activity calendar.
'
)));
// eslint-disable-next-line no-new
new
Activities
();
this
.
loaded
.
activity
=
true
;
}
}
toggleLoading
(
status
)
{
toggleLoading
(
status
)
{
...
...
app/assets/stylesheets/framework/calendar.scss
View file @
337b2c80
.calend
e
r-block
{
.calend
a
r-block
{
padding-left
:
0
;
padding-left
:
0
;
padding-right
:
0
;
padding-right
:
0
;
border-top
:
0
;
border-top
:
0
;
direction
:
rtl
;
@media
(
min-width
:
map-get
(
$grid-breakpoints
,
sm
))
and
(
max-width
:
map-get
(
$grid-breakpoints
,
sm
))
{
@media
(
min-width
:
map-get
(
$grid-breakpoints
,
sm
))
and
(
max-width
:
map-get
(
$grid-breakpoints
,
sm
))
{
overflow-x
:
auto
;
overflow-x
:
auto
;
...
@@ -42,10 +41,13 @@
...
@@ -42,10 +41,13 @@
}
}
.calendar-hint
{
.calendar-hint
{
margin-top
:
-23px
;
float
:
right
;
font-size
:
12px
;
font-size
:
12px
;
&
.bottom-right
{
direction
:
ltr
;
direction
:
ltr
;
margin-top
:
-23px
;
float
:
right
;
}
}
}
.pika-single.gitlab-theme
{
.pika-single.gitlab-theme
{
...
...
app/controllers/users_controller.rb
View file @
337b2c80
...
@@ -29,11 +29,17 @@ class UsersController < ApplicationController
...
@@ -29,11 +29,17 @@ class UsersController < ApplicationController
format
.
json
do
format
.
json
do
load_events
load_events
pager_json
(
"events/_events"
,
@events
.
count
)
pager_json
(
"events/_events"
,
@events
.
count
,
events:
@events
)
end
end
end
end
end
end
def
activity
respond_to
do
|
format
|
format
.
html
{
render
'show'
}
end
end
def
groups
def
groups
load_groups
load_groups
...
@@ -53,9 +59,7 @@ class UsersController < ApplicationController
...
@@ -53,9 +59,7 @@ class UsersController < ApplicationController
respond_to
do
|
format
|
respond_to
do
|
format
|
format
.
html
{
render
'show'
}
format
.
html
{
render
'show'
}
format
.
json
do
format
.
json
do
render
json:
{
pager_json
(
"shared/projects/_list"
,
@projects
.
count
,
projects:
@projects
)
html:
view_to_html_string
(
"shared/projects/_list"
,
projects:
@projects
)
}
end
end
end
end
end
end
...
@@ -125,6 +129,7 @@ class UsersController < ApplicationController
...
@@ -125,6 +129,7 @@ class UsersController < ApplicationController
@projects
=
@projects
=
PersonalProjectsFinder
.
new
(
user
).
execute
(
current_user
)
PersonalProjectsFinder
.
new
(
user
).
execute
(
current_user
)
.
page
(
params
[
:page
])
.
page
(
params
[
:page
])
.
per
(
params
[
:limit
])
prepare_projects_for_rendering
(
@projects
)
prepare_projects_for_rendering
(
@projects
)
end
end
...
...
app/finders/user_recent_events_finder.rb
View file @
337b2c80
...
@@ -31,7 +31,7 @@ class UserRecentEventsFinder
...
@@ -31,7 +31,7 @@ class UserRecentEventsFinder
recent_events
(
params
[
:offset
]
||
0
)
recent_events
(
params
[
:offset
]
||
0
)
.
joins
(
:project
)
.
joins
(
:project
)
.
with_associations
.
with_associations
.
limit_recent
(
LIMIT
,
params
[
:offset
])
.
limit_recent
(
params
[
:limit
].
presence
||
LIMIT
,
params
[
:offset
])
end
end
# rubocop: enable CodeReuse/ActiveRecord
# rubocop: enable CodeReuse/ActiveRecord
...
...
app/helpers/users_helper.rb
View file @
337b2c80
...
@@ -76,7 +76,7 @@ module UsersHelper
...
@@ -76,7 +76,7 @@ module UsersHelper
tabs
=
[]
tabs
=
[]
if
can?
(
current_user
,
:read_user_profile
,
@user
)
if
can?
(
current_user
,
:read_user_profile
,
@user
)
tabs
+=
[
:activity
,
:groups
,
:contributed
,
:projects
,
:snippets
]
tabs
+=
[
:
overview
,
:
activity
,
:groups
,
:contributed
,
:projects
,
:snippets
]
end
end
tabs
tabs
...
...
app/views/users/_overview.html.haml
0 → 100644
View file @
337b2c80
.row
.col-md-12.col-lg-6
.calendar-block
.content-block.hide-bottom-border
%h4
=
s_
(
'UserProfile|Activity'
)
.user-calendar.d-none.d-sm-block.text-left
{
data:
{
calendar_path:
user_calendar_path
(
@user
,
:json
),
calendar_activities_path:
user_calendar_activities_path
,
utc_offset:
Time
.
zone
.
utc_offset
}
}
%h4
.center.light
%i
.fa.fa-spinner.fa-spin
.user-calendar-activities.d-none.d-sm-block
-
if
can?
(
current_user
,
:read_cross_project
)
.activities-block
.content-block
%h5
.prepend-top-10
=
s_
(
'UserProfile|Recent contributions'
)
.overview-content-list
{
data:
{
href:
user_path
}
}
.center.light.loading
%i
.fa.fa-spinner.fa-spin
.prepend-top-10
=
link_to
s_
(
'UserProfile|View all'
),
user_activity_path
,
class:
"hide js-view-all"
.col-md-12.col-lg-6
.projects-block
.content-block
%h4
=
s_
(
'UserProfile|Personal projects'
)
.overview-content-list
{
data:
{
href:
user_projects_path
}
}
.center.light.loading
%i
.fa.fa-spinner.fa-spin
.prepend-top-10
=
link_to
s_
(
'UserProfile|View all'
),
user_projects_path
,
class:
"hide js-view-all"
app/views/users/show.html.haml
View file @
337b2c80
...
@@ -12,22 +12,22 @@
...
@@ -12,22 +12,22 @@
.cover-block.user-cover-block.top-area
.cover-block.user-cover-block.top-area
.cover-controls
.cover-controls
-
if
@user
==
current_user
-
if
@user
==
current_user
=
link_to
profile_path
,
class:
'btn btn-default has-tooltip'
,
title:
'Edit profile'
,
'aria-label'
:
'Edit profile'
do
=
link_to
profile_path
,
class:
'btn btn-default has-tooltip'
,
title:
s_
(
'UserProfile|Edit profile'
)
,
'aria-label'
:
'Edit profile'
do
=
icon
(
'pencil'
)
=
icon
(
'pencil'
)
-
elsif
current_user
-
elsif
current_user
-
if
@user
.
abuse_report
-
if
@user
.
abuse_report
%button
.btn.btn-danger
{
title:
'Already reported for abuse'
,
%button
.btn.btn-danger
{
title:
s_
(
'UserProfile|Already reported for abuse'
)
,
data:
{
toggle:
'tooltip'
,
placement:
'bottom'
,
container:
'body'
}
}
data:
{
toggle:
'tooltip'
,
placement:
'bottom'
,
container:
'body'
}
}
=
icon
(
'exclamation-circle'
)
=
icon
(
'exclamation-circle'
)
-
else
-
else
=
link_to
new_abuse_report_path
(
user_id:
@user
.
id
,
ref_url:
request
.
referrer
),
class:
'btn'
,
=
link_to
new_abuse_report_path
(
user_id:
@user
.
id
,
ref_url:
request
.
referrer
),
class:
'btn'
,
title:
'Report abuse'
,
data:
{
toggle:
'tooltip'
,
placement:
'bottom'
,
container:
'body'
}
do
title:
s_
(
'UserProfile|Report abuse'
)
,
data:
{
toggle:
'tooltip'
,
placement:
'bottom'
,
container:
'body'
}
do
=
icon
(
'exclamation-circle'
)
=
icon
(
'exclamation-circle'
)
-
if
can?
(
current_user
,
:read_user_profile
,
@user
)
-
if
can?
(
current_user
,
:read_user_profile
,
@user
)
=
link_to
user_path
(
@user
,
rss_url_options
),
class:
'btn btn-default has-tooltip'
,
title:
'Subscribe'
,
'aria-label'
:
'Subscribe'
do
=
link_to
user_path
(
@user
,
rss_url_options
),
class:
'btn btn-default has-tooltip'
,
title:
s_
(
'UserProfile|Subscribe'
)
,
'aria-label'
:
'Subscribe'
do
=
icon
(
'rss'
)
=
icon
(
'rss'
)
-
if
current_user
&&
current_user
.
admin?
-
if
current_user
&&
current_user
.
admin?
=
link_to
[
:admin
,
@user
],
class:
'btn btn-default'
,
title:
'View user in admin area'
,
=
link_to
[
:admin
,
@user
],
class:
'btn btn-default'
,
title:
s_
(
'UserProfile|View user in admin area'
)
,
data:
{
toggle:
'tooltip'
,
placement:
'bottom'
,
container:
'body'
}
do
data:
{
toggle:
'tooltip'
,
placement:
'bottom'
,
container:
'body'
}
do
=
icon
(
'users'
)
=
icon
(
'users'
)
...
@@ -51,7 +51,7 @@
...
@@ -51,7 +51,7 @@
@
#{
@user
.
username
}
@
#{
@user
.
username
}
-
if
can?
(
current_user
,
:read_user_profile
,
@user
)
-
if
can?
(
current_user
,
:read_user_profile
,
@user
)
%span
.middle-dot-divider
%span
.middle-dot-divider
Member since
#{
@user
.
created_at
.
to_date
.
to_s
(
:long
)
}
=
s_
(
'Member since %{date}'
)
%
{
date:
@user
.
created_at
.
to_date
.
to_s
(
:long
)
}
.cover-desc
.cover-desc
-
unless
@user
.
public_email
.
blank?
-
unless
@user
.
public_email
.
blank?
...
@@ -91,32 +91,40 @@
...
@@ -91,32 +91,40 @@
.fade-left
=
icon
(
'angle-left'
)
.fade-left
=
icon
(
'angle-left'
)
.fade-right
=
icon
(
'angle-right'
)
.fade-right
=
icon
(
'angle-right'
)
%ul
.nav-links.user-profile-nav.scrolling-tabs.nav.nav-tabs
%ul
.nav-links.user-profile-nav.scrolling-tabs.nav.nav-tabs
-
if
profile_tab?
(
:overview
)
%li
.js-overview-tab
=
link_to
user_path
,
data:
{
target:
'div#js-overview'
,
action:
'overview'
,
toggle:
'tab'
}
do
=
s_
(
'UserProfile|Overview'
)
-
if
profile_tab?
(
:activity
)
-
if
profile_tab?
(
:activity
)
%li
.js-activity-tab
%li
.js-activity-tab
=
link_to
user_path
,
data:
{
target:
'div#activity'
,
action:
'activity'
,
toggle:
'tab'
}
do
=
link_to
user_
activity_
path
,
data:
{
target:
'div#activity'
,
action:
'activity'
,
toggle:
'tab'
}
do
Activity
=
s_
(
'UserProfile|Activity'
)
-
if
profile_tab?
(
:groups
)
-
if
profile_tab?
(
:groups
)
%li
.js-groups-tab
%li
.js-groups-tab
=
link_to
user_groups_path
,
data:
{
target:
'div#groups'
,
action:
'groups'
,
toggle:
'tab'
,
endpoint:
user_groups_path
(
format: :json
)
}
do
=
link_to
user_groups_path
,
data:
{
target:
'div#groups'
,
action:
'groups'
,
toggle:
'tab'
,
endpoint:
user_groups_path
(
format: :json
)
}
do
Groups
=
s_
(
'UserProfile|Groups'
)
-
if
profile_tab?
(
:contributed
)
-
if
profile_tab?
(
:contributed
)
%li
.js-contributed-tab
%li
.js-contributed-tab
=
link_to
user_contributed_projects_path
,
data:
{
target:
'div#contributed'
,
action:
'contributed'
,
toggle:
'tab'
,
endpoint:
user_contributed_projects_path
(
format: :json
)
}
do
=
link_to
user_contributed_projects_path
,
data:
{
target:
'div#contributed'
,
action:
'contributed'
,
toggle:
'tab'
,
endpoint:
user_contributed_projects_path
(
format: :json
)
}
do
Contributed projects
=
s_
(
'UserProfile|Contributed projects'
)
-
if
profile_tab?
(
:projects
)
-
if
profile_tab?
(
:projects
)
%li
.js-projects-tab
%li
.js-projects-tab
=
link_to
user_projects_path
,
data:
{
target:
'div#projects'
,
action:
'projects'
,
toggle:
'tab'
,
endpoint:
user_projects_path
(
format: :json
)
}
do
=
link_to
user_projects_path
,
data:
{
target:
'div#projects'
,
action:
'projects'
,
toggle:
'tab'
,
endpoint:
user_projects_path
(
format: :json
)
}
do
Personal projects
=
s_
(
'UserProfile|Personal projects'
)
-
if
profile_tab?
(
:snippets
)
-
if
profile_tab?
(
:snippets
)
%li
.js-snippets-tab
%li
.js-snippets-tab
=
link_to
user_snippets_path
,
data:
{
target:
'div#snippets'
,
action:
'snippets'
,
toggle:
'tab'
,
endpoint:
user_snippets_path
(
format: :json
)
}
do
=
link_to
user_snippets_path
,
data:
{
target:
'div#snippets'
,
action:
'snippets'
,
toggle:
'tab'
,
endpoint:
user_snippets_path
(
format: :json
)
}
do
Snippets
=
s_
(
'UserProfile|Snippets'
)
%div
{
class:
container_class
}
%div
{
class:
container_class
}
.tab-content
.tab-content
-
if
profile_tab?
(
:overview
)
#js-overview
.tab-pane
=
render
"users/overview"
-
if
profile_tab?
(
:activity
)
-
if
profile_tab?
(
:activity
)
#activity
.tab-pane
#activity
.tab-pane
.row-content-block.calend
e
r-block.white.second-block.d-none.d-sm-block
.row-content-block.calend
a
r-block.white.second-block.d-none.d-sm-block
.user-calendar
{
data:
{
calendar_path:
user_calendar_path
(
@user
,
:json
),
calendar_activities_path:
user_calendar_activities_path
,
utc_offset:
Time
.
zone
.
utc_offset
}
}
.user-calendar
{
data:
{
calendar_path:
user_calendar_path
(
@user
,
:json
),
calendar_activities_path:
user_calendar_activities_path
,
utc_offset:
Time
.
zone
.
utc_offset
}
}
%h4
.center.light
%h4
.center.light
%i
.fa.fa-spinner.fa-spin
%i
.fa.fa-spinner.fa-spin
...
@@ -124,7 +132,7 @@
...
@@ -124,7 +132,7 @@
-
if
can?
(
current_user
,
:read_cross_project
)
-
if
can?
(
current_user
,
:read_cross_project
)
%h4
.prepend-top-20
%h4
.prepend-top-20
Most Recent Activity
=
s_
(
'UserProfile|Most Recent Activity'
)
.content_list
{
data:
{
href:
user_path
}
}
.content_list
{
data:
{
href:
user_path
}
}
=
spinner
=
spinner
...
@@ -155,4 +163,4 @@
...
@@ -155,4 +163,4 @@
.col-12.text-center
.col-12.text-center
.text-content
.text-content
%h4
%h4
This user has a private profile
=
s_
(
'UserProfile|This user has a private profile'
)
changelogs/unreleased/49801-add-new-overview-tab-on-user-profile-page.yml
0 → 100644
View file @
337b2c80
---
title
:
Adds new 'Overview' tab on user profile page
merge_request
:
21663
author
:
type
:
other
config/routes/user.rb
View file @
337b2c80
...
@@ -45,6 +45,7 @@ scope(constraints: { username: Gitlab::PathRegex.root_namespace_route_regex }) d
...
@@ -45,6 +45,7 @@ scope(constraints: { username: Gitlab::PathRegex.root_namespace_route_regex }) d
get
:contributed
,
as: :contributed_projects
get
:contributed
,
as: :contributed_projects
get
:snippets
get
:snippets
get
:exists
get
:exists
get
:activity
get
'/'
,
to:
redirect
(
'%{username}'
),
as:
nil
get
'/'
,
to:
redirect
(
'%{username}'
),
as:
nil
end
end
...
...
locale/gitlab.pot
View file @
337b2c80
...
@@ -3345,6 +3345,9 @@ msgstr ""
...
@@ -3345,6 +3345,9 @@ msgstr ""
msgid "Issues can be bugs, tasks or ideas to be discussed. Also, issues are searchable and filterable."
msgid "Issues can be bugs, tasks or ideas to be discussed. Also, issues are searchable and filterable."
msgstr ""
msgstr ""
msgid "Issues, merge requests, pushes and comments."
msgstr ""
msgid "Jan"
msgid "Jan"
msgstr ""
msgstr ""
...
@@ -3709,6 +3712,9 @@ msgstr ""
...
@@ -3709,6 +3712,9 @@ msgstr ""
msgid "Median"
msgid "Median"
msgstr ""
msgstr ""
msgid "Member since %{date}"
msgstr ""
msgid "Members"
msgid "Members"
msgstr ""
msgstr ""
...
@@ -5753,6 +5759,9 @@ msgstr ""
...
@@ -5753,6 +5759,9 @@ msgstr ""
msgid "Subscribe at project level"
msgid "Subscribe at project level"
msgstr ""
msgstr ""
msgid "Summary of issues, merge requests, push events, and comments (Timezone: %{utcFormatted})"
msgstr ""
msgid "Switch branch/tag"
msgid "Switch branch/tag"
msgstr ""
msgstr ""
...
@@ -6581,6 +6590,51 @@ msgstr ""
...
@@ -6581,6 +6590,51 @@ msgstr ""
msgid "User map"
msgid "User map"
msgstr ""
msgstr ""
msgid "UserProfile|Activity"
msgstr ""
msgid "UserProfile|Already reported for abuse"
msgstr ""
msgid "UserProfile|Contributed projects"
msgstr ""
msgid "UserProfile|Edit profile"
msgstr ""
msgid "UserProfile|Groups"
msgstr ""
msgid "UserProfile|Most Recent Activity"
msgstr ""
msgid "UserProfile|Overview"
msgstr ""
msgid "UserProfile|Personal projects"
msgstr ""
msgid "UserProfile|Recent contributions"
msgstr ""
msgid "UserProfile|Report abuse"
msgstr ""
msgid "UserProfile|Snippets"
msgstr ""
msgid "UserProfile|Subscribe"
msgstr ""
msgid "UserProfile|This user has a private profile"
msgstr ""
msgid "UserProfile|View all"
msgstr ""
msgid "UserProfile|View user in admin area"
msgstr ""
msgid "Users"
msgid "Users"
msgstr ""
msgstr ""
...
...
spec/features/calendar_spec.rb
View file @
337b2c80
...
@@ -64,7 +64,7 @@ describe 'Contributions Calendar', :js do
...
@@ -64,7 +64,7 @@ describe 'Contributions Calendar', :js do
end
end
def
selected_day_activities
(
visible:
true
)
def
selected_day_activities
(
visible:
true
)
find
(
'.user-calendar-activities'
,
visible:
visible
).
text
find
(
'.
tab-pane#activity .
user-calendar-activities'
,
visible:
visible
).
text
end
end
before
do
before
do
...
@@ -74,15 +74,16 @@ describe 'Contributions Calendar', :js do
...
@@ -74,15 +74,16 @@ describe 'Contributions Calendar', :js do
describe
'calendar day selection'
do
describe
'calendar day selection'
do
before
do
before
do
visit
user
.
username
visit
user
.
username
page
.
find
(
'.js-activity-tab a'
).
click
wait_for_requests
wait_for_requests
end
end
it
'displays calendar'
do
it
'displays calendar'
do
expect
(
page
).
to
have_css
(
'.js-contrib-calendar'
)
expect
(
find
(
'.tab-pane#activity'
)
).
to
have_css
(
'.js-contrib-calendar'
)
end
end
describe
'select calendar day'
do
describe
'select calendar day'
do
let
(
:cells
)
{
page
.
all
(
'.user-contrib-cell'
)
}
let
(
:cells
)
{
page
.
all
(
'.
tab-pane#activity .
user-contrib-cell'
)
}
before
do
before
do
cells
[
0
].
click
cells
[
0
].
click
...
@@ -108,6 +109,7 @@ describe 'Contributions Calendar', :js do
...
@@ -108,6 +109,7 @@ describe 'Contributions Calendar', :js do
describe
'deselect calendar day'
do
describe
'deselect calendar day'
do
before
do
before
do
cells
[
0
].
click
cells
[
0
].
click
page
.
find
(
'.js-activity-tab a'
).
click
wait_for_requests
wait_for_requests
end
end
...
@@ -122,6 +124,7 @@ describe 'Contributions Calendar', :js do
...
@@ -122,6 +124,7 @@ describe 'Contributions Calendar', :js do
shared_context
'visit user page'
do
shared_context
'visit user page'
do
before
do
before
do
visit
user
.
username
visit
user
.
username
page
.
find
(
'.js-activity-tab a'
).
click
wait_for_requests
wait_for_requests
end
end
end
end
...
@@ -130,12 +133,12 @@ describe 'Contributions Calendar', :js do
...
@@ -130,12 +133,12 @@ describe 'Contributions Calendar', :js do
include_context
'visit user page'
include_context
'visit user page'
it
'displays calendar activity square color for 1 contribution'
do
it
'displays calendar activity square color for 1 contribution'
do
expect
(
page
).
to
have_selector
(
get_cell_color_selector
(
contribution_count
),
count:
1
)
expect
(
find
(
'.tab-pane#activity'
)
).
to
have_selector
(
get_cell_color_selector
(
contribution_count
),
count:
1
)
end
end
it
'displays calendar activity square on the correct date'
do
it
'displays calendar activity square on the correct date'
do
today
=
Date
.
today
.
strftime
(
date_format
)
today
=
Date
.
today
.
strftime
(
date_format
)
expect
(
page
).
to
have_selector
(
get_cell_date_selector
(
contribution_count
,
today
),
count:
1
)
expect
(
find
(
'.tab-pane#activity'
)
).
to
have_selector
(
get_cell_date_selector
(
contribution_count
,
today
),
count:
1
)
end
end
end
end
...
@@ -150,7 +153,7 @@ describe 'Contributions Calendar', :js do
...
@@ -150,7 +153,7 @@ describe 'Contributions Calendar', :js do
include_context
'visit user page'
include_context
'visit user page'
it
'displays calendar activity log'
do
it
'displays calendar activity log'
do
expect
(
find
(
'.content_list .event-note'
)).
to
have_content
issue_title
expect
(
find
(
'.
tab-pane#activity .
content_list .event-note'
)).
to
have_content
issue_title
end
end
end
end
end
end
...
@@ -182,17 +185,17 @@ describe 'Contributions Calendar', :js do
...
@@ -182,17 +185,17 @@ describe 'Contributions Calendar', :js do
include_context
'visit user page'
include_context
'visit user page'
it
'displays calendar activity squares for both days'
do
it
'displays calendar activity squares for both days'
do
expect
(
page
).
to
have_selector
(
get_cell_color_selector
(
1
),
count:
2
)
expect
(
find
(
'.tab-pane#activity'
)
).
to
have_selector
(
get_cell_color_selector
(
1
),
count:
2
)
end
end
it
'displays calendar activity square for yesterday'
do
it
'displays calendar activity square for yesterday'
do
yesterday
=
Date
.
yesterday
.
strftime
(
date_format
)
yesterday
=
Date
.
yesterday
.
strftime
(
date_format
)
expect
(
page
).
to
have_selector
(
get_cell_date_selector
(
1
,
yesterday
),
count:
1
)
expect
(
find
(
'.tab-pane#activity'
)
).
to
have_selector
(
get_cell_date_selector
(
1
,
yesterday
),
count:
1
)
end
end
it
'displays calendar activity square for today'
do
it
'displays calendar activity square for today'
do
today
=
Date
.
today
.
strftime
(
date_format
)
today
=
Date
.
today
.
strftime
(
date_format
)
expect
(
page
).
to
have_selector
(
get_cell_date_selector
(
1
,
today
),
count:
1
)
expect
(
find
(
'.tab-pane#activity'
)
).
to
have_selector
(
get_cell_date_selector
(
1
,
today
),
count:
1
)
end
end
end
end
end
end
...
...
spec/features/dashboard/datetime_on_tooltips_spec.rb
View file @
337b2c80
...
@@ -14,7 +14,7 @@ describe 'Tooltips on .timeago dates', :js do
...
@@ -14,7 +14,7 @@ describe 'Tooltips on .timeago dates', :js do
updated_at:
created_date
,
created_at:
created_date
)
updated_at:
created_date
,
created_at:
created_date
)
sign_in
user
sign_in
user
visit
user_path
(
user
)
visit
user_
activity_
path
(
user
)
wait_for_requests
()
wait_for_requests
()
page
.
find
(
'.js-timeago'
).
hover
page
.
find
(
'.js-timeago'
).
hover
...
...
spec/features/users/overview_spec.rb
0 → 100644
View file @
337b2c80
require
'spec_helper'
describe
'Overview tab on a user profile'
,
:js
do
let
(
:user
)
{
create
(
:user
)
}
let
(
:contributed_project
)
{
create
(
:project
,
:public
,
:repository
)
}
def
push_code_contribution
event
=
create
(
:push_event
,
project:
contributed_project
,
author:
user
)
create
(
:push_event_payload
,
event:
event
,
commit_from:
'11f9ac0a48b62cef25eedede4c1819964f08d5ce'
,
commit_to:
'1cf19a015df3523caf0a1f9d40c98a267d6a2fc2'
,
commit_count:
3
,
ref:
'master'
)
end
before
do
sign_in
user
end
describe
'activities section'
do
shared_context
'visit overview tab'
do
before
do
visit
user
.
username
page
.
find
(
'.js-overview-tab a'
).
click
wait_for_requests
end
end
describe
'user has no activities'
do
include_context
'visit overview tab'
it
'does not show any entries in the list of activities'
do
page
.
within
(
'.activities-block'
)
do
expect
(
page
).
not_to
have_selector
(
'.event-item'
)
end
end
it
'does not show a link to the activity list'
do
expect
(
find
(
'#js-overview .activities-block'
)).
to
have_selector
(
'.js-view-all'
,
visible:
false
)
end
end
describe
'user has 3 activities'
do
before
do
3
.
times
{
push_code_contribution
}
end
include_context
'visit overview tab'
it
'display 3 entries in the list of activities'
do
expect
(
find
(
'#js-overview'
)).
to
have_selector
(
'.event-item'
,
count:
3
)
end
end
describe
'user has 10 activities'
do
before
do
10
.
times
{
push_code_contribution
}
end
include_context
'visit overview tab'
it
'displays 5 entries in the list of activities'
do
expect
(
find
(
'#js-overview'
)).
to
have_selector
(
'.event-item'
,
count:
5
)
end
it
'shows a link to the activity list'
do
expect
(
find
(
'#js-overview .activities-block'
)).
to
have_selector
(
'.js-view-all'
,
visible:
true
)
end
it
'links to the activity tab'
do
page
.
within
(
'.activities-block'
)
do
find
(
'.js-view-all'
).
click
wait_for_requests
expect
(
URI
.
parse
(
current_url
).
path
).
to
eq
(
"/users/
#{
user
.
username
}
/activity"
)
end
end
end
end
describe
'projects section'
do
shared_context
'visit overview tab'
do
before
do
visit
user
.
username
page
.
find
(
'.js-overview-tab a'
).
click
wait_for_requests
end
end
describe
'user has no personal projects'
do
include_context
'visit overview tab'
it
'it shows an empty project list with an info message'
do
page
.
within
(
'.projects-block'
)
do
expect
(
page
).
to
have_content
(
'No projects found'
)
expect
(
page
).
not_to
have_selector
(
'.project-row'
)
end
end
it
'does not show a link to the project list'
do
expect
(
find
(
'#js-overview .projects-block'
)).
to
have_selector
(
'.js-view-all'
,
visible:
false
)
end
end
describe
'user has a personal project'
do
let
(
:private_project
)
{
create
(
:project
,
:private
,
namespace:
user
.
namespace
,
creator:
user
)
{
|
p
|
p
.
add_maintainer
(
user
)
}
}
let!
(
:private_event
)
{
create
(
:event
,
project:
private_project
,
author:
user
)
}
include_context
'visit overview tab'
it
'it shows one entry in the list of projects'
do
page
.
within
(
'.projects-block'
)
do
expect
(
page
).
to
have_selector
(
'.project-row'
,
count:
1
)
end
end
it
'shows a link to the project list'
do
expect
(
find
(
'#js-overview .projects-block'
)).
to
have_selector
(
'.js-view-all'
,
visible:
true
)
end
end
end
end
spec/features/users/show_spec.rb
View file @
337b2c80
...
@@ -8,6 +8,7 @@ describe 'User page' do
...
@@ -8,6 +8,7 @@ describe 'User page' do
visit
(
user_path
(
user
))
visit
(
user_path
(
user
))
page
.
within
'.nav-links'
do
page
.
within
'.nav-links'
do
expect
(
page
).
to
have_link
(
'Overview'
)
expect
(
page
).
to
have_link
(
'Activity'
)
expect
(
page
).
to
have_link
(
'Activity'
)
expect
(
page
).
to
have_link
(
'Groups'
)
expect
(
page
).
to
have_link
(
'Groups'
)
expect
(
page
).
to
have_link
(
'Contributed projects'
)
expect
(
page
).
to
have_link
(
'Contributed projects'
)
...
@@ -44,6 +45,7 @@ describe 'User page' do
...
@@ -44,6 +45,7 @@ describe 'User page' do
visit
(
user_path
(
user
))
visit
(
user_path
(
user
))
page
.
within
'.nav-links'
do
page
.
within
'.nav-links'
do
expect
(
page
).
to
have_link
(
'Overview'
)
expect
(
page
).
to
have_link
(
'Activity'
)
expect
(
page
).
to
have_link
(
'Activity'
)
expect
(
page
).
to
have_link
(
'Groups'
)
expect
(
page
).
to
have_link
(
'Groups'
)
expect
(
page
).
to
have_link
(
'Contributed projects'
)
expect
(
page
).
to
have_link
(
'Contributed projects'
)
...
...
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