Commit 41a3fa57 authored by Phil Hughes's avatar Phil Hughes

Merge branch '52712-further-ui-improvements-to-profile-overview-tab' into 'master'

Resolve "Further UI improvements to Profile "Overview" tab"

Closes #52712

See merge request gitlab-org/gitlab-ce!22977
parents 91221cd7 6701c46a
...@@ -10,6 +10,7 @@ export default class UserOverviewBlock { ...@@ -10,6 +10,7 @@ export default class UserOverviewBlock {
limit: DEFAULT_LIMIT, limit: DEFAULT_LIMIT,
...options.requestParams, ...options.requestParams,
}; };
this.postRenderCallback = options.postRenderCallback;
this.loadData(); this.loadData();
} }
...@@ -43,5 +44,9 @@ export default class UserOverviewBlock { ...@@ -43,5 +44,9 @@ export default class UserOverviewBlock {
} }
loadingEl.classList.add('hide'); loadingEl.classList.add('hide');
if (this.postRenderCallback) {
this.postRenderCallback.call(this);
}
} }
} }
...@@ -2,7 +2,8 @@ import $ from 'jquery'; ...@@ -2,7 +2,8 @@ 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 { __, sprintf } from '~/locale'; import AjaxCache from '~/lib/utils/ajax_cache';
import { __ } 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'; import UserOverviewBlock from './user_overview_block';
...@@ -62,23 +63,20 @@ import UserOverviewBlock from './user_overview_block'; ...@@ -62,23 +63,20 @@ import UserOverviewBlock from './user_overview_block';
* </div> * </div>
*/ */
const CALENDAR_TEMPLATES = { const CALENDAR_TEMPLATE = `
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 bottom-right"></div>
<div class="calendar-hint bottom-right"></div> </div>
</div> `;
`,
overview: `
<div class="clearfix calendar">
<div class="calendar-hint"></div>
<div class="js-contrib-calendar prepend-top-20"></div>
</div>
`,
};
const CALENDAR_PERIOD_6_MONTHS = 6; const CALENDAR_PERIOD_6_MONTHS = 6;
const CALENDAR_PERIOD_12_MONTHS = 12; const CALENDAR_PERIOD_12_MONTHS = 12;
/* computation based on
* width = (group + 1) * this.daySizeWithSpace + this.getExtraWidthPadding(group);
* (see activity_calendar.js)
*/
const OVERVIEW_CALENDAR_BREAKPOINT = 918;
export default class UserTabs { export default class UserTabs {
constructor({ defaultAction, action, parentEl }) { constructor({ defaultAction, action, parentEl }) {
...@@ -105,6 +103,12 @@ export default class UserTabs { ...@@ -105,6 +103,12 @@ export default class UserTabs {
.off('shown.bs.tab', '.nav-links a[data-toggle="tab"]') .off('shown.bs.tab', '.nav-links a[data-toggle="tab"]')
.on('shown.bs.tab', '.nav-links a[data-toggle="tab"]', event => this.tabShown(event)) .on('shown.bs.tab', '.nav-links a[data-toggle="tab"]', event => this.tabShown(event))
.on('click', '.gl-pagination a', event => this.changeProjectsPage(event)); .on('click', '.gl-pagination a', event => this.changeProjectsPage(event));
window.addEventListener('resize', () => this.onResize());
}
onResize() {
this.loadActivityCalendar();
} }
changeProjectsPage(e) { changeProjectsPage(e) {
...@@ -167,8 +171,6 @@ export default class UserTabs { ...@@ -167,8 +171,6 @@ export default class UserTabs {
return; return;
} }
this.loadActivityCalendar('activity');
// eslint-disable-next-line no-new // eslint-disable-next-line no-new
new Activities('#activity'); new Activities('#activity');
...@@ -180,10 +182,10 @@ export default class UserTabs { ...@@ -180,10 +182,10 @@ export default class UserTabs {
return; return;
} }
this.loadActivityCalendar('overview'); this.loadActivityCalendar();
UserTabs.renderMostRecentBlocks('#js-overview .activities-block', { UserTabs.renderMostRecentBlocks('#js-overview .activities-block', {
requestParams: { limit: 5 }, requestParams: { limit: 10 },
}); });
UserTabs.renderMostRecentBlocks('#js-overview .projects-block', { UserTabs.renderMostRecentBlocks('#js-overview .projects-block', {
requestParams: { limit: 10, skip_pagination: true }, requestParams: { limit: 10, skip_pagination: true },
...@@ -198,52 +200,39 @@ export default class UserTabs { ...@@ -198,52 +200,39 @@ export default class UserTabs {
container, container,
url: $(`${container} .overview-content-list`).data('href'), url: $(`${container} .overview-content-list`).data('href'),
...options, ...options,
postRenderCallback: () => localTimeAgo($('.js-timeago', container)),
}); });
} }
loadActivityCalendar(action) { loadActivityCalendar() {
const monthsAgo = action === 'overview' ? CALENDAR_PERIOD_6_MONTHS : CALENDAR_PERIOD_12_MONTHS;
const $calendarWrap = this.$parentEl.find('.tab-pane.active .user-calendar'); const $calendarWrap = this.$parentEl.find('.tab-pane.active .user-calendar');
const calendarPath = $calendarWrap.data('calendarPath'); const calendarPath = $calendarWrap.data('calendarPath');
AjaxCache.retrieve(calendarPath)
.then(data => UserTabs.renderActivityCalendar(data, $calendarWrap))
.catch(() => flash(__('There was an error loading users activity calendar.')));
}
static renderActivityCalendar(data, $calendarWrap) {
const monthsAgo = UserTabs.getVisibleCalendarPeriod($calendarWrap);
const calendarActivitiesPath = $calendarWrap.data('calendarActivitiesPath'); const calendarActivitiesPath = $calendarWrap.data('calendarActivitiesPath');
const utcOffset = $calendarWrap.data('utcOffset'); const utcOffset = $calendarWrap.data('utcOffset');
let utcFormatted = 'UTC'; const calendarHint = __('Issues, merge requests, pushes and comments.');
if (utcOffset !== 0) {
utcFormatted = `UTC${utcOffset > 0 ? '+' : ''}${utcOffset / 3600}`;
}
axios $calendarWrap.html(CALENDAR_TEMPLATE);
.get(calendarPath)
.then(({ data }) => { $calendarWrap.find('.calendar-hint').text(calendarHint);
$calendarWrap.html(CALENDAR_TEMPLATES[action]);
// eslint-disable-next-line no-new
let calendarHint = ''; new ActivityCalendar(
'.tab-pane.active .js-contrib-calendar',
if (action === 'activity') { '.tab-pane.active .user-calendar-activities',
calendarHint = sprintf( data,
__( calendarActivitiesPath,
'Summary of issues, merge requests, push events, and comments (Timezone: %{utcFormatted})', utcOffset,
), 0,
{ utcFormatted }, monthsAgo,
); );
} else if (action === 'overview') {
calendarHint = __('Issues, merge requests, pushes and comments.');
}
$calendarWrap.find('.calendar-hint').text(calendarHint);
// eslint-disable-next-line no-new
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.')));
} }
toggleLoading(status) { toggleLoading(status) {
...@@ -267,4 +256,11 @@ export default class UserTabs { ...@@ -267,4 +256,11 @@ export default class UserTabs {
getCurrentAction() { getCurrentAction() {
return this.$parentEl.find('.nav-links a.active').data('action'); return this.$parentEl.find('.nav-links a.active').data('action');
} }
static getVisibleCalendarPeriod($calendarWrap) {
const width = $calendarWrap.width();
return width < OVERVIEW_CALENDAR_BREAKPOINT
? CALENDAR_PERIOD_6_MONTHS
: CALENDAR_PERIOD_12_MONTHS;
}
} }
.row
.col-12
.calendar-block.prepend-top-default.append-bottom-default
.user-calendar.d-none.d-sm-block{ data: { calendar_path: user_calendar_path(@user, :json), calendar_activities_path: user_calendar_activities_path, utc_offset: Time.zone.utc_offset } }
%h4.center.light
= spinner nil, true
.user-calendar-activities.d-none.d-sm-block
.row .row
.col-md-12.col-lg-6 .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) - if can?(current_user, :read_cross_project)
.activities-block .activities-block
.border-bottom.prepend-top-16 .prepend-top-16
%h5 .d-flex.align-items-center.border-bottom
= s_('UserProfile|Recent contributions') %h4.flex-grow
= s_('UserProfile|Activity')
= link_to s_('UserProfile|View all'), user_activity_path, class: "hide js-view-all"
.overview-content-list{ data: { href: user_path } } .overview-content-list{ data: { href: user_path } }
.center.light.loading .center.light.loading
%i.fa.fa-spinner.fa-spin = spinner nil, true
.prepend-top-10
= link_to s_('UserProfile|View all'), user_activity_path, class: "hide js-view-all"
.col-md-12.col-lg-6 .col-md-12.col-lg-6
.projects-block .projects-block
.border-bottom.prepend-top-16 .prepend-top-16
%h4 .d-flex.align-items-center.border-bottom
= s_('UserProfile|Personal projects') %h4.flex-grow
= s_('UserProfile|Personal projects')
= link_to s_('UserProfile|View all'), user_projects_path, class: "hide js-view-all"
.overview-content-list{ data: { href: user_projects_path } } .overview-content-list{ data: { href: user_projects_path } }
.center.light.loading .center.light.loading
%i.fa.fa-spinner.fa-spin = spinner nil, true
.prepend-top-10
= link_to s_('UserProfile|View all'), user_projects_path, class: "hide js-view-all"
...@@ -124,12 +124,6 @@ ...@@ -124,12 +124,6 @@
- if profile_tab?(:activity) - if profile_tab?(:activity)
#activity.tab-pane #activity.tab-pane
.row-content-block.calendar-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 } }
%h4.center.light
%i.fa.fa-spinner.fa-spin
.user-calendar-activities
- if can?(current_user, :read_cross_project) - if can?(current_user, :read_cross_project)
%h4.prepend-top-20 %h4.prepend-top-20
= s_('UserProfile|Most Recent Activity') = s_('UserProfile|Most Recent Activity')
......
---
title: UI improvements to user's profile
merge_request: 22977
author:
type: other
...@@ -5961,9 +5961,6 @@ msgstr "" ...@@ -5961,9 +5961,6 @@ msgstr ""
msgid "Subscribed" msgid "Subscribed"
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 ""
...@@ -6837,9 +6834,6 @@ msgstr "" ...@@ -6837,9 +6834,6 @@ msgstr ""
msgid "UserProfile|Personal projects" msgid "UserProfile|Personal projects"
msgstr "" msgstr ""
msgid "UserProfile|Recent contributions"
msgstr ""
msgid "UserProfile|Report abuse" msgid "UserProfile|Report abuse"
msgstr "" msgstr ""
......
...@@ -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('.tab-pane#activity .user-calendar-activities', visible: visible).text find('#js-overview .user-calendar-activities', visible: visible).text
end end
before do before do
...@@ -74,16 +74,16 @@ describe 'Contributions Calendar', :js do ...@@ -74,16 +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 page.find('.js-overview-tab a').click
wait_for_requests wait_for_requests
end end
it 'displays calendar' do it 'displays calendar' do
expect(find('.tab-pane#activity')).to have_css('.js-contrib-calendar') expect(find('#js-overview')).to have_css('.js-contrib-calendar')
end end
describe 'select calendar day' do describe 'select calendar day' do
let(:cells) { page.all('.tab-pane#activity .user-contrib-cell') } let(:cells) { page.all('#js-overview .user-contrib-cell') }
before do before do
cells[0].click cells[0].click
...@@ -109,7 +109,7 @@ describe 'Contributions Calendar', :js do ...@@ -109,7 +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 page.find('.js-overview-tab a').click
wait_for_requests wait_for_requests
end end
...@@ -124,7 +124,7 @@ describe 'Contributions Calendar', :js do ...@@ -124,7 +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 page.find('.js-overview-tab a').click
wait_for_requests wait_for_requests
end end
end end
...@@ -133,12 +133,12 @@ describe 'Contributions Calendar', :js do ...@@ -133,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(find('.tab-pane#activity')).to have_selector(get_cell_color_selector(contribution_count), count: 1) expect(find('#js-overview')).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(find('.tab-pane#activity')).to have_selector(get_cell_date_selector(contribution_count, today), count: 1) expect(find('#js-overview')).to have_selector(get_cell_date_selector(contribution_count, today), count: 1)
end end
end end
...@@ -153,7 +153,7 @@ describe 'Contributions Calendar', :js do ...@@ -153,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('.tab-pane#activity .content_list .event-target-title')).to have_content issue_title expect(find('#js-overview .overview-content-list .event-target-title')).to have_content issue_title
end end
end end
end end
...@@ -185,17 +185,17 @@ describe 'Contributions Calendar', :js do ...@@ -185,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(find('.tab-pane#activity')).to have_selector(get_cell_color_selector(1), count: 2) expect(find('#js-overview')).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(find('.tab-pane#activity')).to have_selector(get_cell_date_selector(1, yesterday), count: 1) expect(find('#js-overview')).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(find('.tab-pane#activity')).to have_selector(get_cell_date_selector(1, today), count: 1) expect(find('#js-overview')).to have_selector(get_cell_date_selector(1, today), count: 1)
end end
end end
end end
......
...@@ -54,15 +54,15 @@ describe 'Overview tab on a user profile', :js do ...@@ -54,15 +54,15 @@ describe 'Overview tab on a user profile', :js do
end end
end end
describe 'user has 10 activities' do describe 'user has 11 activities' do
before do before do
10.times { push_code_contribution } 11.times { push_code_contribution }
end end
include_context 'visit overview tab' include_context 'visit overview tab'
it 'displays 5 entries in the list of activities' do it 'displays 10 entries in the list of activities' do
expect(find('#js-overview')).to have_selector('.event-item', count: 5) expect(find('#js-overview')).to have_selector('.event-item', count: 10)
end end
it 'shows a link to the activity list' do it 'shows a link to the activity list' do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment