Commit bdac5ddd authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Merge branch 'ee-from-ce' into 'master'

CE changes from master

Sidebar navigation, OAuth and other changes from CE

See merge request !275
parents 4f0d2d33 01f7734f
v 7.7.0
-
-
-
-
-
-
-
-
- OAuth applications feature
-
-
- Set project path instead of project name in create form
-
-
- New side navigation
v 7.6.0
- Fork repository to groups
- New rugged version
......
......@@ -101,6 +101,16 @@ Please ensure you support the feature you contribute through all of these steps.
1. Community questions answered
1. Answers to questions radiated (in docs/wiki/etc.)
If you add a dependency in GitLab (such as an operating system package) please consider updating the following and note the applicability of each in your merge request:
1. Note the addition in the release blog post (create one if it doesn't exist yet) https://gitlab.com/gitlab-com/www-gitlab-com/merge_requests/
1. Upgrade guide, for example https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/update/7.5-to-7.6.md
1. Upgrader https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/update/upgrader.md#2-run-gitlab-upgrade-tool
1. Installation guide https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/install/installation.md#1-packages-dependencies
1. GitLab Development Kit https://gitlab.com/gitlab-org/gitlab-development-kit
1. Test suite https://gitlab.com/gitlab-org/gitlab-ci/blob/master/doc/examples/configure_a_runner_to_run_the_gitlab_ce_test_suite.md
1. Omnibus package creator https://gitlab.com/gitlab-org/omnibus-gitlab
## Merge request description format
1. What does this MR do?
......@@ -118,6 +128,7 @@ Please ensure you support the feature you contribute through all of these steps.
1. Can merge without problems (if not please merge `master`, never rebase commits pushed to the remote server)
1. Does not break any existing functionality
1. Fixes one specific issue or implements one specific feature (do not combine things, send separate merge requests if needed)
1. Migrations should do only one thing (eg: either create a table, move data to a new table or remove an old table) to aid retrying on failure
1. Keeps the GitLab code base clean and well structured
1. Contains functionality we think other users will benefit from too
1. Doesn't add configuration options since they complicate future changes
......
......@@ -29,6 +29,8 @@ gem 'omniauth-twitter'
gem 'omniauth-github'
gem 'omniauth-shibboleth'
gem 'omniauth-kerberos'
gem 'doorkeeper', '2.0.1'
gem "rack-oauth2", "~> 1.0.5"
# Extracting information from a git repository
# Provide access to Gitlab::Git library
......
......@@ -37,6 +37,7 @@ GEM
rake (>= 0.8.7)
arel (5.0.1.20140414130214)
asciidoctor (0.1.4)
attr_required (1.0.0)
awesome_print (1.2.0)
axiom-types (0.0.5)
descendants_tracker (~> 0.0.1)
......@@ -107,6 +108,8 @@ GEM
diff-lcs (1.2.5)
diffy (3.0.3)
docile (1.1.5)
doorkeeper (2.0.1)
railties (>= 3.1)
dotenv (0.9.0)
dropzonejs-rails (0.4.14)
rails (> 3.1)
......@@ -158,7 +161,7 @@ GEM
dotenv (>= 0.7)
thor (>= 0.13.6)
formatador (0.2.4)
gemnasium-gitlab-service (0.2.2)
gemnasium-gitlab-service (0.2.3)
rugged (~> 0.19)
gherkin-ruby (0.3.1)
racc
......@@ -250,6 +253,7 @@ GEM
json (~> 1.8)
multi_xml (>= 0.5.2)
httpauth (0.2.1)
httpclient (2.5.3.3)
i18n (0.6.11)
ice_cube (0.12.1)
ice_nine (0.10.0)
......@@ -369,6 +373,12 @@ GEM
rack (>= 1.1.3)
rack-mount (0.8.3)
rack (>= 1.0.0)
rack-oauth2 (1.0.8)
activesupport (>= 2.3)
attr_required (>= 0.0.5)
httpclient (>= 2.2.0.2)
multi_json (>= 1.3.6)
rack (>= 1.1)
rack-protection (1.5.1)
rack
rack-test (0.6.2)
......@@ -621,6 +631,7 @@ DEPENDENCIES
devise (= 3.2.4)
devise-async (= 0.9.0)
diffy (~> 3.0.3)
doorkeeper (= 2.0.1)
dropzonejs-rails
email_spec
enumerize
......@@ -678,6 +689,7 @@ DEPENDENCIES
rack-attack
rack-cors
rack-mini-profiler
rack-oauth2 (~> 1.0.5)
rails (~> 4.1.0)
rails_autolink (~> 1.1)
rails_best_practices
......
......@@ -76,69 +76,30 @@ On [about.gitlab.com](https://about.gitlab.com/) you can find more information a
Please see [the installation page on the GitLab website](https://about.gitlab.com/installation/) for the various options.
Since a manual installation is a lot of work and error prone we strongly recommend the fast and reliable [Omnibus package installation](https://about.gitlab.com/downloads/) (deb/rpm).
You can access new installation with the login `root` and password `5iveL!fe`, after login you are required to set a unique password.
## Third-party applications
There are a lot of applications and API wrappers for GitLab.
Find them [on our website](https://about.gitlab.com/applications/).
### New versions
## New versions
Since 2011 a minor or major version of GitLab is released on the 22nd of every month. Patch and security releases come out when needed. New features are detailed on the [blog](https://about.gitlab.com/blog/) and in the [changelog](CHANGELOG). For more information about the release process see the release [documentation](https://gitlab.com/gitlab-org/gitlab-ce/tree/master/doc/release). Features that will likely be in the next releases can be found on the [feature request forum](http://feedback.gitlab.com/forums/176466-general) with the status [started](http://feedback.gitlab.com/forums/176466-general/status/796456) and [completed](http://feedback.gitlab.com/forums/176466-general/status/796457).
### Upgrading
## Upgrading
For updating the the Omnibus installation please see the [update documentation](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/doc/update.md). For manual installations there is an [upgrader script](doc/update/upgrader.md) and there are [upgrade guides](doc/update).
## Run in production mode
The Installation guide contains instructions on how to download an init script and run it automatically on boot. You can also start the init script manually:
sudo service gitlab start
or by directly calling the script:
sudo /etc/init.d/gitlab start
Please login with `root` / `5iveL!fe`
## Install a development environment
We recommend setting up your development environment with [the GitLab Development Kit](https://gitlab.com/gitlab-org/gitlab-development-kit).
If you do not use the development kit you might need to copy the example development unicorn configuration file
If you do not use the GitLab Development Development kit you need to install and setup all the dependencies yourself, this is a lot of work and error prone.
One small thing you also have to do when installing it yourself is to copy the example development unicorn configuration file:
cp config/unicorn.rb.example.development config/unicorn.rb
## Run in development mode
Start it with [Foreman](https://github.com/ddollar/foreman)
bundle exec foreman start -p 3000
or start each component separately:
bundle exec rails s
bin/background_jobs start
And surf to [localhost:3000](http://localhost:3000/) and login with `root` / `5iveL!fe`.
## Run the tests
- Run all tests:
bundle exec rake test
- [RSpec](http://rspec.info/) unit and functional tests.
All RSpec tests: `bundle exec rake spec`
Single RSpec file: `bundle exec rspec spec/controllers/commit_controller_spec.rb`
- [Spinach](https://github.com/codegram/spinach) integration tests.
All Spinach tests: `bundle exec rake spinach`
Single Spinach test: `bundle exec spinach features/project/issues/milestones.feature`
Instructions on how to start Gitlab and how to run the tests can be found in the [development section of the GitLab Development Kit](https://gitlab.com/gitlab-org/gitlab-development-kit#development).
## Documentation
......
......@@ -12,7 +12,7 @@ class @Activities
toggleFilter: (sender) ->
sender.parent().toggleClass "inactive"
sender.parent().toggleClass "active"
event_filters = $.cookie("event_filter")
filter = sender.attr("id").split("_")[0]
if event_filters
......
......@@ -51,12 +51,6 @@ window.ajaxGet = (url) ->
window.showAndHide = (selector) ->
window.errorMessage = (message) ->
ehtml = $("<p>")
ehtml.addClass("error_message")
ehtml.html(message)
ehtml
window.split = (val) ->
return val.split( /,\s*/ )
......
class @Issue
constructor: ->
$('.edit-issue.inline-update input[type="submit"]').hide()
$(".issue-box .inline-update").on "change", "select", ->
$(".context .inline-update").on "change", "select", ->
$(this).submit()
$(".issue-box .inline-update").on "change", "#issue_assignee_id", ->
$(".context .inline-update").on "change", "#issue_assignee_id", ->
$(this).submit()
if $("a.btn-close").length
......
......@@ -26,9 +26,9 @@ class @MergeRequest
initContextWidget: ->
$('.edit-merge_request.inline-update input[type="submit"]').hide()
$(".issue-box .inline-update").on "change", "select", ->
$(".context .inline-update").on "change", "select", ->
$(this).submit()
$(".issue-box .inline-update").on "change", "#merge_request_assignee_id", ->
$(".context .inline-update").on "change", "#merge_request_assignee_id", ->
$(this).submit()
initMergeWidget: ->
......@@ -89,6 +89,9 @@ class @MergeRequest
this.$('.merge-request-tabs .diffs-tab').addClass 'active'
this.loadDiff() unless @diffs_loaded
this.$('.diffs').show()
when 'commits'
this.$('.merge-request-tabs .commits-tab').addClass 'active'
this.$('.commits').show()
else
this.$('.merge-request-tabs .notes-tab').addClass 'active'
this.$('.notes').show()
......
......@@ -375,7 +375,7 @@ class @Notes
###
addDiffNote: (e) =>
e.preventDefault()
link = e.target
link = e.currentTarget
form = $(".js-new-note-form")
row = $(link).closest("tr")
nextRow = row.next()
......
......@@ -46,7 +46,7 @@ class @ContributorsGraph
class @ContributorsMasterGraph extends ContributorsGraph
constructor: (@data) ->
@width = $('.container').width() - 70
@width = $('.container').width() - 345
@height = 200
@x = null
@y = null
......@@ -119,7 +119,7 @@ class @ContributorsMasterGraph extends ContributorsGraph
class @ContributorsAuthorGraph extends ContributorsGraph
constructor: (@data) ->
@width = $('.container').width()/2 - 100
@width = $('.container').width()/2 - 225
@height = 200
@x = null
@y = null
......
/**
* Issue box:
* Huge block (one per page) for storing title, descripion and other information.
* Issue box for showing Open/Closed state:
* Used for Issue#show page, MergeRequest#show page etc
*
* CLasses:
* .issue-box - Regular box
*/
.issue-box {
color: #555;
margin:20px 0;
background: $box_bg;
@include box-shadow(0 1px 1px rgba(0, 0, 0, 0.09));
display: inline-block;
padding: 7px 13px;
font-weight: normal;
margin-right: 5px;
&.issue-box-closed {
.state {
background-color: #F3CECE;
border-color: $border_danger;
}
.state-label {
background-color: $bg_danger;
color: #FFF;
}
background-color: $bg_danger;
color: #FFF;
}
&.issue-box-merged {
.state {
background-color: #B7CEE7;
border-color: $border_primary;
}
.state-label {
background-color: $bg_primary;
color: #FFF;
}
background-color: $bg_primary;
color: #FFF;
}
&.issue-box-open {
.state {
background-color: #D6F1D7;
border-color: $bg_success;
}
.state-label {
background-color: $bg_success;
color: #FFF;
}
background-color: $bg_success;
color: #FFF;
}
&.issue-box-expired {
.state {
background-color: #EEE9B3;
border-color: #faebcc;
}
.state-label {
background: #cea61b;
color: #FFF;
}
}
.control-group {
margin-bottom: 0;
}
.state {
background-color: #f9f9f9;
}
.title {
font-size: 28px;
font-weight: normal;
line-height: 1.5;
margin: 0;
color: #333;
padding: 10px 15px;
}
.context {
border: none;
border-top: 1px solid #eee;
padding: 10px 15px;
// Reset text align for children
.text-right > * { text-align: left; }
@media (max-width: $screen-xs-max) {
// Don't right align on mobile
.text-right { text-align: left; }
.row .col-md-6 {
padding-top: 5px;
}
}
}
.description {
padding: 0 15px 10px 15px;
code {
white-space: pre-wrap;
}
}
.title, .context, .description {
.clearfix {
margin: 0;
}
}
.state-label {
font-size: 14px;
float: left;
font-weight: bold;
padding: 10px 15px;
}
.cross-project-ref {
float: left;
padding: 10px 15px;
}
.creator {
float: right;
padding: 10px 15px;
a {
text-decoration: underline;
}
background: #cea61b;
color: #FFF;
}
}
table {
&.table {
tr {
td, th {
padding: 8px 10px;
line-height: 20px;
vertical-align: middle;
}
th {
font-weight: normal;
font-size: 15px;
border-bottom: 1px solid #CCC !important;
}
td {
border-color: #F1F1F1 !important;
border-bottom: 1px solid;
}
}
}
}
......@@ -74,6 +74,42 @@
}
}
}
.system-note .timeline-entry-inner {
.timeline-icon {
background: none;
margin-left: 12px;
margin-top: 0;
@include box-shadow(none);
span {
margin: 0 2px;
font-size: 16px;
color: #eeeeee;
}
}
.timeline-content {
background: none;
margin-left: 45px;
padding: 0px 15px;
&:after { border: 0; }
.note-header {
span { font-size: 12px; }
.avatar {
margin-right: 5px;
}
}
.note-text {
font-size: 12px;
margin-left: 20px;
}
}
}
}
@media (max-width: $screen-xs-max) {
......
......@@ -148,6 +148,10 @@ $list-group-active-bg: $bg_primary;
color: #666;
}
.nav-compact > li > a {
padding: 6px 12px;
}
.nav-small > li > a {
padding: 3px 5px;
font-size: 12px;
......
......@@ -4,10 +4,6 @@ html {
&.touch .tooltip { display: none !important; }
}
body {
padding-bottom: 20px;
}
.container {
padding-top: 0;
z-index: 5;
......
......@@ -44,6 +44,6 @@ $added: #63c363;
$deleted: #f77;
/**
*
* NProgress customize
*/
$nprogress-color: #3498db;
......@@ -23,20 +23,6 @@
}
}
.dashboard {
.dash-filter {
width: 205px;
float: left;
height: inherit;
}
}
@media (max-width: 1200px) {
.dashboard .dash-filter {
width: 140px;
}
}
.dash-sidebar-tabs {
margin-bottom: 2px;
border: none;
......
......@@ -140,36 +140,6 @@
}
}
/**
* Event filter
*
*/
.event_filter {
position: absolute;
width: 40px;
margin-left: -55px;
.filter_icon {
a {
text-align:center;
background: $bg_primary;
margin-bottom: 10px;
float: left;
padding: 9px 6px;
font-size: 18px;
width: 40px;
color: #FFF;
@include border-radius(3px);
}
&.inactive {
a {
color: #DDD;
background: #f9f9f9;
}
}
}
}
/*
* Last push widget
......@@ -203,3 +173,7 @@
}
}
}
.event_filter li a {
padding: 5px 10px;
}
......@@ -52,8 +52,6 @@ header {
border-width: 0;
font-size: 18px;
.app_logo { margin-left: -15px; }
.title {
@include str-truncated(70%);
}
......@@ -86,6 +84,11 @@ header {
z-index: 10;
.container {
width: 100% !important;
padding-left: 0px;
}
/**
*
* Logo holder
......@@ -232,21 +235,6 @@ header {
color: #fff;
}
}
.app_logo {
.separator {
margin-left: 0;
margin-right: 0;
}
}
.separator {
float: left;
height: 46px;
width: 2px;
margin-left: 10px;
margin-right: 10px;
}
}
.search .search-input {
......
......@@ -162,3 +162,7 @@ form.edit-issue {
}
}
}
.issue-title {
margin-top: 0;
}
......@@ -19,17 +19,15 @@
}
}
.merge-request .merge-request-tabs{
border-bottom: 2px solid $border_primary;
margin: 20px 0;
li {
a {
padding: 15px 40px;
font-size: 14px;
margin-bottom: -2px;
border-bottom: 2px solid $border_primary;
@include border-radius(0px);
@media(min-width: $screen-sm-max) {
.merge-request .merge-request-tabs{
margin: 20px 0;
li {
a {
padding: 15px 40px;
font-size: 14px;
}
}
}
}
......@@ -106,6 +104,7 @@
.mr-state-widget {
background: $box_bg;
margin-bottom: 20px;
color: #666;
@include box-shadow(0 1px 1px rgba(0, 0, 0, 0.09));
.ci_widget {
......@@ -150,7 +149,6 @@
padding: 10px 15px;
h4 {
font-size: 20px;
font-weight: normal;
}
......
.main-nav {
background: #f5f5f5;
margin: 20px 0;
margin-top: 0;
padding-top: 4px;
border-bottom: 1px solid #E9E9E9;
ul {
padding: 0;
margin: auto;
.count {
font-weight: normal;
display: inline-block;
height: 15px;
padding: 1px 6px;
height: auto;
font-size: 0.82em;
line-height: 14px;
text-align: center;
color: #777;
background: #eee;
@include border-radius(8px);
}
.label {
background: $hover;
text-shadow: none;
color: $style_color;
}
li {
list-style-type: none;
margin: 0;
display: table-cell;
width: 1%;
&.active {
a {
color: $link_color;
font-weight: bold;
border-bottom: 3px solid $link_color;
}
}
&:hover {
a {
color: $link_hover_color;
border-bottom: 3px solid $link_hover_color;
}
}
}
a {
display: block;
text-align: center;
font-weight: bold;
height: 42px;
line-height: 39px;
color: #777;
text-shadow: 0 1px 1px white;
text-decoration: none;
overflow: hidden;
margin-bottom: -1px;
}
}
@media (max-width: $screen-xs-max) {
font-size: 18px;
margin: 0;
max-height: none;
&, .container {
padding: 0;
border-top: 0;
}
ul {
height: auto;
li {
display: list-item;
width: auto;
padding: 5px 0;
&.active {
background-color: $link_hover_color;
a {
color: #fff;
font-weight: normal;
text-shadow: none;
border: none;
&:after { display: none; }
}
}
}
}
}
}
......@@ -155,19 +155,26 @@ ul.notes {
}
.add-diff-note {
background: image-url("diff_note_add.png") no-repeat left 0;
border: none;
height: 22px;
margin-left: -65px;
margin-top: -4px;
@include border-radius(40px);
background: #FFF;
padding: 4px;
font-size: 16px;
color: $link_color;
margin-left: -60px;
position: absolute;
width: 22px;
z-index: 10;
transition: all 0.2s ease;
// "hide" it by default
opacity: 0.0;
filter: alpha(opacity=0);
&:hover {
font-size: 24px;
background: $bg_primary;
color: #FFF;
@include show-add-diff-note;
}
}
......
.page-with-sidebar {
background: #F5F5F5;
}
.sidebar-wrapper {
overflow-y: auto;
background: #F5F5F5;
}
.content-wrapper {
width: 100%;
padding: 15px;
background: #FFF;
}
.nav-sidebar {
margin: 0;
list-style: none;
&.navbar-collapse {
padding: 0px !important;
}
}
.nav-sidebar li a .count {
float: right;
background: #eee;
padding: 0px 8px;
@include border-radius(6px);
}
.nav-sidebar li {
&.active a {
color: #111;
background: #EEE;
font-weight: bold;
&.no-highlight {
background: none;
}
i {
color: #444;
}
}
}
.nav-sidebar li {
&.separate-item {
border-top: 1px solid #ddd;
padding-top: 10px;
margin-top: 10px;
}
a {
color: #555;
display: block;
text-decoration: none;
padding: 6px 15px;
font-size: 13px;
line-height: 20px;
text-shadow: 0 1px 2px #FFF;
padding-left: 20px;
&:hover {
text-decoration: none;
color: #333;
background: #DDD;
}
&:active, &:focus {
text-decoration: none;
}
i {
width: 20px;
color: #888;
margin-right: 23px;
}
}
}
.sidebar-subnav {
margin-left: 0px;
padding-left: 0px;
li {
line-height: 28px;
font-size: 12px;
list-style: none;
a {
padding: 5px 15px;
font-size: 12px;
padding-left: 20px;
}
}
}
@mixin expanded-sidebar {
.page-with-sidebar {
padding-left: 250px;
}
.sidebar-wrapper {
width: 250px;
position: absolute;
left: 250px;
height: 100%;
margin-left: -250px;
.nav-sidebar {
margin-top: 20px;
position: fixed;
top: 45px;
width: 250px;
}
}
.content-wrapper {
padding: 20px;
border-left: 1px solid #EAEAEA;
}
}
@mixin folded-sidebar {
.page-with-sidebar {
padding-left: 50px;
}
.sidebar-wrapper {
width: 52px;
position: absolute;
left: 50px;
height: 100%;
margin-left: -50px;
.nav-sidebar {
margin-top: 20px;
position: fixed;
top: 45px;
width: 52px;
li a {
padding-left: 18px;
font-size: 14px;
padding: 10px 15px;
text-align: center;
& > span {
display: none;
}
}
}
}
}
@media (max-width: $screen-sm-max) {
@include folded-sidebar;
}
@media(min-width: $screen-sm-max) {
@include expanded-sidebar;
}
......@@ -17,19 +17,6 @@
@include border-radius(0);
tr {
td, th {
padding: 8px 10px;
line-height: 20px;
}
th {
font-weight: normal;
font-size: 15px;
border-bottom: 1px solid #CCC !important;
}
td {
border-color: #F1F1F1 !important;
border-bottom: 1px solid;
}
&:hover {
td {
background: $hover;
......
......@@ -37,13 +37,3 @@
margin: 0 8px;
}
.votes-holder {
float: right;
width: 250px;
@media (max-width: $screen-xs-max) {
width: 100%;
margin-top: 5px;
margin-bottom: 10px;
}
}
......@@ -9,17 +9,15 @@
.navbar-inner {
background: #F1F1F1;
border-bottom: 1px solid #DDD;
.app_logo {
background-color: #DDD;
}
.nav > li > a {
color: $style_color;
}
.separator {
background: #F9F9F9;
border-left: 1px solid #DDD;
}
}
}
}
.main-nav {
background: #FFF;
}
}
......@@ -23,9 +23,8 @@
background-color: #436;
}
}
.separator {
background: #436;
border-left: 1px solid #659;
.app_logo {
background-color: #325;
}
.nav > li > a {
color: #98C;
......
......@@ -23,9 +23,8 @@
background-color: #272727;
}
}
.separator {
background: #272727;
border-left: 1px solid #474747;
.app_logo {
background-color: #222;
}
}
}
......
......@@ -23,9 +23,8 @@
background-color: #373D47;
}
}
.separator {
background: #373D47;
border-left: 1px solid #575D67;
.app_logo {
background-color: #24272D;
}
.nav > li > a {
color: #979DA7;
......
......@@ -23,9 +23,8 @@
background-color: #018865;
}
}
.separator {
background: #018865;
border-left: 1px solid #11A885;
.app_logo {
background-color: #017855;
}
.nav > li > a {
color: #ADC;
......
......@@ -21,7 +21,7 @@ class Admin::GroupsController < Admin::ApplicationController
def create
@group = Group.new(group_params)
@group.path = @group.name.dup.parameterize if @group.name
@group.name = @group.path.dup unless @group.name
if @group.save
@group.add_owner(current_user)
......
......@@ -245,4 +245,67 @@ class ApplicationController < ActionController::Base
render_404 and return
end
end
def set_filters_params
params[:sort] ||= 'newest'
params[:scope] = 'all' if params[:scope].blank?
params[:state] = 'opened' if params[:state].blank?
@filter_params = params.dup
if @project
@filter_params[:project_id] = @project.id
elsif @group
@filter_params[:group_id] = @group.id
else
# TODO: this filter ignore issues/mr created in public or
# internal repos where you are not a member. Enable this filter
# or improve current implementation to filter only issues you
# created or assigned or mentioned
#@filter_params[:authorized_only] = true
unless @filter_params[:assignee_id]
@filter_params[:assignee_id] = current_user.id
end
end
@filter_params
end
def set_filter_values(collection)
assignee_id = @filter_params[:assignee_id]
author_id = @filter_params[:author_id]
milestone_id = @filter_params[:milestone_id]
@sort = @filter_params[:sort].try(:humanize)
@assignees = User.where(id: collection.pluck(:assignee_id))
@authors = User.where(id: collection.pluck(:author_id))
@milestones = Milestone.where(id: collection.pluck(:milestone_id))
if assignee_id.present? && !assignee_id.to_i.zero?
@assignee = @assignees.find_by(id: assignee_id)
end
if author_id.present? && !author_id.to_i.zero?
@author = @authors.find_by(id: author_id)
end
if milestone_id.present? && !milestone_id.to_i.zero?
@milestone = @milestones.find_by(id: milestone_id)
end
end
def get_issues_collection
set_filters_params
issues = IssuesFinder.new.execute(current_user, @filter_params)
set_filter_values(issues)
issues
end
def get_merge_requests_collection
set_filters_params
merge_requests = MergeRequestsFinder.new.execute(current_user, @filter_params)
set_filter_values(merge_requests)
merge_requests
end
end
......@@ -3,8 +3,6 @@ class DashboardController < ApplicationController
before_filter :load_projects, except: [:projects]
before_filter :event_filter, only: :show
before_filter :default_filter, only: [:issues, :merge_requests]
def show
# Fetch only 30 projects.
......@@ -55,13 +53,13 @@ class DashboardController < ApplicationController
end
def merge_requests
@merge_requests = MergeRequestsFinder.new.execute(current_user, params)
@merge_requests = get_merge_requests_collection
@merge_requests = @merge_requests.page(params[:page]).per(20)
@merge_requests = @merge_requests.preload(:author, :target_project)
end
def issues
@issues = IssuesFinder.new.execute(current_user, params)
@issues = get_issues_collection
@issues = @issues.page(params[:page]).per(20)
@issues = @issues.preload(:author, :project)
......@@ -76,10 +74,4 @@ class DashboardController < ApplicationController
def load_projects
@projects = current_user.authorized_projects.sorted_by_activity.non_archived
end
def default_filter
params[:scope] = 'assigned-to-me' if params[:scope].blank?
params[:state] = 'opened' if params[:state].blank?
params[:authorized_only] = true
end
end
......@@ -11,8 +11,6 @@ class GroupsController < ApplicationController
# Load group projects
before_filter :load_projects, except: [:new, :create, :projects, :edit, :update]
before_filter :default_filter, only: [:issues, :merge_requests]
layout :determine_layout
before_filter :set_title, only: [:new, :create]
......@@ -23,7 +21,7 @@ class GroupsController < ApplicationController
def create
@group = Group.new(group_params)
@group.path = @group.name.dup.parameterize if @group.name
@group.name = @group.path.dup unless @group.name
if @group.save
@group.add_owner(current_user)
......@@ -49,13 +47,13 @@ class GroupsController < ApplicationController
end
def merge_requests
@merge_requests = MergeRequestsFinder.new.execute(current_user, params)
@merge_requests = get_merge_requests_collection
@merge_requests = @merge_requests.page(params[:page]).per(20)
@merge_requests = @merge_requests.preload(:author, :target_project)
end
def issues
@issues = IssuesFinder.new.execute(current_user, params)
@issues = get_issues_collection
@issues = @issues.page(params[:page]).per(20)
@issues = @issues.preload(:author, :project)
......@@ -150,18 +148,6 @@ class GroupsController < ApplicationController
end
end
def default_filter
if params[:scope].blank?
if current_user
params[:scope] = 'assigned-to-me'
else
params[:scope] = 'all'
end
end
params[:state] = 'opened' if params[:state].blank?
params[:group_id] = @group.id
end
def group_params
params.require(:group).permit(:name, :description, :path, :avatar, :membership_lock)
end
......
class Oauth::ApplicationsController < Doorkeeper::ApplicationsController
before_filter :authenticate_user!
layout "profile"
def index
head :forbidden and return
end
def create
@application = Doorkeeper::Application.new(application_params)
if Doorkeeper.configuration.confirm_application_owner?
@application.owner = current_user
end
if @application.save
flash[:notice] = I18n.t(:notice, scope: [:doorkeeper, :flash, :applications, :create])
redirect_to oauth_application_url(@application)
else
render :new
end
end
def destroy
if @application.destroy
flash[:notice] = I18n.t(:notice, scope: [:doorkeeper, :flash, :applications, :destroy])
end
redirect_to applications_profile_url
end
private
def set_application
@application = current_user.oauth_applications.find(params[:id])
end
rescue_from ActiveRecord::RecordNotFound do |exception|
render "errors/not_found", layout: "errors", status: 404
end
end
class Oauth::AuthorizationsController < Doorkeeper::AuthorizationsController
before_filter :authenticate_resource_owner!
layout "profile"
def new
if pre_auth.authorizable?
if skip_authorization? || matching_token?
auth = authorization.authorize
redirect_to auth.redirect_uri
else
render "doorkeeper/authorizations/new"
end
else
render "doorkeeper/authorizations/error"
end
end
# TODO: Handle raise invalid authorization
def create
redirect_or_render authorization.authorize
end
def destroy
redirect_or_render authorization.deny
end
private
def matching_token?
Doorkeeper::AccessToken.matching_token_for(pre_auth.client,
current_resource_owner.id,
pre_auth.scopes)
end
def redirect_or_render(auth)
if auth.redirectable?
redirect_to auth.redirect_uri
else
render json: auth.body, status: auth.status
end
end
def pre_auth
@pre_auth ||=
Doorkeeper::OAuth::PreAuthorization.new(Doorkeeper.configuration,
server.client_via_uid,
params)
end
def authorization
@authorization ||= strategy.request
end
def strategy
@strategy ||= server.authorization_request(pre_auth.response_type)
end
end
class Oauth::AuthorizedApplicationsController < Doorkeeper::AuthorizedApplicationsController
layout "profile"
def destroy
Doorkeeper::AccessToken.revoke_all_for(params[:id], current_resource_owner)
redirect_to applications_profile_url, notice: I18n.t(:notice, scope: [:doorkeeper, :flash, :authorized_applications, :destroy])
end
end
......@@ -13,6 +13,11 @@ class ProfilesController < ApplicationController
def design
end
def applications
@applications = current_user.oauth_applications
@authorized_tokens = current_user.oauth_authorized_tokens
end
def update
user_params.except!(:email) if @user.ldap_user?
......
......@@ -29,31 +29,4 @@ class Projects::ApplicationController < ApplicationController
redirect_to project_tree_path(@project, @ref), notice: "This action is not allowed unless you are on top of a branch"
end
end
def set_filter_variables(collection)
params[:sort] ||= 'newest'
params[:scope] = 'all' if params[:scope].blank?
params[:state] = 'opened' if params[:state].blank?
@sort = params[:sort].humanize
assignee_id = params[:assignee_id]
author_id = params[:author_id]
milestone_id = params[:milestone_id]
if assignee_id.present? && !assignee_id.to_i.zero?
@assignee = @project.team.find(assignee_id)
end
if author_id.present? && !author_id.to_i.zero?
@author = @project.team.find(assignee_id)
end
if milestone_id.present? && !milestone_id.to_i.zero?
@milestone = @project.milestones.find(milestone_id)
end
@assignees = User.where(id: collection.pluck(:assignee_id))
@authors = User.where(id: collection.pluck(:author_id))
end
end
......@@ -18,9 +18,7 @@ class Projects::IssuesController < Projects::ApplicationController
def index
terms = params['issue_search']
set_filter_variables(@project.issues)
@issues = IssuesFinder.new.execute(current_user, params.merge(project_id: @project.id))
@issues = get_issues_collection
@issues = @issues.full_search(terms) if terms.present?
@issues = @issues.page(params[:page]).per(20)
......
......@@ -17,9 +17,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
before_filter :authorize_modify_merge_request!, only: [:close, :edit, :update, :sort]
def index
set_filter_variables(@project.merge_requests)
@merge_requests = MergeRequestsFinder.new.execute(current_user, params.merge(project_id: @project.id))
@merge_requests = get_merge_requests_collection
@merge_requests = @merge_requests.page(params[:page]).per(20)
end
......
......@@ -44,6 +44,9 @@ class ProjectsController < ApplicationController
def transfer
::Projects::TransferService.new(project, current_user, project_params).execute
if @project.errors[:namespace_id].present?
flash[:alert] = @project.errors[:namespace_id].first
end
end
def show
......
......@@ -114,6 +114,10 @@ module ApplicationHelper
Gitlab::Theme.css_class_by_id(current_user.try(:theme_id))
end
def theme_type
Gitlab::Theme.type_css_class_by_id(current_user.try(:theme_id))
end
def user_color_scheme_class
COLOR_SCHEMES[current_user.try(:color_scheme_id)] if defined?(current_user)
end
......@@ -271,4 +275,22 @@ module ApplicationHelper
def promo_url
'https://' + promo_host
end
def page_filter_path(options={})
exist_opts = {
state: params[:state],
scope: params[:scope],
label_name: params[:label_name],
milestone_id: params[:milestone_id],
assignee_id: params[:assignee_id],
author_id: params[:author_id],
sort: params[:sort],
}
options = exist_opts.merge(options)
path = request.path
path << "?#{options.to_param}"
path
end
end
module DashboardHelper
def filter_path(entity, options={})
exist_opts = {
state: params[:state],
scope: params[:scope],
project_id: params[:project_id],
}
options = exist_opts.merge(options)
path = request.path
path << "?#{options.to_param}"
path
end
def entities_per_project(project, entity)
case entity.to_sym
when :issue then @issues.where(project_id: project.id)
......
......@@ -117,4 +117,22 @@ module DiffHelper
[comments_left, comments_right]
end
def inline_diff_btn
params_copy = params.dup
params_copy[:view] = 'inline'
link_to url_for(params_copy), id: "commit-diff-viewtype", class: (params[:view] != 'parallel' ? 'btn active' : 'btn') do
'Inline'
end
end
def parallel_diff_btn
params_copy = params.dup
params_copy[:view] = 'parallel'
link_to url_for(params_copy), id: "commit-diff-viewtype", class: (params[:view] == 'parallel' ? 'btn active' : 'btn') do
'Side-by-side'
end
end
end
......@@ -21,15 +21,14 @@ module EventsHelper
def event_filter_link(key, tooltip)
key = key.to_s
inactive = if @event_filter.active? key
nil
else
'inactive'
end
active = if @event_filter.active? key
'active'
end
content_tag :div, class: "filter_icon #{inactive}" do
content_tag :li, class: "filter_icon #{active}" do
link_to request.path, class: 'has_tooltip event_filter_link', id: "#{key}_event_filter", 'data-original-title' => tooltip do
content_tag :i, nil, class: icon_for_event[key]
content_tag(:i, nil, class: icon_for_event[key]) +
content_tag(:span, ' ' + tooltip)
end
end
end
......
......@@ -44,4 +44,14 @@ module GroupsHelper
path << "?#{options.to_param}"
path
end
def group_settings_page?
if current_controller?('groups')
current_action?('edit') || current_action?('projects')
elsif current_controller?('ldap_group_links') || current_controller?('audit_events')
true
else
false
end
end
end
......@@ -52,8 +52,11 @@ module NotesHelper
discussion_id: discussion_id
}
button_tag '', class: 'btn add-diff-note js-add-diff-note-button',
data: data, title: 'Add a comment to this line'
button_tag(class: 'btn add-diff-note js-add-diff-note-button',
data: data,
title: 'Add a comment to this line') do
content_tag :i, nil, class: 'fa fa-comment-o'
end
end
def link_to_reply_diff(note)
......
......@@ -68,48 +68,6 @@ module ProjectsHelper
project_nav_tabs.include? name
end
def selected_label?(label_name)
params[:label_name].to_s.split(',').include?(label_name)
end
def labels_filter_path(label_name)
label_name =
if selected_label?(label_name)
params[:label_name].split(',').reject { |l| l == label_name }.join(',')
elsif params[:label_name].present?
"#{params[:label_name]},#{label_name}"
else
label_name
end
project_filter_path(label_name: label_name)
end
def label_filter_class(label_name)
if selected_label?(label_name)
'label-filter-item active'
else
'label-filter-item light'
end
end
def project_filter_path(options={})
exist_opts = {
state: params[:state],
scope: params[:scope],
label_name: params[:label_name],
milestone_id: params[:milestone_id],
assignee_id: params[:assignee_id],
sort: params[:sort],
}
options = exist_opts.merge(options)
path = request.path
path << "?#{options.to_param}"
path
end
def project_active_milestones
@project.milestones.active.order("due_date, title ASC")
end
......
......@@ -28,6 +28,10 @@ module TabHelper
# nav_link(controller: [:tree, :refs]) { "Hello" }
# # => '<li class="active">Hello</li>'
#
# # Several paths
# nav_link(path: ['tree#show', 'profile#show']) { "Hello" }
# # => '<li class="active">Hello</li>'
#
# # Shorthand path
# nav_link(path: 'tree#show') { "Hello" }
# # => '<li class="active">Hello</li>'
......@@ -38,25 +42,7 @@ module TabHelper
#
# Returns a list item element String
def nav_link(options = {}, &block)
if path = options.delete(:path)
if path.respond_to?(:each)
c = path.map { |p| p.split('#').first }
a = path.map { |p| p.split('#').last }
else
c, a, _ = path.split('#')
end
else
c = options.delete(:controller)
a = options.delete(:action)
end
if c && a
# When given both options, make sure BOTH are active
klass = current_controller?(*c) && current_action?(*a) ? 'active' : ''
else
# Otherwise check EITHER option
klass = current_controller?(*c) || current_action?(*a) ? 'active' : ''
end
klass = active_nav_link?(options) ? 'active' : ''
# Add our custom class into the html_options, which may or may not exist
# and which may or may not already have a :class key
......@@ -72,6 +58,34 @@ module TabHelper
end
end
def active_nav_link?(options)
if path = options.delete(:path)
unless path.respond_to?(:each)
path = [path]
end
path.any? do |single_path|
current_path?(single_path)
end
else
c = options.delete(:controller)
a = options.delete(:action)
if c && a
# When given both options, make sure BOTH are true
current_controller?(*c) && current_action?(*a)
else
# Otherwise check EITHER option
current_controller?(*c) || current_action?(*a)
end
end
end
def current_path?(path)
c, a, _ = path.split('#')
current_controller?(c) && current_action?(a)
end
def project_tab_class
return "active" if current_page?(controller: "/projects", action: :edit, id: @project)
......
......@@ -53,13 +53,41 @@ module TreeHelper
File.join(*args)
end
def allowed_tree_edit?
return false unless @repository.branch_names.include?(@ref)
def allowed_tree_edit?(project = nil, ref = nil)
project ||= @project
ref ||= @ref
return false unless project.repository.branch_names.include?(ref)
if @project.protected_branch? @ref
can?(current_user, :push_code_to_protected_branches, @project)
if project.protected_branch? ref
can?(current_user, :push_code_to_protected_branches, project)
else
can?(current_user, :push_code, @project)
can?(current_user, :push_code, project)
end
end
def edit_blob_link(project, ref, path, options = {})
blob =
begin
project.repository.blob_at(ref, path)
rescue
nil
end
if blob && blob.text?
text = 'Edit'
after = options[:after] || ''
from_mr = options[:from_merge_request_id]
link_opts = {}
link_opts[:from_merge_request_id] = from_mr if from_mr
cls = 'btn btn-small'
if allowed_tree_edit?(project, ref)
link_to text, project_edit_tree_path(project, tree_join(ref, path),
link_opts), class: cls
else
content_tag :span, text, class: cls + ' disabled'
end + after.html_safe
else
''
end
end
......
......@@ -106,6 +106,7 @@ class User < ActiveRecord::Base
has_many :recent_events, -> { order "id DESC" }, foreign_key: :author_id, class_name: "Event"
has_many :assigned_issues, dependent: :destroy, foreign_key: :assignee_id, class_name: "Issue"
has_many :assigned_merge_requests, dependent: :destroy, foreign_key: :assignee_id, class_name: "MergeRequest"
has_many :oauth_applications, class_name: 'Doorkeeper::Application', as: :owner, dependent: :destroy
#
......@@ -575,4 +576,8 @@ class User < ActiveRecord::Base
namespaces += masters_groups
end
end
def oauth_authorized_tokens
Doorkeeper::AccessToken.where(resource_owner_id: self.id, revoked_at: nil)
end
end
module Oauth2::AccessTokenValidationService
# Results:
VALID = :valid
EXPIRED = :expired
REVOKED = :revoked
INSUFFICIENT_SCOPE = :insufficient_scope
class << self
def validate(token, scopes: [])
if token.expired?
return EXPIRED
elsif token.revoked?
return REVOKED
elsif !self.sufficent_scope?(token, scopes)
return INSUFFICIENT_SCOPE
else
return VALID
end
end
protected
# True if the token's scope is a superset of required scopes,
# or the required scopes is empty.
def sufficent_scope?(token, scopes)
if scopes.blank?
# if no any scopes required, the scopes of token is sufficient.
return true
else
# If there are scopes required, then check whether
# the set of authorized scopes is a superset of the set of required scopes
required_scopes = Set.new(scopes)
authorized_scopes = Set.new(token.scopes)
return authorized_scopes >= required_scopes
end
end
end
end
\ No newline at end of file
......@@ -12,12 +12,17 @@ module Projects
@project.visibility_level = default_features.visibility_level
end
# Parametrize path for project
#
# Ex.
# 'GitLab HQ'.parameterize => "gitlab-hq"
#
@project.path = @project.name.dup.parameterize unless @project.path.present?
# Set project name from path
if @project.name.present? && @project.path.present?
# if both name and path set - everything is ok
elsif @project.path.present?
# Set project name from path
@project.name = @project.path.dup
elsif @project.name.present?
# For compatibility - set path from name
# TODO: remove this in 8.0
@project.path = @project.name.dup.parameterize
end
# get namespace id
namespace_id = params[:namespace_id]
......
......@@ -21,18 +21,6 @@
= link_to 'Cancel', admin_groups_path, class: "btn btn-cancel"
- else
.form-group.group_name_holder
= f.label :path, class: 'control-label' do
%span Group path
.col-sm-10
= f.text_field :path, placeholder: "example-group", class: "form-control danger"
.bs-callout.bs-callout-danger
%ul
%li Changing group path can have unintended side effects.
%li Renaming group path will rename directory for all related projects
%li It will change web url for access group and group projects.
%li It will change the git path to repositories under this group.
.form-actions
= f.submit 'Save changes', class: "btn btn-primary"
= link_to 'Cancel', admin_group_path(@group), class: "btn btn-cancel"
......
.row
.col-md-2
= render 'groups/settings_nav'
%h3.page-title Group Audit Events
%p.light Events in #{@group.name}
.col-md-10
%h3.page-title Group Audit Events
%p.light Events in #{@group.name}
= render 'event_table', events: @events
= render 'event_table', events: @events
.panel.panel-default
.panel-heading.clearfix
= search_field_tag :filter_group, nil, placeholder: 'Filter by name', class: 'dash-filter form-control'
- if current_user.can_create_group?
= link_to new_group_path, class: "btn btn-new pull-right" do
%i.fa.fa-plus
New group
.input-group
= search_field_tag :filter_group, nil, placeholder: 'Filter by name', class: 'dash-filter form-control'
- if current_user.can_create_group?
.input-group-addon
= link_to new_group_path, class: "" do
%strong New group
%ul.well-list.dash-list
- groups.each do |group|
%li.group-row
......
.panel.panel-default
.panel-heading.clearfix
= search_field_tag :filter_projects, nil, placeholder: 'Filter by name', class: 'dash-filter form-control'
- if current_user.can_create_project?
= link_to new_project_path, class: "btn btn-new pull-right" do
%i.fa.fa-plus
New project
.input-group
= search_field_tag :filter_projects, nil, placeholder: 'Filter by name', class: 'dash-filter form-control'
- if current_user.can_create_project?
.input-group-addon
= link_to new_project_path, class: "" do
%strong New project
%ul.well-list.dash-list
- projects.each do |project|
......
......@@ -15,11 +15,4 @@
= render "groups", groups: @groups
.prepend-top-20
%span.rss-icon
= link_to dashboard_path(:atom, { private_token: current_user.private_token }) do
%strong
%i.fa.fa-rss
News Feed
%hr
= render 'shared/promo'
= render 'shared/promo'
......@@ -5,10 +5,6 @@
List all issues from all projects you have access to.
%hr
.row
.fixed.sidebar-expand-button.hidden-lg.hidden-md
%i.fa.fa-list.fa-2x
.col-md-3.responsive-side
= render 'shared/filter', entity: 'issue'
.col-md-9
= render 'shared/issues'
.append-bottom-20
= render 'shared/issuable_filter'
= render 'shared/issues'
......@@ -5,10 +5,6 @@
%p.light
List all merge requests from all projects you have access to.
%hr
.row
.fixed.sidebar-expand-button.hidden-lg.hidden-md
%i.fa.fa-list.fa-2x
.col-md-3.responsive-side
= render 'shared/filter', entity: 'merge_request'
.col-md-9
= render 'shared/merge_requests'
.append-bottom-20
= render 'shared/issuable_filter'
= render 'shared/merge_requests'
......@@ -38,17 +38,19 @@
= link_to project_path(project), class: dom_class(project) do
= project.name_with_namespace
- if project.forked_from_project
&nbsp;
%small
%i.fa.fa-code-fork
Forked from:
= link_to project.forked_from_project.name_with_namespace, project_path(project.forked_from_project)
- if current_user.can_leave_project?(project)
.pull-right
= link_to leave_project_team_members_path(project), data: { confirm: "Leave project?"}, method: :delete, remote: true, class: "btn-tiny btn remove-row", title: 'Leave project' do
%i.fa.fa-sign-out
Leave
- if project.forked_from_project
%small.pull-right
%i.fa.fa-code-fork
Forked from:
= link_to project.forked_from_project.name_with_namespace, project_path(project.forked_from_project)
.project-info
.pull-right
- if project.archived?
......
- submit_btn_css ||= 'btn btn-link btn-remove btn-small'
= form_tag oauth_application_path(application) do
%input{:name => "_method", :type => "hidden", :value => "delete"}/
= submit_tag 'Destroy', onclick: "return confirm('Are you sure?')", class: submit_btn_css
\ No newline at end of file
= form_for application, url: doorkeeper_submit_path(application), html: {class: 'form-horizontal', role: 'form'} do |f|
- if application.errors.any?
.alert.alert-danger{"data-alert" => ""}
%p Whoops! Check your form for possible errors
= content_tag :div, class: "form-group#{' has-error' if application.errors[:name].present?}" do
= f.label :name, class: 'col-sm-2 control-label'
.col-sm-10
= f.text_field :name, class: 'form-control'
= doorkeeper_errors_for application, :name
= content_tag :div, class: "form-group#{' has-error' if application.errors[:redirect_uri].present?}" do
= f.label :redirect_uri, class: 'col-sm-2 control-label'
.col-sm-10
= f.text_area :redirect_uri, class: 'form-control'
= doorkeeper_errors_for application, :redirect_uri
%span.help-block
Use one line per URI
- if Doorkeeper.configuration.native_redirect_uri
%span.help-block
Use
%code= Doorkeeper.configuration.native_redirect_uri
for local tests
.form-actions
= f.submit 'Submit', class: "btn btn-primary wide"
= link_to "Cancel", applications_profile_path, class: "btn btn-default"
%h3.page-title Edit application
= render 'form', application: @application
\ No newline at end of file
%h3.page-title Your applications
%p= link_to 'New Application', new_oauth_application_path, class: 'btn btn-success'
%table.table.table-striped
%thead
%tr
%th Name
%th Callback URL
%th
%th
%tbody
- @applications.each do |application|
%tr{:id => "application_#{application.id}"}
%td= link_to application.name, oauth_application_path(application)
%td= application.redirect_uri
%td= link_to 'Edit', edit_oauth_application_path(application), class: 'btn btn-link'
%td= render 'delete_form', application: application
\ No newline at end of file
%h3.page-title New application
= render 'form', application: @application
\ No newline at end of file
%h3.page-title
Application: #{@application.name}
%table.table
%tr
%td
Application Id
%td
%code#application_id= @application.uid
%tr
%td
Secret:
%td
%code#secret= @application.secret
%tr
%td
Callback url
%td
- @application.redirect_uri.split.each do |uri|
%div
%span.monospace= uri
.form-actions
= link_to 'Edit', edit_oauth_application_path(@application), class: 'btn btn-primary wide pull-left'
= render 'delete_form', application: @application, submit_btn_css: 'btn btn-danger prepend-left-10'
%h3.page-title An error has occurred
%main{:role => "main"}
%pre= @pre_auth.error_response.body[:error_description]
\ No newline at end of file
%h3.page-title Authorize required
%main{:role => "main"}
%p.h4
Authorize
%strong.text-info= @pre_auth.client.name
to use your account?
- if @pre_auth.scopes
#oauth-permissions
%p This application will be able to:
%ul.text-info
- @pre_auth.scopes.each do |scope|
%li= t scope, scope: [:doorkeeper, :scopes]
%hr/
.actions
= form_tag oauth_authorization_path, method: :post do
= hidden_field_tag :client_id, @pre_auth.client.uid
= hidden_field_tag :redirect_uri, @pre_auth.redirect_uri
= hidden_field_tag :state, @pre_auth.state
= hidden_field_tag :response_type, @pre_auth.response_type
= hidden_field_tag :scope, @pre_auth.scope
= submit_tag "Authorize", class: "btn btn-success wide pull-left"
= form_tag oauth_authorization_path, method: :delete do
= hidden_field_tag :client_id, @pre_auth.client.uid
= hidden_field_tag :redirect_uri, @pre_auth.redirect_uri
= hidden_field_tag :state, @pre_auth.state
= hidden_field_tag :response_type, @pre_auth.response_type
= hidden_field_tag :scope, @pre_auth.scope
= submit_tag "Deny", class: "btn btn-danger prepend-left-10"
\ No newline at end of file
%h3.page-title Authorization code:
%main{:role => "main"}
%code#authorization_code= params[:code]
\ No newline at end of file
- submit_btn_css ||= 'btn btn-link btn-remove'
= form_tag oauth_authorized_application_path(application) do
%input{:name => "_method", :type => "hidden", :value => "delete"}/
= submit_tag 'Revoke', onclick: "return confirm('Are you sure?')", class: 'btn btn-link btn-remove btn-small'
\ No newline at end of file
%header.page-header
%h1 Your authorized applications
%main{:role => "main"}
%table.table.table-striped
%thead
%tr
%th Application
%th Created At
%th
%th
%tbody
- @applications.each do |application|
%tr
%td= application.name
%td= application.created_at.strftime('%Y-%m-%d %H:%M:%S')
%td= render 'delete_form', application: application
\ No newline at end of file
%ul.nav.nav-pills.nav-stacked.nav-stacked-menu
%ul.sidebar-subnav
= nav_link(path: 'groups#edit') do
= link_to edit_group_path(@group) do
%i.fa.fa-pencil-square-o
......
.row
.col-md-2
= render 'settings_nav'
.col-md-10
.panel.panel-default
.panel-heading
%strong= @group.name
group settings:
.panel-body
= form_for @group, html: { multipart: true, class: "form-horizontal" }, authenticity_token: true do |f|
- if @group.errors.any?
.alert.alert-danger
%span= @group.errors.full_messages.first
= render 'shared/group_form', f: f
.panel.panel-default
.panel-heading
%strong= @group.name
group settings:
.panel-body
= form_for @group, html: { multipart: true, class: "form-horizontal" }, authenticity_token: true do |f|
- if @group.errors.any?
.alert.alert-danger
%span= @group.errors.full_messages.first
= render 'shared/group_form', f: f
.form-group
.col-sm-2
.col-sm-10
= image_tag group_icon(@group.to_param), alt: '', class: 'avatar s160'
%p.light
- if @group.avatar?
You can change your group avatar here
- else
You can upload a group avatar here
= render 'shared/choose_group_avatar_button', f: f
- if @group.avatar?
%hr
= link_to 'Remove avatar', group_avatar_path(@group.to_param), data: { confirm: "Group avatar will be removed. Are you sure?"}, method: :delete, class: "btn btn-remove btn-small remove-avatar"
.form-group
.form-group
.col-sm-2
.col-sm-10
= image_tag group_icon(@group.to_param), alt: '', class: 'avatar s160'
%p.light
- if @group.avatar?
You can change your group avatar here
- else
You can upload a group avatar here
= render 'shared/choose_group_avatar_button', f: f
- if @group.avatar?
%hr
= f.label :name, class: 'control-label' do
Member lock
.col-sm-10
.checkbox
= f.check_box :membership_lock
%span.descr Prevent adding new members to project membership within this group
= link_to 'Remove avatar', group_avatar_path(@group.to_param), data: { confirm: "Group avatar will be removed. Are you sure?"}, method: :delete, class: "btn btn-remove btn-small remove-avatar"
.form-group
%hr
= f.label :name, class: 'control-label' do
Member lock
.col-sm-10
.checkbox
= f.check_box :membership_lock
%span.descr Prevent adding new members to project membership within this group
.form-actions
= f.submit 'Save group', class: "btn btn-save"
.form-actions
= f.submit 'Save group', class: "btn btn-save"
.panel.panel-danger
.panel-heading Remove group
.panel-body
%p
Removing group will cause all child projects and resources to be removed.
%br
%strong Removed group can not be restored!
= link_to 'Remove Group', @group, data: {confirm: 'Removed group can not be restored! Are you sure?'}, method: :delete, class: "btn btn-remove"
.panel.panel-danger
.panel-heading Remove group
.panel-body
%p
Removing group will cause all child projects and resources to be removed.
%br
%strong Removed group can not be restored!
= link_to 'Remove Group', @group, data: {confirm: 'Removed group can not be restored! Are you sure?'}, method: :delete, class: "btn btn-remove"
......@@ -9,10 +9,6 @@
To see all issues you should visit #{link_to 'dashboard', issues_dashboard_path} page.
%hr
.row
.fixed.sidebar-expand-button.hidden-lg.hidden-md
%i.fa.fa-list.fa-2x
.col-md-3.responsive-side
= render 'shared/filter', entity: 'issue'
.col-md-9
= render 'shared/issues'
.append-bottom-20
= render 'shared/issuable_filter'
= render 'shared/issues'
.row
.col-md-2= render 'groups/settings_nav'
.col-md-10
%h3.page-title Linked LDAP groups
= render 'ldap_group_links/form', group: @group
= render 'ldap_group_links/ldap_group_links', group: @group
%h3.page-title Linked LDAP groups
= render 'ldap_group_links/form', group: @group
= render 'ldap_group_links/ldap_group_links', group: @group
......@@ -8,10 +8,6 @@
- if current_user
To see all merge requests you should visit #{link_to 'dashboard', merge_requests_dashboard_path} page.
%hr
.row
.fixed.sidebar-expand-button.hidden-lg.hidden-md
%i.fa.fa-list.fa-2x
.col-md-3.responsive-side
= render 'shared/filter', entity: 'merge_request'
.col-md-9
= render 'shared/merge_requests'
.append-bottom-20
= render 'shared/issuable_filter'
= render 'shared/merge_requests'
.row
.col-md-2
= render 'settings_nav'
.col-md-10
.panel.panel-default
.panel-heading
%strong= @group.name
projects:
- if can? current_user, :manage_group, @group
.panel-head-actions
= link_to new_project_path(namespace_id: @group.id), class: "btn btn-new" do
%i.fa.fa-plus
New Project
%ul.well-list
- @projects.each do |project|
%li
.list-item-name
= visibility_level_icon(project.visibility_level)
%strong= link_to project.name_with_namespace, project
%span.label.label-gray
= repository_size(project)
.pull-right
= link_to 'Members', project_team_index_path(project), id: "edit_#{dom_id(project)}", class: "btn btn-small"
= link_to 'Edit', edit_project_path(project), id: "edit_#{dom_id(project)}", class: "btn btn-small"
= link_to 'Remove', project, data: { confirm: remove_project_message(project)}, method: :delete, class: "btn btn-small btn-remove"
- if @projects.blank?
.nothing-here-block This group has no projects yet
.panel.panel-default
.panel-heading
%strong= @group.name
projects:
- if can? current_user, :manage_group, @group
.panel-head-actions
= link_to new_project_path(namespace_id: @group.id), class: "btn btn-new" do
%i.fa.fa-plus
New Project
%ul.well-list
- @projects.each do |project|
%li
.list-item-name
= visibility_level_icon(project.visibility_level)
%strong= link_to project.name_with_namespace, project
%span.label.label-gray
= repository_size(project)
.pull-right
= link_to 'Members', project_team_index_path(project), id: "edit_#{dom_id(project)}", class: "btn btn-small"
= link_to 'Edit', edit_project_path(project), id: "edit_#{dom_id(project)}", class: "btn btn-small"
= link_to 'Remove', project, data: { confirm: remove_project_message(project)}, method: :delete, class: "btn btn-small btn-remove"
- if @projects.blank?
.nothing-here-block This group has no projects yet
= paginate @projects, theme: "gitlab"
= paginate @projects, theme: "gitlab"
.dashboard
%section.activities.col-md-8.hidden-sm.hidden-xs
- if current_user
= render "events/event_last_push", event: @last_push
= link_to dashboard_path, class: 'btn btn-tiny' do
&larr; To dashboard
&nbsp;
%span.cgray
Currently you are only seeing events from the
= @group.name
group
%hr
= render 'shared/event_filter'
- if @events.any?
.content_list
- else
.nothing-here-block Project activity will be displayed here
= spinner
%aside.side.col-md-4
.light-well.append-bottom-20
= image_tag group_icon(@group.path), class: "avatar s90"
.clearfix.light
%h3.page-title
= @group.name
- if @group.description.present?
%p
= escaped_autolink(@group.description)
= render "projects", projects: @projects
%br
= render "shared_projects", projects: @shared_projects
- if current_user
.prepend-top-20
= link_to group_path(@group, { format: :atom, private_token: current_user.private_token }), title: "Feed" do
%strong
%i.fa.fa-rss
News Feed
%hr
= render 'shared/promo'
%div
= image_tag group_icon(@group.path), class: "avatar s90"
.clearfix
%h2
= @group.name
- if @group.description.present?
%p
= escaped_autolink(@group.description)
%hr
.row
%section.activities.col-md-8.hidden-sm.hidden-xs
- if current_user
= render "events/event_last_push", event: @last_push
= render 'shared/event_filter'
- if @events.any?
.content_list
- else
.nothing-here-block Project activity will be displayed here
= spinner
%aside.side.col-md-4
= render "projects", projects: @projects
%br
= render "shared_projects", projects: @shared_projects
......@@ -2,3 +2,7 @@
.broadcast-message{ style: broadcast_styling(broadcast_message) }
%i.fa.fa-bullhorn
= broadcast_message.message
:css
.sidebar-wrapper .nav-sidebar {
margin-top: 58px;
}
......@@ -2,10 +2,8 @@
.navbar-inner
.container
%div.app_logo
%span.separator
= link_to root_path, class: "home has_bottom_tooltip", title: "Dashboard" do
%h1 GITLAB
%span.separator
%h1.title= title
%button.navbar-toggle{"data-target" => ".navbar-collapse", "data-toggle" => "collapse", type: "button"}
......
- if defined?(sidebar)
.page-with-sidebar
.sidebar-wrapper
= render(sidebar)
.content-wrapper
.container-fluid
.content
= render "layouts/flash"
.clearfix
= yield
- else
.container.navless-container
.content
= yield
= yield :embedded_scripts
!!! 5
%html{ lang: "en"}
= render "layouts/head", title: "Admin area"
%body{class: "#{app_theme} admin", :'data-page' => body_data_page}
%body{class: "#{app_theme} #{theme_type} admin", :'data-page' => body_data_page}
= render "layouts/broadcast"
= render "layouts/head_panel", title: "Admin area"
%nav.main-nav.navbar-collapse.collapse
.container= render 'layouts/nav/admin'
.container
.content
= render "layouts/flash"
= yield
= yield :embedded_scripts
= render 'layouts/page', sidebar: 'layouts/nav/admin'
!!! 5
%html{ lang: "en"}
= render "layouts/head", title: "Dashboard"
%body{class: "#{app_theme} application", :'data-page' => body_data_page }
%body{class: "#{app_theme} #{theme_type} application", :'data-page' => body_data_page }
= render "layouts/broadcast"
= render "layouts/head_panel", title: "Dashboard"
%nav.main-nav.navbar-collapse.collapse
.container= render 'layouts/nav/dashboard'
.container
.content
= render "layouts/flash"
= yield
= render 'layouts/page', sidebar: 'layouts/nav/dashboard'
!!!
%html
%head
%meta{:charset => "utf-8"}
%meta{:content => "IE=edge", "http-equiv" => "X-UA-Compatible"}
%meta{:content => "width=device-width, initial-scale=1.0", :name => "viewport"}
%title Doorkeeper
= stylesheet_link_tag "doorkeeper/admin/application"
= csrf_meta_tags
%body
.navbar.navbar-inverse.navbar-fixed-top{:role => "navigation"}
.container
.navbar-header
= link_to 'OAuth2 Provider', oauth_applications_path, class: 'navbar-brand'
%ul.nav.navbar-nav
= content_tag :li, class: "#{'active' if request.path == oauth_applications_path}" do
= link_to 'Applications', oauth_applications_path
.container
- if flash[:notice].present?
.alert.alert-info
= flash[:notice]
= yield
\ No newline at end of file
!!!
%html
%head
%title OAuth authorize required
%meta{:charset => "utf-8"}
%meta{:content => "IE=edge", "http-equiv" => "X-UA-Compatible"}
%meta{:content => "width=device-width, initial-scale=1.0", :name => "viewport"}
= stylesheet_link_tag "doorkeeper/application"
= csrf_meta_tags
%body
#container
- if flash[:notice].present?
.alert.alert-info
= flash[:notice]
= yield
\ No newline at end of file
!!! 5
%html{ lang: "en"}
= render "layouts/head", title: "Error"
%body{class: "#{app_theme} application"}
%body{class: "#{app_theme} #{theme_type} application"}
= render "layouts/head_panel", title: "" if current_user
.container.navless-container
= render "layouts/flash"
......
......@@ -2,7 +2,7 @@
!!! 5
%html{ lang: "en"}
= render "layouts/head", title: page_title
%body{class: "#{app_theme} application", :'data-page' => body_data_page}
%body{class: "#{app_theme} #{theme_type} application", :'data-page' => body_data_page}
= render "layouts/broadcast"
- if current_user
= render "layouts/head_panel", title: page_title
......
!!! 5
%html{ lang: "en"}
= render "layouts/head", title: group_head_title
%body{class: "#{app_theme} application", :'data-page' => body_data_page}
%body{class: "#{app_theme} #{theme_type} application", :'data-page' => body_data_page}
= render "layouts/broadcast"
= render "layouts/head_panel", title: "group: #{@group.name}"
%nav.main-nav.navbar-collapse.collapse
.container= render 'layouts/nav/group'
.container
.content
= render "layouts/flash"
= yield
= render "layouts/head_panel", title: @group.name
= render 'layouts/page', sidebar: 'layouts/nav/group'
%ul
%ul.nav.nav-sidebar
= nav_link(controller: :dashboard, html_options: {class: 'home'}) do
= link_to admin_root_path, title: "Stats" do
Overview
%i.fa.fa-dashboard
%span
Overview
= nav_link(controller: :projects) do
= link_to "Projects", admin_projects_path
= link_to admin_projects_path do
%i.fa.fa-cube
%span
Projects
= nav_link(controller: :users) do
= link_to "Users", admin_users_path
= link_to admin_users_path do
%i.fa.fa-users
%span
Users
= nav_link(controller: :groups) do
= link_to "Groups", admin_groups_path
= link_to admin_groups_path do
%i.fa.fa-group
%span
Groups
= nav_link(controller: :logs) do
= link_to "Logs", admin_logs_path
= link_to admin_logs_path do
%i.fa.fa-file-text
%span
Logs
= nav_link(controller: :broadcast_messages) do
= link_to "Messages", admin_broadcast_messages_path
= link_to admin_broadcast_messages_path do
%i.fa.fa-bullhorn
%span
Messages
= nav_link(controller: :hooks) do
= link_to "Hooks", admin_hooks_path
= link_to admin_hooks_path do
%i.fa.fa-external-link
%span
Hooks
= nav_link(controller: :background_jobs) do
= link_to "Background Jobs", admin_background_jobs_path
= link_to admin_background_jobs_path do
%i.fa.fa-cog
%span
Background Jobs
= nav_link(controller: :appearances) do
= link_to "Appearance", admin_appearances_path
= link_to admin_appearances_path do
%i.fa.fa-image
%span
Appearance
%ul
%ul.nav.nav-sidebar
= nav_link(path: 'dashboard#show', html_options: {class: 'home'}) do
= link_to root_path, title: 'Home', class: 'shortcuts-activity' do
Activity
%i.fa.fa-dashboard
%span
Activity
= nav_link(path: 'dashboard#projects') do
= link_to projects_dashboard_path, class: 'shortcuts-projects' do
Projects
%i.fa.fa-cube
%span
Projects
= nav_link(path: 'dashboard#issues') do
= link_to issues_dashboard_path, class: 'shortcuts-issues' do
Issues
%span.count= current_user.assigned_issues.opened.count
%i.fa.fa-exclamation-circle
%span
Issues
%span.count= current_user.assigned_issues.opened.count
= nav_link(path: 'dashboard#merge_requests') do
= link_to merge_requests_dashboard_path, class: 'shortcuts-merge_requests' do
Merge Requests
%span.count= current_user.assigned_merge_requests.opened.count
%i.fa.fa-tasks
%span
Merge Requests
%span.count= current_user.assigned_merge_requests.opened.count
= nav_link(controller: :help) do
= link_to "Help", help_path
= link_to help_path do
%i.fa.fa-question-circle
%span
Help
%ul
%ul.nav.nav-sidebar
= nav_link(path: 'groups#show', html_options: {class: 'home'}) do
= link_to group_path(@group), title: "Home" do
Activity
= nav_link(controller: [:group, :milestones]) do
= link_to group_milestones_path(@group) do
Milestones
%i.fa.fa-dashboard
%span
Activity
- if current_user
= nav_link(controller: [:group, :milestones]) do
= link_to group_milestones_path(@group) do
%i.fa.fa-clock-o
%span
Milestones
= nav_link(path: 'groups#issues') do
= link_to issues_group_path(@group) do
Issues
- if current_user
%span.count= current_user.assigned_issues.opened.of_group(@group).count
%i.fa.fa-exclamation-circle
%span
Issues
- if current_user
%span.count= Issue.opened.of_group(@group).count
= nav_link(path: 'groups#merge_requests') do
= link_to merge_requests_group_path(@group) do
Merge Requests
- if current_user
%span.count= current_user.cared_merge_requests.opened.of_group(@group).count
%i.fa.fa-tasks
%span
Merge Requests
- if current_user
%span.count= MergeRequest.opened.of_group(@group).count
= nav_link(path: 'groups#members') do
= link_to "Members", members_group_path(@group)
= link_to members_group_path(@group) do
%i.fa.fa-users
%span
Members
- if can?(current_user, :manage_group, @group)
= nav_link(path: 'groups#edit') do
= link_to edit_group_path(@group), class: "tab " do
Settings
= nav_link(html_options: { class: "#{"active" if group_settings_page?} separate-item" }) do
= link_to edit_group_path(@group), class: "tab no-highlight" do
%i.fa.fa-cogs
%span
Settings
%i.fa.fa-angle-down
- if group_settings_page?
= render 'groups/settings_nav'
%ul
%ul.nav.nav-sidebar
= nav_link(path: 'profiles#show', html_options: {class: 'home'}) do
= link_to profile_path, title: "Profile" do
Profile
%i.fa.fa-user
%span
Profile
= nav_link(controller: :accounts) do
= link_to "Account", profile_account_path
= link_to profile_account_path do
%i.fa.fa-gear
Account
= nav_link(path: ['profiles#applications', 'applications#edit', 'applications#show', 'applications#new']) do
= link_to applications_profile_path do
%i.fa.fa-cloud
%span
Applications
= nav_link(controller: :emails) do
= link_to profile_emails_path do
Emails
%span.count= current_user.emails.count + 1
%i.fa.fa-envelope-o
%span
Emails
%span.count= current_user.emails.count + 1
- unless current_user.ldap_user?
= nav_link(controller: :passwords) do
= link_to "Password", edit_profile_password_path
= link_to edit_profile_password_path do
%i.fa.fa-lock
%span
Password
= nav_link(controller: :notifications) do
= link_to "Notifications", profile_notifications_path
= link_to profile_notifications_path do
%i.fa.fa-inbox
%span
Notifications
= nav_link(controller: :keys) do
= link_to profile_keys_path do
SSH Keys
%span.count= current_user.keys.count
%i.fa.fa-key
%span
SSH Keys
%span.count= current_user.keys.count
= nav_link(path: 'profiles#design') do
= link_to "Design", design_profile_path
= link_to design_profile_path do
%i.fa.fa-image
%span
Design
= nav_link(controller: :groups) do
= link_to "Groups", profile_groups_path
= link_to profile_groups_path do
%i.fa.fa-group
%span
Groups
= nav_link(path: 'profiles#history') do
= link_to "History", history_profile_path
= link_to history_profile_path do
%i.fa.fa-history
%span
History
%ul.project-navigation
%ul.project-navigation.nav.nav-sidebar
= nav_link(path: 'projects#show', html_options: {class: "home"}) do
= link_to project_path(@project), title: 'Project', class: 'shortcuts-project' do
Project
%i.fa.fa-dashboard
%span
Project
- if project_nav_tab? :files
= nav_link(controller: %w(tree blob blame edit_tree new_tree)) do
= link_to 'Files', project_tree_path(@project, @ref || @repository.root_ref), class: 'shortcuts-tree'
= link_to project_tree_path(@project, @ref || @repository.root_ref), class: 'shortcuts-tree' do
%i.fa.fa-files-o
%span
Files
- if project_nav_tab? :commits
= nav_link(controller: %w(commit commits compare repositories tags branches)) do
= link_to "Commits", project_commits_path(@project, @ref || @repository.root_ref), class: 'shortcuts-commits'
= link_to project_commits_path(@project, @ref || @repository.root_ref), class: 'shortcuts-commits' do
%i.fa.fa-history
%span
Commits
- if project_nav_tab? :network
= nav_link(controller: %w(network)) do
= link_to "Network", project_network_path(@project, @ref || @repository.root_ref), class: 'shortcuts-network'
= link_to project_network_path(@project, @ref || @repository.root_ref), class: 'shortcuts-network' do
%i.fa.fa-code-fork
%span
Network
- if project_nav_tab? :graphs
= nav_link(controller: %w(graphs)) do
= link_to "Graphs", project_graph_path(@project, @ref || @repository.root_ref), class: 'shortcuts-graphs'
= link_to project_graph_path(@project, @ref || @repository.root_ref), class: 'shortcuts-graphs' do
%i.fa.fa-area-chart
%span
Graphs
- if project_nav_tab? :issues
= nav_link(controller: %w(issues milestones labels)) do
= link_to url_for_project_issues, class: 'shortcuts-issues' do
Issues
- if @project.used_default_issues_tracker?
%span.count.issue_counter= @project.issues.opened.count
%i.fa.fa-exclamation-circle
%span
Issues
- if @project.used_default_issues_tracker?
%span.count.issue_counter= @project.issues.opened.count
- if project_nav_tab? :merge_requests
= nav_link(controller: :merge_requests) do
= link_to project_merge_requests_path(@project), class: 'shortcuts-merge_requests' do
Merge Requests
%span.count.merge_counter= @project.merge_requests.opened.count
%i.fa.fa-tasks
%span
Merge Requests
%span.count.merge_counter= @project.merge_requests.opened.count
- if project_nav_tab? :wiki
= nav_link(controller: :wikis) do
= link_to 'Wiki', project_wiki_path(@project, :home), class: 'shortcuts-wiki'
= link_to project_wiki_path(@project, :home), class: 'shortcuts-wiki' do
%i.fa.fa-book
%span
Wiki
- if project_nav_tab? :snippets
= nav_link(controller: :snippets) do
= link_to 'Snippets', project_snippets_path(@project), class: 'shortcuts-snippets'
= link_to project_snippets_path(@project), class: 'shortcuts-snippets' do
%i.fa.fa-file-text-o
%span
Snippets
- if project_nav_tab? :settings
= nav_link(html_options: {class: "#{project_tab_class}"}) do
= link_to edit_project_path(@project), class: "stat-tab tab " do
Settings
= nav_link(html_options: {class: "#{project_tab_class} separate-item"}) do
= link_to edit_project_path(@project), class: "stat-tab tab no-highlight" do
%i.fa.fa-cogs
%span
Settings
%i.fa.fa-angle-down
- if @project_settings_nav
= render 'projects/settings_nav'
!!! 5
%html{ lang: "en"}
= render "layouts/head", title: @title
%body{class: "#{app_theme} application", :'data-page' => body_data_page}
%body{class: "#{app_theme} #{theme_type} application", :'data-page' => body_data_page}
= render "layouts/broadcast"
= render "layouts/head_panel", title: @title
.container.navless-container
......
!!! 5
%html{ lang: "en"}
= render "layouts/head", title: "Profile"
%body{class: "#{app_theme} profile", :'data-page' => body_data_page}
%body{class: "#{app_theme} #{theme_type} profile", :'data-page' => body_data_page}
= render "layouts/broadcast"
= render "layouts/head_panel", title: "Profile"
%nav.main-nav.navbar-collapse.collapse
.container= render 'layouts/nav/profile'
.container
.content
= render "layouts/flash"
= yield
= render 'layouts/page', sidebar: 'layouts/nav/profile'
!!! 5
%html{ lang: "en"}
= render "layouts/head", title: @project.name_with_namespace
%body{class: "#{app_theme} project", :'data-page' => body_data_page, :'data-project-id' => @project.id }
%body{class: "#{app_theme} #{theme_type} project", :'data-page' => body_data_page, :'data-project-id' => @project.id }
= render "layouts/broadcast"
= render "layouts/head_panel", title: project_title(@project)
= render "layouts/init_auto_complete"
- if can?(current_user, :download_code, @project)
= render 'shared/no_ssh'
%nav.main-nav.navbar-collapse.collapse
.container= render 'layouts/nav/project'
.container
.content
= render "layouts/flash"
.row
.col-md-2
= render "projects/settings_nav"
.col-md-10
= yield
- @project_settings_nav = true
= render 'layouts/page', sidebar: 'layouts/nav/project'
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment