summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorJavier Castro <javier.alejandro.castro@gmail.com>2014-03-04 15:09:33 -0300
committerJavier Castro <javier.alejandro.castro@gmail.com>2014-03-04 15:09:33 -0300
commitb61f80babb10d0583d3199d557b4e8234d981a33 (patch)
tree747f124631f6547103bd30d4b48586382b91ae89 /app
parent556ae5ae8187b89a3785219d5621e7ebc9bb7a8c (diff)
parentfbbd989770ea48d472a5c4d7d95b970542279099 (diff)
downloadgitlab-ce-b61f80babb10d0583d3199d557b4e8234d981a33.tar.gz
Merge remote-tracking branch 'upstream/master' into fix-4305
Diffstat (limited to 'app')
-rw-r--r--app/assets/images/ajax_loader.gifbin7927 -> 0 bytes
-rw-r--r--app/assets/images/ajax_loader_gray.gifbin8370 -> 0 bytes
-rw-r--r--app/assets/images/ajax_loader_tree.gifbin6531 -> 0 bytes
-rw-r--r--app/assets/images/bg-header.pngbin212 -> 210 bytes
-rw-r--r--app/assets/images/dark-scheme-preview.pngbin16935 -> 9873 bytes
-rw-r--r--app/assets/images/file_txt.pngbin290 -> 463 bytes
-rw-r--r--app/assets/images/icon-link.pngbin0 -> 1019 bytes
-rw-r--r--app/assets/images/icon-search.pngbin422 -> 331 bytes
-rw-r--r--app/assets/images/images.pngbin8698 -> 6644 bytes
-rw-r--r--app/assets/images/logo-black.pngbin3018 -> 2797 bytes
-rw-r--r--app/assets/images/logo-white.pngbin8337 -> 7501 bytes
-rw-r--r--app/assets/images/monokai-scheme-preview.pngbin6651 -> 4332 bytes
-rw-r--r--app/assets/images/no_avatar.pngbin1337 -> 704 bytes
-rw-r--r--app/assets/images/no_group_avatar.pngbin0 -> 4884 bytes
-rw-r--r--app/assets/images/onion_skin_sprites.gifbin1584 -> 548 bytes
-rw-r--r--app/assets/images/solarized-dark-scheme-preview.pngbin16320 -> 9902 bytes
-rw-r--r--app/assets/images/swipemode_sprites.gifbin1540 -> 505 bytes
-rw-r--r--app/assets/images/switch_icon.pngbin1203 -> 1197 bytes
-rw-r--r--app/assets/images/trans_bg.gifbin58 -> 50 bytes
-rw-r--r--app/assets/images/white-scheme-preview.pngbin17161 -> 10022 bytes
-rw-r--r--app/assets/javascripts/api.js.coffee18
-rw-r--r--app/assets/javascripts/application.js3
-rw-r--r--app/assets/javascripts/blob.js.coffee4
-rw-r--r--app/assets/javascripts/commit.js.coffee2
-rw-r--r--app/assets/javascripts/dispatcher.js.coffee18
-rw-r--r--app/assets/javascripts/groups.js.coffee11
-rw-r--r--app/assets/javascripts/issue.js.coffee9
-rw-r--r--app/assets/javascripts/issues.js.coffee14
-rw-r--r--app/assets/javascripts/main.js.coffee4
-rw-r--r--app/assets/javascripts/merge_request.js.coffee103
-rw-r--r--app/assets/javascripts/merge_requests.js.coffee94
-rw-r--r--app/assets/javascripts/notes.js.coffee6
-rw-r--r--app/assets/javascripts/profile.js.coffee2
-rw-r--r--app/assets/javascripts/project_users_select.js.coffee63
-rw-r--r--app/assets/javascripts/search_autocomplete.js.coffee9
-rw-r--r--app/assets/javascripts/users_select.js.coffee8
-rw-r--r--app/assets/stylesheets/application.scss7
-rw-r--r--app/assets/stylesheets/generic/blocks.scss15
-rw-r--r--app/assets/stylesheets/generic/buttons.scss28
-rw-r--r--app/assets/stylesheets/generic/common.scss178
-rw-r--r--app/assets/stylesheets/generic/files.scss73
-rw-r--r--app/assets/stylesheets/generic/flash.scss25
-rw-r--r--app/assets/stylesheets/generic/forms.scss24
-rw-r--r--app/assets/stylesheets/generic/highlight.scss64
-rw-r--r--app/assets/stylesheets/generic/issue_box.scss86
-rw-r--r--app/assets/stylesheets/generic/lists.scss6
-rw-r--r--app/assets/stylesheets/generic/selects.scss61
-rw-r--r--app/assets/stylesheets/generic/typography.scss22
-rw-r--r--app/assets/stylesheets/gl_bootstrap.scss2
-rw-r--r--app/assets/stylesheets/highlight/dark.scss262
-rw-r--r--app/assets/stylesheets/highlight/monokai.scss221
-rw-r--r--app/assets/stylesheets/highlight/solarized_dark.scss191
-rw-r--r--app/assets/stylesheets/highlight/white.scss236
-rw-r--r--app/assets/stylesheets/main/layout.scss6
-rw-r--r--app/assets/stylesheets/main/mixins.scss6
-rw-r--r--app/assets/stylesheets/main/variables.scss1
-rw-r--r--app/assets/stylesheets/sections/admin.scss6
-rw-r--r--app/assets/stylesheets/sections/commits.scss344
-rw-r--r--app/assets/stylesheets/sections/dashboard.scss2
-rw-r--r--app/assets/stylesheets/sections/diff.scss329
-rw-r--r--app/assets/stylesheets/sections/events.scss6
-rw-r--r--app/assets/stylesheets/sections/groups.scss9
-rw-r--r--app/assets/stylesheets/sections/header.scss77
-rw-r--r--app/assets/stylesheets/sections/issues.scss64
-rw-r--r--app/assets/stylesheets/sections/login.scss5
-rw-r--r--app/assets/stylesheets/sections/merge_requests.scss19
-rw-r--r--app/assets/stylesheets/sections/nav.scss58
-rw-r--r--app/assets/stylesheets/sections/notes.scss49
-rw-r--r--app/assets/stylesheets/sections/profile.scss20
-rw-r--r--app/assets/stylesheets/sections/projects.scss11
-rw-r--r--app/assets/stylesheets/sections/tree.scss20
-rw-r--r--app/assets/stylesheets/themes/ui_color.scss6
-rw-r--r--app/assets/stylesheets/themes/ui_gray.scss2
-rw-r--r--app/assets/stylesheets/themes/ui_mars.scss2
-rw-r--r--app/assets/stylesheets/themes/ui_modern.scss2
-rw-r--r--app/contexts/commit_load_context.rb34
-rw-r--r--app/contexts/filter_context.rb58
-rw-r--r--app/contexts/issues/list_context.rb53
-rw-r--r--app/contexts/merge_requests_load_context.rb35
-rw-r--r--app/contexts/notes/load_context.rb20
-rw-r--r--app/contexts/test_hook_context.rb7
-rw-r--r--app/controllers/admin/groups_controller.rb2
-rw-r--r--app/controllers/admin/projects_controller.rb4
-rw-r--r--app/controllers/admin/users_controller.rb6
-rw-r--r--app/controllers/application_controller.rb16
-rw-r--r--app/controllers/dashboard_controller.rb21
-rw-r--r--app/controllers/errors_controller.rb2
-rw-r--r--app/controllers/groups/avatars_controller.rb12
-rw-r--r--app/controllers/groups_controller.rb57
-rw-r--r--app/controllers/profiles/emails_controller.rb26
-rw-r--r--app/controllers/profiles/groups_controller.rb9
-rw-r--r--app/controllers/profiles/keys_controller.rb21
-rw-r--r--app/controllers/projects/blob_controller.rb3
-rw-r--r--app/controllers/projects/commit_controller.rb37
-rw-r--r--app/controllers/projects/compare_controller.rb3
-rw-r--r--app/controllers/projects/edit_tree_controller.rb27
-rw-r--r--app/controllers/projects/hooks_controller.rb11
-rw-r--r--app/controllers/projects/issues_controller.rb19
-rw-r--r--app/controllers/projects/labels_controller.rb2
-rw-r--r--app/controllers/projects/merge_requests_controller.rb47
-rw-r--r--app/controllers/projects/milestones_controller.rb2
-rw-r--r--app/controllers/projects/new_tree_controller.rb3
-rw-r--r--app/controllers/projects/notes_controller.rb4
-rw-r--r--app/controllers/projects/raw_controller.rb18
-rw-r--r--app/controllers/projects/refs_controller.rb2
-rw-r--r--app/controllers/projects/tags_controller.rb2
-rw-r--r--app/controllers/projects/team_members_controller.rb8
-rw-r--r--app/controllers/projects_controller.rb8
-rw-r--r--app/controllers/public/projects_controller.rb2
-rw-r--r--app/controllers/search_controller.rb18
-rw-r--r--app/controllers/snippets_controller.rb2
-rw-r--r--app/controllers/users_controller.rb20
-rw-r--r--app/controllers/users_groups_controller.rb15
-rw-r--r--app/finders/README.md22
-rw-r--r--app/finders/base_finder.rb137
-rw-r--r--app/finders/issues_finder.rb22
-rw-r--r--app/finders/merge_requests_finder.rb22
-rw-r--r--app/finders/notes_finder.rb17
-rw-r--r--app/finders/projects_finder.rb63
-rw-r--r--app/helpers/application_helper.rb36
-rw-r--r--app/helpers/commits_helper.rb15
-rw-r--r--app/helpers/dashboard_helper.rb2
-rw-r--r--app/helpers/gitlab_markdown_helper.rb76
-rw-r--r--app/helpers/groups_helper.rb14
-rw-r--r--app/helpers/issues_helper.rb16
-rw-r--r--app/helpers/merge_requests_helper.rb3
-rw-r--r--app/helpers/notes_helper.rb2
-rw-r--r--app/helpers/notifications_helper.rb6
-rw-r--r--app/helpers/projects_helper.rb25
-rw-r--r--app/helpers/search_helper.rb48
-rw-r--r--app/helpers/selects_helper.rb20
-rw-r--r--app/helpers/submodule_helper.rb43
-rw-r--r--app/mailers/emails/issues.rb22
-rw-r--r--app/mailers/emails/merge_requests.rb22
-rw-r--r--app/mailers/emails/notes.rb16
-rw-r--r--app/mailers/emails/profile.rb6
-rw-r--r--app/mailers/emails/projects.rb5
-rw-r--r--app/mailers/notify.rb35
-rw-r--r--app/models/ability.rb33
-rw-r--r--app/models/commit.rb54
-rw-r--r--app/models/concerns/issuable.rb15
-rw-r--r--app/models/email.rb33
-rw-r--r--app/models/event.rb6
-rw-r--r--app/models/gollum_wiki.rb5
-rw-r--r--app/models/group.rb22
-rw-r--r--app/models/issue.rb4
-rw-r--r--app/models/key.rb2
-rw-r--r--app/models/merge_request.rb186
-rw-r--r--app/models/merge_request_diff.rb155
-rw-r--r--app/models/namespace.rb11
-rw-r--r--app/models/note.rb18
-rw-r--r--app/models/notification.rb27
-rw-r--r--app/models/project.rb47
-rw-r--r--app/models/project_services/assembla_service.rb8
-rw-r--r--app/models/project_services/campfire_service.rb1
-rw-r--r--app/models/project_services/emails_on_push_service.rb1
-rw-r--r--app/models/project_services/flowdock_service.rb1
-rw-r--r--app/models/project_services/gemnasium_service.rb54
-rw-r--r--app/models/project_services/gitlab_ci_service.rb1
-rw-r--r--app/models/project_services/hipchat_service.rb5
-rw-r--r--app/models/project_services/pivotaltracker_service.rb1
-rw-r--r--app/models/project_team.rb8
-rw-r--r--app/models/repository.rb53
-rw-r--r--app/models/service.rb5
-rw-r--r--app/models/tree.rb11
-rw-r--r--app/models/user.rb40
-rw-r--r--app/models/web_hook.rb7
-rw-r--r--app/observers/email_observer.rb5
-rw-r--r--app/observers/merge_request_observer.rb19
-rw-r--r--app/observers/system_hook_observer.rb10
-rw-r--r--app/services/base_service.rb (renamed from app/contexts/base_context.rb)2
-rw-r--r--app/services/files/base_service.rb (renamed from app/contexts/files/base_context.rb)2
-rw-r--r--app/services/files/create_service.rb (renamed from app/contexts/files/create_context.rb)9
-rw-r--r--app/services/files/delete_service.rb (renamed from app/contexts/files/delete_context.rb)6
-rw-r--r--app/services/files/update_service.rb (renamed from app/contexts/files/update_context.rb)13
-rw-r--r--app/services/git_push_service.rb4
-rw-r--r--app/services/issues/bulk_update_service.rb (renamed from app/contexts/issues/bulk_update_context.rb)2
-rw-r--r--app/services/merge_requests/auto_merge_service.rb30
-rw-r--r--app/services/merge_requests/base_merge_service.rb26
-rw-r--r--app/services/merge_requests/merge_service.rb22
-rw-r--r--app/services/notes/create_service.rb (renamed from app/contexts/notes/create_context.rb)3
-rw-r--r--app/services/notification_service.rb22
-rw-r--r--app/services/projects/create_service.rb (renamed from app/contexts/projects/create_context.rb)4
-rw-r--r--app/services/projects/fork_service.rb (renamed from app/contexts/projects/fork_context.rb)2
-rw-r--r--app/services/projects/transfer_service.rb (renamed from app/contexts/projects/transfer_context.rb)2
-rw-r--r--app/services/projects/update_service.rb (renamed from app/contexts/projects/update_context.rb)2
-rw-r--r--app/services/search/global_service.rb (renamed from app/contexts/search/global_context.rb)10
-rw-r--r--app/services/search/project_service.rb (renamed from app/contexts/search/project_context.rb)2
-rw-r--r--app/services/system_hooks_service.rb10
-rw-r--r--app/services/test_hook_service.rb6
-rw-r--r--app/views/admin/dashboard/index.html.haml251
-rw-r--r--app/views/admin/groups/index.html.haml27
-rw-r--r--app/views/admin/hooks/_data_ex.html.erb71
-rw-r--r--app/views/admin/projects/index.html.haml2
-rw-r--r--app/views/admin/users/_form.html.haml3
-rw-r--r--app/views/admin/users/index.html.haml12
-rw-r--r--app/views/admin/users/show.html.haml12
-rw-r--r--app/views/dashboard/_activities.html.haml5
-rw-r--r--app/views/dashboard/_groups.html.haml3
-rw-r--r--app/views/dashboard/_projects.html.haml2
-rwxr-xr-x[-rw-r--r--]app/views/dashboard/issues.html.haml2
-rwxr-xr-x[-rw-r--r--]app/views/dashboard/merge_requests.html.haml2
-rw-r--r--app/views/dashboard/projects.html.haml2
-rw-r--r--app/views/dashboard/show.html.haml2
-rwxr-xr-x[-rw-r--r--]app/views/devise/confirmations/new.html.haml3
-rwxr-xr-x[-rw-r--r--]app/views/devise/passwords/new.html.haml3
-rw-r--r--app/views/devise/sessions/new.html.haml2
-rw-r--r--app/views/groups/_filter.html.haml2
-rw-r--r--app/views/groups/_new_group_member.html.haml7
-rw-r--r--app/views/groups/_projects.html.haml2
-rw-r--r--app/views/groups/edit.html.haml30
-rw-r--r--app/views/groups/issues.html.haml4
-rw-r--r--app/views/groups/members.html.haml41
-rw-r--r--app/views/groups/merge_requests.html.haml4
-rw-r--r--app/views/groups/show.html.haml34
-rw-r--r--app/views/help/_api_layout.html.haml2
-rw-r--r--app/views/help/_layout.html.haml7
-rw-r--r--app/views/help/index.html.haml10
-rw-r--r--app/views/help/permissions.html.haml214
-rw-r--r--app/views/help/public_access.html.haml48
-rw-r--r--app/views/help/ssh.html.haml19
-rw-r--r--app/views/help/system_hooks.html.haml13
-rw-r--r--app/views/help/web_hooks.html.haml117
-rw-r--r--app/views/help/workflow.html.haml39
-rw-r--r--app/views/layouts/_head.html.haml6
-rw-r--r--app/views/layouts/_head_panel.html.haml9
-rw-r--r--app/views/layouts/_piwik.html.haml12
-rw-r--r--app/views/layouts/_public_head_panel.html.haml7
-rw-r--r--app/views/layouts/_search.html.haml2
-rw-r--r--app/views/layouts/admin.html.haml3
-rw-r--r--app/views/layouts/application.html.haml2
-rw-r--r--app/views/layouts/group.html.haml2
-rw-r--r--app/views/layouts/nav/_group.html.haml6
-rw-r--r--app/views/layouts/nav/_profile.html.haml4
-rw-r--r--app/views/layouts/navless.html.haml1
-rw-r--r--app/views/layouts/profile.html.haml2
-rw-r--r--app/views/layouts/project_settings.html.haml2
-rw-r--r--app/views/layouts/projects.html.haml2
-rw-r--r--app/views/layouts/public.html.haml4
-rw-r--r--app/views/layouts/public_group.html.haml10
-rw-r--r--app/views/layouts/public_projects.html.haml3
-rw-r--r--app/views/layouts/public_users.html.haml8
-rw-r--r--app/views/layouts/search.html.haml1
-rw-r--r--app/views/layouts/user_team.html.haml3
-rw-r--r--app/views/notify/new_email_email.html.haml10
-rw-r--r--app/views/notify/new_email_email.text.erb7
-rw-r--r--app/views/notify/repository_push_email.html.haml5
-rw-r--r--app/views/notify/repository_push_email.text.haml5
-rw-r--r--app/views/profiles/accounts/show.html.haml5
-rw-r--r--app/views/profiles/emails/index.html.haml33
-rw-r--r--app/views/profiles/groups/index.html.haml9
-rw-r--r--app/views/profiles/keys/index.html.haml2
-rw-r--r--app/views/profiles/notifications/_settings.html.haml44
-rw-r--r--app/views/profiles/notifications/show.html.haml81
-rw-r--r--app/views/profiles/passwords/new.html.haml42
-rw-r--r--app/views/profiles/show.html.haml3
-rw-r--r--app/views/projects/_settings_nav.html.haml12
-rw-r--r--app/views/projects/blob/_blob.html.haml4
-rw-r--r--app/views/projects/blob/_text.html.haml5
-rw-r--r--app/views/projects/blob/show.html.haml1
-rw-r--r--app/views/projects/branches/_branch.html.haml31
-rw-r--r--app/views/projects/branches/index.html.haml2
-rw-r--r--app/views/projects/branches/new.html.haml5
-rw-r--r--app/views/projects/commit/_commit_box.html.haml4
-rw-r--r--app/views/projects/commits/_commit.html.haml9
-rw-r--r--app/views/projects/commits/_diffs.html.haml40
-rw-r--r--app/views/projects/commits/_head.html.haml2
-rw-r--r--app/views/projects/commits/_image.html.haml6
-rw-r--r--app/views/projects/commits/_inline_commit.html.haml6
-rw-r--r--app/views/projects/commits/show.html.haml2
-rw-r--r--app/views/projects/compare/_form.html.haml2
-rw-r--r--app/views/projects/compare/show.html.haml29
-rw-r--r--app/views/projects/deploy_keys/index.html.haml4
-rw-r--r--app/views/projects/edit.html.haml14
-rw-r--r--app/views/projects/edit_tree/show.html.haml7
-rw-r--r--app/views/projects/empty.html.haml5
-rw-r--r--app/views/projects/graphs/show.html.haml5
-rw-r--r--app/views/projects/hooks/index.html.haml4
-rw-r--r--app/views/projects/issues/_form.html.haml6
-rw-r--r--app/views/projects/issues/_head.html.haml8
-rw-r--r--app/views/projects/issues/_issue.html.haml6
-rw-r--r--app/views/projects/issues/_issue_context.html.haml23
-rw-r--r--app/views/projects/issues/_issues.html.haml160
-rw-r--r--app/views/projects/issues/index.html.haml2
-rw-r--r--app/views/projects/issues/show.html.haml40
-rw-r--r--app/views/projects/issues/update.js.haml3
-rw-r--r--app/views/projects/labels/index.html.haml2
-rw-r--r--app/views/projects/merge_requests/_form.html.haml33
-rw-r--r--app/views/projects/merge_requests/_merge_request.html.haml10
-rw-r--r--app/views/projects/merge_requests/_show.html.haml11
-rw-r--r--app/views/projects/merge_requests/branch_from.js.haml2
-rw-r--r--app/views/projects/merge_requests/branch_to.js.haml2
-rw-r--r--app/views/projects/merge_requests/index.html.haml102
-rw-r--r--app/views/projects/merge_requests/show/_commits.html.haml15
-rw-r--r--app/views/projects/merge_requests/show/_context.html.haml22
-rw-r--r--app/views/projects/merge_requests/show/_diffs.html.haml18
-rw-r--r--app/views/projects/merge_requests/show/_mr_accept.html.haml22
-rw-r--r--app/views/projects/merge_requests/show/_mr_box.html.haml68
-rw-r--r--app/views/projects/merge_requests/show/_mr_ci.html.haml2
-rw-r--r--app/views/projects/merge_requests/show/_mr_title.html.haml29
-rw-r--r--app/views/projects/merge_requests/update.js.haml2
-rw-r--r--app/views/projects/merge_requests/update_branches.js.haml8
-rw-r--r--app/views/projects/milestones/_issues.html.haml2
-rw-r--r--app/views/projects/milestones/_merge_request.html.haml2
-rw-r--r--app/views/projects/milestones/_milestone.html.haml2
-rw-r--r--app/views/projects/milestones/index.html.haml2
-rw-r--r--app/views/projects/milestones/show.html.haml36
-rw-r--r--app/views/projects/network/show.html.haml2
-rw-r--r--app/views/projects/new.html.haml5
-rw-r--r--app/views/projects/new_tree/show.html.haml6
-rw-r--r--app/views/projects/notes/_discussion.html.haml17
-rw-r--r--app/views/projects/notes/_discussion_diff.html.haml45
-rw-r--r--app/views/projects/notes/_form.html.haml2
-rw-r--r--app/views/projects/notes/_note.html.haml2
-rw-r--r--app/views/projects/protected_branches/index.html.haml16
-rw-r--r--app/views/projects/repositories/_download_archive.html.haml14
-rw-r--r--app/views/projects/show.html.haml4
-rw-r--r--app/views/projects/snippets/_blob.html.haml9
-rw-r--r--app/views/projects/snippets/_snippet.html.haml7
-rw-r--r--app/views/projects/snippets/index.html.haml2
-rw-r--r--app/views/projects/tags/_tag.html.haml22
-rw-r--r--app/views/projects/tags/index.html.haml26
-rw-r--r--app/views/projects/team_members/_group_members.html.haml8
-rw-r--r--app/views/projects/team_members/index.html.haml4
-rw-r--r--app/views/projects/tree/_blob_item.html.haml4
-rw-r--r--app/views/projects/tree/_readme.html.haml2
-rw-r--r--app/views/projects/tree/_spinner.html.haml3
-rw-r--r--app/views/projects/tree/_submodule_item.html.haml9
-rw-r--r--app/views/projects/tree/_tree.html.haml2
-rw-r--r--app/views/projects/tree/_tree_item.html.haml4
-rw-r--r--app/views/projects/walls/show.html.haml2
-rw-r--r--app/views/projects/wikis/_main_links.html.haml4
-rw-r--r--app/views/projects/wikis/_nav.html.haml2
-rw-r--r--app/views/public/projects/index.html.haml2
-rw-r--r--app/views/search/_project_results.html.haml2
-rw-r--r--app/views/search/results/_blob.html.haml3
-rw-r--r--app/views/shared/_file_hljs.html.haml12
-rw-r--r--app/views/shared/_filter.html.haml39
-rw-r--r--app/views/shared/_issues.html.haml2
-rw-r--r--app/views/shared/_merge_requests.html.haml2
-rw-r--r--app/views/shared/_no_ssh.html.haml8
-rw-r--r--app/views/shared/_project_filter.html.haml28
-rw-r--r--app/views/shared/_promo.html.haml4
-rw-r--r--app/views/shared/_sort_dropdown.html.haml22
-rw-r--r--app/views/snippets/_blob.html.haml16
-rw-r--r--app/views/snippets/_blob_content.html.haml14
-rw-r--r--app/views/snippets/_snippets.html.haml2
-rw-r--r--app/views/snippets/current_user_index.html.haml4
-rw-r--r--app/views/snippets/index.html.haml4
-rw-r--r--app/views/users/_groups.html.haml3
-rw-r--r--app/views/users/_profile.html.haml4
-rw-r--r--app/views/users/show.html.haml4
-rw-r--r--app/views/users_groups/_users_group.html.haml35
-rw-r--r--app/workers/emails_on_push_worker.rb4
354 files changed, 4723 insertions, 3156 deletions
diff --git a/app/assets/images/ajax_loader.gif b/app/assets/images/ajax_loader.gif
deleted file mode 100644
index 8a97c91987a..00000000000
--- a/app/assets/images/ajax_loader.gif
+++ /dev/null
Binary files differ
diff --git a/app/assets/images/ajax_loader_gray.gif b/app/assets/images/ajax_loader_gray.gif
deleted file mode 100644
index af3f618bd0b..00000000000
--- a/app/assets/images/ajax_loader_gray.gif
+++ /dev/null
Binary files differ
diff --git a/app/assets/images/ajax_loader_tree.gif b/app/assets/images/ajax_loader_tree.gif
deleted file mode 100644
index 99d5a0f37f3..00000000000
--- a/app/assets/images/ajax_loader_tree.gif
+++ /dev/null
Binary files differ
diff --git a/app/assets/images/bg-header.png b/app/assets/images/bg-header.png
index 8759ca589fc..9ecdaf4e2d5 100644
--- a/app/assets/images/bg-header.png
+++ b/app/assets/images/bg-header.png
Binary files differ
diff --git a/app/assets/images/dark-scheme-preview.png b/app/assets/images/dark-scheme-preview.png
index 055a9069b63..6dac6cd8ca1 100644
--- a/app/assets/images/dark-scheme-preview.png
+++ b/app/assets/images/dark-scheme-preview.png
Binary files differ
diff --git a/app/assets/images/file_txt.png b/app/assets/images/file_txt.png
index f3638cb4e1e..b3230b5add0 100644
--- a/app/assets/images/file_txt.png
+++ b/app/assets/images/file_txt.png
Binary files differ
diff --git a/app/assets/images/icon-link.png b/app/assets/images/icon-link.png
new file mode 100644
index 00000000000..32ade0fe9a3
--- /dev/null
+++ b/app/assets/images/icon-link.png
Binary files differ
diff --git a/app/assets/images/icon-search.png b/app/assets/images/icon-search.png
index 7632915cacc..084b89e3a7c 100644
--- a/app/assets/images/icon-search.png
+++ b/app/assets/images/icon-search.png
Binary files differ
diff --git a/app/assets/images/images.png b/app/assets/images/images.png
index 973d3bdd39d..da91f6b1f4c 100644
--- a/app/assets/images/images.png
+++ b/app/assets/images/images.png
Binary files differ
diff --git a/app/assets/images/logo-black.png b/app/assets/images/logo-black.png
index 31c4a63cd08..4a96572d570 100644
--- a/app/assets/images/logo-black.png
+++ b/app/assets/images/logo-black.png
Binary files differ
diff --git a/app/assets/images/logo-white.png b/app/assets/images/logo-white.png
index 8a4ec851b1d..bc2ef601a53 100644
--- a/app/assets/images/logo-white.png
+++ b/app/assets/images/logo-white.png
Binary files differ
diff --git a/app/assets/images/monokai-scheme-preview.png b/app/assets/images/monokai-scheme-preview.png
index 9477941778e..3aeed886a02 100644
--- a/app/assets/images/monokai-scheme-preview.png
+++ b/app/assets/images/monokai-scheme-preview.png
Binary files differ
diff --git a/app/assets/images/no_avatar.png b/app/assets/images/no_avatar.png
index 752d26adba7..dac3ab1bb89 100644
--- a/app/assets/images/no_avatar.png
+++ b/app/assets/images/no_avatar.png
Binary files differ
diff --git a/app/assets/images/no_group_avatar.png b/app/assets/images/no_group_avatar.png
new file mode 100644
index 00000000000..a97d4515982
--- /dev/null
+++ b/app/assets/images/no_group_avatar.png
Binary files differ
diff --git a/app/assets/images/onion_skin_sprites.gif b/app/assets/images/onion_skin_sprites.gif
index 85d20260edc..337aa1bfb63 100644
--- a/app/assets/images/onion_skin_sprites.gif
+++ b/app/assets/images/onion_skin_sprites.gif
Binary files differ
diff --git a/app/assets/images/solarized-dark-scheme-preview.png b/app/assets/images/solarized-dark-scheme-preview.png
index 728964bc4c8..ae092ab5213 100644
--- a/app/assets/images/solarized-dark-scheme-preview.png
+++ b/app/assets/images/solarized-dark-scheme-preview.png
Binary files differ
diff --git a/app/assets/images/swipemode_sprites.gif b/app/assets/images/swipemode_sprites.gif
index 327b3c31ffd..b010b4e4482 100644
--- a/app/assets/images/swipemode_sprites.gif
+++ b/app/assets/images/swipemode_sprites.gif
Binary files differ
diff --git a/app/assets/images/switch_icon.png b/app/assets/images/switch_icon.png
index 7c11f206593..6b8bde41bc9 100644
--- a/app/assets/images/switch_icon.png
+++ b/app/assets/images/switch_icon.png
Binary files differ
diff --git a/app/assets/images/trans_bg.gif b/app/assets/images/trans_bg.gif
index c7e98e044f5..5f6ed04a43c 100644
--- a/app/assets/images/trans_bg.gif
+++ b/app/assets/images/trans_bg.gif
Binary files differ
diff --git a/app/assets/images/white-scheme-preview.png b/app/assets/images/white-scheme-preview.png
index 67eb8763044..d1866e00158 100644
--- a/app/assets/images/white-scheme-preview.png
+++ b/app/assets/images/white-scheme-preview.png
Binary files differ
diff --git a/app/assets/javascripts/api.js.coffee b/app/assets/javascripts/api.js.coffee
index 5f4a38ebbd0..fafa5cdfaa4 100644
--- a/app/assets/javascripts/api.js.coffee
+++ b/app/assets/javascripts/api.js.coffee
@@ -3,6 +3,7 @@
user_path: "/api/:version/users/:id.json"
notes_path: "/api/:version/projects/:id/notes.json"
namespaces_path: "/api/:version/namespaces.json"
+ project_users_path: "/api/:version/projects/:id/users.json"
# Get 20 (depends on api) recent notes
# and sort the ascending from oldest to newest
@@ -50,6 +51,23 @@
).done (users) ->
callback(users)
+ # Return project users list. Filtered by query
+ # Only active users retrieved
+ projectUsers: (project_id, query, callback) ->
+ url = Api.buildUrl(Api.project_users_path)
+ url = url.replace(':id', project_id)
+
+ $.ajax(
+ url: url
+ data:
+ private_token: gon.api_token
+ search: query
+ per_page: 20
+ active: true
+ dataType: "json"
+ ).done (users) ->
+ callback(users)
+
# Return namespaces list. Filtered by query
namespaces: (query, callback) ->
url = Api.buildUrl(Api.namespaces_path)
diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js
index aa2db1fc93c..4a393dbfe81 100644
--- a/app/assets/javascripts/application.js
+++ b/app/assets/javascripts/application.js
@@ -24,7 +24,8 @@
//= require g.raphael-min
//= require g.bar-min
//= require branch-graph
-//= require ace-src-noconflict/ace
+//= require highlightjs.min
+//= require ace/ace
//= require_tree .
//= require d3
//= require underscore
diff --git a/app/assets/javascripts/blob.js.coffee b/app/assets/javascripts/blob.js.coffee
index 99cb1cec911..584f6faea16 100644
--- a/app/assets/javascripts/blob.js.coffee
+++ b/app/assets/javascripts/blob.js.coffee
@@ -17,7 +17,7 @@ class BlobView
setHash(hash)
e.preventDefault()
-
+
# See if there are lines selected
# "#L12" and "#L34-56" supported
highlightBlobLines = (e) ->
@@ -64,7 +64,7 @@ class BlobView
nodes.attr("id", hash)
# initialize multi-line select
- $("#tree-content-holder .line_numbers a[id^=L]").on("click", handleMultiSelect)
+ $("#tree-content-holder .line-numbers a[id^=L]").on("click", handleMultiSelect)
# Highlight the correct lines on load
highlightBlobLines()
diff --git a/app/assets/javascripts/commit.js.coffee b/app/assets/javascripts/commit.js.coffee
index 9f55a1e6368..5f53439ca4b 100644
--- a/app/assets/javascripts/commit.js.coffee
+++ b/app/assets/javascripts/commit.js.coffee
@@ -1,6 +1,6 @@
class Commit
constructor: ->
- $('.files .file').each ->
+ $('.files .diff-file').each ->
new CommitFile(this)
@Commit = Commit
diff --git a/app/assets/javascripts/dispatcher.js.coffee b/app/assets/javascripts/dispatcher.js.coffee
index e264e281309..46d6db0f05c 100644
--- a/app/assets/javascripts/dispatcher.js.coffee
+++ b/app/assets/javascripts/dispatcher.js.coffee
@@ -4,6 +4,7 @@ $ ->
class Dispatcher
constructor: () ->
@initSearch()
+ @initHighlight()
@initPageScripts()
initPageScripts: ->
@@ -18,6 +19,8 @@ class Dispatcher
switch page
when 'projects:issues:index'
Issues.init()
+ when 'projects:issues:show'
+ new Issue()
when 'projects:issues:new', 'projects:merge_requests:new'
GitLab.GfmAutoComplete.setup()
when 'dashboard:show'
@@ -47,5 +50,16 @@ class Dispatcher
initSearch: ->
- autocomplete_json = $('.search-autocomplete-json').data('autocomplete-opts')
- new SearchAutocomplete(autocomplete_json)
+ opts = $('.search-autocomplete-opts')
+ path = opts.data('autocomplete-path')
+ project_id = opts.data('autocomplete-project-id')
+ project_ref = opts.data('autocomplete-project-ref')
+
+ new SearchAutocomplete(path, project_id, project_ref)
+
+ initHighlight: ->
+ $('.highlight pre code').each (i, e) ->
+ hljs.highlightBlock(e)
+ $(e).html($.map($(e).html().split("\n"), (line, i) ->
+ "<div class='line' id='LC" + (i + 1) + "'>" + line + "</div>"
+ ).join("\n"))
diff --git a/app/assets/javascripts/groups.js.coffee b/app/assets/javascripts/groups.js.coffee
index c0ffccd8f70..7850eb14e74 100644
--- a/app/assets/javascripts/groups.js.coffee
+++ b/app/assets/javascripts/groups.js.coffee
@@ -4,3 +4,14 @@ class GroupMembers
$(this).fadeOut()
@GroupMembers = GroupMembers
+
+$ ->
+ # avatar
+ $('.js-choose-group-avatar-button').bind "click", ->
+ form = $(this).closest("form")
+ form.find(".js-group-avatar-input").click()
+
+ $('.js-group-avatar-input').bind "change", ->
+ form = $(this).closest("form")
+ filename = $(this).val().replace(/^.*[\\\/]/, '')
+ form.find(".js-avatar-filename").text(filename) \ No newline at end of file
diff --git a/app/assets/javascripts/issue.js.coffee b/app/assets/javascripts/issue.js.coffee
new file mode 100644
index 00000000000..36935a0a159
--- /dev/null
+++ b/app/assets/javascripts/issue.js.coffee
@@ -0,0 +1,9 @@
+class Issue
+ constructor: ->
+ $('.edit-issue.inline-update input[type="submit"]').hide()
+ $(".issue-box .inline-update").on "change", "select", ->
+ $(this).submit()
+ $(".issue-box .inline-update").on "change", "#issue_assignee_id", ->
+ $(this).submit()
+
+@Issue = Issue
diff --git a/app/assets/javascripts/issues.js.coffee b/app/assets/javascripts/issues.js.coffee
index 5e60b2775a6..e2f1bc743f7 100644
--- a/app/assets/javascripts/issues.js.coffee
+++ b/app/assets/javascripts/issues.js.coffee
@@ -29,10 +29,10 @@
$('#filter_issue_search').val($('#issue_search').val())
initSelects: ->
- $("select#update_status").select2()
- $("select#update_assignee_id").select2()
- $("select#update_milestone_id").select2()
- $("select#label_name").select2()
+ $("select#update_status").select2(width: 'resolve', dropdownAutoWidth: true)
+ $("select#update_assignee_id").select2(width: 'resolve', dropdownAutoWidth: true)
+ $("select#update_milestone_id").select2(width: 'resolve', dropdownAutoWidth: true)
+ $("select#label_name").select2(width: 'resolve', dropdownAutoWidth: true)
$("#milestone_id, #assignee_id, #label_name").on "change", ->
$(this).closest("form").submit()
@@ -77,9 +77,3 @@
$("#update_issues_ids").val []
$(".issues_bulk_update").hide()
$(".issues-filters").show()
-
-$ ->
- $('.edit-issue.inline-update input[type="submit"]').hide();
- $("body").on "change", ".edit-issue.inline-update select", ->
- $(this).submit()
-
diff --git a/app/assets/javascripts/main.js.coffee b/app/assets/javascripts/main.js.coffee
index 9cf4dba815b..69c731ff1a1 100644
--- a/app/assets/javascripts/main.js.coffee
+++ b/app/assets/javascripts/main.js.coffee
@@ -117,11 +117,11 @@ $ ->
# Commit show suppressed diff
- $(".content").on "click", ".supp_diff_link", ->
+ $(".diff-content").on "click", ".supp_diff_link", ->
$(@).next('table').show()
$(@).remove()
- $(".content").on "click", ".js-details-expand", ->
+ $(".diff-content").on "click", ".js-details-expand", ->
$(@).next('.js-details-contain').removeClass("hide")
$(@).remove()
diff --git a/app/assets/javascripts/merge_request.js.coffee b/app/assets/javascripts/merge_request.js.coffee
new file mode 100644
index 00000000000..c0f83c93021
--- /dev/null
+++ b/app/assets/javascripts/merge_request.js.coffee
@@ -0,0 +1,103 @@
+class MergeRequest
+ constructor: (@opts) ->
+ @initContextWidget()
+ this.$el = $('.merge-request')
+ @diffs_loaded = if @opts.action == 'diffs' then true else false
+ @commits_loaded = false
+
+ this.activateTab(@opts.action)
+
+ this.bindEvents()
+
+ this.initMergeWidget()
+ this.$('.show-all-commits').on 'click', =>
+ this.showAllCommits()
+
+ modal = $('#modal_merge_info').modal(show: false)
+
+ disableButtonIfEmptyField '#merge_commit_message', '.accept_merge_request'
+
+
+ # Local jQuery finder
+ $: (selector) ->
+ this.$el.find(selector)
+
+ initContextWidget: ->
+ $('.edit-merge_request.inline-update input[type="submit"]').hide()
+ $(".issue-box .inline-update").on "change", "select", ->
+ $(this).submit()
+ $(".issue-box .inline-update").on "change", "#merge_request_assignee_id", ->
+ $(this).submit()
+
+ initMergeWidget: ->
+ this.showState( @opts.current_status )
+
+ if this.$('.automerge_widget').length and @opts.check_enable
+ $.get @opts.url_to_automerge_check, (data) =>
+ this.showState( data.merge_status )
+ , 'json'
+
+ if @opts.ci_enable
+ $.get @opts.url_to_ci_check, (data) =>
+ this.showCiState data.status
+ , 'json'
+
+ bindEvents: ->
+ this.$('.nav-tabs').on 'click', 'a', (event) =>
+ a = $(event.currentTarget)
+
+ href = a.attr('href')
+ History.replaceState {path: href}, document.title, href
+
+ event.preventDefault()
+
+ this.$('.nav-tabs').on 'click', 'li', (event) =>
+ this.activateTab($(event.currentTarget).data('action'))
+
+ this.$('.accept_merge_request').on 'click', ->
+ $('.automerge_widget.can_be_merged').hide()
+ $('.merge-in-progress').show()
+
+ activateTab: (action) ->
+ this.$('.nav-tabs li').removeClass 'active'
+ this.$('.tab-content').hide()
+ switch action
+ when 'diffs'
+ this.$('.nav-tabs .diffs-tab').addClass 'active'
+ this.loadDiff() unless @diffs_loaded
+ this.$('.diffs').show()
+ else
+ this.$('.nav-tabs .notes-tab').addClass 'active'
+ this.$('.notes').show()
+
+ showState: (state) ->
+ $('.automerge_widget').hide()
+ $('.automerge_widget.' + state).show()
+
+ showCiState: (state) ->
+ $('.ci_widget').hide()
+ $('.ci_widget.ci-' + state).show()
+
+ loadDiff: (event) ->
+ $.ajax
+ type: 'GET'
+ url: this.$('.nav-tabs .diffs-tab a').attr('href')
+ beforeSend: =>
+ this.$('.status').addClass 'loading'
+ complete: =>
+ @diffs_loaded = true
+ this.$('.status').removeClass 'loading'
+ success: (data) =>
+ this.$(".diffs").html(data.html)
+ dataType: 'json'
+
+ showAllCommits: ->
+ this.$('.first-commits').remove()
+ this.$('.all-commits').removeClass 'hide'
+
+ alreadyOrCannotBeMerged: ->
+ this.$('.automerge_widget').hide()
+ this.$('.merge-in-progress').hide()
+ this.$('.automerge_widget.already_cannot_be_merged').show()
+
+this.MergeRequest = MergeRequest
diff --git a/app/assets/javascripts/merge_requests.js.coffee b/app/assets/javascripts/merge_requests.js.coffee
index 047683f00b2..9201c84c5ed 100644
--- a/app/assets/javascripts/merge_requests.js.coffee
+++ b/app/assets/javascripts/merge_requests.js.coffee
@@ -6,97 +6,3 @@
$('#milestone_id').select2()
$('#milestone_id, #assignee_id').on 'change', ->
$(this).closest('form').submit()
-
-class MergeRequest
-
- constructor: (@opts) ->
- this.$el = $('.merge-request')
- @diffs_loaded = if @opts.action == 'diffs' then true else false
- @commits_loaded = false
-
- this.activateTab(@opts.action)
-
- this.bindEvents()
-
- this.initMergeWidget()
- this.$('.show-all-commits').on 'click', =>
- this.showAllCommits()
-
- modal = $('#modal_merge_info').modal(show: false)
-
- # Local jQuery finder
- $: (selector) ->
- this.$el.find(selector)
-
- initMergeWidget: ->
- this.showState( @opts.current_status )
-
- if this.$('.automerge_widget').length and @opts.check_enable
- $.get @opts.url_to_automerge_check, (data) =>
- this.showState( data.merge_status )
- , 'json'
-
- if @opts.ci_enable
- $.get @opts.url_to_ci_check, (data) =>
- this.showCiState data.status
- , 'json'
-
- bindEvents: ->
- this.$('.nav-tabs').on 'click', 'a', (event) =>
- a = $(event.currentTarget)
-
- href = a.attr('href')
- History.replaceState {path: href}, document.title, href
-
- event.preventDefault()
-
- this.$('.nav-tabs').on 'click', 'li', (event) =>
- this.activateTab($(event.currentTarget).data('action'))
-
- this.$('.accept_merge_request').on 'click', ->
- $('.automerge_widget.can_be_merged').hide()
- $('.merge-in-progress').show()
-
- activateTab: (action) ->
- this.$('.nav-tabs li').removeClass 'active'
- this.$('.tab-content').hide()
- switch action
- when 'diffs'
- this.$('.nav-tabs .diffs-tab').addClass 'active'
- this.loadDiff() unless @diffs_loaded
- this.$('.diffs').show()
- else
- this.$('.nav-tabs .notes-tab').addClass 'active'
- this.$('.notes').show()
-
- showState: (state) ->
- $('.automerge_widget').hide()
- $('.automerge_widget.' + state).show()
-
- showCiState: (state) ->
- $('.ci_widget').hide()
- $('.ci_widget.ci-' + state).show()
-
- loadDiff: (event) ->
- $.ajax
- type: 'GET'
- url: this.$('.nav-tabs .diffs-tab a').attr('href')
- beforeSend: =>
- this.$('.status').addClass 'loading'
- complete: =>
- @diffs_loaded = true
- this.$('.status').removeClass 'loading'
- success: (data) =>
- this.$(".diffs").html(data.html)
- dataType: 'json'
-
- showAllCommits: ->
- this.$('.first-commits').remove()
- this.$('.all-commits').removeClass 'hide'
-
- alreadyOrCannotBeMerged: ->
- this.$('.automerge_widget').hide()
- this.$('.merge-in-progress').hide()
- this.$('.automerge_widget.already_cannot_be_merged').show()
-
-this.MergeRequest = MergeRequest
diff --git a/app/assets/javascripts/notes.js.coffee b/app/assets/javascripts/notes.js.coffee
index 69e9e67f712..d200d962cae 100644
--- a/app/assets/javascripts/notes.js.coffee
+++ b/app/assets/javascripts/notes.js.coffee
@@ -94,6 +94,9 @@ class Notes
if @isNewNote(note)
@note_ids.push(note.id)
$('ul.main-notes-list').append(note.html)
+ code = "#note_" + note.id + " .highlight pre code"
+ $(code).each (i, e) ->
+ hljs.highlightBlock(e)
###
@@ -253,6 +256,9 @@ class Notes
updateNote: (xhr, note, status) =>
note_li = $("#note_" + note.id)
note_li.replaceWith(note.html)
+ code = "#note_" + note.id + " .highlight pre code"
+ $(code).each (i, e) ->
+ hljs.highlightBlock(e)
###
Called in response to clicking the edit note link
diff --git a/app/assets/javascripts/profile.js.coffee b/app/assets/javascripts/profile.js.coffee
index 744f3086d55..b37a78ac197 100644
--- a/app/assets/javascripts/profile.js.coffee
+++ b/app/assets/javascripts/profile.js.coffee
@@ -26,3 +26,5 @@ $ ->
form = $(this).closest("form")
filename = $(this).val().replace(/^.*[\\\/]/, '')
form.find(".js-avatar-filename").text(filename)
+
+ $('.profile-groups-avatars').tooltip("placement": "top") \ No newline at end of file
diff --git a/app/assets/javascripts/project_users_select.js.coffee b/app/assets/javascripts/project_users_select.js.coffee
new file mode 100644
index 00000000000..03fad41c490
--- /dev/null
+++ b/app/assets/javascripts/project_users_select.js.coffee
@@ -0,0 +1,63 @@
+@projectUsersSelect =
+ init: ->
+ $('.ajax-project-users-select').each (i, select) ->
+ project_id = $('body').data('project-id')
+
+ $(select).select2
+ placeholder: $(select).data('placeholder') || "Search for a user"
+ multiple: $(select).hasClass('multiselect')
+ minimumInputLength: 0
+ query: (query) ->
+ Api.projectUsers project_id, query.term, (users) ->
+ data = { results: users }
+
+ nullUser = {
+ name: 'Unassigned',
+ avatar: null,
+ username: 'none',
+ id: ''
+ }
+
+ data.results.unshift(nullUser)
+
+ query.callback(data)
+
+ initSelection: (element, callback) ->
+ id = $(element).val()
+ if id isnt ""
+ Api.user(id, callback)
+
+
+ formatResult: projectUsersSelect.projectUserFormatResult
+ formatSelection: projectUsersSelect.projectUserFormatSelection
+ dropdownCssClass: "ajax-project-users-dropdown"
+ dropdownAutoWidth: true
+ escapeMarkup: (m) -> # we do not want to escape markup since we are displaying html in results
+ m
+
+ projectUserFormatResult: (user) ->
+ if user.avatar_url
+ avatar = user.avatar_url
+ else if gon.gravatar_enabled
+ avatar = gon.gravatar_url
+ avatar = avatar.replace('%{hash}', md5(user.email))
+ avatar = avatar.replace('%{size}', '24')
+ else
+ avatar = gon.relative_url_root + "/assets/no_avatar.png"
+
+ if user.id == ''
+ avatarMarkup = ''
+ else
+ avatarMarkup = "<div class='user-image'><img class='avatar s24' src='#{avatar}'></div>"
+
+ "<div class='user-result'>
+ #{avatarMarkup}
+ <div class='user-name'>#{user.name}</div>
+ <div class='user-username'>#{user.username}</div>
+ </div>"
+
+ projectUserFormatSelection: (user) ->
+ user.name
+
+$ ->
+ projectUsersSelect.init()
diff --git a/app/assets/javascripts/search_autocomplete.js.coffee b/app/assets/javascripts/search_autocomplete.js.coffee
index 3418690e109..e144dfa1d68 100644
--- a/app/assets/javascripts/search_autocomplete.js.coffee
+++ b/app/assets/javascripts/search_autocomplete.js.coffee
@@ -1,7 +1,12 @@
class SearchAutocomplete
- constructor: (json) ->
+ constructor: (search_autocomplete_path, project_id, project_ref) ->
+ project_id = '' unless project_id
+ project_ref = '' unless project_ref
+ query = "?project_id=" + project_id + "&project_ref=" + project_ref
+
$("#search").autocomplete
- source: json
+ source: search_autocomplete_path + query
+ minLength: 1
select: (event, ui) ->
location.href = ui.item.url
diff --git a/app/assets/javascripts/users_select.js.coffee b/app/assets/javascripts/users_select.js.coffee
index 92cd3a9905b..ce9a505b1e3 100644
--- a/app/assets/javascripts/users_select.js.coffee
+++ b/app/assets/javascripts/users_select.js.coffee
@@ -1,11 +1,13 @@
$ ->
userFormatResult = (user) ->
- if user.avatar
- avatar = user.avatar.url
- else
+ if user.avatar_url
+ avatar = user.avatar_url
+ else if gon.gravatar_enabled
avatar = gon.gravatar_url
avatar = avatar.replace('%{hash}', md5(user.email))
avatar = avatar.replace('%{size}', '24')
+ else
+ avatar = gon.relative_url_root + "/assets/no_avatar.png"
"<div class='user-result'>
<div class='user-image'><img class='avatar s24' src='#{avatar}'></div>
diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss
index eb8bc0d63c0..33466714681 100644
--- a/app/assets/stylesheets/application.scss
+++ b/app/assets/stylesheets/application.scss
@@ -5,6 +5,7 @@
*= require jquery.ui.gitlab
*= require jquery.atwho
*= require select2
+ *= require highlightjs.min
*= require_self
*/
@@ -36,8 +37,10 @@
@import "generic/issue_box.scss";
@import "generic/files.scss";
@import "generic/lists.scss";
+@import "generic/flash.scss";
@import "generic/forms.scss";
@import "generic/selects.scss";
+@import "generic/highlight.scss";
/**
* Page specific styles (issues, projects etc):
@@ -45,6 +48,7 @@
@import "sections/header.scss";
@import "sections/nav.scss";
@import "sections/commits.scss";
+@import "sections/diff.scss";
@import "sections/issues.scss";
@import "sections/projects.scss";
@import "sections/snippets.scss";
@@ -63,9 +67,10 @@
@import "sections/wall.scss";
@import "sections/dashboard.scss";
@import "sections/stat_graph.scss";
+@import "sections/groups.scss";
/**
- * Code ighlight
+ * Code highlight
*/
@import "highlight/white.scss";
@import "highlight/dark.scss";
diff --git a/app/assets/stylesheets/generic/blocks.scss b/app/assets/stylesheets/generic/blocks.scss
index 1cbd7439835..3536a68f416 100644
--- a/app/assets/stylesheets/generic/blocks.scss
+++ b/app/assets/stylesheets/generic/blocks.scss
@@ -2,3 +2,18 @@
background: #f9f9f9;
padding: 15px;
}
+
+.centered-light-block {
+ text-align: center;
+ color: #888;
+ margin: 20px;
+}
+
+.nothing-here-block {
+ text-align: center;
+ padding: 20px;
+ color: #666;
+ font-weight: normal;
+ font-size: 16px;
+ line-height: 36px;
+}
diff --git a/app/assets/stylesheets/generic/buttons.scss b/app/assets/stylesheets/generic/buttons.scss
index 219e6ebd68b..dd0a2938cfe 100644
--- a/app/assets/stylesheets/generic/buttons.scss
+++ b/app/assets/stylesheets/generic/buttons.scss
@@ -118,7 +118,6 @@
@extend .btn-primary;
}
- &.btn-close,
&.btn-remove {
@extend .btn-danger;
}
@@ -143,6 +142,30 @@
line-height: 16px;
margin: 2px;
}
+
+ &.btn-close {
+ color: #B94A48;
+ font-weight: bold;
+ &:hover {
+ color: #B94A48;
+ }
+ }
+
+ &.btn-reopen {
+ color: #468847;
+ font-weight: bold;
+ &:hover {
+ color: #468847;
+ }
+ }
+
+ &.btn-grouped {
+ margin-right: 7px;
+ float: left;
+ &:last-child {
+ margin-right: 0px;
+ }
+ }
}
.btn-block {
@@ -154,9 +177,8 @@
}
}
-.btn,
.btn-group {
- &.grouped {
+ &.btn-grouped {
margin-right: 7px;
float: left;
&:last-child {
diff --git a/app/assets/stylesheets/generic/common.scss b/app/assets/stylesheets/generic/common.scss
index 79a217186de..6183cefa594 100644
--- a/app/assets/stylesheets/generic/common.scss
+++ b/app/assets/stylesheets/generic/common.scss
@@ -11,8 +11,6 @@
.bgred { background: #F2DEDE!important }
/** COMMON CLASSES **/
-.left { float:left }
-
.prepend-top-10 { margin-top:10px }
.prepend-top-20 { margin-top:20px }
.prepend-left-10 { margin-left:10px }
@@ -24,32 +22,9 @@
.append-bottom-20 { margin-bottom:20px }
.inline { display: inline-block }
-.padded { padding:20px }
-.ipadded { padding:20px!important }
-.lborder { border-left:1px solid #eee }
-.underlined_link { text-decoration: underline; }
+.underlined-link { text-decoration: underline; }
.hint { font-style: italic; color: #999; }
.light { color: #888 }
-.tiny { font-weight: normal }
-.vtop { vertical-align: top !important; }
-
-
-/** ALERT MESSAGES **/
-.alert.alert-disabled {
- background: #EEE;
- color: #777;
- border-color: #DDD;
-}
-
-/** HELPERS **/
-.nothing_here_message {
- text-align: center;
- padding: 20px;
- color: #666;
- font-weight: normal;
- font-size: 16px;
- line-height: 36px;
-}
.slead {
color: #666;
@@ -59,49 +34,23 @@
line-height: 24px;
}
-
.tab-content {
overflow: visible;
}
-@media (max-width: 1200px) {
- .only-wide {
- display: none;
- }
-}
-
-pre.well-pre {
- border: 1px solid #EEE;
- background: #f9f9f9;
- border-radius: 0;
- color: #555;
-}
-
-.input-append .btn.active, .input-prepend .btn.active {
- background: #CCC;
- border-color: #BBB;
- text-shadow: 0 1px 1px #fff;
- font-weight: bold;
- @include box-shadow(inset 0 2px 4px rgba(0,0,0,.15));
-}
-
-/** Big Labels **/
-.state-label {
- font-size: 14px;
- padding: 6px 25px;
- text-align: center;
- @include border-radius(4px);
- text-shadow: none;
- margin-left: 10px;
-
- &.state-label-green {
- background: #4A4;
- color: #FFF;
+pre {
+ &.clean {
+ background: none;
+ border: none;
+ margin: 0;
+ padding: 0;
}
- &.state-label-red {
- background: #DA4E49;
- color: #FFF;
+ &.well-pre {
+ border: 1px solid #EEE;
+ background: #f9f9f9;
+ border-radius: 0;
+ color: #555;
}
}
@@ -112,6 +61,7 @@ pre.well-pre {
.dropdown-menu > li > a:hover,
.dropdown-menu > li > a:focus {
background: #29b;
+ color: #FFF
}
.breadcrumb > li + li:before {
@@ -130,31 +80,6 @@ pre.well-pre {
}
/** FLASH message **/
-.flash-container {
- display: none;
- cursor: pointer;
- margin: 0;
- text-align: center;
- color: #fff;
- font-size: 14px;
- position: fixed;
- bottom: 0;
- width: 100%;
- opacity: 0.8;
- z-index: 100;
-
- .flash-notice {
- background: #49C;
- padding: 10px;
- text-shadow: 0 1px 1px #178;
- }
-
- .flash-alert {
- background: #C67;
- text-shadow: 0 1px 1px #945;
- padding: 10px;
- }
-}
.author_link {
color: $link_color;
}
@@ -173,12 +98,10 @@ table a code {
.loading {
margin: 20px auto;
- background: url(ajax_loader.gif) no-repeat center center;
- width: 40px;
height: 40px;
- &.loading-gray {
- background: url(ajax_loader_gray.gif) no-repeat center center;
- }
+ color: #555;
+ font-size: 32px;
+ text-align: center;
}
span.update-author {
@@ -276,22 +199,6 @@ li.note {
cursor: pointer;
}
-.merge-request,
-.issue {
- &.today{
- background: #EFE;
- border-color: #CEC;
- }
- &.closed {
- background: #F5f5f5;
- border-color: #E5E5E5;
- }
- &.merged {
- background: #F5f5f5;
- border-color: #E5E5E5;
- }
-}
-
.git_error_tips {
@extend .col-md-6;
text-align: left;
@@ -327,6 +234,12 @@ li.note {
color: #fff;
text-decoration: underline;
}
+
+ .links-xs {
+ text-align: center;
+ font-size: 16px;
+ padding: 5px;
+ }
}
.warning_message {
@@ -349,15 +262,6 @@ li.note {
}
}
-pre {
- &.clean {
- background: none;
- border: none;
- margin: 0;
- padding: 0;
- }
-}
-
.milestone {
&.milestone-closed {
background: #eee;
@@ -441,40 +345,6 @@ table {
margin-bottom: 20px;
}
-.ajax-users-select {
- width: 400px;
-
- &.input-large {
- width: 210px;
- }
-
- &.input-clamp {
- max-width: 100%;
- }
-}
-
-.user-result {
- .user-image {
- float: left;
- }
- .user-name {
- }
- .user-username {
- color: #999;
- }
-}
-
-.namespace-result {
- .namespace-kind {
- color: #AAA;
- font-weight: normal;
- }
- .namespace-path {
- margin-left: 10px;
- font-weight: bolder;
- }
-}
-
.btn-sign-in {
margin-top: 7px;
text-shadow: none;
@@ -485,3 +355,7 @@ table {
margin-bottom: 15px;
}
}
+
+@media (max-width: $screen-xs-max) {
+ .container .content { margin-top: 20px; }
+}
diff --git a/app/assets/stylesheets/generic/files.scss b/app/assets/stylesheets/generic/files.scss
index 6607ae327e0..12559f76051 100644
--- a/app/assets/stylesheets/generic/files.scss
+++ b/app/assets/stylesheets/generic/files.scss
@@ -45,14 +45,14 @@
text-align: center;
img {
padding: 100px;
- max-width: 300px;
+ max-width: 50%;
}
}
&.wiki {
- padding: 20px;
font-size: 14px;
line-height: 1.6;
+ padding: 25px;
.highlight {
margin-bottom: 9px;
@@ -143,75 +143,6 @@
*/
&.code {
padding: 0;
-
- table.lines {
- border: none;
- box-shadow: none;
- margin: 0px;
- padding: 0px;
- table-layout: fixed;
-
- pre {
- border: none;
- border-radius: 0;
- font-family: $monospace_font;
- font-size: 12px !important;
- line-height: 16px !important;
- margin: 0;
- padding: 10px 0;
- }
- td {
- border: none;
- margin: 0;
- padding: 0;
- vertical-align: top;
-
- &:first-child {
- background: #eee;
- width: 50px;
- }
- &:last-child {
- }
- }
- tr:hover {
- background: none;
- }
-
- pre.line_numbers {
- color: #666;
- padding: 10px 6px 10px 0;
- text-align: right;
- background: #EEE;
-
- a {
- color: #666;
-
- i {
- display: none;
- font-size: 14px;
- line-height: 14px;
- }
- &:hover i {
- display: inherit;
- }
- }
- }
-
- .highlight {
- border-left: 1px solid #DEE2E3;
- overflow: auto;
- overflow-y: hidden;
-
- pre {
- white-space: pre;
- word-wrap: normal;
-
- .line {
- padding: 0 10px;
- }
- }
- }
- }
}
}
}
diff --git a/app/assets/stylesheets/generic/flash.scss b/app/assets/stylesheets/generic/flash.scss
new file mode 100644
index 00000000000..95d28aaef6c
--- /dev/null
+++ b/app/assets/stylesheets/generic/flash.scss
@@ -0,0 +1,25 @@
+.flash-container {
+ display: none;
+ cursor: pointer;
+ margin: 0;
+ text-align: center;
+ color: #fff;
+ font-size: 14px;
+ position: fixed;
+ bottom: 0;
+ width: 100%;
+ opacity: 0.8;
+ z-index: 100;
+
+ .flash-notice {
+ background: #49C;
+ padding: 10px;
+ text-shadow: 0 1px 1px #178;
+ }
+
+ .flash-alert {
+ background: #C67;
+ text-shadow: 0 1px 1px #945;
+ padding: 10px;
+ }
+}
diff --git a/app/assets/stylesheets/generic/forms.scss b/app/assets/stylesheets/generic/forms.scss
index 931b75a3234..19e3e7a9536 100644
--- a/app/assets/stylesheets/generic/forms.scss
+++ b/app/assets/stylesheets/generic/forms.scss
@@ -51,3 +51,27 @@ label {
.input-mn-300 {
min-width: 300px;
}
+
+.custom-form-control {
+ width: 150px;
+}
+
+@media (min-width: $screen-sm-min) {
+ .custom-form-control {
+ width: 150px;
+ }
+}
+
+/* Medium devices (desktops, 992px and up) */
+@media (min-width: $screen-md-min) {
+ .custom-form-control {
+ width: 170px;
+ }
+}
+
+/* Large devices (large desktops, 1200px and up) */
+@media (min-width: $screen-lg-min) {
+ .custom-form-control {
+ width: 200px;
+ }
+}
diff --git a/app/assets/stylesheets/generic/highlight.scss b/app/assets/stylesheets/generic/highlight.scss
new file mode 100644
index 00000000000..4110bddf4f3
--- /dev/null
+++ b/app/assets/stylesheets/generic/highlight.scss
@@ -0,0 +1,64 @@
+.highlighted-data {
+ border: none;
+ box-shadow: none;
+ margin: 0px;
+ padding: 0px;
+ table-layout: fixed;
+
+ pre {
+ padding: 10px;
+ border: none;
+ border-radius: 0;
+ font-family: $monospace_font;
+ font-size: 12px !important;
+ line-height: 16px !important;
+ margin: 0;
+
+ code {
+ white-space: pre;
+ word-wrap: normal;
+ padding: 0;
+
+ .line {
+ display: inline;
+ }
+ }
+ }
+
+ .hljs {
+ padding: 0;
+ }
+
+ .line-numbers {
+ padding: 10px;
+ text-align: right;
+ float: left;
+
+ a {
+ font-family: $monospace_font;
+ display: block;
+ font-size: 12px !important;
+ line-height: 16px !important;
+ white-space: nowrap;
+
+ i {
+ visibility: hidden;
+ @extend .pull-left;
+ }
+
+ &:hover i {
+ visibility: visible;
+ }
+ }
+ }
+
+ .highlight {
+ overflow: auto;
+ overflow-y: hidden;
+
+ pre {
+ white-space: pre;
+ word-wrap: normal;
+ }
+ }
+}
diff --git a/app/assets/stylesheets/generic/issue_box.scss b/app/assets/stylesheets/generic/issue_box.scss
index 6330523ea22..3db4d908d9c 100644
--- a/app/assets/stylesheets/generic/issue_box.scss
+++ b/app/assets/stylesheets/generic/issue_box.scss
@@ -10,37 +10,103 @@
.issue-box {
color: #666;
margin:20px 0;
- background: #FAFAFA;
- border: 1px solid #DDD;
+ background: #FFF;
+ border: 1px solid #EEE;
+
+ &.issue-box-closed {
+ border-color: #DA4E49;
+ .state {
+ background-color: #f2dede;
+ border-color: #ebccd1;
+ color: #a94442;
+ .state-label {
+ background: #DA4E49;
+ color: #FFF;
+ }
+ }
+ }
+
+ &.issue-box-merged {
+ border-color: #31708f;
+ .state {
+ background-color: #d9edf7;
+ border-color: #bce8f1;
+ color: #31708f;
+ .state-label {
+ background: #31708f;
+ color: #FFF;
+ }
+ }
+ }
+
+ &.issue-box-open {
+ border-color: #4A4;
+ .state {
+ background-color: #dff0d8;
+ border-color: #d6e9c6;
+ color: #3c763d;
+ .state-label {
+ background: #4A4;
+ color: #FFF;
+ }
+ }
+ }
+
+ &.issue-box-expired {
+ border-color: #cea61b;
+ .state {
+ background-color: #fcf8e3;
+ border-color: #faebcc;
+ color: #8a6d3b;
+ .state-label {
+ background: #cea61b;
+ color: #FFF;
+ }
+ }
+ }
.control-group {
margin-bottom: 0;
}
+ .state {
+ height: 34px;
+ border-bottom: 1px solid #DDD;
+ line-height: 32px;
+ }
+
.title {
- font-size: 20px;
+ font-size: 22px;
font-weight: 500;
- line-height: 28px;
+ line-height: 1.5;
margin: 0;
- color: #444;
+ color: #333;
+ padding-bottom: 0;
+ padding: 15px 25px;
}
.context {
border: none;
- background-color: #f5f5f5;
- border: none;
border-top: 1px solid #eee;
+ padding: 15px 25px;
}
.description {
- border-top: 1px solid #eee;
+ padding: 0 25px 15px 25px;
}
.title, .context, .description {
- padding: 15px;
-
.clearfix {
margin: 0;
}
}
+
+ .state-label {
+ font-size: 14px;
+ padding: 1px 25px;
+ text-align: center;
+ text-shadow: none;
+ margin-right: 20px;
+ display: inline-block;
+ }
}
diff --git a/app/assets/stylesheets/generic/lists.scss b/app/assets/stylesheets/generic/lists.scss
index 245cccf855d..de70e47333f 100644
--- a/app/assets/stylesheets/generic/lists.scss
+++ b/app/assets/stylesheets/generic/lists.scss
@@ -23,6 +23,12 @@
}
}
+ &.warning-row {
+ background-color: #fcf8e3;
+ border-color: #faebcc;
+ color: #8a6d3b;
+ }
+
&.smoke { background-color: #f5f5f5; }
&:hover {
diff --git a/app/assets/stylesheets/generic/selects.scss b/app/assets/stylesheets/generic/selects.scss
index fa10e85664a..03597c1fc7d 100644
--- a/app/assets/stylesheets/generic/selects.scss
+++ b/app/assets/stylesheets/generic/selects.scss
@@ -1,6 +1,5 @@
/** Select2 selectbox style override **/
-
-.select2-container {
+.select2-container, .select2-container.select2-drop-above {
.select2-choice {
background: #FFF;
border-color: #BBB;
@@ -12,8 +11,24 @@
}
.select2-drop-active {
- border: 1px solid #BBB;
+ border: 1px solid #BBB !important;
margin-top: 4px;
+
+ &.select2-drop-above {
+ margin-bottom: 8px;
+ }
+
+ .select2-search input {
+ background: #fafafa;
+ border-color: #DDD;
+ }
+
+ .select2-results {
+ max-height: 350px;
+ .select2-highlighted {
+ background: $bg_style_color;
+ }
+ }
}
select {
@@ -66,3 +81,43 @@ select {
.project-refs-form .select2-container {
margin-right: 10px;
}
+
+.ajax-users-dropdown, .ajax-project-users-dropdown {
+ .select2-search {
+ padding-top: 4px;
+ }
+}
+
+.ajax-users-select {
+ width: 400px;
+
+ &.input-large {
+ width: 210px;
+ }
+
+ &.input-clamp {
+ max-width: 100%;
+ }
+}
+
+.user-result {
+ .user-image {
+ float: left;
+ }
+ .user-name {
+ }
+ .user-username {
+ color: #999;
+ }
+}
+
+.namespace-result {
+ .namespace-kind {
+ color: #AAA;
+ font-weight: normal;
+ }
+ .namespace-path {
+ margin-left: 10px;
+ font-weight: bolder;
+ }
+}
diff --git a/app/assets/stylesheets/generic/typography.scss b/app/assets/stylesheets/generic/typography.scss
index 4490566d4e8..1a07fde53f1 100644
--- a/app/assets/stylesheets/generic/typography.scss
+++ b/app/assets/stylesheets/generic/typography.scss
@@ -90,9 +90,27 @@ a:focus {
font-size: 14px;
line-height: 1.6;
- .white .highlight pre {
- background: #f5f5f5;
+
+ /* Link to current header. */
+ h1, h2, h3, h4, h5, h6 {
+ position: relative;
+ &:hover > :last-child {
+ $size: 16px;
+ position: absolute;
+ right: 100%;
+ top: 50%;
+ margin-top: -$size/2;
+ margin-right: 0px;
+ padding-right: 20px;
+ display: inline-block;
+ width: $size;
+ height: $size;
+ background-image: url("icon-link.png");
+ background-size: contain;
+ background-repeat: no-repeat;
+ }
}
+
ul {
padding: 0;
margin: 0 0 9px 25px !important;
diff --git a/app/assets/stylesheets/gl_bootstrap.scss b/app/assets/stylesheets/gl_bootstrap.scss
index 7f45d64fb7c..169f1268cd7 100644
--- a/app/assets/stylesheets/gl_bootstrap.scss
+++ b/app/assets/stylesheets/gl_bootstrap.scss
@@ -108,6 +108,8 @@ $pagination-active-bg: $bg_style_color;
// Nav tabs
.nav.nav-tabs {
+ margin-bottom: 15px;
+
li {
> a {
padding: 8px 20px;
diff --git a/app/assets/stylesheets/highlight/dark.scss b/app/assets/stylesheets/highlight/dark.scss
index 129d33dcac3..ca51da3fdd4 100644
--- a/app/assets/stylesheets/highlight/dark.scss
+++ b/app/assets/stylesheets/highlight/dark.scss
@@ -1,71 +1,199 @@
-.dark .highlight {
+.dark {
+ background-color: #232323;
- background-color: #333;
+ .line.hll {
+ background: #558;
+ }
+
+ .highlight{
+ border-left: 1px solid #444;
+ }
+
+ .no-highlight {
+ color: #DDD;
+ }
+
+ .line-numbers a {
+ color: #666;
+ }
pre {
- background-color: #333;
- color: #eee;
- }
-
- .hll { display: block; background-color: darken($hover, 65%) }
- .c { color: #888888; font-style: italic } /* Comment */
- .err { color: #a61717; background-color: #e3d2d2 } /* Error */
- .k { color: #CDA869; font-weight: bold } /* Keyword */
- .kp { color: #CDA869; font-weight: bold } /* Keyword */
- .cm { color: #888888 } /* Comment.Multiline */
- .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
- .c1 { color: #888888 } /* Comment.Single */
- .cs { color: #cc0000; font-weight: bold; background-color: transparent } /* Comment.Special */
- .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
- .ge { font-style: italic } /* Generic.Emph */
- .gr { color: #aa0000 } /* Generic.Error */
- .gh { color: #303030 } /* Generic.Heading */
- .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
- .go { color: #888888 } /* Generic.Output */
- .gp { color: #555555 } /* Generic.Prompt */
- .gs { font-weight: bold } /* Generic.Strong */
- .gu { color: #606060 } /* Generic.Subheading */
- .gt { color: #aa0000 } /* Generic.Traceback */
- .kc{font-weight: bold;} /* Keyword.Constant */
- .kd{font-weight: bold;} /* Keyword.Declaration */
- .kn{font-weight: bold;} /* Keyword.Namespace */
- .kp{font-weight: bold;} /* Keyword.Pseudo */
- .kr{font-weight: bold;} /* Keyword.Reserved */
- .kt{color: #458;font-weight: bold;} /* Keyword.Type */
- .m { color: #0000DD; font-weight: bold } /* Literal.Number */
- .p { color: #eee; }
- .s { color: #0AD; background-color: transparent } /* Literal.String */
- .na{color: #008080;} /* Name.Attribute */
- .nb{color: #0086B3;} /* Name.Builtin */
- .nc{color: #ccc;font-weight: bold;} /* Name.Class */
- .no{color: turquoise;} /* Name.Constant */
- .ni{color: #800080;}
- .ne{color: #900;font-weight: bold;} /* Name.Exception */
- .nf{color: #ccc;font-weight: bold;} /* Name.Function */
- .nn{color: #79C3E0;font-weight: bold;} /* Name.Namespace */
- .nt{color: #fc5;} /* Name.Tag */
- .nv{color: #FA4;} /* Name.Variable */
- .py { color: #336699; font-weight: bold } /* Name.Property */
- .ow { color: #008800 } /* Operator.Word */
- .w { color: #bbbbbb } /* Text.Whitespace */
- .mf { color: #7AC; font-weight: bold } /* Literal.Number.Float */
- .mh { color: #7AC; font-weight: bold } /* Literal.Number.Hex */
- .mi {color: #099;} /* Literal.Number.Integer */
- .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
- .sb { color: #dd2200; background-color: transparent; } /* Literal.String.Backtick */
- .sc{color: #d14;} /* Literal.String.Char */
- .sd { color: #dd2200; background-color: transparent; } /* Literal.String.Doc */
- .s2{color: orange;} /* Literal.String.Double */
- .se{color: orange;} /* Literal.String.Escape */
- .sh{color: orange;} /* Literal.String.Heredoc */
- .si{color: orange;} /* Literal.String.Interpol */
- .sx{color: orange;} /* Literal.String.Other */
- .sr{color: orange;} /* Literal.String.Regex */
- .s1{color: orange;} /* Literal.String.Single */
- .ss{color: orange;} /* Literal.String.Symbol */
- .bp { color: #D58 } /* Name.Builtin.Pseudo */
- .vc { color: #336699 } /* Name.Variable.Class */
- .vg { color: #dd7700 } /* Name.Variable.Global */
- .vi { color: cyan }
-}
+ background-color: #232323;
+ }
+
+ .hljs {
+ display: block;
+ background: #232323;
+ color: #E6E1DC;
+ }
+
+ .hljs-comment,
+ .hljs-template_comment,
+ .hljs-javadoc,
+ .hljs-shebang {
+ color: #BC9458;
+ font-style: italic;
+ }
+
+ .hljs-keyword,
+ .ruby .hljs-function .hljs-keyword,
+ .hljs-request,
+ .hljs-status,
+ .nginx .hljs-title,
+ .method,
+ .hljs-list .hljs-title {
+ color: #C26230;
+ }
+
+ .hljs-string,
+ .hljs-number,
+ .hljs-regexp,
+ .hljs-tag .hljs-value,
+ .hljs-cdata,
+ .hljs-filter .hljs-argument,
+ .hljs-attr_selector,
+ .apache .hljs-cbracket,
+ .hljs-date,
+ .tex .hljs-command,
+ .markdown .hljs-link_label {
+ color: #A5C261;
+ }
+
+ .hljs-subst {
+ color: #519F50;
+ }
+
+ .hljs-tag,
+ .hljs-tag .hljs-keyword,
+ .hljs-tag .hljs-title,
+ .hljs-doctype,
+ .hljs-sub .hljs-identifier,
+ .hljs-pi,
+ .input_number {
+ color: #E8BF6A;
+ }
+
+ .hljs-identifier {
+ color: #D0D0FF;
+ }
+
+ .hljs-class .hljs-title,
+ .haskell .hljs-type,
+ .smalltalk .hljs-class,
+ .hljs-javadoctag,
+ .hljs-yardoctag,
+ .hljs-phpdoc {
+ text-decoration: none;
+ }
+
+ .hljs-constant {
+ color: #DA4939;
+ }
+
+
+ .hljs-symbol,
+ .hljs-built_in,
+ .ruby .hljs-symbol .hljs-string,
+ .ruby .hljs-symbol .hljs-identifier,
+ .markdown .hljs-link_url,
+ .hljs-attribute {
+ color: #6D9CBE;
+ }
+
+ .markdown .hljs-link_url {
+ text-decoration: underline;
+ }
+
+
+ .hljs-params,
+ .hljs-variable,
+ .clojure .hljs-attribute {
+ color: #D0D0FF;
+ }
+
+ .css .hljs-tag,
+ .hljs-rules .hljs-property,
+ .hljs-pseudo,
+ .tex .hljs-special {
+ color: #CDA869;
+ }
+
+ .css .hljs-class {
+ color: #9B703F;
+ }
+
+ .hljs-rules .hljs-keyword {
+ color: #C5AF75;
+ }
+
+ .hljs-rules .hljs-value {
+ color: #CF6A4C;
+ }
+
+ .css .hljs-id {
+ color: #8B98AB;
+ }
+
+ .hljs-annotation,
+ .apache .hljs-sqbracket,
+ .nginx .hljs-built_in {
+ color: #9B859D;
+ }
+
+ .hljs-preprocessor,
+ .hljs-preprocessor *,
+ .hljs-pragma {
+ color: #8996A8 !important;
+ }
+
+ .hljs-hexcolor,
+ .css .hljs-value .hljs-number {
+ color: #A5C261;
+ }
+
+ .hljs-title,
+ .hljs-decorator,
+ .css .hljs-function {
+ color: #FFC66D;
+ }
+
+ .diff .hljs-header,
+ .hljs-chunk {
+ background-color: #2F33AB;
+ color: #E6E1DC;
+ display: inline-block;
+ width: 100%;
+ }
+
+ .diff .hljs-change {
+ background-color: #4A410D;
+ color: #F8F8F8;
+ display: inline-block;
+ width: 100%;
+ }
+
+ .hljs-addition {
+ background-color: #144212;
+ color: #E6E1DC;
+ display: inline-block;
+ width: 100%;
+ }
+
+ .hljs-deletion {
+ background-color: #600;
+ color: #E6E1DC;
+ display: inline-block;
+ width: 100%;
+ }
+
+ .coffeescript .javascript,
+ .javascript .xml,
+ .tex .hljs-formula,
+ .xml .javascript,
+ .xml .vbscript,
+ .xml .css,
+ .xml .hljs-cdata {
+ opacity: 0.7;
+ }
+}
diff --git a/app/assets/stylesheets/highlight/monokai.scss b/app/assets/stylesheets/highlight/monokai.scss
index c9709fa7f12..36bc5df2f44 100644
--- a/app/assets/stylesheets/highlight/monokai.scss
+++ b/app/assets/stylesheets/highlight/monokai.scss
@@ -1,89 +1,148 @@
-$monokai-fg: #f8f8f2;
-$monokai-comment: #75715e;
-$monokai-pink: #f92672;
-$monokai-blue: #66d9ef;
-$monokai-green: #a6e22e;
-$monokai-gold: #e6db74;
-$monokai-dark: #3b3a32;
-$monokai-purple: #ae81ff;
+.monokai {
+ background-color: #272822;
-.monokai .highlight {
+ .highlight{
+ border-left: 1px solid #444;
+ }
- background-color: #272822;
+ .line.hll {
+ background: #558;
+ }
+
+ .no-highlight {
+ color: #DDD;
+ }
+
+ .line-numbers a {
+ color: #666;
+ }
pre {
background-color: #272822;
- color: $monokai-fg;
+ color: #f8f8f2;
}
- .hll { background-color: darken($hover, 65%) }
- .c { color: $monokai-comment } /* Comment */
- .err { color: $monokai-fg } /* Error */
- .g { color: $monokai-fg } /* Generic */
- .k { color: $monokai-pink } /* Keyword */
- .l { color: $monokai-fg } /* Literal */
- .n { color: $monokai-blue } /* Name */
- .o { color: $monokai-fg } /* Operator */
- .x { color: $monokai-fg } /* Other */
- .p { color: $monokai-fg } /* Punctuation */
- .cm { color: $monokai-comment } /* Comment.Multiline */
- .cp { color: $monokai-comment } /* Comment.Preproc */
- .c1 { color: $monokai-comment } /* Comment.Single */
- .cs { color: $monokai-comment } /* Comment.Special */
- .gd { color: #8b0807 } /* Generic.Deleted */
- .ge { color: $monokai-fg; text-decoration: underline } /* Generic.Emph */
- .gr { color: $monokai-fg } /* Generic.Error */
- .gh { color: $monokai-fg; font-weight: bold } /* Generic.Heading */
- .gi { color: $monokai-fg; font-weight: bold; background-color: #46830c } /* Generic.Inserted */
- .go { color: $monokai-dark; background-color: #31322c } /* Generic.Output */
- .gp { color: $monokai-fg } /* Generic.Prompt */
- .gs { color: $monokai-fg } /* Generic.Strong */
- .gu { color: $monokai-fg; font-weight: bold } /* Generic.Subheading */
- .gt { color: #f8f8f0; background-color: $monokai-pink } /* Generic.Traceback */
- .kc { color: $monokai-purple } /* Keyword.Constant */
- .kd { color: $monokai-pink } /* Keyword.Declaration */
- .kn { color: $monokai-pink } /* Keyword.Namespace */
- .kp { color: $monokai-pink } /* Keyword.Pseudo */
- .kr { color: $monokai-pink } /* Keyword.Reserved */
- .kt { color: $monokai-fg } /* Keyword.Type */
- .ld { color: $monokai-fg } /* Literal.Date */
- .m { color: $monokai-purple } /* Literal.Number */
- .s { color: $monokai-gold } /* Literal.String */
- .na { color: $monokai-purple } /* Name.Attribute */
- .nb { color: $monokai-blue } /* Name.Builtin */
- .nc { color: $monokai-fg } /* Name.Class */
- .no { color: $monokai-fg } /* Name.Constant */
- .nd { color: $monokai-fg } /* Name.Decorator */
- .ni { color: $monokai-fg } /* Name.Entity */
- .ne { color: $monokai-fg } /* Name.Exception */
- .nf { color: $monokai-green } /* Name.Function */
- .nl { color: $monokai-gold } /* Name.Label */
- .nn { color: $monokai-fg } /* Name.Namespace */
- .nx { color: $monokai-fg } /* Name.Other */
- .nt { color: $monokai-pink } /* Name.Tag */
- .nv { color: $monokai-blue; font-style: italic } /* Name.Variable */
- .py { color: $monokai-fg } /* Name.Property */
- .ow { color: $monokai-pink } /* Operator.Word */
- .w { color: $monokai-fg } /* Text.Whitespace */
- .mf { color: $monokai-purple } /* Literal.Number.Float */
- .mh { color: $monokai-purple } /* Literal.Number.Hex */
- .mi { color: $monokai-purple } /* Literal.Number.Integer */
- .mo { color: $monokai-purple } /* Literal.Number.Oct */
- .sb { color: $monokai-gold } /* Literal.String.Backtick */
- .sc { color: $monokai-gold } /* Literal.String.Char */
- .sd { color: $monokai-gold } /* Literal.String.Doc */
- .s2 { color: $monokai-gold } /* Literal.String.Double */
- .se { color: $monokai-gold } /* Literal.String.Escape */
- .sh { color: $monokai-gold } /* Literal.String.Heredoc */
- .si { color: $monokai-gold } /* Literal.String.Interpol */
- .sx { color: $monokai-gold } /* Literal.String.Other */
- .sr { color: $monokai-gold } /* Literal.String.Regex */
- .s1 { color: $monokai-gold } /* Literal.String.Single */
- .ss { color: $monokai-gold } /* Literal.String.Symbol */
- .bp { color: $monokai-fg } /* Name.Builtin.Pseudo */
- .vc { color: $monokai-blue; font-style: italic } /* Name.Variable.Class */
- .vg { color: $monokai-blue; font-style: italic } /* Name.Variable.Global */
- .vi { color: $monokai-blue; font-style: italic } /* Name.Variable.Instance */
- .il { color: $monokai-purple } /* Literal.Number.Integer.Long */
-}
+ .hljs {
+ display: block;
+ background: #272822;
+ }
+
+ .hljs-tag,
+ .hljs-tag .hljs-title,
+ .hljs-keyword,
+ .hljs-literal,
+ .hljs-strong,
+ .hljs-change,
+ .hljs-winutils,
+ .hljs-flow,
+ .lisp .hljs-title,
+ .clojure .hljs-built_in,
+ .nginx .hljs-title,
+ .tex .hljs-special {
+ color: #F92672;
+ }
+
+ .hljs {
+ color: #DDD;
+ }
+ .hljs .hljs-constant,
+ .asciidoc .hljs-code {
+ color: #66D9EF;
+ }
+
+ .hljs-code,
+ .hljs-class .hljs-title,
+ .hljs-header {
+ color: white;
+ }
+
+ .hljs-link_label,
+ .hljs-attribute,
+ .hljs-symbol,
+ .hljs-symbol .hljs-string,
+ .hljs-value,
+ .hljs-regexp {
+ color: #BF79DB;
+ }
+
+ .hljs-link_url,
+ .hljs-tag .hljs-value,
+ .hljs-string,
+ .hljs-bullet,
+ .hljs-subst,
+ .hljs-title,
+ .hljs-emphasis,
+ .haskell .hljs-type,
+ .hljs-preprocessor,
+ .hljs-pragma,
+ .ruby .hljs-class .hljs-parent,
+ .hljs-built_in,
+ .sql .hljs-aggregate,
+ .django .hljs-template_tag,
+ .django .hljs-variable,
+ .smalltalk .hljs-class,
+ .hljs-javadoc,
+ .django .hljs-filter .hljs-argument,
+ .smalltalk .hljs-localvars,
+ .smalltalk .hljs-array,
+ .hljs-attr_selector,
+ .hljs-pseudo,
+ .hljs-addition,
+ .hljs-stream,
+ .hljs-envvar,
+ .apache .hljs-tag,
+ .apache .hljs-cbracket,
+ .tex .hljs-command,
+ .hljs-prompt {
+ color: #A6E22E;
+ }
+
+ .hljs-comment,
+ .java .hljs-annotation,
+ .smartquote,
+ .hljs-blockquote,
+ .hljs-horizontal_rule,
+ .python .hljs-decorator,
+ .hljs-template_comment,
+ .hljs-pi,
+ .hljs-doctype,
+ .hljs-deletion,
+ .hljs-shebang,
+ .apache .hljs-sqbracket,
+ .tex .hljs-formula {
+ color: #75715E;
+ }
+
+ .hljs-keyword,
+ .hljs-literal,
+ .css .hljs-id,
+ .hljs-phpdoc,
+ .hljs-title,
+ .hljs-header,
+ .haskell .hljs-type,
+ .vbscript .hljs-built_in,
+ .sql .hljs-aggregate,
+ .rsl .hljs-built_in,
+ .smalltalk .hljs-class,
+ .diff .hljs-header,
+ .hljs-chunk,
+ .hljs-winutils,
+ .bash .hljs-variable,
+ .apache .hljs-tag,
+ .tex .hljs-special,
+ .hljs-request,
+ .hljs-status {
+ font-weight: bold;
+ }
+
+ .coffeescript .javascript,
+ .javascript .xml,
+ .tex .hljs-formula,
+ .xml .javascript,
+ .xml .vbscript,
+ .xml .css,
+ .xml .hljs-cdata {
+ opacity: 0.5;
+ }
+}
diff --git a/app/assets/stylesheets/highlight/solarized_dark.scss b/app/assets/stylesheets/highlight/solarized_dark.scss
index cc82f39ac93..b9bec225188 100644
--- a/app/assets/stylesheets/highlight/solarized_dark.scss
+++ b/app/assets/stylesheets/highlight/solarized_dark.scss
@@ -1,80 +1,125 @@
-.solarized-dark .highlight {
-
+.solarized-dark {
background-color: #002B36;
-
+
+ .highlight{
+ border-left: 1px solid #113b46;
+ }
+
+ .line.hll {
+ background: #000;
+ }
+
+ .no-highlight {
+ color: #DDD;
+ }
+
pre {
background-color: #002B36;
color: #eee;
}
- .hll { background-color: #073642 }
- .c { color: #586E75 } /* Comment */
- .err { color: #93A1A1 } /* Error */
- .g { color: #93A1A1 } /* Generic */
- .k { color: #859900 } /* Keyword */
- .l { color: #93A1A1 } /* Literal */
- .n { color: #93A1A1 } /* Name */
- .o { color: #859900 } /* Operator */
- .x { color: #CB4B16 } /* Other */
- .p { color: #93A1A1 } /* Punctuation */
- .cm { color: #586E75 } /* Comment.Multiline */
- .cp { color: #859900 } /* Comment.Preproc */
- .c1 { color: #586E75 } /* Comment.Single */
- .cs { color: #859900 } /* Comment.Special */
- .gd { color: #2AA198 } /* Generic.Deleted */
- .ge { color: #93A1A1; font-style: italic } /* Generic.Emph */
- .gr { color: #DC322F } /* Generic.Error */
- .gh { color: #CB4B16 } /* Generic.Heading */
- .gi { color: #859900 } /* Generic.Inserted */
- .go { color: #93A1A1 } /* Generic.Output */
- .gp { color: #93A1A1 } /* Generic.Prompt */
- .gs { color: #93A1A1; font-weight: bold } /* Generic.Strong */
- .gu { color: #CB4B16 } /* Generic.Subheading */
- .gt { color: #93A1A1 } /* Generic.Traceback */
- .kc { color: #CB4B16 } /* Keyword.Constant */
- .kd { color: #268BD2 } /* Keyword.Declaration */
- .kn { color: #859900 } /* Keyword.Namespace */
- .kp { color: #859900 } /* Keyword.Pseudo */
- .kr { color: #268BD2 } /* Keyword.Reserved */
- .kt { color: #DC322F } /* Keyword.Type */
- .ld { color: #93A1A1 } /* Literal.Date */
- .m { color: #2AA198 } /* Literal.Number */
- .s { color: #2AA198 } /* Literal.String */
- .na { color: #93A1A1 } /* Name.Attribute */
- .nb { color: #B58900 } /* Name.Builtin */
- .nc { color: #268BD2 } /* Name.Class */
- .no { color: #CB4B16 } /* Name.Constant */
- .nd { color: #268BD2 } /* Name.Decorator */
- .ni { color: #CB4B16 } /* Name.Entity */
- .ne { color: #CB4B16 } /* Name.Exception */
- .nf { color: #268BD2 } /* Name.Function */
- .nl { color: #93A1A1 } /* Name.Label */
- .nn { color: #93A1A1 } /* Name.Namespace */
- .nx { color: #93A1A1 } /* Name.Other */
- .py { color: #93A1A1 } /* Name.Property */
- .nt { color: #268BD2 } /* Name.Tag */
- .nv { color: #268BD2 } /* Name.Variable */
- .ow { color: #859900 } /* Operator.Word */
- .w { color: #93A1A1 } /* Text.Whitespace */
- .mf { color: #2AA198 } /* Literal.Number.Float */
- .mh { color: #2AA198 } /* Literal.Number.Hex */
- .mi { color: #2AA198 } /* Literal.Number.Integer */
- .mo { color: #2AA198 } /* Literal.Number.Oct */
- .sb { color: #586E75 } /* Literal.String.Backtick */
- .sc { color: #2AA198 } /* Literal.String.Char */
- .sd { color: #93A1A1 } /* Literal.String.Doc */
- .s2 { color: #2AA198 } /* Literal.String.Double */
- .se { color: #CB4B16 } /* Literal.String.Escape */
- .sh { color: #93A1A1 } /* Literal.String.Heredoc */
- .si { color: #2AA198 } /* Literal.String.Interpol */
- .sx { color: #2AA198 } /* Literal.String.Other */
- .sr { color: #DC322F } /* Literal.String.Regex */
- .s1 { color: #2AA198 } /* Literal.String.Single */
- .ss { color: #2AA198 } /* Literal.String.Symbol */
- .bp { color: #268BD2 } /* Name.Builtin.Pseudo */
- .vc { color: #268BD2 } /* Name.Variable.Class */
- .vg { color: #268BD2 } /* Name.Variable.Global */
- .vi { color: #268BD2 } /* Name.Variable.Instance */
- .il { color: #2AA198 } /* Literal.Number.Integer.Long */
-}
+ .line-numbers a {
+ color: #666;
+ }
+
+ .hljs {
+ display: block;
+ background: #002b36;
+ color: #839496;
+ }
+
+ .hljs-comment,
+ .hljs-template_comment,
+ .diff .hljs-header,
+ .hljs-doctype,
+ .hljs-pi,
+ .lisp .hljs-string,
+ .hljs-javadoc {
+ color: #586e75;
+ }
+
+ /* Solarized Green */
+ .hljs-keyword,
+ .hljs-winutils,
+ .method,
+ .hljs-addition,
+ .css .hljs-tag,
+ .hljs-request,
+ .hljs-status,
+ .nginx .hljs-title {
+ color: #859900;
+ }
+ /* Solarized Cyan */
+ .hljs-number,
+ .hljs-command,
+ .hljs-string,
+ .hljs-tag .hljs-value,
+ .hljs-rules .hljs-value,
+ .hljs-phpdoc,
+ .tex .hljs-formula,
+ .hljs-regexp,
+ .hljs-hexcolor,
+ .hljs-link_url {
+ color: #2aa198;
+ }
+
+ /* Solarized Blue */
+ .hljs-title,
+ .hljs-localvars,
+ .hljs-chunk,
+ .hljs-decorator,
+ .hljs-built_in,
+ .hljs-identifier,
+ .vhdl .hljs-literal,
+ .hljs-id,
+ .css .hljs-function {
+ color: #268bd2;
+ }
+
+ /* Solarized Yellow */
+ .hljs-attribute,
+ .hljs-variable,
+ .lisp .hljs-body,
+ .smalltalk .hljs-number,
+ .hljs-constant,
+ .hljs-class .hljs-title,
+ .hljs-parent,
+ .haskell .hljs-type,
+ .hljs-link_reference {
+ color: #b58900;
+ }
+
+ /* Solarized Orange */
+ .hljs-preprocessor,
+ .hljs-preprocessor .hljs-keyword,
+ .hljs-pragma,
+ .hljs-shebang,
+ .hljs-symbol,
+ .hljs-symbol .hljs-string,
+ .diff .hljs-change,
+ .hljs-special,
+ .hljs-attr_selector,
+ .hljs-subst,
+ .hljs-cdata,
+ .clojure .hljs-title,
+ .css .hljs-pseudo,
+ .hljs-header {
+ color: #cb4b16;
+ }
+
+ /* Solarized Red */
+ .hljs-deletion,
+ .hljs-important {
+ color: #dc322f;
+ }
+
+ /* Solarized Violet */
+ .hljs-link_label {
+ color: #6c71c4;
+ }
+
+ .tex .hljs-formula {
+ background: #073642;
+ }
+}
diff --git a/app/assets/stylesheets/highlight/white.scss b/app/assets/stylesheets/highlight/white.scss
index df127a7c491..c06bed3c21e 100644
--- a/app/assets/stylesheets/highlight/white.scss
+++ b/app/assets/stylesheets/highlight/white.scss
@@ -1,72 +1,186 @@
-.white .highlight {
-
+.white {
background-color: #fff;
-
+
+ .line.hll {
+ background: #FFA;
+ }
+
+ .highlight{
+ border-left: 1px solid #eee;
+ }
+
pre {
background-color: #fff;
color: #333;
}
- .hll { display: block; background-color: $hover }
- .c { color: #888888; font-style: italic } /* Comment */
- .err { color: #a61717; background-color: #e3d2d2 } /* Error */
- .k { color: #000000; font-weight: bold } /* Keyword */
- .cm { color: #888888 } /* Comment.Multiline */
- .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
- .c1 { color: #888888 } /* Comment.Single */
- .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
- .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
- .ge { font-style: italic } /* Generic.Emph */
- .gr { color: #aa0000 } /* Generic.Error */
- .gh { color: #303030 } /* Generic.Heading */
- .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
- .go { color: #888888 } /* Generic.Output */
- .gp { color: #555555 } /* Generic.Prompt */
- .gs { font-weight: bold } /* Generic.Strong */
- .gu { color: #606060 } /* Generic.Subheading */
- .gt { color: #aa0000 } /* Generic.Traceback */
- .kc{font-weight: bold;} /* Keyword.Constant */
- .kd{font-weight: bold;} /* Keyword.Declaration */
- .kn{font-weight: bold;} /* Keyword.Namespace */
- .kp{font-weight: bold;} /* Keyword.Pseudo */
- .kr{font-weight: bold;} /* Keyword.Reserved */
- .kt{color: #458;font-weight: bold;} /* Keyword.Type */
- .m { color: #0000DD; font-weight: bold } /* Literal.Number */
- .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
- .na{color: #008080;} /* Name.Attribute */
- .nb{color: #0086B3;} /* Name.Builtin */
- .nc{color: #458;font-weight: bold;} /* Name.Class */
- .no{color: #008080;} /* Name.Constant */
- .ni{color: #800080;}
- .ne{color: #900;font-weight: bold;} /* Name.Exception */
- .nf{color: #900;font-weight: bold;} /* Name.Function */
- .nn{color: #005;font-weight: bold;} /* Name.Namespace */
- .nt{color: #000080;} /* Name.Tag */
- .nv{color: #008080;} /* Name.Variable */
- .py { color: #336699; font-weight: bold } /* Name.Property */
- .ow { color: #008800 } /* Operator.Word */
- .w { color: #bbbbbb } /* Text.Whitespace */
- .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
- .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
- .mi {color: #099;} /* Literal.Number.Integer */
- .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
- .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
- .sc{color: #d14;} /* Literal.String.Char */
- .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
- .s2{color: #d14;} /* Literal.String.Double */
- .se{color: #d14;} /* Literal.String.Escape */
- .sh{color: #d14;} /* Literal.String.Heredoc */
- .si{color: #d14;} /* Literal.String.Interpol */
- .sx{color: #d14;} /* Literal.String.Other */
- .sr{color: #d14;} /* Literal.String.Regex */
- .s1{color: #d14;} /* Literal.String.Single */
- .ss{color: #d14;} /* Literal.String.Symbol */
- .bp { color: #003388 } /* Name.Builtin.Pseudo */
- .vc { color: #336699 } /* Name.Variable.Class */
- .vg { color: #dd7700 } /* Name.Variable.Global */
- .vi { color: #3333bb }
+ .hljs {
+ background: #FFF;
+ }
+
+ .line-numbers a {
+ color: #999;
+ }
+
+ .hljs {
+ display: block;
+ background: #fff; color: black;
+ }
+
+ .hljs-comment,
+ .hljs-template_comment,
+ .hljs-javadoc,
+ .hljs-comment * {
+ color: #006a00;
+ }
+
+ .hljs-keyword,
+ .hljs-literal,
+ .nginx .hljs-title {
+ color: #aa0d91;
+ }
+ .method,
+ .hljs-list .hljs-title,
+ .hljs-tag .hljs-title,
+ .setting .hljs-value,
+ .hljs-winutils,
+ .tex .hljs-command,
+ .http .hljs-title,
+ .hljs-request,
+ .hljs-status {
+ color: #008;
+ }
+
+ .hljs-envvar,
+ .tex .hljs-special {
+ color: #660;
+ }
+
+ .hljs-string {
+ color: #c41a16;
+ }
+ .hljs-tag .hljs-value,
+ .hljs-cdata,
+ .hljs-filter .hljs-argument,
+ .hljs-attr_selector,
+ .apache .hljs-cbracket,
+ .hljs-date,
+ .hljs-regexp {
+ color: #080;
+ }
+
+ .hljs-sub .hljs-identifier,
+ .hljs-pi,
+ .hljs-tag,
+ .hljs-tag .hljs-keyword,
+ .hljs-decorator,
+ .ini .hljs-title,
+ .hljs-shebang,
+ .hljs-prompt,
+ .hljs-hexcolor,
+ .hljs-rules .hljs-value,
+ .hljs-symbol,
+ .hljs-symbol .hljs-string,
+ .hljs-number,
+ .css .hljs-function,
+ .clojure .hljs-title,
+ .clojure .hljs-built_in,
+ .hljs-function .hljs-title,
+ .coffeescript .hljs-attribute {
+ color: #1c00cf;
+ }
+
+ .hljs-class .hljs-title,
+ .haskell .hljs-type,
+ .smalltalk .hljs-class,
+ .hljs-javadoctag,
+ .hljs-yardoctag,
+ .hljs-phpdoc,
+ .hljs-typename,
+ .hljs-tag .hljs-attribute,
+ .hljs-doctype,
+ .hljs-class .hljs-id,
+ .hljs-built_in,
+ .setting,
+ .hljs-params,
+ .clojure .hljs-attribute {
+ color: #5c2699;
+ }
+
+ .hljs-variable {
+ color: #3f6e74;
+ }
+ .css .hljs-tag,
+ .hljs-rules .hljs-property,
+ .hljs-pseudo,
+ .hljs-subst {
+ color: #000;
+ }
+
+ .css .hljs-class,
+ .css .hljs-id {
+ color: #9B703F;
+ }
+
+ .hljs-value .hljs-important {
+ color: #ff7700;
+ font-weight: bold;
+ }
+
+ .hljs-rules .hljs-keyword {
+ color: #C5AF75;
+ }
+
+ .hljs-annotation,
+ .apache .hljs-sqbracket,
+ .nginx .hljs-built_in {
+ color: #9B859D;
+ }
+
+ .hljs-preprocessor,
+ .hljs-preprocessor *,
+ .hljs-pragma {
+ color: #643820;
+ }
+
+ .tex .hljs-formula {
+ background-color: #EEE;
+ font-style: italic;
+ }
+
+ .diff .hljs-header,
+ .hljs-chunk {
+ color: #808080;
+ font-weight: bold;
+ }
+
+ .diff .hljs-change {
+ background-color: #BCCFF9;
+ }
+
+ .hljs-addition {
+ background-color: #BAEEBA;
+ }
+
+ .hljs-deletion {
+ background-color: #FFC8BD;
+ }
+
+ .hljs-comment .hljs-yardoctag {
+ font-weight: bold;
+ }
+
+ .method .hljs-id {
+ color: #000;
+ }
}
.shadow {
@include box-shadow(0 5px 15px #000);
}
+
+.wiki, .note-body {
+ .highlight {
+ border: 1px solid #DDD;
+ }
+}
diff --git a/app/assets/stylesheets/main/layout.scss b/app/assets/stylesheets/main/layout.scss
index a4d889f26dd..e28da65c01f 100644
--- a/app/assets/stylesheets/main/layout.scss
+++ b/app/assets/stylesheets/main/layout.scss
@@ -1,11 +1,11 @@
html {
overflow-y: scroll;
+
+ &.touch .tooltip { display: none !important; }
}
body {
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
- margin-bottom: 20px;
+ padding-bottom: 20px;
}
.container {
diff --git a/app/assets/stylesheets/main/mixins.scss b/app/assets/stylesheets/main/mixins.scss
index e637b645b55..4afe61d756c 100644
--- a/app/assets/stylesheets/main/mixins.scss
+++ b/app/assets/stylesheets/main/mixins.scss
@@ -106,12 +106,12 @@
h3 {
margin-top: 35px;
- font-size: 2em;
+ font-size: 1.5em;
}
h4 {
margin-top: 30px;
- font-size: 1.5em;
+ font-size: 1.2em;
}
blockquote p {
@@ -128,7 +128,7 @@
}
}
- code {
+ p > code {
font-size: inherit;
font-weight: inherit;
color: #555;
diff --git a/app/assets/stylesheets/main/variables.scss b/app/assets/stylesheets/main/variables.scss
index decc5f50469..4b5fa0979be 100644
--- a/app/assets/stylesheets/main/variables.scss
+++ b/app/assets/stylesheets/main/variables.scss
@@ -5,6 +5,7 @@ $primary_color: #2FA0BB;
$link_color: #3A89A3;
$style_color: #474D57;
$bg_style_color: #2299BB;
+$list-group-active-bg: $bg_style_color;
$hover: #D9EDF7;
/**
diff --git a/app/assets/stylesheets/sections/admin.scss b/app/assets/stylesheets/sections/admin.scss
index 8ad9bc732b2..a558633d112 100644
--- a/app/assets/stylesheets/sections/admin.scss
+++ b/app/assets/stylesheets/sections/admin.scss
@@ -2,7 +2,7 @@
* Admin area
*
*/
-.admin_dash {
+.admin-dashboard {
.data {
a {
h1 {
@@ -14,6 +14,10 @@
}
}
}
+
+ .str-truncated {
+ max-width: 60%;
+ }
}
.admin-filter form {
diff --git a/app/assets/stylesheets/sections/commits.scss b/app/assets/stylesheets/sections/commits.scss
index ff293bc4a00..f3355c8f1d6 100644
--- a/app/assets/stylesheets/sections/commits.scss
+++ b/app/assets/stylesheets/sections/commits.scss
@@ -10,331 +10,6 @@
}
}
-.file {
- border: 1px solid #CCC;
- margin-bottom: 1em;
-
- .header {
- @extend .clearfix;
- background: #DDD;
- border-bottom: 1px solid #CCC;
- padding: 5px 5px 5px 10px;
- color: #555;
-
- > span {
- font-family: $monospace_font;
- font-size: 14px;
- line-height: 2;
- }
-
- .view-file {
- font-weight: bold;
- float: right;
- background-color: #EEE;
- }
-
- .commit-short-id {
- font-family: $monospace_font;
- font-size: smaller;
- }
-
- .file-mode {
- font-family: $monospace_font;
- }
- }
- .content {
- overflow: auto;
- overflow-y: hidden;
- background: #FFF;
- color: #333;
- font-size: 12px;
- .old {
- span.idiff {
- background-color: #FAA;
- }
- }
- .new {
- span.idiff {
- background-color: #AFA;
- }
- }
-
- table {
- width: 100%;
- font-family: $monospace_font;
- border: none;
- margin: 0px;
- padding: 0px;
- td {
- line-height: 18px;
- font-size: 12px;
- }
- }
- .old_line, .new_line, .diff_line {
- margin: 0px;
- padding: 0px;
- border: none;
- background: #EEE;
- color: #666;
- padding: 0px 5px;
- border-right: 1px solid #ccc;
- text-align: right;
- min-width: 35px;
- max-width: 50px;
- width: 35px;
- @include user-select(none);
- a {
- float: left;
- width: 35px;
- font-weight: normal;
- color: #666;
- &:hover {
- text-decoration: underline;
- }
- }
- &.new {
- background: #CFD;
- }
- &.old {
- background: #FDD;
- }
- }
- .diff_line {
- padding: 0;
- }
- .line_holder {
- &.old .old_line,
- &.old .new_line {
- background: #FCC;
- border-color: #E7BABA;
- }
- &.new .old_line,
- &.new .new_line {
- background: #CFC;
- border-color: #B9ECB9;
- }
- }
- .line_content {
- display: block;
- white-space: pre;
- height: 18px;
- margin: 0px;
- padding: 0px 0.5em;
- border: none;
- &.new {
- background: #CFD;
- }
- &.old {
- background: #FDD;
- }
- &.matched {
- color: #ccc;
- background: #fafafa;
- }
- &.parallel {
- display: table-cell;
- overflow: hidden;
- width: 50%;
- }
- }
- }
- .image {
- background: #ddd;
- text-align: center;
- padding: 30px;
- .wrap{
- display: inline-block;
- }
-
- .frame {
- display: inline-block;
- background-color: #fff;
- line-height: 0;
- img{
- border: 1px solid #FFF;
- background: url('trans_bg.gif');
- }
- &.deleted {
- border: 1px solid $deleted;
- }
-
- &.added {
- border: 1px solid $added;
- }
- }
- .image-info{
- font-size: 12px;
- margin: 5px 0 0 0;
- color: grey;
- }
-
- .view.swipe{
- position: relative;
-
- .swipe-frame{
- display: block;
- margin: auto;
- position: relative;
- }
- .swipe-wrap{
- overflow: hidden;
- border-left: 1px solid #999;
- position: absolute;
- display: block;
- top: 13px;
- right: 7px;
- }
- .frame{
- top: 0;
- right: 0;
- position: absolute;
- &.deleted{
- margin: 0;
- display: block;
- top: 13px;
- right: 7px;
- }
- }
- .swipe-bar{
- display: block;
- height: 100%;
- width: 15px;
- z-index: 100;
- position: absolute;
- cursor: pointer;
- &:hover{
- .top-handle{
- background-position: -15px 3px;
- }
- .bottom-handle{
- background-position: -15px -11px;
- }
- };
- .top-handle{
- display: block;
- height: 14px;
- width: 15px;
- position: absolute;
- top: 0px;
- background: url('swipemode_sprites.gif') 0 3px no-repeat;
- }
- .bottom-handle{
- display: block;
- height: 14px;
- width: 15px;
- position: absolute;
- bottom: 0px;
- background: url('swipemode_sprites.gif') 0 -11px no-repeat;
- }
- }
- } //.view.swipe
- .view.onion-skin{
- .onion-skin-frame{
- display: block;
- margin: auto;
- position: relative;
- }
- .frame.added, .frame.deleted {
- position: absolute;
- display: block;
- top: 0px;
- left: 0px;
- }
- .controls{
- display: block;
- height: 14px;
- width: 300px;
- z-index: 100;
- position: absolute;
- bottom: 0px;
- left: 50%;
- margin-left: -150px;
-
- .drag-track{
- display: block;
- position: absolute;
- left: 12px;
- height: 10px;
- width: 276px;
- background: url('onion_skin_sprites.gif') -4px -20px repeat-x;
- }
-
- .dragger {
- display: block;
- position: absolute;
- left: 0px;
- top: 0px;
- height: 14px;
- width: 14px;
- background: url('onion_skin_sprites.gif') 0px -34px repeat-x;
- cursor: pointer;
- }
-
- .transparent {
- display: block;
- position: absolute;
- top: 2px;
- right: 0px;
- height: 10px;
- width: 10px;
- background: url('onion_skin_sprites.gif') -2px 0px no-repeat;
- }
-
- .opaque {
- display: block;
- position: absolute;
- top: 2px;
- left: 0px;
- height: 10px;
- width: 10px;
- background: url('onion_skin_sprites.gif') -2px -10px no-repeat;
- }
- }
- } //.view.onion-skin
- }
- .view-modes{
-
- padding: 10px;
- text-align: center;
-
- background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf));
- background-image: -webkit-linear-gradient(#eee 6.6%, #dfdfdf);
- background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf);
- background-image: -ms-linear-gradient(#eee 6.6%, #dfdfdf);
- background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf);
-
- ul, li{
- list-style: none;
- margin: 0;
- padding: 0;
- display: inline-block;
- }
-
- li{
- color: grey;
- border-left: 1px solid #c1c1c1;
- padding: 0 12px 0 16px;
- cursor: pointer;
- &:first-child{
- border-left: none;
- }
- &:hover{
- text-decoration: underline;
- }
- &.active{
- &:hover{
- text-decoration: none;
- }
- cursor: default;
- color: #333;
- }
- &.disabled{
- display: none;
- }
- }
- }
-}
-
/** COMMIT BLOCK **/
.commit-title{
display: block;
@@ -493,6 +168,25 @@ li.commit {
text-decoration: underline;
}
}
+
+ .text-expander {
+ background: #eee;
+ color: #555;
+ padding: 0 5px;
+ cursor: pointer;
+ margin-left: 4px;
+ &:hover {
+ background-color: #ddd;
+ }
+ }
+ }
+
+ .commit-row-description {
+ font-size: 14px;
+ border-left: 1px solid #e5e5e5;
+ padding: 0 15px 0 7px;
+ margin: 5px 0 10px 5px;
+ display: none;
}
.commit-row-info {
diff --git a/app/assets/stylesheets/sections/dashboard.scss b/app/assets/stylesheets/sections/dashboard.scss
index 1fd82c84fc9..6fc394e2e2b 100644
--- a/app/assets/stylesheets/sections/dashboard.scss
+++ b/app/assets/stylesheets/sections/dashboard.scss
@@ -41,7 +41,7 @@
.dash-sidebar-tabs {
margin-bottom: 2px;
border: none;
- margin: 0;
+ margin: 0 !important;
li {
&.active {
diff --git a/app/assets/stylesheets/sections/diff.scss b/app/assets/stylesheets/sections/diff.scss
new file mode 100644
index 00000000000..74d144dfb06
--- /dev/null
+++ b/app/assets/stylesheets/sections/diff.scss
@@ -0,0 +1,329 @@
+.diff-file {
+ border: 1px solid #CCC;
+ margin-bottom: 1em;
+
+ .diff-header {
+ @extend .clearfix;
+ background: #DDD;
+ border-bottom: 1px solid #CCC;
+ padding: 5px 5px 5px 10px;
+ color: #555;
+
+ > span {
+ font-family: $monospace_font;
+ font-size: 14px;
+ line-height: 2;
+ }
+
+ .diff-btn-group {
+ float: right;
+
+ .btn {
+ background-color: #EEE;
+ color: #666;
+ font-weight: bolder;
+ }
+ }
+
+ .commit-short-id {
+ font-family: $monospace_font;
+ font-size: smaller;
+ }
+
+ .file-mode {
+ font-family: $monospace_font;
+ }
+ }
+ .diff-content {
+ overflow: auto;
+ overflow-y: hidden;
+ background: #FFF;
+ color: #333;
+ font-size: 12px;
+ .old {
+ span.idiff {
+ background-color: #FAA;
+ }
+ }
+ .new {
+ span.idiff {
+ background-color: #AFA;
+ }
+ }
+
+ table {
+ width: 100%;
+ font-family: $monospace_font;
+ border: none;
+ margin: 0px;
+ padding: 0px;
+ td {
+ line-height: 18px;
+ font-size: 12px;
+ }
+ }
+ .old_line, .new_line, .diff_line {
+ margin: 0px;
+ padding: 0px;
+ border: none;
+ background: #EEE;
+ color: #666;
+ padding: 0px 5px;
+ border-right: 1px solid #ccc;
+ text-align: right;
+ min-width: 35px;
+ max-width: 50px;
+ width: 35px;
+ @include user-select(none);
+ a {
+ float: left;
+ width: 35px;
+ font-weight: normal;
+ color: #666;
+ &:hover {
+ text-decoration: underline;
+ }
+ }
+ &.new {
+ background: #CFD;
+ }
+ &.old {
+ background: #FDD;
+ }
+ }
+ .diff_line {
+ padding: 0;
+ }
+ .line_holder {
+ &.old .old_line,
+ &.old .new_line {
+ background: #FCC;
+ border-color: #E7BABA;
+ }
+ &.new .old_line,
+ &.new .new_line {
+ background: #CFC;
+ border-color: #B9ECB9;
+ }
+ }
+ .line_content {
+ display: block;
+ white-space: pre;
+ height: 18px;
+ margin: 0px;
+ padding: 0px 0.5em;
+ border: none;
+ &.new {
+ background: #CFD;
+ }
+ &.old {
+ background: #FDD;
+ }
+ &.matched {
+ color: #ccc;
+ background: #fafafa;
+ }
+ &.parallel {
+ display: table-cell;
+ overflow: hidden;
+ width: 50%;
+ }
+ }
+ }
+ .image {
+ background: #ddd;
+ text-align: center;
+ padding: 30px;
+ .wrap{
+ display: inline-block;
+ }
+
+ .frame {
+ display: inline-block;
+ background-color: #fff;
+ line-height: 0;
+ img{
+ border: 1px solid #FFF;
+ background: url('trans_bg.gif');
+ max-width: 100%;
+ }
+ &.deleted {
+ border: 1px solid $deleted;
+ }
+
+ &.added {
+ border: 1px solid $added;
+ }
+ }
+ .image-info{
+ font-size: 12px;
+ margin: 5px 0 0 0;
+ color: grey;
+ }
+
+ .view.swipe{
+ position: relative;
+
+ .swipe-frame{
+ display: block;
+ margin: auto;
+ position: relative;
+ }
+ .swipe-wrap{
+ overflow: hidden;
+ border-left: 1px solid #999;
+ position: absolute;
+ display: block;
+ top: 13px;
+ right: 7px;
+ }
+ .frame{
+ top: 0;
+ right: 0;
+ position: absolute;
+ &.deleted{
+ margin: 0;
+ display: block;
+ top: 13px;
+ right: 7px;
+ }
+ }
+ .swipe-bar{
+ display: block;
+ height: 100%;
+ width: 15px;
+ z-index: 100;
+ position: absolute;
+ cursor: pointer;
+ &:hover{
+ .top-handle{
+ background-position: -15px 3px;
+ }
+ .bottom-handle{
+ background-position: -15px -11px;
+ }
+ };
+ .top-handle{
+ display: block;
+ height: 14px;
+ width: 15px;
+ position: absolute;
+ top: 0px;
+ background: url('swipemode_sprites.gif') 0 3px no-repeat;
+ }
+ .bottom-handle{
+ display: block;
+ height: 14px;
+ width: 15px;
+ position: absolute;
+ bottom: 0px;
+ background: url('swipemode_sprites.gif') 0 -11px no-repeat;
+ }
+ }
+ } //.view.swipe
+ .view.onion-skin{
+ .onion-skin-frame{
+ display: block;
+ margin: auto;
+ position: relative;
+ }
+ .frame.added, .frame.deleted {
+ position: absolute;
+ display: block;
+ top: 0px;
+ left: 0px;
+ }
+ .controls{
+ display: block;
+ height: 14px;
+ width: 300px;
+ z-index: 100;
+ position: absolute;
+ bottom: 0px;
+ left: 50%;
+ margin-left: -150px;
+
+ .drag-track{
+ display: block;
+ position: absolute;
+ left: 12px;
+ height: 10px;
+ width: 276px;
+ background: url('onion_skin_sprites.gif') -4px -20px repeat-x;
+ }
+
+ .dragger {
+ display: block;
+ position: absolute;
+ left: 0px;
+ top: 0px;
+ height: 14px;
+ width: 14px;
+ background: url('onion_skin_sprites.gif') 0px -34px repeat-x;
+ cursor: pointer;
+ }
+
+ .transparent {
+ display: block;
+ position: absolute;
+ top: 2px;
+ right: 0px;
+ height: 10px;
+ width: 10px;
+ background: url('onion_skin_sprites.gif') -2px 0px no-repeat;
+ }
+
+ .opaque {
+ display: block;
+ position: absolute;
+ top: 2px;
+ left: 0px;
+ height: 10px;
+ width: 10px;
+ background: url('onion_skin_sprites.gif') -2px -10px no-repeat;
+ }
+ }
+ } //.view.onion-skin
+ }
+ .view-modes{
+
+ padding: 10px;
+ text-align: center;
+
+ background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf));
+ background-image: -webkit-linear-gradient(#eee 6.6%, #dfdfdf);
+ background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf);
+ background-image: -ms-linear-gradient(#eee 6.6%, #dfdfdf);
+ background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf);
+
+ ul, li{
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ display: inline-block;
+ }
+
+ li{
+ color: grey;
+ border-left: 1px solid #c1c1c1;
+ padding: 0 12px 0 16px;
+ cursor: pointer;
+ &:first-child{
+ border-left: none;
+ }
+ &:hover{
+ text-decoration: underline;
+ }
+ &.active{
+ &:hover{
+ text-decoration: none;
+ }
+ cursor: default;
+ color: #333;
+ }
+ &.disabled{
+ display: none;
+ }
+ }
+ }
+}
diff --git a/app/assets/stylesheets/sections/events.scss b/app/assets/stylesheets/sections/events.scss
index a576fefdea1..6ef12b20a5a 100644
--- a/app/assets/stylesheets/sections/events.scss
+++ b/app/assets/stylesheets/sections/events.scss
@@ -37,8 +37,8 @@
&.event-inline {
.avatar {
- width: 16px;
- height: 16px;
+ position: relative;
+ top: -2px;
}
}
@@ -113,6 +113,7 @@
&.commit {
background: transparent;
padding: 3px;
+ padding-left: 0;
border: none;
color: #666;
.commit-row-title {
@@ -122,6 +123,7 @@
&.commits-stat {
display: block;
padding: 3px;
+ padding-left: 0;
&:hover {
background: none;
diff --git a/app/assets/stylesheets/sections/groups.scss b/app/assets/stylesheets/sections/groups.scss
new file mode 100644
index 00000000000..60ec79acadb
--- /dev/null
+++ b/app/assets/stylesheets/sections/groups.scss
@@ -0,0 +1,9 @@
+.new-group-member-holder {
+ margin-top: 50px;
+ background: #f9f9f9;
+ padding-top: 20px;
+}
+
+.member-search-form {
+ float: left;
+}
diff --git a/app/assets/stylesheets/sections/header.scss b/app/assets/stylesheets/sections/header.scss
index b0dd0d08356..68873327845 100644
--- a/app/assets/stylesheets/sections/header.scss
+++ b/app/assets/stylesheets/sections/header.scss
@@ -19,7 +19,7 @@ header {
line-height: 32px;
padding: 6px 10px;
- &:hover {
+ &:hover, &:focus, &:active {
background: none;
}
}
@@ -29,6 +29,64 @@ header {
float: right;
margin-right: 0;
}
+
+ .navbar-toggle {
+ color: $style_color;
+ margin: 0 -15px 0 0;
+ padding: 10px;
+ border-radius: 0;
+
+ button i { font-size: 22px; }
+
+ &.collapsed { background-color: transparent !important;}
+
+ &:hover {
+ background-color: #EEE;
+ }
+ }
+ }
+
+ .turbolink-spinner {
+ font-size: 20px;
+ margin-right: 10px;
+ }
+
+ @media (max-width: $screen-xs-max) {
+ border-width: 0;
+ font-size: 18px;
+
+ .app_logo { margin-left: -15px; }
+ .title {
+ display: inline-block;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ vertical-align: top;
+ white-space: nowrap;
+ max-width: 70%;
+ }
+
+ .navbar-collapse {
+ padding-right: 0;
+ padding-left: 0;
+ }
+
+ .navbar-nav {
+ margin: 5px 0;
+
+ .visible-xs, .visable-sm {
+ display: table-cell !important;
+ }
+ }
+
+ li {
+ display: table-cell;
+ width: 1%;
+
+ a {
+ text-align: center;
+ font-size: 18px !important;
+ }
+ }
}
}
@@ -50,7 +108,7 @@ header {
h1 {
margin: 0;
- background: url('logo-black.png') no-repeat center center;
+ background: image-url('logo-black.png') no-repeat center center;
background-size: 32px;
float: left;
height: 46px;
@@ -69,7 +127,7 @@ header {
* Project / Area name
*
*/
- .project_name {
+ .title {
position: relative;
float: left;
margin: 0;
@@ -128,11 +186,14 @@ header {
background: #708090;
border-bottom: 1px solid #AAA;
+ .navbar-toggle { color: #fff; }
+
.nav > li > a {
color: #AAA;
text-shadow: 0 1px 0 #444;
- &:hover {
+ &:hover, &:focus, &:active {
+ background: none;
color: #FFF;
}
}
@@ -160,18 +221,18 @@ header {
.app_logo {
a {
h1 {
- background: url('logo-white.png') no-repeat center center;
+ background: image-url('logo-white.png') no-repeat center center;
background-size: 32px;
color: #fff;
text-shadow: 0 1px 1px #444;
}
}
}
- .project_name {
+ .title {
a {
- color: #BBB;
+ color: #FFF;
&:hover {
- color: #FFF;
+ text-decoration: underline;
}
}
color: #fff;
diff --git a/app/assets/stylesheets/sections/issues.scss b/app/assets/stylesheets/sections/issues.scss
index 81d945a9b3c..d4f8c8108ab 100644
--- a/app/assets/stylesheets/sections/issues.scss
+++ b/app/assets/stylesheets/sections/issues.scss
@@ -14,8 +14,8 @@
.issue-check {
float: left;
- padding: 8px 0;
padding-right: 8px;
+ margin-bottom: 10px;
min-width: 15px;
}
@@ -38,13 +38,21 @@
}
}
-input.check_all_issues {
+.check-all-holder {
+ height: 32px;
float: left;
- padding: 0;
- margin: 0;
- margin-right: 10px;
- position: relative;
- top: 13px;
+ margin-right: 12px;
+ padding: 6px 10px;
+ border: 1px solid #ccc;
+ @include border-radius(4px);
+
+
+ input.check_all_issues {
+ padding: 0;
+ margin: 0;
+ position: relative;
+ top: 3px;
+ }
}
.issues_content {
@@ -57,23 +65,6 @@ input.check_all_issues {
}
}
-.btn.close_issue {
- color: #B94A48;
- font-weight: bold;
- @include shade;
- &:hover {
- color: #B94A48;
- }
-}
-.btn.reopen_issue {
- color: #468847;
- font-weight: bold;
- @include shade;
- &:hover {
- color: #468847;
- }
-}
-
@media (min-width: 800px) { .issues_filters select { width: 160px; } }
@media (min-width: 1200px) { .issues_filters select { width: 220px; } }
@@ -93,6 +84,13 @@ input.check_all_issues {
.update_selected_issues {
margin-left: 4px;
}
+
+ .select2-container .select2-choice {
+ height: 32px;
+ line-height: 28px;
+ color: #444 !important;
+ font-weight: 500;
+ }
}
}
@@ -127,3 +125,21 @@ input.check_all_issues {
form.edit-issue {
margin: 0;
}
+
+.merge-request,
+.issue {
+ &.today {
+ background: #EFE;
+ border-color: #CEC;
+ }
+
+ &.closed {
+ background: #F5f5f5;
+ border-color: #E5E5E5;
+ }
+
+ &.merged {
+ background: #F5f5f5;
+ border-color: #E5E5E5;
+ }
+}
diff --git a/app/assets/stylesheets/sections/login.scss b/app/assets/stylesheets/sections/login.scss
index 186294424a2..a78a9cd4879 100644
--- a/app/assets/stylesheets/sections/login.scss
+++ b/app/assets/stylesheets/sections/login.scss
@@ -6,11 +6,10 @@
}
.login-box{
- width: 304px;
+ max-width: 304px;
position: relative;
@include border-radius(5px);
margin: auto;
- padding: 20px;
background: white;
}
@@ -23,7 +22,7 @@
background-color: #f1f1f1;
font-size: 16px;
padding: 14px 10px;
- width: 280px;
+ width: 100%;
height: auto;
&.top {
diff --git a/app/assets/stylesheets/sections/merge_requests.scss b/app/assets/stylesheets/sections/merge_requests.scss
index d3462d6aaa7..5341f411e54 100644
--- a/app/assets/stylesheets/sections/merge_requests.scss
+++ b/app/assets/stylesheets/sections/merge_requests.scss
@@ -31,10 +31,10 @@
.mr_source_commit,
.mr_target_commit {
+ margin-top: 10px;
.commit {
margin: 0;
- padding: 0;
- padding: 5px 0;
+ padding: 2px 0;
list-style: none;
&:hover {
background: none;
@@ -90,15 +90,8 @@
padding-top: 15px;
}
-.merge-request-branches {
- .commit-row-message {
- font-weight: normal !important;
- }
-
- .select2-container .select2-single {
- span {
- font-weight: bold;
- color: #555;
- }
- }
+// hide mr close link for inline diff comment form
+.diff-file .close-mr-link,
+.diff-file .reopen-mr-link {
+ display: none;
}
diff --git a/app/assets/stylesheets/sections/nav.scss b/app/assets/stylesheets/sections/nav.scss
index f706854b4fe..88f16a21596 100644
--- a/app/assets/stylesheets/sections/nav.scss
+++ b/app/assets/stylesheets/sections/nav.scss
@@ -35,9 +35,8 @@
width: 1%;
&.active {
a {
- color: $style_color;
- font-weight: bolder;
-
+ color: #333;
+ font-weight: bold;
&:after {
content: '';
display: block;
@@ -46,7 +45,7 @@
left: 50%;
width: 0;
height: 0;
- border-color: transparent transparent #777 transparent;
+ border-color: transparent transparent #333 transparent;
border-style: solid;
border-width: 6px;
margin-left: -6px;
@@ -56,7 +55,20 @@
&:hover {
a {
- color: $style_color;
+ color: $link_color;
+ &:after {
+ content: '';
+ display: block;
+ position: relative;
+ bottom: 8px;
+ left: 50%;
+ width: 0;
+ height: 0;
+ border-color: transparent transparent #29b transparent;
+ border-style: solid;
+ border-width: 6px;
+ margin-left: -6px;
+ }
}
}
@@ -73,7 +85,7 @@
a {
display: block;
text-align: center;
- font-weight: normal;
+ font-weight: 500;
height: 38px;
line-height: 34px;
color: #777;
@@ -83,4 +95,38 @@
padding-top: 2px;
}
}
+
+ @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: $primary_color;
+
+ a {
+ color: #fff;
+ font-weight: normal;
+ text-shadow: none;
+
+ &:after { display: none; }
+ }
+ }
+ }
+ }
+ }
}
diff --git a/app/assets/stylesheets/sections/notes.scss b/app/assets/stylesheets/sections/notes.scss
index 1ae0e161aa2..8a38cd5a939 100644
--- a/app/assets/stylesheets/sections/notes.scss
+++ b/app/assets/stylesheets/sections/notes.scss
@@ -47,13 +47,13 @@ ul.notes {
.discussion-body {
margin-left: 50px;
- .file,
+ .diff-file,
.discussion-hidden,
.notes {
@extend .borders;
background-color: #F9F9F9;
}
- .file .notes {
+ .diff-file .notes {
/* reset */
background: inherit;
border: none;
@@ -87,15 +87,10 @@ ul.notes {
}
.attachment {
font-size: 14px;
- margin-top: -20px;
}
.note-body {
@include md-typography;
margin-left: 45px;
-
- .highlight {
- @include border-radius(4px);
- }
}
.note-header {
padding-bottom: 5px;
@@ -118,7 +113,7 @@ ul.notes {
}
}
-.file .notes_holder {
+.diff-file .notes_holder {
font-size: 13px;
line-height: 18px;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
@@ -188,7 +183,7 @@ ul.notes {
}
}
}
-.file .note .note-actions {
+.diff-file .note .note-actions {
right: 0;
top: 0;
}
@@ -199,7 +194,7 @@ ul.notes {
* Line note button on the side of diffs
*/
-.file tr.line_holder {
+.diff-file tr.line_holder {
.add-diff-note {
background: url("diff_note_add.png") no-repeat left 0;
height: 22px;
@@ -239,22 +234,25 @@ ul.notes {
.reply-btn {
@extend .btn-primary;
}
-.file .content tr.line_holder:hover {
- &> td.line_content {
- background: $hover !important;
- border-color: darken($hover, 10%) !important;
+.diff-file .diff-content {
+ tr.line_holder:hover {
+ &> td.line_content {
+ background: $hover !important;
+ border-color: darken($hover, 10%) !important;
+ }
+ &> td.new_line,
+ &> td.old_line {
+ background: darken($hover, 4%) !important;
+ border-color: darken($hover, 10%) !important;
+ }
}
- &> td.new_line,
- &> td.old_line {
- background: darken($hover, 4%) !important;
- border-color: darken($hover, 10%) !important;
+
+ tr.line_holder:hover > td .line_note_link {
+ opacity: 1.0;
+ filter: alpha(opacity=100);
}
}
-.file .content tr.line_holder:hover > td .line_note_link {
- opacity: 1.0;
- filter: alpha(opacity=100);
-}
-.file,
+.diff-file,
.discussion {
.new_note {
margin: 0;
@@ -292,7 +290,7 @@ ul.notes {
box-shadow: none;
font-size: 14px;
height: 80px;
- width: 98.6%;
+ width: 100%;
}
}
}
@@ -306,6 +304,7 @@ ul.notes {
@extend .col-md-4;
@extend .thumbnail;
margin-left: 45px;
+ float: none;
}
@@ -341,7 +340,7 @@ ul.notes {
box-shadow: none;
font-size: 14px;
height: 80px;
- width: 98.6%;
+ width: 100%;
}
.form-actions {
diff --git a/app/assets/stylesheets/sections/profile.scss b/app/assets/stylesheets/sections/profile.scss
index 3a3bf7cdf2a..7a696c21e47 100644
--- a/app/assets/stylesheets/sections/profile.scss
+++ b/app/assets/stylesheets/sections/profile.scss
@@ -105,3 +105,23 @@
}
}
}
+
+.profile-groups-avatars {
+ margin: 0 5px 10px 0;
+
+ img {
+ width: 50px;
+ height: 50px;
+ }
+}
+
+.global-notifications-form .level-title {
+ font-size: 15px;
+ color: #333;
+ font-weight: bold;
+}
+
+.notification-icon-holder {
+ width: 20px;
+ float: left;
+}
diff --git a/app/assets/stylesheets/sections/projects.scss b/app/assets/stylesheets/sections/projects.scss
index 178364835ae..5757858a1ce 100644
--- a/app/assets/stylesheets/sections/projects.scss
+++ b/app/assets/stylesheets/sections/projects.scss
@@ -123,14 +123,9 @@
}
.save-project-loader {
- img {
- margin-top: 50px;
- margin-bottom: 50px;
- }
- h3 {
- @extend .page-title;
- }
-
+ margin-top: 50px;
+ margin-bottom: 50px;
+ color: #555;
}
ul.nav.nav-projects-tabs {
diff --git a/app/assets/stylesheets/sections/tree.scss b/app/assets/stylesheets/sections/tree.scss
index dfdcbb59b6b..55a5819b55a 100644
--- a/app/assets/stylesheets/sections/tree.scss
+++ b/app/assets/stylesheets/sections/tree.scss
@@ -127,9 +127,27 @@
border-top: 1px dashed #CCC;
padding-top: 10px;
- h4 {
+ .readme-file-title {
font-size: 14px;
margin-bottom: 20px;
color: #777;
}
}
+
+.blob-commit-info {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ margin-bottom: 10px;
+
+ .commit {
+ .commit-row-title {
+ font-size: 13px;
+
+ .commit-row-message {
+ font-weight: normal;
+ color: #555;
+ }
+ }
+ }
+}
diff --git a/app/assets/stylesheets/themes/ui_color.scss b/app/assets/stylesheets/themes/ui_color.scss
index 7d9cab215c8..edac4290e74 100644
--- a/app/assets/stylesheets/themes/ui_color.scss
+++ b/app/assets/stylesheets/themes/ui_color.scss
@@ -18,7 +18,7 @@
.navbar-inner {
background: #547;
border-bottom: 1px solid #435;
- .app_logo {
+ .app_logo, .navbar-toggle {
&:hover {
background-color: #435;
}
@@ -36,4 +36,8 @@
}
}
}
+
+ .nav-pills > li.active > a, .nav-pills > li.active > a:hover, .nav-pills > li.active > a:focus {
+ background: #769;
+ }
}
diff --git a/app/assets/stylesheets/themes/ui_gray.scss b/app/assets/stylesheets/themes/ui_gray.scss
index 41c08c840e2..959febad6fe 100644
--- a/app/assets/stylesheets/themes/ui_gray.scss
+++ b/app/assets/stylesheets/themes/ui_gray.scss
@@ -18,7 +18,7 @@
.navbar-inner {
background: #373737;
border-bottom: 1px solid #272727;
- .app_logo {
+ .app_logo, .navbar-toggle {
&:hover {
background-color: #272727;
}
diff --git a/app/assets/stylesheets/themes/ui_mars.scss b/app/assets/stylesheets/themes/ui_mars.scss
index aba3e0ca827..9af5adbf10a 100644
--- a/app/assets/stylesheets/themes/ui_mars.scss
+++ b/app/assets/stylesheets/themes/ui_mars.scss
@@ -18,7 +18,7 @@
.navbar-inner {
background: #474D57;
border-bottom: 1px solid #373D47;
- .app_logo {
+ .app_logo, .navbar-toggle {
&:hover {
background-color: #373D47;
}
diff --git a/app/assets/stylesheets/themes/ui_modern.scss b/app/assets/stylesheets/themes/ui_modern.scss
index 015a4bbf0c3..b0827deb1ac 100644
--- a/app/assets/stylesheets/themes/ui_modern.scss
+++ b/app/assets/stylesheets/themes/ui_modern.scss
@@ -18,7 +18,7 @@
.navbar-inner {
background: #345;
border-bottom: 1px solid #234;
- .app_logo {
+ .app_logo, .navbar-toggle {
&:hover {
background-color: #234;
}
diff --git a/app/contexts/commit_load_context.rb b/app/contexts/commit_load_context.rb
deleted file mode 100644
index 0c684976b64..00000000000
--- a/app/contexts/commit_load_context.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-class CommitLoadContext < BaseContext
- def execute
- result = {
- commit: nil,
- suppress_diff: false,
- line_notes: [],
- notes_count: 0,
- note: nil,
- status: :ok
- }
-
- commit = project.repository.commit(params[:id])
-
- if commit
- line_notes = project.notes.for_commit_id(commit.id).inline
-
- result[:commit] = commit
- result[:note] = project.build_commit_note(commit)
- result[:line_notes] = line_notes
- result[:notes_count] = project.notes.for_commit_id(commit.id).count
- result[:branches] = project.repository.branch_names_contains(commit.id)
-
- begin
- result[:suppress_diff] = true if commit.diff_suppress? && !params[:force_show_diff]
- result[:force_suppress_diff] = commit.diff_force_suppress?
- rescue Grit::Git::GitTimeout
- result[:suppress_diff] = true
- result[:status] = :huge_commit
- end
- end
-
- result
- end
-end
diff --git a/app/contexts/filter_context.rb b/app/contexts/filter_context.rb
deleted file mode 100644
index fb0d42cf87d..00000000000
--- a/app/contexts/filter_context.rb
+++ /dev/null
@@ -1,58 +0,0 @@
-class FilterContext
- attr_accessor :klass, :current_user, :params
-
- def initialize(klass, current_user, params)
- @klass = klass
- @current_user = current_user
- @params = params
- end
-
- def execute
- items = by_scope
- items = by_state(items)
- items = by_project(items)
- items = by_search(items)
- end
-
- private
-
- def by_scope
- table_name = klass.table_name
-
- case params[:scope]
- when 'authored' then
- current_user.send(table_name)
- when 'all' then
- klass.of_projects(current_user.authorized_projects.pluck(:id))
- else
- current_user.send("assigned_#{table_name}")
- end
- end
-
- def by_state(items)
- case params[:status]
- when 'closed'
- items.closed
- when 'all'
- items
- else
- items.opened
- end
- end
-
- def by_project(items)
- if params[:project_id].present?
- items = items.of_projects(params[:project_id])
- end
-
- items
- end
-
- def by_search(items)
- if params[:search].present?
- items = items.search(params[:search])
- end
-
- items
- end
-end
diff --git a/app/contexts/issues/list_context.rb b/app/contexts/issues/list_context.rb
deleted file mode 100644
index b256fd4c732..00000000000
--- a/app/contexts/issues/list_context.rb
+++ /dev/null
@@ -1,53 +0,0 @@
-module Issues
- class ListContext < BaseContext
- attr_accessor :issues
-
- def execute
- @issues = @project.issues
-
- @issues = case params[:state]
- when 'all' then @issues
- when 'closed' then @issues.closed
- else @issues.opened
- end
-
- @issues = case params[:scope]
- when 'assigned-to-me' then @issues.assigned_to(current_user)
- when 'created-by-me' then @issues.authored(current_user)
- else @issues
- end
-
- @issues = @issues.tagged_with(params[:label_name]) if params[:label_name].present?
- @issues = @issues.includes(:author, :project)
-
- # Filter by specific assignee_id (or lack thereof)?
- if params[:assignee_id].present?
- @issues = @issues.where(assignee_id: (params[:assignee_id] == '0' ? nil : params[:assignee_id]))
- end
-
- # Filter by specific milestone_id (or lack thereof)?
- if params[:milestone_id].present?
- @issues = @issues.where(milestone_id: (params[:milestone_id] == '0' ? nil : params[:milestone_id]))
- end
-
- # Sort by :sort param
- @issues = sort(@issues, params[:sort])
-
- @issues
- end
-
- private
-
- def sort(issues, condition)
- case condition
- when 'newest' then issues.except(:order).order('created_at DESC')
- when 'oldest' then issues.except(:order).order('created_at ASC')
- when 'recently_updated' then issues.except(:order).order('updated_at DESC')
- when 'last_updated' then issues.except(:order).order('updated_at ASC')
- when 'milestone_due_soon' then issues.except(:order).joins(:milestone).order("milestones.due_date ASC")
- when 'milestone_due_later' then issues.except(:order).joins(:milestone).order("milestones.due_date DESC")
- else issues
- end
- end
- end
-end
diff --git a/app/contexts/merge_requests_load_context.rb b/app/contexts/merge_requests_load_context.rb
deleted file mode 100644
index c3408db6e11..00000000000
--- a/app/contexts/merge_requests_load_context.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-# Build collection of Merge Requests
-# based on filtering passed via params for @project
-class MergeRequestsLoadContext < BaseContext
- def execute
- merge_requests = @project.merge_requests
-
- merge_requests = case params[:state]
- when 'all' then merge_requests
- when 'closed' then merge_requests.closed
- else merge_requests.opened
- end
-
- merge_requests = case params[:scope]
- when 'assigned-to-me' then merge_requests.assigned_to(current_user)
- when 'created-by-me' then merge_requests.authored(current_user)
- else merge_requests
- end
-
-
- merge_requests = merge_requests.page(params[:page]).per(20)
- merge_requests = merge_requests.includes(:author, :source_project, :target_project).order("created_at desc")
-
- # Filter by specific assignee_id (or lack thereof)?
- if params[:assignee_id].present?
- merge_requests = merge_requests.where(assignee_id: (params[:assignee_id] == '0' ? nil : params[:assignee_id]))
- end
-
- # Filter by specific milestone_id (or lack thereof)?
- if params[:milestone_id].present?
- merge_requests = merge_requests.where(milestone_id: (params[:milestone_id] == '0' ? nil : params[:milestone_id]))
- end
-
- merge_requests
- end
-end
diff --git a/app/contexts/notes/load_context.rb b/app/contexts/notes/load_context.rb
deleted file mode 100644
index 234e9ac3cdd..00000000000
--- a/app/contexts/notes/load_context.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-module Notes
- class LoadContext < BaseContext
- def execute
- target_type = params[:target_type]
- target_id = params[:target_id]
-
-
- @notes = case target_type
- when "commit"
- project.notes.for_commit_id(target_id).not_inline.fresh
- when "issue"
- project.issues.find(target_id).notes.inc_author.fresh
- when "merge_request"
- project.merge_requests.find(target_id).mr_and_commit_notes.inc_author.fresh
- when "snippet"
- project.snippets.find(target_id).notes.fresh
- end
- end
- end
-end
diff --git a/app/contexts/test_hook_context.rb b/app/contexts/test_hook_context.rb
deleted file mode 100644
index 63eda6c7d06..00000000000
--- a/app/contexts/test_hook_context.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-class TestHookContext < BaseContext
- def execute
- hook = project.hooks.find(params[:id])
- data = GitPushService.new.sample_data(project, current_user)
- hook.execute(data)
- end
-end
diff --git a/app/controllers/admin/groups_controller.rb b/app/controllers/admin/groups_controller.rb
index 89b395786b3..4bb3cf07da0 100644
--- a/app/controllers/admin/groups_controller.rb
+++ b/app/controllers/admin/groups_controller.rb
@@ -52,6 +52,6 @@ class Admin::GroupsController < Admin::ApplicationController
private
def group
- @group = Group.find_by_path(params[:id])
+ @group = Group.find_by(path: params[:id])
end
end
diff --git a/app/controllers/admin/projects_controller.rb b/app/controllers/admin/projects_controller.rb
index 7e3e29f59fb..13a7bdcf34a 100644
--- a/app/controllers/admin/projects_controller.rb
+++ b/app/controllers/admin/projects_controller.rb
@@ -5,7 +5,7 @@ class Admin::ProjectsController < Admin::ApplicationController
def index
owner_id = params[:owner_id]
- user = User.find_by_id(owner_id)
+ user = User.find_by(id: owner_id)
@projects = user ? user.owned_projects : Project.all
@projects = @projects.where("visibility_level IN (?)", params[:visibility_levels]) if params[:visibility_levels].present?
@@ -19,7 +19,7 @@ class Admin::ProjectsController < Admin::ApplicationController
end
def transfer
- result = ::Projects::TransferContext.new(@project, current_user, project: params).execute(:admin)
+ result = ::Projects::TransferService.new(@project, current_user, project: params).execute(:admin)
if result
redirect_to [:admin, @project]
diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb
index 2f981627137..5b06af79d5a 100644
--- a/app/controllers/admin/users_controller.rb
+++ b/app/controllers/admin/users_controller.rb
@@ -68,7 +68,9 @@ class Admin::UsersController < Admin::ApplicationController
params[:user].delete(:password_confirmation)
end
- user.admin = (admin && admin.to_i > 0)
+ if admin.present?
+ user.admin = !admin.to_i.zero?
+ end
respond_to do |format|
if user.update_attributes(params[:user], as: :admin)
@@ -100,6 +102,6 @@ class Admin::UsersController < Admin::ApplicationController
protected
def user
- @user ||= User.find_by_username!(params[:id])
+ @user ||= User.find_by!(username: params[:id])
end
end
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index b6501eacea3..9ed46c23942 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -135,12 +135,12 @@ class ApplicationController < ActionController::Base
end
end
- def render_404
- render file: Rails.root.join("public", "404"), layout: false, status: "404"
+ def render_403
+ head :forbidden
end
- def render_403
- render file: Rails.root.join("public", "403"), layout: false, status: "403"
+ def render_404
+ render file: Rails.root.join("public", "404"), layout: false, status: "404"
end
def require_non_empty_project
@@ -154,7 +154,6 @@ class ApplicationController < ActionController::Base
end
def dev_tools
- Rack::MiniProfiler.authorize_request
end
def default_headers
@@ -171,6 +170,7 @@ class ApplicationController < ActionController::Base
gon.api_token = current_user.private_token if current_user
gon.gravatar_url = request.ssl? || Gitlab.config.gitlab.https ? Gitlab.config.gravatar.ssl_url : Gitlab.config.gravatar.plain_url
gon.relative_url_root = Gitlab.config.gitlab.relative_url_root
+ gon.gravatar_enabled = Gitlab.config.gravatar.enabled
end
def check_password_expiration
@@ -207,7 +207,11 @@ class ApplicationController < ActionController::Base
end
def configure_permitted_parameters
- devise_parameter_sanitizer.for(:sign_in) { |u| u.permit(:username, :email, :password) }
+ devise_parameter_sanitizer.for(:sign_in) { |u| u.permit(:username, :email, :password, :login, :remember_me) }
devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:username, :email, :name, :password, :password_confirmation) }
end
+
+ def hexdigest(string)
+ Digest::SHA1.hexdigest string
+ end
end
diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb
index 27955c62488..a74e97ac253 100644
--- a/app/controllers/dashboard_controller.rb
+++ b/app/controllers/dashboard_controller.rb
@@ -3,6 +3,8 @@ 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.
@@ -39,7 +41,7 @@ class DashboardController < ApplicationController
current_user.authorized_projects
end
- @projects = @projects.where(namespace_id: Group.find_by_name(params[:group])) if params[:group].present?
+ @projects = @projects.where(namespace_id: Group.find_by(name: params[:group])) if params[:group].present?
@projects = @projects.where(visibility_level: params[:visibility_level]) if params[:visibility_level].present?
@projects = @projects.includes(:namespace)
@projects = @projects.tagged_with(params[:label]) if params[:label].present?
@@ -51,14 +53,15 @@ class DashboardController < ApplicationController
end
def merge_requests
- @merge_requests = FilterContext.new(MergeRequest, current_user, params).execute
- @merge_requests = @merge_requests.recent.page(params[:page]).per(20)
+ @merge_requests = MergeRequestsFinder.new.execute(current_user, params)
+ @merge_requests = @merge_requests.page(params[:page]).per(20)
+ @merge_requests = @merge_requests.preload(:author, :target_project)
end
def issues
- @issues = FilterContext.new(Issue, current_user, params).execute
- @issues = @issues.recent.page(params[:page]).per(20)
- @issues = @issues.includes(:author, :project)
+ @issues = IssuesFinder.new.execute(current_user, params)
+ @issues = @issues.page(params[:page]).per(20)
+ @issues = @issues.preload(:author, :project)
respond_to do |format|
format.html
@@ -71,4 +74,10 @@ 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
diff --git a/app/controllers/errors_controller.rb b/app/controllers/errors_controller.rb
deleted file mode 100644
index a0c8a000fc7..00000000000
--- a/app/controllers/errors_controller.rb
+++ /dev/null
@@ -1,2 +0,0 @@
-class ErrorsController < ApplicationController
-end
diff --git a/app/controllers/groups/avatars_controller.rb b/app/controllers/groups/avatars_controller.rb
new file mode 100644
index 00000000000..38071410f40
--- /dev/null
+++ b/app/controllers/groups/avatars_controller.rb
@@ -0,0 +1,12 @@
+class Groups::AvatarsController < ApplicationController
+ layout "profile"
+
+ def destroy
+ @group = Group.find_by(path: params[:group_id])
+ @group.remove_avatar!
+
+ @group.save
+
+ redirect_to edit_group_path(@group)
+ end
+end
diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb
index 5e8efe35a46..ebddf36de97 100644
--- a/app/controllers/groups_controller.rb
+++ b/app/controllers/groups_controller.rb
@@ -1,4 +1,5 @@
class GroupsController < ApplicationController
+ skip_before_filter :authenticate_user!, only: [:show, :issues, :members, :merge_requests]
respond_to :html
before_filter :group, except: [:new, :create]
@@ -10,6 +11,8 @@ class GroupsController < ApplicationController
# Load group projects
before_filter :projects, except: [:new, :create]
+ before_filter :default_filter, only: [:issues, :merge_requests]
+
layout :determine_layout
before_filter :set_title, only: [:new, :create]
@@ -34,7 +37,7 @@ class GroupsController < ApplicationController
@events = Event.in_projects(project_ids)
@events = event_filter.apply_filter(@events)
@events = @events.limit(20).offset(params[:offset] || 0)
- @last_push = current_user.recent_push
+ @last_push = current_user.recent_push if current_user
respond_to do |format|
format.html
@@ -43,19 +46,16 @@ class GroupsController < ApplicationController
end
end
- # Get authored or assigned open merge requests
def merge_requests
- @merge_requests = FilterContext.new(MergeRequest, current_user, params).execute
- @merge_requests = @merge_requests.of_group(@group)
- @merge_requests = @merge_requests.recent.page(params[:page]).per(20)
+ @merge_requests = MergeRequestsFinder.new.execute(current_user, params)
+ @merge_requests = @merge_requests.page(params[:page]).per(20)
+ @merge_requests = @merge_requests.preload(:author, :target_project)
end
- # Get only assigned issues
def issues
- @issues = FilterContext.new(Issue, current_user, params).execute
- @issues = @issues.of_group(@group)
- @issues = @issues.recent.page(params[:page]).per(20)
- @issues = @issues.includes(:author, :project)
+ @issues = IssuesFinder.new.execute(current_user, params)
+ @issues = @issues.page(params[:page]).per(20)
+ @issues = @issues.preload(:author, :project)
respond_to do |format|
format.html
@@ -65,7 +65,14 @@ class GroupsController < ApplicationController
def members
@project = group.projects.find(params[:project_id]) if params[:project_id]
- @members = group.users_groups.order('group_access DESC')
+ @members = group.users_groups
+
+ if params[:search].present?
+ users = group.users.search(params[:search])
+ @members = @members.where(user_id: users)
+ end
+
+ @members = @members.order('group_access DESC').page(params[:page]).per(50)
@users_group = UsersGroup.new
end
@@ -89,21 +96,25 @@ class GroupsController < ApplicationController
protected
def group
- @group ||= Group.find_by_path(params[:id])
+ @group ||= Group.find_by(path: params[:id])
end
def projects
- @projects ||= current_user.authorized_projects.where(namespace_id: group.id).sorted_by_activity
+ @projects ||= ProjectsFinder.new.execute(current_user, group: group)
end
def project_ids
- projects.map(&:id)
+ projects.pluck(:id)
end
# Dont allow unauthorized access to group
def authorize_read_group!
unless @group and (projects.present? or can?(current_user, :read_group, @group))
- return render_404
+ if current_user.nil?
+ return authenticate_user!
+ else
+ return render_404
+ end
end
end
@@ -126,8 +137,22 @@ class GroupsController < ApplicationController
def determine_layout
if [:new, :create].include?(action_name.to_sym)
'navless'
- else
+ elsif current_user
'group'
+ else
+ 'public_group'
+ 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
end
diff --git a/app/controllers/profiles/emails_controller.rb b/app/controllers/profiles/emails_controller.rb
new file mode 100644
index 00000000000..9996b67a8a4
--- /dev/null
+++ b/app/controllers/profiles/emails_controller.rb
@@ -0,0 +1,26 @@
+class Profiles::EmailsController < ApplicationController
+ layout "profile"
+
+ def index
+ @primary = current_user.email
+ @emails = current_user.emails
+ end
+
+ def create
+ @email = current_user.emails.new(params[:email])
+
+ flash[:alert] = @email.errors.full_messages.first unless @email.save
+
+ redirect_to profile_emails_url
+ end
+
+ def destroy
+ @email = current_user.emails.find(params[:id])
+ @email.destroy
+
+ respond_to do |format|
+ format.html { redirect_to profile_emails_url }
+ format.js { render nothing: true }
+ end
+ end
+end
diff --git a/app/controllers/profiles/groups_controller.rb b/app/controllers/profiles/groups_controller.rb
index 378ff6bcf34..9a4d088651e 100644
--- a/app/controllers/profiles/groups_controller.rb
+++ b/app/controllers/profiles/groups_controller.rb
@@ -7,18 +7,17 @@ class Profiles::GroupsController < ApplicationController
def leave
@users_group = group.users_groups.where(user_id: current_user.id).first
-
- if group.last_owner?(current_user)
- redirect_to(profile_groups_path, alert: "You can't leave group. You must add at least one more owner to it.")
- else
+ if can?(current_user, :destroy, @users_group)
@users_group.destroy
redirect_to(profile_groups_path, info: "You left #{group.name} group.")
+ else
+ return render_403
end
end
private
def group
- @group ||= Group.find_by_path(params[:id])
+ @group ||= Group.find_by(path: params[:id])
end
end
diff --git a/app/controllers/profiles/keys_controller.rb b/app/controllers/profiles/keys_controller.rb
index 541319e8d0f..b4f14e649e2 100644
--- a/app/controllers/profiles/keys_controller.rb
+++ b/app/controllers/profiles/keys_controller.rb
@@ -1,5 +1,6 @@
class Profiles::KeysController < ApplicationController
layout "profile"
+ skip_before_filter :authenticate_user!, only: [:get_keys]
def index
@keys = current_user.keys.order('id DESC')
@@ -32,4 +33,24 @@ class Profiles::KeysController < ApplicationController
format.js { render nothing: true }
end
end
+
+ # Get all keys of a user(params[:username]) in a text format
+ # Helpful for sysadmins to put in respective servers
+ def get_keys
+ if params[:username].present?
+ begin
+ user = User.find_by_username(params[:username])
+ if user.present?
+ render text: user.all_ssh_keys.join("\n")
+ else
+ render_404 and return
+ end
+ rescue => e
+ render text: e.message
+ end
+ else
+ render_404 and return
+ end
+ end
+
end
diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb
index fc9807e3c47..a1a8bed09f4 100644
--- a/app/controllers/projects/blob_controller.rb
+++ b/app/controllers/projects/blob_controller.rb
@@ -6,6 +6,7 @@ class Projects::BlobController < Projects::ApplicationController
before_filter :authorize_read_project!
before_filter :authorize_code_access!
before_filter :require_non_empty_project
+ before_filter :authorize_push!, only: [:destroy]
before_filter :blob
@@ -13,7 +14,7 @@ class Projects::BlobController < Projects::ApplicationController
end
def destroy
- result = Files::DeleteContext.new(@project, current_user, params, @ref, @path).execute
+ result = Files::DeleteService.new(@project, current_user, params, @ref, @path).execute
if result[:status] == :success
flash[:notice] = "Your changes have been successfully committed"
diff --git a/app/controllers/projects/commit_controller.rb b/app/controllers/projects/commit_controller.rb
index 65b8a7283a7..c56df65dcba 100644
--- a/app/controllers/projects/commit_controller.rb
+++ b/app/controllers/projects/commit_controller.rb
@@ -6,34 +6,35 @@ class Projects::CommitController < Projects::ApplicationController
before_filter :authorize_read_project!
before_filter :authorize_code_access!
before_filter :require_non_empty_project
+ before_filter :commit
def show
- result = CommitLoadContext.new(project, current_user, params).execute
+ return git_not_found! unless @commit
- @commit = result[:commit]
+ @line_notes = project.notes.for_commit_id(commit.id).inline
+ @branches = project.repository.branch_names_contains(commit.id)
- if @commit.nil?
- git_not_found!
- return
+ begin
+ @suppress_diff = true if commit.diff_suppress? && !params[:force_show_diff]
+ @force_suppress_diff = commit.diff_force_suppress?
+ rescue Grit::Git::GitTimeout
+ @suppress_diff = true
+ @status = :huge_commit
end
- @suppress_diff = result[:suppress_diff]
- @force_suppress_diff = result[:force_suppress_diff]
-
- @note = result[:note]
- @line_notes = result[:line_notes]
- @branches = result[:branches]
- @notes_count = result[:notes_count]
+ @note = project.build_commit_note(commit)
+ @notes_count = project.notes.for_commit_id(commit.id).count
@notes = project.notes.for_commit_id(@commit.id).not_inline.fresh
@noteable = @commit
-
@comments_allowed = @reply_allowed = true
- @comments_target = { noteable_type: 'Commit',
- commit_id: @commit.id }
+ @comments_target = {
+ noteable_type: 'Commit',
+ commit_id: @commit.id
+ }
respond_to do |format|
format.html do
- if result[:status] == :huge_commit
+ if @status == :huge_commit
render "huge_commit" and return
end
end
@@ -42,4 +43,8 @@ class Projects::CommitController < Projects::ApplicationController
format.patch { render text: @commit.to_patch }
end
end
+
+ def commit
+ @commit ||= project.repository.commit(params[:id])
+ end
end
diff --git a/app/controllers/projects/compare_controller.rb b/app/controllers/projects/compare_controller.rb
index b7531e2cefb..234b6058ff0 100644
--- a/app/controllers/projects/compare_controller.rb
+++ b/app/controllers/projects/compare_controller.rb
@@ -8,13 +8,14 @@ class Projects::CompareController < Projects::ApplicationController
end
def show
- compare = Gitlab::Git::Compare.new(@repository.raw_repository, params[:from], params[:to])
+ compare = Gitlab::Git::Compare.new(@repository.raw_repository, params[:from], params[:to], MergeRequestDiff::COMMITS_SAFE_SIZE)
@commits = compare.commits
@commit = compare.commit
@diffs = compare.diffs
@refs_are_same = compare.same
@line_notes = []
+ @timeout = compare.timeout
diff_line_count = Commit::diff_line_count(@diffs)
@suppress_diff = Commit::diff_suppress?(@diffs, diff_line_count) && !params[:force_show_diff]
diff --git a/app/controllers/projects/edit_tree_controller.rb b/app/controllers/projects/edit_tree_controller.rb
index 3921273620c..ff5206b6fa1 100644
--- a/app/controllers/projects/edit_tree_controller.rb
+++ b/app/controllers/projects/edit_tree_controller.rb
@@ -1,17 +1,25 @@
class Projects::EditTreeController < Projects::BaseTreeController
before_filter :require_branch_head
before_filter :blob
+ before_filter :authorize_push!
+ before_filter :from_merge_request
+ before_filter :after_edit_path
def show
@last_commit = Gitlab::Git::Commit.last_for_path(@repository, @ref, @path).sha
end
def update
- result = Files::UpdateContext.new(@project, current_user, params, @ref, @path).execute
+ result = Files::UpdateService.new(@project, current_user, params, @ref, @path).execute
if result[:status] == :success
flash[:notice] = "Your changes have been successfully committed"
- redirect_to project_blob_path(@project, @id)
+
+ if from_merge_request
+ from_merge_request.reload_code
+ end
+
+ redirect_to after_edit_path
else
flash[:alert] = result[:error]
render :show
@@ -23,4 +31,19 @@ class Projects::EditTreeController < Projects::BaseTreeController
def blob
@blob ||= @repository.blob_at(@commit.id, @path)
end
+
+ def after_edit_path
+ @after_edit_path ||=
+ if from_merge_request
+ diffs_project_merge_request_path(from_merge_request.target_project, from_merge_request) +
+ "#file-path-#{hexdigest(@path)}"
+ else
+ project_blob_path(@project, @id)
+ end
+ end
+
+ def from_merge_request
+ # If blob edit was initiated from merge request page
+ @from_merge_request ||= MergeRequest.find_by(id: params[:from_merge_request_id])
+ end
end
diff --git a/app/controllers/projects/hooks_controller.rb b/app/controllers/projects/hooks_controller.rb
index 314d87df034..a863b318324 100644
--- a/app/controllers/projects/hooks_controller.rb
+++ b/app/controllers/projects/hooks_controller.rb
@@ -24,15 +24,20 @@ class Projects::HooksController < Projects::ApplicationController
end
def test
- TestHookContext.new(project, current_user, params).execute
+ TestHookService.new.execute(hook, current_user)
redirect_to :back
end
def destroy
- @hook = @project.hooks.find(params[:id])
- @hook.destroy
+ hook.destroy
redirect_to project_hooks_path(@project)
end
+
+ private
+
+ def hook
+ @hook ||= @project.hooks.find(params[:id])
+ end
end
diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index c58ac71277e..9d97c820f38 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -11,6 +11,9 @@ class Projects::IssuesController < Projects::ApplicationController
# Allow modify issue
before_filter :authorize_modify_issue!, only: [:edit, :update]
+ # Allow issues bulk update
+ before_filter :authorize_admin_issues!, only: [:bulk_update]
+
respond_to :html
def index
@@ -25,7 +28,7 @@ class Projects::IssuesController < Projects::ApplicationController
@milestone = @project.milestones.find(milestone_id) if milestone_id.present? && !milestone_id.to_i.zero?
sort_param = params[:sort] || 'newest'
@sort = sort_param.humanize unless sort_param.empty?
-
+ @assignees = User.where(id: @project.issues.pluck(:assignee_id))
respond_to do |format|
format.html
@@ -89,7 +92,7 @@ class Projects::IssuesController < Projects::ApplicationController
end
def bulk_update
- result = Issues::BulkUpdateContext.new(project, current_user, params).execute
+ result = Issues::BulkUpdateService.new(project, current_user, params).execute
redirect_to :back, notice: "#{result[:count]} issues updated"
end
@@ -97,7 +100,7 @@ class Projects::IssuesController < Projects::ApplicationController
def issue
@issue ||= begin
- @project.issues.find_by_iid!(params[:id])
+ @project.issues.find_by!(iid: params[:id])
rescue ActiveRecord::RecordNotFound
redirect_old
end
@@ -107,8 +110,8 @@ class Projects::IssuesController < Projects::ApplicationController
return render_404 unless can?(current_user, :modify_issue, @issue)
end
- def authorize_admin_issue!
- return render_404 unless can?(current_user, :admin_issue, @issue)
+ def authorize_admin_issues!
+ return render_404 unless can?(current_user, :admin_issue, @project)
end
def module_enabled
@@ -116,7 +119,9 @@ class Projects::IssuesController < Projects::ApplicationController
end
def issues_filtered
- @issues = Issues::ListContext.new(project, current_user, params).execute
+ params[:scope] = 'all' if params[:scope].blank?
+ params[:state] = 'opened' if params[:state].blank?
+ @issues = IssuesFinder.new.execute(current_user, params.merge(project_id: @project.id))
end
# Since iids are implemented only in 6.1
@@ -125,7 +130,7 @@ class Projects::IssuesController < Projects::ApplicationController
# To prevent 404 errors we provide a redirect to correct iids until 7.0 release
#
def redirect_old
- issue = @project.issues.find_by_id(params[:id])
+ issue = @project.issues.find_by(id: params[:id])
if issue
redirect_to project_issue_path(@project, issue)
diff --git a/app/controllers/projects/labels_controller.rb b/app/controllers/projects/labels_controller.rb
index 65f9e2b9d57..0166ca9ff00 100644
--- a/app/controllers/projects/labels_controller.rb
+++ b/app/controllers/projects/labels_controller.rb
@@ -13,7 +13,7 @@ class Projects::LabelsController < Projects::ApplicationController
def generate
Gitlab::IssuesLabels.generate(@project)
- redirect_to project_labels_path(@project)
+ redirect_to project_issues_path(@project)
end
protected
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index bba08bdd782..38e567f3b13 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -17,10 +17,18 @@ class Projects::MergeRequestsController < Projects::ApplicationController
before_filter :authorize_modify_merge_request!, only: [:close, :edit, :update, :sort]
def index
- @merge_requests = MergeRequestsLoadContext.new(project, current_user, params).execute
+ params[:sort] ||= 'newest'
+ params[:scope] = 'all' if params[:scope].blank?
+ params[:state] = 'opened' if params[:state].blank?
+
+ @merge_requests = MergeRequestsFinder.new.execute(current_user, params.merge(project_id: @project.id))
+ @merge_requests = @merge_requests.page(params[:page]).per(20)
+
+ @sort = params[:sort].humanize
assignee_id, milestone_id = params[:assignee_id], params[:milestone_id]
@assignee = @project.team.find(assignee_id) if assignee_id.present? && !assignee_id.to_i.zero?
@milestone = @project.milestones.find(milestone_id) if milestone_id.present? && !milestone_id.to_i.zero?
+ @assignees = User.where(id: @project.merge_requests.pluck(:assignee_id))
end
def show
@@ -52,8 +60,11 @@ class Projects::MergeRequestsController < Projects::ApplicationController
def new
@merge_request = MergeRequest.new(params[:merge_request])
@merge_request.source_project = @project unless @merge_request.source_project
- @merge_request.target_project = @project unless @merge_request.target_project
+ @merge_request.target_project ||= (@project.forked_from_project || @project)
@target_branches = @merge_request.target_project.nil? ? [] : @merge_request.target_project.repository.branch_names
+
+ @merge_request.target_branch ||= @merge_request.target_project.default_branch
+
@source_project = @merge_request.source_project
@merge_request
end
@@ -69,7 +80,6 @@ class Projects::MergeRequestsController < Projects::ApplicationController
@merge_request.author = current_user
@target_branches ||= []
if @merge_request.save
- @merge_request.reload_code
redirect_to [@merge_request.target_project, @merge_request], notice: 'Merge request was successfully created.'
else
@source_project = @merge_request.source_project
@@ -100,10 +110,14 @@ class Projects::MergeRequestsController < Projects::ApplicationController
params[:merge_request].delete(:target_project_id)
if @merge_request.update_attributes(params[:merge_request].merge(author_id_of_changes: current_user.id))
- @merge_request.reload_code
- @merge_request.mark_as_unchecked
@merge_request.reset_events_cache
- redirect_to [@merge_request.target_project, @merge_request], notice: 'Merge request was successfully updated.'
+
+ respond_to do |format|
+ format.js
+ format.html do
+ redirect_to [@merge_request.target_project, @merge_request], notice: 'Merge request was successfully updated.'
+ end
+ end
else
render "edit"
end
@@ -121,9 +135,9 @@ class Projects::MergeRequestsController < Projects::ApplicationController
def automerge
return access_denied! unless allowed_to_merge?
- if @merge_request.opened? && @merge_request.can_be_merged?
+ if @merge_request.open? && @merge_request.can_be_merged?
@merge_request.should_remove_source_branch = params[:should_remove_source_branch]
- @merge_request.automerge!(current_user)
+ @merge_request.automerge!(current_user, params[:merge_commit_message])
@status = true
else
@status = false
@@ -145,10 +159,14 @@ class Projects::MergeRequestsController < Projects::ApplicationController
@target_project = selected_target_project
@target_branches = @target_project.repository.branch_names
@target_branches
+
+ respond_to do |format|
+ format.js
+ end
end
def ci_status
- status = project.gitlab_ci_service.commit_status(merge_request.last_commit.sha)
+ status = @merge_request.source_project.gitlab_ci_service.commit_status(merge_request.last_commit.sha)
response = {status: status}
render json: response
@@ -157,11 +175,15 @@ class Projects::MergeRequestsController < Projects::ApplicationController
protected
def selected_target_project
- ((@project.id.to_s == params[:target_project_id]) || @project.forked_project_link.nil?) ? @project : @project.forked_project_link.forked_from_project
+ if @project.id.to_s == params[:target_project_id] || @project.forked_project_link.nil?
+ @project
+ else
+ @project.forked_project_link.forked_from_project
+ end
end
def merge_request
- @merge_request ||= @project.merge_requests.find_by_iid!(params[:id])
+ @merge_request ||= @project.merge_requests.find_by!(iid: params[:id])
end
def closes_issues
@@ -206,8 +228,9 @@ class Projects::MergeRequestsController < Projects::ApplicationController
# or from cache if already merged
@commits = @merge_request.commits
+ @merge_request_diff = @merge_request.merge_request_diff
@allowed_to_merge = allowed_to_merge?
- @show_merge_controls = @merge_request.opened? && @commits.any? && @allowed_to_merge
+ @show_merge_controls = @merge_request.open? && @commits.any? && @allowed_to_merge
end
def allowed_to_merge?
diff --git a/app/controllers/projects/milestones_controller.rb b/app/controllers/projects/milestones_controller.rb
index ecb1fc1d566..aea92a19f34 100644
--- a/app/controllers/projects/milestones_controller.rb
+++ b/app/controllers/projects/milestones_controller.rb
@@ -76,7 +76,7 @@ class Projects::MilestonesController < Projects::ApplicationController
protected
def milestone
- @milestone ||= @project.milestones.find_by_iid!(params[:id])
+ @milestone ||= @project.milestones.find_by!(iid: params[:id])
end
def authorize_admin_milestone!
diff --git a/app/controllers/projects/new_tree_controller.rb b/app/controllers/projects/new_tree_controller.rb
index 933a0cb876e..3a51a78ef6f 100644
--- a/app/controllers/projects/new_tree_controller.rb
+++ b/app/controllers/projects/new_tree_controller.rb
@@ -1,12 +1,13 @@
class Projects::NewTreeController < Projects::BaseTreeController
before_filter :require_branch_head
+ before_filter :authorize_push!
def show
end
def update
file_path = File.join(@path, File.basename(params[:file_name]))
- result = Files::CreateContext.new(@project, current_user, params, @ref, file_path).execute
+ result = Files::CreateService.new(@project, current_user, params, @ref, file_path).execute
if result[:status] == :success
flash[:notice] = "Your changes have been successfully committed"
diff --git a/app/controllers/projects/notes_controller.rb b/app/controllers/projects/notes_controller.rb
index 261841f1ea2..85d042a89b5 100644
--- a/app/controllers/projects/notes_controller.rb
+++ b/app/controllers/projects/notes_controller.rb
@@ -5,7 +5,7 @@ class Projects::NotesController < Projects::ApplicationController
before_filter :authorize_admin_note!, only: [:update, :destroy]
def index
- @notes = Notes::LoadContext.new(project, current_user, params).execute
+ @notes = NotesFinder.new.execute(project, current_user, params)
notes_json = { notes: [] }
@@ -20,7 +20,7 @@ class Projects::NotesController < Projects::ApplicationController
end
def create
- @note = Notes::CreateContext.new(project, current_user, params).execute
+ @note = Notes::CreateService.new(project, current_user, params).execute
respond_to do |format|
format.json { render_note_json(@note) }
diff --git a/app/controllers/projects/raw_controller.rb b/app/controllers/projects/raw_controller.rb
index 18ace028b0c..a6b7ae3f127 100644
--- a/app/controllers/projects/raw_controller.rb
+++ b/app/controllers/projects/raw_controller.rb
@@ -11,11 +11,7 @@ class Projects::RawController < Projects::ApplicationController
@blob = @repository.blob_at(@commit.id, @path)
if @blob
- type = if @blob.mime_type =~ /html|javascript/
- 'text/plain; charset=utf-8'
- else
- @blob.mime_type
- end
+ type = get_blob_type
headers['X-Content-Type-Options'] = 'nosniff'
@@ -29,5 +25,17 @@ class Projects::RawController < Projects::ApplicationController
not_found!
end
end
+
+ private
+
+ def get_blob_type
+ if @blob.mime_type =~ /html|javascript/
+ 'text/plain; charset=utf-8'
+ elsif @blob.name =~ /(?:msi|exe|rar|r0\d|7z|7zip|zip)$/
+ 'application/octet-stream'
+ else
+ @blob.mime_type
+ end
+ end
end
diff --git a/app/controllers/projects/refs_controller.rb b/app/controllers/projects/refs_controller.rb
index 16621c0371e..7b8026cff9f 100644
--- a/app/controllers/projects/refs_controller.rb
+++ b/app/controllers/projects/refs_controller.rb
@@ -34,7 +34,7 @@ class Projects::RefsController < Projects::ApplicationController
contents = tree.entries
@logs = contents.map do |content|
file = params[:path] ? File.join(params[:path], content.name) : content.name
- last_commit = @repo.commits(@commit.id, file, 1).last
+ last_commit = @repo.last_commit_for_path(@commit.id, file)
{
file_name: content.name,
commit: last_commit
diff --git a/app/controllers/projects/tags_controller.rb b/app/controllers/projects/tags_controller.rb
index 9dbb0d81888..818c5d971e9 100644
--- a/app/controllers/projects/tags_controller.rb
+++ b/app/controllers/projects/tags_controller.rb
@@ -8,7 +8,7 @@ class Projects::TagsController < Projects::ApplicationController
before_filter :authorize_admin_project!, only: [:destroy]
def index
- @tags = Kaminari.paginate_array(@repository.tags).page(params[:page]).per(30)
+ @tags = Kaminari.paginate_array(@repository.tags.reverse).page(params[:page]).per(30)
end
def create
diff --git a/app/controllers/projects/team_members_controller.rb b/app/controllers/projects/team_members_controller.rb
index 2c40b3c75f2..44068878cd1 100644
--- a/app/controllers/projects/team_members_controller.rb
+++ b/app/controllers/projects/team_members_controller.rb
@@ -26,7 +26,7 @@ class Projects::TeamMembersController < Projects::ApplicationController
end
def update
- @user_project_relation = project.users_projects.find_by_user_id(member)
+ @user_project_relation = project.users_projects.find_by(user_id: member)
@user_project_relation.update_attributes(params[:team_member])
unless @user_project_relation.valid?
@@ -36,7 +36,7 @@ class Projects::TeamMembersController < Projects::ApplicationController
end
def destroy
- @user_project_relation = project.users_projects.find_by_user_id(member)
+ @user_project_relation = project.users_projects.find_by(user_id: member)
@user_project_relation.destroy
respond_to do |format|
@@ -46,7 +46,7 @@ class Projects::TeamMembersController < Projects::ApplicationController
end
def leave
- project.users_projects.find_by_user_id(current_user).destroy
+ project.users_projects.find_by(user_id: current_user).destroy
respond_to do |format|
format.html { redirect_to :back }
@@ -65,6 +65,6 @@ class Projects::TeamMembersController < Projects::ApplicationController
protected
def member
- @member ||= User.find_by_username(params[:id])
+ @member ||= User.find_by(username: params[:id])
end
end
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index e1c55e7d913..6ec109b9145 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -20,7 +20,7 @@ class ProjectsController < ApplicationController
end
def create
- @project = ::Projects::CreateContext.new(current_user, params[:project]).execute
+ @project = ::Projects::CreateService.new(current_user, params[:project]).execute
respond_to do |format|
flash[:notice] = 'Project was successfully created.' if @project.saved?
@@ -36,7 +36,7 @@ class ProjectsController < ApplicationController
end
def update
- status = ::Projects::UpdateContext.new(@project, current_user, params).execute
+ status = ::Projects::UpdateService.new(@project, current_user, params).execute
respond_to do |format|
if status
@@ -51,7 +51,7 @@ class ProjectsController < ApplicationController
end
def transfer
- ::Projects::TransferContext.new(project, current_user, params).execute
+ ::Projects::TransferService.new(project, current_user, params).execute
end
def show
@@ -89,7 +89,7 @@ class ProjectsController < ApplicationController
end
def fork
- @forked_project = ::Projects::ForkContext.new(project, current_user).execute
+ @forked_project = ::Projects::ForkService.new(project, current_user).execute
respond_to do |format|
format.html do
diff --git a/app/controllers/public/projects_controller.rb b/app/controllers/public/projects_controller.rb
index d7297161c22..d6238f79547 100644
--- a/app/controllers/public/projects_controller.rb
+++ b/app/controllers/public/projects_controller.rb
@@ -6,7 +6,7 @@ class Public::ProjectsController < ApplicationController
layout 'public'
def index
- @projects = Project.public_or_internal_only(current_user)
+ @projects = Project.publicish(current_user)
@projects = @projects.search(params[:search]) if params[:search].present?
@projects = @projects.sort(@sort = params[:sort])
@projects = @projects.includes(:namespace).page(params[:page]).per(20)
diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb
index ba8f08c5b82..c1648d6c387 100644
--- a/app/controllers/search_controller.rb
+++ b/app/controllers/search_controller.rb
@@ -1,13 +1,23 @@
class SearchController < ApplicationController
+ include SearchHelper
+
def show
- @project = Project.find_by_id(params[:project_id]) if params[:project_id].present?
- @group = Group.find_by_id(params[:group_id]) if params[:group_id].present?
+ @project = Project.find_by(id: params[:project_id]) if params[:project_id].present?
+ @group = Group.find_by(id: params[:group_id]) if params[:group_id].present?
if @project
return access_denied! unless can?(current_user, :download_code, @project)
- @search_results = Search::ProjectContext.new(@project, current_user, params).execute
+ @search_results = Search::ProjectService.new(@project, current_user, params).execute
else
- @search_results = Search::GlobalContext.new(current_user, params).execute
+ @search_results = Search::GlobalService.new(current_user, params).execute
end
end
+
+ def autocomplete
+ term = params[:term]
+ @project = Project.find(params[:project_id]) if params[:project_id].present?
+ @ref = params[:project_ref] if params[:project_ref].present?
+
+ render json: search_autocomplete_opts(term).to_json
+ end
end
diff --git a/app/controllers/snippets_controller.rb b/app/controllers/snippets_controller.rb
index b91f68aab5e..e54a968326f 100644
--- a/app/controllers/snippets_controller.rb
+++ b/app/controllers/snippets_controller.rb
@@ -18,7 +18,7 @@ class SnippetsController < ApplicationController
end
def user_index
- @user = User.find_by_username(params[:username])
+ @user = User.find_by(username: params[:username])
@snippets = @user.snippets.fresh.non_expired
if @user == current_user
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index 4947c33f959..9461174b950 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -1,11 +1,23 @@
class UsersController < ApplicationController
- layout 'navless'
+ skip_before_filter :authenticate_user!, only: [:show]
+ layout :determine_layout
def show
@user = User.find_by_username!(params[:username])
- @projects = @user.authorized_projects.where('projects.id in (?)', current_user.authorized_projects.map(&:id))
- @events = @user.recent_events.where(project_id: @projects.map(&:id)).limit(20)
-
+ @projects = @user.authorized_projects.accessible_to(current_user)
+ if !current_user && @projects.empty?
+ return authenticate_user!
+ end
+ @groups = @user.groups.accessible_to(current_user)
+ @events = @user.recent_events.where(project_id: @projects.pluck(:id)).limit(20)
@title = @user.name
end
+
+ def determine_layout
+ if current_user
+ 'navless'
+ else
+ 'public_users'
+ end
+ end
end
diff --git a/app/controllers/users_groups_controller.rb b/app/controllers/users_groups_controller.rb
index 749da1e1413..b9bdc189522 100644
--- a/app/controllers/users_groups_controller.rb
+++ b/app/controllers/users_groups_controller.rb
@@ -19,18 +19,21 @@ class UsersGroupsController < ApplicationController
def destroy
@users_group = @group.users_groups.find(params[:id])
- @users_group.destroy
-
- respond_to do |format|
- format.html { redirect_to members_group_path(@group), notice: 'User was successfully removed from group.' }
- format.js { render nothing: true }
+ if can?(current_user, :destroy, @users_group) # May fail if last owner.
+ @users_group.destroy
+ respond_to do |format|
+ format.html { redirect_to members_group_path(@group), notice: 'User was successfully removed from group.' }
+ format.js { render nothing: true }
+ end
+ else
+ return render_403
end
end
protected
def group
- @group ||= Group.find_by_path(params[:group_id])
+ @group ||= Group.find_by(path: params[:group_id])
end
def authorize_admin_group!
diff --git a/app/finders/README.md b/app/finders/README.md
new file mode 100644
index 00000000000..47823c51efb
--- /dev/null
+++ b/app/finders/README.md
@@ -0,0 +1,22 @@
+# Finders
+
+This type of classes responsible for collectiong items based on different conditions.
+To prevent lookup methods in models like this:
+
+```ruby
+class Project
+ def issues_for_user_filtered_by(user, filter)
+ # A lot of logic not related to project model itself
+ end
+end
+
+issues = project.issues_for_user_filtered_by(user, params)
+```
+
+Better use this:
+
+```ruby
+issues = IssuesFinder.new.execute(project, user, filter)
+```
+
+It will help keep models thiner
diff --git a/app/finders/base_finder.rb b/app/finders/base_finder.rb
new file mode 100644
index 00000000000..d20716fb170
--- /dev/null
+++ b/app/finders/base_finder.rb
@@ -0,0 +1,137 @@
+# BaseFinder
+#
+# Used to filter Issues and MergeRequests collections by set of params
+#
+# Arguments:
+# klass - actual class like Issue or MergeRequest
+# current_user - which user use
+# params:
+# scope: 'created-by-me' or 'assigned-to-me' or 'all'
+# state: 'open' or 'closed' or 'all'
+# group_id: integer
+# project_id: integer
+# milestone_id: integer
+# assignee_id: integer
+# search: string
+# label_name: string
+# sort: string
+#
+class BaseFinder
+ attr_accessor :current_user, :params
+
+ def execute(current_user, params)
+ @current_user = current_user
+ @params = params
+
+ items = init_collection
+ items = by_scope(items)
+ items = by_state(items)
+ items = by_group(items)
+ items = by_project(items)
+ items = by_search(items)
+ items = by_milestone(items)
+ items = by_assignee(items)
+ items = by_label(items)
+ items = sort(items)
+ end
+
+ private
+
+ def init_collection
+ table_name = klass.table_name
+
+ if project
+ if project.public? || (current_user && current_user.can?(:read_project, project))
+ project.send(table_name)
+ else
+ []
+ end
+ elsif current_user && params[:authorized_only].presence
+ klass.of_projects(current_user.authorized_projects)
+ else
+ klass.of_projects(Project.accessible_to(current_user))
+ end
+ end
+
+ def by_scope(items)
+ case params[:scope]
+ when 'created-by-me', 'authored' then
+ items.where(author_id: current_user.id)
+ when 'all' then
+ items
+ when 'assigned-to-me' then
+ items.where(assignee_id: current_user.id)
+ else
+ raise 'You must specify default scope'
+ end
+ end
+
+ def by_state(items)
+ case params[:state]
+ when 'closed'
+ items.closed
+ when 'all'
+ items
+ when 'opened'
+ items.opened
+ else
+ raise 'You must specify default state'
+ end
+ end
+
+ def by_group(items)
+ if params[:group_id].present?
+ items = items.of_group(Group.find(params[:group_id]))
+ end
+
+ items
+ end
+
+ def by_project(items)
+ if params[:project_id].present?
+ items = items.of_projects(params[:project_id])
+ end
+
+ items
+ end
+
+ def by_search(items)
+ if params[:search].present?
+ items = items.search(params[:search])
+ end
+
+ items
+ end
+
+ def sort(items)
+ items.sort(params[:sort])
+ end
+
+ def by_milestone(items)
+ if params[:milestone_id].present?
+ items = items.where(milestone_id: (params[:milestone_id] == '0' ? nil : params[:milestone_id]))
+ end
+
+ items
+ end
+
+ def by_assignee(items)
+ if params[:assignee_id].present?
+ items = items.where(assignee_id: (params[:assignee_id] == '0' ? nil : params[:assignee_id]))
+ end
+
+ items
+ end
+
+ def by_label(items)
+ if params[:label_name].present?
+ items = items.tagged_with(params[:label_name])
+ end
+
+ items
+ end
+
+ def project
+ Project.where(id: params[:project_id]).first if params[:project_id].present?
+ end
+end
diff --git a/app/finders/issues_finder.rb b/app/finders/issues_finder.rb
new file mode 100644
index 00000000000..8e0c606249e
--- /dev/null
+++ b/app/finders/issues_finder.rb
@@ -0,0 +1,22 @@
+# Finders::Issues class
+#
+# Used to filter Issues collections by set of params
+#
+# Arguments:
+# current_user - which user use
+# params:
+# scope: 'created-by-me' or 'assigned-to-me' or 'all'
+# state: 'open' or 'closed' or 'all'
+# group_id: integer
+# project_id: integer
+# milestone_id: integer
+# assignee_id: integer
+# search: string
+# label_name: string
+# sort: string
+#
+class IssuesFinder < BaseFinder
+ def klass
+ Issue
+ end
+end
diff --git a/app/finders/merge_requests_finder.rb b/app/finders/merge_requests_finder.rb
new file mode 100644
index 00000000000..3727149c8fb
--- /dev/null
+++ b/app/finders/merge_requests_finder.rb
@@ -0,0 +1,22 @@
+# Finders::MergeRequest class
+#
+# Used to filter MergeRequests collections by set of params
+#
+# Arguments:
+# current_user - which user use
+# params:
+# scope: 'created-by-me' or 'assigned-to-me' or 'all'
+# state: 'open' or 'closed' or 'all'
+# group_id: integer
+# project_id: integer
+# milestone_id: integer
+# assignee_id: integer
+# search: string
+# label_name: string
+# sort: string
+#
+class MergeRequestsFinder < BaseFinder
+ def klass
+ MergeRequest
+ end
+end
diff --git a/app/finders/notes_finder.rb b/app/finders/notes_finder.rb
new file mode 100644
index 00000000000..384316e14b7
--- /dev/null
+++ b/app/finders/notes_finder.rb
@@ -0,0 +1,17 @@
+class NotesFinder
+ def execute(project, current_user, params)
+ target_type = params[:target_type]
+ target_id = params[:target_id]
+
+ case target_type
+ when "commit"
+ project.notes.for_commit_id(target_id).not_inline.fresh
+ when "issue"
+ project.issues.find(target_id).notes.inc_author.fresh
+ when "merge_request"
+ project.merge_requests.find(target_id).mr_and_commit_notes.inc_author.fresh
+ when "snippet"
+ project.snippets.find(target_id).notes.fresh
+ end
+ end
+end
diff --git a/app/finders/projects_finder.rb b/app/finders/projects_finder.rb
new file mode 100644
index 00000000000..bfaba758788
--- /dev/null
+++ b/app/finders/projects_finder.rb
@@ -0,0 +1,63 @@
+class ProjectsFinder
+ def execute(current_user, options)
+ group = options[:group]
+
+ if group
+ group_projects(current_user, group)
+ else
+ all_projects(current_user)
+ end
+ end
+
+ private
+
+ def group_projects(current_user, group)
+ if current_user
+ if group.users.include?(current_user)
+ # User is group member
+ #
+ # Return ALL group projects
+ group.projects
+ else
+ projects_members = UsersProject.where(
+ project_id: group.projects,
+ user_id: current_user
+ )
+
+ if projects_members.any?
+ # User is a project member
+ #
+ # Return only:
+ # public projects
+ # internal projects
+ # joined projects
+ #
+ group.projects.where(
+ "projects.id IN (?) OR projects.visibility_level IN (?)",
+ projects_members.pluck(:project_id),
+ Project.public_and_internal_levels
+ )
+ else
+ # User has no access to group or group projects
+ #
+ # Return only:
+ # public projects
+ # internal projects
+ #
+ group.projects.public_and_internal_only
+ end
+ end
+ else
+ # Not authenticated
+ #
+ # Return only:
+ # public projects
+ group.projects.public_only
+ end
+ end
+
+ def all_projects
+ # TODO: implement
+ raise 'Not implemented yet'
+ end
+end
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 0db43fa1809..4e7d01acd2a 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -49,8 +49,17 @@ module ApplicationHelper
args.any? { |v| v.to_s.downcase == action_name }
end
+ def group_icon(group_path)
+ group = Group.find_by(path: group_path)
+ if group && group.avatar.present?
+ group.avatar.url
+ else
+ '/assets/no_group_avatar.png'
+ end
+ end
+
def avatar_icon(user_email = '', size = nil)
- user = User.find_by_email(user_email)
+ user = User.find_by(email: user_email)
if user && user.avatar.present?
user.avatar.url
else
@@ -153,15 +162,6 @@ module ApplicationHelper
alias_method :url_to_image, :image_url
- def users_select_tag(id, opts = {})
- css_class = "ajax-users-select "
- css_class << "multiselect " if opts[:multiple]
- css_class << (opts[:class] || '')
- value = opts[:selected] || ''
-
- hidden_field_tag(id, value, class: css_class)
- end
-
def body_data_page
path = controller.controller_path.split('/')
namespace = path.first if path.second
@@ -203,8 +203,14 @@ module ApplicationHelper
def highlight_js(&block)
string = capture(&block)
- content_tag :div, class: user_color_scheme_class do
- Pygments::Lexer[:js].highlight(string).html_safe
+ content_tag :div, class: "highlighted-data #{user_color_scheme_class}" do
+ content_tag :div, class: 'highlight' do
+ content_tag :pre do
+ content_tag :code do
+ string.html_safe
+ end
+ end
+ end
end
end
@@ -221,4 +227,10 @@ module ApplicationHelper
def render_markup(file_name, file_content)
GitHub::Markup.render(file_name, file_content).html_safe
end
+
+ def spinner(text = nil)
+ content_tag :div, class: 'loading hide' do
+ content_tag(:i, nil, class: 'icon-spinner icon-spin') + text
+ end
+ end
end
diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb
index 663369e4584..5e5f3f77a21 100644
--- a/app/helpers/commits_helper.rb
+++ b/app/helpers/commits_helper.rb
@@ -122,17 +122,18 @@ module CommitsHelper
def commit_person_link(commit, options = {})
source_name = commit.send "#{options[:source]}_name".to_sym
source_email = commit.send "#{options[:source]}_email".to_sym
+
+ user = User.find_for_commit(source_email, source_name)
+ person_name = user.nil? ? source_name : user.name
+ person_email = user.nil? ? source_email : user.email
+
text = if options[:avatar]
- avatar = image_tag(avatar_icon(source_email, options[:size]), class: "avatar #{"s#{options[:size]}" if options[:size]}", width: options[:size], alt: "")
- %Q{#{avatar} <span class="commit-#{options[:source]}-name">#{source_name}</span>}
+ avatar = image_tag(avatar_icon(person_email, options[:size]), class: "avatar #{"s#{options[:size]}" if options[:size]}", width: options[:size], alt: "")
+ %Q{#{avatar} <span class="commit-#{options[:source]}-name">#{person_name}</span>}
else
- source_name
+ person_name
end
- # Prefer email match over name match
- user = User.where(email: source_email).first
- user ||= User.where(name: source_name).first
-
options = {
class: "commit-#{options[:source]}-link has_tooltip",
data: { :'original-title' => sanitize(source_email) }
diff --git a/app/helpers/dashboard_helper.rb b/app/helpers/dashboard_helper.rb
index 7f86a833cb0..d5712ab3374 100644
--- a/app/helpers/dashboard_helper.rb
+++ b/app/helpers/dashboard_helper.rb
@@ -1,7 +1,7 @@
module DashboardHelper
def filter_path(entity, options={})
exist_opts = {
- status: params[:status],
+ state: params[:state],
scope: params[:scope],
project_id: params[:project_id],
}
diff --git a/app/helpers/gitlab_markdown_helper.rb b/app/helpers/gitlab_markdown_helper.rb
index 8894a01eaea..6cad5e4658e 100644
--- a/app/helpers/gitlab_markdown_helper.rb
+++ b/app/helpers/gitlab_markdown_helper.rb
@@ -28,14 +28,16 @@ module GitlabMarkdownHelper
link_to(gfm_body.html_safe, url, html_options)
end
- def markdown(text)
- unless @markdown
- gitlab_renderer = Redcarpet::Render::GitlabHTML.new(self,
- # see https://github.com/vmg/redcarpet#darling-i-packed-you-a-couple-renderers-for-lunch-
- filter_html: true,
- with_toc_data: true,
- hard_wrap: true,
- safe_links_only: true)
+ def markdown(text, options={})
+ unless (@markdown and options == @options)
+ @options = options
+ gitlab_renderer = Redcarpet::Render::GitlabHTML.new(self, {
+ # see https://github.com/vmg/redcarpet#darling-i-packed-you-a-couple-renderers-for-lunch-
+ filter_html: true,
+ with_toc_data: true,
+ hard_wrap: true,
+ safe_links_only: true
+ }.merge(options))
@markdown = Redcarpet::Markdown.new(gitlab_renderer,
# see https://github.com/vmg/redcarpet#and-its-like-really-simple-to-use
no_intra_emphasis: true,
@@ -47,7 +49,6 @@ module GitlabMarkdownHelper
space_after_headers: true,
superscript: true)
end
-
@markdown.render(text).html_safe
end
@@ -69,10 +70,17 @@ module GitlabMarkdownHelper
project_path_with_namespace = project.path_with_namespace
paths = extract_paths(text)
paths.each do |file_path|
- new_path = rebuild_path(project_path_with_namespace, file_path, requested_path, ref)
- # Replacing old string with a new one with brackets ]() to prevent replacing occurence of a word
- # e.g. If we have a markdown like [test](test) this will replace ](test) and not the word test
- text.gsub!("](#{file_path})", "](/#{new_path})")
+ original_file_path = extract(file_path)
+ new_path = rebuild_path(project_path_with_namespace, original_file_path, requested_path, ref)
+ if reference_path?(file_path)
+ # Replacing old string with a new one that contains updated path
+ # eg. [some document]: document.md will be replaced with [some document] /namespace/project/master/blob/document.md
+ text.gsub!(file_path, file_path.gsub(original_file_path, "/#{new_path}"))
+ else
+ # Replacing old string with a new one with brackets ]() to prevent replacing occurence of a word
+ # e.g. If we have a markdown like [test](test) this will replace ](test) and not the word test
+ text.gsub!("](#{file_path})", "](/#{new_path})")
+ end
end
text
end
@@ -83,9 +91,11 @@ module GitlabMarkdownHelper
select_relative(paths)
end
- # Split the markdown text to each line and find all paths, this will match anything with - ]("some_text")
+ # Split the markdown text to each line and find all paths, this will match anything with - ]("some_text") and [some text]: file.md
def pick_out_paths(markdown_text)
- markdown_text.split("\n").map { |text| text.scan(/\]\(([^(]+)\)/) }
+ inline_paths = markdown_text.split("\n").map { |text| text.scan(/\]\(([^(]+)\)/) }
+ reference_paths = markdown_text.split("\n").map { |text| text.scan(/\[.*\]:.*/) }
+ inline_paths + reference_paths
end
# Removes any empty result produced by not matching the regexp
@@ -93,23 +103,35 @@ module GitlabMarkdownHelper
paths.reject{|l| l.empty? }.flatten
end
+ # If a path is a reference style link we need to omit ]:
+ def extract(path)
+ path.split("]: ").last
+ end
+
# Reject any path that contains ignored protocol
# eg. reject "https://gitlab.org} but accept "doc/api/README.md"
def select_relative(paths)
paths.reject{|path| ignored_protocols.map{|protocol| path.include?(protocol)}.any?}
end
+ # Check whether a path is a reference-style link
+ def reference_path?(path)
+ path.include?("]: ")
+ end
+
def ignored_protocols
["http://","https://", "ftp://", "mailto:"]
end
def rebuild_path(path_with_namespace, path, requested_path, ref)
+ path.gsub!(/(#.*)/, "")
+ id = $1 || ""
file_path = relative_file_path(path, requested_path)
[
path_with_namespace,
path_with_ref(file_path, ref),
file_path
- ].compact.join("/")
+ ].compact.join("/").gsub(/\/*$/, '') + id
end
# Checks if the path exists in the repo
@@ -134,6 +156,7 @@ module GitlabMarkdownHelper
# If we are at doc/api and the README.md shown in below the tree view
# this takes the rquest path(doc/api) and adds users.md so the path looks like doc/api/users.md
def build_nested_path(path, request_path)
+ return request_path if path == ""
return path unless request_path
if local_path(request_path) == "tree"
base = request_path.split("/").push(path)
@@ -146,19 +169,28 @@ module GitlabMarkdownHelper
end
def file_exists?(path)
- return false if path.nil? || path.empty?
- File.exists?(path_on_fs(path))
+ return false if path.nil?
+ return @repository.blob_at(current_sha, path).present? || @repository.tree(current_sha, path).entries.any?
end
# Check if the path is pointing to a directory(tree) or a file(blob)
# eg. doc/api is directory and doc/README.md is file
def local_path(path)
- File.directory?(path_on_fs(path)) ? "tree" : "blob"
+ return "tree" if @repository.tree(current_sha, path).entries.any?
+ return "raw" if @repository.blob_at(current_sha, path).image?
+ return "blob"
end
- # Path to the file in the satellites repository on the filesystem
- def path_on_fs(path)
- [@path_to_satellite, path].join("/")
+ def current_ref
+ @commit.nil? ? "master" : @commit.id
+ end
+
+ def current_sha
+ if @commit
+ @commit.id
+ else
+ @repository.head_commit.sha
+ end
end
# We will assume that if no ref exists we can point to master
diff --git a/app/helpers/groups_helper.rb b/app/helpers/groups_helper.rb
index 7c09273d53e..cfc9a572cac 100644
--- a/app/helpers/groups_helper.rb
+++ b/app/helpers/groups_helper.rb
@@ -1,6 +1,18 @@
module GroupsHelper
def remove_user_from_group_message(group, user)
- "You are going to remove #{user.name} from #{group.name} Group. Are you sure?"
+ "Are you sure you want to remove \"#{user.name}\" from \"#{group.name}\"?"
+ end
+
+ def leave_group_message(group)
+ "Are you sure you want to leave \"#{group}\" group?"
+ end
+
+ def should_user_see_group_roles?(user, group)
+ if user
+ user.is_admin? || group.members.exists?(user_id: user.id)
+ else
+ false
+ end
end
def group_head_title
diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb
index cdba6ce84dc..95f0eff58b1 100644
--- a/app/helpers/issues_helper.rb
+++ b/app/helpers/issues_helper.rb
@@ -70,11 +70,11 @@ module IssuesHelper
end
def bulk_update_milestone_options
- options_for_select(["None (backlog)", nil]) + options_from_collection_for_select(project_active_milestones, "id", "title", params[:milestone_id])
+ options_for_select(["None (backlog)"]) + options_from_collection_for_select(project_active_milestones, "id", "title", params[:milestone_id])
end
def bulk_update_assignee_options
- options_for_select(["None (unassigned)", nil]) + options_from_collection_for_select(@project.team.members, "id", "name", params[:assignee_id])
+ options_for_select(["None (unassigned)"]) + options_from_collection_for_select(@project.team.members, "id", "name", params[:assignee_id])
end
def assignee_options object
@@ -84,4 +84,16 @@ module IssuesHelper
def milestone_options object
options_from_collection_for_select(@project.milestones.active, 'id', 'title', object.milestone_id)
end
+
+ def issue_box_class(item)
+ if item.respond_to?(:expired?) && item.expired?
+ 'issue-box-expired'
+ elsif item.respond_to?(:merged?) && item.merged?
+ 'issue-box-merged'
+ elsif item.closed?
+ 'issue-box-closed'
+ else
+ 'issue-box-open'
+ end
+ end
end
diff --git a/app/helpers/merge_requests_helper.rb b/app/helpers/merge_requests_helper.rb
index 5e3f82fe9ce..1381b0220d6 100644
--- a/app/helpers/merge_requests_helper.rb
+++ b/app/helpers/merge_requests_helper.rb
@@ -1,8 +1,9 @@
module MergeRequestsHelper
def new_mr_path_from_push_event(event)
+ target_project = event.project.forked_from_project || event.project
new_project_merge_request_path(
event.project,
- new_mr_from_push_event(event, event.project)
+ new_mr_from_push_event(event, target_project)
)
end
diff --git a/app/helpers/notes_helper.rb b/app/helpers/notes_helper.rb
index 695147cd6db..7ae104b8fd1 100644
--- a/app/helpers/notes_helper.rb
+++ b/app/helpers/notes_helper.rb
@@ -17,7 +17,7 @@ module NotesHelper
def link_to_merge_request_diff_line_note(note)
if note.for_merge_request_diff_line? and note.diff
- link_to "#{note.diff_file_name}:L#{note.diff_new_line}", diffs_project_merge_request_path(note.project, note.noteable_id, anchor: note.line_code)
+ link_to "#{note.diff_file_name}:L#{note.diff_new_line}", diffs_project_merge_request_path(note.project, note.noteable, anchor: note.line_code)
end
end
diff --git a/app/helpers/notifications_helper.rb b/app/helpers/notifications_helper.rb
index ae3402b2617..b2399bb6db1 100644
--- a/app/helpers/notifications_helper.rb
+++ b/app/helpers/notifications_helper.rb
@@ -1,11 +1,11 @@
module NotificationsHelper
def notification_icon(notification)
if notification.disabled?
- content_tag :i, nil, class: 'icon-circle cred'
+ content_tag :i, nil, class: 'icon-volume-off cred'
elsif notification.participating?
- content_tag :i, nil, class: 'icon-circle cblue'
+ content_tag :i, nil, class: 'icon-volume-down cblue'
elsif notification.watch?
- content_tag :i, nil, class: 'icon-circle cgreen'
+ content_tag :i, nil, class: 'icon-volume-up cgreen'
else
content_tag :i, nil, class: 'icon-circle-blank cblue'
end
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index a6a507360bd..e943045e414 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -64,6 +64,31 @@ 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],
diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb
index f24156e4d85..d7f3da7e537 100644
--- a/app/helpers/search_helper.rb
+++ b/app/helpers/search_helper.rb
@@ -1,16 +1,21 @@
module SearchHelper
- def search_autocomplete_source
+ def search_autocomplete_opts(term)
return unless current_user
+
+ resources_results = [
+ groups_autocomplete(term),
+ projects_autocomplete(term)
+ ].flatten
+
+ generic_results = project_autocomplete + default_autocomplete + help_autocomplete
+ generic_results.select! { |result| result[:label] =~ Regexp.new(term, "i") }
+
[
- groups_autocomplete,
- projects_autocomplete,
- public_projects_autocomplete,
- default_autocomplete,
- project_autocomplete,
- help_autocomplete
+ resources_results,
+ generic_results
].flatten.uniq do |item|
item[:label]
- end.to_json
+ end
end
private
@@ -43,7 +48,7 @@ module SearchHelper
# Autocomplete results for the current project, if it's defined
def project_autocomplete
if @project && @project.repository.exists? && @project.repository.root_ref
- prefix = simple_sanitize(@project.name_with_namespace)
+ prefix = search_result_sanitize(@project.name_with_namespace)
ref = @ref || @project.repository.root_ref
[
@@ -65,23 +70,26 @@ module SearchHelper
end
# Autocomplete results for the current user's groups
- def groups_autocomplete
- current_user.authorized_groups.map do |group|
- { label: "group: #{simple_sanitize(group.name)}", url: group_path(group) }
+ def groups_autocomplete(term, limit = 5)
+ current_user.authorized_groups.search(term).limit(limit).map do |group|
+ {
+ label: "group: #{search_result_sanitize(group.name)}",
+ url: group_path(group)
+ }
end
end
# Autocomplete results for the current user's projects
- def projects_autocomplete
- current_user.authorized_projects.non_archived.map do |p|
- { label: "project: #{simple_sanitize(p.name_with_namespace)}", url: project_path(p) }
+ def projects_autocomplete(term, limit = 5)
+ Project.accessible_to(current_user).search_by_title(term).non_archived.limit(limit).map do |p|
+ {
+ label: "project: #{search_result_sanitize(p.name_with_namespace)}",
+ url: project_path(p)
+ }
end
end
- # Autocomplete results for the current user's projects
- def public_projects_autocomplete
- Project.public_or_internal_only(current_user).non_archived.map do |p|
- { label: "project: #{simple_sanitize(p.name_with_namespace)}", url: project_path(p) }
- end
+ def search_result_sanitize(str)
+ Sanitize.clean(str)
end
end
diff --git a/app/helpers/selects_helper.rb b/app/helpers/selects_helper.rb
new file mode 100644
index 00000000000..a1fe4488ae9
--- /dev/null
+++ b/app/helpers/selects_helper.rb
@@ -0,0 +1,20 @@
+module SelectsHelper
+ def users_select_tag(id, opts = {})
+ css_class = "ajax-users-select "
+ css_class << "multiselect " if opts[:multiple]
+ css_class << (opts[:class] || '')
+ value = opts[:selected] || ''
+
+ hidden_field_tag(id, value, class: css_class)
+ end
+
+ def project_users_select_tag(id, opts = {})
+ css_class = "ajax-project-users-select "
+ css_class << "multiselect " if opts[:multiple]
+ css_class << (opts[:class] || '')
+ value = opts[:selected] || ''
+ placeholder = opts[:placeholder] || 'Select user'
+
+ hidden_field_tag(id, value, class: css_class, 'data-placeholder' => placeholder)
+ end
+end
diff --git a/app/helpers/submodule_helper.rb b/app/helpers/submodule_helper.rb
new file mode 100644
index 00000000000..56f6e4d9cc1
--- /dev/null
+++ b/app/helpers/submodule_helper.rb
@@ -0,0 +1,43 @@
+module SubmoduleHelper
+ include Gitlab::ShellAdapter
+
+ # links to files listing for submodule if submodule is a project on this server
+ def submodule_links(submodule_item)
+ url = @repository.submodule_url_for(@ref, submodule_item.path)
+
+ return url, nil unless url =~ /([^\/:]+\/[^\/]+\.git)\Z/
+
+ project = $1
+ project.chomp!('.git')
+
+ if self_url?(url, project)
+ return project_path(project), project_tree_path(project, submodule_item.id)
+ elsif github_dot_com_url?(url)
+ standard_links('github.com', project, submodule_item.id)
+ elsif gitlab_dot_com_url?(url)
+ standard_links('gitlab.com', project, submodule_item.id)
+ else
+ return url, nil
+ end
+ end
+
+ protected
+
+ def github_dot_com_url?(url)
+ url =~ /github\.com[\/:][^\/]+\/[^\/]+\Z/
+ end
+
+ def gitlab_dot_com_url?(url)
+ url =~ /gitlab\.com[\/:][^\/]+\/[^\/]+\Z/
+ end
+
+ def self_url?(url, project)
+ return true if url == [ Gitlab.config.gitlab.url, '/', project, '.git' ].join('')
+ url == gitlab_shell.url_to_repo(project)
+ end
+
+ def standard_links(host, project, commit)
+ base = [ 'https://', host, '/', project ].join('')
+ return base, [ base, '/tree/', commit ].join('')
+ end
+end
diff --git a/app/mailers/emails/issues.rb b/app/mailers/emails/issues.rb
index 5abdf99529c..3adb47dc5b1 100644
--- a/app/mailers/emails/issues.rb
+++ b/app/mailers/emails/issues.rb
@@ -3,22 +3,27 @@ module Emails
def new_issue_email(recipient_id, issue_id)
@issue = Issue.find(issue_id)
@project = @issue.project
- mail(to: recipient(recipient_id), subject: subject("New issue ##{@issue.iid}", @issue.title))
+ mail(from: sender(@issue.author_id),
+ to: recipient(recipient_id),
+ subject: subject("#{@issue.title} (##{@issue.iid})"))
end
- def reassigned_issue_email(recipient_id, issue_id, previous_assignee_id)
+ def reassigned_issue_email(recipient_id, issue_id, previous_assignee_id, updated_by_user_id)
@issue = Issue.find(issue_id)
- @previous_assignee = User.find_by_id(previous_assignee_id) if previous_assignee_id
+ @previous_assignee = User.find_by(id: previous_assignee_id) if previous_assignee_id
@project = @issue.project
- mail(to: recipient(recipient_id), subject: subject("Changed issue ##{@issue.iid}", @issue.title))
+ mail(from: sender(updated_by_user_id),
+ to: recipient(recipient_id),
+ subject: subject("#{@issue.title} (##{@issue.iid})"))
end
def closed_issue_email(recipient_id, issue_id, updated_by_user_id)
@issue = Issue.find issue_id
@project = @issue.project
@updated_by = User.find updated_by_user_id
- mail(to: recipient(recipient_id),
- subject: subject("Closed issue ##{@issue.iid}", @issue.title))
+ mail(from: sender(updated_by_user_id),
+ to: recipient(recipient_id),
+ subject: subject("#{@issue.title} (##{@issue.iid})"))
end
def issue_status_changed_email(recipient_id, issue_id, status, updated_by_user_id)
@@ -26,8 +31,9 @@ module Emails
@issue_status = status
@project = @issue.project
@updated_by = User.find updated_by_user_id
- mail(to: recipient(recipient_id),
- subject: subject("Changed issue ##{@issue.iid}", @issue.title))
+ mail(from: sender(updated_by_user_id),
+ to: recipient(recipient_id),
+ subject: subject("#{@issue.title} (##{@issue.iid})"))
end
end
end
diff --git a/app/mailers/emails/merge_requests.rb b/app/mailers/emails/merge_requests.rb
index 25b8bf755e2..0845e14edc7 100644
--- a/app/mailers/emails/merge_requests.rb
+++ b/app/mailers/emails/merge_requests.rb
@@ -3,27 +3,35 @@ module Emails
def new_merge_request_email(recipient_id, merge_request_id)
@merge_request = MergeRequest.find(merge_request_id)
@project = @merge_request.project
- mail(to: recipient(recipient_id), subject: subject("New merge request ##{@merge_request.iid}", @merge_request.title))
+ mail(from: sender(@merge_request.author_id),
+ to: recipient(recipient_id),
+ subject: subject("#{@merge_request.title} (!#{@merge_request.iid})"))
end
- def reassigned_merge_request_email(recipient_id, merge_request_id, previous_assignee_id)
+ def reassigned_merge_request_email(recipient_id, merge_request_id, previous_assignee_id, updated_by_user_id)
@merge_request = MergeRequest.find(merge_request_id)
- @previous_assignee = User.find_by_id(previous_assignee_id) if previous_assignee_id
+ @previous_assignee = User.find_by(id: previous_assignee_id) if previous_assignee_id
@project = @merge_request.project
- mail(to: recipient(recipient_id), subject: subject("Changed merge request ##{@merge_request.iid}", @merge_request.title))
+ mail(from: sender(updated_by_user_id),
+ to: recipient(recipient_id),
+ subject: subject("#{@merge_request.title} (!#{@merge_request.iid})"))
end
def closed_merge_request_email(recipient_id, merge_request_id, updated_by_user_id)
@merge_request = MergeRequest.find(merge_request_id)
@updated_by = User.find updated_by_user_id
@project = @merge_request.project
- mail(to: recipient(recipient_id), subject: subject("Closed merge request ##{@merge_request.iid}", @merge_request.title))
+ mail(from: sender(updated_by_user_id),
+ to: recipient(recipient_id),
+ subject: subject("#{@merge_request.title} (!#{@merge_request.iid})"))
end
def merged_merge_request_email(recipient_id, merge_request_id)
@merge_request = MergeRequest.find(merge_request_id)
@project = @merge_request.project
- mail(to: recipient(recipient_id), subject: subject("Accepted merge request ##{@merge_request.iid}", @merge_request.title))
+ mail(from: sender(@merge_request.author_id_of_changes),
+ to: recipient(recipient_id),
+ subject: subject("#{@merge_request.title} (!#{@merge_request.iid})"))
end
end
@@ -57,7 +65,7 @@ module Emails
# >> subject('Lorem ipsum', 'Dolor sit amet')
# => "GitLab Merge Request | Lorem ipsum | Dolor sit amet"
def subject(*extra)
- subject = "GitLab Merge Request |"
+ subject = "Merge Request | "
if @merge_request.for_fork?
subject << "#{@merge_request.source_project.name_with_namespace}:#{merge_request.source_branch} >> #{@merge_request.target_project.name_with_namespace}:#{merge_request.target_branch}"
else
diff --git a/app/mailers/emails/notes.rb b/app/mailers/emails/notes.rb
index e967cf6dc73..00b127da429 100644
--- a/app/mailers/emails/notes.rb
+++ b/app/mailers/emails/notes.rb
@@ -4,27 +4,35 @@ module Emails
@note = Note.find(note_id)
@commit = @note.noteable
@project = @note.project
- mail(to: recipient(recipient_id), subject: subject("Note for commit #{@commit.short_id}", @commit.title))
+ mail(from: sender(@note.author_id),
+ to: recipient(recipient_id),
+ subject: subject("#{@commit.title} (#{@commit.short_id})"))
end
def note_issue_email(recipient_id, note_id)
@note = Note.find(note_id)
@issue = @note.noteable
@project = @note.project
- mail(to: recipient(recipient_id), subject: subject("Note for issue ##{@issue.iid}"))
+ mail(from: sender(@note.author_id),
+ to: recipient(recipient_id),
+ subject: subject("#{@issue.title} (##{@issue.iid})"))
end
def note_merge_request_email(recipient_id, note_id)
@note = Note.find(note_id)
@merge_request = @note.noteable
@project = @note.project
- mail(to: recipient(recipient_id), subject: subject("Note for merge request ##{@merge_request.iid}"))
+ mail(from: sender(@note.author_id),
+ to: recipient(recipient_id),
+ subject: subject("#{@merge_request.title} (!#{@merge_request.iid})"))
end
def note_wall_email(recipient_id, note_id)
@note = Note.find(note_id)
@project = @note.project
- mail(to: recipient(recipient_id), subject: subject("Note on wall"))
+ mail(from: sender(@note.author_id),
+ to: recipient(recipient_id),
+ subject: subject("Note on wall"))
end
end
end
diff --git a/app/mailers/emails/profile.rb b/app/mailers/emails/profile.rb
index bcd44f9476c..c91660a02b5 100644
--- a/app/mailers/emails/profile.rb
+++ b/app/mailers/emails/profile.rb
@@ -6,6 +6,12 @@ module Emails
mail(to: @user.email, subject: subject("Account was created for you"))
end
+ def new_email_email(email_id)
+ @email = Email.find(email_id)
+ @user = @email.user
+ mail(to: @user.email, subject: subject("Email was added to your account"))
+ end
+
def new_ssh_key_email(key_id)
@key = Key.find(key_id)
@user = @key.user
diff --git a/app/mailers/emails/projects.rb b/app/mailers/emails/projects.rb
index df21d7b5b02..46f24e9fb7c 100644
--- a/app/mailers/emails/projects.rb
+++ b/app/mailers/emails/projects.rb
@@ -17,11 +17,14 @@ module Emails
def repository_push_email(project_id, recipient, author_id, branch, compare)
@project = Project.find(project_id)
@author = User.find(author_id)
+ @compare = compare
@commits = Commit.decorate(compare.commits)
@diffs = compare.diffs
@branch = branch
- mail(to: recipient, subject: subject("New push to repository"))
+ mail(from: sender(author_id),
+ to: recipient,
+ subject: subject("New push to repository"))
end
end
end
diff --git a/app/mailers/notify.rb b/app/mailers/notify.rb
index aec4c57cba8..554f53cf148 100644
--- a/app/mailers/notify.rb
+++ b/app/mailers/notify.rb
@@ -12,19 +12,36 @@ class Notify < ActionMailer::Base
default_url_options[:host] = Gitlab.config.gitlab.host
default_url_options[:protocol] = Gitlab.config.gitlab.protocol
- default_url_options[:port] = Gitlab.config.gitlab.port if Gitlab.config.gitlab_on_non_standard_port?
+ default_url_options[:port] = Gitlab.config.gitlab.port unless Gitlab.config.gitlab_on_standard_port?
default_url_options[:script_name] = Gitlab.config.gitlab.relative_url_root
- default from: Gitlab.config.gitlab.email_from
+ default from: Proc.new { default_sender_address.format }
default reply_to: "noreply@#{Gitlab.config.gitlab.host}"
- # Just send email with 3 seconds delay
+ # Just send email with 2 seconds delay
def self.delay
delay_for(2.seconds)
end
private
+ # The default email address to send emails from
+ def default_sender_address
+ address = Mail::Address.new(Gitlab.config.gitlab.email_from)
+ address.display_name = "GitLab"
+ address
+ end
+
+ # Return an email address that displays the name of the sender.
+ # Only the displayed name changes; the actual email address is always the same.
+ def sender(sender_id)
+ if sender = User.find(sender_id)
+ address = default_sender_address
+ address.display_name = sender.name
+ address.format
+ end
+ end
+
# Look up a User by their ID and return their email address
#
# recipient_id - User ID
@@ -43,21 +60,21 @@ class Notify < ActionMailer::Base
# Examples
#
# >> subject('Lorem ipsum')
- # => "GitLab | Lorem ipsum"
+ # => "Lorem ipsum"
#
# # Automatically inserts Project name when @project is set
# >> @project = Project.last
# => #<Project id: 1, name: "Ruby on Rails", path: "ruby_on_rails", ...>
# >> subject('Lorem ipsum')
- # => "GitLab | Ruby on Rails | Lorem ipsum "
+ # => "Ruby on Rails | Lorem ipsum "
#
# # Accepts multiple arguments
# >> subject('Lorem ipsum', 'Dolor sit amet')
- # => "GitLab | Lorem ipsum | Dolor sit amet"
+ # => "Lorem ipsum | Dolor sit amet"
def subject(*extra)
- subject = "GitLab"
- subject << (@project ? " | #{@project.name_with_namespace}" : "")
- subject << " | " + extra.join(' | ') if extra.present?
+ subject = ""
+ subject << "#{@project.name} | " if @project
+ subject << extra.join(' | ') if extra.present?
subject
end
end
diff --git a/app/models/ability.rb b/app/models/ability.rb
index cf925141f2d..69ada753d02 100644
--- a/app/models/ability.rb
+++ b/app/models/ability.rb
@@ -14,6 +14,7 @@ class Ability
when "MergeRequest" then merge_request_abilities(user, subject)
when "Group" then group_abilities(user, subject)
when "Namespace" then namespace_abilities(user, subject)
+ when "UsersGroup" then users_group_abilities(user, subject)
else []
end.concat(global_abilities(user))
end
@@ -42,7 +43,19 @@ class Ability
:download_code
]
else
- []
+ group = if subject.kind_of?(Group)
+ subject
+ elsif subject.respond_to?(:group)
+ subject.group
+ else
+ nil
+ end
+
+ if group && group.has_projects_accessible_to?(nil)
+ [:read_group]
+ else
+ []
+ end
end
end
@@ -125,6 +138,8 @@ class Ability
project_report_rules + [
:write_merge_request,
:write_wiki,
+ :modify_issue,
+ :admin_issue,
:push_code
]
end
@@ -169,7 +184,7 @@ class Ability
def group_abilities user, group
rules = []
- if group.users.include?(user) || user.admin?
+ if user.admin? || group.users.include?(user) || ProjectsFinder.new.execute(user, group: group).any?
rules << :read_group
end
@@ -217,5 +232,19 @@ class Ability
end
end
end
+
+ def users_group_abilities(user, subject)
+ rules = []
+ target_user = subject.user
+ group = subject.group
+ can_manage = group_abilities(user, group).include?(:manage_group)
+ if can_manage && (user != target_user)
+ rules << :modify
+ end
+ if !group.last_owner?(user) && (can_manage || (user == target_user))
+ rules << :destroy
+ end
+ rules
+ end
end
end
diff --git a/app/models/commit.rb b/app/models/commit.rb
index dd1f9801878..c313aeb7572 100644
--- a/app/models/commit.rb
+++ b/app/models/commit.rb
@@ -16,29 +16,31 @@ class Commit
DIFF_HARD_LIMIT_FILES = 500
DIFF_HARD_LIMIT_LINES = 10000
- def self.decorate(commits)
- commits.map { |c| self.new(c) }
- end
+ class << self
+ def decorate(commits)
+ commits.map { |c| self.new(c) }
+ end
- # Calculate number of lines to render for diffs
- def self.diff_line_count(diffs)
- diffs.reduce(0){|sum, d| sum + d.diff.lines.count}
- end
+ # Calculate number of lines to render for diffs
+ def diff_line_count(diffs)
+ diffs.reduce(0){|sum, d| sum + d.diff.lines.count}
+ end
- def self.diff_suppress?(diffs, line_count = nil)
- # optimize - check file count first
- return true if diffs.size > DIFF_SAFE_FILES
+ def diff_suppress?(diffs, line_count = nil)
+ # optimize - check file count first
+ return true if diffs.size > DIFF_SAFE_FILES
- line_count ||= Commit::diff_line_count(diffs)
- line_count > DIFF_SAFE_LINES
- end
+ line_count ||= Commit::diff_line_count(diffs)
+ line_count > DIFF_SAFE_LINES
+ end
- def self.diff_force_suppress?(diffs, line_count = nil)
- # optimize - check file count first
- return true if diffs.size > DIFF_HARD_LIMIT_FILES
+ def diff_force_suppress?(diffs, line_count = nil)
+ # optimize - check file count first
+ return true if diffs.size > DIFF_HARD_LIMIT_FILES
- line_count ||= Commit::diff_line_count(diffs)
- line_count > DIFF_HARD_LIMIT_LINES
+ line_count ||= Commit::diff_line_count(diffs)
+ line_count > DIFF_HARD_LIMIT_LINES
+ end
end
attr_accessor :raw
@@ -97,14 +99,16 @@ class Commit
#
# cut off, ellipses (`&hellp;`) are prepended to the commit message.
def description
- description = safe_message
+ title_end = safe_message.index(/\n/)
+ @description ||= if (!title_end && safe_message.length > 100) || (title_end && title_end > 100)
+ "&hellip;".html_safe << safe_message[80..-1]
+ else
+ safe_message.split(/\n/, 2)[1].try(:chomp)
+ end
+ end
- title_end = description.index(/\n/)
- if (!title_end && description.length > 100) || (title_end && title_end > 100)
- "&hellip;".html_safe << description[80..-1]
- else
- description.split(/\n/, 2)[1].try(:chomp)
- end
+ def description?
+ description.present?
end
# Regular expression that identifies commit message clauses that trigger issue closing.
diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb
index 58bf621f91b..75989888bfa 100644
--- a/app/models/concerns/issuable.rb
+++ b/app/models/concerns/issuable.rb
@@ -23,7 +23,8 @@ module Issuable
scope :assigned, -> { where("assignee_id IS NOT NULL") }
scope :unassigned, -> { where("assignee_id IS NULL") }
scope :of_projects, ->(ids) { where(project_id: ids) }
-
+ scope :opened, -> { with_state(:opened, :reopened) }
+ scope :closed, -> { with_state(:closed) }
delegate :name,
:email,
@@ -45,6 +46,18 @@ module Issuable
def search(query)
where("title like :query", query: "%#{query}%")
end
+
+ def sort(method)
+ case method.to_s
+ when 'newest' then reorder("#{table_name}.created_at DESC")
+ when 'oldest' then reorder("#{table_name}.created_at ASC")
+ when 'recently_updated' then reorder("#{table_name}.updated_at DESC")
+ when 'last_updated' then reorder("#{table_name}.updated_at ASC")
+ when 'milestone_due_soon' then joins(:milestone).reorder("milestones.due_date ASC")
+ when 'milestone_due_later' then joins(:milestone).reorder("milestones.due_date DESC")
+ else reorder("#{table_name}.created_at DESC")
+ end
+ end
end
def today?
diff --git a/app/models/email.rb b/app/models/email.rb
new file mode 100644
index 00000000000..22e71e4f107
--- /dev/null
+++ b/app/models/email.rb
@@ -0,0 +1,33 @@
+# == Schema Information
+#
+# Table name: emails
+#
+# id :integer not null, primary key
+# user_id :integer not null
+# email :string not null
+# created_at :datetime not null
+class Email < ActiveRecord::Base
+ attr_accessible :email, :user_id
+
+ #
+ # Relations
+ #
+ belongs_to :user
+
+ #
+ # Validations
+ #
+ validates :user_id, presence: true
+ validates :email, presence: true, email: { strict_mode: true }, uniqueness: true
+ validate :unique_email, if: ->(email) { email.email_changed? }
+
+ before_validation :cleanup_email
+
+ def cleanup_email
+ self.email = self.email.downcase.strip
+ end
+
+ def unique_email
+ self.errors.add(:email, 'has already been taken') if User.exists?(email: self.email)
+ end
+end \ No newline at end of file
diff --git a/app/models/event.rb b/app/models/event.rb
index ddb863c1be2..d43d6eb682f 100644
--- a/app/models/event.rb
+++ b/app/models/event.rb
@@ -56,11 +56,13 @@ class Event < ActiveRecord::Base
end
def create_ref_event(project, user, ref, action = 'add', prefix = 'refs/heads')
+ commit = project.repository.commit(ref.target)
+
if action.to_s == 'add'
before = '00000000'
- after = ref.commit.id
+ after = commit.id
else
- before = ref.commit.id
+ before = commit.id
after = '00000000'
end
diff --git a/app/models/gollum_wiki.rb b/app/models/gollum_wiki.rb
index 7ebaaff61cb..613a7110d12 100644
--- a/app/models/gollum_wiki.rb
+++ b/app/models/gollum_wiki.rb
@@ -1,4 +1,5 @@
class GollumWiki
+ include Gitlab::ShellAdapter
MARKUPS = {
"Markdown" => :markdown,
@@ -113,10 +114,6 @@ class GollumWiki
"#{@user.username} #{action} page: #{title}"
end
- def gitlab_shell
- @gitlab_shell ||= Gitlab::Shell.new
- end
-
def path_to_repo
@path_to_repo ||= File.join(Gitlab.config.gitlab_shell.repos_path, "#{path_with_namespace}.git")
end
diff --git a/app/models/group.rb b/app/models/group.rb
index 0b64d5b4f7f..0d4d5f4e836 100644
--- a/app/models/group.rb
+++ b/app/models/group.rb
@@ -12,10 +12,26 @@
# description :string(255) default(""), not null
#
+require 'carrierwave/orm/activerecord'
+require 'file_size_validator'
+
class Group < Namespace
has_many :users_groups, dependent: :destroy
has_many :users, through: :users_groups
+ attr_accessible :avatar
+
+ validate :avatar_type, if: ->(user) { user.avatar_changed? }
+ validates :avatar, file_size: { maximum: 100.kilobytes.to_i }
+
+ mount_uploader :avatar, AttachmentUploader
+
+ def self.accessible_to(user)
+ accessible_ids = Project.accessible_to(user).pluck(:namespace_id)
+ accessible_ids += user.groups.pluck(:id) if user
+ where(id: accessible_ids)
+ end
+
def human_name
name
end
@@ -50,4 +66,10 @@ class Group < Namespace
def members
users_groups
end
+
+ def avatar_type
+ unless self.avatar.image?
+ self.errors.add :avatar, "only images allowed"
+ end
+ end
end
diff --git a/app/models/issue.rb b/app/models/issue.rb
index 6580c5004af..a8dc6e5fd85 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -28,8 +28,6 @@ class Issue < ActiveRecord::Base
scope :of_group, ->(group) { where(project_id: group.project_ids) }
scope :of_user_team, ->(team) { where(project_id: team.project_ids, assignee_id: team.member_ids) }
- scope :opened, -> { with_state(:opened, :reopened) }
- scope :closed, -> { with_state(:closed) }
attr_accessible :title, :assignee_id, :position, :description,
:milestone_id, :label_list, :author_id_of_changes,
@@ -50,9 +48,7 @@ class Issue < ActiveRecord::Base
end
state :opened
-
state :reopened
-
state :closed
end
diff --git a/app/models/key.rb b/app/models/key.rb
index 79f7bbd2590..29a76f53f3d 100644
--- a/app/models/key.rb
+++ b/app/models/key.rb
@@ -53,7 +53,7 @@ class Key < ActiveRecord::Base
Tempfile.open('gitlab_key_file') do |file|
file.puts key
file.rewind
- cmd_output, cmd_status = popen("ssh-keygen -lf #{file.path}", '/tmp')
+ cmd_output, cmd_status = popen(%W(ssh-keygen -lf #{file.path}), '/tmp')
end
if cmd_status.zero?
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index e59aee8b445..4774cbcf3aa 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -31,6 +31,13 @@ class MergeRequest < ActiveRecord::Base
belongs_to :target_project, foreign_key: :target_project_id, class_name: "Project"
belongs_to :source_project, foreign_key: :source_project_id, class_name: "Project"
+ has_one :merge_request_diff, dependent: :destroy
+
+ after_create :create_merge_request_diff
+ after_update :update_merge_request_diff
+
+ delegate :commits, :diffs, :last_commit, :last_commit_short_sha, to: :merge_request_diff, prefix: nil
+
attr_accessible :title, :assignee_id, :source_project_id, :source_branch, :target_project_id, :target_branch, :milestone_id, :author_id_of_changes, :state_event, :description
attr_accessor :should_remove_source_branch
@@ -45,20 +52,26 @@ class MergeRequest < ActiveRecord::Base
end
event :merge do
- transition [:reopened, :opened] => :merged
+ transition [:reopened, :opened, :locked] => :merged
end
event :reopen do
transition closed: :reopened
end
- state :opened
+ event :lock do
+ transition [:reopened, :opened] => :locked
+ end
- state :reopened
+ event :unlock do
+ transition locked: :reopened
+ end
+ state :opened
+ state :reopened
state :closed
-
state :merged
+ state :locked
end
state_machine :merge_status, initial: :unchecked do
@@ -75,15 +88,10 @@ class MergeRequest < ActiveRecord::Base
end
state :unchecked
-
state :can_be_merged
-
state :cannot_be_merged
end
- serialize :st_commits
- serialize :st_diffs
-
validates :source_project, presence: true, unless: :allow_broken
validates :source_branch, presence: true
validates :target_project, presence: true
@@ -92,8 +100,6 @@ class MergeRequest < ActiveRecord::Base
scope :of_group, ->(group) { where("source_project_id in (:group_project_ids) OR target_project_id in (:group_project_ids)", group_project_ids: group.project_ids) }
scope :of_user_team, ->(team) { where("(source_project_id in (:team_project_ids) OR target_project_id in (:team_project_ids) AND assignee_id in (:team_member_ids))", team_project_ids: team.project_ids, team_member_ids: team.member_ids) }
- scope :opened, -> { with_state(:opened) }
- scope :closed, -> { with_state(:closed) }
scope :merged, -> { with_state(:merged) }
scope :by_branch, ->(branch_name) { where("(source_branch LIKE :branch) OR (target_branch LIKE :branch)", branch: branch_name) }
scope :cared, ->(user) { where('assignee_id = :user OR author_id = :user', user: user.id) }
@@ -105,7 +111,7 @@ class MergeRequest < ActiveRecord::Base
scope :closed, -> { with_states(:closed, :merged) }
def validate_branches
- if target_project==source_project && target_branch == source_branch
+ if target_project == source_project && target_branch == source_branch
errors.add :branch_conflict, "You can not use same project/branch for source and target"
end
@@ -119,9 +125,17 @@ class MergeRequest < ActiveRecord::Base
end
end
+ def update_merge_request_diff
+ if source_branch_changed? || target_branch_changed?
+ reload_code
+ mark_as_unchecked
+ end
+ end
+
def reload_code
- self.reloaded_commits
- self.reloaded_diffs
+ if merge_request_diff && opened?
+ merge_request_diff.reload_content
+ end
end
def check_if_can_be_merged
@@ -132,42 +146,6 @@ class MergeRequest < ActiveRecord::Base
end
end
- def diffs
- @diffs ||= (load_diffs(st_diffs) || [])
- end
-
- def reloaded_diffs
- if opened? && unmerged_diffs.any?
- self.st_diffs = dump_diffs(unmerged_diffs)
- self.save
- end
- end
-
- def broken_diffs?
- diffs == broken_diffs
- rescue
- true
- end
-
- def valid_diffs?
- !broken_diffs?
- end
-
- def unmerged_diffs
- diffs = if for_fork?
- Gitlab::Satellite::MergeAction.new(author, self).diffs_between_satellite
- else
- Gitlab::Git::Diff.between(target_project.repository, source_branch, target_branch)
- end
-
- diffs ||= []
- diffs
- end
-
- def last_commit
- commits.first
- end
-
def merge_event
self.target_project.events.where(target_id: self.id, target_type: "MergeRequest", action: Event::MERGED).last
end
@@ -176,56 +154,19 @@ class MergeRequest < ActiveRecord::Base
self.target_project.events.where(target_id: self.id, target_type: "MergeRequest", action: Event::CLOSED).last
end
- def commits
- load_commits(st_commits || [])
+ def automerge!(current_user, commit_message = nil)
+ MergeRequests::AutoMergeService.new.execute(self, current_user, commit_message)
end
- def probably_merged?
- unmerged_commits.empty? &&
- commits.any? && opened?
- end
-
- def reloaded_commits
- if opened? && unmerged_commits.any?
- self.st_commits = dump_commits(unmerged_commits)
- save
-
- end
- commits
- end
-
- def unmerged_commits
- if for_fork?
- commits = Gitlab::Satellite::MergeAction.new(self.author, self).commits_between
- else
- commits = target_project.repository.commits_between(self.target_branch, self.source_branch)
- end
-
- if commits.present?
- commits = Commit.decorate(commits).
- sort_by(&:created_at).
- reverse
- end
- commits
- end
-
- def merge!(user_id)
- self.author_id_of_changes = user_id
- self.merge
- end
-
- def automerge!(current_user)
- if Gitlab::Satellite::MergeAction.new(current_user, self).merge! && self.unmerged_commits.empty?
- self.merge!(current_user.id)
- true
- end
- rescue
- mark_as_unmergeable
- false
+ def open?
+ opened? || reopened?
end
def mr_and_commit_notes
- commit_ids = commits.map(&:id)
+ # Fetch comments only from last 100 commits
+ commits_for_notes_limit = 100
+ commit_ids = commits.last(commits_for_notes_limit).map(&:id)
+
project.notes.where(
"(noteable_type = 'MergeRequest' AND noteable_id = :mr_id) OR (noteable_type = 'Commit' AND commit_id IN (:commit_ids))",
mr_id: id,
@@ -247,10 +188,6 @@ class MergeRequest < ActiveRecord::Base
Gitlab::Satellite::MergeAction.new(current_user, self).format_patch
end
- def last_commit_short_sha
- @last_commit_short_sha ||= last_commit.sha[0..10]
- end
-
def for_fork?
target_project != source_project
end
@@ -293,6 +230,14 @@ class MergeRequest < ActiveRecord::Base
end
end
+ def source_project_namespace
+ if source_project && source_project.namespace
+ source_project.namespace.path
+ else
+ "(removed)"
+ end
+ end
+
def source_branch_exists?
return false unless self.source_project
@@ -319,33 +264,32 @@ class MergeRequest < ActiveRecord::Base
update_all(updated_at: Time.now)
end
- private
-
- def dump_commits(commits)
- commits.map(&:to_hash)
+ def merge_commit_message
+ message = "Merge branch '#{source_branch}' into '#{target_branch}'"
+ message << "\n\n"
+ message << title.to_s
+ message << "\n\n"
+ message << description.to_s
+ message
end
- def load_commits(array)
- array.map { |hash| Commit.new(Gitlab::Git::Commit.new(hash)) }
- end
-
- def dump_diffs(diffs)
- if diffs == broken_diffs
- broken_diffs
- elsif diffs.respond_to?(:map)
- diffs.map(&:to_hash)
+ # Return array of possible target branches
+ # dependes on target project of MR
+ def target_branches
+ if target_project.nil?
+ []
+ else
+ target_project.repository.branch_names
end
end
- def load_diffs(raw)
- if raw == broken_diffs
- broken_diffs
- elsif raw.respond_to?(:map)
- raw.map { |hash| Gitlab::Git::Diff.new(hash) }
+ # Return array of possible source branches
+ # dependes on source project of MR
+ def source_branches
+ if source_project.nil?
+ []
+ else
+ source_project.repository.branch_names
end
end
-
- def broken_diffs
- [Gitlab::Git::Diff::BROKEN_DIFF]
- end
end
diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb
new file mode 100644
index 00000000000..99afffc1db0
--- /dev/null
+++ b/app/models/merge_request_diff.rb
@@ -0,0 +1,155 @@
+require Rails.root.join("app/models/commit")
+
+class MergeRequestDiff < ActiveRecord::Base
+ # Prevent store of diff
+ # if commits amount more then 200
+ COMMITS_SAFE_SIZE = 200
+
+ attr_reader :commits, :diffs
+
+ belongs_to :merge_request
+
+ attr_accessible :state, :st_commits, :st_diffs
+
+ delegate :target_branch, :source_branch, to: :merge_request, prefix: nil
+
+ state_machine :state, initial: :empty do
+ state :collected
+ state :timeout
+ state :overflow_commits_safe_size
+ state :overflow_diff_files_limit
+ state :overflow_diff_lines_limit
+ end
+
+ serialize :st_commits
+ serialize :st_diffs
+
+ after_create :reload_content
+
+ def reload_content
+ reload_commits
+ reload_diffs
+ end
+
+ def diffs
+ @diffs ||= (load_diffs(st_diffs) || [])
+ end
+
+ def commits
+ @commits ||= load_commits(st_commits || [])
+ end
+
+ def last_commit
+ commits.first
+ end
+
+ def last_commit_short_sha
+ @last_commit_short_sha ||= last_commit.sha[0..10]
+ end
+
+ private
+
+ def dump_commits(commits)
+ commits.map(&:to_hash)
+ end
+
+ def load_commits(array)
+ array.map { |hash| Commit.new(Gitlab::Git::Commit.new(hash)) }
+ end
+
+ def dump_diffs(diffs)
+ if diffs.respond_to?(:map)
+ diffs.map(&:to_hash)
+ end
+ end
+
+ def load_diffs(raw)
+ if raw.respond_to?(:map)
+ raw.map { |hash| Gitlab::Git::Diff.new(hash) }
+ end
+ end
+
+ # Collect array of Git::Commit objects
+ # between target and source branches
+ def unmerged_commits
+ commits = if merge_request.for_fork?
+ Gitlab::Satellite::MergeAction.new(merge_request.author, merge_request).commits_between
+ else
+ repository.commits_between(target_branch, source_branch)
+ end
+
+ if commits.present?
+ commits = Commit.decorate(commits).
+ sort_by(&:created_at).
+ reverse
+ end
+
+ commits
+ end
+
+ # Reload all commits related to current merge request from repo
+ # and save it as array of hashes in st_commits db field
+ def reload_commits
+ commit_objects = unmerged_commits
+
+ if commit_objects.present?
+ self.st_commits = dump_commits(commit_objects)
+ end
+
+ save
+ end
+
+ # Reload diffs between branches related to current merge request from repo
+ # and save it as array of hashes in st_diffs db field
+ def reload_diffs
+ new_diffs = []
+
+ if commits.size.zero?
+ self.state = :empty
+ elsif commits.size > COMMITS_SAFE_SIZE
+ self.state = :overflow_commits_safe_size
+ else
+ new_diffs = unmerged_diffs
+ end
+
+ if new_diffs.any?
+ if new_diffs.size > Commit::DIFF_HARD_LIMIT_FILES
+ self.state = :overflow_diff_files_limit
+ new_diffs = []
+ end
+
+ if new_diffs.sum { |diff| diff.diff.lines.count } > Commit::DIFF_HARD_LIMIT_LINES
+ self.state = :overflow_diff_lines_limit
+ new_diffs = []
+ end
+ end
+
+ if new_diffs.present?
+ new_diffs = dump_commits(new_diffs)
+ self.state = :collected
+ end
+
+ self.st_diffs = new_diffs
+ self.save
+ end
+
+ # Collect array of Git::Diff objects
+ # between target and source branches
+ def unmerged_diffs
+ diffs = if merge_request.for_fork?
+ Gitlab::Satellite::MergeAction.new(merge_request.author, merge_request).diffs_between_satellite
+ else
+ Gitlab::Git::Diff.between(repository, source_branch, target_branch)
+ end
+
+ diffs ||= []
+ diffs
+ rescue Gitlab::Git::Diff::TimeoutError => ex
+ self.state = :timeout
+ diffs = []
+ end
+
+ def repository
+ merge_request.target_project.repository
+ end
+end
diff --git a/app/models/namespace.rb b/app/models/namespace.rb
index 8f837c72ff5..468c93bd426 100644
--- a/app/models/namespace.rb
+++ b/app/models/namespace.rb
@@ -10,6 +10,7 @@
# updated_at :datetime not null
# type :string(255)
# description :string(255) default(""), not null
+# avatar :string(255)
#
class Namespace < ActiveRecord::Base
@@ -26,7 +27,7 @@ class Namespace < ActiveRecord::Base
format: { with: Gitlab::Regex.name_regex,
message: "only letters, digits, spaces & '_' '-' '.' allowed." }
validates :description, length: { within: 0..255 }
- validates :path, uniqueness: true, presence: true, length: { within: 1..255 },
+ validates :path, uniqueness: { case_sensitive: false }, presence: true, length: { within: 1..255 },
exclusion: { in: Gitlab::Blacklist.path },
format: { with: Gitlab::Regex.path_regex,
message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" }
@@ -46,6 +47,14 @@ class Namespace < ActiveRecord::Base
def self.global_id
'GLN'
end
+
+ def projects_accessible_to(user)
+ projects.accessible_to(user)
+ end
+
+ def has_projects_accessible_to?(user)
+ projects_accessible_to(user).present?
+ end
def to_param
path
diff --git a/app/models/note.rb b/app/models/note.rb
index 67755f44148..48c03c9d587 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -72,14 +72,20 @@ class Note < ActiveRecord::Base
# +noteable+ was referenced from +mentioner+, by including GFM in either +mentioner+'s description or an associated Note.
# Create a system Note associated with +noteable+ with a GFM back-reference to +mentioner+.
def create_cross_reference_note(noteable, mentioner, author, project)
- create({
- noteable: noteable,
- commit_id: (noteable.sha if noteable.respond_to? :sha),
+ note_options = {
project: project,
author: author,
note: "_mentioned in #{mentioner.gfm_reference}_",
system: true
- }, without_protection: true)
+ }
+
+ if noteable.kind_of?(Commit)
+ note_options.merge!(noteable_type: 'Commit', commit_id: noteable.id)
+ else
+ note_options.merge!(noteable: noteable)
+ end
+
+ create(note_options, without_protection: true)
end
def create_assignee_change_note(noteable, project, author, assignee)
@@ -123,8 +129,8 @@ class Note < ActiveRecord::Base
def commit_author
@commit_author ||=
- project.users.find_by_email(noteable.author_email) ||
- project.users.find_by_name(noteable.author_name)
+ project.users.find_by(email: noteable.author_email) ||
+ project.users.find_by(name: noteable.author_name)
rescue
nil
end
diff --git a/app/models/notification.rb b/app/models/notification.rb
index ff6a18d6a51..b0f8ed6a4ec 100644
--- a/app/models/notification.rb
+++ b/app/models/notification.rb
@@ -9,12 +9,23 @@ class Notification
attr_accessor :target
- def self.notification_levels
- [N_DISABLED, N_PARTICIPATING, N_WATCH]
- end
-
- def self.project_notification_levels
- [N_DISABLED, N_PARTICIPATING, N_WATCH, N_GLOBAL]
+ class << self
+ def notification_levels
+ [N_DISABLED, N_PARTICIPATING, N_WATCH]
+ end
+
+ def options_with_labels
+ {
+ disabled: N_DISABLED,
+ participating: N_PARTICIPATING,
+ watch: N_WATCH,
+ global: N_GLOBAL
+ }
+ end
+
+ def project_notification_levels
+ [N_DISABLED, N_PARTICIPATING, N_WATCH, N_GLOBAL]
+ end
end
def initialize(target)
@@ -36,4 +47,8 @@ class Notification
def global?
target.notification_level == N_GLOBAL
end
+
+ def level
+ target.notification_level
+ end
end
diff --git a/app/models/project.rb b/app/models/project.rb
index a55f7a65b0b..47dc8a1fdb0 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -28,6 +28,9 @@ class Project < ActiveRecord::Base
include Gitlab::VisibilityLevel
extend Enumerize
+ default_value_for :imported, false
+ default_value_for :archived, false
+
ActsAsTaggableOn.strict_case_match = true
attr_accessible :name, :path, :description, :issues_tracker, :label_list,
@@ -53,6 +56,7 @@ class Project < ActiveRecord::Base
has_one :hipchat_service, dependent: :destroy
has_one :flowdock_service, dependent: :destroy
has_one :assembla_service, dependent: :destroy
+ has_one :gemnasium_service, dependent: :destroy
has_one :forked_project_link, dependent: :destroy, foreign_key: "forked_to_project_id"
has_one :forked_from_project, through: :forked_project_link
@@ -114,18 +118,35 @@ class Project < ActiveRecord::Base
scope :sorted_by_activity, -> { reorder("projects.last_activity_at DESC") }
scope :personal, ->(user) { where(namespace_id: user.namespace_id) }
scope :joined, ->(user) { where("namespace_id != ?", user.namespace_id) }
- scope :public_only, -> { where(visibility_level: PUBLIC) }
- scope :public_or_internal_only, ->(user) { where("visibility_level IN (:levels)", levels: user ? [ INTERNAL, PUBLIC ] : [ PUBLIC ]) }
+
+ scope :public_only, -> { where(visibility_level: Project::PUBLIC) }
+ scope :public_and_internal_only, -> { where(visibility_level: Project.public_and_internal_levels) }
scope :non_archived, -> { where(archived: false) }
enumerize :issues_tracker, in: (Gitlab.config.issues_tracker.keys).append(:gitlab), default: :gitlab
class << self
+ def public_and_internal_levels
+ [Project::PUBLIC, Project::INTERNAL]
+ end
+
def abandoned
where('projects.last_activity_at < ?', 6.months.ago)
end
+ def publicish(user)
+ visibility_levels = [Project::PUBLIC]
+ visibility_levels += [Project::INTERNAL] if user
+ where(visibility_level: visibility_levels)
+ end
+
+ def accessible_to(user)
+ accessible_ids = publicish(user).pluck(:id)
+ accessible_ids += user.authorized_projects.pluck(:id) if user
+ where(id: accessible_ids)
+ end
+
def with_push
includes(:events).where('events.action = ?', Event::PUSHED)
end
@@ -138,13 +159,17 @@ class Project < ActiveRecord::Base
joins(:namespace).where("projects.archived = ?", false).where("projects.name LIKE :query OR projects.path LIKE :query OR namespaces.name LIKE :query OR projects.description LIKE :query", query: "%#{query}%")
end
+ def search_by_title query
+ where("projects.archived = ?", false).where("LOWER(projects.name) LIKE :query", query: "%#{query.downcase}%")
+ end
+
def find_with_namespace(id)
if id.include?("/")
id = id.split("/")
- namespace = Namespace.find_by_path(id.first)
+ namespace = Namespace.find_by(path: id.first)
return nil unless namespace
- where(namespace_id: namespace.id).find_by_path(id.second)
+ where(namespace_id: namespace.id).find_by(path: id.second)
else
where(path: id, namespace_id: nil).last
end
@@ -201,6 +226,10 @@ class Project < ActiveRecord::Base
[Gitlab.config.gitlab.url, path_with_namespace].join("/")
end
+ def web_url_without_protocol
+ web_url.split("://")[1]
+ end
+
def build_commit_note(commit)
notes.new(commit_id: commit.id, noteable_type: "Commit")
end
@@ -248,7 +277,7 @@ class Project < ActiveRecord::Base
end
def available_services_names
- %w(gitlab_ci campfire hipchat pivotaltracker flowdock assembla emails_on_push)
+ %w(gitlab_ci campfire hipchat pivotaltracker flowdock assembla emails_on_push gemnasium)
end
def gitlab_ci?
@@ -270,9 +299,7 @@ class Project < ActiveRecord::Base
end
def send_move_instructions
- team.members.each do |user|
- Notify.delay.project_was_moved_email(self.id, user.id)
- end
+ NotificationService.new.project_was_moved(self)
end
def owner
@@ -290,7 +317,7 @@ class Project < ActiveRecord::Base
# Get Team Member record by user id
def team_member_by_id(user_id)
- users_projects.find_by_user_id(user_id)
+ users_projects.find_by(user_id: user_id)
end
def name_with_namespace
@@ -344,7 +371,7 @@ class Project < ActiveRecord::Base
# Close merge requests
mrs = self.merge_requests.opened.where(target_branch: branch_name).to_a
mrs = mrs.select(&:last_commit).select { |mr| c_ids.include?(mr.last_commit.id) }
- mrs.each { |merge_request| merge_request.merge!(user.id) }
+ mrs.each { |merge_request| MergeRequests::MergeService.new.execute(merge_request, user, nil) }
true
end
diff --git a/app/models/project_services/assembla_service.rb b/app/models/project_services/assembla_service.rb
index 66ecf394784..2a2c5172916 100644
--- a/app/models/project_services/assembla_service.rb
+++ b/app/models/project_services/assembla_service.rb
@@ -13,9 +13,12 @@
# project_url :string(255)
# subdomain :string(255)
# room :string(255)
+# api_key :string(255)
#
class AssemblaService < Service
+ attr_accessible :subdomain
+
include HTTParty
validates :token, presence: true, if: :activated?
@@ -34,12 +37,13 @@ class AssemblaService < Service
def fields
[
- { type: 'text', name: 'token', placeholder: '' }
+ { type: 'text', name: 'token', placeholder: '' },
+ { type: 'text', name: 'subdomain', placeholder: '' }
]
end
def execute(push)
- url = "https://atlas.assembla.com/spaces/ouposp/github_tool?secret_key=#{token}"
+ url = "https://atlas.assembla.com/spaces/#{subdomain}/github_tool?secret_key=#{token}"
AssemblaService.post(url, body: { payload: push }.to_json, headers: { 'Content-Type' => 'application/json' })
end
end
diff --git a/app/models/project_services/campfire_service.rb b/app/models/project_services/campfire_service.rb
index fb2a49fd586..f9247e054c7 100644
--- a/app/models/project_services/campfire_service.rb
+++ b/app/models/project_services/campfire_service.rb
@@ -13,6 +13,7 @@
# project_url :string(255)
# subdomain :string(255)
# room :string(255)
+# api_key :string(255)
#
class CampfireService < Service
diff --git a/app/models/project_services/emails_on_push_service.rb b/app/models/project_services/emails_on_push_service.rb
index 2a46eff7846..0a453166342 100644
--- a/app/models/project_services/emails_on_push_service.rb
+++ b/app/models/project_services/emails_on_push_service.rb
@@ -13,6 +13,7 @@
# project_url :string(255)
# subdomain :string(255)
# room :string(255)
+# api_key :string(255)
#
class EmailsOnPushService < Service
diff --git a/app/models/project_services/flowdock_service.rb b/app/models/project_services/flowdock_service.rb
index f72d9fa9015..2603a1f67a4 100644
--- a/app/models/project_services/flowdock_service.rb
+++ b/app/models/project_services/flowdock_service.rb
@@ -13,6 +13,7 @@
# project_url :string(255)
# subdomain :string(255)
# room :string(255)
+# api_key :string(255)
#
require "flowdock-git-hook"
diff --git a/app/models/project_services/gemnasium_service.rb b/app/models/project_services/gemnasium_service.rb
new file mode 100644
index 00000000000..0b8e7bad353
--- /dev/null
+++ b/app/models/project_services/gemnasium_service.rb
@@ -0,0 +1,54 @@
+# == Schema Information
+#
+# Table name: services
+#
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# token :string(255)
+# project_id :integer not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# active :boolean default(FALSE), not null
+# project_url :string(255)
+# subdomain :string(255)
+# room :string(255)
+# api_key :string(255)
+#
+
+require "gemnasium/gitlab_service"
+
+class GemnasiumService < Service
+ validates :token, :api_key, presence: true, if: :activated?
+
+ def title
+ 'Gemnasium'
+ end
+
+ def description
+ 'Gemnasium monitors your project dependencies and alerts you about updates and security vulnerabilities.'
+ end
+
+ def to_param
+ 'gemnasium'
+ end
+
+ def fields
+ [
+ { type: 'text', name: 'api_key', placeholder: 'Your personal API KEY on gemnasium.com ' },
+ { type: 'text', name: 'token', placeholder: 'The project\'s slug on gemnasium.com' }
+ ]
+ end
+
+ def execute(push_data)
+ repo_path = File.join(Gitlab.config.gitlab_shell.repos_path, "#{project.path_with_namespace}.git")
+ Gemnasium::GitlabService.execute(
+ ref: push_data[:ref],
+ before: push_data[:before],
+ after: push_data[:after],
+ token: token,
+ api_key: api_key,
+ repo: repo_path
+ )
+ end
+end
diff --git a/app/models/project_services/gitlab_ci_service.rb b/app/models/project_services/gitlab_ci_service.rb
index 7f5380a4551..017cd9eeaab 100644
--- a/app/models/project_services/gitlab_ci_service.rb
+++ b/app/models/project_services/gitlab_ci_service.rb
@@ -13,6 +13,7 @@
# project_url :string(255)
# subdomain :string(255)
# room :string(255)
+# api_key :string(255)
#
class GitlabCiService < Service
diff --git a/app/models/project_services/hipchat_service.rb b/app/models/project_services/hipchat_service.rb
index ea2169fb168..3cee047a32a 100644
--- a/app/models/project_services/hipchat_service.rb
+++ b/app/models/project_services/hipchat_service.rb
@@ -13,6 +13,7 @@
# project_url :string(255)
# subdomain :string(255)
# room :string(255)
+# api_key :string(255)
#
class HipchatService < Service
@@ -40,7 +41,7 @@ class HipchatService < Service
end
def execute(push_data)
- gate[room].send('Gitlab', create_message(push_data))
+ gate[room].send('GitLab', create_message(push_data))
end
private
@@ -61,7 +62,7 @@ class HipchatService < Service
elsif after =~ /000000/
message << "removed branch #{ref} from <a href=\"#{project.web_url}\">#{project.name_with_namespace.gsub!(/\s/,'')}</a> \n"
else
- message << "#pushed to branch <a href=\"#{project.web_url}/commits/#{ref}\">#{ref}</a> "
+ message << "pushed to branch <a href=\"#{project.web_url}/commits/#{ref}\">#{ref}</a> "
message << "of <a href=\"#{project.web_url}\">#{project.name_with_namespace.gsub!(/\s/,'')}</a> "
message << "(<a href=\"#{project.web_url}/compare/#{before}...#{after}\">Compare changes</a>)"
for commit in push[:commits] do
diff --git a/app/models/project_services/pivotaltracker_service.rb b/app/models/project_services/pivotaltracker_service.rb
index c5b1b9ab8d3..877b9a77404 100644
--- a/app/models/project_services/pivotaltracker_service.rb
+++ b/app/models/project_services/pivotaltracker_service.rb
@@ -13,6 +13,7 @@
# project_url :string(255)
# subdomain :string(255)
# room :string(255)
+# api_key :string(255)
#
class PivotaltrackerService < Service
diff --git a/app/models/project_team.rb b/app/models/project_team.rb
index 5630f280aea..eca13e56061 100644
--- a/app/models/project_team.rb
+++ b/app/models/project_team.rb
@@ -22,22 +22,22 @@ class ProjectTeam
end
def find(user_id)
- user = project.users.find_by_id(user_id)
+ user = project.users.find_by(id: user_id)
if group
- user ||= group.users.find_by_id(user_id)
+ user ||= group.users.find_by(id: user_id)
end
user
end
def find_tm(user_id)
- tm = project.users_projects.find_by_user_id(user_id)
+ tm = project.users_projects.find_by(user_id: user_id)
# If user is not in project members
# we should check for group membership
if group && !tm
- tm = group.users_groups.find_by_user_id(user_id)
+ tm = group.users_groups.find_by(user_id: user_id)
end
tm
diff --git a/app/models/repository.rb b/app/models/repository.rb
index 1255b814533..35ec84f1651 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -57,7 +57,7 @@ class Repository
def recent_branches(limit = 20)
branches.sort do |a, b|
- b.commit.committed_date <=> a.commit.committed_date
+ commit(b.target).committed_date <=> commit(a.target).committed_date
end[0..limit]
end
@@ -134,6 +134,7 @@ class Repository
Rails.cache.delete(cache_key(:commit_count))
Rails.cache.delete(cache_key(:graph_log))
Rails.cache.delete(cache_key(:readme))
+ Rails.cache.delete(cache_key(:contribution_guide))
end
def graph_log
@@ -163,7 +164,55 @@ class Repository
def readme
Rails.cache.fetch(cache_key(:readme)) do
- Tree.new(self, self.root_ref).readme
+ tree(:head).readme
end
end
+
+ def contribution_guide
+ Rails.cache.fetch(cache_key(:contribution_guide)) do
+ tree(:head).contribution_guide
+ end
+ end
+
+ def head_commit
+ commit(self.root_ref)
+ end
+
+ def tree(sha = :head, path = nil)
+ if sha == :head
+ sha = head_commit.sha
+ end
+
+ Tree.new(self, sha, path)
+ end
+
+ def blob_at_branch(branch_name, path)
+ last_commit = commit(branch_name)
+
+ if last_commit
+ blob_at(last_commit.sha, path)
+ else
+ nil
+ end
+ end
+
+ # Returns url for submodule
+ #
+ # Ex.
+ # @repository.submodule_url_for('master', 'rack')
+ # # => git@localhost:rack.git
+ #
+ def submodule_url_for(ref, path)
+ if submodules(ref).any?
+ submodule = submodules(ref)[path]
+
+ if submodule
+ submodule['url']
+ end
+ end
+ end
+
+ def last_commit_for_path(sha, path)
+ commits(sha, path, 1).last
+ end
end
diff --git a/app/models/service.rb b/app/models/service.rb
index 540aaad1ce5..f7e440dcc81 100644
--- a/app/models/service.rb
+++ b/app/models/service.rb
@@ -13,12 +13,15 @@
# project_url :string(255)
# subdomain :string(255)
# room :string(255)
+# api_key :string(255)
#
# To add new service you should build a class inherited from Service
# and implement a set of methods
class Service < ActiveRecord::Base
- attr_accessible :title, :token, :type, :active
+ default_value_for :active, false
+
+ attr_accessible :title, :token, :type, :active, :api_key
belongs_to :project
has_one :service_hook
diff --git a/app/models/tree.rb b/app/models/tree.rb
index ed06cb1a128..ac2183be44b 100644
--- a/app/models/tree.rb
+++ b/app/models/tree.rb
@@ -1,5 +1,5 @@
class Tree
- attr_accessor :entries, :readme
+ attr_accessor :entries, :readme, :contribution_guide
def initialize(repository, sha, path = '/')
path = '/' if path.blank?
@@ -10,6 +10,11 @@ class Tree
readme_path = path == '/' ? readme_tree.name : File.join(path, readme_tree.name)
@readme = Gitlab::Git::Blob.find(git_repo, sha, readme_path)
end
+
+ if contribution_tree = @entries.find(&:contributing?)
+ contribution_path = path == '/' ? contribution_tree.name : File.join(path, contribution_tree.name)
+ @contribution_guide = Gitlab::Git::Blob.find(git_repo, sha, contribution_path)
+ end
end
def trees
@@ -23,4 +28,8 @@ class Tree
def submodules
@entries.select(&:submodule?)
end
+
+ def sorted_entries
+ trees + blobs + submodules
+ end
end
diff --git a/app/models/user.rb b/app/models/user.rb
index f2cd554f9c3..855fe58ffe8 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -41,7 +41,8 @@
# confirmed_at :datetime
# confirmation_sent_at :datetime
# unconfirmed_email :string(255)
-# hide_no_ssh_key :boolean default(FALSE), not null
+# hide_no_ssh_key :boolean default(FALSE)
+# website_url :string(255) default(""), not null
#
require 'carrierwave/orm/activerecord'
@@ -52,7 +53,7 @@ class User < ActiveRecord::Base
:recoverable, :rememberable, :trackable, :validatable, :omniauthable, :confirmable, :registerable
attr_accessible :email, :password, :password_confirmation, :remember_me, :bio, :name, :username,
- :skype, :linkedin, :twitter, :color_scheme_id, :theme_id, :force_random_password,
+ :skype, :linkedin, :twitter, :website_url, :color_scheme_id, :theme_id, :force_random_password,
:extern_uid, :provider, :password_expires_at, :avatar, :hide_no_ssh_key,
as: [:default, :admin]
@@ -77,6 +78,7 @@ class User < ActiveRecord::Base
# Profile
has_many :keys, dependent: :destroy
+ has_many :emails, dependent: :destroy
# Groups
has_many :users_groups, dependent: :destroy
@@ -103,11 +105,11 @@ class User < ActiveRecord::Base
# Validations
#
validates :name, presence: true
- validates :email, presence: true, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/ }, uniqueness: true
+ validates :email, presence: true, email: {strict_mode: true}, uniqueness: true
validates :bio, length: { maximum: 255 }, allow_blank: true
validates :extern_uid, allow_blank: true, uniqueness: {scope: :provider}
validates :projects_limit, presence: true, numericality: {greater_than_or_equal_to: 0}
- validates :username, presence: true, uniqueness: true,
+ validates :username, presence: true, uniqueness: { case_sensitive: false },
exclusion: { in: Gitlab::Blacklist.path },
format: { with: Gitlab::Regex.username_regex,
message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" }
@@ -115,6 +117,7 @@ class User < ActiveRecord::Base
validates :notification_level, inclusion: { in: Notification.notification_levels }, presence: true
validate :namespace_uniq, if: ->(user) { user.username_changed? }
validate :avatar_type, if: ->(user) { user.avatar_changed? }
+ validate :unique_email, if: ->(user) { user.email_changed? }
validates :avatar, file_size: { maximum: 100.kilobytes.to_i }
before_validation :generate_password, on: :create
@@ -182,6 +185,13 @@ class User < ActiveRecord::Base
where(conditions).first
end
end
+
+ def find_for_commit(email, name)
+ # Prefer email match over name match
+ User.where(email: email).first ||
+ User.joins(:emails).where(emails: { email: email }).first ||
+ User.where(name: name).first
+ end
def filter filter_name
case filter_name
@@ -238,7 +248,7 @@ class User < ActiveRecord::Base
def namespace_uniq
namespace_name = self.username
- if Namespace.find_by_path(namespace_name)
+ if Namespace.find_by(path: namespace_name)
self.errors.add :username, "already exist"
end
end
@@ -249,6 +259,10 @@ class User < ActiveRecord::Base
end
end
+ def unique_email
+ self.errors.add(:email, 'has already been taken') if Email.exists?(email: self.email)
+ end
+
# Groups user has access to
def authorized_groups
@authorized_groups ||= begin
@@ -382,7 +396,7 @@ class User < ActiveRecord::Base
end
def created_by
- User.find_by_id(created_by_id) if created_by_id
+ User.find_by(id: created_by_id) if created_by_id
end
def sanitize_attrs
@@ -424,4 +438,18 @@ class User < ActiveRecord::Base
order('id DESC').limit(1000).
update_all(updated_at: Time.now)
end
+
+ def full_website_url
+ return "http://#{website_url}" if website_url !~ /^https?:\/\//
+
+ website_url
+ end
+
+ def short_website_url
+ website_url.gsub(/https?:\/\//, '')
+ end
+
+ def all_ssh_keys
+ keys.map(&:key)
+ end
end
diff --git a/app/models/web_hook.rb b/app/models/web_hook.rb
index c0aa3734917..45a795391a2 100644
--- a/app/models/web_hook.rb
+++ b/app/models/web_hook.rb
@@ -17,6 +17,10 @@
class WebHook < ActiveRecord::Base
include HTTParty
+ default_value_for :push_events, true
+ default_value_for :issues_events, false
+ default_value_for :merge_requests_events, false
+
attr_accessible :url
# HTTParty timeout
@@ -28,7 +32,7 @@ class WebHook < ActiveRecord::Base
def execute(data)
parsed_url = URI.parse(url)
if parsed_url.userinfo.blank?
- WebHook.post(url, body: data.to_json, headers: { "Content-Type" => "application/json" })
+ WebHook.post(url, body: data.to_json, headers: { "Content-Type" => "application/json" }, verify: false)
else
post_url = url.gsub("#{parsed_url.userinfo}@", "")
auth = {
@@ -38,6 +42,7 @@ class WebHook < ActiveRecord::Base
WebHook.post(post_url,
body: data.to_json,
headers: {"Content-Type" => "application/json"},
+ verify: false,
basic_auth: auth)
end
end
diff --git a/app/observers/email_observer.rb b/app/observers/email_observer.rb
new file mode 100644
index 00000000000..026ad8b1d9a
--- /dev/null
+++ b/app/observers/email_observer.rb
@@ -0,0 +1,5 @@
+class EmailObserver < BaseObserver
+ def after_create(email)
+ notification.new_email(email)
+ end
+end
diff --git a/app/observers/merge_request_observer.rb b/app/observers/merge_request_observer.rb
index 0ac555fce7c..f2e2d16c943 100644
--- a/app/observers/merge_request_observer.rb
+++ b/app/observers/merge_request_observer.rb
@@ -18,27 +18,12 @@ class MergeRequestObserver < ActivityObserver
execute_hooks(merge_request)
end
- def after_merge(merge_request, transition)
- notification.merge_mr(merge_request)
- # Since MR can be merged via sidekiq
- # to prevent event duplication do this check
- return true if merge_request.merge_event
-
- Event.create(
- project: merge_request.target_project,
- target_id: merge_request.id,
- target_type: merge_request.class.name,
- action: Event::MERGED,
- author_id: merge_request.author_id_of_changes
- )
-
- execute_hooks(merge_request)
- end
-
def after_reopen(merge_request, transition)
create_event(merge_request, Event::REOPENED)
create_note(merge_request)
execute_hooks(merge_request)
+ merge_request.reload_code
+ merge_request.mark_as_unchecked
end
def after_update(merge_request)
diff --git a/app/observers/system_hook_observer.rb b/app/observers/system_hook_observer.rb
index 3a649fd590d..80de177b9a2 100644
--- a/app/observers/system_hook_observer.rb
+++ b/app/observers/system_hook_observer.rb
@@ -2,10 +2,16 @@ class SystemHookObserver < BaseObserver
observe :user, :project, :users_project
def after_create(model)
- SystemHooksService.execute_hooks_for(model, :create)
+ system_hook_service.execute_hooks_for(model, :create)
end
def after_destroy(model)
- SystemHooksService.execute_hooks_for(model, :destroy)
+ system_hook_service.execute_hooks_for(model, :destroy)
+ end
+
+ private
+
+ def system_hook_service
+ SystemHooksService.new
end
end
diff --git a/app/contexts/base_context.rb b/app/services/base_service.rb
index 6accd9b2457..610f0474872 100644
--- a/app/contexts/base_context.rb
+++ b/app/services/base_service.rb
@@ -1,4 +1,4 @@
-class BaseContext
+class BaseService
attr_accessor :project, :current_user, :params
def initialize(project, user, params)
diff --git a/app/contexts/files/base_context.rb b/app/services/files/base_service.rb
index 44f9826652c..f1765d38976 100644
--- a/app/contexts/files/base_context.rb
+++ b/app/services/files/base_service.rb
@@ -1,5 +1,5 @@
module Files
- class BaseContext < ::BaseContext
+ class BaseService < ::BaseService
attr_reader :ref, :path
def initialize(project, user, params, ref, path = nil)
diff --git a/app/contexts/files/create_context.rb b/app/services/files/create_service.rb
index b3d62a028c7..1998fb79e7d 100644
--- a/app/contexts/files/create_context.rb
+++ b/app/services/files/create_service.rb
@@ -1,7 +1,7 @@
-require_relative "base_context"
+require_relative "base_service"
module Files
- class CreateContext < BaseContext
+ class CreateService < BaseService
def execute
allowed = if project.protected_branch?(ref)
can?(current_user, :push_code_to_protected_branches, project)
@@ -24,7 +24,7 @@ module Files
return error("Your changes could not be committed, because file name contains not allowed characters")
end
- blob = repository.blob_at(ref, file_path)
+ blob = repository.blob_at_branch(ref, file_path)
if blob
return error("Your changes could not be committed, because file with such name exists")
@@ -33,7 +33,8 @@ module Files
new_file_action = Gitlab::Satellite::NewFileAction.new(current_user, project, ref, file_path)
created_successfully = new_file_action.commit!(
params[:content],
- params[:commit_message]
+ params[:commit_message],
+ params[:encoding]
)
if created_successfully
diff --git a/app/contexts/files/delete_context.rb b/app/services/files/delete_service.rb
index 39ff7c2a4b1..ff5dc6ef34c 100644
--- a/app/contexts/files/delete_context.rb
+++ b/app/services/files/delete_service.rb
@@ -1,7 +1,7 @@
-require_relative "base_context"
+require_relative "base_service"
module Files
- class DeleteContext < BaseContext
+ class DeleteService < BaseService
def execute
allowed = if project.protected_branch?(ref)
can?(current_user, :push_code_to_protected_branches, project)
@@ -17,7 +17,7 @@ module Files
return error("You can only create files if you are on top of a branch")
end
- blob = repository.blob_at(ref, path)
+ blob = repository.blob_at_branch(ref, path)
unless blob
return error("You can only edit text files")
diff --git a/app/contexts/files/update_context.rb b/app/services/files/update_service.rb
index 556027a3256..c631f28749c 100644
--- a/app/contexts/files/update_context.rb
+++ b/app/services/files/update_service.rb
@@ -1,7 +1,7 @@
-require_relative "base_context"
+require_relative "base_service"
module Files
- class UpdateContext < BaseContext
+ class UpdateService < BaseService
def execute
allowed = if project.protected_branch?(ref)
can?(current_user, :push_code_to_protected_branches, project)
@@ -17,16 +17,17 @@ module Files
return error("You can only create files if you are on top of a branch")
end
- blob = repository.blob_at(ref, path)
+ blob = repository.blob_at_branch(ref, path)
unless blob
return error("You can only edit text files")
end
- new_file_action = Gitlab::Satellite::EditFileAction.new(current_user, project, ref, path)
- created_successfully = new_file_action.commit!(
+ edit_file_action = Gitlab::Satellite::EditFileAction.new(current_user, project, ref, path)
+ created_successfully = edit_file_action.commit!(
params[:content],
- params[:commit_message]
+ params[:commit_message],
+ params[:encoding]
)
if created_successfully
diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb
index e54f88e42de..fcc03c3e4b8 100644
--- a/app/services/git_push_service.rb
+++ b/app/services/git_push_service.rb
@@ -188,8 +188,6 @@ class GitPushService
end
def commit_user commit
- User.where(email: commit.author_email).first ||
- User.where(name: commit.author_name).first ||
- user
+ User.find_for_commit(commit.author_email, commit.author_name) || user
end
end
diff --git a/app/contexts/issues/bulk_update_context.rb b/app/services/issues/bulk_update_service.rb
index ab38a4f8ab5..f72a346af6f 100644
--- a/app/contexts/issues/bulk_update_context.rb
+++ b/app/services/issues/bulk_update_service.rb
@@ -1,5 +1,5 @@
module Issues
- class BulkUpdateContext < BaseContext
+ class BulkUpdateService < BaseService
def execute
update_data = params[:update]
diff --git a/app/services/merge_requests/auto_merge_service.rb b/app/services/merge_requests/auto_merge_service.rb
new file mode 100644
index 00000000000..d60d61ed54a
--- /dev/null
+++ b/app/services/merge_requests/auto_merge_service.rb
@@ -0,0 +1,30 @@
+module MergeRequests
+ # AutoMergeService class
+ #
+ # Do git merge in satellite and in case of success
+ # mark merge request as merged and execute all hooks and notifications
+ # Called when you do merge via GitLab UI
+ class AutoMergeService < BaseMergeService
+ def execute(merge_request, current_user, commit_message)
+ merge_request.lock
+
+ if Gitlab::Satellite::MergeAction.new(current_user, merge_request).merge!(commit_message)
+ merge_request.author_id_of_changes = current_user.id
+ merge_request.merge
+
+ notification.merge_mr(merge_request)
+ create_merge_event(merge_request)
+ execute_project_hooks(merge_request)
+
+ true
+ else
+ merge_request.unlock
+ false
+ end
+ rescue
+ merge_request.unlock if merge_request.locked?
+ merge_request.mark_as_unmergeable
+ false
+ end
+ end
+end
diff --git a/app/services/merge_requests/base_merge_service.rb b/app/services/merge_requests/base_merge_service.rb
new file mode 100644
index 00000000000..dbdb0063074
--- /dev/null
+++ b/app/services/merge_requests/base_merge_service.rb
@@ -0,0 +1,26 @@
+module MergeRequests
+ class BaseMergeService
+
+ private
+
+ def notification
+ NotificationService.new
+ end
+
+ def create_merge_event(merge_request)
+ Event.create(
+ project: merge_request.target_project,
+ target_id: merge_request.id,
+ target_type: merge_request.class.name,
+ action: Event::MERGED,
+ author_id: merge_request.author_id_of_changes
+ )
+ end
+
+ def execute_project_hooks(merge_request)
+ if merge_request.project
+ merge_request.project.execute_hooks(merge_request.to_hook_data, :merge_request_hooks)
+ end
+ end
+ end
+end
diff --git a/app/services/merge_requests/merge_service.rb b/app/services/merge_requests/merge_service.rb
new file mode 100644
index 00000000000..1d5af04cdbb
--- /dev/null
+++ b/app/services/merge_requests/merge_service.rb
@@ -0,0 +1,22 @@
+module MergeRequests
+ # MergeService class
+ #
+ # Mark existing merge request as merged
+ # and execute all hooks and notifications
+ # Called when you do merge via command line and push code
+ # to target branch
+ class MergeService < BaseMergeService
+ def execute(merge_request, current_user, commit_message)
+ merge_request.author_id_of_changes = current_user.id
+ merge_request.merge
+
+ notification.merge_mr(merge_request)
+ create_merge_event(merge_request)
+ execute_project_hooks(merge_request)
+
+ true
+ rescue
+ false
+ end
+ end
+end
diff --git a/app/contexts/notes/create_context.rb b/app/services/notes/create_service.rb
index 36ea76ff949..ff6dfb61139 100644
--- a/app/contexts/notes/create_context.rb
+++ b/app/services/notes/create_service.rb
@@ -1,8 +1,9 @@
module Notes
- class CreateContext < BaseContext
+ class CreateService < BaseService
def execute
note = project.notes.new(params[:note])
note.author = current_user
+ note.system = false
note.save
note
end
diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb
index eb42cac3f83..5daf573630d 100644
--- a/app/services/notification_service.rb
+++ b/app/services/notification_service.rb
@@ -17,6 +17,13 @@ class NotificationService
end
end
+ # Always notify user about email added to profile
+ def new_email(email)
+ if email.user
+ mailer.new_email_email(email.id)
+ end
+ end
+
# When create an issue we should send next emails:
#
# * issue assignee if their notification level is not Disabled
@@ -157,6 +164,15 @@ class NotificationService
mailer.group_access_granted_email(users_group.id)
end
+ def project_was_moved(project)
+ recipients = project.team.members
+ recipients = reject_muted_users(recipients, project)
+
+ recipients.each do |recipient|
+ mailer.project_was_moved_email(project.id, recipient.id)
+ end
+ end
+
protected
# Get project users with WATCH notification level
@@ -186,10 +202,10 @@ class NotificationService
users.reject do |user|
next user.notification.disabled? unless project
- tm = project.users_projects.find_by_user_id(user.id)
+ tm = project.users_projects.find_by(user_id: user.id)
if !tm && project.group
- tm = project.group.users_groups.find_by_user_id(user.id)
+ tm = project.group.users_groups.find_by(user_id: user.id)
end
# reject users who globally disabled notification and has no membership
@@ -241,7 +257,7 @@ class NotificationService
recipients.delete(current_user)
recipients.each do |recipient|
- mailer.send(method, recipient.id, target.id, target.assignee_id_was)
+ mailer.send(method, recipient.id, target.id, target.assignee_id_was, current_user.id)
end
end
diff --git a/app/contexts/projects/create_context.rb b/app/services/projects/create_service.rb
index 2acb9fbfe14..ba131d8ffbe 100644
--- a/app/contexts/projects/create_context.rb
+++ b/app/services/projects/create_service.rb
@@ -1,5 +1,5 @@
module Projects
- class CreateContext < BaseContext
+ class CreateService < BaseService
def initialize(user, params)
@current_user, @params = user, params.dup
end
@@ -73,7 +73,7 @@ module Projects
end
def allowed_namespace?(user, namespace_id)
- namespace = Namespace.find_by_id(namespace_id)
+ namespace = Namespace.find_by(id: namespace_id)
current_user.can?(:manage_namespace, namespace)
end
end
diff --git a/app/contexts/projects/fork_context.rb b/app/services/projects/fork_service.rb
index fbc67220d5d..2f1c7b18aa0 100644
--- a/app/contexts/projects/fork_context.rb
+++ b/app/services/projects/fork_service.rb
@@ -1,5 +1,5 @@
module Projects
- class ForkContext < BaseContext
+ class ForkService < BaseService
include Gitlab::ShellAdapter
def initialize(project, user)
diff --git a/app/contexts/projects/transfer_context.rb b/app/services/projects/transfer_service.rb
index 3011984e3f8..f8e27f6f1c6 100644
--- a/app/contexts/projects/transfer_context.rb
+++ b/app/services/projects/transfer_service.rb
@@ -1,5 +1,5 @@
module Projects
- class TransferContext < BaseContext
+ class TransferService < BaseService
def execute(role = :default)
namespace_id = params[:project].delete(:namespace_id)
allowed_transfer = can?(current_user, :change_namespace, project) || role == :admin
diff --git a/app/contexts/projects/update_context.rb b/app/services/projects/update_service.rb
index 94de10de0f6..d9d371da5c4 100644
--- a/app/contexts/projects/update_context.rb
+++ b/app/services/projects/update_service.rb
@@ -1,5 +1,5 @@
module Projects
- class UpdateContext < BaseContext
+ class UpdateService < BaseService
def execute(role = :default)
params[:project].delete(:namespace_id)
# check that user is allowed to set specified visibility_level
diff --git a/app/contexts/search/global_context.rb b/app/services/search/global_service.rb
index 74e746018e6..09c7cb25dd5 100644
--- a/app/contexts/search/global_context.rb
+++ b/app/services/search/global_service.rb
@@ -1,5 +1,5 @@
module Search
- class GlobalContext
+ class GlobalService
attr_accessor :current_user, :params
def initialize(user, params)
@@ -11,12 +11,8 @@ module Search
query = Shellwords.shellescape(query) if query.present?
return result unless query.present?
- authorized_projects_ids = []
- authorized_projects_ids += current_user.authorized_projects.pluck(:id) if current_user
- authorized_projects_ids += Project.public_or_internal_only(current_user).pluck(:id)
-
- group = Group.find_by_id(params[:group_id]) if params[:group_id].present?
- projects = Project.where(id: authorized_projects_ids)
+ group = Group.find_by(id: params[:group_id]) if params[:group_id].present?
+ projects = Project.accessible_to(current_user)
projects = projects.where(namespace_id: group.id) if group
projects = projects.search(query)
project_ids = projects.pluck(:id)
diff --git a/app/contexts/search/project_context.rb b/app/services/search/project_service.rb
index 690652b2cdb..3ebaafc752c 100644
--- a/app/contexts/search/project_context.rb
+++ b/app/services/search/project_service.rb
@@ -1,5 +1,5 @@
module Search
- class ProjectContext
+ class ProjectService
attr_accessor :project, :current_user, :params
def initialize(project, user, params)
diff --git a/app/services/system_hooks_service.rb b/app/services/system_hooks_service.rb
index de4fa9b79e7..4969198b8c2 100644
--- a/app/services/system_hooks_service.rb
+++ b/app/services/system_hooks_service.rb
@@ -1,21 +1,21 @@
class SystemHooksService
- def self.execute_hooks_for(model, event)
+ def execute_hooks_for(model, event)
execute_hooks(build_event_data(model, event))
end
private
- def self.execute_hooks(data)
+ def execute_hooks(data)
SystemHook.all.each do |sh|
async_execute_hook sh, data
end
end
- def self.async_execute_hook(hook, data)
+ def async_execute_hook(hook, data)
Sidekiq::Client.enqueue(SystemHookWorker, hook.id, data)
end
- def self.build_event_data(model, event)
+ def build_event_data(model, event)
data = {
event_name: build_event_name(model, event),
created_at: model.created_at
@@ -51,7 +51,7 @@ class SystemHooksService
end
end
- def self.build_event_name(model, event)
+ def build_event_name(model, event)
case model
when UsersProject
return "user_add_to_team" if event == :create
diff --git a/app/services/test_hook_service.rb b/app/services/test_hook_service.rb
new file mode 100644
index 00000000000..17d86a7a274
--- /dev/null
+++ b/app/services/test_hook_service.rb
@@ -0,0 +1,6 @@
+class TestHookService
+ def execute(hook, current_user)
+ data = GitPushService.new.sample_data(hook.project, current_user)
+ hook.execute(data)
+ end
+end
diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml
index dd663945ea9..bbd60bc6224 100644
--- a/app/views/admin/dashboard/index.html.haml
+++ b/app/views/admin/dashboard/index.html.haml
@@ -3,136 +3,137 @@
%p.light
You can manage projects, users and other GitLab data from here.
%hr
-.admin_dash.row
- .col-sm-4
- .light-well
- %h4 Projects
- .data
- = link_to admin_projects_path do
- %h1= Project.count
- %hr
- = link_to 'New Project', new_project_path, class: "btn btn-new"
- .col-sm-4
- .light-well
- %h4 Users
- .data
- = link_to admin_users_path do
- %h1= User.count
- %hr
- = link_to 'New User', new_admin_user_path, class: "btn btn-new"
- .col-sm-4
- .light-well
- %h4 Groups
- .data
- = link_to admin_groups_path do
- %h1= Group.count
- %hr
- = link_to 'New Group', new_admin_group_path, class: "btn btn-new"
+.admin-dashboard
+ .row
+ .col-sm-4
+ .light-well
+ %h4 Projects
+ .data
+ = link_to admin_projects_path do
+ %h1= Project.count
+ %hr
+ = link_to 'New Project', new_project_path, class: "btn btn-new"
+ .col-sm-4
+ .light-well
+ %h4 Users
+ .data
+ = link_to admin_users_path do
+ %h1= User.count
+ %hr
+ = link_to 'New User', new_admin_user_path, class: "btn btn-new"
+ .col-sm-4
+ .light-well
+ %h4 Groups
+ .data
+ = link_to admin_groups_path do
+ %h1= Group.count
+ %hr
+ = link_to 'New Group', new_admin_group_path, class: "btn btn-new"
-.row.prepend-top-10
- .col-md-4
- %h4 Latest projects
- %hr
- - @projects.each do |project|
+ .row.prepend-top-10
+ .col-md-4
+ %h4 Latest projects
+ %hr
+ - @projects.each do |project|
+ %p
+ = link_to project.name_with_namespace, [:admin, project], class: 'str-truncated'
+ %span.light.pull-right
+ #{time_ago_with_tooltip(project.created_at)}
+
+ .col-md-4
+ %h4 Latest users
+ %hr
+ - @users.each do |user|
+ %p
+ = link_to [:admin, user], class: 'str-truncated' do
+ = user.name
+ %span.light.pull-right
+ #{time_ago_with_tooltip(user.created_at)}
+
+ .col-md-4
+ %h4 Latest groups
+ %hr
+ - @groups.each do |group|
+ %p
+ = link_to [:admin, group], class: 'str-truncated' do
+ = group.name
+ %span.light.pull-right
+ #{time_ago_with_tooltip(group.created_at)}
+
+ %br
+ .row
+ .col-md-4
+ %h4 Stats
+ %hr
%p
- = link_to project.name_with_namespace, [:admin, project]
+ Forks
%span.light.pull-right
- #{time_ago_with_tooltip(project.created_at)}
-
- .col-md-4
- %h4 Latest users
- %hr
- - @users.each do |user|
+ = ForkedProjectLink.count
%p
- = link_to [:admin, user] do
- = user.name
+ Issues
%span.light.pull-right
- #{time_ago_with_tooltip(user.created_at)}
-
- .col-md-4
- %h4 Latest groups
- %hr
- - @groups.each do |group|
+ = Issue.count
%p
- = link_to [:admin, group] do
- = group.name
+ Merge Requests
%span.light.pull-right
- #{time_ago_with_tooltip(group.created_at)}
-
-%br
-.row
- .col-md-4
- %h4 Stats
- %hr
- %p
- Forks
- %span.light.pull-right
- = ForkedProjectLink.count
- %p
- Issues
- %span.light.pull-right
- = Issue.count
- %p
- Merge Requests
- %span.light.pull-right
- = MergeRequest.count
- %p
- Notes
- %span.light.pull-right
- = Note.count
- %p
- Snippets
- %span.light.pull-right
- = Snippet.count
- %p
- SSH Keys
- %span.light.pull-right
- = Key.count
- %p
- Milestones
- %span.light.pull-right
- = Milestone.count
- .col-md-4
- %h4
- Features
- %hr
- %p
- Sign up
- %span.light.pull-right
- = boolean_to_icon gitlab_config.signup_enabled
- %p
- LDAP
- %span.light.pull-right
- = boolean_to_icon Gitlab.config.ldap.enabled
- %p
- Gravatar
- %span.light.pull-right
- = boolean_to_icon Gitlab.config.gravatar.enabled
- %p
- OmniAuth
- %span.light.pull-right
- = boolean_to_icon Gitlab.config.omniauth.enabled
- .col-md-4
- %h4 Components
- %hr
- %p
- GitLab
- %span.pull-right
- = Gitlab::VERSION
- %p
- GitLab Shell
- %span.pull-right
- = Gitlab::Shell.new.version
- %p
- GitLab API
- %span.pull-right
- = API::API::version
- %p
- Ruby
- %span.pull-right
- #{RUBY_VERSION}p#{RUBY_PATCHLEVEL}
+ = MergeRequest.count
+ %p
+ Notes
+ %span.light.pull-right
+ = Note.count
+ %p
+ Snippets
+ %span.light.pull-right
+ = Snippet.count
+ %p
+ SSH Keys
+ %span.light.pull-right
+ = Key.count
+ %p
+ Milestones
+ %span.light.pull-right
+ = Milestone.count
+ .col-md-4
+ %h4
+ Features
+ %hr
+ %p
+ Sign up
+ %span.light.pull-right
+ = boolean_to_icon gitlab_config.signup_enabled
+ %p
+ LDAP
+ %span.light.pull-right
+ = boolean_to_icon Gitlab.config.ldap.enabled
+ %p
+ Gravatar
+ %span.light.pull-right
+ = boolean_to_icon Gitlab.config.gravatar.enabled
+ %p
+ OmniAuth
+ %span.light.pull-right
+ = boolean_to_icon Gitlab.config.omniauth.enabled
+ .col-md-4
+ %h4 Components
+ %hr
+ %p
+ GitLab
+ %span.pull-right
+ = Gitlab::VERSION
+ %p
+ GitLab Shell
+ %span.pull-right
+ = Gitlab::Shell.new.version
+ %p
+ GitLab API
+ %span.pull-right
+ = API::API::version
+ %p
+ Ruby
+ %span.pull-right
+ #{RUBY_VERSION}p#{RUBY_PATCHLEVEL}
- %p
- Rails
- %span.pull-right
- #{Rails::VERSION::STRING}
+ %p
+ Rails
+ %span.pull-right
+ #{Rails::VERSION::STRING}
diff --git a/app/views/admin/groups/index.html.haml b/app/views/admin/groups/index.html.haml
index 7a373ee586c..9a0d5967927 100644
--- a/app/views/admin/groups/index.html.haml
+++ b/app/views/admin/groups/index.html.haml
@@ -1,11 +1,12 @@
%h3.page-title
Groups (#{@groups.total_count})
- %small
- allows you to keep projects organized.
- Use groups for uniting related projects.
-
= link_to 'New Group', new_admin_group_path, class: "btn btn-new pull-right"
-%br
+
+%p.light
+ Group allows you to keep projects organized.
+ Use groups for uniting related projects.
+
+%hr
= form_tag admin_groups_path, method: :get, class: 'form-inline' do
.form-group
= text_field_tag :name, params[:name], class: "form-control input-mn-300"
@@ -23,24 +24,18 @@
%h4
= link_to [:admin, group] do
+ %i.icon-folder-close
= group.name
&rarr;
%span.monospace
- %i.icon-folder-close
%strong #{group.path}/
-
- .clearfix.light.append-bottom-10
- %span
- %b Members:
- %span.badge= group.members.size
- \|
- %span
- %b Projects:
- %span.badge= group.projects.count
-
.clearfix
%p
= truncate group.description, length: 150
+ .clearfix
+ %p.light
+ #{pluralize(group.members.size, 'member')}, #{pluralize(group.projects.count, 'project')}
+
= paginate @groups, theme: "gitlab"
diff --git a/app/views/admin/hooks/_data_ex.html.erb b/app/views/admin/hooks/_data_ex.html.erb
deleted file mode 100644
index 5b16dfb398a..00000000000
--- a/app/views/admin/hooks/_data_ex.html.erb
+++ /dev/null
@@ -1,71 +0,0 @@
-<% data_ex_str = <<eos
-1. Project created:
-{
- "created_at": "2012-07-21T07:30:54Z",
- "event_name": "project_create",
- "name": "StoreCloud",
- "owner_email": "johnsmith@gmail.com"
- "owner_name": "John Smit",
- "path": "stormcloud",
- "path_with_namespace": "jsmith/stormcloud",
- "project_id": 74,
-}
-
-2. Project destroyed:
-{
- "created_at": "2012-07-21T07:30:58Z",
- "event_name": "project_destroy",
- "name": "Underscore",
- "owner_email": "johnsmith@gmail.com"
- "owner_name": "John Smith",
- "path": "underscore",
- "path_with_namespace": "jsmith/underscore",
- "project_id": 73,
-}
-
-3. New Team Member:
-{
- "created_at": "2012-07-21T07:30:56Z",
- "event_name": "user_add_to_team",
- "project_access": "Master",
- "project_id": 74,
- "project_name": "StoreCloud",
- "project_path": "storecloud",
- "user_email": "johnsmith@gmail.com",
- "user_name": "John Smith",
-}
-
-4. Team Member Removed:
-{
- "created_at": "2012-07-21T07:30:56Z",
- "event_name": "user_remove_from_team",
- "project_access": "Master",
- "project_id": 74,
- "project_name": "StoreCloud",
- "project_path": "storecloud",
- "user_email": "johnsmith@gmail.com",
- "user_name": "John Smith",
-}
-
-5. User created:
-{
- "created_at": "2012-07-21T07:44:07Z",
- "email": "js@gitlabhq.com",
- "event_name": "user_create",
- "name": "John Smith",
- "user_id": 41
-}
-
-6. User removed:
-{
- "created_at": "2012-07-21T07:44:07Z",
- "email": "js@gitlabhq.com",
- "event_name": "user_destroy",
- "name": "John Smith",
- "user_id": 41
-}
-
-eos
-%>
-<% js_lexer = Pygments::Lexer[:js] %>
-<%= raw js_lexer.highlight(data_ex_str) %>
diff --git a/app/views/admin/projects/index.html.haml b/app/views/admin/projects/index.html.haml
index 940a539d5e1..5f19d21f106 100644
--- a/app/views/admin/projects/index.html.haml
+++ b/app/views/admin/projects/index.html.haml
@@ -53,5 +53,5 @@
= link_to 'Edit', edit_project_path(project), id: "edit_#{dom_id(project)}", class: "btn btn-small"
= link_to 'Destroy', [project], data: { confirm: remove_project_message(project) }, method: :delete, class: "btn btn-small btn-remove"
- if @projects.blank?
- %p.nothing_here_message 0 projects matches
+ .nothing-here-block 0 projects matches
= paginate @projects, theme: "gitlab"
diff --git a/app/views/admin/users/_form.html.haml b/app/views/admin/users/_form.html.haml
index 98bf65bc420..881a043f36f 100644
--- a/app/views/admin/users/_form.html.haml
+++ b/app/views/admin/users/_form.html.haml
@@ -80,6 +80,9 @@
.form-group
= f.label :twitter, class: 'control-label'
.col-sm-10= f.text_field :twitter, class: 'form-control'
+ .form-group
+ = f.label :website_url, 'Website', class: 'control-label'
+ .col-sm-10= f.text_field :website_url, class: 'form-control'
.form-actions
- if @user.new_record?
diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml
index 1fa6fdfaff1..0b3934a712d 100644
--- a/app/views/admin/users/index.html.haml
+++ b/app/views/admin/users/index.html.haml
@@ -1,12 +1,6 @@
.row
.col-md-3
.admin-filter
- = form_tag admin_users_path, method: :get, class: 'form-inline' do
- .append-bottom-10
- .form-group
- = search_field_tag :name, params[:name], placeholder: 'Name, email or username', class: 'form-control'
- = button_tag type: 'submit', class: 'btn btn-primary' do
- %i.icon-search
%ul.nav.nav-pills.nav-stacked
%li{class: "#{'active' unless params[:filter]}"}
= link_to admin_users_path do
@@ -25,6 +19,12 @@
Without projects
%small.pull-right= User.without_projects.count
%hr
+ = form_tag admin_users_path, method: :get, class: 'form-inline' do
+ .form-group
+ = search_field_tag :name, params[:name], placeholder: 'Name, email or username', class: 'form-control'
+ = button_tag type: 'submit', class: 'btn btn-primary' do
+ %i.icon-search
+ %hr
= link_to 'Reset', admin_users_path, class: "btn btn-cancel"
.col-md-9
diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml
index bd276f22221..d66119e2712 100644
--- a/app/views/admin/users/show.html.haml
+++ b/app/views/admin/users/show.html.haml
@@ -7,7 +7,7 @@
%span.cred (Admin)
.pull-right
- = link_to edit_admin_user_path(@user), class: "btn grouped" do
+ = link_to edit_admin_user_path(@user), class: "btn btn-grouped" do
%i.icon-edit
Edit
%hr
@@ -78,7 +78,6 @@
- if @user.blocked?
.alert.alert-info
%h4 This user is blocked
- %br
%p Blocking user has the following effects:
%ul
%li User will not be able to login
@@ -86,11 +85,11 @@
%li User will be removed from joined projects and groups
%li Personal projects will be left
%li Owned groups will be left
+ %br
= link_to 'Unblock user', unblock_admin_user_path(@user), method: :put, class: "btn btn-new", data: { confirm: 'Are you sure?' }
- else
- .alert
+ .alert.alert-warning
%h4 Block this user
- %br
%p Blocking user has the following effects:
%ul
%li User will not be able to login
@@ -98,12 +97,12 @@
%li User will be removed from joined projects and groups
%li Personal projects will be left
%li Owned groups will be left
+ %br
= link_to 'Block user', block_admin_user_path(@user), data: { confirm: 'USER WILL BE BLOCKED! Are you sure?' }, method: :put, class: "btn btn-remove"
.alert.alert-danger
%h4
Remove user
- %br
%p Deleting a user has the following effects:
%ul
%li All user content like authored issues, snippets, comments will be removed
@@ -114,6 +113,7 @@
%li
Next groups with all content will be removed:
%strong #{@user.solo_owned_groups.map(&:name).join(', ')}
+ %br
= link_to 'Remove user', [:admin, @user], data: { confirm: "USER #{@user.name} WILL BE REMOVED! Are you sure?" }, method: :delete, class: "btn btn-remove"
.col-md-6
@@ -150,5 +150,3 @@
- if tm.respond_to? :project
= link_to project_team_member_path(project, @user), data: { confirm: remove_from_project_team_message(project, @user) }, remote: true, method: :delete, class: "btn-tiny btn btn-remove", title: 'Remove user from project' do
%i.icon-remove
-
-
diff --git a/app/views/dashboard/_activities.html.haml b/app/views/dashboard/_activities.html.haml
index 89117726317..fdf96dd6f56 100644
--- a/app/views/dashboard/_activities.html.haml
+++ b/app/views/dashboard/_activities.html.haml
@@ -4,5 +4,6 @@
- if @events.any?
.content_list
- else
- %p.nothing_here_message Projects activity will be displayed here
-.loading.hide
+ .nothing-here-block Projects activity will be displayed here
+
+= spinner
diff --git a/app/views/dashboard/_groups.html.haml b/app/views/dashboard/_groups.html.haml
index d6937ca4813..a6bc946bedc 100644
--- a/app/views/dashboard/_groups.html.haml
+++ b/app/views/dashboard/_groups.html.haml
@@ -10,10 +10,11 @@
- groups.each do |group|
%li.group-row
= link_to group_path(id: group.path), class: dom_class(group) do
+ = image_tag group_icon(group.path), class: "avatar s24"
%span.group-name.filter-title
= truncate(group.name, length: 35)
%span.arrow
%i.icon-angle-right
- if groups.blank?
%li
- %h3.nothing_here_message You have no groups yet.
+ .nothing-here-block You have no groups yet.
diff --git a/app/views/dashboard/_projects.html.haml b/app/views/dashboard/_projects.html.haml
index 8313cc07b5e..44c7a4b8c80 100644
--- a/app/views/dashboard/_projects.html.haml
+++ b/app/views/dashboard/_projects.html.haml
@@ -14,7 +14,7 @@
- if projects.blank?
%li
- %h3.nothing_here_message There are no projects here.
+ .nothing-here-block There are no projects here.
- if @projects_count > @projects_limit
%li.bottom
%span.light
diff --git a/app/views/dashboard/issues.html.haml b/app/views/dashboard/issues.html.haml
index 19bd4e7bd54..af627588ad9 100644..100755
--- a/app/views/dashboard/issues.html.haml
+++ b/app/views/dashboard/issues.html.haml
@@ -3,7 +3,7 @@
%span.pull-right #{@issues.total_count} issues
%p.light
- List all issues from all project's you have access to.
+ List all issues from all projects you have access to.
%hr
.row
diff --git a/app/views/dashboard/merge_requests.html.haml b/app/views/dashboard/merge_requests.html.haml
index b487a4d6666..550a93e178c 100644..100755
--- a/app/views/dashboard/merge_requests.html.haml
+++ b/app/views/dashboard/merge_requests.html.haml
@@ -4,7 +4,7 @@
%p.light
- List all merge requests from all project's you have access to.
+ List all merge requests from all projects you have access to.
%hr
.row
.col-md-3
diff --git a/app/views/dashboard/projects.html.haml b/app/views/dashboard/projects.html.haml
index 8feef97c732..e1c9a5941e9 100644
--- a/app/views/dashboard/projects.html.haml
+++ b/app/views/dashboard/projects.html.haml
@@ -67,7 +67,7 @@
- if @projects.blank?
%li
- %h3.nothing_here_message There are no projects here.
+ .nothing-here-block There are no projects here.
.bottom
= paginate @projects, theme: "gitlab"
diff --git a/app/views/dashboard/show.html.haml b/app/views/dashboard/show.html.haml
index c4018d4b6d8..e5b7fbf097e 100644
--- a/app/views/dashboard/show.html.haml
+++ b/app/views/dashboard/show.html.haml
@@ -2,7 +2,7 @@
.dashboard.row
.activities.col-md-8
= render 'activities'
- .side.col-md-4.hidden-sm
+ .side.col-md-4.hidden-sm.hidden-xs
= render 'sidebar'
- else
diff --git a/app/views/devise/confirmations/new.html.haml b/app/views/devise/confirmations/new.html.haml
index dd63a232fe2..bf634d9de60 100644..100755
--- a/app/views/devise/confirmations/new.html.haml
+++ b/app/views/devise/confirmations/new.html.haml
@@ -3,7 +3,8 @@
= form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f|
.devise-errors
= devise_error_messages!
- = f.email_field :email, placeholder: 'Email', class: "form-control", required: true
+ .clearfix.append-bottom-20
+ = f.email_field :email, placeholder: 'Email', class: "form-control", required: true
.clearfix.append-bottom-10
= f.submit "Resend confirmation instructions", class: 'btn btn-success'
%hr
diff --git a/app/views/devise/passwords/new.html.haml b/app/views/devise/passwords/new.html.haml
index a14ef2995c8..040821ca32a 100644..100755
--- a/app/views/devise/passwords/new.html.haml
+++ b/app/views/devise/passwords/new.html.haml
@@ -2,7 +2,8 @@
%h3.page-title Reset password
.devise-errors
= devise_error_messages!
- = f.email_field :email, placeholder: "Email", class: "form-control", required: true
+ .clearfix.append-bottom-20
+ = f.email_field :email, placeholder: "Email", class: "form-control", required: true
.clearfix.append-bottom-10
= f.submit "Reset password", class: "btn-primary btn"
%hr
diff --git a/app/views/devise/sessions/new.html.haml b/app/views/devise/sessions/new.html.haml
index 938f61d2093..bb87d9ecb4a 100644
--- a/app/views/devise/sessions/new.html.haml
+++ b/app/views/devise/sessions/new.html.haml
@@ -1,7 +1,7 @@
.login-box
%h3.page-title Sign in
- if ldap_enabled?
- %ul.nav.nav-tabs.append-bottom-20
+ %ul.nav.nav-tabs
%li.active
= link_to 'LDAP', '#tab-ldap', 'data-toggle' => 'tab'
%li
diff --git a/app/views/groups/_filter.html.haml b/app/views/groups/_filter.html.haml
index 9fbc6c190cc..fe8c0669c0e 100644
--- a/app/views/groups/_filter.html.haml
+++ b/app/views/groups/_filter.html.haml
@@ -21,7 +21,7 @@
= project.name_with_namespace
%small.pull-right= entities_per_project(project, entity)
- if @projects.blank?
- %p.nothing_here_message This group has no projects yet
+ .nothing-here-block This group has no projects yet
%fieldset
%hr
diff --git a/app/views/groups/_new_group_member.html.haml b/app/views/groups/_new_group_member.html.haml
index 5801139a9f2..3ab9276c541 100644
--- a/app/views/groups/_new_group_member.html.haml
+++ b/app/views/groups/_new_group_member.html.haml
@@ -1,15 +1,8 @@
= form_for @users_group, url: group_users_groups_path(@group), html: { class: 'form-horizontal users-group-form' } do |f|
- %h4.append-bottom-20
- New member(s) for
- %strong #{@group.name}
- group
-
- %p 1. Choose users you want in the group
.form-group
= f.label :user_ids, "People", class: 'control-label'
.col-sm-10= users_select_tag(:user_ids, multiple: true, class: 'input-large')
- %p 2. Set access level for them
.form-group
= f.label :group_access, "Group Access", class: 'control-label'
.col-sm-10= select_tag :group_access, options_for_select(UsersGroup.group_access_roles, @users_group.group_access), class: "project-access-select select2"
diff --git a/app/views/groups/_projects.html.haml b/app/views/groups/_projects.html.haml
index 029d6cb0efa..bd4e3156af0 100644
--- a/app/views/groups/_projects.html.haml
+++ b/app/views/groups/_projects.html.haml
@@ -8,7 +8,7 @@
New project
%ul.well-list
- if projects.blank?
- %p.nothing_here_message This groups has no projects yet
+ .nothing-here-block This groups has no projects yet
- projects.each do |project|
%li.project-row
= link_to project_path(project), class: dom_class(project) do
diff --git a/app/views/groups/edit.html.haml b/app/views/groups/edit.html.haml
index 77734815b8a..9308bd8124e 100644
--- a/app/views/groups/edit.html.haml
+++ b/app/views/groups/edit.html.haml
@@ -4,13 +4,15 @@
%li.active
= link_to '#tab-edit', 'data-toggle' => 'tab' do
%i.icon-edit
- Edit Group
+ Group
%li
= link_to '#tab-projects', 'data-toggle' => 'tab' do
%i.icon-folder-close
Projects
%li
- = link_to 'Remove', '#tab-remove', 'data-toggle' => 'tab'
+ = link_to '#tab-remove', 'data-toggle' => 'tab' do
+ %i.icon-remove-sign
+ Remove
.col-md-10
.tab-content
@@ -20,7 +22,7 @@
%strong= @group.name
group settings:
%div.form-holder
- = form_for @group, html: { class: "form-horizontal" } do |f|
+ = 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
@@ -35,6 +37,26 @@
.col-sm-10
= f.text_area :description, maxlength: 250, class: "form-control js-gfm-input", rows: 4
+ .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 an group avatar here
+ %a.choose-btn.btn.btn-small.js-choose-group-avatar-button
+ %i.icon-paper-clip
+ %span Choose File ...
+ &nbsp;
+ %span.file_name.js-avatar-filename File name...
+ = f.file_field :avatar, class: "js-group-avatar-input hidden"
+ .light The maximum file size allowed is 100KB.
+ - 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-actions
= f.submit 'Save group', class: "btn btn-save"
@@ -58,7 +80,7 @@
= 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 @group.projects.blank?
- %p.nothing_here_message This group has no projects yet
+ .nothing-here-block This group has no projects yet
.tab-pane#tab-remove
.ui-box.ui-box-danger
diff --git a/app/views/groups/issues.html.haml b/app/views/groups/issues.html.haml
index e24df310910..4b11d91dc98 100644
--- a/app/views/groups/issues.html.haml
+++ b/app/views/groups/issues.html.haml
@@ -5,7 +5,9 @@
%p.light
Only issues from
%strong #{@group.name}
- group are listed here. To see all issues you should visit #{link_to 'dashboard', issues_dashboard_path} page.
+ group are listed here.
+ - if current_user
+ To see all issues you should visit #{link_to 'dashboard', issues_dashboard_path} page.
%hr
.row
diff --git a/app/views/groups/members.html.haml b/app/views/groups/members.html.haml
index 124560e4786..0c972622f88 100644
--- a/app/views/groups/members.html.haml
+++ b/app/views/groups/members.html.haml
@@ -1,20 +1,41 @@
+- show_roles = should_user_see_group_roles?(current_user, @group)
%h3.page-title
Group members
-%p.light
- Members of group have access to all group projects.
- Read more about permissions
- %strong= link_to "here", help_permissions_path, class: "vlink"
+- if show_roles
+ %p.light
+ Members of group have access to all group projects.
+ Read more about permissions
+ %strong= link_to "here", help_permissions_path, class: "vlink"
%hr
-- can_manage_group = current_user.can? :manage_group, @group
-.ui-box
+
+.clearfix
+ = form_tag members_group_path(@group), method: :get, class: 'form-inline member-search-form' do
+ .form-group
+ = search_field_tag :search, params[:search], { placeholder: 'Find member by name', class: 'form-control search-text-input input-mn-300' }
+ = submit_tag 'Search', class: 'btn'
+
+ - if current_user && current_user.can?(:manage_group, @group)
+ .pull-right
+ = link_to '#', class: 'btn btn-new js-toggle-visibility-link' do
+ Add members
+ %i.icon-chevron-down
+
+ .js-toggle-visibility-container.hide.new-group-member-holder
+ = render "new_group_member"
+
+.ui-box.prepend-top-20
.title
%strong #{@group.name}
group members
%small
- (#{@members.count})
+ (#{@members.total_count})
%ul.well-list
- @members.each do |member|
- = render 'users_groups/users_group', member: member, show_controls: can_manage_group
-- if can_manage_group
- = render "new_group_member"
+ = render 'users_groups/users_group', member: member, show_roles: show_roles, show_controls: true
+= paginate @members, theme: 'gitlab'
+
+:coffeescript
+ $('form.member-search-form').on 'submit', (event) ->
+ event.preventDefault()
+ Turbolinks.visit @.action + '?' + $(@).serialize()
diff --git a/app/views/groups/merge_requests.html.haml b/app/views/groups/merge_requests.html.haml
index eaf85bbdbc8..209130ec444 100644
--- a/app/views/groups/merge_requests.html.haml
+++ b/app/views/groups/merge_requests.html.haml
@@ -5,7 +5,9 @@
%p.light
Only merge requests from
%strong #{@group.name}
- group are listed here. To see all merge requests you should visit #{link_to 'dashboard', merge_requests_dashboard_path} page.
+ group are listed here.
+ - if current_user
+ To see all merge requests you should visit #{link_to 'dashboard', merge_requests_dashboard_path} page.
%hr
.row
.col-md-3
diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml
index 5332d383c4c..0343670c203 100644
--- a/app/views/groups/show.html.haml
+++ b/app/views/groups/show.html.haml
@@ -1,27 +1,33 @@
.dashboard
.activities.col-md-8.hidden-sm
- = render "events/event_last_push", event: @last_push
- = link_to dashboard_path, class: 'btn btn-tiny' do
- &larr; To dashboard
- &nbsp;
+ - 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 You will only see events from projects in this group
%hr
= render 'shared/event_filter'
- if @events.any?
.content_list
- else
- %p.nothing_here_message Project activity will be displayed here
- .loading.hide
+ .nothing-here-block Project activity will be displayed here
+ = spinner
.side.col-md-4
- - if @group.description.present?
- .description-block
- = @group.description
+ .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= @group.description
= render "projects", projects: @projects
- .prepend-top-20
- = link_to group_path(@group, { format: :atom, private_token: current_user.private_token }), title: "Feed" do
- %strong
- %i.icon-rss
- News Feed
+ - if current_user
+ .prepend-top-20
+ = link_to group_path(@group, { format: :atom, private_token: current_user.private_token }), title: "Feed" do
+ %strong
+ %i.icon-rss
+ News Feed
%hr
= render 'shared/promo'
diff --git a/app/views/help/_api_layout.html.haml b/app/views/help/_api_layout.html.haml
index c211b658410..af723f906d9 100644
--- a/app/views/help/_api_layout.html.haml
+++ b/app/views/help/_api_layout.html.haml
@@ -5,7 +5,7 @@
%i.icon-angle-left
Back to help
%ul.nav.nav-pills.nav-stacked
- - %w(README projects project_snippets repositories deploy_keys users groups session issues milestones merge_requests notes system_hooks).each do |file|
+ - %w(README projects project_snippets repositories repository_files commits deploy_keys users groups session issues milestones merge_requests notes system_hooks).each do |file|
%li{class: file == @category ? 'active' : nil}
= link_to file.titleize, help_api_file_path(file)
diff --git a/app/views/help/_layout.html.haml b/app/views/help/_layout.html.haml
index fc0ac277a48..201d63ca243 100644
--- a/app/views/help/_layout.html.haml
+++ b/app/views/help/_layout.html.haml
@@ -1,5 +1,5 @@
.row
- .col-md-3{:"data-spy" => 'affix'}
+ .col-md-3
%h3.page-title Help
%ul.nav.nav-pills.nav-stacked
- links = {:"Workflow" => help_workflow_path, :"SSH Keys" => help_ssh_path, :"GitLab Markdown" => help_markdown_path, :"Permissions" => help_permissions_path, :"API" => help_api_path, :"Web Hooks" => help_web_hooks_path, :"Rake Tasks" => help_raketasks_path, :"System Hooks" => help_system_hooks_path, :"Public Access" => help_public_access_path, :"Security" => help_security_path}
@@ -7,5 +7,6 @@
%li{class: current_page?(path) ? 'active' : nil}
= link_to title, path
- .col-md-9.pull-right
- = yield
+ .col-md-9
+ .wiki
+ = yield
diff --git a/app/views/help/index.html.haml b/app/views/help/index.html.haml
index f1cb723ebac..c82acd917d0 100644
--- a/app/views/help/index.html.haml
+++ b/app/views/help/index.html.haml
@@ -6,9 +6,15 @@
%p.slead
GitLab is open source software to collaborate on code.
%br
- Create projects and repositories, manage access and do code reviews.
+ Manage git repositories with fine grained access controls that keep your code secure.
%br
- Read more about GitLab at #{link_to "gitlab.org", "http://gitlab.org/", target: "_blank"}.
+ Perform code reviews and enhance collaboration with merge requests.
+ %br
+ Each project can also have an issue tracker and a wiki.
+ %br
+ Used by more than 50,000 organizations, GitLab is the most popular solution to manage git repositories on-premises.
+ %br
+ Read more about GitLab at #{link_to "www.gitlab.com", "https://www.gitlab.com/", target: "_blank"}.
.row
.col-md-4
diff --git a/app/views/help/permissions.html.haml b/app/views/help/permissions.html.haml
index 15e3bf3a135..5d3ee4526fe 100644
--- a/app/views/help/permissions.html.haml
+++ b/app/views/help/permissions.html.haml
@@ -1,212 +1,6 @@
= render layout: 'help/layout' do
- %h3.page-title Permissions
- %p.light Users have different abilities depending on the access level they have in particular group or project.
- %p.light If a user is both in a project group and in the project itself the highest permission level is used.
- %p.light If a user is a GitLab administrator they receive all permissions.
- %hr
+ %h3.page-title Permissions
- %h4 Project:
- %table.table
- %thead
- %tr
- %th Action
- %th Guest
- %th Reporter
- %th Developer
- %th Master
- %th Owner
- %tbody
- %tr
- %td Create new issue
- %td.permission-x &#10003;
- %td.permission-x &#10003;
- %td.permission-x &#10003;
- %td.permission-x &#10003;
- %td.permission-x &#10003;
- %tr
- %td Leave comments
- %td.permission-x &#10003;
- %td.permission-x &#10003;
- %td.permission-x &#10003;
- %td.permission-x &#10003;
- %td.permission-x &#10003;
- %tr
- %td Write on project wall
- %td.permission-x &#10003;
- %td.permission-x &#10003;
- %td.permission-x &#10003;
- %td.permission-x &#10003;
- %td.permission-x &#10003;
- %tr
- %td Pull project code
- %td
- %td.permission-x &#10003;
- %td.permission-x &#10003;
- %td.permission-x &#10003;
- %td.permission-x &#10003;
- %tr
- %td Download project
- %td
- %td.permission-x &#10003;
- %td.permission-x &#10003;
- %td.permission-x &#10003;
- %td.permission-x &#10003;
- %tr
- %td Create code snippets
- %td
- %td.permission-x &#10003;
- %td.permission-x &#10003;
- %td.permission-x &#10003;
- %td.permission-x &#10003;
- %tr
- %td Create new merge request
- %td
- %td
- %td.permission-x &#10003;
- %td.permission-x &#10003;
- %td.permission-x &#10003;
- %tr
- %td Create new branches
- %td
- %td
- %td.permission-x &#10003;
- %td.permission-x &#10003;
- %td.permission-x &#10003;
- %tr
- %td Push to non-protected branches
- %td
- %td
- %td.permission-x &#10003;
- %td.permission-x &#10003;
- %td.permission-x &#10003;
- %tr
- %td Remove non-protected branches
- %td
- %td
- %td.permission-x &#10003;
- %td.permission-x &#10003;
- %td.permission-x &#10003;
- %tr
- %td Add tags
- %td
- %td
- %td.permission-x &#10003;
- %td.permission-x &#10003;
- %td.permission-x &#10003;
- %tr
- %td Write a wiki
- %td
- %td
- %td.permission-x &#10003;
- %td.permission-x &#10003;
- %td.permission-x &#10003;
- %tr
- %td Add new team members
- %td
- %td
- %td
- %td.permission-x &#10003;
- %td.permission-x &#10003;
- %tr
- %td Push to protected branches
- %td
- %td
- %td
- %td.permission-x &#10003;
- %td.permission-x &#10003;
- %tr
- %td Remove protected branches
- %td
- %td
- %td
- %td.permission-x &#10003;
- %td.permission-x &#10003;
- %tr
- %td Edit project
- %td
- %td
- %td
- %td.permission-x &#10003;
- %td.permission-x &#10003;
- %tr
- %td Add Deploy Keys to project
- %td
- %td
- %td
- %td.permission-x &#10003;
- %td.permission-x &#10003;
- %tr
- %td Configure Project Hooks
- %td
- %td
- %td
- %td.permission-x &#10003;
- %td.permission-x &#10003;
- %tr
- %td Switch visibility level
- %td
- %td
- %td
- %td
- %td.permission-x &#10003;
- %tr
- %td Transfer project to another namespace
- %td
- %td
- %td
- %td
- %td.permission-x &#10003;
- %tr
- %td Remove project
- %td
- %td
- %td
- %td
- %td.permission-x &#10003;
-
- %h4 Group
- %table.table
- %thead
- %tr
- %th Action
- %th Guest
- %th Reporter
- %th Developer
- %th Master
- %th Owner
- %tbody
- %tr
- %td Browse group
- %td.permission-x &#10003;
- %td.permission-x &#10003;
- %td.permission-x &#10003;
- %td.permission-x &#10003;
- %td.permission-x &#10003;
- %tr
- %td Edit group
- %td
- %td
- %td
- %td
- %td.permission-x &#10003;
- %tr
- %td Create project in group
- %td
- %td
- %td
- %td
- %td.permission-x &#10003;
- %tr
- %td Manage group members
- %td
- %td
- %td
- %td
- %td.permission-x &#10003;
- %tr
- %td Remove group
- %td
- %td
- %td
- %td
- %td.permission-x &#10003;
+ .help_body
+ = preserve do
+ = markdown File.read(Rails.root.join("doc", "permissions", "permissions.md"))
diff --git a/app/views/help/public_access.html.haml b/app/views/help/public_access.html.haml
index ba2df8c3553..d1ec3f5d5c1 100644
--- a/app/views/help/public_access.html.haml
+++ b/app/views/help/public_access.html.haml
@@ -1,46 +1,6 @@
= render layout: 'help/layout' do
- %h3.page-title Public Access
+ %h3.page-title Public Access
- %p.slead
- GitLab allows you to open selected projects to be accessed
- %strong publicly
- or
- %strong internally
- \.
- %br
- Projects with either of these visibility levels will be listed in the #{link_to "public access directory", public_root_path}.
- %br
- Internal projects will only be available to authenticated users.
-
- .clearfix
- .dashboard-intro-icon
- = public_icon
- %h4
- Public projects
- %p
- Public project can be cloned
- %strong without any
- authentication.
- %br
- It will also be listed on the #{link_to "public access directory", public_root_path}.
- %br
- %strong Any logged in user
- will have #{link_to "Guest", help_permissions_path} permissions on the repository.
-
- .clearfix
- .dashboard-intro-icon
- = internal_icon
- %h4
- Internal projects
- %p
- Internal project can be cloned by any logged in user.
- %br
- It will also be listed on the #{link_to "public access directory", public_root_path} for logged in users.
- %br
- Any logged in user will have #{link_to "Guest", help_permissions_path} permissions on the repository.
-
- %h4 How to change project visibility
- %ol
- %li Go to your project dashboard
- %li Click on the "Edit" tab
- %li Change "Visibility Level"
+ .help_body
+ = preserve do
+ = markdown File.read(Rails.root.join("doc", "public_access", "public_access.md"))
diff --git a/app/views/help/ssh.html.haml b/app/views/help/ssh.html.haml
index 773e490ef80..8ae1ed1ab6e 100644
--- a/app/views/help/ssh.html.haml
+++ b/app/views/help/ssh.html.haml
@@ -1,17 +1,6 @@
= render layout: 'help/layout' do
- %h3.page-title SSH Keys
+ %h3.page-title SSH Keys
- %p.slead
- SSH key allows you to establish a secure connection between your computer and GitLab
-
- %p.slead
- To generate a new SSH key just open your terminal and use code below. Press enter to accept the defaults when generating the key.
-
- %pre.dark
- ssh-keygen -t rsa -C "#{current_user.email}"
-
- %p.slead
- Next just use code below to dump your public key and add to GitLab SSH Keys
-
- %pre.dark
- cat ~/.ssh/id_rsa.pub
+ .help_body
+ = preserve do
+ = markdown File.read(Rails.root.join("doc", "ssh", "ssh.md"))
diff --git a/app/views/help/system_hooks.html.haml b/app/views/help/system_hooks.html.haml
index 3e401a6e19f..e24f566121d 100644
--- a/app/views/help/system_hooks.html.haml
+++ b/app/views/help/system_hooks.html.haml
@@ -1,11 +1,6 @@
= render layout: 'help/layout' do
- %h3.page-title System hooks
+ %h3.page-title System hooks
- %p.slead
- Your GitLab instance can perform HTTP POST requests on the following events: create_project, delete_project, create_user, delete_user, change_team_member.
- %br
- %br
- System Hooks can be used, e.g. for logging or changing information in a LDAP server.
- %br
- %h5 Hooks request example:
- = render "admin/hooks/data_ex"
+ .help_body
+ = preserve do
+ = markdown File.read(Rails.root.join("doc", "system_hooks", "system_hooks.md"))
diff --git a/app/views/help/web_hooks.html.haml b/app/views/help/web_hooks.html.haml
index 7bde7fcc3d0..9e2b54ab6ec 100644
--- a/app/views/help/web_hooks.html.haml
+++ b/app/views/help/web_hooks.html.haml
@@ -1,115 +1,6 @@
= render layout: 'help/layout' do
- %h3.page-title Project web hooks
- %p.light
- Project web hooks allow you to trigger url if new code is pushed or new issue is created
- %hr
+ %h3.page-title Project web hooks
- %p.slead
- You can configure web hook to listen for specific events like pushes, issues, merge requests.
- %br
- GitLab will send POST request with data to web hook url.
- %br
- Web Hooks can be used to update an external issue tracker, trigger CI builds, update a backup mirror, or even deploy to your production server.
- %hr
-
- %h4 Push events
- %p.light
- Triggered when you push to the repository except pushing tags.
- %br
- Request body:
- = highlight_js do
- :erb
- {
- "before": "95790bf891e76fee5e1747ab589903a6a1f80f22",
- "after": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
- "ref": "refs/heads/master",
- "user_id": 4,
- "user_name": "John Smith",
- "project_id": 15,
- "repository": {
- "name": "Diaspora",
- "url": "git@localhost:diaspora.git",
- "description": "",
- "homepage": "http://localhost/diaspora",
- },
- "commits": [
- {
- "id": "b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
- "message": "Update Catalan translation to e38cb41.",
- "timestamp": "2011-12-12T14:27:31+02:00",
- "url": "http://localhost/diaspora/commits/b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
- "author": {
- "name": "Jordi Mallach",
- "email": "jordi@softcatala.org",
- }
- },
- // ...
- {
- "id": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
- "message": "fixed readme",
- "timestamp": "2012-01-03T23:36:29+02:00",
- "url": "http://localhost/diaspora/commits/da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
- "author": {
- "name": "GitLab dev user",
- "email": "gitlabdev@dv6700.(none)",
- },
- },
- ],
- "total_commits_count": 4,
- };
-
-
- %h4.prepend-top-20 Issues events
- %p.light
- Triggered when new issue created or existing issue was updated/closed/reopened.
- %br
- Request body:
- = highlight_js do
- :erb
- {
- "object_kind":"issue",
- "object_attributes":{
- "id":301,
- "title":"New API: create/update/delete file",
- "assignee_id":51,
- "author_id":51,
- "project_id":14,
- "created_at":"2013-12-03T17:15:43Z",
- "updated_at":"2013-12-03T17:15:43Z",
- "position":0,
- "branch_name":null,
- "description":"Create new API for manipulations with repository",
- "milestone_id":null,
- "state":"opened",
- "iid":23
- }
- }
- %h4.prepend-top-20 Merge request events
- %p.light
- Triggered when new merge request created or existing merge request was updated/merged/closed.
- %br
- Request body:
- = highlight_js do
- :erb
- {
- "object_kind":"merge_request",
- "object_attributes":{
- "id":99,
- "target_branch":"master",
- "source_branch":"ms-viewport",
- "source_project_id":14,
- "author_id":51,
- "assignee_id":6,
- "title":"MS-Viewport",
- "created_at":"2013-12-03T17:23:34Z",
- "updated_at":"2013-12-03T17:23:34Z",
- "st_commits":null,
- "st_diffs":null,
- "milestone_id":null,
- "state":"opened",
- "merge_status":"unchecked",
- "target_project_id":14,
- "iid":1,
- "description":""
- }
- }
+ .help_body
+ = preserve do
+ = markdown File.read(Rails.root.join("doc", "web_hooks", "web_hooks.md"))
diff --git a/app/views/help/workflow.html.haml b/app/views/help/workflow.html.haml
index 2b8950cd5c2..47de4ad796c 100644
--- a/app/views/help/workflow.html.haml
+++ b/app/views/help/workflow.html.haml
@@ -1,37 +1,6 @@
= render layout: 'help/layout' do
- %h3.page-title Workflow
-
- %ol.help
- %li
- %p Clone project
- .bash
- %pre.dark
- git clone git@example.com:project-name.git
-
- %li
- %p Create branch with your feature
- .bash
- %pre.dark
- git checkout -b $feature_name
-
- %li
- %p Write code. Commit changes
- .bash
- %pre.dark
- git commit -am "My feature is ready"
-
- %li
- %p Push your branch to GitLab
- .bash
- %pre.dark
- git push origin $feature_name
-
- %li
- %p Review your code on Commits page
-
- %li
- %p Create a merge request
-
- %li
- %p Your team lead will review code &amp; merge it to main branch
+ %h3.page-title Workflow
+ .help_body
+ = preserve do
+ = markdown File.read(Rails.root.join("doc", "workflow", "workflow.md"))
diff --git a/app/views/layouts/_head.html.haml b/app/views/layouts/_head.html.haml
index 68146e661eb..9ba20f1347d 100644
--- a/app/views/layouts/_head.html.haml
+++ b/app/views/layouts/_head.html.haml
@@ -12,6 +12,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
= render 'layouts/google_analytics' if extra_config.has_key?('google_analytics_id')
+ = render 'layouts/piwik' if extra_config.has_key?('piwik_url') && extra_config.has_key?('piwik_site_id')
-# Atom feed
- if current_user
@@ -22,3 +23,8 @@
= auto_discovery_link_tag(:atom, project_commits_url(@project, @ref, format: :atom, private_token: current_user.private_token), title: "Recent commits to #{@project.name}:#{@ref}")
- if current_controller?(:issues)
= auto_discovery_link_tag(:atom, project_issues_url(@project, :atom, private_token: current_user.private_token), title: "#{@project.name} issues")
+
+ -# Go repository retrieval support.
+ - if controller_name == 'projects' && action_name == 'show'
+ %meta{name: "go-import", content: "#{@project.web_url_without_protocol} git #{@project.web_url}.git"}
+
diff --git a/app/views/layouts/_head_panel.html.haml b/app/views/layouts/_head_panel.html.haml
index 58b216f2e98..5080a1b7ef6 100644
--- a/app/views/layouts/_head_panel.html.haml
+++ b/app/views/layouts/_head_panel.html.haml
@@ -6,7 +6,7 @@
= link_to root_path, class: "home has_bottom_tooltip", title: "Dashboard" do
%h1 GITLAB
%span.separator
- %h1.project_name= title
+ %h1.title= title
%button.navbar-toggle{"data-target" => ".navbar-collapse", "data-toggle" => "collapse", type: "button"}
%span.sr-only Toggle navigation
@@ -14,14 +14,13 @@
.navbar-collapse.collapse
%ul.nav.navbar-nav
- %li
+ %li.hidden-sm.hidden-xs
%a
%div.hide.turbolink-spinner
%i.icon-refresh.icon-spin
- Loading...
- %li.hidden-sm
+ %li.hidden-sm.hidden-xs
= render "layouts/search"
- %li.visible-sm
+ %li.visible-sm.visible-xs
= link_to search_path, title: "Search", class: 'has_bottom_tooltip', 'data-original-title' => 'Search area' do
%i.icon-search
%li
diff --git a/app/views/layouts/_piwik.html.haml b/app/views/layouts/_piwik.html.haml
new file mode 100644
index 00000000000..135e8daca26
--- /dev/null
+++ b/app/views/layouts/_piwik.html.haml
@@ -0,0 +1,12 @@
+:javascript
+ var _paq = _paq || [];
+ _paq.push(["trackPageView"]);
+ _paq.push(["enableLinkTracking"]);
+
+ (function() {
+ var u=(("https:" == document.location.protocol) ? "https" : "http") + "://#{extra_config.piwik_url}/";
+ _paq.push(["setTrackerUrl", u+"piwik.php"]);
+ _paq.push(["setSiteId", "#{extra_config.piwik_site_id}"]);
+ var d=document, g=d.createElement("script"), s=d.getElementsByTagName("script")[0]; g.type="text/javascript";
+ g.defer=true; g.async=true; g.src=u+"piwik.js"; s.parentNode.insertBefore(g,s);
+ })();
diff --git a/app/views/layouts/_public_head_panel.html.haml b/app/views/layouts/_public_head_panel.html.haml
index 7d188fb28e4..99e11cd2b5c 100644
--- a/app/views/layouts/_public_head_panel.html.haml
+++ b/app/views/layouts/_public_head_panel.html.haml
@@ -6,11 +6,7 @@
= link_to public_root_path, class: "home" do
%h1 GITLAB
%span.separator
- %h1.project_name
- - if @project
- = project_title(@project)
- - else
- Public Projects
+ %h1.title= title
.pull-right
= link_to "Sign in", new_session_path(:user), class: 'btn btn-sign-in btn-new'
@@ -20,4 +16,3 @@
%a
%div.hide.turbolink-spinner
%i.icon-refresh.icon-spin
- Loading...
diff --git a/app/views/layouts/_search.html.haml b/app/views/layouts/_search.html.haml
index 9a0db99332a..a0e55b21c32 100644
--- a/app/views/layouts/_search.html.haml
+++ b/app/views/layouts/_search.html.haml
@@ -7,4 +7,4 @@
= hidden_field_tag :search_code, true
= hidden_field_tag :repository_ref, @ref
= submit_tag 'Go' if ENV['RAILS_ENV'] == 'test'
- .search-autocomplete-json.hide{:'data-autocomplete-opts' => search_autocomplete_source }
+ .search-autocomplete-opts.hide{:'data-autocomplete-path' => search_autocomplete_path, :'data-autocomplete-project-id' => @project.try(:id), :'data-autocomplete-project-ref' => @ref }
diff --git a/app/views/layouts/admin.html.haml b/app/views/layouts/admin.html.haml
index 3a23cbdb376..53e0dbaef9b 100644
--- a/app/views/layouts/admin.html.haml
+++ b/app/views/layouts/admin.html.haml
@@ -2,9 +2,10 @@
%html{ lang: "en"}
= render "layouts/head", title: "Admin area"
%body{class: "#{app_theme} admin", :'data-page' => body_data_page}
+ = render "layouts/broadcast"
= render "layouts/head_panel", title: "Admin area"
= render "layouts/flash"
- %nav.main-nav
+ %nav.main-nav.navbar-collapse.collapse
.container= render 'layouts/nav/admin'
.container
diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml
index 92edc718235..511db389e0f 100644
--- a/app/views/layouts/application.html.haml
+++ b/app/views/layouts/application.html.haml
@@ -5,7 +5,7 @@
= render "layouts/broadcast"
= render "layouts/head_panel", title: "Dashboard"
= render "layouts/flash"
- %nav.main-nav
+ %nav.main-nav.navbar-collapse.collapse
.container= render 'layouts/nav/dashboard'
.container
diff --git a/app/views/layouts/group.html.haml b/app/views/layouts/group.html.haml
index b546a9fa84f..fb4a3a3ba95 100644
--- a/app/views/layouts/group.html.haml
+++ b/app/views/layouts/group.html.haml
@@ -5,7 +5,7 @@
= render "layouts/broadcast"
= render "layouts/head_panel", title: "group: #{@group.name}"
= render "layouts/flash"
- %nav.main-nav
+ %nav.main-nav.navbar-collapse.collapse
.container= render 'layouts/nav/group'
.container
diff --git a/app/views/layouts/nav/_group.html.haml b/app/views/layouts/nav/_group.html.haml
index a8bb3b91559..36b102dc25a 100644
--- a/app/views/layouts/nav/_group.html.haml
+++ b/app/views/layouts/nav/_group.html.haml
@@ -5,11 +5,13 @@
= nav_link(path: 'groups#issues') do
= link_to issues_group_path(@group) do
Issues
- %span.count= current_user.assigned_issues.opened.of_group(@group).count
+ - if current_user
+ %span.count= current_user.assigned_issues.opened.of_group(@group).count
= nav_link(path: 'groups#merge_requests') do
= link_to merge_requests_group_path(@group) do
Merge Requests
- %span.count= current_user.cared_merge_requests.opened.of_group(@group).count
+ - if current_user
+ %span.count= current_user.cared_merge_requests.opened.of_group(@group).count
= nav_link(path: 'groups#members') do
= link_to "Members", members_group_path(@group)
diff --git a/app/views/layouts/nav/_profile.html.haml b/app/views/layouts/nav/_profile.html.haml
index d44cb975ea5..35d0d417502 100644
--- a/app/views/layouts/nav/_profile.html.haml
+++ b/app/views/layouts/nav/_profile.html.haml
@@ -4,6 +4,10 @@
%i.icon-home
= nav_link(controller: :accounts) do
= link_to "Account", profile_account_path
+ = nav_link(controller: :emails) do
+ = link_to profile_emails_path do
+ 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
diff --git a/app/views/layouts/navless.html.haml b/app/views/layouts/navless.html.haml
index 7325664bc19..c43d688a2cb 100644
--- a/app/views/layouts/navless.html.haml
+++ b/app/views/layouts/navless.html.haml
@@ -2,6 +2,7 @@
%html{ lang: "en"}
= render "layouts/head", title: @title
%body{class: "#{app_theme} application", :'data-page' => body_data_page}
+ = render "layouts/broadcast"
= render "layouts/head_panel", title: @title
= render "layouts/flash"
diff --git a/app/views/layouts/profile.html.haml b/app/views/layouts/profile.html.haml
index 72849639571..2d869a6cdcb 100644
--- a/app/views/layouts/profile.html.haml
+++ b/app/views/layouts/profile.html.haml
@@ -5,7 +5,7 @@
= render "layouts/broadcast"
= render "layouts/head_panel", title: "Profile"
= render "layouts/flash"
- %nav.main-nav
+ %nav.main-nav.navbar-collapse.collapse
.container= render 'layouts/nav/profile'
.container
diff --git a/app/views/layouts/project_settings.html.haml b/app/views/layouts/project_settings.html.haml
index a55f043f2cf..5659cfab31d 100644
--- a/app/views/layouts/project_settings.html.haml
+++ b/app/views/layouts/project_settings.html.haml
@@ -9,7 +9,7 @@
- if can?(current_user, :download_code, @project)
= render 'shared/no_ssh'
- %nav.main-nav
+ %nav.main-nav.navbar-collapse.collapse
.container= render 'layouts/nav/project'
.container
diff --git a/app/views/layouts/projects.html.haml b/app/views/layouts/projects.html.haml
index 55214c6a5c9..3ae4961b137 100644
--- a/app/views/layouts/projects.html.haml
+++ b/app/views/layouts/projects.html.haml
@@ -9,7 +9,7 @@
- if can?(current_user, :download_code, @project)
= render 'shared/no_ssh'
- %nav.main-nav
+ %nav.main-nav.navbar-collapse.collapse
.container= render 'layouts/nav/project'
.container
diff --git a/app/views/layouts/public.html.haml b/app/views/layouts/public.html.haml
index 8f490f61a9c..3c76bbb9575 100644
--- a/app/views/layouts/public.html.haml
+++ b/app/views/layouts/public.html.haml
@@ -2,10 +2,10 @@
%html{ lang: "en"}
= render "layouts/head", title: "Public Projects"
%body{class: "#{app_theme} application", :'data-page' => body_data_page}
+ = render "layouts/broadcast"
- if current_user
= render "layouts/head_panel", title: "Public Projects"
- else
- = render "layouts/public_head_panel"
-
+ = render "layouts/public_head_panel", title: "Public Projects"
.container.navless-container
.content= yield
diff --git a/app/views/layouts/public_group.html.haml b/app/views/layouts/public_group.html.haml
new file mode 100644
index 00000000000..a289b784725
--- /dev/null
+++ b/app/views/layouts/public_group.html.haml
@@ -0,0 +1,10 @@
+!!! 5
+%html{ lang: "en"}
+ = render "layouts/head", title: group_head_title
+ %body{class: "#{app_theme} application", :'data-page' => body_data_page}
+ = render "layouts/broadcast"
+ = render "layouts/public_head_panel", title: "group: #{@group.name}"
+ %nav.main-nav.navbar-collapse.collapse
+ .container= render 'layouts/nav/group'
+ .container
+ .content= yield
diff --git a/app/views/layouts/public_projects.html.haml b/app/views/layouts/public_projects.html.haml
index 1e8814134f5..cf4ca9c7a84 100644
--- a/app/views/layouts/public_projects.html.haml
+++ b/app/views/layouts/public_projects.html.haml
@@ -2,7 +2,8 @@
%html{ lang: "en"}
= render "layouts/head", title: @project.name_with_namespace
%body{class: "#{app_theme} application", :'data-page' => body_data_page}
- = render "layouts/public_head_panel"
+ = render "layouts/broadcast"
+ = render "layouts/public_head_panel", title: project_title(@project)
%nav.main-nav
.container= render 'layouts/nav/project'
.container
diff --git a/app/views/layouts/public_users.html.haml b/app/views/layouts/public_users.html.haml
new file mode 100644
index 00000000000..4aa258fea0d
--- /dev/null
+++ b/app/views/layouts/public_users.html.haml
@@ -0,0 +1,8 @@
+!!! 5
+%html{ lang: "en"}
+ = render "layouts/head", title: @title
+ %body{class: "#{app_theme} application", :'data-page' => body_data_page}
+ = render "layouts/broadcast"
+ = render "layouts/public_head_panel", title: @title
+ .container.navless-container
+ .content= yield
diff --git a/app/views/layouts/search.html.haml b/app/views/layouts/search.html.haml
index 177b3a4f8f4..97ed8ba12df 100644
--- a/app/views/layouts/search.html.haml
+++ b/app/views/layouts/search.html.haml
@@ -2,6 +2,7 @@
%html{ lang: "en"}
= render "layouts/head", title: "Search"
%body{class: "#{app_theme} application", :'data-page' => body_data_page}
+ = render "layouts/broadcast"
= render "layouts/head_panel", title: "Search"
= render "layouts/flash"
diff --git a/app/views/layouts/user_team.html.haml b/app/views/layouts/user_team.html.haml
index e64e68d2446..ce13853ed7f 100644
--- a/app/views/layouts/user_team.html.haml
+++ b/app/views/layouts/user_team.html.haml
@@ -2,9 +2,10 @@
%html{ lang: "en"}
= render "layouts/head", title: "#{@team.name}"
%body{class: "#{app_theme} application", :'data-page' => body_data_page}
+ = render "layouts/broadcast"
= render "layouts/head_panel", title: "team: #{@team.name}"
= render "layouts/flash"
- %nav.main-nav
+ %nav.main-nav.navbar-collapse.collapse
.container= render 'layouts/nav/team'
.container
diff --git a/app/views/notify/new_email_email.html.haml b/app/views/notify/new_email_email.html.haml
new file mode 100644
index 00000000000..4a0448a573c
--- /dev/null
+++ b/app/views/notify/new_email_email.html.haml
@@ -0,0 +1,10 @@
+%p
+ Hi #{@user.name}!
+%p
+ A new email was added to your account:
+%p
+ email:
+ %code= @email.email
+%p
+ If this email was added in error, you can remove it here:
+ = link_to "Emails", profile_emails_url
diff --git a/app/views/notify/new_email_email.text.erb b/app/views/notify/new_email_email.text.erb
new file mode 100644
index 00000000000..51cba99ad0d
--- /dev/null
+++ b/app/views/notify/new_email_email.text.erb
@@ -0,0 +1,7 @@
+Hi <%= @user.name %>!
+
+A new email was added to your account:
+
+email.................. <%= @email.email %>
+
+If this email was added in error, you can remove it here: <%= profile_emails_url %>
diff --git a/app/views/notify/repository_push_email.html.haml b/app/views/notify/repository_push_email.html.haml
index d0b30c08338..ab0d6c653b9 100644
--- a/app/views/notify/repository_push_email.html.haml
+++ b/app/views/notify/repository_push_email.html.haml
@@ -21,3 +21,8 @@
%pre
= diff.diff
%br
+
+- if @compare.timeout
+ %h5 Huge diff. To prevent performance issues it was hidden
+- elsif @compare.commits_over_limit?
+ %h5 Diff for big amount of commits is disabled
diff --git a/app/views/notify/repository_push_email.text.haml b/app/views/notify/repository_push_email.text.haml
index 6718ca68359..93b344d2c82 100644
--- a/app/views/notify/repository_push_email.text.haml
+++ b/app/views/notify/repository_push_email.text.haml
@@ -18,3 +18,8 @@ Diff:
= diff.new_path || diff.old_path
\=====================================
= diff.diff
+\
+- if @compare.timeout
+ Huge diff. To prevent performance issues it was hidden
+- elsif @compare.commits_over_limit?
+ Diff for big amount of commits is disabled
diff --git a/app/views/profiles/accounts/show.html.haml b/app/views/profiles/accounts/show.html.haml
index 3220736b078..c60e1ca9297 100644
--- a/app/views/profiles/accounts/show.html.haml
+++ b/app/views/profiles/accounts/show.html.haml
@@ -50,7 +50,10 @@
%div
= f.text_field :username, required: true, class: 'form-control'
&nbsp;
- %span.loading-gif.hide= image_tag "ajax_loader.gif"
+ .loading-gif.hide
+ %p
+ %i.icon-spinner.icon-spin
+ Saving new username
%p.light
= user_url(@user)
%div
diff --git a/app/views/profiles/emails/index.html.haml b/app/views/profiles/emails/index.html.haml
new file mode 100644
index 00000000000..b5f1e438ccb
--- /dev/null
+++ b/app/views/profiles/emails/index.html.haml
@@ -0,0 +1,33 @@
+%h3.page-title
+ My email addresses
+%p.light
+ Your
+ %b Primary Email
+ will be used for account notifications, avatar detection and web based operations, such as edits and merges.
+ %br
+ All email addresses will be used to identify your commits.
+
+%hr
+
+.ui-box
+ .title
+ Emails (#{@emails.count + 1})
+ %ul.well-list#emails-table
+ %li
+ %strong= @primary
+ %span.label.label-success Primary Email
+ - @emails.each do |email|
+ %li
+ %strong= email.email
+ %span.cgray
+ added #{time_ago_with_tooltip(email.created_at)}
+ = link_to 'Remove', profile_email_path(email), data: { confirm: 'Are you sure?'}, method: :delete, class: 'btn btn-small btn-remove pull-right'
+
+%h4 Add email address
+= form_for 'email', url: profile_emails_path, html: { class: 'form-horizontal' } do |f|
+ .form-group
+ = f.label :email, class: 'control-label'
+ .col-sm-10
+ = f.text_field :email, class: 'form-control'
+ .form-actions
+ = f.submit 'Add', class: 'btn btn-create'
diff --git a/app/views/profiles/groups/index.html.haml b/app/views/profiles/groups/index.html.haml
index 1d24e636bf4..cebc0b6bccb 100644
--- a/app/views/profiles/groups/index.html.haml
+++ b/app/views/profiles/groups/index.html.haml
@@ -18,13 +18,14 @@
%li
.pull-right
- if can?(current_user, :manage_group, group)
- = link_to edit_group_path(group), class: "btn-small btn grouped" do
+ = link_to edit_group_path(group), class: "btn-small btn btn-grouped" do
%i.icon-cogs
Settings
- = link_to leave_profile_group_path(group), data: { confirm: "Are you sure you want to leave #{group.name} group?"}, method: :delete, class: "btn-small btn grouped", title: 'Remove user from group' do
- %i.icon-signout
- Leave
+ - if can?(current_user, :destroy, user_group)
+ = link_to leave_profile_group_path(group), data: { confirm: leave_group_message(group.name) }, method: :delete, class: "btn-small btn btn-grouped", title: 'Remove user from group' do
+ %i.icon-signout
+ Leave
= link_to group, class: 'group-name' do
%strong= group.name
diff --git a/app/views/profiles/keys/index.html.haml b/app/views/profiles/keys/index.html.haml
index 79fdb164089..71a4ca91d42 100644
--- a/app/views/profiles/keys/index.html.haml
+++ b/app/views/profiles/keys/index.html.haml
@@ -17,6 +17,6 @@
= render @keys
- if @keys.blank?
%li
- %h3.nothing_here_message There are no SSH keys with access to your account.
+ .nothing-here-block There are no SSH keys with access to your account.
diff --git a/app/views/profiles/notifications/_settings.html.haml b/app/views/profiles/notifications/_settings.html.haml
index d123b8f9407..218d51d31af 100644
--- a/app/views/profiles/notifications/_settings.html.haml
+++ b/app/views/profiles/notifications/_settings.html.haml
@@ -1,31 +1,17 @@
%li
- .row
- .col-sm-4
- %span
- = notification_icon(notification)
-
- - if membership.kind_of? UsersGroup
- = link_to membership.group.name, membership.group
- - else
- = link_to_project(membership.project)
- .col-sm-8
- = form_tag profile_notifications_path, method: :put, remote: true, class: 'update-notifications' do
- = hidden_field_tag :notification_type, type, id: dom_id(membership, 'notification_type')
- = hidden_field_tag :notification_id, membership.id, id: dom_id(membership, 'notification_id')
-
- = label_tag nil, class: 'radio-inline' do
- = radio_button_tag :notification_level, Notification::N_GLOBAL, notification.global?, id: dom_id(membership, 'notification_level'), class: 'trigger-submit'
- %span Use global setting
-
- = label_tag nil, class: 'radio-inline' do
- = radio_button_tag :notification_level, Notification::N_DISABLED, notification.disabled?, id: dom_id(membership, 'notification_level'), class: 'trigger-submit'
- %span Disabled
-
- = label_tag nil, class: 'radio-inline' do
- = radio_button_tag :notification_level, Notification::N_PARTICIPATING, notification.participating?, id: dom_id(membership, 'notification_level'), class: 'trigger-submit'
- %span Participating
-
- = label_tag nil, class: 'radio-inline' do
- = radio_button_tag :notification_level, Notification::N_WATCH, notification.watch?, id: dom_id(membership, 'notification_level'), class: 'trigger-submit'
- %span Watch
+ %span.notification-icon-holder
+ - if notification.global?
+ = notification_icon(@notification)
+ - else
+ = notification_icon(notification)
+ %span.str-truncated
+ - if membership.kind_of? UsersGroup
+ = link_to membership.group.name, membership.group
+ - else
+ = link_to_project(membership.project)
+ .pull-right
+ = form_tag profile_notifications_path, method: :put, remote: true, class: 'update-notifications' do
+ = hidden_field_tag :notification_type, type, id: dom_id(membership, 'notification_type')
+ = hidden_field_tag :notification_id, membership.id, id: dom_id(membership, 'notification_id')
+ = select_tag :notification_level, options_for_select(Notification.options_with_labels, notification.level), class: 'trigger-submit'
diff --git a/app/views/profiles/notifications/show.html.haml b/app/views/profiles/notifications/show.html.haml
index 878d7f77430..efe9c032190 100644
--- a/app/views/profiles/notifications/show.html.haml
+++ b/app/views/profiles/notifications/show.html.haml
@@ -3,56 +3,49 @@
%p.light
GitLab uses the email specified in your profile for notifications
%hr
-.alert.alert-info
- %p
- %i.icon-circle.cred
- %strong Disabled
- &ndash; You will not get any notifications via email
- %p
- %i.icon-circle.cblue
- %strong Participating
- &ndash; You will only receive notifications from related resources (e.g. from your commits or assigned issues)
- %p
- %i.icon-circle.cgreen
- %strong Watch
- &ndash; You will receive all notifications from projects in which you participate
+= form_tag profile_notifications_path, method: :put, remote: true, class: 'update-notifications form-horizontal global-notifications-form' do
+ = hidden_field_tag :notification_type, 'global'
-.row
- .col-sm-4
- %h4
- = notification_icon(@notification)
- Global setting
- .col-sm-8
- = form_tag profile_notifications_path, method: :put, remote: true, class: 'update-notifications' do
- = hidden_field_tag :notification_type, 'global'
-
- = label_tag nil, class: 'radio-inline' do
+ = label_tag :notification_level, 'Notification level', class: 'control-label'
+ .col-sm-10
+ .radio
+ = label_tag nil, class: '' do
= radio_button_tag :notification_level, Notification::N_DISABLED, @notification.disabled?, class: 'trigger-submit'
- %span Disabled
+ .level-title
+ Disabled
+ %p You will not get any notifications via email
- = label_tag nil, class: 'radio-inline' do
+ .radio
+ = label_tag nil, class: '' do
= radio_button_tag :notification_level, Notification::N_PARTICIPATING, @notification.participating?, class: 'trigger-submit'
- %span Participating
+ .level-title
+ Participating
+ %p You will only receive notifications from related resources (e.g. from your commits or assigned issues)
- = label_tag nil, class: 'radio-inline' do
+ .radio
+ = label_tag nil, class: '' do
= radio_button_tag :notification_level, Notification::N_WATCH, @notification.watch?, class: 'trigger-submit'
- %span Watch
+ .level-title
+ Watch
+ %p You will receive all notifications from projects in which you participate
-%br
-= link_to '#', class: 'js-toggle-visibility-link' do
- %span.btn.btn-tiny
- %i.icon-chevron-down
- %span Advanced notifications settings
-.js-toggle-visibility-container.hide
+.clearfix
%hr
- %h4 Groups:
- %ul.bordered-list
- - @users_groups.each do |users_group|
- - notification = Notification.new(users_group)
- = render 'settings', type: 'group', membership: users_group, notification: notification
+ %p
+ You can also specify notification level per group or per project
+ %br
+ By default all projects and groups uses notification level set above
+.row.all-notifications
+ .col-md-6
+ %h4 Groups:
+ %ul.bordered-list
+ - @users_groups.each do |users_group|
+ - notification = Notification.new(users_group)
+ = render 'settings', type: 'group', membership: users_group, notification: notification
- %h4 Projects:
- %ul.bordered-list
- - @users_projects.each do |users_project|
- - notification = Notification.new(users_project)
- = render 'settings', type: 'project', membership: users_project, notification: notification
+ .col-md-6
+ %h4 Projects:
+ %ul.bordered-list
+ - @users_projects.each do |users_project|
+ - notification = Notification.new(users_project)
+ = render 'settings', type: 'project', membership: users_project, notification: notification
diff --git a/app/views/profiles/passwords/new.html.haml b/app/views/profiles/passwords/new.html.haml
index f333879cf6c..b72232ee36b 100644
--- a/app/views/profiles/passwords/new.html.haml
+++ b/app/views/profiles/passwords/new.html.haml
@@ -1,22 +1,22 @@
-= form_for @user, url: profile_password_path, method: :post do |f|
- .light-well.padded
- %p.slead
- Please set new password before proceed.
- %br
- After successful password update you will be redirected to login screen
- -if @user.errors.any?
- .alert.alert-danger
- %ul
- - @user.errors.full_messages.each do |msg|
- %li= msg
+%h3.page-title Setup new password
+%hr
+= form_for @user, url: profile_password_path, method: :post, html: { class: 'form-horizontal '} do |f|
+ %p.slead
+ Please set a new password before proceeding.
+ %br
+ After a successful password update you will be redirected to login screen.
+ -if @user.errors.any?
+ .alert.alert-danger
+ %ul
+ - @user.errors.full_messages.each do |msg|
+ %li= msg
- .form-group
- = f.label :password
- .col-sm-10= f.password_field :password, required: true
- .form-group
- = f.label :password_confirmation
- .col-sm-10
- = f.password_field :password_confirmation, required: true
- .form-group
- .col-sm-10
- = f.submit 'Set new password', class: "btn btn-create"
+ .form-group
+ = f.label :password, class: 'control-label'
+ .col-sm-10= f.password_field :password, required: true, class: 'form-control'
+ .form-group
+ = f.label :password_confirmation, class: 'control-label'
+ .col-sm-10
+ = f.password_field :password_confirmation, required: true, class: 'form-control'
+ .form-actions
+ = f.submit 'Set new password', class: "btn btn-create"
diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml
index 6ae1032aebf..523a07db400 100644
--- a/app/views/profiles/show.html.haml
+++ b/app/views/profiles/show.html.haml
@@ -47,6 +47,9 @@
= f.label :twitter, class: "control-label"
.col-sm-10= f.text_field :twitter, class: "form-control"
.form-group
+ = f.label :website_url, 'Website', class: "control-label"
+ .col-sm-10= f.text_field :website_url, class: "form-control"
+ .form-group
= f.label :bio, class: "control-label"
.col-sm-10
= f.text_area :bio, rows: 6, class: "form-control", maxlength: 250
diff --git a/app/views/projects/_settings_nav.html.haml b/app/views/projects/_settings_nav.html.haml
index e4cfabc3100..4c7b088ae9a 100644
--- a/app/views/projects/_settings_nav.html.haml
+++ b/app/views/projects/_settings_nav.html.haml
@@ -1,19 +1,21 @@
-%ul.nav.nav-pills.nav-stacked.nav-stacked-menu.append-bottom-20
+%ul.nav.nav-pills.nav-stacked.nav-stacked-menu.append-bottom-20.project-settings-nav
= nav_link(path: 'projects#edit') do
= link_to edit_project_path(@project), class: "stat-tab tab " do
- Edit Project
+ %i.icon-edit
+ Project
= nav_link(controller: [:team_members, :teams]) do
= link_to project_team_index_path(@project), class: "team-tab tab" do
+ %i.icon-group
Members
= nav_link(controller: :deploy_keys) do
= link_to project_deploy_keys_path(@project) do
- %span
+ %i.icon-key
Deploy Keys
= nav_link(controller: :hooks) do
= link_to project_hooks_path(@project) do
- %span
+ %i.icon-link
Web Hooks
= nav_link(controller: :services) do
= link_to project_services_path(@project) do
- %span
+ %i.icon-cogs
Services
diff --git a/app/views/projects/blob/_blob.html.haml b/app/views/projects/blob/_blob.html.haml
index 32ea967105a..e59d970bf46 100644
--- a/app/views/projects/blob/_blob.html.haml
+++ b/app/views/projects/blob/_blob.html.haml
@@ -15,6 +15,10 @@
- else
= link_to title, '#'
+%ul.blob-commit-info.bs-callout.bs-callout-info
+ - blob_commit = @repository.last_commit_for_path(@commit.id, @blob.path)
+ = render blob_commit, project: @project
+
%div#tree-content-holder.tree-content-holder
.file-holder
.file-title
diff --git a/app/views/projects/blob/_text.html.haml b/app/views/projects/blob/_text.html.haml
index d03b53888ae..7cbea7c3eb6 100644
--- a/app/views/projects/blob/_text.html.haml
+++ b/app/views/projects/blob/_text.html.haml
@@ -8,7 +8,6 @@
- else
.file-content.code
- unless blob.empty?
- %div{class: user_color_scheme_class}
- = raw blob.colorize(formatter: :gitlab)
+ = render 'shared/file_hljs', blob: blob
- else
- %p.nothing_here_message Empty file
+ .nothing-here-block Empty file
diff --git a/app/views/projects/blob/show.html.haml b/app/views/projects/blob/show.html.haml
index 56220e520f3..69167654c39 100644
--- a/app/views/projects/blob/show.html.haml
+++ b/app/views/projects/blob/show.html.haml
@@ -1,5 +1,6 @@
%div.tree-ref-holder
= render 'shared/ref_switcher', destination: 'blob', path: @path
+
%div#tree-holder.tree-holder
= render 'blob', blob: @blob
diff --git a/app/views/projects/branches/_branch.html.haml b/app/views/projects/branches/_branch.html.haml
index 4fd708517fc..f0731977098 100644
--- a/app/views/projects/branches/_branch.html.haml
+++ b/app/views/projects/branches/_branch.html.haml
@@ -1,4 +1,4 @@
-- commit = Commit.new(Gitlab::Git::Commit.new(branch.commit))
+- commit = @repository.commit(branch.target)
%li
%h4
= link_to project_commits_path(@project, branch.name) do
@@ -10,19 +10,24 @@
%i.icon-lock
.pull-right
- if can?(current_user, :download_code, @project)
- = render 'projects/repositories/download_archive', ref: branch.name, btn_class: 'grouped btn-group-small'
- = link_to project_compare_index_path(@project, from: branch.name, to: branch.name), class: 'btn grouped btn-small', title: "Compare" do
- %i.icon-copy
- Compare
+ = render 'projects/repositories/download_archive', ref: branch.name, btn_class: 'btn-grouped btn-group-small'
+ - if branch.name != @repository.root_ref
+ = link_to project_compare_index_path(@project, from: @repository.root_ref, to: branch.name), class: 'btn btn-grouped btn-small', method: :post, title: "Compare" do
+ %i.icon-copy
+ Compare
- if can?(current_user, :admin_project, @project) && branch.name != @repository.root_ref
- = link_to project_branch_path(@project, branch.name), class: 'btn grouped btn-small remove-row', method: :delete, data: { confirm: 'Removed branch cannot be restored. Are you sure?'}, remote: true do
+ = link_to project_branch_path(@project, branch.name), class: 'btn btn-grouped btn-small remove-row', method: :delete, data: { confirm: 'Removed branch cannot be restored. Are you sure?'}, remote: true do
%i.icon-trash
- %p
- = link_to project_commit_path(@project, commit.id), class: 'commit_short_id' do
- = commit.short_id
- = image_tag avatar_icon(commit.author_email), class: "avatar s16", alt: ''
- %span.light
- = gfm escape_once(truncate(commit.title, length: 40))
- #{time_ago_with_tooltip(commit.committed_date)}
+ - if commit
+ %p
+ = link_to project_commit_path(@project, commit.id), class: 'commit_short_id' do
+ = commit.short_id
+ = image_tag avatar_icon(commit.author_email), class: "avatar s16", alt: ''
+ %span.light
+ = gfm escape_once(truncate(commit.title, length: 40))
+ #{time_ago_with_tooltip(commit.committed_date)}
+ - else
+ %p
+ Cant find HEAD commit for this branch
diff --git a/app/views/projects/branches/index.html.haml b/app/views/projects/branches/index.html.haml
index 690df98a2ab..bee04eb013e 100644
--- a/app/views/projects/branches/index.html.haml
+++ b/app/views/projects/branches/index.html.haml
@@ -4,7 +4,7 @@
= render "filter"
.col-md-9
- unless @branches.empty?
- %ul.bordered-list.top-list
+ %ul.bordered-list.top-list.all-branches
- @branches.each do |branch|
= render "projects/branches/branch", branch: branch
= paginate @branches, theme: 'gitlab'
diff --git a/app/views/projects/branches/new.html.haml b/app/views/projects/branches/new.html.haml
index d173065afd2..5da2ede2937 100644
--- a/app/views/projects/branches/new.html.haml
+++ b/app/views/projects/branches/new.html.haml
@@ -5,12 +5,11 @@
.form-group
= label_tag :branch_name, 'Name for new branch', class: 'control-label'
.col-sm-10
- = text_field_tag :branch_name, nil, placeholder: 'feature/dashboard', required: true, tabindex: 1, class: 'form-control'
+ = text_field_tag :branch_name, nil, placeholder: 'enter new branch name', required: true, tabindex: 1, class: 'form-control'
.form-group
= label_tag :ref, 'Create from', class: 'control-label'
.col-sm-10
- = text_field_tag :ref, nil, placeholder: 'master', required: true, tabindex: 2, class: 'form-control'
- .light branch name or commit SHA
+ = text_field_tag :ref, nil, placeholder: 'existing branch name, tag or commit SHA', required: true, tabindex: 2, class: 'form-control'
.form-actions
= submit_tag 'Create branch', class: 'btn btn-create', tabindex: 3
= link_to 'Cancel', project_branches_path(@project), class: 'btn btn-cancel'
diff --git a/app/views/projects/commit/_commit_box.html.haml b/app/views/projects/commit/_commit_box.html.haml
index 3d666807cf9..df44c30c005 100644
--- a/app/views/projects/commit/_commit_box.html.haml
+++ b/app/views/projects/commit/_commit_box.html.haml
@@ -5,14 +5,14 @@
%i.icon-comment
= @notes_count
.pull-left.btn-group
- %a.btn.grouped.dropdown-toggle{ data: {toggle: :dropdown} }
+ %a.btn.btn-grouped.dropdown-toggle{ data: {toggle: :dropdown} }
%i.icon-download-alt
Download as
%span.caret
%ul.dropdown-menu
%li= link_to "Email Patches", project_commit_path(@project, @commit, format: :patch)
%li= link_to "Plain Diff", project_commit_path(@project, @commit, format: :diff)
- = link_to project_tree_path(@project, @commit), class: "btn btn-primary grouped" do
+ = link_to project_tree_path(@project, @commit), class: "btn btn-primary btn-grouped" do
%span Browse Code »
%div
diff --git a/app/views/projects/commits/_commit.html.haml b/app/views/projects/commits/_commit.html.haml
index 9772d3ef2ef..a0606662807 100644
--- a/app/views/projects/commits/_commit.html.haml
+++ b/app/views/projects/commits/_commit.html.haml
@@ -1,9 +1,12 @@
-%li.commit
+%li.commit.js-toggle-container
.commit-row-title
= link_to commit.short_id(8), project_commit_path(project, commit), class: "commit_short_id"
&nbsp;
%span.str-truncated
= link_to_gfm commit.title, project_commit_path(project, commit.id), class: "commit-row-message"
+ - if commit.description?
+ %a.text-expander.js-toggle-button ...
+
= link_to "Browse Code »", project_tree_path(project, commit), class: "pull-right"
.notes_count
- notes = project.notes.for_commit_id(commit.id)
@@ -12,6 +15,10 @@
%i.icon-comment
= notes.count
+ - if commit.description?
+ .commit-row-description.js-toggle-content
+ = simple_format(commit.description)
+
.commit-row-info
= commit_author_link(commit, avatar: true, size: 16)
.committed_ago
diff --git a/app/views/projects/commits/_diffs.html.haml b/app/views/projects/commits/_diffs.html.haml
index a41a89bb972..dd287fcc153 100644
--- a/app/views/projects/commits/_diffs.html.haml
+++ b/app/views/projects/commits/_diffs.html.haml
@@ -8,18 +8,18 @@
- if current_controller?(:commit) or current_controller?(:merge_requests)
Please, download the diff as
- if current_controller?(:commit)
- = link_to "plain diff", project_commit_path(@project, @commit, format: :diff), class: "underlined_link"
+ = link_to "plain diff", project_commit_path(@project, @commit, format: :diff), class: "underlined-link"
or
- = link_to "email patch", project_commit_path(@project, @commit, format: :patch), class: "underlined_link"
+ = link_to "email patch", project_commit_path(@project, @commit, format: :patch), class: "underlined-link"
- else
- = link_to "plain diff", project_merge_request_path(@project, @merge_request, format: :diff), class: "underlined_link"
+ = link_to "plain diff", project_merge_request_path(@project, @merge_request, format: :diff), class: "underlined-link"
or
- = link_to "email patch", project_merge_request_path(@project, @merge_request, format: :patch), class: "underlined_link"
+ = link_to "email patch", project_merge_request_path(@project, @merge_request, format: :patch), class: "underlined-link"
instead.
- unless @force_suppress_diff
%p
If you still want to see the diff
- = link_to "click this link", url_for(force_show_diff: true), class: "underlined_link"
+ = link_to "click this link", url_for(force_show_diff: true), class: "underlined-link"
%p.commit-stat-summary
Showing
@@ -44,25 +44,33 @@
- file = project.repository.blob_at(@commit.id, diff.new_path)
- file = project.repository.blob_at(@commit.parent_id, diff.old_path) unless file
- next unless file
- .file{id: "diff-#{i}"}
- .header
+ .diff-file{id: "diff-#{i}"}
+ .diff-header{id: "file-path-#{hexdigest(diff.new_path || diff.old_path)}"}
- if diff.deleted_file
%span= diff.old_path
- - if @commit.parent_ids.present?
- = link_to project_blob_path(project, tree_join(@commit.parent_id, diff.new_path)), { class: 'btn btn-small view-file' } do
- View file @
- %span.commit-short-id= @commit.short_id(6)
+ .diff-btn-group
+ - if @commit.parent_ids.present?
+ = link_to project_blob_path(project, tree_join(@commit.parent_id, diff.new_path)), { class: 'btn btn-small view-file' } do
+ View file @
+ %span.commit-short-id= @commit.short_id(6)
- else
%span= diff.new_path
- if diff.a_mode && diff.b_mode && diff.a_mode != diff.b_mode
%span.file-mode= "#{diff.a_mode} → #{diff.b_mode}"
- = link_to project_blob_path(project, tree_join(@commit.id, diff.new_path)), { class: 'btn btn-small view-file' } do
- View file @
- %span.commit-short-id= @commit.short_id(6)
+ .diff-btn-group
+ - if @merge_request && @merge_request.source_project
+ = link_to project_edit_tree_path(@merge_request.source_project, tree_join(@merge_request.source_branch, diff.new_path), from_merge_request_id: @merge_request.id), { class: 'btn btn-small' } do
+ Edit
+ &nbsp;
+
+ = link_to project_blob_path(project, tree_join(@commit.id, diff.new_path)), { class: 'btn btn-small view-file' } do
+ View file @
+ %span.commit-short-id= @commit.short_id(6)
+
- .content
+ .diff-content
-# Skipp all non non-supported blobs
- next unless file.respond_to?('text?')
- if file.text?
@@ -74,4 +82,4 @@
- old_file = project.repository.blob_at(@commit.parent_id, diff.old_path) if @commit.parent_id
= render "projects/commits/image", diff: diff, old_file: old_file, file: file, index: i
- else
- %p.nothing_here_message No preview for this file type
+ .nothing-here-block No preview for this file type
diff --git a/app/views/projects/commits/_head.html.haml b/app/views/projects/commits/_head.html.haml
index b9ab27d212c..81e33743911 100644
--- a/app/views/projects/commits/_head.html.haml
+++ b/app/views/projects/commits/_head.html.haml
@@ -1,4 +1,4 @@
-%ul.nav.nav-tabs.append-bottom-15
+%ul.nav.nav-tabs
%li= render partial: 'shared/ref_switcher', locals: {destination: 'commits'}
= nav_link(controller: [:commit, :commits]) do
diff --git a/app/views/projects/commits/_image.html.haml b/app/views/projects/commits/_image.html.haml
index 9a8b7c857e5..6d9ef5964d9 100644
--- a/app/views/projects/commits/_image.html.haml
+++ b/app/views/projects/commits/_image.html.haml
@@ -15,7 +15,7 @@
%span.meta-filesize= "#{number_to_human_size old_file.size}"
|
%b W:
- %span.meta-width
+ %span.meta-width
|
%b H:
%span.meta-height
@@ -27,7 +27,7 @@
%span.meta-filesize= "#{number_to_human_size file.size}"
|
%b W:
- %span.meta-width
+ %span.meta-width
|
%b H:
%span.meta-height
@@ -49,7 +49,7 @@
%img{src: "data:#{old_file.mime_type};base64,#{Base64.encode64(old_file.data)}"}
.frame.added
%img{src: "data:#{file.mime_type};base64,#{Base64.encode64(file.data)}"}
- .col-sm-10
+ .controls
.transparent
.drag-track
.dragger{:style => "left: 0px;"}
diff --git a/app/views/projects/commits/_inline_commit.html.haml b/app/views/projects/commits/_inline_commit.html.haml
index f5863463fee..b36369b4285 100644
--- a/app/views/projects/commits/_inline_commit.html.haml
+++ b/app/views/projects/commits/_inline_commit.html.haml
@@ -2,5 +2,7 @@
.commit-row-title
= link_to commit.short_id(8), project_commit_path(project, commit), class: "commit_short_id"
&nbsp;
- = link_to_gfm truncate(commit.title, length: 40), project_commit_path(project, commit.id), class: "commit-row-message"
- #{time_ago_with_tooltip(commit.committed_date)} &nbsp;
+ %span.str-truncated
+ = link_to_gfm commit.title, project_commit_path(project, commit.id), class: "commit-row-message"
+ .pull-right
+ #{time_ago_with_tooltip(commit.committed_date)}
diff --git a/app/views/projects/commits/show.html.haml b/app/views/projects/commits/show.html.haml
index 723c5a1c340..3a4f304a255 100644
--- a/app/views/projects/commits/show.html.haml
+++ b/app/views/projects/commits/show.html.haml
@@ -9,7 +9,7 @@
%div{id: dom_id(@project)}
#commits-list= render "commits"
.clear
-.loading{ style: "display:none;"}
+= spinner
- if @commits.count == @limit
:javascript
diff --git a/app/views/projects/compare/_form.html.haml b/app/views/projects/compare/_form.html.haml
index 0762655fb93..da6157cf1b6 100644
--- a/app/views/projects/compare/_form.html.haml
+++ b/app/views/projects/compare/_form.html.haml
@@ -14,7 +14,7 @@
&nbsp;
= submit_tag "Compare", class: "btn btn-create commits-compare-btn"
- if compare_to_mr_button?
- = link_to compare_mr_path, class: 'prepend-left-10' do
+ = link_to compare_mr_path, class: 'prepend-left-10 btn' do
%strong Make a merge request
diff --git a/app/views/projects/compare/show.html.haml b/app/views/projects/compare/show.html.haml
index e9456c24960..9bd49855369 100644
--- a/app/views/projects/compare/show.html.haml
+++ b/app/views/projects/compare/show.html.haml
@@ -5,21 +5,32 @@
= render "form"
-- if @commits.size > 100
- .alert.alert-warning
- %p
- %strong Warning! This comparison includes more than 100 commits.
- %p To preserve performance the line diff is not shown.
-
- if @commits.present?
%div.ui-box
.title
Commits (#{@commits.count})
- %ul.well-list= render Commit.decorate(@commits), project: @project
+ - if @commits.size > MergeRequestDiff::COMMITS_SAFE_SIZE
+ %ul.well-list
+ - Commit.decorate(@commits.first(MergeRequestDiff::COMMITS_SAFE_SIZE)).each do |commit|
+ = render "projects/commits/inline_commit", commit: commit, project: @project
+ %li.warning-row.unstyled
+ other #{@commits.size - MergeRequestDiff::COMMITS_SAFE_SIZE} commits hidden to prevent performance issues.
+ - else
+ %ul.well-list= render Commit.decorate(@commits), project: @project
- - unless @diffs.empty?
- %h4 Diff
+ %h4 Diff
+ - if @diffs.present?
= render "projects/commits/diffs", diffs: @diffs, project: @project
+ - elsif @commits.size > MergeRequestDiff::COMMITS_SAFE_SIZE
+ .bs-callout.bs-callout-danger
+ %h4 This comparison includes more than #{MergeRequestDiff::COMMITS_SAFE_SIZE} commits.
+ %p To preserve performance the line diff is not shown.
+ - elsif @timeout
+ .bs-callout.bs-callout-danger
+ %h4 Diff for this comparison is extremely large.
+ %p Use command line to browse diff for this comparison.
+
+
- else
.light-well
%center
diff --git a/app/views/projects/deploy_keys/index.html.haml b/app/views/projects/deploy_keys/index.html.haml
index 90d86102aca..f50aeba337a 100644
--- a/app/views/projects/deploy_keys/index.html.haml
+++ b/app/views/projects/deploy_keys/index.html.haml
@@ -20,7 +20,7 @@
= render @enabled_keys
- if @enabled_keys.blank?
.light-well
- %p.nothing_here_message Create a #{link_to 'new deploy key', new_project_deploy_key_path(@project)} or add an existing one
+ .nothing-here-block Create a #{link_to 'new deploy key', new_project_deploy_key_path(@project)} or add an existing one
.col-md-6.available-keys
%h5
%strong Deploy keys
@@ -29,4 +29,4 @@
= render @available_keys
- if @available_keys.blank?
.light-well
- %p.nothing_here_message Deploy keys from projects you have access to will be displayed here
+ .nothing-here-block Deploy keys from projects you have access to will be displayed here
diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml
index 79234fe4fa9..005d994806e 100644
--- a/app/views/projects/edit.html.haml
+++ b/app/views/projects/edit.html.haml
@@ -93,10 +93,11 @@
- %center.light.prepend-top-20.padded
+ .centered-light-block
%h3
%i.icon-warning-sign
Dangerous settings
+
%p Project settings below may result in data loss!
= link_to '#', class: 'btn js-toggle-visibility-link' do
Show it to me
@@ -132,7 +133,7 @@
data: { confirm: "Are you sure that you want to archive this project?\nAn archived project cannot be committed to." },
method: :post, class: "btn btn-remove"
- else
- %p.nothing_here_message Only the project owner can archive a project
+ .nothing-here-block Only the project owner can archive a project
- if can?(current_user, :change_namespace, @project)
.ui-box.ui-box-danger
@@ -153,7 +154,7 @@
.form-actions
= f.submit 'Transfer', class: "btn btn-remove"
- else
- %p.nothing_here_message Only the project owner can transfer a project
+ .nothing-here-block Only the project owner can transfer a project
.ui-box.ui-box-danger
.title Rename repository
@@ -185,10 +186,11 @@
= link_to 'Remove project', @project, data: { confirm: remove_project_message(@project) }, method: :delete, class: "btn btn-remove"
- else
- %p.nothing_here_message Only project owner can remove a project
+ .nothing-here-block Only project owner can remove a project
.save-project-loader.hide
%center
- = image_tag "ajax_loader.gif"
- %h3 Saving project.
+ %h2
+ %i.icon-spinner.icon-spin
+ Saving project.
%p Please wait a moment, this page will automatically refresh when ready.
diff --git a/app/views/projects/edit_tree/show.html.haml b/app/views/projects/edit_tree/show.html.haml
index 10dae3c8ff0..3f2e98f3a7f 100644
--- a/app/views/projects/edit_tree/show.html.haml
+++ b/app/views/projects/edit_tree/show.html.haml
@@ -11,7 +11,7 @@
%strong= @ref
%span.options
.btn-group.tree-btn-group
- = link_to "Cancel", project_blob_path(@project, @id), class: "btn btn-tiny btn-cancel", data: { confirm: leave_edit_message }
+ = link_to "Cancel", @after_edit_path, class: "btn btn-tiny btn-cancel", data: { confirm: leave_edit_message }
.file-content.code
%pre#editor= @blob.data
@@ -23,15 +23,16 @@
.form-actions
= hidden_field_tag 'last_commit', @last_commit
= hidden_field_tag 'content', '', id: "file-content"
+ = hidden_field_tag 'from_merge_request_id', params[:from_merge_request_id]
.commit-button-annotation
= button_tag "Commit changes", class: 'btn commit-btn js-commit-button btn-primary'
.message
to branch
%strong= @ref
- = link_to "Cancel", project_blob_path(@project, @id), class: "btn btn-cancel", data: { confirm: leave_edit_message}
+ = link_to "Cancel", @after_edit_path, class: "btn btn-cancel", data: { confirm: leave_edit_message}
:javascript
- ace.config.set("modePath", gon.relative_url_root + "#{Gitlab::Application.config.assets.prefix}/ace-src-noconflict")
+ ace.config.set("modePath", gon.relative_url_root + "#{Gitlab::Application.config.assets.prefix}/ace")
var ace_mode = "#{@blob.language.try(:ace_mode)}";
var editor = ace.edit("editor");
if (ace_mode) {
diff --git a/app/views/projects/empty.html.haml b/app/views/projects/empty.html.haml
index eae4949fcd3..489b9b0e951 100644
--- a/app/views/projects/empty.html.haml
+++ b/app/views/projects/empty.html.haml
@@ -3,8 +3,9 @@
- if @project.import? && !@project.imported
.save-project-loader
%center
- = image_tag "ajax_loader.gif"
- %h3 Importing repository.
+ %h2
+ %i.icon-spinner.icon-spin
+ Importing repository.
%p.monospace git clone --bare #{@project.import_url}
%p Please wait while we import the repository for you. Refresh at will.
:javascript
diff --git a/app/views/projects/graphs/show.html.haml b/app/views/projects/graphs/show.html.haml
index a21cb9e7861..27348232ba2 100644
--- a/app/views/projects/graphs/show.html.haml
+++ b/app/views/projects/graphs/show.html.haml
@@ -1,7 +1,8 @@
.loading-graph
%center
- .loading
- %h3.page-title Building repository graph.
+ %h3.page-title
+ %i.icon-spinner.icon-spin
+ Building repository graph.
%p Please wait a moment, this page will automatically refresh when ready.
.stat-graph
diff --git a/app/views/projects/hooks/index.html.haml b/app/views/projects/hooks/index.html.haml
index a095fd06d2f..00e5ae27779 100644
--- a/app/views/projects/hooks/index.html.haml
+++ b/app/views/projects/hooks/index.html.haml
@@ -51,8 +51,8 @@
- @hooks.each do |hook|
%li
.pull-right
- = link_to 'Test Hook', test_project_hook_path(@project, hook), class: "btn btn-small grouped"
- = link_to 'Remove', project_hook_path(@project, hook), data: { confirm: 'Are you sure?'}, method: :delete, class: "btn btn-remove btn-small grouped"
+ = link_to 'Test Hook', test_project_hook_path(@project, hook), class: "btn btn-small btn-grouped"
+ = link_to 'Remove', project_hook_path(@project, hook), data: { confirm: 'Are you sure?'}, method: :delete, class: "btn btn-remove btn-small btn-grouped"
.clearfix
%span.monospace= hook.url
%p
diff --git a/app/views/projects/issues/_form.html.haml b/app/views/projects/issues/_form.html.haml
index c95e8178594..dd091302c8e 100644
--- a/app/views/projects/issues/_form.html.haml
+++ b/app/views/projects/issues/_form.html.haml
@@ -1,6 +1,10 @@
%div.issue-form-holder
%h3.page-title= @issue.new_record? ? "New Issue" : "Edit Issue ##{@issue.iid}"
%hr
+ - if @repository.contribution_guide && !@issue.persisted?
+ - contribution_guide_url = project_blob_path(@project, tree_join(@repository.root_ref, @repository.contribution_guide.name))
+ .alert.alert-info.col-sm-10.col-sm-offset-2
+ ="Please review the <strong>#{link_to "guidelines for contribution", contribution_guide_url}</strong> to this repository.".html_safe
= form_for [@project, @issue], html: { class: 'form-horizontal issue-form' } do |f|
-if @issue.errors.any?
.alert.alert-danger
@@ -24,7 +28,7 @@
%i.icon-user
Assign to
.col-sm-10
- = f.select(:assignee_id, assignee_options(@issue), { include_blank: "Select a user" }, {class: 'select2'})
+ = project_users_select_tag('issue[assignee_id]', placeholder: 'Select a user', class: 'custom-form-control', selected: @issue.assignee_id)
&nbsp;
= link_to 'Assign to me', '#', class: 'btn btn-small assign-to-me-link'
.form-group
diff --git a/app/views/projects/issues/_head.html.haml b/app/views/projects/issues/_head.html.haml
index 36549aae7d3..0b7697622b0 100644
--- a/app/views/projects/issues/_head.html.haml
+++ b/app/views/projects/issues/_head.html.haml
@@ -1,4 +1,4 @@
-%ul.nav.nav-tabs.append-bottom-15
+%ul.nav.nav-tabs
= nav_link(controller: :issues) do
= link_to project_issues_path(@project), class: "tab" do
Browse Issues
@@ -17,10 +17,10 @@
%li.pull-right
.pull-right
- = form_tag project_issues_path(@project), method: :get, id: "issue_search_form", class: 'inline issue-search-form' do
+ = form_tag project_issues_path(@project), method: :get, id: "issue_search_form", class: 'pull-left issue-search-form' do
.append-right-10.hidden-xs.hidden-sm
- = search_field_tag :issue_search, nil, { placeholder: 'Filter by title or description', class: 'form-control issue_search search-text-input' }
+ = search_field_tag :issue_search, nil, { placeholder: 'Filter by title or description', class: 'form-control issue_search search-text-input input-mn-300' }
- if can? current_user, :write_issue, @project
- = link_to new_project_issue_path(@project, issue: { assignee_id: params[:assignee_id], milestone_id: params[:milestone_id]}), class: "btn btn-new", title: "New Issue", id: "new_issue_link" do
+ = link_to new_project_issue_path(@project, issue: { assignee_id: params[:assignee_id], milestone_id: params[:milestone_id]}), class: "btn btn-new pull-left", title: "New Issue", id: "new_issue_link" do
%i.icon-plus
New Issue
diff --git a/app/views/projects/issues/_issue.html.haml b/app/views/projects/issues/_issue.html.haml
index 1bd93b774f1..3fc04c26cf2 100644
--- a/app/views/projects/issues/_issue.html.haml
+++ b/app/views/projects/issues/_issue.html.haml
@@ -38,10 +38,10 @@
.issue-actions
- if can? current_user, :modify_issue, issue
- if issue.closed?
- = link_to 'Reopen', project_issue_path(issue.project, issue, issue: {state_event: :reopen }, status_only: true), method: :put, class: "btn btn-small grouped reopen_issue", remote: true
+ = link_to 'Reopen', project_issue_path(issue.project, issue, issue: {state_event: :reopen }, status_only: true), method: :put, class: "btn btn-small btn-grouped reopen_issue", remote: true
- else
- = link_to 'Close', project_issue_path(issue.project, issue, issue: {state_event: :close }, status_only: true), method: :put, class: "btn btn-small grouped close_issue", remote: true
- = link_to edit_project_issue_path(issue.project, issue), class: "btn btn-small edit-issue-link grouped" do
+ = link_to 'Close', project_issue_path(issue.project, issue, issue: {state_event: :close }, status_only: true), method: :put, class: "btn btn-small btn-grouped close_issue", remote: true
+ = link_to edit_project_issue_path(issue.project, issue), class: "btn btn-small edit-issue-link btn-grouped" do
%i.icon-edit
Edit
diff --git a/app/views/projects/issues/_issue_context.html.haml b/app/views/projects/issues/_issue_context.html.haml
index 7ddf470b6a0..aae101cf40f 100644
--- a/app/views/projects/issues/_issue_context.html.haml
+++ b/app/views/projects/issues/_issue_context.html.haml
@@ -1,25 +1,22 @@
= form_for [@project, @issue], remote: true, html: {class: 'edit-issue inline-update'} do |f|
- Created by #{link_to_member(@project, issue.author)}&nbsp;
- - if issue.assignee
- \ and currently assigned to
+ %strong.append-right-10
+ Assignee:
- if can?(current_user, :modify_issue, @issue)
- = link_to profile_path(issue.assignee) do
- = image_tag(avatar_icon(issue.assignee.email), class: 'avatar avatar-inline s16 assignee') if issue.assignee
- = f.select(:assignee_id, assignee_options(@issue), { include_blank: "Assign to user (none):" }, {class: 'select2'})
+ = project_users_select_tag('issue[assignee_id]', placeholder: 'Select assignee', class: 'custom-form-control', selected: @issue.assignee_id)
- elsif issue.assignee
= link_to_member(@project, @issue.assignee)
+ - else
+ None
-
- .pull-right.hidden-sm
- - if issue.milestone
- - milestone = issue.milestone
- %cite.cgray Attached to milestone
-
+ .pull-right
+ %strong.append-right-10
+ Milestone:
- if can?(current_user, :modify_issue, @issue)
= f.select(:milestone_id, milestone_options(@issue), { include_blank: "Select milestone (none):" }, {class: 'select2 select2-compact'})
-
= hidden_field_tag :issue_context
= f.submit class: 'btn'
- elsif issue.milestone
= link_to issue.milestone.title, project_milestone_path
+ - else
+ None
diff --git a/app/views/projects/issues/_issues.html.haml b/app/views/projects/issues/_issues.html.haml
index e2ce26feac3..3b5e398c327 100644
--- a/app/views/projects/issues/_issues.html.haml
+++ b/app/views/projects/issues/_issues.html.haml
@@ -1,112 +1,72 @@
-.ui-box
- .title
+.append-bottom-10
+ .check-all-holder
= check_box_tag "check_all_issues", nil, false, class: "check_all_issues left"
- .clearfix
- .issues_bulk_update.hide
- = form_tag bulk_update_project_issues_path(@project), method: :post do
- %span Update selected issues with &nbsp;
- = select_tag('update[status]', options_for_select(['open', 'closed']), prompt: "Status")
- = select_tag('update[assignee_id]', bulk_update_assignee_options, prompt: "Assignee")
- = select_tag('update[milestone_id]', bulk_update_milestone_options, prompt: "Milestone")
- = hidden_field_tag 'update[issues_ids]', []
- = hidden_field_tag :status, params[:status]
- = button_tag "Save", class: "btn update_selected_issues btn-small btn-save"
- .issues-filters
- %span Filter by
- .dropdown.inline.prepend-left-10
- %a.dropdown-toggle.btn.btn-small{href: '#', "data-toggle" => "dropdown"}
- %i.icon-tags
- %span.light labels:
- - if params[:label_name].present?
- %strong= params[:label_name]
- - else
- Any
- %b.caret
- %ul.dropdown-menu
- %li
- = link_to project_filter_path(label_name: nil) do
- Any
- - issue_label_names.each do |label_name|
- %li
- = link_to project_filter_path(label_name: label_name) do
- %span{class: "label #{label_css_class(label_name)}"}
- %i.icon-tag
- = label_name
- .dropdown.inline.prepend-left-10
- %a.dropdown-toggle.btn.btn-small{href: '#', "data-toggle" => "dropdown"}
- %i.icon-user
- %span.light assignee:
- - if @assignee.present?
- %strong= @assignee.name
- - elsif params[:assignee_id] == "0"
- Unassigned
- - else
- Any
- %b.caret
- %ul.dropdown-menu
- %li
- = link_to project_filter_path(assignee_id: nil) do
- Any
- = link_to project_filter_path(assignee_id: 0) do
- Unassigned
- - @project.team.members.sort_by(&:name).each do |user|
- %li
- = link_to project_filter_path(assignee_id: user.id) do
- = image_tag avatar_icon(user.email), class: "avatar s16", alt: ''
- = user.name
+ .issues-filters
+ .dropdown.inline
+ %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
+ %i.icon-user
+ %span.light assignee:
+ - if @assignee.present?
+ %strong= @assignee.name
+ - elsif params[:assignee_id] == "0"
+ Unassigned
+ - else
+ Any
+ %b.caret
+ %ul.dropdown-menu
+ %li
+ = link_to project_filter_path(assignee_id: nil) do
+ Any
+ = link_to project_filter_path(assignee_id: 0) do
+ Unassigned
+ - @assignees.sort_by(&:name).each do |user|
+ %li
+ = link_to project_filter_path(assignee_id: user.id) do
+ = image_tag avatar_icon(user.email), class: "avatar s16", alt: ''
+ = user.name
- .dropdown.inline.prepend-left-10
- %a.dropdown-toggle.btn.btn-small{href: '#', "data-toggle" => "dropdown"}
- %i.icon-time
- %span.light milestone:
- - if @milestone.present?
- %strong= @milestone.title
- - elsif params[:milestone_id] == "0"
- None (backlog)
- - else
- Any
- %b.caret
- %ul.dropdown-menu
- %li
- = link_to project_filter_path(milestone_id: nil) do
- Any
- = link_to project_filter_path(milestone_id: 0) do
- None (backlog)
- - project_active_milestones.each do |milestone|
- %li
- = link_to project_filter_path(milestone_id: milestone.id) do
- %strong= milestone.title
- %small.light= milestone.expires_at
+ .dropdown.inline.prepend-left-10
+ %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
+ %i.icon-time
+ %span.light milestone:
+ - if @milestone.present?
+ %strong= @milestone.title
+ - elsif params[:milestone_id] == "0"
+ None (backlog)
+ - else
+ Any
+ %b.caret
+ %ul.dropdown-menu
+ %li
+ = link_to project_filter_path(milestone_id: nil) do
+ Any
+ = link_to project_filter_path(milestone_id: 0) do
+ None (backlog)
+ - project_active_milestones.each do |milestone|
+ %li
+ = link_to project_filter_path(milestone_id: milestone.id) do
+ %strong= milestone.title
+ %small.light= milestone.expires_at
- .dropdown.inline.prepend-left-10
- %a.dropdown-toggle.btn.btn-small{href: '#', "data-toggle" => "dropdown"}
- %span.light sort:
- - if @sort.present?
- = @sort
- - else
- Newest
- %b.caret
- %ul.dropdown-menu
- %li
- = link_to project_filter_path(sort: 'newest') do
- Newest
- = link_to project_filter_path(sort: 'oldest') do
- Oldest
- = link_to project_filter_path(sort: 'recently_updated') do
- Recently updated
- = link_to project_filter_path(sort: 'last_updated') do
- Last updated
- = link_to project_filter_path(sort: 'milestone_due_soon') do
- Milestone due soon
- = link_to project_filter_path(sort: 'milestone_due_later') do
- Milestone due later
+ .pull-right
+ = render 'shared/sort_dropdown'
+ .clearfix
+ .issues_bulk_update.hide
+ = form_tag bulk_update_project_issues_path(@project), method: :post do
+ = select_tag('update[status]', options_for_select(['Open', 'Closed']), prompt: "Status")
+ = project_users_select_tag('update[assignee_id]', placeholder: 'Assignee')
+ = select_tag('update[milestone_id]', bulk_update_milestone_options, prompt: "Milestone")
+ = hidden_field_tag 'update[issues_ids]', []
+ = hidden_field_tag :status, params[:status]
+ = button_tag "Update issues", class: "btn update_selected_issues btn-save"
+.ui-box
%ul.well-list.issues-list
= render @issues
- if @issues.blank?
%li
- %h4.nothing_here_message No issues to show
+ .nothing-here-block No issues to show
- if @issues.present?
.pull-right
diff --git a/app/views/projects/issues/index.html.haml b/app/views/projects/issues/index.html.haml
index 71a89af61a2..5e899d412c6 100644
--- a/app/views/projects/issues/index.html.haml
+++ b/app/views/projects/issues/index.html.haml
@@ -1,6 +1,6 @@
= render "head"
.row
.col-md-3
- = render 'shared/project_filter', project_entities_path: project_issues_path(@project)
+ = render 'shared/project_filter', project_entities_path: project_issues_path(@project), labels: true
.col-md-9.issues-holder
= render "issues"
diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml
index cd4a158e427..124eb53571d 100644
--- a/app/views/projects/issues/show.html.haml
+++ b/app/views/projects/issues/show.html.haml
@@ -1,26 +1,18 @@
%h3.page-title
Issue ##{@issue.iid}
- %small
- created #{time_ago_with_tooltip(@issue.created_at)}
-
- - if @issue.closed?
- %span.state-label.state-label-red Closed
- - else
- %span.state-label.state-label-green Open
-
%span.pull-right
- if can?(current_user, :write_issue, @project)
- = link_to new_project_issue_path(@project), class: "btn grouped", title: "New Issue", id: "new_issue_link" do
+ = link_to new_project_issue_path(@project), class: "btn btn-grouped", title: "New Issue", id: "new_issue_link" do
%i.icon-plus
New Issue
- if can?(current_user, :modify_issue, @issue)
- if @issue.closed?
- = link_to 'Reopen', project_issue_path(@project, @issue, issue: {state_event: :reopen }, status_only: true), method: :put, class: "btn grouped reopen_issue"
+ = link_to 'Reopen', project_issue_path(@project, @issue, issue: {state_event: :reopen }, status_only: true), method: :put, class: "btn btn-grouped btn-reopen"
- else
- = link_to 'Close', project_issue_path(@project, @issue, issue: {state_event: :close }, status_only: true), method: :put, class: "btn grouped close_issue", title: "Close Issue"
+ = link_to 'Close', project_issue_path(@project, @issue, issue: {state_event: :close }, status_only: true), method: :put, class: "btn btn-grouped btn-close", title: "Close Issue"
- = link_to edit_project_issue_path(@project, @issue), class: "btn grouped" do
+ = link_to edit_project_issue_path(@project, @issue), class: "btn btn-grouped" do
%i.icon-edit
Edit
@@ -37,26 +29,36 @@
= link_to project_milestone_path(@project, @issue.milestone) do
= @issue.milestone.title
-.issue-box
+.issue-box{ class: issue_box_class(@issue) }
+ .state
+ %span.state-label
+ - if @issue.closed?
+ Closed
+ - else
+ Open
+
+ %span.creator
+ Created by #{link_to_member(@project, @issue.author)} #{time_ago_with_tooltip(@issue.created_at)}
+
%h4.title
= gfm escape_once(@issue.title)
- .context
- %cite.cgray
- = render partial: 'issue_context', locals: { issue: @issue }
-
- if @issue.description.present?
.description
.wiki
= preserve do
= markdown @issue.description
+ .context
+ %cite.cgray
+ = render partial: 'issue_context', locals: { issue: @issue }
+
- content_for :note_actions do
- if can?(current_user, :modify_issue, @issue)
- if @issue.closed?
- = link_to 'Reopen Issue', project_issue_path(@project, @issue, issue: {state_event: :reopen }, status_only: true), method: :put, class: "btn grouped reopen_issue"
+ = link_to 'Reopen Issue', project_issue_path(@project, @issue, issue: {state_event: :reopen }, status_only: true), method: :put, class: "btn btn-grouped btn-reopen"
- else
- = link_to 'Close Issue', project_issue_path(@project, @issue, issue: {state_event: :close }, status_only: true), method: :put, class: "btn grouped close_issue", title: "Close Issue"
+ = link_to 'Close Issue', project_issue_path(@project, @issue, issue: {state_event: :close }, status_only: true), method: :put, class: "btn btn-grouped btn-close", title: "Close Issue"
.participants
%cite.cgray #{@issue.participants.count} participants
diff --git a/app/views/projects/issues/update.js.haml b/app/views/projects/issues/update.js.haml
index 59524e0f224..5199e9fc61f 100644
--- a/app/views/projects/issues/update.js.haml
+++ b/app/views/projects/issues/update.js.haml
@@ -3,10 +3,7 @@
:plain
$("##{dom_id(@issue)}").fadeOut();
- elsif params[:issue_context]
- $('.issue-box .context').html("#{escape_javascript(render partial: 'issue_context', locals: { issue: @issue })}");
$('.issue-box .context').effect('highlight');
- $('.select2').select2();
- $('.edit-issue.inline-update input[type="submit"]').hide();
- if @issue.milestone
$('.milestone-nav-link').replaceWith("<span class='milestone-nav-link'>| <span class='light'>Milestone</span> #{escape_javascript(link_to @issue.milestone.title, project_milestone_path(@issue.project, @issue.milestone))}</span>")
- else
diff --git a/app/views/projects/labels/index.html.haml b/app/views/projects/labels/index.html.haml
index a058d09a1ce..329cf9ceba8 100644
--- a/app/views/projects/labels/index.html.haml
+++ b/app/views/projects/labels/index.html.haml
@@ -7,4 +7,4 @@
- else
.light-well
- %h3.nothing_here_message Add first label to your issues or #{link_to 'generate', generate_project_labels_path(@project), method: :post} default set of labels
+ .nothing-here-block Add first label to your issues or #{link_to 'generate', generate_project_labels_path(@project), method: :post} default set of labels
diff --git a/app/views/projects/merge_requests/_form.html.haml b/app/views/projects/merge_requests/_form.html.haml
index 67cb5ccd72d..51fa29ddcbe 100644
--- a/app/views/projects/merge_requests/_form.html.haml
+++ b/app/views/projects/merge_requests/_form.html.haml
@@ -1,3 +1,7 @@
+- if @repository.contribution_guide && !@merge_request.persisted?
+ - contribution_guide_url = project_blob_path(@project, tree_join(@repository.root_ref, @repository.contribution_guide.name))
+ .alert.alert-info.col-sm-10.col-sm-offset-2
+ ="Please review the <strong>#{link_to "guidelines for contribution", contribution_guide_url}</strong> to this repository.".html_safe
= form_for [@project, @merge_request], html: { class: "merge-request-form form-horizontal" } do |f|
-if @merge_request.errors.any?
.alert.alert-danger
@@ -6,27 +10,30 @@
%li= msg
.merge-request-branches
- .row
- .col-md-5
+ .form-group
+ = label_tag nil, class: 'control-label' do
+ From
+ .col-sm-10
.clearfix
.pull-left
= f.select(:source_project_id, [[@merge_request.source_project_path,@merge_request.source_project.id]] , {}, { class: 'source_project select2 span3', disabled: @merge_request.persisted? })
.pull-left
&nbsp;
- = f.select(:source_branch, @merge_request.source_project.repository.branch_names, { include_blank: "Select branch" }, {class: 'source_branch select2 span2'})
- .mr_source_commit.prepend-top-10
- .col-md-2
- .merge-request-angle
- %i.icon-long-arrow-right
- .col-md-5
+ = f.select(:source_branch, @merge_request.source_branches, { include_blank: "Select branch" }, {class: 'source_branch select2 span2'})
+ .mr_source_commit
+ %br
+ .form-group
+ = label_tag nil, class: 'control-label' do
+ To
+ .col-sm-10
.clearfix
.pull-left
- projects = @project.forked_from_project.nil? ? [@project] : [ @project,@project.forked_from_project]
- = f.select(:target_project_id, options_from_collection_for_select(projects, 'id', 'path_with_namespace'), {}, { class: 'target_project select2 span3', disabled: @merge_request.persisted? })
+ = f.select(:target_project_id, options_from_collection_for_select(projects, 'id', 'path_with_namespace', f.object.target_project_id), {}, { class: 'target_project select2 span3', disabled: @merge_request.persisted? })
.pull-left
&nbsp;
- = f.select(:target_branch, @target_branches, { include_blank: "Select branch" }, {class: 'target_branch select2 span2'})
- .mr_target_commit.prepend-top-10
+ = f.select(:target_branch, @merge_request.target_branches, { include_blank: "Select branch" }, {class: 'target_branch select2 span2'})
+ .mr_target_commit
%hr
.merge-request-form-info
@@ -47,7 +54,7 @@
%i.icon-user
Assign to
.col-sm-10
- = f.select(:assignee_id, assignee_options(@merge_request), { include_blank: "Select a user" }, {class: 'select2'})
+ = project_users_select_tag('merge_request[assignee_id]', placeholder: 'Select a user', class: 'custom-form-control', selected: @merge_request.assignee_id)
&nbsp;
= link_to 'Assign to me', '#', class: 'btn btn-small assign-to-me-link'
.form-group
@@ -90,6 +97,6 @@
$.get("#{branch_to_project_merge_requests_path(@source_project)}", {target_project_id: target_project.val(),ref: $(this).val() });
});
$('.assign-to-me-link').on('click', function(e){
- $('#merge_request_assignee_id').val("#{current_user.id}").trigger("select2:updated");
+ $('#merge_request_assignee_id').val("#{current_user.id}").trigger("change");
e.preventDefault();
});
diff --git a/app/views/projects/merge_requests/_merge_request.html.haml b/app/views/projects/merge_requests/_merge_request.html.haml
index ff763bca307..980ac126742 100644
--- a/app/views/projects/merge_requests/_merge_request.html.haml
+++ b/app/views/projects/merge_requests/_merge_request.html.haml
@@ -10,14 +10,14 @@
%span.pull-right
- if merge_request.for_fork?
%span.light
- = "#{merge_request.source_project_path}"
- = "#{merge_request.source_branch}"
+ #{merge_request.source_project_namespace}:
+ = merge_request.source_branch
%i.icon-angle-right.light
- = "#{merge_request.target_branch}"
+ = merge_request.target_branch
- else
- = "#{merge_request.source_branch}"
+ = merge_request.source_branch
%i.icon-angle-right.light
- = "#{merge_request.target_branch}"
+ = merge_request.target_branch
.merge-request-info
- if merge_request.author
authored by #{link_to_member(merge_request.source_project, merge_request.author)}
diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml
index 42641765c5c..809b01918cf 100644
--- a/app/views/projects/merge_requests/_show.html.haml
+++ b/app/views/projects/merge_requests/_show.html.haml
@@ -2,7 +2,7 @@
= render "projects/merge_requests/show/mr_title"
= render "projects/merge_requests/show/how_to_merge"
= render "projects/merge_requests/show/mr_box"
- - if @merge_request.opened?
+ - if @merge_request.open?
- if @merge_request.source_branch_exists? && @merge_request.target_branch_exists?
= render "projects/merge_requests/show/mr_accept"
- else
@@ -12,7 +12,7 @@
= render "projects/merge_requests/show/commits"
- if @commits.present?
- %ul.nav.nav-tabs.append-bottom-10
+ %ul.nav.nav-tabs
%li.notes-tab{data: {action: 'notes'}}
= link_to project_merge_request_path(@project, @merge_request) do
%i.icon-comment
@@ -22,6 +22,13 @@
%i.icon-list-alt
Diff
+ - content_for :note_actions do
+ - if can?(current_user, :modify_merge_request, @merge_request)
+ - unless @merge_request.closed? || @merge_request.merged?
+ = link_to 'Close', project_merge_request_path(@project, @merge_request, merge_request: {state_event: :close }), method: :put, class: "btn btn-grouped btn-close close-mr-link", title: "Close merge request"
+ - if @merge_request.closed?
+ = link_to 'Reopen', project_merge_request_path(@project, @merge_request, merge_request: {state_event: :reopen }), method: :put, class: "btn btn-grouped btn-reopen reopen-mr-link", title: "Close merge request"
+
.notes.tab-content.voting_notes#notes{ class: (controller.action_name == 'show') ? "" : "hide" }
= render "projects/notes/notes_with_form"
.diffs.tab-content
diff --git a/app/views/projects/merge_requests/branch_from.js.haml b/app/views/projects/merge_requests/branch_from.js.haml
index ec4d7f2121b..d3147188d1c 100644
--- a/app/views/projects/merge_requests/branch_from.js.haml
+++ b/app/views/projects/merge_requests/branch_from.js.haml
@@ -1,5 +1,5 @@
:plain
- $(".mr_source_commit").html("#{commit_to_html(@commit, @source_project)}");
+ $(".mr_source_commit").html("#{commit_to_html(@commit, @source_project, false)}");
var mrTitle = $('#merge_request_title');
if(mrTitle.val().length == 0) {
diff --git a/app/views/projects/merge_requests/branch_to.js.haml b/app/views/projects/merge_requests/branch_to.js.haml
index f4e2886ee44..f7ede0ded53 100644
--- a/app/views/projects/merge_requests/branch_to.js.haml
+++ b/app/views/projects/merge_requests/branch_to.js.haml
@@ -1,2 +1,2 @@
:plain
- $(".mr_target_commit").html("#{commit_to_html(@commit, @target_project)}");
+ $(".mr_target_commit").html("#{commit_to_html(@commit, @target_project, false)}");
diff --git a/app/views/projects/merge_requests/index.html.haml b/app/views/projects/merge_requests/index.html.haml
index d6d0cde85be..34faebf619c 100644
--- a/app/views/projects/merge_requests/index.html.haml
+++ b/app/views/projects/merge_requests/index.html.haml
@@ -5,67 +5,67 @@
%h3.page-title
Merge Requests
%span (#{@merge_requests.total_count})
-
-
+%hr
.row
.col-md-3
= render 'shared/project_filter', project_entities_path: project_merge_requests_path(@project)
.col-md-9
- .ui-box
- .title
- .mr-filters
- %span Filter by
- .dropdown.inline.prepend-left-10
- %a.dropdown-toggle.btn.btn-small{href: '#', "data-toggle" => "dropdown"}
- %i.icon-user
- %span.light assignee:
- - if @assignee.present?
- %strong= @assignee.name
- - elsif params[:assignee_id] == "0"
- Unassigned
- - else
- Any
- %b.caret
- %ul.dropdown-menu
- %li
- = link_to project_filter_path(assignee_id: nil) do
- Any
- = link_to project_filter_path(assignee_id: 0) do
- Unassigned
- - @project.team.members.sort_by(&:name).each do |user|
- %li
- = link_to project_filter_path(assignee_id: user.id) do
- = image_tag avatar_icon(user.email), class: "avatar s16", alt: ''
- = user.name
+ .mr-filters.append-bottom-10
+ .dropdown.inline
+ %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
+ %i.icon-user
+ %span.light assignee:
+ - if @assignee.present?
+ %strong= @assignee.name
+ - elsif params[:assignee_id] == "0"
+ Unassigned
+ - else
+ Any
+ %b.caret
+ %ul.dropdown-menu
+ %li
+ = link_to project_filter_path(assignee_id: nil) do
+ Any
+ = link_to project_filter_path(assignee_id: 0) do
+ Unassigned
+ - @assignees.sort_by(&:name).each do |user|
+ %li
+ = link_to project_filter_path(assignee_id: user.id) do
+ = image_tag avatar_icon(user.email), class: "avatar s16", alt: ''
+ = user.name
- .dropdown.inline.prepend-left-10
- %a.dropdown-toggle.btn.btn-small{href: '#', "data-toggle" => "dropdown"}
- %i.icon-time
- %span.light milestone:
- - if @milestone.present?
- %strong= @milestone.title
- - elsif params[:milestone_id] == "0"
- None (backlog)
- - else
- Any
- %b.caret
- %ul.dropdown-menu
- %li
- = link_to project_filter_path(milestone_id: nil) do
- Any
- = link_to project_filter_path(milestone_id: 0) do
- None (backlog)
- - project_active_milestones.each do |milestone|
- %li
- = link_to project_filter_path(milestone_id: milestone.id) do
- %strong= milestone.title
- %small.light= milestone.expires_at
+ .dropdown.inline.prepend-left-10
+ %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
+ %i.icon-time
+ %span.light milestone:
+ - if @milestone.present?
+ %strong= @milestone.title
+ - elsif params[:milestone_id] == "0"
+ None (backlog)
+ - else
+ Any
+ %b.caret
+ %ul.dropdown-menu
+ %li
+ = link_to project_filter_path(milestone_id: nil) do
+ Any
+ = link_to project_filter_path(milestone_id: 0) do
+ None (backlog)
+ - project_active_milestones.each do |milestone|
+ %li
+ = link_to project_filter_path(milestone_id: milestone.id) do
+ %strong= milestone.title
+ %small.light= milestone.expires_at
+
+ .pull-right
+ = render 'shared/sort_dropdown'
+ .ui-box
%ul.well-list.mr-list
= render @merge_requests
- if @merge_requests.blank?
%li
- %h4.nothing_here_message No merge requests to show
+ .nothing-here-block No merge requests to show
- if @merge_requests.present?
.pull-right
%span.cgray.pull-right #{@merge_requests.total_count} merge requests for this filter
diff --git a/app/views/projects/merge_requests/show/_commits.html.haml b/app/views/projects/merge_requests/show/_commits.html.haml
index 7b0e67053a5..9b4271bbffc 100644
--- a/app/views/projects/merge_requests/show/_commits.html.haml
+++ b/app/views/projects/merge_requests/show/_commits.html.haml
@@ -12,9 +12,16 @@
8 of #{@commits.count} commits displayed.
%strong
%a.show-all-commits Click here to show all
- %ul.all-commits.hide.well-list
- - @commits.each do |commit|
- = render "projects/commits/commit", commit: commit, project: @merge_request.source_project
+ - if @commits.size > MergeRequestDiff::COMMITS_SAFE_SIZE
+ %ul.all-commits.hide.well-list
+ - @commits.first(MergeRequestDiff::COMMITS_SAFE_SIZE).each do |commit|
+ = render "projects/commits/inline_commit", commit: commit, project: @merge_request.source_project
+ %li
+ other #{@commits.size - MergeRequestDiff::COMMITS_SAFE_SIZE} commits hidden top prevent performance issues.
+ - else
+ %ul.all-commits.hide.well-list
+ - @commits.each do |commit|
+ = render "projects/commits/inline_commit", commit: commit, project: @merge_request.source_project
- else
%ul.well-list
@@ -22,7 +29,7 @@
= render "projects/commits/commit", commit: commit, project: @merge_request.source_project
- else
- %h4.nothing_here_message
+ .nothing-here-block
Nothing to merge from
%span.label-branch #{@merge_request.source_branch}
to
diff --git a/app/views/projects/merge_requests/show/_context.html.haml b/app/views/projects/merge_requests/show/_context.html.haml
new file mode 100644
index 00000000000..2bd850426a9
--- /dev/null
+++ b/app/views/projects/merge_requests/show/_context.html.haml
@@ -0,0 +1,22 @@
+= form_for [@project, @merge_request], remote: true, html: {class: 'edit-merge_request inline-update'} do |f|
+ %strong.append-right-10
+ Assignee:
+
+ - if can?(current_user, :modify_merge_request, @merge_request)
+ = project_users_select_tag('merge_request[assignee_id]', placeholder: 'Select assignee', class: 'custom-form-control', selected: @merge_request.assignee_id)
+ - elsif merge_request.assignee
+ = link_to_member(@project, @merge_request.assignee)
+ - else
+ None
+
+ .pull-right
+ %strong.append-right-10
+ Milestone:
+ - if can?(current_user, :modify_merge_request, @merge_request)
+ = f.select(:milestone_id, milestone_options(@merge_request), { include_blank: "Select milestone (none):" }, {class: 'select2 select2-compact'})
+ = hidden_field_tag :merge_request_context
+ = f.submit class: 'btn'
+ - elsif merge_request.milestone
+ = link_to merge_request.milestone.title, project_milestone_path
+ - else
+ None
diff --git a/app/views/projects/merge_requests/show/_diffs.html.haml b/app/views/projects/merge_requests/show/_diffs.html.haml
index 25f63804858..7c4f43d2d80 100644
--- a/app/views/projects/merge_requests/show/_diffs.html.haml
+++ b/app/views/projects/merge_requests/show/_diffs.html.haml
@@ -1,10 +1,12 @@
-- if @merge_request.valid_diffs?
+- if @merge_request_diff.collected?
= render "projects/commits/diffs", diffs: @merge_request.diffs, project: @merge_request.source_project
-- elsif @merge_request.broken_diffs?
- %h4.nothing_here_message
- Can't load diff.
- You can
- = link_to "download it", project_merge_request_path(@merge_request.source_project, @merge_request), format: :diff, class: "vlink"
- instead.
+- elsif @merge_request_diff.empty?
+ .nothing-here-block Nothing to merge from #{@merge_request.source_branch} into #{@merge_request.target_branch}
- else
- %h4.nothing_here_message Nothing to merge
+ .bs-callout.bs-callout-warning
+ %h4
+ Diff for this comparison is extremely large.
+ %p
+ You can
+ = link_to "download it", project_merge_request_path(@merge_request.source_project, @merge_request, format: :diff), class: "vlink"
+ instead.
diff --git a/app/views/projects/merge_requests/show/_mr_accept.html.haml b/app/views/projects/merge_requests/show/_mr_accept.html.haml
index d210d4667fd..a9cbe43fb16 100644
--- a/app/views/projects/merge_requests/show/_mr_accept.html.haml
+++ b/app/views/projects/merge_requests/show/_mr_accept.html.haml
@@ -13,7 +13,21 @@
If you still want to do it manually -
%strong
= link_to "click here", "#modal_merge_info", class: "how_to_merge_link vlink", title: "How To Merge", "data-toggle" => "modal"
- for instructions
+ for instructions.
+
+ %br
+ If you want to modify merge commit message -
+ %strong
+ = link_to "click here", "#", class: "modify-merge-commit-link js-toggle-visibility-link", title: "Modify merge commit message"
+
+ .js-toggle-visibility-container.hide
+ .form-group
+ = label_tag :merge_commit_message, "Commit message", class: 'control-label'
+ .col-sm-10
+ = text_area_tag :merge_commit_message, @merge_request.merge_commit_message, class: "form-control js-gfm-input", rows: 14, required: true
+ %p.hint
+ The recommended maximum line length is 52 characters for the first line and 72 characters for all following lines.
+
.accept-group
.pull-left
= f.submit "Accept Merge Request", class: "btn btn-create accept_merge_request"
@@ -41,15 +55,15 @@
.automerge_widget.unchecked
.bs-callout.bs-callout-warning
%strong
- %i.icon-refresh.icon-spin
+ %i.icon-spinner.icon-spin
Checking for ability to automatically merge…
.automerge_widget.already_cannot_be_merged.hide
.bs-callout.bs-callout-info
- %strong This merge request already can not be merged. Try to reload page.
+ %strong This merge request can not be merged. Try to reload the page.
.merge-in-progress.hide
.bs-callout.bs-callout-success
- %i.icon-refresh.icon-spin
+ %i.icon-spinner.icon-spin
&nbsp;
Merge is in progress. Please wait. Page will be automatically reloaded. &nbsp;
diff --git a/app/views/projects/merge_requests/show/_mr_box.html.haml b/app/views/projects/merge_requests/show/_mr_box.html.haml
index b4f648ab197..38db4363ade 100644
--- a/app/views/projects/merge_requests/show/_mr_box.html.haml
+++ b/app/views/projects/merge_requests/show/_mr_box.html.haml
@@ -1,18 +1,18 @@
-.issue-box
- %h4.title
- = gfm escape_once(@merge_request.title)
+.issue-box{ class: issue_box_class(@merge_request) }
+ .state
+ %span.state-label
+ - if @merge_request.merged?
+ Merged
+ - elsif @merge_request.closed?
+ Closed
+ - else
+ Open
- .context
- %cite.cgray
- Created by #{link_to_member(@project, @merge_request.author)}.
- - if @merge_request.assignee
- Currently assigned to #{link_to_member(@project, @merge_request.assignee)}.
- - if @merge_request.milestone
- .pull-right
- - milestone = @merge_request.milestone
- %cite.cgray Attached to milestone
- %strong= link_to_gfm truncate(milestone.title, length: 20), project_milestone_path(milestone.project, milestone)
+ %span.creator
+ Created by #{link_to_member(@project, @merge_request.author)} #{time_ago_with_tooltip(@merge_request.created_at)}
+ %h4.title
+ = gfm escape_once(@merge_request.title)
- if @merge_request.description.present?
.description
@@ -20,22 +20,26 @@
= preserve do
= markdown @merge_request.description
- - if @merge_request.closed?
- .description.alert-danger
- %span
- %i.icon-remove
- Closed by #{link_to_member(@project, @merge_request.closed_event.author)}
- #{time_ago_with_tooltip(@merge_request.closed_event.created_at)}.
- - if @merge_request.merged?
- .description.alert-success
- %span
- %i.icon-ok
- Merged by #{link_to_member(@project, @merge_request.merge_event.author)}
- #{time_ago_with_tooltip(@merge_request.merge_event.created_at)}.
- - if !@closes_issues.empty? && @merge_request.opened?
- .description.alert-info
- %span
- %i.icon-ok
- Accepting this merge request will close #{@closes_issues.size == 1 ? 'issue' : 'issues'}
- = succeed '.' do
- != gfm(@closes_issues.map { |i| "##{i.iid}" }.to_sentence)
+ .context
+ %cite.cgray
+ = render partial: 'projects/merge_requests/show/context', locals: { merge_request: @merge_request }
+
+- if @merge_request.closed?
+ .alert.alert-info
+ %span
+ %i.icon-remove
+ Closed by #{link_to_member(@project, @merge_request.closed_event.author)}
+ #{time_ago_with_tooltip(@merge_request.closed_event.created_at)}.
+- if @merge_request.merged?
+ .alert.alert-info
+ %span
+ %i.icon-ok
+ Merged by #{link_to_member(@project, @merge_request.merge_event.author)}
+ #{time_ago_with_tooltip(@merge_request.merge_event.created_at)}.
+- if !@closes_issues.empty? && @merge_request.open?
+ .alert.alert-info.alert-info
+ %span
+ %i.icon-ok
+ Accepting this merge request will close #{@closes_issues.size == 1 ? 'issue' : 'issues'}
+ = succeed '.' do
+ != gfm(@closes_issues.map { |i| "##{i.iid}" }.to_sentence)
diff --git a/app/views/projects/merge_requests/show/_mr_ci.html.haml b/app/views/projects/merge_requests/show/_mr_ci.html.haml
index 2e923ec5f35..915d24dd021 100644
--- a/app/views/projects/merge_requests/show/_mr_ci.html.haml
+++ b/app/views/projects/merge_requests/show/_mr_ci.html.haml
@@ -25,7 +25,7 @@
.ci_widget
.alert.alert-warning
%strong
- %i.icon-refresh
+ %i.icon-spinner
Checking for CI status for #{@merge_request.last_commit_short_sha}
.ci_widget.ci-error{style: "display:none"}
diff --git a/app/views/projects/merge_requests/show/_mr_title.html.haml b/app/views/projects/merge_requests/show/_mr_title.html.haml
index 08a3fdf869a..7676fc137c7 100644
--- a/app/views/projects/merge_requests/show/_mr_title.html.haml
+++ b/app/views/projects/merge_requests/show/_mr_title.html.haml
@@ -1,26 +1,11 @@
%h3.page-title
= "Merge Request ##{@merge_request.iid}"
- %small
- created #{time_ago_with_tooltip(@merge_request.created_at)}
-
- - if @merge_request.merged?
- %span.state-label.state-label-green
- %i.icon-ok
- Merged
- - elsif @merge_request.closed?
- %span.state-label.state-label-red
- Closed
- - else
- %span.state-label.state-label-green
- Open
-
-
%span.pull-right
- if can?(current_user, :modify_merge_request, @merge_request)
- - if @merge_request.opened?
- .left.btn-group
- %a.btn.grouped.dropdown-toggle{ data: {toggle: :dropdown} }
+ - if @merge_request.open?
+ .btn-group.pull-left
+ %a.btn.btn-grouped.dropdown-toggle{ data: {toggle: :dropdown} }
%i.icon-download-alt
Download as
%span.caret
@@ -28,13 +13,15 @@
%li= link_to "Email Patches", project_merge_request_path(@project, @merge_request, format: :patch)
%li= link_to "Plain Diff", project_merge_request_path(@project, @merge_request, format: :diff)
- = link_to 'Close', project_merge_request_path(@project, @merge_request, merge_request: { state_event: :close }), method: :put, class: "btn grouped btn-close", title: "Close merge request"
+ = link_to 'Close', project_merge_request_path(@project, @merge_request, merge_request: { state_event: :close }), method: :put, class: "btn btn-grouped btn-close", title: "Close merge request"
- = link_to edit_project_merge_request_path(@project, @merge_request), class: "btn grouped", id:"edit_merge_request" do
+ = link_to edit_project_merge_request_path(@project, @merge_request), class: "btn btn-grouped", id:"edit_merge_request" do
%i.icon-edit
Edit
+ - if @merge_request.closed?
+ = link_to 'Reopen', project_merge_request_path(@project, @merge_request, merge_request: {state_event: :reopen }), method: :put, class: "btn btn-grouped btn-reopen reopen-mr-link", title: "Close merge request"
-.votes-holder
+.votes-holder.hidden-sm.hidden-xs
#votes= render 'votes/votes_block', votable: @merge_request
.back-link
diff --git a/app/views/projects/merge_requests/update.js.haml b/app/views/projects/merge_requests/update.js.haml
new file mode 100644
index 00000000000..6452cc6382d
--- /dev/null
+++ b/app/views/projects/merge_requests/update.js.haml
@@ -0,0 +1,2 @@
+- if params[:merge_request_context]
+ $('.issue-box .context').effect('highlight');
diff --git a/app/views/projects/merge_requests/update_branches.js.haml b/app/views/projects/merge_requests/update_branches.js.haml
index 6a21551e811..ca21b3bc0de 100644
--- a/app/views/projects/merge_requests/update_branches.js.haml
+++ b/app/views/projects/merge_requests/update_branches.js.haml
@@ -1,5 +1,9 @@
:plain
$(".target_branch").html("#{escape_javascript(options_for_select(@target_branches))}");
- $(".target_branch").trigger("select2:updated");
+
+ $('select.target_branch').select2({
+ width: 'resolve',
+ dropdownAutoWidth: true
+ });
+
$(".mr_target_commit").html("");
- $(".target_branch").trigger("change");
diff --git a/app/views/projects/milestones/_issues.html.haml b/app/views/projects/milestones/_issues.html.haml
index 21939ad0132..c277dcc5364 100644
--- a/app/views/projects/milestones/_issues.html.haml
+++ b/app/views/projects/milestones/_issues.html.haml
@@ -4,7 +4,7 @@
- issues.each do |issue|
%li
= link_to [@project, issue] do
- %span.badge{class: issue.closed? ? 'badge-important' : 'badge-info'} ##{issue.iid}
+ %span.label{class: issue.closed? ? 'label-danger' : 'label-info'} ##{issue.iid}
= link_to_gfm truncate(issue.title, length: 40), [@project, issue]
- if issue.assignee
.pull-right
diff --git a/app/views/projects/milestones/_merge_request.html.haml b/app/views/projects/milestones/_merge_request.html.haml
index 8e30a42a608..faa35a25f2f 100644
--- a/app/views/projects/milestones/_merge_request.html.haml
+++ b/app/views/projects/milestones/_merge_request.html.haml
@@ -1,5 +1,5 @@
%li
= link_to [@project, merge_request] do
- %span.badge.badge-info ##{merge_request.iid}
+ %span.label.label-info ##{merge_request.iid}
&ndash;
= link_to_gfm truncate(merge_request.title, length: 60), [@project, merge_request]
diff --git a/app/views/projects/milestones/_milestone.html.haml b/app/views/projects/milestones/_milestone.html.haml
index 4dec3838d97..5579659d60e 100644
--- a/app/views/projects/milestones/_milestone.html.haml
+++ b/app/views/projects/milestones/_milestone.html.haml
@@ -1,7 +1,7 @@
%li{class: "milestone milestone-#{milestone.closed? ? 'closed' : 'open'}", id: dom_id(milestone) }
.pull-right
- if can?(current_user, :admin_milestone, milestone.project) and milestone.active?
- = link_to edit_project_milestone_path(milestone.project, milestone), class: "btn btn-small edit-milestone-link grouped" do
+ = link_to edit_project_milestone_path(milestone.project, milestone), class: "btn btn-small edit-milestone-link btn-grouped" do
%i.icon-edit
Edit
= link_to 'Close Milestone', project_milestone_path(@project, milestone, milestone: {state_event: :close }), method: :put, remote: true, class: "btn btn-small btn-remove"
diff --git a/app/views/projects/milestones/index.html.haml b/app/views/projects/milestones/index.html.haml
index 6cfe4d28778..3537650ad43 100644
--- a/app/views/projects/milestones/index.html.haml
+++ b/app/views/projects/milestones/index.html.haml
@@ -26,6 +26,6 @@
- if @milestones.blank?
%li
- %h3.nothing_here_message No milestones to show
+ .nothing-here-block No milestones to show
= paginate @milestones, theme: "gitlab"
diff --git a/app/views/projects/milestones/show.html.haml b/app/views/projects/milestones/show.html.haml
index e7c3785c056..06cf9946784 100644
--- a/app/views/projects/milestones/show.html.haml
+++ b/app/views/projects/milestones/show.html.haml
@@ -3,21 +3,15 @@
Milestone ##{@milestone.iid}
%small
= @milestone.expires_at
- - if @milestone.closed?
- %span.state-label.state-label-red Closed
- - elsif @milestone.expired?
- %span.state-label.state-label-red Expired
- - else
- %span.state-label.state-label-green Open
.pull-right
- if can?(current_user, :admin_milestone, @project)
- = link_to edit_project_milestone_path(@project, @milestone), class: "btn grouped" do
+ = link_to edit_project_milestone_path(@project, @milestone), class: "btn btn-grouped" do
%i.icon-edit
Edit
- if @milestone.active?
- = link_to 'Close Milestone', project_milestone_path(@project, @milestone, milestone: {state_event: :close }), method: :put, class: "btn btn-remove grouped"
+ = link_to 'Close Milestone', project_milestone_path(@project, @milestone, milestone: {state_event: :close }), method: :put, class: "btn btn-remove btn-grouped"
- else
- = link_to 'Reopen Milestone', project_milestone_path(@project, @milestone, milestone: {state_event: :activate }), method: :put, class: "btn grouped"
+ = link_to 'Reopen Milestone', project_milestone_path(@project, @milestone, milestone: {state_event: :activate }), method: :put, class: "btn btn-grouped"
- if @milestone.issues.any? && @milestone.can_be_closed?
.alert.alert-success
@@ -28,7 +22,16 @@
&larr; To milestones list
-.issue-box
+.issue-box{ class: issue_box_class(@milestone) }
+ .state
+ %span.state-label
+ - if @milestone.closed?
+ Closed
+ - elsif @milestone.expired?
+ Expired
+ - else
+ Open
+
%h4.title
= gfm escape_once(@milestone.title)
@@ -42,14 +45,13 @@
.progress.progress-info
.progress-bar{style: "width: #{@milestone.percent_complete}%;"}
-
- if @milestone.description.present?
.description
- = preserve do
- = markdown @milestone.description
-
+ .wiki
+ = preserve do
+ = markdown @milestone.description
-%ul.nav.nav-tabs.append-bottom-10
+%ul.nav.nav-tabs
%li.active
= link_to '#tab-issues', 'data-toggle' => 'tab' do
Issues
@@ -64,10 +66,10 @@
%span.badge= @users.count
.pull-right
- = link_to new_project_issue_path(@project, issue: { milestone_id: @milestone.id }), class: "btn btn-small grouped", title: "New Issue" do
+ = link_to new_project_issue_path(@project, issue: { milestone_id: @milestone.id }), class: "btn btn-small btn-grouped", title: "New Issue" do
%i.icon-plus
New Issue
- = link_to 'Browse Issues', project_issues_path(@milestone.project, milestone_id: @milestone.id), class: "btn btn-small edit-milestone-link grouped"
+ = link_to 'Browse Issues', project_issues_path(@milestone.project, milestone_id: @milestone.id), class: "btn btn-small edit-milestone-link btn-grouped"
.tab-content
.tab-pane.active#tab-issues
diff --git a/app/views/projects/network/show.html.haml b/app/views/projects/network/show.html.haml
index 492f77341f7..da0cfa84c2d 100644
--- a/app/views/projects/network/show.html.haml
+++ b/app/views/projects/network/show.html.haml
@@ -3,7 +3,7 @@
.tip
You can move around the graph by using the arrow keys.
.network-graph
- .loading.loading-gray
+ = spinner
:javascript
new Network({
diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml
index f21cef6f2e3..9ee54fef062 100644
--- a/app/views/projects/new.html.haml
+++ b/app/views/projects/new.html.haml
@@ -62,6 +62,7 @@
.save-project-loader.hide
%center
- = image_tag "ajax_loader.gif"
- %h3 Creating project &amp; repository.
+ %h2
+ %i.icon-spinner.icon-spin
+ Creating project &amp; repository.
%p Please wait a moment, this page will automatically refresh when ready.
diff --git a/app/views/projects/new_tree/show.html.haml b/app/views/projects/new_tree/show.html.haml
index 078a4b80d0d..9d7c7afbeac 100644
--- a/app/views/projects/new_tree/show.html.haml
+++ b/app/views/projects/new_tree/show.html.haml
@@ -15,6 +15,12 @@
%span= @ref
.form-group.commit_message-group
+ = label_tag :encoding, class: "control-label" do
+ Encoding
+ .col-sm-10
+ = select_tag :encoding, options_for_select([ "base64", "text" ], "text"), class: 'form-control'
+
+ .form-group.commit_message-group
= label_tag 'commit_message', class: "control-label" do
Commit message
.col-sm-10
diff --git a/app/views/projects/notes/_discussion.html.haml b/app/views/projects/notes/_discussion.html.haml
index ee65ae1e2f5..9b1f4d77587 100644
--- a/app/views/projects/notes/_discussion.html.haml
+++ b/app/views/projects/notes/_discussion.html.haml
@@ -36,21 +36,17 @@
.discussion-body
- if note.for_diff_line?
- if note.active?
- .content
- .file= render "projects/notes/discussion_diff", discussion_notes: discussion_notes, note: note
+ = render "projects/notes/discussion_diff", discussion_notes: discussion_notes, note: note
- else
= link_to 'show outdated discussion', '#', class: 'js-show-outdated-discussion'
%div.hide.outdated-discussion
- .content
- .notes{ rel: discussion_notes.first.discussion_id }
- = render discussion_notes
-
+ .notes{ rel: discussion_notes.first.discussion_id }
+ = render discussion_notes
- else
- .content
- .notes{ rel: discussion_notes.first.discussion_id }
- = render discussion_notes
- = render "projects/notes/discussion_reply_button", note: discussion_notes.first
+ .notes{ rel: discussion_notes.first.discussion_id }
+ = render discussion_notes
+ = render "projects/notes/discussion_reply_button", note: discussion_notes.first
-# will be shown when the other one is hidden
.discussion-hidden.content.hide
@@ -59,4 +55,3 @@
= link_to "javascript:;", class: "js-details-target js-toggler-target" do
%i.icon-eye-open
Show
-
diff --git a/app/views/projects/notes/_discussion_diff.html.haml b/app/views/projects/notes/_discussion_diff.html.haml
index c3f41a1b6b5..687fac04973 100644
--- a/app/views/projects/notes/_discussion_diff.html.haml
+++ b/app/views/projects/notes/_discussion_diff.html.haml
@@ -1,24 +1,25 @@
- diff = note.diff
-.header
- - if diff.deleted_file
- %span= diff.old_path
- - else
- %span= diff.new_path
- - if diff.a_mode && diff.b_mode && diff.a_mode != diff.b_mode
- %span.file-mode= "#{diff.a_mode} → #{diff.b_mode}"
- %br/
-.content
- %table
- - each_diff_line_near(diff, note.diff_file_index, note.line_code) do |line, type, line_code, line_new, line_old|
- %tr.line_holder{ id: line_code }
- - if type == "match"
- %td.old_line= "..."
- %td.new_line= "..."
- %td.line_content.matched= line
- - else
- %td.old_line= raw(type == "new" ? "&nbsp;" : line_old)
- %td.new_line= raw(type == "old" ? "&nbsp;" : line_new)
- %td.line_content{class: "noteable_line #{type} #{line_code}", "line_code" => line_code}= raw "#{line} &nbsp;"
+.diff-file
+ .diff-header
+ - if diff.deleted_file
+ %span= diff.old_path
+ - else
+ %span= diff.new_path
+ - if diff.a_mode && diff.b_mode && diff.a_mode != diff.b_mode
+ %span.file-mode= "#{diff.a_mode} → #{diff.b_mode}"
+ %br/
+ .diff-content
+ %table
+ - each_diff_line_near(diff, note.diff_file_index, note.line_code) do |line, type, line_code, line_new, line_old|
+ %tr.line_holder{ id: line_code }
+ - if type == "match"
+ %td.old_line= "..."
+ %td.new_line= "..."
+ %td.line_content.matched= line
+ - else
+ %td.old_line= raw(type == "new" ? "&nbsp;" : line_old)
+ %td.new_line= raw(type == "old" ? "&nbsp;" : line_new)
+ %td.line_content{class: "noteable_line #{type} #{line_code}", "line_code" => line_code}= raw "#{line} &nbsp;"
- - if line_code == note.line_code
- = render "projects/notes/diff_notes_with_reply", notes: discussion_notes
+ - if line_code == note.line_code
+ = render "projects/notes/diff_notes_with_reply", notes: discussion_notes
diff --git a/app/views/projects/notes/_form.html.haml b/app/views/projects/notes/_form.html.haml
index bcaedc8bd7c..3db551e993b 100644
--- a/app/views/projects/notes/_form.html.haml
+++ b/app/views/projects/notes/_form.html.haml
@@ -22,7 +22,7 @@
.note-form-actions
.buttons
- = f.submit 'Add Comment', class: "btn comment-btn grouped js-comment-button"
+ = f.submit 'Add Comment', class: "btn comment-btn btn-grouped js-comment-button"
= yield(:note_actions)
%a.btn.grouped.js-close-discussion-note-form Cancel
diff --git a/app/views/projects/notes/_note.html.haml b/app/views/projects/notes/_note.html.haml
index be9c6ca79bb..6a67f5242b2 100644
--- a/app/views/projects/notes/_note.html.haml
+++ b/app/views/projects/notes/_note.html.haml
@@ -31,7 +31,7 @@
.note-body
.note-text
= preserve do
- = markdown(note.note)
+ = markdown(note.note, {no_header_anchors: true})
.note-edit-form
= form_for note, url: project_note_path(@project, note), method: :put, remote: true, authenticity_token: true do |f|
diff --git a/app/views/projects/protected_branches/index.html.haml b/app/views/projects/protected_branches/index.html.haml
index e0d058de79e..8b100766e97 100644
--- a/app/views/projects/protected_branches/index.html.haml
+++ b/app/views/projects/protected_branches/index.html.haml
@@ -3,27 +3,27 @@
.col-md-3
= render "projects/branches/filter"
.col-md-9
- .alert.alert-info
+ .bs-callout.bs-callout-info
%p Protected branches designed to prevent push for all except #{link_to "masters", help_permissions_path, class: "vlink"}.
%p This ability allows:
%ul
%li keep stable branches secured
%li forced code review before merge to protected branches
- %p Read more about project permissions #{link_to "here", help_permissions_path, class: "underlined_link"}
+ %p Read more about project permissions #{link_to "here", help_permissions_path, class: "underlined-link"}
- if can? current_user, :admin_project, @project
- = form_for [@project, @protected_branch] do |f|
+ = form_for [@project, @protected_branch], html: { class: 'form-horizontal' } do |f|
-if @protected_branch.errors.any?
.alert.alert-danger
%ul
- @protected_branch.errors.full_messages.each do |msg|
%li= msg
- .entry.clearfix
- = f.label :name, "Branch"
- .col-md-3
- = f.select(:name, @project.open_branches.map { |br| [br.name, br.name] } , {include_blank: "Select branch"}, {class: "select2 span3"})
- &nbsp;
+ .form-group
+ = f.label :name, "Branch", class: 'control-label'
+ .col-sm-10
+ = f.select(:name, @project.open_branches.map { |br| [br.name, br.name] } , {include_blank: "Select branch"}, {class: "select2"})
+ .form-actions
= f.submit 'Protect', class: "btn-create btn"
- unless @branches.empty?
%h5 Already Protected:
diff --git a/app/views/projects/repositories/_download_archive.html.haml b/app/views/projects/repositories/_download_archive.html.haml
index b03feded0a7..88c1cfa28e0 100644
--- a/app/views/projects/repositories/_download_archive.html.haml
+++ b/app/views/projects/repositories/_download_archive.html.haml
@@ -3,7 +3,7 @@
- split_button = split_button || false
- if split_button == true
%span.btn-group{class: btn_class}
- = link_to archive_project_repository_path(@project, ref: ref, format: 'zip'), class: 'btn' do
+ = link_to archive_project_repository_path(@project, ref: ref, format: 'zip'), class: 'btn', rel: 'nofollow' do
%i.icon-download-alt
%span Download zip
%a.btn.dropdown-toggle{ 'data-toggle' => 'dropdown' }
@@ -12,26 +12,26 @@
Select Archive Format
%ul.dropdown-menu{ role: 'menu' }
%li
- = link_to archive_project_repository_path(@project, ref: ref, format: 'zip') do
+ = link_to archive_project_repository_path(@project, ref: ref, format: 'zip'), rel: 'nofollow' do
%i.icon-download-alt
%span Download zip
%li
- = link_to archive_project_repository_path(@project, ref: ref, format: 'tar.gz') do
+ = link_to archive_project_repository_path(@project, ref: ref, format: 'tar.gz'), rel: 'nofollow' do
%i.icon-download-alt
%span Download tar.gz
%li
- = link_to archive_project_repository_path(@project, ref: ref, format: 'tar.bz2') do
+ = link_to archive_project_repository_path(@project, ref: ref, format: 'tar.bz2'), rel: 'nofollow' do
%i.icon-download-alt
%span Download tar.bz2
%li
- = link_to archive_project_repository_path(@project, ref: ref, format: 'tar') do
+ = link_to archive_project_repository_path(@project, ref: ref, format: 'tar'), rel: 'nofollow' do
%i.icon-download-alt
%span Download tar
- else
%span.btn-group{class: btn_class}
- = link_to archive_project_repository_path(@project, ref: ref, format: 'zip'), class: 'btn' do
+ = link_to archive_project_repository_path(@project, ref: ref, format: 'zip'), class: 'btn', rel: 'nofollow' do
%i.icon-download-alt
%span zip
- = link_to archive_project_repository_path(@project, ref: ref, format: 'tar.gz'), class: 'btn' do
+ = link_to archive_project_repository_path(@project, ref: ref, format: 'tar.gz'), class: 'btn', rel: 'nofollow' do
%i.icon-download-alt
%span tar.gz \ No newline at end of file
diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml
index 59075abf984..8a1e1d3354b 100644
--- a/app/views/projects/show.html.haml
+++ b/app/views/projects/show.html.haml
@@ -5,7 +5,7 @@
= render "events/event_last_push", event: @last_push
= render 'shared/event_filter'
.content_list
- .loading.hide
+ = spinner
.col-md-3.project-side.hidden-sm
.clearfix
- if @project.archived?
@@ -51,7 +51,7 @@
%p
%span.light Owned by
- if @project.group
- #{link_to @project.group.name, @project.group} Group
+ #{link_to @project.group.name, @project.group} group
- else
#{link_to @project.owner_name, @project.owner}
diff --git a/app/views/projects/snippets/_blob.html.haml b/app/views/projects/snippets/_blob.html.haml
index f14a2bd4ec0..af326a1a99a 100644
--- a/app/views/projects/snippets/_blob.html.haml
+++ b/app/views/projects/snippets/_blob.html.haml
@@ -6,10 +6,5 @@
.btn-group.tree-btn-group.pull-right
- if can?(current_user, :admin_project_snippet, @project) || @snippet.author == current_user
= link_to "Edit", edit_project_snippet_path(@project, @snippet), class: "btn btn-tiny", title: 'Edit Snippet'
- = link_to "raw", raw_project_snippet_path(@project, @snippet), class: "btn btn-tiny", target: "_blank"
- .file-content.code
- - unless @snippet.content.empty?
- %div{class: user_color_scheme_class}
- = raw @snippet.colorize(formatter: :gitlab)
- - else
- %p.nothing_here_message Empty file
+ = link_to "Raw", raw_project_snippet_path(@project, @snippet), class: "btn btn-tiny", target: "_blank"
+ = render 'snippets/blob_content'
diff --git a/app/views/projects/snippets/_snippet.html.haml b/app/views/projects/snippets/_snippet.html.haml
index ddd9645ee51..b2c35edc44c 100644
--- a/app/views/projects/snippets/_snippet.html.haml
+++ b/app/views/projects/snippets/_snippet.html.haml
@@ -5,13 +5,6 @@
%span.cgray.monospace.tiny.pull-right
= snippet.file_name
- %small.pull-right.cgray
- Expires:
- - if snippet.expires_at
- = snippet.expires_at.to_date.to_s(:short)
- - else
- Never
-
.snippet-info
= "##{snippet.id}"
%span
diff --git a/app/views/projects/snippets/index.html.haml b/app/views/projects/snippets/index.html.haml
index c40f63d05b3..e60f9a44322 100644
--- a/app/views/projects/snippets/index.html.haml
+++ b/app/views/projects/snippets/index.html.haml
@@ -12,4 +12,4 @@
= render partial: "projects/snippets/snippet", collection: @snippets
- if @snippets.empty?
%li
- %h3.nothing_here_message Nothing here.
+ .nothing-here-block Nothing here.
diff --git a/app/views/projects/tags/_tag.html.haml b/app/views/projects/tags/_tag.html.haml
new file mode 100644
index 00000000000..6629e47ad38
--- /dev/null
+++ b/app/views/projects/tags/_tag.html.haml
@@ -0,0 +1,22 @@
+- commit = @repository.commit(tag.target)
+%li
+ %h4
+ = link_to project_commits_path(@project, tag.name), class: "" do
+ %i.icon-tag
+ = tag.name
+ .pull-right
+ %small.cdark
+ %i.icon-calendar
+ #{time_ago_with_tooltip(commit.committed_date)}
+ %p.prepend-left-20
+ = link_to commit.short_id(8), project_commit_path(@project, commit), class: "monospace"
+ &ndash;
+ = link_to_gfm truncate(commit.title, length: 70), project_commit_path(@project, commit.id), class: "cdark"
+
+ %span.pull-right
+ - if can? current_user, :download_code, @project
+ = render 'projects/repositories/download_archive', ref: tag.name, btn_class: 'btn-grouped btn-group-small'
+ - if can?(current_user, :admin_project, @project)
+ = link_to project_tag_path(@project, tag.name), class: 'btn btn-small remove-row grouped', method: :delete, data: { confirm: 'Removed tag cannot be restored. Are you sure?'}, remote: true do
+ %i.icon-trash
+
diff --git a/app/views/projects/tags/index.html.haml b/app/views/projects/tags/index.html.haml
index c88e42a1073..53f3e67ff2c 100644
--- a/app/views/projects/tags/index.html.haml
+++ b/app/views/projects/tags/index.html.haml
@@ -13,34 +13,12 @@
- unless @tags.empty?
%ul.bordered-list
- @tags.each do |tag|
- - commit = Commit.new(Gitlab::Git::Commit.new(tag.commit))
- %li
- %h4
- = link_to project_commits_path(@project, tag.name), class: "" do
- %i.icon-tag
- = tag.name
- %small
- = truncate(tag.message || '', length: 70)
- .pull-right
- %small.cdark
- %i.icon-calendar
- #{time_ago_with_tooltip(commit.committed_date)}
- %p.prepend-left-20
- = link_to commit.short_id(8), project_commit_path(@project, commit), class: "monospace"
- &ndash;
- = link_to_gfm truncate(commit.title, length: 70), project_commit_path(@project, commit.id), class: "cdark"
-
- %span.pull-right
- - if can? current_user, :download_code, @project
- = render 'projects/repositories/download_archive', ref: tag.name, btn_class: 'grouped btn-group-small'
- - if can?(current_user, :admin_project, @project)
- = link_to project_tag_path(@project, tag.name), class: 'btn btn-small remove-row grouped', method: :delete, data: { confirm: 'Removed tag cannot be restored. Are you sure?'}, remote: true do
- %i.icon-trash
+ = render 'tag', tag: tag
= paginate @tags, theme: 'gitlab'
- else
- %h3.nothing_here_message
+ .nothing-here-block
Repository has no tags yet.
%br
%small
diff --git a/app/views/projects/team_members/_group_members.html.haml b/app/views/projects/team_members/_group_members.html.haml
index 68f08006854..eceec6627b9 100644
--- a/app/views/projects/team_members/_group_members.html.haml
+++ b/app/views/projects/team_members/_group_members.html.haml
@@ -1,10 +1,14 @@
+- group_users_count = @group.users_groups.count
.ui-box
.title
%strong #{@group.name}
- group members (#{@group.users_groups.count})
+ group members (#{group_users_count})
.pull-right
= link_to members_group_path(@group), class: 'btn btn-small' do
%i.icon-edit
%ul.well-list
- - @group.users_groups.order('group_access DESC').each do |member|
+ - @group.users_groups.order('group_access DESC').limit(20).each do |member|
= render 'users_groups/users_group', member: member, show_controls: false
+ - if group_users_count > 20
+ %li
+ and #{group_users_count - 20} more. For full list visit #{link_to 'group members page', members_group_path(@group)}
diff --git a/app/views/projects/team_members/index.html.haml b/app/views/projects/team_members/index.html.haml
index acbe82919f1..6eccaafe3de 100644
--- a/app/views/projects/team_members/index.html.haml
+++ b/app/views/projects/team_members/index.html.haml
@@ -3,9 +3,9 @@
- if can? current_user, :admin_team_member, @project
%span.pull-right
- = link_to new_project_team_member_path(@project), class: "btn btn-new grouped", title: "New project member" do
+ = link_to new_project_team_member_path(@project), class: "btn btn-new btn-grouped", title: "New project member" do
New project member
- = link_to import_project_team_members_path(@project), class: "btn grouped", title: "Import members from another project" do
+ = link_to import_project_team_members_path(@project), class: "btn btn-grouped", title: "Import members from another project" do
Import members
%p.light
diff --git a/app/views/projects/tree/_blob_item.html.haml b/app/views/projects/tree/_blob_item.html.haml
index 92dfd7537ca..6fee604b554 100644
--- a/app/views/projects/tree/_blob_item.html.haml
+++ b/app/views/projects/tree/_blob_item.html.haml
@@ -4,7 +4,5 @@
%span.str-truncated
= link_to blob_item.name, project_blob_path(@project, tree_join(@id || @commit.id, blob_item.name))
%td.tree_time_ago.cgray
- %span.log_loading.hide
- Loading commit data...
- = image_tag "ajax_loader_tree.gif", width: 14
+ = render 'spinner'
%td.tree_commit{ colspan: 2 }
diff --git a/app/views/projects/tree/_readme.html.haml b/app/views/projects/tree/_readme.html.haml
index ab572f2e97b..16a9602ac97 100644
--- a/app/views/projects/tree/_readme.html.haml
+++ b/app/views/projects/tree/_readme.html.haml
@@ -1,5 +1,5 @@
.readme-holder#README
- %h4
+ %h4.readme-file-title
%i.icon-file
= readme.name
.wiki
diff --git a/app/views/projects/tree/_spinner.html.haml b/app/views/projects/tree/_spinner.html.haml
new file mode 100644
index 00000000000..5a9e77b63df
--- /dev/null
+++ b/app/views/projects/tree/_spinner.html.haml
@@ -0,0 +1,3 @@
+%span.log_loading.hide
+ %i.icon-spinner.icon-spin
+ Loading commit data...
diff --git a/app/views/projects/tree/_submodule_item.html.haml b/app/views/projects/tree/_submodule_item.html.haml
index badc7d992bd..ae87dbde67a 100644
--- a/app/views/projects/tree/_submodule_item.html.haml
+++ b/app/views/projects/tree/_submodule_item.html.haml
@@ -1,10 +1,15 @@
+- tree, commit = submodule_links(submodule_item)
%tr{ class: "tree-item" }
%td.tree-item-file-name
= image_tag "submodule.png"
%span
- = link_to truncate(submodule_item.name, length: 40), submodule_item.submodule_url
+ = link_to truncate(submodule_item.name, length: 40), tree
@
- %span.monospace #{submodule_item.id[0..10]}
+ %span.monospace
+ - if commit.nil?
+ #{submodule_item.id[0..10]}
+ - else
+ = link_to "#{submodule_item.id[0..10]}", commit
%td
%td
%td
diff --git a/app/views/projects/tree/_tree.html.haml b/app/views/projects/tree/_tree.html.haml
index 4e80872df48..ee850e2bc1b 100644
--- a/app/views/projects/tree/_tree.html.haml
+++ b/app/views/projects/tree/_tree.html.haml
@@ -9,7 +9,7 @@
= link_to truncate(title, length: 40), project_tree_path(@project, path)
- else
= link_to title, '#'
- - if @repository.branch_names.include?(@ref)
+ - if current_user && @repository.branch_names.include?(@ref) && current_user.can?(:push_code, @project)
%li
= link_to project_new_tree_path(@project, @id), title: 'New file', id: 'new-file-link' do
%small
diff --git a/app/views/projects/tree/_tree_item.html.haml b/app/views/projects/tree/_tree_item.html.haml
index b4dd6f48b62..1b3900bcbae 100644
--- a/app/views/projects/tree/_tree_item.html.haml
+++ b/app/views/projects/tree/_tree_item.html.haml
@@ -4,7 +4,5 @@
%span.str-truncated
= link_to tree_item.name, project_tree_path(@project, tree_join(@id || @commit.id, tree_item.name))
%td.tree_time_ago.cgray
- %span.log_loading.hide
- Loading commit data...
- = image_tag "ajax_loader_tree.gif", width: 14
+ = render 'spinner'
%td.tree_commit{ colspan: 2 }
diff --git a/app/views/projects/walls/show.html.haml b/app/views/projects/walls/show.html.haml
index c6afec443f4..3e3c7c4f8dd 100644
--- a/app/views/projects/walls/show.html.haml
+++ b/app/views/projects/walls/show.html.haml
@@ -9,7 +9,7 @@
= f.text_area :note, size: 255, class: 'note_text js-note-text js-gfm-input turn-on'
.note-form-actions
.buttons
- = f.submit 'Add Comment', class: "btn comment-btn grouped js-comment-button"
+ = f.submit 'Add Comment', class: "btn comment-btn btn-grouped js-comment-button"
.note-form-option
%a.choose-btn.btn.btn-small.js-choose-note-attachment-button
diff --git a/app/views/projects/wikis/_main_links.html.haml b/app/views/projects/wikis/_main_links.html.haml
index 1001bb10c4f..5dd769dcfe1 100644
--- a/app/views/projects/wikis/_main_links.html.haml
+++ b/app/views/projects/wikis/_main_links.html.haml
@@ -1,8 +1,8 @@
%span.pull-right
- if (@wiki && @wiki.persisted?)
- = link_to history_project_wiki_path(@project, @wiki), class: "btn grouped" do
+ = link_to history_project_wiki_path(@project, @wiki), class: "btn btn-grouped" do
Page History
- if can?(current_user, :write_wiki, @project)
- = link_to edit_project_wiki_path(@project, @wiki), class: "btn grouped" do
+ = link_to edit_project_wiki_path(@project, @wiki), class: "btn btn-grouped" do
%i.icon-edit
Edit
diff --git a/app/views/projects/wikis/_nav.html.haml b/app/views/projects/wikis/_nav.html.haml
index 5e5aa5170d6..0a7e51e974c 100644
--- a/app/views/projects/wikis/_nav.html.haml
+++ b/app/views/projects/wikis/_nav.html.haml
@@ -1,4 +1,4 @@
-%ul.nav.nav-tabs.append-bottom-20
+%ul.nav.nav-tabs
= nav_link(html_options: {class: params[:id] == 'home' ? 'active' : '' }) do
= link_to 'Home', project_wiki_path(@project, :home)
diff --git a/app/views/public/projects/index.html.haml b/app/views/public/projects/index.html.haml
index 2fc93c5b742..624ec0b9b95 100644
--- a/app/views/public/projects/index.html.haml
+++ b/app/views/public/projects/index.html.haml
@@ -63,6 +63,6 @@
%i.icon-warning-sign
Empty repository
- unless @projects.present?
- %h3.nothing_here_message No public projects
+ .nothing-here-block No public projects
= paginate @projects, theme: "gitlab"
diff --git a/app/views/search/_project_results.html.haml b/app/views/search/_project_results.html.haml
index ea324b3a9aa..f285bda5736 100644
--- a/app/views/search/_project_results.html.haml
+++ b/app/views/search/_project_results.html.haml
@@ -1,4 +1,4 @@
-%ul.nav.nav-tabs.append-bottom-10
+%ul.nav.nav-tabs
%li{class: ("active" if params[:search_code].present?)}
= link_to search_path(params.merge(search_code: true)) do
Repository Code
diff --git a/app/views/search/results/_blob.html.haml b/app/views/search/results/_blob.html.haml
index a2e4a00b718..f9d217e8408 100644
--- a/app/views/search/results/_blob.html.haml
+++ b/app/views/search/results/_blob.html.haml
@@ -6,5 +6,4 @@
%strong
= blob.filename
.file-content.code.term
- %div{class: user_color_scheme_class}
- = raw blob.colorize( formatter: :gitlab, options: { first_line_number: blob.startline } )
+ = render 'shared/file_hljs', blob: blob, first_line_number: blob.startline
diff --git a/app/views/shared/_file_hljs.html.haml b/app/views/shared/_file_hljs.html.haml
new file mode 100644
index 00000000000..338236c0752
--- /dev/null
+++ b/app/views/shared/_file_hljs.html.haml
@@ -0,0 +1,12 @@
+%div.highlighted-data{class: user_color_scheme_class}
+ .line-numbers
+ - blob.data.lines.to_a.size.times do |index|
+ - offset = defined?(first_line_number) ? first_line_number : 1
+ - i = index + offset
+ = link_to "#L#{i}", id: "L#{i}", rel: "#L#{i}" do
+ %i.icon-link
+ = i
+ .highlight
+ %pre
+ %code
+ = blob.data
diff --git a/app/views/shared/_filter.html.haml b/app/views/shared/_filter.html.haml
index 96299f8dcf2..0becf531cc3 100644
--- a/app/views/shared/_filter.html.haml
+++ b/app/views/shared/_filter.html.haml
@@ -1,28 +1,29 @@
.side-filters.hidden-xs.hidden-sm
= form_tag filter_path(entity), method: 'get' do
- %fieldset.scope-filter
- %ul.nav.nav-pills.nav-stacked
- %li{class: ("active" if params[:scope].blank?)}
- = link_to filter_path(entity, scope: nil) do
- Assigned to me
- %li{class: ("active" if params[:scope] == 'authored')}
- = link_to filter_path(entity, scope: 'authored') do
- Created by me
- %li{class: ("active" if params[:scope] == 'all')}
- = link_to filter_path(entity, scope: 'all') do
- Everyone's
+ - if current_user
+ %fieldset.scope-filter
+ %ul.nav.nav-pills.nav-stacked
+ %li{class: ("active" if params[:scope] == 'assigned-to-me')}
+ = link_to filter_path(entity, scope: 'assigned-to-me') do
+ Assigned to me
+ %li{class: ("active" if params[:scope] == 'authored')}
+ = link_to filter_path(entity, scope: 'authored') do
+ Created by me
+ %li{class: ("active" if params[:scope] == 'all')}
+ = link_to filter_path(entity, scope: 'all') do
+ Everyone's
%fieldset.status-filter
%legend State
%ul.nav.nav-pills
- %li{class: ("active" if params[:status].blank?)}
- = link_to filter_path(entity, status: nil) do
+ %li{class: ("active" if params[:state] == 'opened')}
+ = link_to filter_path(entity, state: 'opened') do
Open
- %li{class: ("active" if params[:status] == 'closed')}
- = link_to filter_path(entity, status: 'closed') do
+ %li{class: ("active" if params[:state] == 'closed')}
+ = link_to filter_path(entity, state: 'closed') do
Closed
- %li{class: ("active" if params[:status] == 'all')}
- = link_to filter_path(entity, status: 'all') do
+ %li{class: ("active" if params[:state] == 'all')}
+ = link_to filter_path(entity, state: 'all') do
All
%fieldset
@@ -36,8 +37,8 @@
%small.pull-right= entities_per_project(project, entity)
%fieldset
- - if params[:status].present? || params[:project_id].present?
- = link_to filter_path(entity, status: nil, project_id: nil), class: 'pull-right cgray' do
+ - if params[:state].present? || params[:project_id].present?
+ = link_to filter_path(entity, state: nil, project_id: nil), class: 'pull-right cgray' do
%i.icon-remove
%strong Clear filter
diff --git a/app/views/shared/_issues.html.haml b/app/views/shared/_issues.html.haml
index 199000656fe..087b6632e8d 100644
--- a/app/views/shared/_issues.html.haml
+++ b/app/views/shared/_issues.html.haml
@@ -11,5 +11,5 @@
= render 'projects/issues/issue', issue: issue
= paginate @issues, theme: "gitlab"
- else
- %p.nothing_here_message No issues to show
+ .nothing-here-block No issues to show
diff --git a/app/views/shared/_merge_requests.html.haml b/app/views/shared/_merge_requests.html.haml
index ddad28339c8..f40b7be4864 100644
--- a/app/views/shared/_merge_requests.html.haml
+++ b/app/views/shared/_merge_requests.html.haml
@@ -11,4 +11,4 @@
= paginate @merge_requests, theme: "gitlab"
- else
- %h3.nothing_here_message No merge requests to show
+ .nothing-here-block No merge requests to show
diff --git a/app/views/shared/_no_ssh.html.haml b/app/views/shared/_no_ssh.html.haml
index 077e6c6a808..e70eb4d01b9 100644
--- a/app/views/shared/_no_ssh.html.haml
+++ b/app/views/shared/_no_ssh.html.haml
@@ -2,7 +2,13 @@
.no-ssh-key-message
.container
You won't be able to pull or push project code via SSH until you #{link_to 'add an SSH key', new_profile_key_path} to your profile
- %div.pull-right
+ .pull-right.hidden-xs
= link_to "Don't show again", profile_path(user: {hide_no_ssh_key: true}), method: :put, class: 'hide-no-ssh-message', remote: true
|
= link_to 'Remind later', '#', class: 'hide-no-ssh-message'
+ .links-xs.visible-xs
+ = link_to "Add key", new_profile_key_path
+ |
+ = link_to "Don't show again", profile_path(user: {hide_no_ssh_key: true}), method: :put, class: 'hide-no-ssh-message', remote: true
+ |
+ = link_to 'Later', '#', class: 'hide-no-ssh-message'
diff --git a/app/views/shared/_project_filter.html.haml b/app/views/shared/_project_filter.html.haml
index a4f406a4ab6..d82b08eeaa2 100644
--- a/app/views/shared/_project_filter.html.haml
+++ b/app/views/shared/_project_filter.html.haml
@@ -3,8 +3,8 @@
- if current_user
%fieldset
%ul.nav.nav-pills.nav-stacked
- %li{class: ("active" if params[:scope].blank?)}
- = link_to project_filter_path(scope: nil) do
+ %li{class: ("active" if params[:scope] == 'all')}
+ = link_to project_filter_path(scope: 'all') do
Everyone's
%li{class: ("active" if params[:scope] == 'assigned-to-me')}
= link_to project_filter_path(scope: 'assigned-to-me') do
@@ -16,8 +16,8 @@
%fieldset
%legend State
%ul.nav.nav-pills
- %li{class: ("active" if params[:state].blank?)}
- = link_to project_filter_path(state: nil) do
+ %li{class: ("active" if params[:state] == 'opened')}
+ = link_to project_filter_path(state: 'opened') do
Open
%li{class: ("active" if params[:state] == 'closed')}
= link_to project_filter_path(state: 'closed') do
@@ -26,6 +26,26 @@
= link_to project_filter_path(state: 'all') do
All
+ - if defined?(labels)
+ %fieldset
+ %legend Labels
+ %ul.nav.nav-pills.nav-stacked.nav-small.labels-filter
+ - issue_label_names.each do |label_name|
+ %li{class: label_filter_class(label_name)}
+ = link_to labels_filter_path(label_name) do
+ %span{class: "label #{label_css_class(label_name)}"}
+ %i.icon-tag
+ = label_name
+ - if selected_label?(label_name)
+ .pull-right
+ %i.icon-remove
+
+ - if issue_label_names.empty?
+ .light-well
+ Add first label to your issues
+ %br
+ or #{link_to 'generate', generate_project_labels_path(@project), method: :post} default set of labels
+
%fieldset
- if %w(state scope milestone_id assignee_id label_name).select { |k| params[k].present? }.any?
= link_to project_entities_path, class: 'cgray pull-right' do
diff --git a/app/views/shared/_promo.html.haml b/app/views/shared/_promo.html.haml
index c97f8ba0f0e..7dec48e6585 100644
--- a/app/views/shared/_promo.html.haml
+++ b/app/views/shared/_promo.html.haml
@@ -1,4 +1,4 @@
.gitlab-promo
- = link_to "Homepage", "http://gitlab.org"
- = link_to "Blog", "http://blog.gitlab.org"
+ = link_to "Homepage", "https://www.gitlab.com/"
+ = link_to "Blog", "https://www.gitlab.com/blog/"
= link_to "@gitlabhq", "https://twitter.com/gitlabhq"
diff --git a/app/views/shared/_sort_dropdown.html.haml b/app/views/shared/_sort_dropdown.html.haml
new file mode 100644
index 00000000000..7b37b39780e
--- /dev/null
+++ b/app/views/shared/_sort_dropdown.html.haml
@@ -0,0 +1,22 @@
+.dropdown.inline.prepend-left-10
+ %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
+ %span.light sort:
+ - if @sort.present?
+ = @sort
+ - else
+ Newest
+ %b.caret
+ %ul.dropdown-menu
+ %li
+ = link_to project_filter_path(sort: 'newest') do
+ Newest
+ = link_to project_filter_path(sort: 'oldest') do
+ Oldest
+ = link_to project_filter_path(sort: 'recently_updated') do
+ Recently updated
+ = link_to project_filter_path(sort: 'last_updated') do
+ Last updated
+ = link_to project_filter_path(sort: 'milestone_due_soon') do
+ Milestone due soon
+ = link_to project_filter_path(sort: 'milestone_due_later') do
+ Milestone due later
diff --git a/app/views/snippets/_blob.html.haml b/app/views/snippets/_blob.html.haml
index e6ae33f38f3..15867f071ef 100644
--- a/app/views/snippets/_blob.html.haml
+++ b/app/views/snippets/_blob.html.haml
@@ -8,18 +8,4 @@
= link_to "Edit", edit_snippet_path(@snippet), class: "btn btn-tiny", title: 'Edit Snippet'
= link_to "Delete", snippet_path(@snippet), method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-tiny", title: 'Delete Snippet'
= link_to "Raw", raw_snippet_path(@snippet), class: "btn btn-tiny", target: "_blank"
- - unless @snippet.content.empty?
- - if gitlab_markdown?(@snippet.file_name)
- .file-content.wiki
- = preserve do
- = markdown(@snippet.data)
- - elsif markup?(@snippet.file_name)
- .file-content.wiki
- = render_markup(@snippet.file_name, @snippet.data)
- - else
- .file-content.code
- %div{class: user_color_scheme_class}
- = raw @snippet.colorize(formatter: :gitlab)
- - else
- .file-content.code
- %p.nothing_here_message Empty file
+ = render 'snippets/blob_content'
diff --git a/app/views/snippets/_blob_content.html.haml b/app/views/snippets/_blob_content.html.haml
new file mode 100644
index 00000000000..8cec6168ab8
--- /dev/null
+++ b/app/views/snippets/_blob_content.html.haml
@@ -0,0 +1,14 @@
+- unless @snippet.content.empty?
+ - if gitlab_markdown?(@snippet.file_name)
+ .file-content.wiki
+ = preserve do
+ = markdown(@snippet.data)
+ - elsif markup?(@snippet.file_name)
+ .file-content.wiki
+ = render_markup(@snippet.file_name, @snippet.data)
+ - else
+ .file-content.code
+ = render 'shared/file_hljs', blob: @snippet
+- else
+ .file-content.code
+ .nothing-here-block Empty file
diff --git a/app/views/snippets/_snippets.html.haml b/app/views/snippets/_snippets.html.haml
index 05365dd8b88..40df42b6cf5 100644
--- a/app/views/snippets/_snippets.html.haml
+++ b/app/views/snippets/_snippets.html.haml
@@ -2,6 +2,6 @@
= render partial: 'snippet', collection: @snippets
- if @snippets.empty?
%li
- %h3.nothing_here_message Nothing here.
+ .nothing-here-block Nothing here.
= paginate @snippets, theme: 'gitlab'
diff --git a/app/views/snippets/current_user_index.html.haml b/app/views/snippets/current_user_index.html.haml
index bf712b2c7e7..90ddc7198f6 100644
--- a/app/views/snippets/current_user_index.html.haml
+++ b/app/views/snippets/current_user_index.html.haml
@@ -1,9 +1,9 @@
%h3.page-title
My Snippets
.pull-right
- = link_to new_snippet_path, class: "btn btn-new grouped", title: "New Snippet" do
+ = link_to new_snippet_path, class: "btn btn-new btn-grouped", title: "New Snippet" do
Add new snippet
- = link_to snippets_path, class: "btn grouped" do
+ = link_to snippets_path, class: "btn btn-grouped" do
Discover snippets
%p.light
diff --git a/app/views/snippets/index.html.haml b/app/views/snippets/index.html.haml
index 2f6c914a159..cea2517a8e1 100644
--- a/app/views/snippets/index.html.haml
+++ b/app/views/snippets/index.html.haml
@@ -2,9 +2,9 @@
Public snippets
.pull-right
- = link_to new_snippet_path, class: "btn btn-new grouped", title: "New Snippet" do
+ = link_to new_snippet_path, class: "btn btn-new btn-grouped", title: "New Snippet" do
Add new snippet
- = link_to user_snippets_path(current_user), class: "btn grouped" do
+ = link_to user_snippets_path(current_user), class: "btn btn-grouped" do
My snippets
%p.light
diff --git a/app/views/users/_groups.html.haml b/app/views/users/_groups.html.haml
new file mode 100644
index 00000000000..412df943fcc
--- /dev/null
+++ b/app/views/users/_groups.html.haml
@@ -0,0 +1,3 @@
+- groups.each do |group|
+ = link_to group, class: 'profile-groups-avatars', :title => group.name do
+ = image_tag group_icon(group.path) \ No newline at end of file
diff --git a/app/views/users/_profile.html.haml b/app/views/users/_profile.html.haml
index c7eb6fa182e..7ffd43e837d 100644
--- a/app/views/users/_profile.html.haml
+++ b/app/views/users/_profile.html.haml
@@ -17,6 +17,10 @@
%li
%span.light Twitter:
%strong= link_to user.twitter, "http://www.twitter.com/#{user.twitter}"
+ - unless user.website_url.blank?
+ %li
+ %span.light Website:
+ %strong= link_to user.short_website_url, user.full_website_url
- unless user.bio.blank?
%li
%span.light Bio:
diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml
index 65f46500a89..edcaf3acf98 100644
--- a/app/views/users/show.html.haml
+++ b/app/views/users/show.html.haml
@@ -13,9 +13,11 @@
%br
%small member since #{@user.created_at.stamp("Nov 12, 2031")}
.clearfix
+ %h4 Groups:
+ = render 'groups', groups: @groups
%hr
%h4 User Activity:
= render @events
.col-md-4
= render 'profile', user: @user
- = render 'projects', user: @user
+ = render 'projects'
diff --git a/app/views/users_groups/_users_group.html.haml b/app/views/users_groups/_users_group.html.haml
index 5f477f3c976..1784dab35b4 100644
--- a/app/views/users_groups/_users_group.html.haml
+++ b/app/views/users_groups/_users_group.html.haml
@@ -1,5 +1,6 @@
- user = member.user
- return unless user
+- show_roles = true if show_roles.nil?
%li{class: "#{dom_class(member)} js-toggle-container", id: dom_id(member)}
= image_tag avatar_icon(user.email, 16), class: "avatar s16"
%strong= user.name
@@ -7,17 +8,23 @@
- if user == current_user
%span.label.label-success It's you
- %span.pull-right
- %strong= member.human_access
-
- - if show_controls && can?(current_user, :manage_group, @group) && current_user != user
- = link_to '#', class: "btn-tiny btn js-toggle-button", title: 'Edit access level' do
- %i.icon-edit
- = link_to group_users_group_path(@group, member), data: { confirm: remove_user_from_group_message(@group, user) }, method: :delete, remote: true, class: "btn-tiny btn btn-remove", title: 'Remove user from group' do
- %i.icon-minus.icon-white
-
- .edit-member.hide.js-toggle-content
- = form_for [@group, member], remote: true do |f|
- .alert.prepend-top-20
- = f.select :group_access, options_for_select(UsersGroup.group_access_roles, member.group_access)
- = f.submit 'Save', class: 'btn btn-save btn-small'
+ - if show_roles
+ %span.pull-right
+ %strong= member.human_access
+ - if show_controls
+ - if can?(current_user, :modify, member)
+ = link_to '#', class: "btn-tiny btn js-toggle-button", title: 'Edit access level' do
+ %i.icon-edit
+ - if can?(current_user, :destroy, member)
+ - if current_user == member.user
+ = link_to leave_profile_group_path(@group), data: { confirm: leave_group_message(@group.name)}, method: :delete, class: "btn-tiny btn btn-remove", title: 'Remove user from group' do
+ %i.icon-minus.icon-white
+ - else
+ = link_to group_users_group_path(@group, member), data: { confirm: remove_user_from_group_message(@group, user) }, method: :delete, remote: true, class: "btn-tiny btn btn-remove", title: 'Remove user from group' do
+ %i.icon-minus.icon-white
+
+ .edit-member.hide.js-toggle-content
+ = form_for [@group, member], remote: true do |f|
+ .alert.prepend-top-20
+ = f.select :group_access, options_for_select(UsersGroup.group_access_roles, member.group_access)
+ = f.submit 'Save', class: 'btn btn-save btn-small'
diff --git a/app/workers/emails_on_push_worker.rb b/app/workers/emails_on_push_worker.rb
index 9982b362a10..5e81810cbdb 100644
--- a/app/workers/emails_on_push_worker.rb
+++ b/app/workers/emails_on_push_worker.rb
@@ -13,13 +13,13 @@ class EmailsOnPushWorker
return true
end
- compare = Gitlab::Git::Compare.new(project.repository.raw_repository, before_sha, after_sha)
+ compare = Gitlab::Git::Compare.new(project.repository.raw_repository, before_sha, after_sha, MergeRequestDiff::COMMITS_SAFE_SIZE)
# Do not send emails if git compare failed
return false unless compare && compare.commits.present?
recipients.split(" ").each do |recipient|
- Notify.delay.repository_push_email(project_id, recipient, author_id, branch, compare)
+ Notify.repository_push_email(project_id, recipient, author_id, branch, compare).deliver
end
end
end