提交 7e17f9bc 编写于 作者: T Tim Zallmann

Merge branch '35224-transform-user-profile-javascript-into-async-bundle' into 'master'

Resolve "Transform user profile javascript into async bundle"

Closes #35224

See merge request !12929
...@@ -538,6 +538,13 @@ import GpgBadges from './gpg_badges'; ...@@ -538,6 +538,13 @@ import GpgBadges from './gpg_badges';
case 'protected_branches': case 'protected_branches':
shortcut_handler = new ShortcutsNavigation(); shortcut_handler = new ShortcutsNavigation();
} }
break;
case 'users':
const action = path[1];
import(/* webpackChunkName: 'user_profile' */ './users')
.then(user => user.default(action))
.catch(() => {});
break;
} }
// If we haven't installed a custom shortcut handler, install the default one // If we haven't installed a custom shortcut handler, install the default one
if (!shortcut_handler) { if (!shortcut_handler) {
......
/* eslint-disable func-names, space-before-function-paren, no-var, wrap-iife, camelcase, vars-on-top, object-shorthand, comma-dangle, eqeqeq, no-mixed-operators, no-return-assign, newline-per-chained-call, prefer-arrow-callback, consistent-return, one-var, one-var-declaration-per-line, prefer-template, quotes, no-unused-vars, no-else-return, max-len, class-methods-use-this */
import d3 from 'd3'; import d3 from 'd3';
const LOADING_HTML = `
<div class="text-center">
<i class="fa fa-spinner fa-spin user-calendar-activities-loading"></i>
</div>
`;
function formatTooltipText({ date, count }) {
const dateObject = new Date(date);
const dateDayName = gl.utils.getDayName(dateObject);
const dateText = dateObject.format('mmm d, yyyy');
let contribText = 'No contributions';
if (count > 0) {
contribText = `${count} contribution${count > 1 ? 's' : ''}`;
}
return `${contribText}<br />${dateDayName} ${dateText}`;
}
const initColorKey = () => d3.scale.linear().range(['#acd5f2', '#254e77']).domain([0, 3]);
export default class ActivityCalendar { export default class ActivityCalendar {
constructor(timestamps, calendar_activities_path) { constructor(container, timestamps, calendarActivitiesPath) {
this.calendar_activities_path = calendar_activities_path; this.calendarActivitiesPath = calendarActivitiesPath;
this.clickDay = this.clickDay.bind(this); this.clickDay = this.clickDay.bind(this);
this.currentSelectedDate = ''; this.currentSelectedDate = '';
this.daySpace = 1; this.daySpace = 1;
...@@ -12,25 +30,26 @@ export default class ActivityCalendar { ...@@ -12,25 +30,26 @@ export default class ActivityCalendar {
this.daySizeWithSpace = this.daySize + (this.daySpace * 2); this.daySizeWithSpace = this.daySize + (this.daySpace * 2);
this.monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; this.monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
this.months = []; this.months = [];
// 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
this.timestampsTmp = []; this.timestampsTmp = [];
var group = 0; let group = 0;
var today = new Date(); const today = new Date();
today.setHours(0, 0, 0, 0, 0); today.setHours(0, 0, 0, 0, 0);
var oneYearAgo = new Date(today); const oneYearAgo = new Date(today);
oneYearAgo.setFullYear(today.getFullYear() - 1); oneYearAgo.setFullYear(today.getFullYear() - 1);
var days = gl.utils.getDayDifference(oneYearAgo, today); const days = gl.utils.getDayDifference(oneYearAgo, today);
for (var i = 0; i <= days; i += 1) { for (let i = 0; i <= days; i += 1) {
var date = new Date(oneYearAgo); const date = new Date(oneYearAgo);
date.setDate(date.getDate() + i); date.setDate(date.getDate() + i);
var day = date.getDay(); const day = date.getDay();
var count = timestamps[date.format('yyyy-mm-dd')]; const count = timestamps[date.format('yyyy-mm-dd')] || 0;
// Create a new group array if this is the first day of the week // Create a new group array if this is the first day of the week
// or if is first object // or if is first object
...@@ -39,129 +58,119 @@ export default class ActivityCalendar { ...@@ -39,129 +58,119 @@ export default class ActivityCalendar {
group += 1; group += 1;
} }
var innerArray = this.timestampsTmp[group - 1];
// Push to the inner array the values that will be used to render map // Push to the inner array the values that will be used to render map
innerArray.push({ const innerArray = this.timestampsTmp[group - 1];
count: count || 0, innerArray.push({ count, date, day });
date: date,
day: day
});
} }
// Init color functions // Init color functions
this.colorKey = this.initColorKey(); this.colorKey = initColorKey();
this.color = this.initColor(); this.color = this.initColor();
// Init the svg element // Init the svg element
this.renderSvg(group); this.svg = this.renderSvg(container, group);
this.renderDays(); this.renderDays();
this.renderMonths(); this.renderMonths();
this.renderDayTitles(); this.renderDayTitles();
this.renderKey(); this.renderKey();
this.initTooltips();
// Init tooltips
$(`${container} .js-tooltip`).tooltip({ html: true });
} }
// Add extra padding for the last month label if it is also the last column // Add extra padding for the last month label if it is also the last column
getExtraWidthPadding(group) { getExtraWidthPadding(group) {
var extraWidthPadding = 0; let extraWidthPadding = 0;
var lastColMonth = this.timestampsTmp[group - 1][0].date.getMonth(); const lastColMonth = this.timestampsTmp[group - 1][0].date.getMonth();
var secondLastColMonth = this.timestampsTmp[group - 2][0].date.getMonth(); const secondLastColMonth = this.timestampsTmp[group - 2][0].date.getMonth();
if (lastColMonth != secondLastColMonth) { if (lastColMonth !== secondLastColMonth) {
extraWidthPadding = 3; extraWidthPadding = 3;
} }
return extraWidthPadding; return extraWidthPadding;
} }
renderSvg(group) { renderSvg(container, group) {
var width = (group + 1) * this.daySizeWithSpace + this.getExtraWidthPadding(group); const width = ((group + 1) * this.daySizeWithSpace) + this.getExtraWidthPadding(group);
return this.svg = d3.select('.js-contrib-calendar').append('svg').attr('width', width).attr('height', 167).attr('class', 'contrib-calendar'); return d3.select(container)
.append('svg')
.attr('width', width)
.attr('height', 167)
.attr('class', 'contrib-calendar');
} }
renderDays() { renderDays() {
return this.svg.selectAll('g').data(this.timestampsTmp).enter().append('g').attr('transform', (function(_this) { this.svg.selectAll('g').data(this.timestampsTmp).enter().append('g')
return function(group, i) { .attr('transform', (group, i) => {
_.each(group, function(stamp, a) { _.each(group, (stamp, a) => {
var lastMonth, lastMonthX, month, x;
if (a === 0 && stamp.day === 0) { if (a === 0 && stamp.day === 0) {
month = stamp.date.getMonth(); const month = stamp.date.getMonth();
x = (_this.daySizeWithSpace * i + 1) + _this.daySizeWithSpace; const x = (this.daySizeWithSpace * i) + 1 + this.daySizeWithSpace;
lastMonth = _.last(_this.months); const lastMonth = _.last(this.months);
if (lastMonth != null) { if (
lastMonthX = lastMonth.x; lastMonth == null ||
} (month !== lastMonth.month && x - this.daySizeWithSpace !== lastMonth.x)
if (lastMonth == null) { ) {
return _this.months.push({ this.months.push({ month, x });
month: month,
x: x
});
} else if (month !== lastMonth.month && x - _this.daySizeWithSpace !== lastMonthX) {
return _this.months.push({
month: month,
x: x
});
} }
} }
}); });
return "translate(" + ((_this.daySizeWithSpace * i + 1) + _this.daySizeWithSpace) + ", 18)"; return `translate(${(this.daySizeWithSpace * i) + 1 + this.daySizeWithSpace}, 18)`;
}; })
})(this)).selectAll('rect').data(function(stamp) { .selectAll('rect')
return stamp; .data(stamp => stamp)
}).enter().append('rect').attr('x', '0').attr('y', (function(_this) { .enter()
return function(stamp, i) { .append('rect')
return _this.daySizeWithSpace * stamp.day; .attr('x', '0')
}; .attr('y', stamp => this.daySizeWithSpace * stamp.day)
})(this)).attr('width', this.daySize).attr('height', this.daySize).attr('title', (function(_this) { .attr('width', this.daySize)
return function(stamp) { .attr('height', this.daySize)
var contribText, date, dateText; .attr('fill', stamp => (
date = new Date(stamp.date); stamp.count !== 0 ? this.color(Math.min(stamp.count, 40)) : '#ededed'
contribText = 'No contributions'; ))
if (stamp.count > 0) { .attr('title', stamp => formatTooltipText(stamp))
contribText = stamp.count + " contribution" + (stamp.count > 1 ? 's' : ''); .attr('class', 'user-contrib-cell js-tooltip')
} .attr('data-container', 'body')
dateText = date.format('mmm d, yyyy'); .on('click', this.clickDay);
return contribText + "<br />" + (gl.utils.getDayName(date)) + " " + dateText;
};
})(this)).attr('class', 'user-contrib-cell js-tooltip').attr('fill', (function(_this) {
return function(stamp) {
if (stamp.count !== 0) {
return _this.color(Math.min(stamp.count, 40));
} else {
return '#ededed';
}
};
})(this)).attr('data-container', 'body').on('click', this.clickDay);
} }
renderDayTitles() { renderDayTitles() {
var days; const days = [
days = [
{ {
text: 'M', text: 'M',
y: 29 + (this.daySizeWithSpace * 1) y: 29 + (this.daySizeWithSpace * 1),
}, { }, {
text: 'W', text: 'W',
y: 29 + (this.daySizeWithSpace * 3) y: 29 + (this.daySizeWithSpace * 3),
}, { }, {
text: 'F', text: 'F',
y: 29 + (this.daySizeWithSpace * 5) y: 29 + (this.daySizeWithSpace * 5),
} },
]; ];
return this.svg.append('g').selectAll('text').data(days).enter().append('text').attr('text-anchor', 'middle').attr('x', 8).attr('y', function(day) { this.svg.append('g')
return day.y; .selectAll('text')
}).text(function(day) { .data(days)
return day.text; .enter()
}).attr('class', 'user-contrib-text'); .append('text')
.attr('text-anchor', 'middle')
.attr('x', 8)
.attr('y', day => day.y)
.text(day => day.text)
.attr('class', 'user-contrib-text');
} }
renderMonths() { renderMonths() {
return this.svg.append('g').attr('direction', 'ltr').selectAll('text').data(this.months).enter().append('text').attr('x', function(date) { this.svg.append('g')
return date.x; .attr('direction', 'ltr')
}).attr('y', 10).attr('class', 'user-contrib-text').text((function(_this) { .selectAll('text')
return function(date) { .data(this.months)
return _this.monthNames[date.month]; .enter()
}; .append('text')
})(this)); .attr('x', date => date.x)
.attr('y', 10)
.attr('class', 'user-contrib-text')
.text(date => this.monthNames[date.month]);
} }
renderKey() { renderKey() {
...@@ -169,7 +178,7 @@ export default class ActivityCalendar { ...@@ -169,7 +178,7 @@ export default class ActivityCalendar {
const keyColors = ['#ededed', this.colorKey(0), this.colorKey(1), this.colorKey(2), this.colorKey(3)]; const keyColors = ['#ededed', this.colorKey(0), this.colorKey(1), this.colorKey(2), this.colorKey(3)];
this.svg.append('g') this.svg.append('g')
.attr('transform', `translate(18, ${this.daySizeWithSpace * 8 + 16})`) .attr('transform', `translate(18, ${(this.daySizeWithSpace * 8) + 16})`)
.selectAll('rect') .selectAll('rect')
.data(keyColors) .data(keyColors)
.enter() .enter()
...@@ -185,43 +194,31 @@ export default class ActivityCalendar { ...@@ -185,43 +194,31 @@ export default class ActivityCalendar {
} }
initColor() { initColor() {
var colorRange; const colorRange = ['#ededed', this.colorKey(0), this.colorKey(1), this.colorKey(2), this.colorKey(3)];
colorRange = ['#ededed', this.colorKey(0), this.colorKey(1), this.colorKey(2), this.colorKey(3)];
return d3.scale.threshold().domain([0, 10, 20, 30]).range(colorRange); return d3.scale.threshold().domain([0, 10, 20, 30]).range(colorRange);
} }
initColorKey() {
return d3.scale.linear().range(['#acd5f2', '#254e77']).domain([0, 3]);
}
clickDay(stamp) { clickDay(stamp) {
var formatted_date;
if (this.currentSelectedDate !== stamp.date) { if (this.currentSelectedDate !== stamp.date) {
this.currentSelectedDate = stamp.date; this.currentSelectedDate = stamp.date;
formatted_date = this.currentSelectedDate.getFullYear() + "-" + (this.currentSelectedDate.getMonth() + 1) + "-" + this.currentSelectedDate.getDate();
return $.ajax({ const date = [
url: this.calendar_activities_path, this.currentSelectedDate.getFullYear(),
data: { this.currentSelectedDate.getMonth() + 1,
date: formatted_date this.currentSelectedDate.getDate(),
}, ].join('-');
$.ajax({
url: this.calendarActivitiesPath,
data: { date },
cache: false, cache: false,
dataType: 'html', dataType: 'html',
beforeSend: function() { beforeSend: () => $('.user-calendar-activities').html(LOADING_HTML),
return $('.user-calendar-activities').html('<div class="text-center"><i class="fa fa-spinner fa-spin user-calendar-activities-loading"></i></div>'); success: data => $('.user-calendar-activities').html(data),
},
success: function(data) {
return $('.user-calendar-activities').html(data);
}
}); });
} else { } else {
this.currentSelectedDate = ''; this.currentSelectedDate = '';
return $('.user-calendar-activities').html(''); $('.user-calendar-activities').html('');
} }
} }
initTooltips() {
return $('.js-contrib-calendar .js-tooltip').tooltip({
html: true
});
}
} }
import ActivityCalendar from './activity_calendar'; import Cookies from 'js-cookie';
import User from './user'; import UserTabs from './user_tabs';
// use legacy exports until embedded javascript is refactored export default function initUserProfile(action) {
window.Calendar = ActivityCalendar; // place profile avatars to top
window.gl = window.gl || {}; $('.profile-groups-avatars').tooltip({
window.gl.User = User; placement: 'top',
});
// eslint-disable-next-line no-new
new UserTabs({ parentEl: '.user-profile', action });
// hide project limit message
$('.hide-project-limit-message').on('click', (e) => {
e.preventDefault();
Cookies.set('hide_project_limit_message', 'false');
$(this).parents('.project-limit-message').remove();
});
}
/* eslint-disable class-methods-use-this */
import Cookies from 'js-cookie';
import UserTabs from './user_tabs';
export default class User {
constructor({ action }) {
this.action = action;
this.placeProfileAvatarsToTop();
this.initTabs();
this.hideProjectLimitMessage();
}
placeProfileAvatarsToTop() {
$('.profile-groups-avatars').tooltip({
placement: 'top',
});
}
initTabs() {
return new UserTabs({
parentEl: '.user-profile',
action: this.action,
});
}
hideProjectLimitMessage() {
$('.hide-project-limit-message').on('click', (e) => {
e.preventDefault();
Cookies.set('hide_project_limit_message', 'false');
$(this).parents('.project-limit-message').remove();
});
}
}
/* eslint-disable max-len, space-before-function-paren, no-underscore-dangle, consistent-return, comma-dangle, no-unused-vars, dot-notation, no-new, no-return-assign, camelcase, no-param-reassign, class-methods-use-this */ import ActivityCalendar from './activity_calendar';
/* /**
UserTabs * UserTabs
*
Handles persisting and restoring the current tab selection and lazily-loading * Handles persisting and restoring the current tab selection and lazily-loading
content on the Users#show page. * content on the Users#show page.
*
### Example Markup * ### Example Markup
*
<ul class="nav-links"> * <ul class="nav-links">
<li class="activity-tab active"> * <li class="activity-tab active">
<a data-action="activity" data-target="#activity" data-toggle="tab" href="/u/username"> * <a data-action="activity" data-target="#activity" data-toggle="tab" href="/u/username">
Activity * Activity
</a> * </a>
</li> * </li>
<li class="groups-tab"> * <li class="groups-tab">
<a data-action="groups" data-target="#groups" data-toggle="tab" href="/u/username/groups"> * <a data-action="groups" data-target="#groups" data-toggle="tab" href="/u/username/groups">
Groups * Groups
</a> * </a>
</li> * </li>
<li class="contributed-tab"> * <li class="contributed-tab">
<a data-action="contributed" data-target="#contributed" data-toggle="tab" href="/u/username/contributed"> * ...
Contributed projects * </li>
</a> * <li class="projects-tab">
</li> * ...
<li class="projects-tab"> * </li>
<a data-action="projects" data-target="#projects" data-toggle="tab" href="/u/username/projects"> * <li class="snippets-tab">
Personal projects * ...
</a> * </li>
</li> * </ul>
<li class="snippets-tab"> *
<a data-action="snippets" data-target="#snippets" data-toggle="tab" href="/u/username/snippets"> * <div class="tab-content">
</a> * <div class="tab-pane" id="activity">
</li> * Activity Content
</ul> * </div>
* <div class="tab-pane" id="groups">
<div class="tab-content"> * Groups Content
<div class="tab-pane" id="activity"> * </div>
Activity Content * <div class="tab-pane" id="contributed">
</div> * Contributed projects content
<div class="tab-pane" id="groups"> * </div>
Groups Content * <div class="tab-pane" id="projects">
</div> * Projects content
<div class="tab-pane" id="contributed"> * </div>
Contributed projects content * <div class="tab-pane" id="snippets">
</div> * Snippets content
<div class="tab-pane" id="projects"> * </div>
Projects content * </div>
</div> *
<div class="tab-pane" id="snippets"> * <div class="loading-status">
Snippets content * <div class="loading">
</div> * Loading Animation
* </div>
* </div>
*/
const CALENDAR_TEMPLATE = `
<div class="clearfix calendar">
<div class="js-contrib-calendar"></div>
<div class="calendar-hint">
Summary of issues, merge requests, push events, and comments
</div>
</div> </div>
`;
<div class="loading-status">
<div class="loading">
Loading Animation
</div>
</div>
*/
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 || 'activity';
this.action = action || this.defaultAction; this.action = action || this.defaultAction;
this.$parentEl = $(parentEl) || $(document); this.$parentEl = $(parentEl) || $(document);
this._location = window.location; this.windowLocation = window.location;
this.$parentEl.find('.nav-links a') this.$parentEl.find('.nav-links a')
.each((i, navLink) => { .each((i, navLink) => {
this.loaded[$(navLink).attr('data-action')] = false; this.loaded[$(navLink).attr('data-action')] = false;
...@@ -82,12 +86,10 @@ export default class UserTabs { ...@@ -82,12 +86,10 @@ export default class UserTabs {
} }
bindEvents() { bindEvents() {
this.changeProjectsPageWrapper = this.changeProjectsPage.bind(this); this.$parentEl
.off('shown.bs.tab', '.nav-links a[data-toggle="tab"]')
this.$parentEl.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));
this.$parentEl.on('click', '.gl-pagination a', this.changeProjectsPageWrapper);
} }
changeProjectsPage(e) { changeProjectsPage(e) {
...@@ -122,7 +124,7 @@ export default class UserTabs { ...@@ -122,7 +124,7 @@ export default class UserTabs {
const loadableActions = ['groups', 'contributed', 'projects', 'snippets']; const loadableActions = ['groups', 'contributed', 'projects', 'snippets'];
if (loadableActions.indexOf(action) > -1) { if (loadableActions.indexOf(action) > -1) {
return this.loadTab(action, endpoint); this.loadTab(action, endpoint);
} }
} }
...@@ -131,25 +133,38 @@ export default class UserTabs { ...@@ -131,25 +133,38 @@ export default class UserTabs {
beforeSend: () => this.toggleLoading(true), beforeSend: () => this.toggleLoading(true),
complete: () => this.toggleLoading(false), complete: () => this.toggleLoading(false),
dataType: 'json', dataType: 'json',
type: 'GET',
url: endpoint, url: endpoint,
success: (data) => { success: (data) => {
const tabSelector = `div#${action}`; const tabSelector = `div#${action}`;
this.$parentEl.find(tabSelector).html(data.html); this.$parentEl.find(tabSelector).html(data.html);
this.loaded[action] = true; this.loaded[action] = true;
return gl.utils.localTimeAgo($('.js-timeago', tabSelector)); gl.utils.localTimeAgo($('.js-timeago', tabSelector));
} },
}); });
} }
loadActivities() { loadActivities() {
if (this.loaded['activity']) { if (this.loaded.activity) {
return; return;
} }
const $calendarWrap = this.$parentEl.find('.user-calendar'); const $calendarWrap = this.$parentEl.find('.user-calendar');
$calendarWrap.load($calendarWrap.data('href')); const calendarPath = $calendarWrap.data('calendarPath');
const calendarActivitiesPath = $calendarWrap.data('calendarActivitiesPath');
$.ajax({
dataType: 'json',
url: calendarPath,
success: (activityData) => {
$calendarWrap.html(CALENDAR_TEMPLATE);
// eslint-disable-next-line no-new
new ActivityCalendar('.js-contrib-calendar', activityData, calendarActivitiesPath);
},
});
// eslint-disable-next-line no-new
new gl.Activities(); new gl.Activities();
return this.loaded['activity'] = true; this.loaded.activity = true;
} }
toggleLoading(status) { toggleLoading(status) {
...@@ -158,13 +173,13 @@ export default class UserTabs { ...@@ -158,13 +173,13 @@ export default class UserTabs {
} }
setCurrentAction(source) { setCurrentAction(source) {
let new_state = source; let newState = source;
new_state = new_state.replace(/\/+$/, ''); newState = newState.replace(/\/+$/, '');
new_state += this._location.search + this._location.hash; newState += this.windowLocation.search + this.windowLocation.hash;
history.replaceState({ history.replaceState({
url: new_state url: newState,
}, document.title, new_state); }, document.title, newState);
return new_state; return newState;
} }
getCurrentAction() { getCurrentAction() {
......
...@@ -73,10 +73,7 @@ class UsersController < ApplicationController ...@@ -73,10 +73,7 @@ class UsersController < ApplicationController
end end
def calendar def calendar
calendar = contributions_calendar render json: contributions_calendar.activity_dates
@activity_dates = calendar.activity_dates
render 'calendar', layout: false
end end
def calendar_activities def calendar_activities
......
.clearfix.calendar
.js-contrib-calendar
.calendar-hint
Summary of issues, merge requests, push events, and comments
:javascript
new Calendar(
#{@activity_dates.to_json},
'#{user_calendar_activities_path}'
);
...@@ -2,9 +2,6 @@ ...@@ -2,9 +2,6 @@
- @hide_breadcrumbs = true - @hide_breadcrumbs = true
- page_title @user.name - page_title @user.name
- page_description @user.bio - page_description @user.bio
- content_for :page_specific_javascripts do
= page_specific_javascript_bundle_tag('common_d3')
= page_specific_javascript_bundle_tag('users')
- header_title @user.name, user_path(@user) - header_title @user.name, user_path(@user)
- @no_container = true - @no_container = true
...@@ -107,7 +104,7 @@ ...@@ -107,7 +104,7 @@
.tab-content .tab-content
#activity.tab-pane #activity.tab-pane
.row-content-block.calender-block.white.second-block.hidden-xs .row-content-block.calender-block.white.second-block.hidden-xs
.user-calendar{ data: { href: user_calendar_path } } .user-calendar{ data: { calendar_path: user_calendar_path(@user, :json), calendar_activities_path: user_calendar_activities_path } }
%h4.center.light %h4.center.light
%i.fa.fa-spinner.fa-spin %i.fa.fa-spinner.fa-spin
.user-calendar-activities .user-calendar-activities
...@@ -131,10 +128,3 @@ ...@@ -131,10 +128,3 @@
.loading-status .loading-status
= spinner = spinner
:javascript
var userProfile;
userProfile = new gl.User({
action: "#{controller.action_name}"
});
...@@ -67,7 +67,6 @@ var config = { ...@@ -67,7 +67,6 @@ var config = {
stl_viewer: './blob/stl_viewer.js', stl_viewer: './blob/stl_viewer.js',
terminal: './terminal/terminal_bundle.js', terminal: './terminal/terminal_bundle.js',
u2f: ['vendor/u2f'], u2f: ['vendor/u2f'],
users: './users/index.js',
raven: './raven/index.js', raven: './raven/index.js',
vue_merge_request_widget: './vue_merge_request_widget/index.js', vue_merge_request_widget: './vue_merge_request_widget/index.js',
test: './test.js', test: './test.js',
...@@ -185,7 +184,6 @@ var config = { ...@@ -185,7 +184,6 @@ var config = {
name: 'common_d3', name: 'common_d3',
chunks: [ chunks: [
'graphs', 'graphs',
'users',
'monitoring', 'monitoring',
], ],
}), }),
......
...@@ -80,9 +80,9 @@ describe UsersController do ...@@ -80,9 +80,9 @@ describe UsersController do
it 'renders calendar' do it 'renders calendar' do
sign_in(user) sign_in(user)
get :calendar, username: user.username get :calendar, username: user.username, format: :json
expect(response).to render_template('calendar') expect(response).to have_http_status(200)
end end
context 'forked project' do context 'forked project' do
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册