debian-mirror-gitlab/app/assets/javascripts/pages/users/user_tabs.js

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

290 lines
8 KiB
JavaScript
Raw Normal View History

2020-03-13 15:44:24 +05:30
import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils';
2021-03-11 19:13:27 +05:30
import $ from 'jquery';
2018-03-27 19:54:05 +05:30
import Activities from '~/activities';
2019-02-15 15:39:39 +05:30
import AjaxCache from '~/lib/utils/ajax_cache';
2021-03-11 19:13:27 +05:30
import axios from '~/lib/utils/axios_utils';
import { localTimeAgo } from '~/lib/utils/datetime_utility';
2019-02-15 15:39:39 +05:30
import { __ } from '~/locale';
2017-09-10 17:25:29 +05:30
import ActivityCalendar from './activity_calendar';
2018-12-05 23:21:45 +05:30
import UserOverviewBlock from './user_overview_block';
2017-09-10 17:25:29 +05:30
/**
* UserTabs
*
* Handles persisting and restoring the current tab selection and lazily-loading
* content on the Users#show page.
*
* ### Example Markup
*
* <ul class="nav-links">
* <li class="activity-tab active">
2019-09-30 21:07:59 +05:30
* <a data-action="activity" data-target="#activity" data-toggle="tab" href="/username">
2017-09-10 17:25:29 +05:30
* Activity
* </a>
* </li>
* <li class="groups-tab">
2019-09-30 21:07:59 +05:30
* <a data-action="groups" data-target="#groups" data-toggle="tab" href="/users/username/groups">
2017-09-10 17:25:29 +05:30
* Groups
* </a>
* </li>
* <li class="contributed-tab">
* ...
* </li>
* <li class="projects-tab">
* ...
* </li>
* <li class="snippets-tab">
* ...
* </li>
* </ul>
*
* <div class="tab-content">
* <div class="tab-pane" id="activity">
* Activity Content
* </div>
* <div class="tab-pane" id="groups">
* Groups Content
* </div>
* <div class="tab-pane" id="contributed">
* Contributed projects content
* </div>
* <div class="tab-pane" id="projects">
* Projects content
* </div>
* <div class="tab-pane" id="snippets">
* Snippets content
* </div>
* </div>
*
2020-03-13 15:44:24 +05:30
* <div class="loading">
* Loading Animation
2017-09-10 17:25:29 +05:30
* </div>
*/
2019-02-15 15:39:39 +05:30
const CALENDAR_TEMPLATE = `
2021-01-29 00:20:46 +05:30
<div class="calendar">
2019-02-15 15:39:39 +05:30
<div class="js-contrib-calendar"></div>
2021-01-29 00:20:46 +05:30
<div class="calendar-hint"></div>
2019-02-15 15:39:39 +05:30
</div>
`;
2018-12-05 23:21:45 +05:30
const CALENDAR_PERIOD_6_MONTHS = 6;
const CALENDAR_PERIOD_12_MONTHS = 12;
2019-02-15 15:39:39 +05:30
/* computation based on
* width = (group + 1) * this.daySizeWithSpace + this.getExtraWidthPadding(group);
* (see activity_calendar.js)
*/
const OVERVIEW_CALENDAR_BREAKPOINT = 918;
2017-09-10 17:25:29 +05:30
export default class UserTabs {
constructor({ defaultAction, action, parentEl }) {
this.loaded = {};
2018-12-05 23:21:45 +05:30
this.defaultAction = defaultAction || 'overview';
2017-09-10 17:25:29 +05:30
this.action = action || this.defaultAction;
this.$parentEl = $(parentEl) || $(document);
this.windowLocation = window.location;
2018-11-08 19:23:39 +05:30
this.$parentEl.find('.nav-links a').each((i, navLink) => {
this.loaded[$(navLink).attr('data-action')] = false;
});
2017-09-10 17:25:29 +05:30
this.actions = Object.keys(this.loaded);
this.bindEvents();
2019-07-07 11:18:12 +05:30
// TODO: refactor to make this configurable via constructor params with a default value of 'show'
2017-09-10 17:25:29 +05:30
if (this.action === 'show') {
this.action = this.defaultAction;
}
this.activateTab(this.action);
}
bindEvents() {
this.$parentEl
.off('shown.bs.tab', '.nav-links a[data-toggle="tab"]')
2021-03-08 18:12:59 +05:30
.on('shown.bs.tab', '.nav-links a[data-toggle="tab"]', (event) => this.tabShown(event))
.on('click', '.gl-pagination a', (event) => this.changeProjectsPage(event));
2019-02-15 15:39:39 +05:30
window.addEventListener('resize', () => this.onResize());
}
onResize() {
this.loadActivityCalendar();
2017-09-10 17:25:29 +05:30
}
changeProjectsPage(e) {
e.preventDefault();
$('.tab-pane.active').empty();
const endpoint = $(e.target).attr('href');
this.loadTab(this.getCurrentAction(), endpoint);
}
tabShown(event) {
const $target = $(event.target);
const action = $target.data('action');
const source = $target.attr('href');
const endpoint = $target.data('endpoint');
this.setTab(action, endpoint);
return this.setCurrentAction(source);
}
activateTab(action) {
2018-11-08 19:23:39 +05:30
return this.$parentEl.find(`.nav-links .js-${action}-tab a`).tab('show');
2017-09-10 17:25:29 +05:30
}
setTab(action, endpoint) {
if (this.loaded[action]) {
return;
}
if (action === 'activity') {
this.loadActivities();
2018-12-05 23:21:45 +05:30
} else if (action === 'overview') {
this.loadOverviewTab();
2017-09-10 17:25:29 +05:30
}
2021-03-11 19:13:27 +05:30
const loadableActions = [
'groups',
'contributed',
'projects',
'starred',
'snippets',
'followers',
'following',
];
2017-09-10 17:25:29 +05:30
if (loadableActions.indexOf(action) > -1) {
this.loadTab(action, endpoint);
}
}
loadTab(action, endpoint) {
2018-03-17 18:26:18 +05:30
this.toggleLoading(true);
2019-02-15 15:39:39 +05:30
const params = action === 'projects' ? { skip_namespace: true } : {};
2018-11-08 19:23:39 +05:30
return axios
2019-02-15 15:39:39 +05:30
.get(endpoint, { params })
2018-03-17 18:26:18 +05:30
.then(({ data }) => {
2017-09-10 17:25:29 +05:30
const tabSelector = `div#${action}`;
this.$parentEl.find(tabSelector).html(data.html);
this.loaded[action] = true;
2021-09-30 23:02:18 +05:30
localTimeAgo(document.querySelectorAll(`${tabSelector} .js-timeago`));
2018-03-17 18:26:18 +05:30
this.toggleLoading(false);
})
.catch(() => {
this.toggleLoading(false);
});
2017-09-10 17:25:29 +05:30
}
loadActivities() {
if (this.loaded.activity) {
return;
}
2018-12-05 23:21:45 +05:30
// eslint-disable-next-line no-new
2018-12-13 13:39:08 +05:30
new Activities('#activity');
2018-12-05 23:21:45 +05:30
this.loaded.activity = true;
}
loadOverviewTab() {
if (this.loaded.overview) {
return;
}
2019-02-15 15:39:39 +05:30
this.loadActivityCalendar();
2018-12-05 23:21:45 +05:30
UserTabs.renderMostRecentBlocks('#js-overview .activities-block', {
2019-02-15 15:39:39 +05:30
requestParams: { limit: 10 },
2018-12-05 23:21:45 +05:30
});
UserTabs.renderMostRecentBlocks('#js-overview .projects-block', {
2019-02-15 15:39:39 +05:30
requestParams: { limit: 10, skip_pagination: true, skip_namespace: true, compact_mode: true },
2018-12-05 23:21:45 +05:30
});
this.loaded.overview = true;
}
static renderMostRecentBlocks(container, options) {
// eslint-disable-next-line no-new
new UserOverviewBlock({
container,
url: $(`${container} .overview-content-list`).data('href'),
...options,
2021-09-30 23:02:18 +05:30
postRenderCallback: () => localTimeAgo(document.querySelectorAll(`${container} .js-timeago`)),
2018-12-05 23:21:45 +05:30
});
}
2019-02-15 15:39:39 +05:30
loadActivityCalendar() {
2018-12-05 23:21:45 +05:30
const $calendarWrap = this.$parentEl.find('.tab-pane.active .user-calendar');
2020-03-13 15:44:24 +05:30
if (!$calendarWrap.length || bp.getBreakpointSize() === 'xs') return;
2019-02-15 15:39:39 +05:30
2017-09-10 17:25:29 +05:30
const calendarPath = $calendarWrap.data('calendarPath');
2019-02-15 15:39:39 +05:30
AjaxCache.retrieve(calendarPath)
2021-03-08 18:12:59 +05:30
.then((data) => UserTabs.renderActivityCalendar(data, $calendarWrap))
2021-01-29 00:20:46 +05:30
.catch(() => {
const cWrap = $calendarWrap[0];
2021-06-08 01:23:25 +05:30
cWrap.querySelector('.gl-spinner').classList.add('invisible');
2021-01-29 00:20:46 +05:30
cWrap.querySelector('.user-calendar-error').classList.remove('invisible');
2021-03-08 18:12:59 +05:30
cWrap
.querySelector('.user-calendar-error .js-retry-load')
.addEventListener('click', (e) => {
e.preventDefault();
cWrap.querySelector('.user-calendar-error').classList.add('invisible');
2021-06-08 01:23:25 +05:30
cWrap.querySelector('.gl-spinner').classList.remove('invisible');
2021-03-08 18:12:59 +05:30
this.loadActivityCalendar();
});
2021-01-29 00:20:46 +05:30
});
2019-02-15 15:39:39 +05:30
}
static renderActivityCalendar(data, $calendarWrap) {
const monthsAgo = UserTabs.getVisibleCalendarPeriod($calendarWrap);
2017-09-10 17:25:29 +05:30
const calendarActivitiesPath = $calendarWrap.data('calendarActivitiesPath');
const utcOffset = $calendarWrap.data('utcOffset');
2019-07-07 11:18:12 +05:30
const calendarHint = __('Issues, merge requests, pushes, and comments.');
2018-12-23 12:14:25 +05:30
2019-02-15 15:39:39 +05:30
$calendarWrap.html(CALENDAR_TEMPLATE);
$calendarWrap.find('.calendar-hint').text(calendarHint);
// eslint-disable-next-line no-new
2023-05-27 22:25:52 +05:30
new ActivityCalendar({
container: '.tab-pane.active .js-contrib-calendar',
activitiesContainer: '.tab-pane.active .user-calendar-activities',
timestamps: data,
2019-02-15 15:39:39 +05:30
calendarActivitiesPath,
utcOffset,
2023-05-27 22:25:52 +05:30
firstDayOfWeek: gon.first_day_of_week,
2019-02-15 15:39:39 +05:30
monthsAgo,
2023-05-27 22:25:52 +05:30
});
2017-09-10 17:25:29 +05:30
}
toggleLoading(status) {
2020-03-13 15:44:24 +05:30
return this.$parentEl.find('.loading').toggleClass('hide', !status);
2017-09-10 17:25:29 +05:30
}
setCurrentAction(source) {
let newState = source;
newState = newState.replace(/\/+$/, '');
newState += this.windowLocation.search + this.windowLocation.hash;
2018-11-08 19:23:39 +05:30
window.history.replaceState(
{
url: newState,
},
document.title,
newState,
);
2017-09-10 17:25:29 +05:30
return newState;
}
getCurrentAction() {
2018-11-08 19:23:39 +05:30
return this.$parentEl.find('.nav-links a.active').data('action');
2017-09-10 17:25:29 +05:30
}
2019-02-15 15:39:39 +05:30
static getVisibleCalendarPeriod($calendarWrap) {
const width = $calendarWrap.width();
return width < OVERVIEW_CALENDAR_BREAKPOINT
? CALENDAR_PERIOD_6_MONTHS
: CALENDAR_PERIOD_12_MONTHS;
}
2017-09-10 17:25:29 +05:30
}