#214: updated #branches page, integrated AngularJS
This commit is contained in:
parent
6c6b73ada9
commit
d747ffd070
5
Gemfile
5
Gemfile
|
@ -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'
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
var RosaABF = angular.module('RosaABF', ['ngResource', 'ng-rails-csrf']);
|
|
@ -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();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
|
@ -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;
|
||||||
|
};
|
|
@ -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;
|
||||||
|
};
|
|
@ -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);
|
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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: Список публичных проектов
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue