#214: updated #branches page, integrated AngularJS

This commit is contained in:
Vokhmin Alexey V 2013-07-11 14:34:44 +04:00
parent 6c6b73ada9
commit d747ffd070
17 changed files with 194 additions and 15 deletions

View File

@ -58,6 +58,11 @@ gem 'rest-client', '~> 1.6.6'
gem 'attr_encrypted', '1.2.1' gem 'attr_encrypted', '1.2.1'
gem "gemoji", "~> 1.2.1", require: 'emoji/railtie' gem "gemoji", "~> 1.2.1", require: 'emoji/railtie'
# AngularJS related stuff
gem 'angularjs-rails'
gem 'ng-rails-csrf'
# gem 'angularjs-rails-resource'
group :assets do group :assets do
gem 'sass-rails', '~> 3.2.5' gem 'sass-rails', '~> 3.2.5'
gem 'coffee-rails', '~> 3.2.2' gem 'coffee-rails', '~> 3.2.2'

View File

@ -58,6 +58,8 @@ GEM
json json
ancestry (1.3.0) ancestry (1.3.0)
activerecord (>= 2.3.14) activerecord (>= 2.3.14)
angularjs-rails (1.0.7)
angularjs-rails-resource (0.2.0)
arel (3.0.2) arel (3.0.2)
attr_encrypted (1.2.1) attr_encrypted (1.2.1)
encryptor (>= 1.1.1) encryptor (>= 1.1.1)
@ -209,6 +211,7 @@ GEM
net-ssh-gateway (1.2.0) net-ssh-gateway (1.2.0)
net-ssh (>= 2.6.5) net-ssh (>= 2.6.5)
newrelic_rpm (3.5.5.38) newrelic_rpm (3.5.5.38)
ng-rails-csrf (0.1.0)
nokogiri (1.5.9) nokogiri (1.5.9)
oauth2 (0.8.1) oauth2 (0.8.1)
faraday (~> 0.8) faraday (~> 0.8)
@ -407,6 +410,8 @@ DEPENDENCIES
RedCloth RedCloth
airbrake (~> 3.1.2) airbrake (~> 3.1.2)
ancestry (~> 1.3.0) ancestry (~> 1.3.0)
angularjs-rails
angularjs-rails-resource
attr_encrypted (= 1.2.1) attr_encrypted (= 1.2.1)
better_errors better_errors
binding_of_caller binding_of_caller
@ -437,6 +442,7 @@ DEPENDENCIES
meta_request meta_request
mock_redis (= 0.6.2) mock_redis (= 0.6.2)
newrelic_rpm (~> 3.5.5.38) newrelic_rpm (~> 3.5.5.38)
ng-rails-csrf
omniauth omniauth
omniauth-facebook omniauth-facebook
omniauth-github omniauth-github

View File

@ -0,0 +1 @@
var RosaABF = angular.module('RosaABF', ['ngResource', 'ng-rails-csrf']);

View File

@ -0,0 +1,44 @@
RosaABF.controller('ProjectRefsController', function($scope, $http, $location, ApiProject) {
$scope.branches = [];
$scope.tags = [];
$scope.project_id = null;
$scope.current_ref = null;
$scope.init = function(project_id, ref) {
$scope.project_id = project_id;
$scope.current_ref = ref;
ApiProject.project($scope.project_id, function(result){
$scope.project = result;
});
$scope.getRefs();
}
$scope.getRefs = function() {
//returns [ProjectRef, ProjectRef, ...]
ApiProject.refs($scope.project_id, function(results){
_.each(results, function(result){
if (result.isTag) {
if (result.ref == $scope.current_ref) {
$scope.tags.unshift(result);
} else {
$scope.tags.push(result);
}
} else {
if (result.ref == $scope.current_ref) {
$scope.branches.unshift(result);
} else {
$scope.branches.push(result);
}
}
});
});
};
$scope.destroy = function(branch) {
var path = $location.$$absUrl.replace(/\/[\w\-]+$/, '') + '/' + branch.name;
$http.delete(path).success(function(data) {
$scope.getRefs();
});
}
});

View File

@ -0,0 +1,14 @@
var Project = function(atts){
var self = this;
var initialSettings = atts || {};
//initial settings if passed in
for(var setting in initialSettings){
if(initialSettings.hasOwnProperty(setting))
self[setting] = initialSettings[setting];
};
//with some logic...
//return the scope-safe instance
return self;
};

View File

@ -0,0 +1,25 @@
var ProjectRef = function(atts) {
var self = this;
var initialSettings = atts || {};
//initial settings if passed in
for(var setting in initialSettings){
if(initialSettings.hasOwnProperty(setting))
self[setting] = initialSettings[setting];
};
//with some logic...
self.isTag = self.object.type == 'tag';
self.path = function(project) {
return '/' + project.fullname + '/tree/' + self.ref;
}
self.diff_path = function(project, current_ref) {
return '/' + project.fullname + '/diff/' + current_ref + '...' + self.ref;
}
//return the scope-safe instance
return self;
};

