[#369] add new comment & new push notifications
This commit is contained in:
parent
5cf413139d
commit
09b75e4110
|
@ -1,6 +1,6 @@
|
|||
//var RosaABF = angular.module('RosaABF', ['ngResource', 'ng-rails-csrf', 'angular-i18n', 'angularMoment']);
|
||||
var RosaABF = angular.module('RosaABF', ['ui.bootstrap', 'angular-i18n', 'angularMoment',
|
||||
'chieffancypants.loadingBar', 'ngAnimate']);
|
||||
'chieffancypants.loadingBar', 'ngSanitize']);
|
||||
|
||||
var LocalesHelper = function($locale) {
|
||||
var locales = {
|
||||
|
@ -13,4 +13,9 @@ var LocalesHelper = function($locale) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
RosaABF.factory("LocalesHelper", ['$locale', LocalesHelper]);
|
||||
|
||||
RosaABF.config(function(cfpLoadingBarProvider) {
|
||||
cfpLoadingBarProvider.includeSpinner = false;
|
||||
});
|
|
@ -1,13 +1,15 @@
|
|||
RosaABF.controller('ActivityCtrl', ['$scope', '$http', '$timeout', '$q',
|
||||
function($scope, $http, $timeout, $q) {
|
||||
RosaABF.controller('ActivityCtrl', ['$scope', '$http', '$timeout', '$q', '$filter',
|
||||
function($scope, $http, $timeout, $q, $filter) {
|
||||
$scope.activity_tab = { title: 'activity_menu.activity_feed', content: [] , isLoaded: false , active: true };
|
||||
$scope.tracker_tab = { title: 'activity_menu.tracker', content: [] , isLoaded: false , active: false };
|
||||
$scope.pull_requests_tab = { title: 'activity_menu.pull_requests', content: [] , isLoaded: false , active: false };
|
||||
|
||||
var today = moment().startOf('day');
|
||||
$scope.activity_tab.content = [{date: today, test:'adf'}, {date: today.add('days', 1).calendar, test:'fd'}];
|
||||
// $scope.activity_tab.content = [{date: today, kind:'new_comment_notification'},
|
||||
// {date: today, kind:'git_new_push_notification'},
|
||||
// {date: moment().add('days', 1), kind:'build_list_notification'}];
|
||||
|
||||
$scope.getContent=function(tab){
|
||||
$scope.getContent=function(tab){
|
||||
var cur_tab = $scope.$eval(tab+'_tab');
|
||||
/* see if we have data already */
|
||||
if(cur_tab.isLoaded){
|
||||
|
@ -15,27 +17,42 @@ RosaABF.controller('ActivityCtrl', ['$scope', '$http', '$timeout', '$q',
|
|||
}
|
||||
/* or make request for data */
|
||||
var path = Routes.root_path({ filter: cur_tab.filter, format: 'json' });
|
||||
$http.get(path, { tracker: 'activity' }).then(function(res){
|
||||
//cur_tab.content=res.data;
|
||||
$http.get(path).then(function(res){
|
||||
cur_tab.content=res.data;
|
||||
cur_tab.isLoaded=true;
|
||||
});
|
||||
}
|
||||
|
||||
$scope.getTimeLinefaClass = function(contentType) {
|
||||
var template = 'bg-warning fa-question';
|
||||
$scope.getTimeLinefaClass = function(content) {
|
||||
var template = 'btn-warning fa-question';
|
||||
|
||||
switch(contentType) {
|
||||
switch(content.kind) {
|
||||
case 'build_list_notification':
|
||||
template = 'bg-danger fa-gear';
|
||||
break;
|
||||
template = 'btn-success fa-gear';
|
||||
break;
|
||||
case 'new_comment_notification':
|
||||
template = 'bg-primary fa-comment';
|
||||
break;
|
||||
case 'new_comment_commit_notification':
|
||||
template = 'btn-warning fa-comment';
|
||||
break;
|
||||
case 'git_new_push_notification':
|
||||
template = 'bg-success fa-sign-in';
|
||||
break;
|
||||
template = 'bg-primary fa-sign-in';
|
||||
break;
|
||||
case 'new_issue_notification':
|
||||
template = 'btn-warning fa-check-square-o';
|
||||
break;
|
||||
}
|
||||
|
||||
return template;
|
||||
}
|
||||
|
||||
$scope.needShowTimeLabel = function(index) {
|
||||
var cur_date = $filter('amDateFormat')($scope.activity_tab.content[index].date, 'll');
|
||||
var prev_date = index == 0 || $filter('amDateFormat')($scope.activity_tab.content[index-1].date, 'll');
|
||||
return cur_date !== prev_date;
|
||||
};
|
||||
|
||||
$scope.isComment = function(content) {
|
||||
return content.kind === 'new_comment_notification' ||
|
||||
content.kind === 'new_comment_commit_notification';
|
||||
};
|
||||
}]);
|
||||
|
|
|
@ -3,13 +3,14 @@
|
|||
|
||||
// Loads all Bootstrap javascripts
|
||||
//= require bootstrap
|
||||
//= require unstable/angular
|
||||
// require angular
|
||||
//= require angular-ui-bootstrap-tpls
|
||||
|
||||
// require unstable/angular
|
||||
//= require angular
|
||||
//= require angular-sanitize
|
||||
//= require angular-ui-bootstrap-tpls
|
||||
//= require angular-i18n
|
||||
//= require angular-animate
|
||||
//= require angularjs/locales
|
||||
|
||||
//= require moment
|
||||
//= require angularjs/angular-moment
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@ footer {
|
|||
}
|
||||
|
||||
.offset20 { margin-top: 20px; }
|
||||
.boffset20 { margin-bottom: 20px; }
|
||||
|
||||
[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
|
||||
display: none !important;
|
||||
|
|
|
@ -13,6 +13,7 @@ class HomeController < ApplicationController
|
|||
@activity_feeds = @activity_feeds.paginate page: params[:page]
|
||||
respond_to do |format|
|
||||
format.html { request.xhr? ? render('_list', layout: false) : render('activity') }
|
||||
format.json {}
|
||||
format.atom
|
||||
end
|
||||
end
|
||||
|
|
|
@ -10,7 +10,38 @@ module ActivityFeedsHelper
|
|||
feed_title = feed_title.gsub(/\s{2,}/, ' ').strip
|
||||
end
|
||||
|
||||
def get_user_from_activity_item(item)
|
||||
email = item.data[:user_email]
|
||||
User.where(email: email).first || User.new(email: email) if email.present?
|
||||
end
|
||||
|
||||
def user_link(user, user_name, full_url = false)
|
||||
user.persisted? ? link_to(user_name, full_url ? user_url(user) : user_path(user)) : user_name
|
||||
end
|
||||
|
||||
def get_title_from_activity_item(item, opts = {})
|
||||
case item.kind
|
||||
when 'new_comment_notification'
|
||||
res = t('notifications.bodies.new_comment_notification.title', { user_link: nil })
|
||||
res << ' ' << t('notifications.bodies.new_comment_notification.content',
|
||||
{ issue_link: link_to(item.data[:issue_title], opts[:path]) })
|
||||
when 'git_new_push_notification'
|
||||
res = t("notifications.bodies.#{item.data[:change_type]}_branch",
|
||||
{ branch_name: item.data[:branch_name], user_link: nil })
|
||||
res << ' ' << t('notifications.bodies.project', project_link: link_to(opts[:project_name_with_owner], opts[:path]))
|
||||
else nil
|
||||
end
|
||||
raw res
|
||||
end
|
||||
|
||||
def get_path_from_activity_item(item, opts = {})
|
||||
case item.kind
|
||||
when 'new_comment_notification'
|
||||
project_issue_path(opts[:project_name_with_owner], item.data[:issue_serial_id])
|
||||
when 'git_new_push_notification'
|
||||
project_path(opts[:project_name_with_owner])
|
||||
else
|
||||
'?'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -13,7 +13,7 @@ class ActivityFeed < ActiveRecord::Base
|
|||
default_scope { order created_at: :desc }
|
||||
scope :outdated, -> { offset(100) }
|
||||
|
||||
self.per_page = 4
|
||||
self.per_page = 10
|
||||
|
||||
def partial
|
||||
'home/partials/' + self.kind
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
.row
|
||||
- item.data[:last_commits].each do |commit|
|
||||
.col-sm-3.col-md-2= link_to shortest_hash_id(commit[0]), commit_path(project_name_with_owner, commit[0])
|
||||
.col-sm-8.col-md-9= truncate(commit[1], length: 70, omission: '…')
|
||||
.clearfix
|
||||
-#%br
|
||||
- if item.data[:other_commits].present?
|
||||
%br
|
||||
=link_to t('notifications.bodies.more_commits', count: item.data[:other_commits_count],
|
||||
commits: commits_pluralize(item.data[:other_commits_count])),
|
||||
diff_path(project_name_with_owner, diff: item.data[:other_commits])
|
|
@ -8,12 +8,12 @@
|
|||
/ - render 'top_menu'
|
||||
|
||||
%div{ 'ng-controller' => 'ActivityCtrl', 'cg-busy' => "'activity'" }
|
||||
%tabset
|
||||
%tabset.offset20
|
||||
|
||||
%tab{ 'heading' => "{{activity_tab.title | i18n}}", 'active' => "activity_tab.active", 'select' => "getContent('activity')" }
|
||||
|
||||
.row
|
||||
.col-md-3.offset20
|
||||
.col-md-3.col-sm-4.offset20
|
||||
%p
|
||||
= link_to t('layout.activity_feed.new_project'), new_project_path,
|
||||
class: 'btn btn-primary btn-small', role: 'button'
|
||||
|
@ -24,44 +24,47 @@
|
|||
- current_user.projects.order(updated_at: :desc).limit(5).each do |project|
|
||||
%li
|
||||
= link_to project_path(project) do
|
||||
- image, color = project.public? ? ['unlock-alt', 'text-success'] : ['lock', 'text-danger']
|
||||
- image, color = project.public? ? ['unlock-alt', 'text-success fa-fw'] : ['lock', 'text-danger fa-fw']
|
||||
= fa_icon(image, class: color)
|
||||
= project.name_with_owner
|
||||
%li
|
||||
= link_to t('layout.activity_feed.all_my_projects'), projects_path
|
||||
|
||||
.col-md-9
|
||||
.col-md-9.col-sm-8
|
||||
%h3
|
||||
= t("layout.activity_feed.header")
|
||||
= link_to image_tag("rss.ico", width: '15px', height: '15px', class: 'atom_icon'), atom_activity_feeds_path(format: 'atom', token: current_user.authentication_token)
|
||||
/ The time line
|
||||
.row
|
||||
.col-md-12
|
||||
.col-md-12.col-sm-12
|
||||
%ul.timeline
|
||||
.timeline-element{ 'ng-repeat' => 'item in activity_tab.content' }
|
||||
/ timeline time label
|
||||
%li.time-label
|
||||
%span{ 'ng-show' => "(item.date | amDateFormat:'ll') != (item[$index-1].date | amDateFormat:'ll')" }
|
||||
{{item.date | amDateFormat:'ll'}}
|
||||
/ timeline item
|
||||
%li
|
||||
%i.img-circle.bg-primary.fa.fa-comment
|
||||
.timeline-item
|
||||
%span.time
|
||||
/ timeline time label
|
||||
%li.time-label{ 'ng-repeat-start' => 'item in activity_tab.content' }
|
||||
%span{ 'ng-show' => "needShowTimeLabel($index)", 'ng-cloak' => true }
|
||||
{{item.date | amDateFormat:'ll'}}
|
||||
/ timeline item
|
||||
%li
|
||||
%i.img-circle.fa{ 'ng-class' => "getTimeLinefaClass(item)" }
|
||||
.timeline-item
|
||||
%h3.timeline-header
|
||||
%a{ 'ng-href' => "{{item.user.link}}" }
|
||||
%img{ 'ng-src' => "{{item.user.image}}" }
|
||||
{{item.user.uname}}
|
||||
%span.time{ 'ng-cloak' => true, popover: "{{item.date | amDateFormat:'ddd, LLL'}}",
|
||||
"popover-trigger" => "mouseenter", 'popover-append-to-body' => 'true' }
|
||||
%span.glyphicon.glyphicon-time
|
||||
12:05
|
||||
%h3.timeline-header
|
||||
%a{href: "#"} Support Team
|
||||
sent you and email
|
||||
.timeline-body
|
||||
Etsy doostang zoodles disqus groupon greplin oooj voxy zoodles,
|
||||
weebly ning heekya handango imeem plugg dopplr jibjab, movity
|
||||
jajah plickers sifteo edmodo ifttt zimbra. Babblely odeo kaboodle
|
||||
quora plaxo ideeli hulu weebly balihoo...
|
||||
.timeline-footer
|
||||
%a.btn.btn-primary.btn-xs Read more
|
||||
%a.btn.btn-danger.btn-xs Delete
|
||||
%span {{item.date | amDateFormat:'HH:mm'}}
|
||||
.clearfix
|
||||
.timeline-body
|
||||
-#%p{ 'ng-bind-html' => "item.title" }
|
||||
%p{ 'ng-bind-html' => "item.title" }
|
||||
%blockquote{ 'ng-if' => "isComment(item)" }
|
||||
{{item.body}}
|
||||
%p{ 'ng-if' => "!isComment(item)", 'ng-bind-html' => "item.body" }
|
||||
|
||||
%li
|
||||
%i.fa.fa-clock-o
|
||||
/ /.col
|
||||
.timeline-footer
|
||||
%a.btn.btn-primary.btn-xs{ 'ng-href' => "{{item.read_more}}", 'ng-if' => "isComment(item)" }
|
||||
= t('layout.read_more')
|
||||
.hide{ 'ng-repeat-end' => true }
|
||||
%li
|
||||
%i.img-circle.bg-primary.fa.fa-clock-o
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
json.array!(@activity_feeds) do |item|
|
||||
json.cache! item do
|
||||
json.date item.created_at
|
||||
json.kind item.kind
|
||||
user = get_user_from_activity_item(item)
|
||||
json.user do
|
||||
json.link user_path(user) if user.persisted?
|
||||
json.image avatar_url(user, :small) if user.persisted?
|
||||
json.uname (user.fullname || user.email)
|
||||
end if user
|
||||
project_name_with_owner = "#{item.data[:project_owner]}/#{item.data[:project_name]}"
|
||||
json.project_name_with_owner project_name_with_owner
|
||||
path = get_path_from_activity_item(item, project_name_with_owner: project_name_with_owner)
|
||||
json.title get_title_from_activity_item(item, user: user, project_name_with_owner: project_name_with_owner, path: path)
|
||||
|
||||
case item.kind
|
||||
when 'new_comment_notification'
|
||||
json.read_more path + "#comment#{item.data[:comment_id]}"
|
||||
json.body short_message(item.data[:comment_body], 1000)
|
||||
when 'git_new_push_notification'
|
||||
json.body render('commits_list', item: item, project_name_with_owner: project_name_with_owner).html_safe
|
||||
end
|
||||
json.id item.id
|
||||
end
|
||||
end
|
|
@ -1,4 +1,4 @@
|
|||
%footer
|
||||
%footer.offset20
|
||||
%ul
|
||||
%li= t('bottom_menu.copyright', year: Date.today.year)
|
||||
%li ·
|
||||
|
|
|
@ -48,7 +48,7 @@ $loading-bar-bg: #254561; // #dff0d8;
|
|||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 4px;
|
||||
height: 3px;
|
||||
border-bottom-right-radius: 1px;
|
||||
border-top-right-radius: 1px;
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ $loading-bar-bg: #254561; // #dff0d8;
|
|||
position: fixed;
|
||||
z-index: 2000;
|
||||
top: 10px;
|
||||
left: 17px;
|
||||
left: 18px;
|
||||
font-size: 31px;
|
||||
color: $loading-bar-bg;
|
||||
}
|
||||
|
|
|
@ -47,63 +47,67 @@ Component: timeline
|
|||
-moz-border-radius: 2px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
.timeline > .timeline-element > li {
|
||||
.timeline > li {
|
||||
position: relative;
|
||||
margin-right: 10px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.timeline > .timeline-element > li:before,
|
||||
.timeline > .timeline-element > li:after {
|
||||
.timeline > li:before,
|
||||
.timeline > li:after {
|
||||
display: table;
|
||||
content: " ";
|
||||
}
|
||||
.timeline > .timeline-element > li:after {
|
||||
.timeline > li:after {
|
||||
clear: both;
|
||||
}
|
||||
.timeline > .timeline-element > li > .timeline-item {
|
||||
.timeline > li > .timeline-item {
|
||||
margin-top: 10px;
|
||||
border: 0px solid #dfdfdf;
|
||||
border: 0px solid #b2b2b2;
|
||||
background: #fff;
|
||||
color: #555;
|
||||
margin-left: 60px;
|
||||
margin-right: 15px;
|
||||
padding: 5px;
|
||||
position: relative;
|
||||
box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.1);
|
||||
box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
.timeline > .timeline-element > li > .timeline-item > .time {
|
||||
.timeline > li > .timeline-item .time {
|
||||
color: #999;
|
||||
float: right;
|
||||
margin: 2px 0 0 0;
|
||||
margin: 2px 0 2px 0;
|
||||
}
|
||||
.timeline > .timeline-element > li > .timeline-item > .timeline-header {
|
||||
.timeline > li > .timeline-item > .timeline-header {
|
||||
margin: 0;
|
||||
color: #555;
|
||||
border-bottom: 1px solid #f4f4f4;
|
||||
padding: 5px;
|
||||
//border-bottom: 1px solid #dcdcdc;
|
||||
padding: 2px;
|
||||
font-size: 16px;
|
||||
line-height: 1.1;
|
||||
}
|
||||
.timeline > .timeline-element > li > .timeline-item > .timeline-header > a {
|
||||
.timeline > li > .timeline-item > .timeline-header > a {
|
||||
font-weight: 600;
|
||||
}
|
||||
.timeline > .timeline-element > li > .timeline-item > .timeline-body,
|
||||
.timeline > .timeline-element > li > .timeline-item > .timeline-footer {
|
||||
padding: 10px;
|
||||
.timeline > li > .timeline-item > .timeline-header > a > img {
|
||||
margin: 0 10px 0 10px;
|
||||
}
|
||||
.timeline > .timeline-element > li.time-label > span {
|
||||
.timeline > li > .timeline-item > .timeline-body,
|
||||
.timeline > li > .timeline-item > .timeline-footer {
|
||||
padding: 5px 10px 5px 10px;
|
||||
}
|
||||
.timeline > li.time-label > span {
|
||||
font-weight: 600;
|
||||
padding: 5px;
|
||||
display: inline-block;
|
||||
background-color: #fff;
|
||||
background-color: #AA53AA;
|
||||
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.5);
|
||||
-webkit-border-radius: 4px;
|
||||
-moz-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
color: #f9f9f9;
|
||||
}
|
||||
.timeline > .timeline-element > li > .fa,
|
||||
.timeline > .timeline-element > li > .glyphicon,
|
||||
.timeline > .timeline-element > li > .ion {
|
||||
.timeline > li > .fa,
|
||||
.timeline > li > .glyphicon,
|
||||
.timeline > li > .ion {
|
||||
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
|
|
Loading…
Reference in New Issue