View File

@ -0,0 +1,30 @@
var ApiProject = function($resource) {
var projectResource = $resource('/api/v1/projects/:project_id.json');
var queryProject = function(project_id, next) {
projectResource.get({project_id: project_id}, function(results){
next(new Project(results.project));
});
};
var refsResource = $resource('/api/v1/projects/:project_id/refs_list.json');
var queryRefs = function(project_id, next) {
//use a callback instead of a promise
refsResource.get({project_id: project_id}, function(results) {
var out = [];
//Underscore's "each" method
_.each(results.refs_list, function(ref){
//using our ProjectRef(ref) prototype above
out.push(new ProjectRef(ref));
});
next(out);
});
};
return {
refs : queryRefs,
project : queryProject
}
}
RosaABF.factory("ApiProject", ApiProject);

View File

@ -13,6 +13,11 @@
//= require backbone_rails_sync //= require backbone_rails_sync
//= require backbone_datalink //= require backbone_datalink
//= require backbone/rosa //= require backbone/rosa
//= require angular
//= require angular-resource
// require angularjs/rails/resource
//= require ng-rails-csrf
//= require_tree ./angularjs
//= require_self //= require_self
function disableNotifierCbx(global_cbx) { function disableNotifierCbx(global_cbx) {

View File

@ -2,7 +2,11 @@
class Projects::Git::BaseController < Projects::BaseController class Projects::Git::BaseController < Projects::BaseController
before_filter :authenticate_user! before_filter :authenticate_user!
skip_before_filter :authenticate_user!, :only => [:show, :index, :blame, :raw, :archive, :diff, :tags, :branches] if APP_CONFIG['anonymous_access'] skip_before_filter :authenticate_user!, :only => [:show, :index, :blame, :raw, :archive, :diff, :tags, :branches] if APP_CONFIG['anonymous_access']
load_and_authorize_resource :project
load_and_authorize_resource :project, :except => :destroy
load_resource :project, :only => :destroy
before_filter lambda { authorize!(:write, @project) }, :only => :destroy
before_filter :set_treeish_and_path before_filter :set_treeish_and_path
before_filter :set_branch_and_tree before_filter :set_branch_and_tree

View File

@ -32,10 +32,26 @@ class Projects::Git::TreesController < Projects::Git::BaseController
render 'refs' render 'refs'
end end
def destroy
render :nothing => true
end
def branches def branches
raise Grit::NoSuchPathError if params[:treeish] != @branch.try(:name) # get wrong branch name to nonempty project raise Grit::NoSuchPathError if params[:treeish] != @branch.try(:name) # get wrong branch name to nonempty project
@branches = @project.repo.branches.sort_by(&:name).select{ |b| b.name != @branch.name }.unshift(@branch).compact if @branch if request.xhr?
render 'refs' @branches = @project.repo.branches.sort_by(&:name).select{ |b| b.name != @branch.name }.unshift(@branch).compact if @branch
@branches = @branches.map do |branch|
{
:name => branch.name,
:path => tree_path(@project, branch.name),
:current => (branch.name == @branch.try(:name)),
:diff_path => diff_path(@project, "#{@branch.name}...#{branch.name}")
}
end
render :json => @branches
else
render 'refs'
end
end end
end end

View File

@ -12,7 +12,7 @@
- if user_signed_in? - if user_signed_in?
= auto_discovery_link_tag :atom, atom_activity_feeds_path(:format => 'atom', :token => current_user.authentication_token), :title => t("layout.atom_link_tag_title", :nickname => current_user.uname, :app_name => APP_CONFIG['project_name']) = auto_discovery_link_tag :atom, atom_activity_feeds_path(:format => 'atom', :token => current_user.authentication_token), :title => t("layout.atom_link_tag_title", :nickname => current_user.uname, :app_name => APP_CONFIG['project_name'])
%body %body{'ng-app' => 'RosaABF'}
.wrap{:class => content_for?(:sidebar) ? 'columns' : ''} .wrap{:class => content_for?(:sidebar) ? 'columns' : ''}
%header %header
.left .left

View File

@ -4,7 +4,7 @@
- if subject.blank? - if subject.blank?
%p= t("layout.projects.no_#{subjects_name}") %p= t("layout.projects.no_#{subjects_name}")
- elsif subject.count == 1 - elsif subject.count == 1
%p= t("layout.projects.showing_#{subjects_name.singularize}") %p= t("layout.projects.total_#{subjects_name.singularize}")
- else - else
%p= t("layout.projects.showing_#{subjects_name}", :count => subject.count) %p= t("layout.projects.total_#{subjects_name}", :count => subject.count)
.both .both

View File

@ -4,11 +4,35 @@
= render 'repo_block', :project => @project = render 'repo_block', :project => @project
= render 'header', :subject => (@branches || @tags) = render 'header', :subject => (@branches || @tags)
%div{'ng-controller' => 'ProjectRefsController',
'ng-init' => "init('#{@project.id}','#{@branch.try(:name)}')"}
.both
Search:
%input{'ng-model' => 'query.ref'}
.both
%table#project-branches
%tbody
%tr{'ng-repeat' => 'branch in branches | filter:query', 'ng-class' => '{base: branch.ref == current_ref}'}
%td.name
%a{'ng-href' => '{{branch.path(project)}}' } {{branch.ref}}
%td.actions
%ul.actions
%li.text{'ng-show' => 'branch.ref == current_ref'}
= t('layout.projects.base_branch')
%li{'ng-hide' => 'branch.ref == current_ref'}
%a{:href => '#', 'ng-click' => 'destroy(branch)'}= t('layout.projects.delete_branch')
%li{'ng-hide' => 'branch.ref == current_ref'}
%a{'ng-href' => '{{branch.diff_path(project, current_ref)}}' }= t('layout.projects.compare')
- if @tags.present? - if @tags.present?
%div#project-tags %div#project-tags
%ol.release-list %ol.release-list
= render :partial => 'tag', :collection => @tags = render :partial => 'tag', :collection => @tags
- elsif @branches.present? - elsif false # @branches.present?
%table#project-branches %table#project-branches
%tbody %tbody
= render :partial => 'branch', :collection => @branches = render :partial => 'branch', :collection => @branches

View File

@ -6,6 +6,7 @@
.flash .flash
%div{:class => @pull.ready? ? 'notice' : 'alert'} %div{:class => @pull.ready? ? 'notice' : 'alert'}
=pull_status @pull =pull_status @pull
wwwww
-if can? :update, @pull -if can? :update, @pull
-if action = @pull.can_close? ? 'close' : ('reopen' if @pull.can_reopen?) -if action = @pull.can_close? ? 'close' : ('reopen' if @pull.can_reopen?)
%br %br

View File

@ -2,16 +2,17 @@ en:
layout: layout:
projects: projects:
branches: Branches branches: Branches
showing_branches: Showing %{count} branches delete_branch: Delete branch
showing_branch: Showing 1 branch total_branches: Total %{count} branches
total_branch: Total 1 branch
no_branches: No branches no_branches: No branches
base_branch: Base branch base_branch: Base branch
compare: Compare compare: Compare
browse_code: Browse code browse_code: Browse code
source_code: Source code (%{type}) source_code: Source code (%{type})
tags: Tags tags: Tags
showing_tags: Showing %{count} tags total_tags: Total %{count} tags
showing_tag: Showing 1 tag total_tag: Total 1 tag
no_tags: No tags no_tags: No tags
add: Add add: Add
public_projects_list: Public projects list public_projects_list: Public projects list

View File

@ -2,16 +2,17 @@ ru:
layout: layout:
projects: projects:
branches: Ветки branches: Ветки
showing_branches: Показано %{count} веток delete_branch: Удалить ветку
showing_branch: Показана 1 ветка total_branches: Всего %{count} веток
total_branch: Всего 1 ветка
no_branch: Нет веток no_branch: Нет веток
base_branch: Текущая ветка base_branch: Текущая ветка
compare: Сравнить compare: Сравнить
browse_code: Просмотреть код browse_code: Просмотреть код
source_code: Исходный код (%{type}) source_code: Исходный код (%{type})
tags: Теги tags: Теги
showing_tags: Показано %{count} тегов total_tags: Всего %{count} тегов
showing_tag: Показан 1 тег total_tag: Всего 1 тег
no_tags: Нет тегов no_tags: Нет тегов
add: Добавить add: Добавить
public_projects_list: Список публичных проектов public_projects_list: Список публичных проектов

View File

@ -331,8 +331,10 @@ Rosa::Application.routes.draw do
get '/tree/:treeish(/*path)' => "git/trees#show", :as => :tree, :format => false get '/tree/:treeish(/*path)' => "git/trees#show", :as => :tree, :format => false
# Tags # Tags
get '/tags' => "git/trees#tags", :as => :tags get '/tags' => "git/trees#tags", :as => :tags
# delete '/tags/:treeish' => "git/trees#destroy", :as => :tags
# Branches # Branches
get '/branches/:treeish' => "git/trees#branches", :as => :branches get '/branches/:treeish' => "git/trees#branches", :as => :branches
# delete '/branches/:treeish' => "git/trees#destroy", :as => :branches
# Commits # Commits
get '/commits/:treeish(/*path)' => "git/commits#index", :as => :commits, :format => false get '/commits/:treeish(/*path)' => "git/commits#index", :as => :commits, :format => false
get '/commit/:id(.:format)' => "git/commits#show", :as => :commit get '/commit/:id(.:format)' => "git/commits#show", :as => :commit